From a1c0241a58c9b28ce24901633cd8d230f2cca357 Mon Sep 17 00:00:00 2001
From: davidoskky <davidoskky@yahoo.it>
Date: Sun, 9 Mar 2025 13:49:32 +0000
Subject: [PATCH] Show a confirmation dialog before deleting sources (#185)

## Types of changes

- [ x ] I have read the **CONTRIBUTING** document.
- [ x ] My code follows the code style of this project.
- [ ] I have updated the documentation accordingly.
- [ ] I have added tests to cover my changes.
- [ x ] All new and existing tests passed.
- [ x ] This is **NOT** translation related.

This is implements feature #156

I added a confirmation dialogue which pops up after tapping the delete source button. The popup displays the full name of the source to be deleted and allows the user to decide not to delete the source to prevent erroneous deletions.

I moved most of the logic into the viewholder. Can be easily reverted if you prefer.

All tests pass. I tested correct behavior in emulated versions of android API 25, 34 and 35.

Co-authored-by: Amine <amine.bouabdallaoui@pm.me>
Reviewed-on: https://gitea.amine-bouabdallaoui.fr/Louvorg/ReaderForSelfoss-multiplatform/pulls/185
Co-authored-by: davidoskky <davidoskky@yahoo.it>
Co-committed-by: davidoskky <davidoskky@yahoo.it>
---
 .../android/adapters/SourcesListAdapter.kt    | 127 ++++++++++--------
 .../src/main/res/values-ca-rES/strings.xml    |   2 +
 .../src/main/res/values-de-rDE/strings.xml    |   2 +
 .../src/main/res/values-es-rES/strings.xml    |   2 +
 .../src/main/res/values-fr-rFR/strings.xml    |   2 +
 .../src/main/res/values-gl-rES/strings.xml    |   2 +
 .../src/main/res/values-in-rID/strings.xml    |   2 +
 .../src/main/res/values-it-rIT/strings.xml    |   2 +
 .../src/main/res/values-ko-rKR/strings.xml    |   2 +
 .../src/main/res/values-nl-rNL/strings.xml    |   2 +
 .../src/main/res/values-pt-rBR/strings.xml    |   2 +
 .../src/main/res/values-pt-rPT/strings.xml    |   2 +
 .../src/main/res/values-si-rLK/strings.xml    |   2 +
 .../src/main/res/values-tr-rTR/strings.xml    |   2 +
 .../src/main/res/values-zh-rCN/strings.xml    |   2 +
 .../src/main/res/values-zh-rTW/strings.xml    |   2 +
 androidApp/src/main/res/values/strings.xml    |   2 +
 17 files changed, 104 insertions(+), 55 deletions(-)

diff --git a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/adapters/SourcesListAdapter.kt b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/adapters/SourcesListAdapter.kt
index 0aa6d1ae..03c4b7ef 100644
--- a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/adapters/SourcesListAdapter.kt
+++ b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/adapters/SourcesListAdapter.kt
@@ -6,9 +6,8 @@ import android.content.Intent
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
-import android.widget.Button
 import android.widget.Toast
-import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.appcompat.app.AlertDialog
 import androidx.recyclerview.widget.RecyclerView
 import bou.amine.apps.readerforselfossv2.android.R
 import bou.amine.apps.readerforselfossv2.android.UpsertSourceActivity
@@ -32,69 +31,21 @@ class SourcesListAdapter(
     private val items: ArrayList<SelfossModel.SourceDetail>,
 ) : RecyclerView.Adapter<SourcesListAdapter.ViewHolder>(),
     DIAware {
-    private val c: Context = app.baseContext
-    private lateinit var binding: SourceListItemBinding
-
     override val di: DI by closestDI(app)
-    private val repository: Repository by instance()
-    private val appSettingsService: AppSettingsService by instance()
 
     override fun onCreateViewHolder(
         parent: ViewGroup,
         viewType: Int,
     ): ViewHolder {
-        binding = SourceListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
-        return ViewHolder(binding.root)
+        val binding = SourceListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
+        return ViewHolder(binding)
     }
 
     override fun onBindViewHolder(
         holder: ViewHolder,
         position: Int,
     ) {
-        val itm = items[position]
-
-        val deleteBtn: Button = holder.mView.findViewById(R.id.deleteBtn)
-
-        deleteBtn.setOnClickListener {
-            val (id, title) = items[position]
-            CoroutineScope(Dispatchers.IO).launch {
-                val successfullyDeletedSource = repository.deleteSource(id, title)
-                if (successfullyDeletedSource) {
-                    items.removeAt(position)
-                    notifyItemRemoved(position)
-                    notifyItemRangeChanged(position, itemCount)
-                } else {
-                    Toast
-                        .makeText(
-                            app,
-                            R.string.can_delete_source,
-                            Toast.LENGTH_SHORT,
-                        ).show()
-                }
-            }
-        }
-
-        holder.mView.setOnClickListener {
-            val source = items[position]
-
-            repository.setSelectedSource(source)
-            app.startActivity(Intent(app, UpsertSourceActivity::class.java))
-        }
-
-        if (itm.getIcon(repository.baseUrl).isEmpty()) {
-            binding.itemImage.setBackgroundAndText(itm.title.getHtmlDecoded())
-        } else {
-            c.circularDrawable(itm.getIcon(repository.baseUrl), binding.itemImage, appSettingsService)
-        }
-
-        if (!itm.error.isNullOrBlank()) {
-            binding.errorText.visibility = View.VISIBLE
-            binding.errorText.text = itm.error
-        } else {
-            binding.errorText.visibility = View.GONE
-        }
-
-        binding.sourceTitle.text = itm.title.getHtmlDecoded()
+        holder.bind(items[position], position)
     }
 
     override fun getItemId(position: Int) = position.toLong()
@@ -104,6 +55,72 @@ class SourcesListAdapter(
     override fun getItemCount(): Int = items.size
 
     inner class ViewHolder(
-        val mView: ConstraintLayout,
-    ) : RecyclerView.ViewHolder(mView)
+        val binding: SourceListItemBinding,
+    ) : RecyclerView.ViewHolder(binding.root) {
+        private val context: Context = app.applicationContext
+        private val repository: Repository by instance()
+        private val appSettingsService: AppSettingsService by instance()
+
+        fun bind(
+            source: SelfossModel.SourceDetail,
+            position: Int,
+        ) {
+            binding.apply {
+                sourceTitle.text = source.title.getHtmlDecoded()
+                if (source.getIcon(repository.baseUrl).isEmpty()) {
+                    itemImage.setBackgroundAndText(source.title.getHtmlDecoded())
+                } else {
+                    context.circularDrawable(source.getIcon(repository.baseUrl), itemImage, appSettingsService)
+                }
+
+                errorText.apply {
+                    visibility = if (!source.error.isNullOrBlank()) View.VISIBLE else View.GONE
+                    text = source.error
+                }
+
+                deleteBtn.setOnClickListener { showDeleteConfirmationDialog(source, position) }
+
+                root.setOnClickListener {
+                    repository.setSelectedSource(source)
+                    app.startActivity(Intent(app, UpsertSourceActivity::class.java))
+                }
+            }
+        }
+
+        private fun showDeleteConfirmationDialog(
+            source: SelfossModel.SourceDetail,
+            position: Int,
+        ) {
+            AlertDialog
+                .Builder(app)
+                .setTitle(app.getString(R.string.confirm_delete_title))
+                .setMessage(app.getString(R.string.confirm_delete_message, source.title))
+                .setPositiveButton(android.R.string.ok) { _, _ -> deleteSource(source, position) }
+                .setNegativeButton(android.R.string.cancel, null)
+                .show()
+        }
+
+        private fun deleteSource(
+            source: SelfossModel.SourceDetail,
+            position: Int,
+        ) {
+            CoroutineScope(Dispatchers.IO).launch {
+                val successfullyDeletedSource = repository.deleteSource(source.id, source.title)
+                launch(Dispatchers.Main) {
+                    if (successfullyDeletedSource) {
+                        items.removeAt(position)
+                        notifyItemRemoved(position)
+                        notifyItemRangeChanged(position, itemCount)
+                    } else {
+                        Toast
+                            .makeText(
+                                app,
+                                R.string.can_delete_source,
+                                Toast.LENGTH_SHORT,
+                            ).show()
+                    }
+                }
+            }
+        }
+    }
 }
diff --git a/androidApp/src/main/res/values-ca-rES/strings.xml b/androidApp/src/main/res/values-ca-rES/strings.xml
index b49b5cab..c3bd1f70 100644
--- a/androidApp/src/main/res/values-ca-rES/strings.xml
+++ b/androidApp/src/main/res/values-ca-rES/strings.xml
@@ -129,4 +129,6 @@
     <string name="action_about">"Quant a"</string>
     <string name="marked_as_read">"Element llegit"</string>
     <string name="marked_as_unread">"Item unread"</string>
+    <string name="confirm_delete_title">Confirm Deletion</string>
+    <string name="confirm_delete_message">Are you sure you want to delete the following source?\n%s</string>
 </resources>
diff --git a/androidApp/src/main/res/values-de-rDE/strings.xml b/androidApp/src/main/res/values-de-rDE/strings.xml
index 9e672304..7dfe940a 100644
--- a/androidApp/src/main/res/values-de-rDE/strings.xml
+++ b/androidApp/src/main/res/values-de-rDE/strings.xml
@@ -129,4 +129,6 @@
     <string name="action_about">"Über"</string>
     <string name="marked_as_read">"Artikel gelesen"</string>
     <string name="marked_as_unread">"Item unread"</string>
+    <string name="confirm_delete_title">Confirm Deletion</string>
+    <string name="confirm_delete_message">Are you sure you want to delete the following source?\n%s</string>
 </resources>
diff --git a/androidApp/src/main/res/values-es-rES/strings.xml b/androidApp/src/main/res/values-es-rES/strings.xml
index 035c84d2..fb12df99 100644
--- a/androidApp/src/main/res/values-es-rES/strings.xml
+++ b/androidApp/src/main/res/values-es-rES/strings.xml
@@ -129,4 +129,6 @@
     <string name="action_about">"Acerca de"</string>
     <string name="marked_as_read">"Artículo leído"</string>
     <string name="marked_as_unread">"Artículo no leído"</string>
+    <string name="confirm_delete_title">Confirm Deletion</string>
+    <string name="confirm_delete_message">Are you sure you want to delete the following source?\n%s</string>
 </resources>
diff --git a/androidApp/src/main/res/values-fr-rFR/strings.xml b/androidApp/src/main/res/values-fr-rFR/strings.xml
index 2fc0366c..07d553a8 100644
--- a/androidApp/src/main/res/values-fr-rFR/strings.xml
+++ b/androidApp/src/main/res/values-fr-rFR/strings.xml
@@ -129,4 +129,6 @@
     <string name="action_about">"À propos"</string>
     <string name="marked_as_read">"Marqué comme lu"</string>
     <string name="marked_as_unread">"Marqué comme non lu"</string>
+    <string name="confirm_delete_title">Confirm Deletion</string>
+    <string name="confirm_delete_message">Are you sure you want to delete the following source?\n%s</string>
 </resources>
diff --git a/androidApp/src/main/res/values-gl-rES/strings.xml b/androidApp/src/main/res/values-gl-rES/strings.xml
index e3a3e389..e3576b03 100644
--- a/androidApp/src/main/res/values-gl-rES/strings.xml
+++ b/androidApp/src/main/res/values-gl-rES/strings.xml
@@ -129,4 +129,6 @@
     <string name="action_about">"Acerca de"</string>
     <string name="marked_as_read">"Elemento lido"</string>
     <string name="marked_as_unread">"Elemento non lido"</string>
+    <string name="confirm_delete_title">Confirm Deletion</string>
+    <string name="confirm_delete_message">Are you sure you want to delete the following source?\n%s</string>
 </resources>
diff --git a/androidApp/src/main/res/values-in-rID/strings.xml b/androidApp/src/main/res/values-in-rID/strings.xml
index 8175827f..30eeaef7 100644
--- a/androidApp/src/main/res/values-in-rID/strings.xml
+++ b/androidApp/src/main/res/values-in-rID/strings.xml
@@ -129,4 +129,6 @@
     <string name="action_about">"Tentang"</string>
     <string name="marked_as_read">"Membaca item"</string>
     <string name="marked_as_unread">"Item unread"</string>
+    <string name="confirm_delete_title">Confirm Deletion</string>
+    <string name="confirm_delete_message">Are you sure you want to delete the following source?\n%s</string>
 </resources>
diff --git a/androidApp/src/main/res/values-it-rIT/strings.xml b/androidApp/src/main/res/values-it-rIT/strings.xml
index 8bb17490..d11d45d3 100644
--- a/androidApp/src/main/res/values-it-rIT/strings.xml
+++ b/androidApp/src/main/res/values-it-rIT/strings.xml
@@ -129,4 +129,6 @@
     <string name="action_about">"Informazioni"</string>
     <string name="marked_as_read">"Articolo letto"</string>
     <string name="marked_as_unread">"Item unread"</string>
+    <string name="confirm_delete_title">Confirm Deletion</string>
+    <string name="confirm_delete_message">Are you sure you want to delete the following source?\n%s</string>
 </resources>
diff --git a/androidApp/src/main/res/values-ko-rKR/strings.xml b/androidApp/src/main/res/values-ko-rKR/strings.xml
index 66920664..63c81b1e 100644
--- a/androidApp/src/main/res/values-ko-rKR/strings.xml
+++ b/androidApp/src/main/res/values-ko-rKR/strings.xml
@@ -129,4 +129,6 @@
     <string name="action_about">"정보"</string>
     <string name="marked_as_read">"항목 읽기"</string>
     <string name="marked_as_unread">"Item unread"</string>
+    <string name="confirm_delete_title">Confirm Deletion</string>
+    <string name="confirm_delete_message">Are you sure you want to delete the following source?\n%s</string>
 </resources>
diff --git a/androidApp/src/main/res/values-nl-rNL/strings.xml b/androidApp/src/main/res/values-nl-rNL/strings.xml
index 43da71bb..3035383c 100644
--- a/androidApp/src/main/res/values-nl-rNL/strings.xml
+++ b/androidApp/src/main/res/values-nl-rNL/strings.xml
@@ -129,4 +129,6 @@
     <string name="action_about">"Over"</string>
     <string name="marked_as_read">"Artikel gelezen"</string>
     <string name="marked_as_unread">"Item unread"</string>
+    <string name="confirm_delete_title">Confirm Deletion</string>
+    <string name="confirm_delete_message">Are you sure you want to delete the following source?\n%s</string>
 </resources>
diff --git a/androidApp/src/main/res/values-pt-rBR/strings.xml b/androidApp/src/main/res/values-pt-rBR/strings.xml
index c847693f..d3019324 100644
--- a/androidApp/src/main/res/values-pt-rBR/strings.xml
+++ b/androidApp/src/main/res/values-pt-rBR/strings.xml
@@ -129,4 +129,6 @@
     <string name="action_about">"Sobre"</string>
     <string name="marked_as_read">"Item lido"</string>
     <string name="marked_as_unread">"Item unread"</string>
+    <string name="confirm_delete_title">Confirm Deletion</string>
+    <string name="confirm_delete_message">Are you sure you want to delete the following source?\n%s</string>
 </resources>
diff --git a/androidApp/src/main/res/values-pt-rPT/strings.xml b/androidApp/src/main/res/values-pt-rPT/strings.xml
index 41543a0e..fb4a81dc 100644
--- a/androidApp/src/main/res/values-pt-rPT/strings.xml
+++ b/androidApp/src/main/res/values-pt-rPT/strings.xml
@@ -129,4 +129,6 @@
     <string name="action_about">"Sobre"</string>
     <string name="marked_as_read">"Item lido"</string>
     <string name="marked_as_unread">"Item unread"</string>
+    <string name="confirm_delete_title">Confirm Deletion</string>
+    <string name="confirm_delete_message">Are you sure you want to delete the following source?\n%s</string>
 </resources>
diff --git a/androidApp/src/main/res/values-si-rLK/strings.xml b/androidApp/src/main/res/values-si-rLK/strings.xml
index 9ad0b919..56179362 100644
--- a/androidApp/src/main/res/values-si-rLK/strings.xml
+++ b/androidApp/src/main/res/values-si-rLK/strings.xml
@@ -129,4 +129,6 @@
     <string name="action_about">"මේ ගැන"</string>
     <string name="marked_as_read">"Item read"</string>
     <string name="marked_as_unread">"Item unread"</string>
+    <string name="confirm_delete_title">Confirm Deletion</string>
+    <string name="confirm_delete_message">Are you sure you want to delete the following source?\n%s</string>
 </resources>
diff --git a/androidApp/src/main/res/values-tr-rTR/strings.xml b/androidApp/src/main/res/values-tr-rTR/strings.xml
index 49252428..96b2912e 100644
--- a/androidApp/src/main/res/values-tr-rTR/strings.xml
+++ b/androidApp/src/main/res/values-tr-rTR/strings.xml
@@ -129,4 +129,6 @@
     <string name="action_about">"Hakkında"</string>
     <string name="marked_as_read">"Öğeleri oku"</string>
     <string name="marked_as_unread">"Item unread"</string>
+    <string name="confirm_delete_title">Confirm Deletion</string>
+    <string name="confirm_delete_message">Are you sure you want to delete the following source?\n%s</string>
 </resources>
diff --git a/androidApp/src/main/res/values-zh-rCN/strings.xml b/androidApp/src/main/res/values-zh-rCN/strings.xml
index f8a132c8..a1ab3457 100644
--- a/androidApp/src/main/res/values-zh-rCN/strings.xml
+++ b/androidApp/src/main/res/values-zh-rCN/strings.xml
@@ -129,4 +129,6 @@
     <string name="action_about">"关于我们"</string>
     <string name="marked_as_read">"已读"</string>
     <string name="marked_as_unread">"未读条目"</string>
+    <string name="confirm_delete_title">Confirm Deletion</string>
+    <string name="confirm_delete_message">Are you sure you want to delete the following source?\n%s</string>
 </resources>
diff --git a/androidApp/src/main/res/values-zh-rTW/strings.xml b/androidApp/src/main/res/values-zh-rTW/strings.xml
index 108e15fc..dbf21a08 100644
--- a/androidApp/src/main/res/values-zh-rTW/strings.xml
+++ b/androidApp/src/main/res/values-zh-rTW/strings.xml
@@ -129,4 +129,6 @@
     <string name="action_about">"关于我们"</string>
     <string name="marked_as_read">"已读"</string>
     <string name="marked_as_unread">"未讀項目"</string>
+    <string name="confirm_delete_title">Confirm Deletion</string>
+    <string name="confirm_delete_message">Are you sure you want to delete the following source?\n%s</string>
 </resources>
diff --git a/androidApp/src/main/res/values/strings.xml b/androidApp/src/main/res/values/strings.xml
index 8698e41c..d04a31ac 100644
--- a/androidApp/src/main/res/values/strings.xml
+++ b/androidApp/src/main/res/values/strings.xml
@@ -131,4 +131,6 @@
     <string name="action_about">"About"</string>
     <string name="marked_as_read">"Item read"</string>
     <string name="marked_as_unread">"Item unread"</string>
+    <string name="confirm_delete_title">Confirm Deletion</string>
+    <string name="confirm_delete_message">Are you sure you want to delete the following source?\n%s</string>
 </resources>