Skip to content

Commit

Permalink
Added multiselect delete in manageNotesType
Browse files Browse the repository at this point in the history
  • Loading branch information
jainv4156 committed Sep 27, 2024
1 parent 27b1c06 commit 3c56315
Show file tree
Hide file tree
Showing 6 changed files with 273 additions and 43 deletions.
99 changes: 96 additions & 3 deletions AnkiDroid/src/main/java/com/ichi2/anki/notetype/ManageNotetypes.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@ 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
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.widget.SearchView
import androidx.appcompat.widget.Toolbar
import androidx.recyclerview.widget.RecyclerView
import anki.notetypes.copy
import com.google.android.material.floatingactionbutton.FloatingActionButton
Expand All @@ -52,12 +54,18 @@ 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<ManageNoteTypeUiModel> = emptyList()

lateinit var toolbar: Toolbar
private var toDeleteList: List<Long> = emptyList()
private var isInMultiSelectMode = false
private fun getIsInMultiSelectMode(): Boolean {
return isInMultiSelectMode
}
private val notetypesAdapter: NotetypesAdapter by lazy {
NotetypesAdapter(
this@ManageNotetypes,
Expand All @@ -71,6 +79,8 @@ class ManageNotetypes : AnkiActivity() {
},
onEditCards = { launchForChanges<CardTemplateEditor>(mapOf("modelId" to it.id)) },
onRename = ::renameNotetype,
callback = this,
getIsInMultiSelectMode = ::getIsInMultiSelectMode,
onDelete = ::deleteNotetype
)
}
Expand All @@ -90,6 +100,7 @@ class ManageNotetypes : AnkiActivity() {
setTitle(R.string.model_browser_label)
setContentView(R.layout.activity_manage_note_types)
actionBar = enableToolbar()
toolbar = findViewById(R.id.toolbar)
noteTypesList = findViewById<RecyclerView?>(R.id.note_types_list).apply {
adapter = notetypesAdapter
}
Expand All @@ -101,8 +112,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
val searchView = searchItem?.actionView as? AccessibleSearchView
Expand All @@ -126,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) {
Expand Down Expand Up @@ -168,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()) {
Expand Down Expand Up @@ -237,4 +282,52 @@ class ManageNotetypes : AnkiActivity() {
else -> throw IllegalArgumentException("Unexpected value type: ${newExtra.value}")
}
}

override fun enableMultiSelectMode() {
isInMultiSelectMode = true
toolbar.setNavigationOnClickListener {
disableMultiSelectMode()
}
notetypesAdapter.notifyItemRangeChanged(0, notetypesAdapter.itemCount, "payload_enable_checkbox_visibility")
}

private fun disableMultiSelectMode() {
toDeleteList = emptyList()
isInMultiSelectMode = false

toolbar.setNavigationOnClickListener {
finish()
}
notetypesAdapter.notifyItemRangeChanged(0, notetypesAdapter.itemCount, "payload_disable_checkbox_visibility")
invalidateMenu()
}

override fun isToDeleteListContains(id: Long): Boolean {
return toDeleteList.contains(id)
}

override fun setCheckBoxSelectionOnCLick(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()
}

override fun setCheckBoxSelectionOnStart(id: Long): Boolean {
return if (toDeleteList.contains(id)) {
true
} else {
false
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/****************************************************************************************
* Copyright (c) 2022 Vaibhav Jain <[email protected]> *
* *
* 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 <http://www.gnu.org/licenses/>. *
****************************************************************************************/
package com.ichi2.anki.notetype

interface NoteTypeAdapterCallbacks {
fun enableMultiSelectMode()
fun isToDeleteListContains(id: Long): Boolean
fun setCheckBoxSelectionOnCLick(id: Long, position: Int)
fun setCheckBoxSelectionOnStart(id: Long): Boolean
}
103 changes: 100 additions & 3 deletions AnkiDroid/src/main/java/com/ichi2/anki/notetype/NotetypeAdapter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@ 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
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.button.MaterialButton
import com.ichi2.anki.R

private val notetypeNamesAndCountDiff =
Expand All @@ -46,6 +48,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<ManageNoteTypeUiModel, NotetypeViewHolder>(notetypeNamesAndCountDiff) {
private val layoutInflater = LayoutInflater.from(context)
Expand All @@ -56,44 +60,137 @@ internal class NotetypesAdapter(
onDelete = onDelete,
onRename = onRename,
onEditCards = onEditCards,
callback = callback,
getIsInMultiSelectMode = getIsInMultiSelectMode,
onShowFields = onShowFields
)
}

override fun onBindViewHolder(holder: NotetypeViewHolder, position: Int) {
holder.bind(getItem(position))
}

override fun onBindViewHolder(holder: NotetypeViewHolder, position: Int, payloads: List<Any>) {
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)
private val editCardButton: MaterialButton = rowView.findViewById(R.id.note_edit_cards)
private val renameCardButton: MaterialButton = rowView.findViewById(R.id.note_rename)
private val deleteCardButton: MaterialButton = rowView.findViewById(R.id.note_delete)

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) {
if (isInMultiSelectMode()) {
applyMultiSelectMode(manageNoteTypeUiModel)
} else {
removeMultiSelectMode()
}
this.mManageNoteTypeUiModel = manageNoteTypeUiModel
name.text = manageNoteTypeUiModel.name
useCount.text = resources.getQuantityString(
R.plurals.model_browser_of_type,
manageNoteTypeUiModel.useCount,
manageNoteTypeUiModel.useCount
)
itemView.setOnLongClickListener {
callback.enableMultiSelectMode()
callback.setCheckBoxSelectionOnCLick(manageNoteTypeUiModel.id, bindingAdapterPosition)
true
}
}
fun applyMultiSelectMode(manageNoteTypeUiModel: ManageNoteTypeUiModel) {
showCheckBox(selectedItemCheckbox)
if (callback.setCheckBoxSelectionOnStart(manageNoteTypeUiModel.id)) {
selectCheckBox()
} else {
deselectCheckBox()
}
disableEditDeleteRenameButton()
itemView.setOnClickListener {
callback.setCheckBoxSelectionOnCLick(manageNoteTypeUiModel.id, bindingAdapterPosition)
}
}
fun removeMultiSelectMode() {
enableEditDeleteRenameButton()
hideCheckBox(selectedItemCheckbox)
selectedItemCheckbox.isChecked = false
itemView.setOnClickListener { mManageNoteTypeUiModel?.let(onShowFields) }
}
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
}
private fun disableEditDeleteRenameButton() {
editCardButton.apply {
visibility = View.GONE
}
renameCardButton.apply {
visibility = View.GONE
}
deleteCardButton.apply {
visibility = View.GONE
}
}
private fun enableEditDeleteRenameButton() {
editCardButton.apply {
visibility = View.VISIBLE
}
renameCardButton.apply {
visibility = View.VISIBLE
}
deleteCardButton.apply {
visibility = View.VISIBLE
}
}
}
Loading

0 comments on commit 3c56315

Please sign in to comment.