implémenter des actions sur nos tâches, en naviguant entre des Activity
et partager des infos entre elle ou dans une autre application avec des Intent
.
Prérequis: Terminez au moins l'étape "Ajout de tâche rapide" du TP 1
Dans le layout de vos item, ajouter un ImageButton
qui servira à supprimer la tâche associée. Vous pouvez utiliser par exemple l'icône @android:drawable/ic_menu_delete
Aidez vous des lignes de code plus bas pour réaliser un "Click Listener" à l'aide d'une lambda en suivant ces étapes:
onClickDelete
de type lambda qui prends en arguments une Task
et ne renvoie rien: (Task) -> Unit
et l'initier à {}
(elle ne fait rien par défaut)onClickListener
du bouton supprimeronClickDelete
depuis l'adapter et implémentez là: donnez lui comme valeur une lambda qui va supprimer la tache passée en argument de la liste{}
):var onClickDelete: (Task) -> Unit = {}
onClickDelete(task)
myAdapter.onClickDelete = { task ->
// Supprimer la tâche
}
detail
dans votre package principalDetailActivity
: Clic droit sur le package > New > Activity > Gallery... > Empty Activity
app/build.gradle.kts
pour configurer Compose (buildFeatures, dependencies, etc) et l'ajouter au AndroidManifest.xml
startActivity(Intent(context, ...))
Greeting
en Detail
et GreetingPreview
en DetailPreview
et supprimez l'argument name
Text(...)
par un titre: "Task Detail"
textStyle
: MaterialTheme.typography.headlineLarge
Text()
avec comme contenu "title"
et "description"
Text
dans une Column {}
: c'est l'équivalent d'un LinearLayout
verticalmodifier
à votre Column
pour ajouter un padding de 16.dp
verticalArrangement
à votre Column
pour espacer ses enfants de 16.dp
(Arrangement.spacedBy(...)
)Button
de validation dans la Column
TaskListFragment
qui permettra de lancer votre nouvelle activité et d'utiliser son résultat:val createTask = registerForActivityResult(StartActivityForResult()) { result ->
// dans cette callback on récupèrera la task et on l'ajoutera à la liste
}
Intent
createTask.launch(intent)
Detail
, ajoutez un argument onValidate: (Task) -> Unit
et appelez cette lambda dans le onClick
de votre bouton de validation, en passant une nouvelle task:val newTask = Task(id = UUID.randomUUID().toString(), title = "New Task !")
onCreate
, Detail
va donc maintenant nécessiter une lambda onValidate
, que nous allons définir et utiliser:newTask
dans intent
: intent.putExtra("task", newTask)
: ça ne compilera pas car Task
ne fait pas partie des types de base autorisés dans un intent !Serializable
: Faites donc hériter Task
de java.io.Serializable
, comme c'est une data class
, il n'y a rien à implémenter !setResult(RESULT_OK, intent)
pour signifier que l'action s'est bien passée (idéalement, on aurait aussi géré des cas d'erreur)finish()
pour quitter cette activité, et donc retourner à l'écran précédentcreateTask
récupérer cette task:val task = result.data?.getSerializableExtra("task") as Task?
"task"
:companion object {
const val TASK_KEY = "task"
}
DetailActivity
, changez les Text
en OutlinedTextField
, on va mettre à jour dynamiquement la Task affichée:Inspirez vous de ce que vous avez fait pour le bouton "supprimer" et le bouton "ajouter" pour créer un bouton "éditer" permettant de modifier chaque tâche en ouvrant l'activité DetailActivity
pré-remplie avec les informations de la tâche en question:
putExtra
pour transmettre la Task
à éditer (depuis TaskListFragment
cette fois)Task
dans le onCreate
de DetailActivity
avec getSerializableExtra
comme précédemment (avec intent
à la place de result.data
)Task
récupérée est nullable
: c'est utile car elle sera null
quand vous êtes dans le cas "Ajout", et sinon, elle aura une vraie valeur car vous êtes dans le cas "Édition"Detail
: initialTask: Task?
et utilisez la comme valeur initiale de votre variable compose task
afin de préremplir les OutlinedTextField
lors de l'édition?:
pour gérer à la fois le cas édition et ajout:mutableStateOf(initialTask ?: newTask)
if
ou un ?: return
par ex) mettez à jour la liste: taskList = taskList.map { if (it.id == task.id) task else it }
Une façon plus classique de gérer les clicks d'un item est de définir une interface que l'on implémentera dans l'Activity/Fragment. Mettez à jour votre code pour utiliser cette méthode:
interface TaskListListener {
fun onClickDelete(task: Task)
fun onClickEdit(task: Task)
}
class TaskListAdapter(val listener: TaskListListener) : ... {
// use: listener.onClickDelete(task)
}
class TaskListFragment : Fragment {
val adapterListener : TaskListListener = object : TaskListListener {
override fun onClickDelete(task: Task) {...}
override fun onClickEdit(task: Task) {...}
}
val adapter = TaskListAdapter(adapterListener)
}
AndroidManifest.xml
, ajouter la possibilité de partager du texte depuis les autres applications (par ex en surlignant un texte dans un navigateur puis en cliquant sur "partager") et ouvrir le formulaire de création de tâche avec une description pré-remplie (Documentation)Intent
implicite, ajouter la possibilité de partager du texte vers les autres applications (avec un OnLongClickListener
sur les tâches par ex ou bien avec un bouton dans la vue formulaire) (Documentation)Que se passe-t-il pour votre liste si vous tournez votre téléphone pour passer en mode paysage ? 🤔
onSaveInstanceState
putSerializable
(un peu comme précédemment avec putExtra
) pour sauvegarder la listegetSerializable
dans onCreateView
ou onViewCreated
, sur le paramètre savedInstanceState