From 5121916dbbb8585421c02db0b354da0fbde32258 Mon Sep 17 00:00:00 2001 From: Christian Adams Date: Mon, 30 Dec 2024 10:18:33 +0100 Subject: [PATCH] Implemented feature request #92 to move all done tasks to recycle bin with one click. For tasks the term "delete" was replaced by "remove" because tasks first get moved to recycle bin before they get deleted. Most texts already used "remove", only a few needed to be changed. Merged some texts. --- .../model/ModelServices.kt | 9 ++++ .../model/database/dao/TodoTaskDao.kt | 3 ++ .../model/impl/ModelServicesImpl.kt | 14 ++++++ .../view/MainActivity.kt | 50 ++++++++++++++++--- ...st_action_view.xml => nav_action_view.xml} | 1 - app/src/main/res/menu/all_tasks_context.xml | 6 +++ app/src/main/res/menu/todo_task_context.xml | 4 +- app/src/main/res/values-de/strings.xml | 14 +++--- app/src/main/res/values-es/strings.xml | 3 +- app/src/main/res/values-fr/strings.xml | 2 +- app/src/main/res/values-ja/strings.xml | 2 +- app/src/main/res/values-nl/strings.xml | 2 +- app/src/main/res/values-pl/strings.xml | 2 +- app/src/main/res/values/strings.xml | 12 ++--- 14 files changed, 95 insertions(+), 29 deletions(-) rename app/src/main/res/layout/{list_action_view.xml => nav_action_view.xml} (89%) create mode 100644 app/src/main/res/menu/all_tasks_context.xml diff --git a/app/src/main/java/org/secuso/privacyfriendlytodolist/model/ModelServices.kt b/app/src/main/java/org/secuso/privacyfriendlytodolist/model/ModelServices.kt index 5f849945..db50f76e 100644 --- a/app/src/main/java/org/secuso/privacyfriendlytodolist/model/ModelServices.kt +++ b/app/src/main/java/org/secuso/privacyfriendlytodolist/model/ModelServices.kt @@ -139,6 +139,15 @@ class ModelServices( } } + fun setAllDoneTasksInRecycleBin(deliveryOption: DeliveryOption = DeliveryOption.POST, + resultConsumer: ResultConsumer>? = null): Job { + return coroutineScope.launch(Dispatchers.IO) { + val counter = services.setAllDoneTasksInRecycleBin() + dispatchResult(deliveryOption, resultConsumer, counter) + notifyDataChanged(0, counter.first, counter.second) + } + } + fun setTaskAndSubtasksInRecycleBin(todoTask: TodoTask, inRecycleBin: Boolean, deliveryOption: DeliveryOption = DeliveryOption.POST, diff --git a/app/src/main/java/org/secuso/privacyfriendlytodolist/model/database/dao/TodoTaskDao.kt b/app/src/main/java/org/secuso/privacyfriendlytodolist/model/database/dao/TodoTaskDao.kt index b8390fe6..0dc2080c 100644 --- a/app/src/main/java/org/secuso/privacyfriendlytodolist/model/database/dao/TodoTaskDao.kt +++ b/app/src/main/java/org/secuso/privacyfriendlytodolist/model/database/dao/TodoTaskDao.kt @@ -72,6 +72,9 @@ interface TodoTaskDao { " ORDER BY todoLists.sortOrder ASC, todoTasks.sortOrder ASC") suspend fun getOverdueTasks(now: Long): Array + @Query("SELECT * FROM todoTasks WHERE isInRecycleBin = 0 AND doneTime IS NOT NULL") + suspend fun getAllDoneNotInRecycleBin(): Array + @Query("SELECT todoTasks.* FROM todoTasks" + " LEFT JOIN todoLists" + " ON todoTasks.listId = todoLists.id" + diff --git a/app/src/main/java/org/secuso/privacyfriendlytodolist/model/impl/ModelServicesImpl.kt b/app/src/main/java/org/secuso/privacyfriendlytodolist/model/impl/ModelServicesImpl.kt index a288ec15..213f1935 100644 --- a/app/src/main/java/org/secuso/privacyfriendlytodolist/model/impl/ModelServicesImpl.kt +++ b/app/src/main/java/org/secuso/privacyfriendlytodolist/model/impl/ModelServicesImpl.kt @@ -126,6 +126,20 @@ class ModelServicesImpl(private val context: Context) { return counter } + suspend fun setAllDoneTasksInRecycleBin(): Pair { + val dataArray = getDB().getTodoTaskDao().getAllDoneNotInRecycleBin() + val tasks = loadTasksSubtasks(false, *dataArray) + var counterTasks = 0 + var counterSubtasks = 0 + for (task in tasks) { + val counters = setTaskAndSubtasksInRecycleBin(task, true) + counterTasks += counters.first + counterSubtasks += counters.second + } + Log.i(TAG, "$counterTasks task and $counterSubtasks subtasks put into recycle bin.") + return Pair(counterTasks, counterSubtasks) + } + suspend fun setTaskAndSubtasksInRecycleBin(todoTask: TodoTask, inRecycleBin: Boolean): Pair { var counterSubtasks = 0 for (subtask in todoTask.getSubtasks()) { diff --git a/app/src/main/java/org/secuso/privacyfriendlytodolist/view/MainActivity.kt b/app/src/main/java/org/secuso/privacyfriendlytodolist/view/MainActivity.kt index 9fe19eb1..f6dc259e 100644 --- a/app/src/main/java/org/secuso/privacyfriendlytodolist/view/MainActivity.kt +++ b/app/src/main/java/org/secuso/privacyfriendlytodolist/view/MainActivity.kt @@ -429,6 +429,17 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte navigationView = findViewById(R.id.nav_view) navigationView!!.setNavigationItemSelectedListener(this) + val navMenu = navigationView!!.menu + val btnAllTasks = navMenu.findItem(R.id.menu_home) + btnAllTasks.setActionView(R.layout.nav_action_view) + val actionButton: ImageButton = btnAllTasks.actionView!!.findViewById(R.id.action_button) + actionButton.tag = ACT_BTN_ALL_TASKS + actionButton.setOnClickListener { + registerForContextMenu(actionButton) + openContextMenu(actionButton) + unregisterForContextMenu(actionButton) + } + addTodoListsToNavigationMenu() var tasksGetDisplayed = false @@ -539,7 +550,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte deleteAllDataBeforeImport = false importTasksLauncher.launch(intent) } - setNeutralButton(R.string.abort) { _, _ -> + setNeutralButton(R.string.cancel) { _, _ -> } show() } @@ -641,7 +652,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte val item = navMenu.add(R.id.menu_group_todo_lists, entry.key, 1, entry.value) item.isCheckable = true item.setIcon(R.drawable.ic_label_black_24dp) - item.setActionView(R.layout.list_action_view) + item.setActionView(R.layout.nav_action_view) val actionButton: ImageButton = item.actionView!!.findViewById(R.id.action_button) actionButton.tag = entry.key actionButton.setOnClickListener { @@ -794,6 +805,10 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte if (pomodoroInstalled) { menu.findItem(workItemId).setVisible(true) } + } else if (v.tag == ACT_BTN_ALL_TASKS) { + val menuHeader = Helper.getMenuHeader(layoutInflater, v.rootView, R.string.select_option) + menu.setHeaderView(menuHeader) + menuInflater.inflate(R.menu.all_tasks_context, menu) // Check for to-do lists in main menu. } else if (v.tag is Int) { selectedTodoListId = v.tag as Int @@ -807,6 +822,26 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte override fun onContextItemSelected(item: MenuItem): Boolean { when (item.itemId) { + R.id.remove_all_done_tasks -> { + MaterialAlertDialogBuilder(this).apply { + setMessage(R.string.alert_done_tasks_remove) + setCancelable(true) + setPositiveButton(R.string.yes) { dialog, setId -> + model!!.setAllDoneTasksInRecycleBin { counters -> + val msg = getString(R.string.tasks_removed, counters.first, counters.second) + Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show() + if (counters.first > 0) { + showTasksOfListOrAllTasks(activeListId) + } + } + } + setNegativeButton(R.string.cancel) { dialog, id -> + dialog.cancel() + } + show() + } + } + R.id.move_up_list -> { moveList(true) } @@ -852,7 +887,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte } } - R.id.delete_task -> { + R.id.remove_task -> { val todoTask = contextMenuTodoTask if (null != todoTask) { val snackBar = Snackbar.make(fabNewTodoTask!!, R.string.task_removed, Snackbar.LENGTH_LONG) @@ -862,7 +897,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte showTasksOfListOrAllTasks(activeListId) showHints() } else { - Log.w(TAG, "Task was not removed from the database.") + Log.e(TAG, "Task was not restored from recycle bin.") } } } @@ -873,7 +908,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte showHints() snackBar.show() } else { - Log.w(TAG, "Task was not removed from the database.") + Log.e(TAG, "Task was not moved to recycle bin.") } } } @@ -991,7 +1026,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte MaterialAlertDialogBuilder(this).apply { setMessage(R.string.alert_list_delete) setCancelable(true) - setPositiveButton(R.string.alert_delete_yes) { dialog, setId -> + setPositiveButton(R.string.yes) { dialog, setId -> model!!.deleteTodoList(todoList.getId()) { counter -> if (counter.first > 0) { Log.i(TAG, "List '${todoList.getName()}' with ID ${todoList.getId()} deleted.") @@ -1009,7 +1044,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte dialog.cancel() } } - setNegativeButton(R.string.alert_delete_no) { dialog, id -> + setNegativeButton(R.string.cancel) { dialog, id -> dialog.cancel() } show() @@ -1138,6 +1173,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte const val COMMAND = "command" //const val COMMAND_RUN_TODO = 2 const val COMMAND_UPDATE = 3 + const val ACT_BTN_ALL_TASKS = "ACT_BTN_ALL_TASKS" // Keys private const val KEY_IS_UNLOCKED = "restore_is_unlocked_key_with_savedinstancestate" diff --git a/app/src/main/res/layout/list_action_view.xml b/app/src/main/res/layout/nav_action_view.xml similarity index 89% rename from app/src/main/res/layout/list_action_view.xml rename to app/src/main/res/layout/nav_action_view.xml index 8512cae4..d62a2a27 100644 --- a/app/src/main/res/layout/list_action_view.xml +++ b/app/src/main/res/layout/nav_action_view.xml @@ -9,7 +9,6 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" - android:contentDescription="@string/edit_todo_list" app:srcCompat="@drawable/ic_menu_black_24dp" /> \ No newline at end of file diff --git a/app/src/main/res/menu/all_tasks_context.xml b/app/src/main/res/menu/all_tasks_context.xml new file mode 100644 index 00000000..1479d426 --- /dev/null +++ b/app/src/main/res/menu/all_tasks_context.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/todo_task_context.xml b/app/src/main/res/menu/todo_task_context.xml index f691bc78..f713a47a 100644 --- a/app/src/main/res/menu/todo_task_context.xml +++ b/app/src/main/res/menu/todo_task_context.xml @@ -7,8 +7,8 @@ android:id="@+id/share_task" android:title="@string/share_task" /> + android:id="@+id/remove_task" + android:title="@string/remove_task" /> To-Do\'s Alle Aufgaben Alle Aufgaben + Alle erledigten Aufgaben entfernen Kalenderansicht Einstellungen Daten teilen @@ -27,7 +28,7 @@ Name Beschreibung Okay - Löschen + Abbrechen Auswählen @@ -111,8 +112,9 @@ Kein Termin Aufgabe bearbeiten Aufgabe teilen - Aufgabe löschen - Aufgabe ist im Papierkorb + Aufgabe entfernen + Aufgabe wurde entfernt + %d Aufgabe(n) und %d Unteraufgabe(n) entfernt. Termin Wiederholung alle 1..n @@ -285,13 +287,11 @@ Sollen alle existierenden Daten (alle To-Do Listen, Aufgaben und Unteraufgaben) vor dem Import gelöscht werden? Existierende Daten löschen Existierende Daten beibehalten - Abbrechen - Wollen Sie die Liste wirklich löschen? + Die Liste wirklich löschen? + Die erledigten Aufgaben wirklich entfernen? Wirklich leeren? - Löschen - Abbrechen Widget hinzufügen diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 2e874687..3d3d9f6e 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -78,7 +78,7 @@ Fecha límite: No hay ninguna fecha límite Editar la tarea - Eliminar la tarea + Eliminar la tarea Tarea eliminada Facha límite Alarma @@ -161,7 +161,6 @@ Widget Patrón de repetición Una tarea que se repite necesita una fecha límite. - Borrar Puede utilizar la aplicación independiente Privacy Friendly Backup para realizar copias de seguridad y restaurar los datos y la configuración de esta aplicación. También se puede utilizar para transferir los datos a otro dispositivo. Además, esta aplicación proporciona un widget que puedes añadir a tu pantalla de inicio. El widget te presenta las tareas que pertenecen a una lista elegida. Al hacer clic en una tarea se accede a la vista principal de la aplicación. El botón de sincronización puede actualizar la lista de tareas mostradas. Editar la lista diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index a344c6be..aed0aa09 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -87,7 +87,7 @@ Date limite: Aucune date limite Editer la tâche - Supprimer la tâche + Supprimer la tâche La tâche a été supprimée. Date limite Alarme diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 762d102a..5ad69914 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -87,7 +87,7 @@ 期限: 期限なし タスクを編集 - タスクを削除 + タスクを削除 タスクを削除しました。 期限 リマインダー diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 4456632d..07cf273b 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -87,7 +87,7 @@ Deadline: Geen Deadline Bewerk taak - Verwijder taak + Verwijder taak Taak is verwijderd. Deadline Herinnering diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 8fe999c3..17b9323d 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -87,7 +87,7 @@ Termin: Brak terminu Edytuj zadanie - Usuń zadanie + Usuń zadanie Zadanie zostało usunięte. Termin Alarm diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1ce6359b..f40fe079 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -11,6 +11,7 @@ To-Do\'s All tasks Show all tasks + Remove all done tasks Calendar Settings Share data @@ -27,7 +28,7 @@ Name Description Okay - Delete + Cancel Select option @@ -115,8 +116,9 @@ No Deadline Edit task Share task - Delete task - Task put into recycle bin + Remove task + Task successfully removed. + %d task(s) and %d subtask(s) removed. Deadline Recurrence every 1..n @@ -309,13 +311,11 @@ Delete all existing data (all To-Do lists, tasks and subtasks) before importing new data? Delete existing data Keep existing data - Abort Really delete this list? + Really remove all done tasks? Really clear? - Delete - Cancel Add widget