Complete settings copy and field ordering controls

This commit is contained in:
ajp_anton
2026-07-23 10:41:20 +00:00
parent 2709c2e92d
commit a65fa80903
2 changed files with 36 additions and 10 deletions
@@ -1,6 +1,7 @@
package se.ajpanton.notificationlog package se.ajpanton.notificationlog
import android.os.Bundle import android.os.Bundle
import android.content.ClipData
import android.view.View import android.view.View
import android.widget.ArrayAdapter import android.widget.ArrayAdapter
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
@@ -16,12 +17,13 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
class SettingsFragment : Fragment(R.layout.fragment_settings) { class SettingsFragment : Fragment(R.layout.fragment_settings) {
private var binding: FragmentSettingsBinding? = null private var binding: FragmentSettingsBinding? = null
private var selectedCopyTargets = emptySet<LoggingType>()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
binding = FragmentSettingsBinding.bind(view) binding = FragmentSettingsBinding.bind(view)
val store = LogViewSettingsStore(requireContext()) val store = LogViewSettingsStore(requireContext())
var settings = store.load() var settings = store.load()
LogField.entries.forEach { field -> settings.order.forEach { field ->
binding!!.fieldToggles.addView(SwitchMaterial(requireContext()).apply { binding!!.fieldToggles.addView(SwitchMaterial(requireContext()).apply {
text = when (field) { text = when (field) {
LogField.TIMESTAMP -> "Timestamp"; LogField.APP_NAME -> "App name" LogField.TIMESTAMP -> "Timestamp"; LogField.APP_NAME -> "App name"
@@ -29,6 +31,11 @@ class SettingsFragment : Fragment(R.layout.fragment_settings) {
LogField.CONTENTS -> "Contents of the notification" LogField.CONTENTS -> "Contents of the notification"
} }
isChecked = field in settings.visibleFields isChecked = field in settings.visibleFields
tag = field
setOnLongClickListener {
startDragAndDrop(ClipData.newPlainText("field", field.name), View.DragShadowBuilder(this), this, 0)
true
}
setOnCheckedChangeListener { _, checked -> setOnCheckedChangeListener { _, checked ->
settings = settings.copy(visibleFields = settings.visibleFields.toMutableSet().apply { settings = settings.copy(visibleFields = settings.visibleFields.toMutableSet().apply {
if (checked) add(field) else remove(field) if (checked) add(field) else remove(field)
@@ -37,6 +44,16 @@ class SettingsFragment : Fragment(R.layout.fragment_settings) {
} }
}) })
} }
binding!!.fieldToggles.setOnDragListener { _, event ->
if (event.action != android.view.DragEvent.ACTION_DROP) return@setOnDragListener true
val source = event.localState as? View ?: return@setOnDragListener false
val container = binding!!.fieldToggles
val index = (0 until container.childCount).firstOrNull { event.y < container.getChildAt(it).bottom } ?: container.childCount
container.removeView(source); container.addView(source, index.coerceAtMost(container.childCount))
settings = settings.copy(order = (0 until container.childCount).map { container.getChildAt(it).tag as LogField })
store.save(settings)
true
}
val labels = listOf("Current local timezone", "UTC", "Local timezone when event happened") val labels = listOf("Current local timezone", "UTC", "Local timezone when event happened")
binding!!.timezone.adapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_dropdown_item, labels) binding!!.timezone.adapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_dropdown_item, labels)
binding!!.timezone.setSelection(TimestampZone.entries.indexOf(settings.timestampZone)) binding!!.timezone.setSelection(TimestampZone.entries.indexOf(settings.timestampZone))
@@ -46,19 +63,26 @@ class SettingsFragment : Fragment(R.layout.fragment_settings) {
settings = settings.copy(timestampZone = TimestampZone.entries[position]); store.save(settings) settings = settings.copy(timestampZone = TimestampZone.entries[position]); store.save(settings)
} }
} }
binding!!.copyEventSettings.setOnClickListener { chooseCopySource() } setupCopyControls()
val lockStore = AppLockStore(requireContext()) val lockStore = AppLockStore(requireContext())
binding!!.appLock.isChecked = lockStore.enabled binding!!.appLock.isChecked = lockStore.enabled
binding!!.appLock.setOnCheckedChangeListener { _, enabled -> lockStore.enabled = enabled } binding!!.appLock.setOnCheckedChangeListener { _, enabled -> lockStore.enabled = enabled }
} }
override fun onDestroyView() { binding = null; super.onDestroyView() } override fun onDestroyView() { binding = null; super.onDestroyView() }
private fun chooseCopySource() { private fun setupCopyControls() {
val types = LoggingType.entries val labels = listOf("From") + LoggingType.entries.map { it.label() }
MaterialAlertDialogBuilder(requireContext()) binding!!.copyFrom.adapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_dropdown_item, labels)
.setTitle("Copy settings from") binding!!.copyFrom.onItemSelectedListener = object : android.widget.AdapterView.OnItemSelectedListener {
.setItems(types.map { it.label() }.toTypedArray()) { _, index -> chooseCopyTargets(types[index]) } override fun onNothingSelected(parent: android.widget.AdapterView<*>?) = Unit
.show() override fun onItemSelected(parent: android.widget.AdapterView<*>?, view: View?, position: Int, id: Long) {
selectedCopyTargets = emptySet(); binding!!.copyTo.isEnabled = position > 0; updateCopyButton()
}
}
binding!!.copyTo.setOnClickListener { chooseCopyTargets(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 chooseCopyTargets(source: LoggingType) {
@@ -69,9 +93,11 @@ class SettingsFragment : Fragment(R.layout.fragment_settings) {
.setMultiChoiceItems(targets.map { it.label() }.toTypedArray(), checked) { _, index, selected -> checked[index] = selected } .setMultiChoiceItems(targets.map { it.label() }.toTypedArray(), checked) { _, index, selected -> checked[index] = selected }
.setNegativeButton("Cancel", null) .setNegativeButton("Cancel", null)
.setPositiveButton("Copy") { _, _ -> .setPositiveButton("Copy") { _, _ ->
LoggingRuleStore(requireContext()).copy(source, targets.filterIndexed { index, _ -> checked[index] }.toSet()) selectedCopyTargets = targets.filterIndexed { index, _ -> checked[index] }.toSet(); updateCopyButton()
}.show() }.show()
} }
private fun updateCopyButton() { binding?.copyEventSettings?.isEnabled = selectedCopyTargets.isNotEmpty() }
private fun LoggingType.label() = name.lowercase().replace('_', ' ').replaceFirstChar(Char::uppercase) private fun LoggingType.label() = name.lowercase().replace('_', ' ').replaceFirstChar(Char::uppercase)
} }
@@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"><LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="@dimen/page_padding"><TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Settings" android:textAppearance="?attr/textAppearanceHeadline5"/><TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="24dp" android:text="Show on each log line"/><LinearLayout android:id="@+id/field_toggles" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"/><TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="24dp" android:text="Timestamp timezone"/><Spinner android:id="@+id/timezone" android:layout_width="match_parent" android:layout_height="wrap_content"/><com.google.android.material.switchmaterial.SwitchMaterial android:id="@+id/app_lock" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="24dp" android:text="Lock app with phone unlock"/><Button android:id="@+id/copy_event_settings" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="24dp" android:text="Copy settings"/></LinearLayout></ScrollView> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"><LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="@dimen/page_padding"><TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Settings" android:textAppearance="?attr/textAppearanceHeadline5"/><TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="24dp" android:text="Show on each log line (long-press and drag to reorder)"/><LinearLayout android:id="@+id/field_toggles" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"/><TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="24dp" android:text="Timestamp timezone"/><Spinner android:id="@+id/timezone" android:layout_width="match_parent" android:layout_height="wrap_content"/><com.google.android.material.switchmaterial.SwitchMaterial android:id="@+id/app_lock" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="24dp" android:text="Lock app with phone unlock"/><TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="24dp" android:text="Copy event settings"/><Spinner android:id="@+id/copy_from" android:layout_width="match_parent" android:layout_height="wrap_content"/><Button android:id="@+id/copy_to" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Choose targets" android:enabled="false"/><Button android:id="@+id/copy_event_settings" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Copy settings" android:enabled="false"/></LinearLayout></ScrollView>