From 546949f376eb37d6c93ba641e2e5672d0d87cc66 Mon Sep 17 00:00:00 2001 From: jainv4156 Date: Mon, 16 Sep 2024 22:25:00 +0530 Subject: [PATCH] Added multiselect delete in manageNotesType Added Multiselect delete in manageNoteType djsakj adding payload to reduce ui rendering Debuging debugging debugging Debugging Debug solved errors remove commented code --- .../ichi2/anki/notetype/ManageNotetypes.kt | 80 ++++++++++++++++++- .../anki/notetype/NoteTypeAdapterCallbacks.kt | 22 +++++ .../ichi2/anki/notetype/NotetypeAdapter.kt | 67 +++++++++++++++- .../main/res/layout/item_manage_note_type.xml | 43 +++++++--- .../src/main/res/menu/menu_manage_notes.xml | 12 +++ 5 files changed, 208 insertions(+), 16 deletions(-) create mode 100644 AnkiDroid/src/main/java/com/ichi2/anki/notetype/NoteTypeAdapterCallbacks.kt create mode 100644 AnkiDroid/src/main/res/menu/menu_manage_notes.xml diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/notetype/ManageNotetypes.kt b/AnkiDroid/src/main/java/com/ichi2/anki/notetype/ManageNotetypes.kt index f33549fc4ca1..826977490a8c 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/notetype/ManageNotetypes.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/notetype/ManageNotetypes.kt @@ -21,6 +21,7 @@ import android.content.Context import android.content.Intent import android.os.Bundle import android.view.Menu +import android.view.MenuItem import androidx.activity.result.ActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.ActionBar @@ -51,12 +52,19 @@ import com.ichi2.utils.positiveButton import com.ichi2.utils.show import com.ichi2.utils.title -class ManageNotetypes : AnkiActivity() { +class ManageNotetypes : AnkiActivity(), NoteTypeAdapterCallbacks { private lateinit var actionBar: ActionBar private lateinit var noteTypesList: RecyclerView private var currentNotetypes: List = emptyList() + private var toDeleteList: List = emptyList() + + private var isInMultiSelectMode = false + private fun getIsInMultiSelectMode(): Boolean { + return isInMultiSelectMode + } + private val notetypesAdapter: NotetypesAdapter by lazy { NotetypesAdapter( this@ManageNotetypes, @@ -70,6 +78,8 @@ class ManageNotetypes : AnkiActivity() { }, onEditCards = { launchForChanges(mapOf("modelId" to it.id)) }, onRename = ::renameNotetype, + callback = this, + getIsInMultiSelectMode = ::getIsInMultiSelectMode, onDelete = ::deleteNotetype ) } @@ -101,6 +111,7 @@ class ManageNotetypes : AnkiActivity() { override fun onCreateOptionsMenu(menu: Menu): Boolean { menuInflater.inflate(R.menu.search, menu) + menuInflater.inflate(R.menu.menu_manage_notes, menu) val searchItem = menu.findItem(R.id.search_item) val searchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager @@ -125,8 +136,21 @@ class ManageNotetypes : AnkiActivity() { return true } }) + + launchCatchingTask { + menu.findItem(R.id.action_delete_notes).isVisible = toDeleteList.isNotEmpty() && isInMultiSelectMode + } return true } + override fun onOptionsItemSelected(item: MenuItem): Boolean { + return when (item.itemId) { + R.id.action_delete_notes -> { + deleteSelectedNotetype() + true + } + else -> super.onOptionsItemSelected(item) + } + } @SuppressLint("CheckResult") private fun renameNotetype(manageNoteTypeUiModel: ManageNoteTypeUiModel) { @@ -167,6 +191,28 @@ class ManageNotetypes : AnkiActivity() { } } + private fun deleteSelectedNotetype() { + val selectedItems = toDeleteList + AlertDialog.Builder(this@ManageNotetypes).show { + title(R.string.model_browser_delete) + message(R.string.model_delete_warning) + positiveButton(R.string.dialog_positive_delete) { + disableMultiSelectMode() + launchCatchingTask { + withProgress { + withCol { + selectedItems.forEach { item -> + removeNotetype(item) + } + } + } + runAndRefreshAfter() + } + } + negativeButton(R.string.dialog_cancel) + } + } + private fun deleteNotetype(manageNoteTypeUiModel: ManageNoteTypeUiModel) { launchCatchingTask { val messageResourceId: Int? = if (userAcceptsSchemaChange()) { @@ -236,4 +282,36 @@ class ManageNotetypes : AnkiActivity() { else -> throw IllegalArgumentException("Unexpected value type: ${newExtra.value}") } } + + override fun enableMultiSelectMode() { + isInMultiSelectMode = true + notetypesAdapter.notifyItemRangeChanged(0, notetypesAdapter.itemCount, "payload_enable_checkbox_visibility") + } + + override fun isToDeleteListContains(id: Long): Boolean { + return toDeleteList.contains(id) + } + + override fun setCheckBoxSelection(id: Long, position: Int) { + if (toDeleteList.contains(id)) { + toDeleteList = toDeleteList.minus(id) + + /** deselecting all checkbox will turnoff the multiselect mode*/ + if (toDeleteList.isEmpty()) { + disableMultiSelectMode() + } else { + notetypesAdapter.notifyItemChanged(position, "payload_deselect_checkbox") + } + } else { + toDeleteList = toDeleteList.plus(id) + notetypesAdapter.notifyItemChanged(position, "payload_select_checkbox") + } + invalidateMenu() + } + private fun disableMultiSelectMode() { + toDeleteList = emptyList() + isInMultiSelectMode = false + notetypesAdapter.notifyItemRangeChanged(0, notetypesAdapter.itemCount, "payload_disable_checkbox_visibility") + invalidateMenu() + } } diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/notetype/NoteTypeAdapterCallbacks.kt b/AnkiDroid/src/main/java/com/ichi2/anki/notetype/NoteTypeAdapterCallbacks.kt new file mode 100644 index 000000000000..2c1ee216ab15 --- /dev/null +++ b/AnkiDroid/src/main/java/com/ichi2/anki/notetype/NoteTypeAdapterCallbacks.kt @@ -0,0 +1,22 @@ +/**************************************************************************************** + * Copyright (c) 2022 lukstbit <52494258+lukstbit@users.noreply.github.com> * + * * + * This program is free software; you can redistribute it and/or modify it under * + * the terms of the GNU General Public License as published by the Free Software * + * Foundation; either version 3 of the License, or (at your option) any later * + * version. * + * * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY * + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * + * PARTICULAR PURPOSE. See the GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License along with * + * this program. If not, see . * + ****************************************************************************************/ +package com.ichi2.anki.notetype + +interface NoteTypeAdapterCallbacks { + fun enableMultiSelectMode() + fun isToDeleteListContains(id: Long): Boolean + fun setCheckBoxSelection(id: Long, position: Int) +} diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/notetype/NotetypeAdapter.kt b/AnkiDroid/src/main/java/com/ichi2/anki/notetype/NotetypeAdapter.kt index 7104f0010b91..02790ea3a04a 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/notetype/NotetypeAdapter.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/notetype/NotetypeAdapter.kt @@ -20,6 +20,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.Button +import android.widget.CheckBox import android.widget.TextView import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter @@ -46,6 +47,8 @@ internal class NotetypesAdapter( private val onShowFields: (ManageNoteTypeUiModel) -> Unit, private val onEditCards: (ManageNoteTypeUiModel) -> Unit, private val onRename: (ManageNoteTypeUiModel) -> Unit, + private val callback: NoteTypeAdapterCallbacks, + private val getIsInMultiSelectMode: () -> Boolean, private val onDelete: (ManageNoteTypeUiModel) -> Unit ) : ListAdapter(notetypeNamesAndCountDiff) { private val layoutInflater = LayoutInflater.from(context) @@ -56,6 +59,8 @@ internal class NotetypesAdapter( onDelete = onDelete, onRename = onRename, onEditCards = onEditCards, + callback = callback, + getIsInMultiSelectMode = getIsInMultiSelectMode, onShowFields = onShowFields ) } @@ -63,31 +68,58 @@ internal class NotetypesAdapter( override fun onBindViewHolder(holder: NotetypeViewHolder, position: Int) { holder.bind(getItem(position)) } + + override fun onBindViewHolder(holder: NotetypeViewHolder, position: Int, payloads: List) { + if (payloads.isEmpty()) { + onBindViewHolder(holder, position) + } else { + for (payload in payloads) { + when (payload) { + "payload_enable_checkbox_visibility" -> { + holder.applyMultiSelectMode(getItem(position)) + } + "payload_disable_checkbox_visibility" -> { + holder.removeMultiSelectMode() + } + "payload_select_checkbox" -> { + holder.selectCheckBox() + } + "payload_deselect_checkbox" -> { + holder.deselectCheckBox() + } + } + } + } + } } internal class NotetypeViewHolder( rowView: View, - onShowFields: (ManageNoteTypeUiModel) -> Unit, + private val onShowFields: (ManageNoteTypeUiModel) -> Unit, + private val callback: NoteTypeAdapterCallbacks, onEditCards: (ManageNoteTypeUiModel) -> Unit, onRename: (ManageNoteTypeUiModel) -> Unit, + getIsInMultiSelectMode: () -> Boolean, onDelete: (ManageNoteTypeUiModel) -> Unit ) : RecyclerView.ViewHolder(rowView) { val name: TextView = rowView.findViewById(R.id.note_name) - val useCount: TextView = rowView.findViewById(R.id.note_use_count) + private val useCount: TextView = rowView.findViewById(R.id.note_use_count) private val btnDelete: Button = rowView.findViewById(R.id.note_delete) private val btnRename: Button = rowView.findViewById(R.id.note_rename) private val btnEditCards: Button = rowView.findViewById(R.id.note_edit_cards) private var mManageNoteTypeUiModel: ManageNoteTypeUiModel? = null private val resources = rowView.context.resources + private val isInMultiSelectMode = getIsInMultiSelectMode + private val selectedItemCheckbox: CheckBox = rowView.findViewById(R.id.selected_item_checkbox) init { - rowView.setOnClickListener { mManageNoteTypeUiModel?.let(onShowFields) } btnEditCards.setOnClickListener { mManageNoteTypeUiModel?.let(onEditCards) } btnDelete.setOnClickListener { mManageNoteTypeUiModel?.let(onDelete) } btnRename.setOnClickListener { mManageNoteTypeUiModel?.let(onRename) } } fun bind(manageNoteTypeUiModel: ManageNoteTypeUiModel) { + itemView.setOnClickListener { mManageNoteTypeUiModel?.let(onShowFields) } this.mManageNoteTypeUiModel = manageNoteTypeUiModel name.text = manageNoteTypeUiModel.name useCount.text = resources.getQuantityString( @@ -95,5 +127,34 @@ internal class NotetypeViewHolder( manageNoteTypeUiModel.useCount, manageNoteTypeUiModel.useCount ) + itemView.setOnLongClickListener { + callback.enableMultiSelectMode() + callback.setCheckBoxSelection(manageNoteTypeUiModel.id, bindingAdapterPosition) + true + } + } + + fun removeMultiSelectMode() { + hideCheckBox(selectedItemCheckbox) + selectedItemCheckbox.isChecked = false + itemView.setOnClickListener { mManageNoteTypeUiModel?.let(onShowFields) } + } + fun applyMultiSelectMode(manageNoteTypeUiModel: ManageNoteTypeUiModel) { + showCheckBox(selectedItemCheckbox) + itemView.setOnClickListener { + callback.setCheckBoxSelection(manageNoteTypeUiModel.id, bindingAdapterPosition) + } + } + fun selectCheckBox() { + selectedItemCheckbox.isChecked = true + } + fun deselectCheckBox() { + selectedItemCheckbox.isChecked = false + } + private fun hideCheckBox(checkBox: CheckBox) { + checkBox.visibility = View.GONE + } + private fun showCheckBox(checkBox: CheckBox) { + checkBox.visibility = View.VISIBLE } } diff --git a/AnkiDroid/src/main/res/layout/item_manage_note_type.xml b/AnkiDroid/src/main/res/layout/item_manage_note_type.xml index 00c18dda8131..f3d76612c6a5 100644 --- a/AnkiDroid/src/main/res/layout/item_manage_note_type.xml +++ b/AnkiDroid/src/main/res/layout/item_manage_note_type.xml @@ -14,23 +14,42 @@ - - + + + + + + + android:checked="false" + android:focusable="false" + android:focusableInTouchMode="false" + android:visibility="gone" + android:clickable="false" + tools:visibility="visible" /> + + + + \ No newline at end of file