Reassign all mappings to chosen group when disabling groups

This commit is contained in:
fgerber 2024-04-08 17:44:49 +02:00
parent 59a72e0544
commit ddef61a0cf
10 changed files with 125 additions and 23 deletions

View File

@ -15,6 +15,7 @@ import net.helcel.beans.countries.GeoLoc
import net.helcel.beans.databinding.ItemListGeolocBinding import net.helcel.beans.databinding.ItemListGeolocBinding
import net.helcel.beans.helper.AUTO_GROUP import net.helcel.beans.helper.AUTO_GROUP
import net.helcel.beans.helper.Data import net.helcel.beans.helper.Data
import net.helcel.beans.helper.DialogCloser
import net.helcel.beans.helper.NO_GROUP import net.helcel.beans.helper.NO_GROUP
import net.helcel.beans.helper.Settings import net.helcel.beans.helper.Settings
import net.helcel.beans.helper.Theme.colorWrapper import net.helcel.beans.helper.Theme.colorWrapper
@ -52,7 +53,7 @@ class GeolocListAdapter(
private val _binding: ItemListGeolocBinding, private val _binding: ItemListGeolocBinding,
private val _parentHolder: FoldingListViewHolder? = null, private val _parentHolder: FoldingListViewHolder? = null,
private val _parentGeoLoc: GeoLoc, private val _parentGeoLoc: GeoLoc,
) : RecyclerView.ViewHolder(_binding.root) { ) : RecyclerView.ViewHolder(_binding.root), DialogCloser {
private fun bindGroup(el: GeoLoc) { private fun bindGroup(el: GeoLoc) {
refreshCount(el) refreshCount(el)
@ -86,11 +87,11 @@ class GeolocListAdapter(
if (_binding.checkBox.isChecked) { if (_binding.checkBox.isChecked) {
// If one has just checked the box (assign unique group) // If one has just checked the box (assign unique group)
Data.selected_group = Data.groups.getUniqueEntry() Data.selected_group = Data.groups.getUniqueEntry()
onColorDialogDismiss(false) onDialogDismiss(false)
} else { } else {
// If one has just unchecked the box (unassign unique group) // If one has just unchecked the box (unassign unique group)
Data.selected_group = null Data.selected_group = null
onColorDialogDismiss(true) onDialogDismiss(true)
} }
} else { } else {
Data.selected_group = null Data.selected_group = null
@ -103,7 +104,7 @@ class GeolocListAdapter(
} }
} }
fun onColorDialogDismiss(clear: Boolean) { override fun onDialogDismiss(clear: Boolean) {
if (clear) { if (clear) {
Data.visits.setVisited(Data.selected_geoloc, NO_GROUP) Data.visits.setVisited(Data.selected_geoloc, NO_GROUP)
Data.saveData() Data.saveData()

View File

@ -13,7 +13,8 @@ import net.helcel.beans.helper.Theme.getContrastColor
class GroupListAdapter( class GroupListAdapter(
private val activity: FragmentActivity, private val activity: FragmentActivity,
private val selectDialog: DialogFragment private val selectDialog: DialogFragment,
private val delete: Boolean = false
) : RecyclerView.Adapter<GroupListAdapter.GroupViewHolder>() { ) : RecyclerView.Adapter<GroupListAdapter.GroupViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GroupViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GroupViewHolder {
@ -63,6 +64,7 @@ class GroupListAdapter(
Data.selected_group = entry.second Data.selected_group = entry.second
selectDialog.dismiss() selectDialog.dismiss()
} }
if (!delete) {
_binding.groupColor.setOnLongClickListener { _binding.groupColor.setOnLongClickListener {
dialogFragment.show( dialogFragment.show(
activity.supportFragmentManager, activity.supportFragmentManager,
@ -72,4 +74,5 @@ class GroupListAdapter(
} }
} }
} }
}
} }

View File

@ -52,8 +52,8 @@ class EditGroupAddFragment(
.setPositiveButton(android.R.string.ok) { _, _ -> .setPositiveButton(android.R.string.ok) { _, _ ->
val pos = Data.groups.findGroupPos(key) val pos = Data.groups.findGroupPos(key)
// Remove all countries belonging to that group // Remove all countries belonging to that group
// Delete the group
Data.visits.deleteVisited(key) Data.visits.deleteVisited(key)
// Delete the group
Data.groups.deleteGroup(key) Data.groups.deleteGroup(key)
Data.saveData() Data.saveData()
onDelCb(pos) onDelCb(pos)

View File

@ -3,17 +3,19 @@ package net.helcel.beans.activity.fragment
import android.app.Dialog import android.app.Dialog
import android.content.DialogInterface import android.content.DialogInterface
import android.os.Bundle import android.os.Bundle
import android.view.View
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import net.helcel.beans.activity.adapter.GeolocListAdapter import net.helcel.beans.R
import net.helcel.beans.activity.adapter.GroupListAdapter import net.helcel.beans.activity.adapter.GroupListAdapter
import net.helcel.beans.databinding.FragmentEditPlacesColorsBinding import net.helcel.beans.databinding.FragmentEditPlacesColorsBinding
import net.helcel.beans.helper.Data import net.helcel.beans.helper.Data
import net.helcel.beans.helper.DialogCloser
class EditPlaceColorFragment(private val parent: GeolocListAdapter.FoldingListViewHolder) : class EditPlaceColorFragment(private val parent: DialogCloser, private val delete: Boolean = false) :
DialogFragment() { DialogFragment() {
private lateinit var _binding: FragmentEditPlacesColorsBinding private lateinit var _binding: FragmentEditPlacesColorsBinding
@ -21,7 +23,8 @@ class EditPlaceColorFragment(private val parent: GeolocListAdapter.FoldingListVi
private var clear: Boolean = false private var clear: Boolean = false
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val builder = MaterialAlertDialogBuilder(requireContext()) val ctx = requireContext()
val builder = MaterialAlertDialogBuilder(ctx)
_binding = FragmentEditPlacesColorsBinding.inflate(layoutInflater) _binding = FragmentEditPlacesColorsBinding.inflate(layoutInflater)
_binding.btnAdd.setOnClickListener { _binding.btnAdd.setOnClickListener {
EditGroupAddFragment(0, { EditGroupAddFragment(0, {
@ -34,16 +37,25 @@ class EditPlaceColorFragment(private val parent: GeolocListAdapter.FoldingListVi
} }
val dialog = builder.setView(_binding.root).create() val dialog = builder.setView(_binding.root).create()
listAdapt = GroupListAdapter(requireActivity(), this) listAdapt = GroupListAdapter(requireActivity(), this, delete)
_binding.groupsColor.layoutManager = _binding.groupsColor.layoutManager =
LinearLayoutManager(requireContext(), RecyclerView.VERTICAL, false) LinearLayoutManager(ctx, RecyclerView.VERTICAL, false)
_binding.groupsColor.adapter = listAdapt _binding.groupsColor.adapter = listAdapt
if (delete) {
_binding.btnAdd.visibility = View.GONE
_binding.btnClear.text = ctx.getString(R.string.cancel)
with (_binding.warningText) {
visibility = View.VISIBLE
text = ctx.getString(R.string.select_group)
}
}
return dialog return dialog
} }
override fun onDismiss(dialog: DialogInterface) { override fun onDismiss(dialog: DialogInterface) {
super.onDismiss(dialog) super.onDismiss(dialog)
parent.onColorDialogDismiss(clear) parent.onDialogDismiss(clear)
} }
} }

View File

@ -1,19 +1,52 @@
package net.helcel.beans.activity.fragment package net.helcel.beans.activity.fragment
import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.content.DialogInterface
import android.os.Bundle import android.os.Bundle
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceManager
import net.helcel.beans.R import net.helcel.beans.R
import net.helcel.beans.countries.GeoLocImporter import net.helcel.beans.countries.GeoLocImporter
import net.helcel.beans.helper.Data
import net.helcel.beans.helper.DialogCloser
import net.helcel.beans.helper.Settings
class SettingsFragment : PreferenceFragmentCompat() { class SettingsFragment : PreferenceFragmentCompat(), DialogCloser {
private var savedInstanceState: Bundle? = null
private var rootKey: String? = null
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
this.savedInstanceState = savedInstanceState
this.rootKey = rootKey
setPreferencesFromResource(R.xml.fragment_settings, rootKey) setPreferencesFromResource(R.xml.fragment_settings, rootKey)
val ctx = requireContext() val ctx = requireContext()
// Select Light/Dark/System Mode
findPreference<Preference>(getString(R.string.key_theme))?.setOnPreferenceChangeListener { _, key ->
setTheme(ctx, key as String)
}
// Toggle groups
findPreference<Preference>(getString(R.string.key_group))?.setOnPreferenceChangeListener { _, key ->
if (key as String == ctx.getString(R.string.off)) {
val fragment = EditPlaceColorFragment(this, true)
fragment.show(
this.parentFragmentManager,
"AddColorDialogFragment"
)
false
} else {
true
}
}
// Toggle regional geolocs
findPreference<Preference>(getString(R.string.key_regional))?.setOnPreferenceChangeListener { _, key -> findPreference<Preference>(getString(R.string.key_regional))?.setOnPreferenceChangeListener { _, key ->
when (key as String) { when (key as String) {
ctx.getString(R.string.off) -> GeoLocImporter.clearStates() ctx.getString(R.string.off) -> GeoLocImporter.clearStates()
@ -22,10 +55,6 @@ class SettingsFragment : PreferenceFragmentCompat() {
true true
} }
// Select Light/Dark/System Mode
findPreference<Preference>(getString(R.string.key_theme))?.setOnPreferenceChangeListener { _, key ->
setTheme(ctx, key as String)
}
// Open license fragment // Open license fragment
findPreference<Preference>(getString(R.string.licenses))?.setOnPreferenceClickListener { findPreference<Preference>(getString(R.string.licenses))?.setOnPreferenceClickListener {
@ -58,4 +87,30 @@ class SettingsFragment : PreferenceFragmentCompat() {
return true return true
} }
} }
override fun onDialogDismiss(clear: Boolean) {
// When turning groups off, select one group to keep and reassign everything
Data.selected_group?.let { selectedGroup ->
// Reassign all visited that are not to selectedGroup to selectedGroup
Data.visits.reassignAllVisitedtoGroup(selectedGroup.key)
// Delete all groups that are not selectedGroup
Data.groups.deleteAllExcept(selectedGroup.key)
// Save and clear global variables
Data.saveData()
Data.selected_geoloc = null
Data.selected_group = null
// Actually change preference
val ctx = requireContext()
val sp = PreferenceManager.getDefaultSharedPreferences(ctx)
sp.edit().putString(ctx.getString(R.string.key_group), ctx.getString(R.string.off))
.commit()
// Refresh entire preference fragment to reflect changes
preferenceScreen.removeAll()
onCreatePreferences(savedInstanceState, rootKey)
}
}
} }

View File

@ -0,0 +1,5 @@
package net.helcel.beans.helper
interface DialogCloser {
fun onDialogDismiss(clear: Boolean)
}

View File

@ -28,6 +28,11 @@ class Groups(val id: Int, private val grps: HashMap<Int, Group>) {
grps.remove(key) grps.remove(key)
} }
fun deleteAllExcept(grp: Int) {
val keysToDelete = grps.keys.filter { it != grp }
keysToDelete.forEach { grps.remove(it) }
}
fun getGroupFromKey(key: Int): Group { fun getGroupFromKey(key: Int): Group {
return grps.getOrDefault(key, EmptyGroup()) return grps.getOrDefault(key, EmptyGroup())
} }
@ -60,6 +65,10 @@ class Groups(val id: Int, private val grps: HashMap<Int, Group>) {
return grps.keys.toList().indexOf(key) return grps.keys.toList().indexOf(key)
} }
fun forEach(action: (Map.Entry<Int, Group>) -> Unit) {
grps.forEach { action(it) }
}
class EmptyGroup : Group(0, "") class EmptyGroup : Group(0, "")
@Serializable @Serializable

View File

@ -42,6 +42,15 @@ class Visits(val id: Int, private val locs: HashMap<String, Int>) {
return locs.keys.groupBy { getVisited(it) } return locs.keys.groupBy { getVisited(it) }
} }
fun reassignAllVisitedtoGroup(group: Int) {
val keys = locs.filter { (_, grp) ->
grp !in listOf(NO_GROUP, AUTO_GROUP)
}.keys
keys.forEach {
locs[it] = group
}
}
@OptIn(ExperimentalSerializationApi::class) @OptIn(ExperimentalSerializationApi::class)
@Serializer(Visits::class) @Serializer(Visits::class)
class VisitsSerializer { class VisitsSerializer {

View File

@ -6,6 +6,13 @@
android:orientation="vertical" android:orientation="vertical"
android:padding="16dp"> android:padding="16dp">
<TextView
android:id="@+id/warning_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:visibility="gone" />
<ScrollView <ScrollView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View File

@ -21,6 +21,7 @@
<string name="foss_licenses">Free and open source dependencies and licenses</string> <string name="foss_licenses">Free and open source dependencies and licenses</string>
<string name="about_beans">About the Beans application</string> <string name="about_beans">About the Beans application</string>
<string name="delete_group">Are your sure you want to delete this group and remove all its country mappings?</string> <string name="delete_group">Are your sure you want to delete this group and remove all its country mappings?</string>
<string name="select_group">Select one group you want to keep. All others will be deleted and its mappings reassigned to the group you choose here.</string>
<string name="add">Add</string> <string name="add">Add</string>
<string name="clear">Clear</string> <string name="clear">Clear</string>
<string name="logo">Logo</string> <string name="logo">Logo</string>