Simplify settings navigation and copy controls

This commit is contained in:
ajp_anton
2026-07-26 14:38:40 +00:00
parent 14a96046f7
commit c5f3dade9f
5 changed files with 105 additions and 49 deletions
@@ -5,12 +5,18 @@ import android.content.ClipData
import android.net.Uri
import android.content.ComponentName
import android.content.Intent
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.provider.Settings
import android.view.View
import android.widget.ArrayAdapter
import android.widget.CheckBox
import android.widget.LinearLayout
import android.widget.PopupWindow
import androidx.fragment.app.Fragment
import com.google.android.material.switchmaterial.SwitchMaterial
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.color.MaterialColors
import se.ajpanton.notificationlog.databinding.FragmentSettingsBinding
import se.ajpanton.notificationlog.settings.LogField
import se.ajpanton.notificationlog.settings.LogViewSettingsStore
@@ -122,48 +128,80 @@ class SettingsFragment : Fragment(R.layout.fragment_settings) {
}
private fun setupCopyControls() {
val labels = listOf("From") + LoggingType.entries.map { it.label() }
val labels = listOf("Source") + LoggingType.entries.map { it.label() }
binding!!.copyFrom.adapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_dropdown_item, labels)
binding!!.copyFrom.onItemSelectedListener = object : android.widget.AdapterView.OnItemSelectedListener {
override fun onNothingSelected(parent: android.widget.AdapterView<*>?) = Unit
override fun onItemSelected(parent: android.widget.AdapterView<*>?, view: View?, position: Int, id: Long) {
selectedCopyTargets = emptySet()
binding!!.copyTo.isEnabled = position > 0
updateCopyButton()
binding!!.copyTo.text = "Destination"
updateCopyControls()
}
}
binding!!.copyTo.setOnClickListener { chooseCopyTargets(LoggingType.entries[binding!!.copyFrom.selectedItemPosition - 1]) }
binding!!.copyTo.setOnClickListener { showDestinationDropdown(LoggingType.entries[binding!!.copyFrom.selectedItemPosition - 1]) }
binding!!.copyEventSettings.setOnClickListener {
LoggingRuleStore(requireContext()).copy(LoggingType.entries[binding!!.copyFrom.selectedItemPosition - 1], selectedCopyTargets)
}
}
private fun chooseCopyTargets(source: LoggingType) {
private fun showDestinationDropdown(source: LoggingType) {
val targets = LoggingType.entries.filterNot { it == source }
val checked = BooleanArray(targets.size) { targets[it] in selectedCopyTargets }
val dialog = MaterialAlertDialogBuilder(requireContext())
.setTitle("Copy ${source.label()} settings to")
.setMultiChoiceItems(targets.map { it.label() }.toTypedArray(), checked) { _, index, selected -> checked[index] = selected }
.setNegativeButton("Cancel", null)
.setNeutralButton("All", null)
.setPositiveButton("Done") { _, _ ->
selectedCopyTargets = targets.filterIndexed { index, _ -> checked[index] }.toSet()
updateCopyButton()
val popupContent = LinearLayout(requireContext()).apply {
orientation = LinearLayout.VERTICAL
setPadding(dp(8), dp(8), dp(8), dp(8))
}
val popup = PopupWindow(popupContent, binding!!.copyTo.width.coerceAtLeast(dp(200)), LinearLayout.LayoutParams.WRAP_CONTENT, true).apply {
isOutsideTouchable = true
elevation = dp(8).toFloat()
setBackgroundDrawable(ColorDrawable(MaterialColors.getColor(requireContext(), com.google.android.material.R.attr.colorSurface, Color.WHITE)))
}
val boxes = mutableListOf<CheckBox>()
popupContent.addView(android.widget.Button(requireContext()).apply {
text = "All"
setOnClickListener {
val selectAll = selectedCopyTargets.size != targets.size
selectedCopyTargets = if (selectAll) targets.toSet() else emptySet()
boxes.forEachIndexed { index, box -> box.isChecked = targets[index] in selectedCopyTargets }
updateCopyControls()
}
.create()
dialog.setOnShowListener {
dialog.getButton(androidx.appcompat.app.AlertDialog.BUTTON_NEUTRAL).setOnClickListener {
val selectAll = checked.any { !it }
checked.indices.forEach { index ->
checked[index] = selectAll
dialog.listView.setItemChecked(index, selectAll)
})
popupContent.addView(View(requireContext()).apply {
layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 1).apply {
setMargins(0, dp(4), 0, dp(4))
}
setBackgroundColor(0x33000000)
})
targets.forEach { target ->
val box = CheckBox(requireContext()).apply {
text = target.label()
isChecked = target in selectedCopyTargets
setOnCheckedChangeListener { _, checked ->
selectedCopyTargets = selectedCopyTargets.toMutableSet().apply {
if (checked) add(target) else remove(target)
}
updateCopyControls()
}
}
boxes += box
popupContent.addView(box)
}
dialog.show()
popup.showAsDropDown(binding!!.copyTo)
}
private fun updateCopyButton() { binding?.copyEventSettings?.isEnabled = selectedCopyTargets.isNotEmpty() }
private fun updateCopyControls() {
val currentBinding = binding ?: return
val sourceChosen = currentBinding.copyFrom.selectedItemPosition > 0
currentBinding.copyTo.isEnabled = sourceChosen
currentBinding.copyTo.text = destinationLabel()
currentBinding.copyEventSettings.isEnabled = sourceChosen && selectedCopyTargets.isNotEmpty()
}
private fun destinationLabel(): String = when (selectedCopyTargets.size) {
0 -> "Destination"
1 -> selectedCopyTargets.first().label()
else -> "${selectedCopyTargets.sortedBy { it.ordinal }.first().label()}..."
}
private fun isListenerEnabled(): Boolean = requireContext().getSystemService(android.app.NotificationManager::class.java)
.isNotificationListenerAccessGranted(ComponentName(requireContext(), NotificationCaptureService::class.java))
@@ -229,5 +267,7 @@ class SettingsFragment : Fragment(R.layout.fragment_settings) {
private fun LoggingType.label() = name.lowercase().replace('_', ' ').replaceFirstChar(Char::uppercase)
private fun dp(value: Int): Int = (value * resources.displayMetrics.density).toInt()
private enum class ExportFormat(val extension: String) { CSV("csv"), FORMATTED("txt"), HTML_ZIP("zip") }
}