The following procedures are based on Android Studio 4.1 and Kotlin 1.4.
Create Android Studio Project
This guide is based on Android Studio 4.1 and Kotlin 1.4
The first step is to create a project. Go to File → New → New Project and select Basic Activity:
Next, fill out the options with the product name: "Tasks", choose Kotlin, and set the minimum API level to 26:
In newer version of Android Studio the Basic Activity template includes additional files that are not need for this tutorial. To continue, remove the following if they exist:
FirstFragment.kt
SecondFragment.kt
fragment_first.xml
fragment_second.xml
nav_graph.xml
Install Ditto
To install Ditto, we need to add it as a dependency in the build.gradle script for the app, as well as ensuring that we have the relevant Java -compatibility set.
Android requires requesting permission to use Bluetooth Low Energy and Wifi Direct. For instructions, see Jetpack Compose: Defining UI.
Add Extensions
For the UI in this example, we are still using Kotlin synthetics, which are no longer bundled automatically. We need to add kotlin-android-extensionsin the the plugins section of build.gradle to enable.
build.gradle
|
plugins {
// ...
id 'kotlin-android-extensions'
}
Be sure to Sync Project with Gradle Files after you add Ditto as a dependency. Click the elephant icon with the blue arrow in the top right to manually trigger if it doesn't prompt.
At this point, you have the basic project in place! Now we need to start to build the UI elements.
Navigate to the content_main.xml layout file and replace the XML in the text representation view. This will remove the existing text view and a recycler view that we will use to display the list of tasks:
Now navigate to activity_main.xml layout file and replace the XML in the text representation view. This will adjust the floating action button to use a white add icon:
Now navigate to activity_main.xml layout file and replace the XML in the text representation view. This will adjust the floating action button to use a white add icon:
Now navigate to activity_main.xml layout file and replace the XML in the text representation view. This will adjust the floating action button to use a white add icon:
We now need to create a new layout resource file to define our alert dialog. Right click on the layouts folder in the project and Go to File → New → XML → Layout XML.
Name the resource file dialog_new_task
Open the new dialog_new_task.xml layout file and replace the XML in the text representation view. This will add an editable text input to allow the user to enter the task:
We need to create a few string constants. Open strings.xml in the /res/values folder and replace it with this XML:
XML
|
<resources><stringname="app_name">Tasks</string><stringname="action_settings">Settings</string><stringname="title_activity_main">Tasks</string><stringname="add_new_task_dialog_title">Add New Task</string><stringname="save">Save</string></resources>
Right click on the layouts folder in the project and Go to File → New → XML → Layout XML. Name the file task_view:
Open the task_view.xml layout file and replace the XML in the text representation view. This will add a text view and checkbox to display the task in each row of the RecyclerView:
We now need to continue to configure the MainActivity to customize the RecyclerView, to display the tasks and add the logic for the user actions. Replace the onCreate() function with this code that will configure the recycler view:
We need to declare a RecyclerView.Adapter to provide a data source to the RecyclerView. Add this code to the bottom of MainActivity, as a new class within the file:
MainActivity
|
class TasksAdapter: RecyclerView.Adapter<TasksAdapter.TaskViewHolder>(){privateval tasks = mutableListOf<DittoDocument>()var onItemClick:((DittoDocument)-> Unit)?=nullclassTaskViewHolder(v: View): RecyclerView.ViewHolder(v)overridefunonCreateViewHolder(parent: ViewGroup, viewType: Int): TaskViewHolder {val view = LayoutInflater.from(parent.context).inflate(R.layout.task_view, parent,false)returnTaskViewHolder(view)}overridefunonBindViewHolder(holder: TaskViewHolder, position: Int){val task = tasks[position]
holder.itemView.taskTextView.text = task["body"].stringValue
holder.itemView.taskCheckBox.isChecked = task["isCompleted"].booleanValue
holder.itemView.setOnClickListener{// NOTE: Cannot use position as this is not accurate based on async updates
onItemClick?.invoke(tasks[holder.adapterPosition])}}overridefungetItemCount()=this.tasks.size
funtasks(): List<DittoDocument>{returnthis.tasks.toList()}funset(tasks: List<DittoDocument>): Int {this.tasks.clear()this.tasks.addAll(tasks)returnthis.tasks.size
}funinserts(indexes: List<Int>): Int {for(index in indexes){this.notifyItemRangeInserted(index,1)}returnthis.tasks.size
}fundeletes(indexes: List<Int>): Int {for(index in indexes){this.notifyItemRangeRemoved(index,1)}returnthis.tasks.size
}funupdates(indexes: List<Int>): Int {for(index in indexes){this.notifyItemRangeChanged(index,1)}returnthis.tasks.size
}funmoves(moves: List<DittoLiveQueryMove>){for(move in moves){this.notifyItemMoved(move.from, move.to)}}funsetInitial(tasks: List<DittoDocument>): Int {this.tasks.addAll(tasks)this.notifyDataSetChanged()returnthis.tasks.size
}}
To match the iOS getting started app, we also want to add swipe to delete functionality. Insert this code at the bottom of MainActivity as a new class: