Simplify settings navigation and copy controls
This commit is contained in:
@@ -104,9 +104,6 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onNavigationItemSelected(item: MenuItem): Boolean {
|
override fun onNavigationItemSelected(item: MenuItem): Boolean {
|
||||||
if (item.itemId == R.id.nav_settings_header) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
navigateTo(item.itemId)
|
navigateTo(item.itemId)
|
||||||
if (!permanentSidebar) {
|
if (!permanentSidebar) {
|
||||||
binding.drawerLayout.closeDrawer(GravityCompat.START)
|
binding.drawerLayout.closeDrawer(GravityCompat.START)
|
||||||
@@ -149,12 +146,8 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
|
|||||||
val menu = navigationView.menu ?: return
|
val menu = navigationView.menu ?: return
|
||||||
for (index in 0 until menu.size()) {
|
for (index in 0 until menu.size()) {
|
||||||
val item = menu.getItem(index)
|
val item = menu.getItem(index)
|
||||||
if (item.itemId == R.id.nav_settings_header) {
|
item.isCheckable = true
|
||||||
item.isCheckable = false
|
item.isChecked = item.itemId == itemId
|
||||||
} else {
|
|
||||||
item.isCheckable = true
|
|
||||||
item.isChecked = item.itemId == itemId
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
navigationView.invalidate()
|
navigationView.invalidate()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,12 +5,18 @@ import android.content.ClipData
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.content.ComponentName
|
import android.content.ComponentName
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.graphics.drawable.ColorDrawable
|
||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.ArrayAdapter
|
import android.widget.ArrayAdapter
|
||||||
|
import android.widget.CheckBox
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
import android.widget.PopupWindow
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import com.google.android.material.switchmaterial.SwitchMaterial
|
import com.google.android.material.switchmaterial.SwitchMaterial
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import com.google.android.material.color.MaterialColors
|
||||||
import se.ajpanton.notificationlog.databinding.FragmentSettingsBinding
|
import se.ajpanton.notificationlog.databinding.FragmentSettingsBinding
|
||||||
import se.ajpanton.notificationlog.settings.LogField
|
import se.ajpanton.notificationlog.settings.LogField
|
||||||
import se.ajpanton.notificationlog.settings.LogViewSettingsStore
|
import se.ajpanton.notificationlog.settings.LogViewSettingsStore
|
||||||
@@ -122,48 +128,80 @@ class SettingsFragment : Fragment(R.layout.fragment_settings) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun setupCopyControls() {
|
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.adapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_dropdown_item, labels)
|
||||||
binding!!.copyFrom.onItemSelectedListener = object : android.widget.AdapterView.OnItemSelectedListener {
|
binding!!.copyFrom.onItemSelectedListener = object : android.widget.AdapterView.OnItemSelectedListener {
|
||||||
override fun onNothingSelected(parent: android.widget.AdapterView<*>?) = Unit
|
override fun onNothingSelected(parent: android.widget.AdapterView<*>?) = Unit
|
||||||
override fun onItemSelected(parent: android.widget.AdapterView<*>?, view: View?, position: Int, id: Long) {
|
override fun onItemSelected(parent: android.widget.AdapterView<*>?, view: View?, position: Int, id: Long) {
|
||||||
selectedCopyTargets = emptySet()
|
selectedCopyTargets = emptySet()
|
||||||
binding!!.copyTo.isEnabled = position > 0
|
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 {
|
binding!!.copyEventSettings.setOnClickListener {
|
||||||
LoggingRuleStore(requireContext()).copy(LoggingType.entries[binding!!.copyFrom.selectedItemPosition - 1], selectedCopyTargets)
|
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 targets = LoggingType.entries.filterNot { it == source }
|
||||||
val checked = BooleanArray(targets.size) { targets[it] in selectedCopyTargets }
|
val popupContent = LinearLayout(requireContext()).apply {
|
||||||
val dialog = MaterialAlertDialogBuilder(requireContext())
|
orientation = LinearLayout.VERTICAL
|
||||||
.setTitle("Copy ${source.label()} settings to")
|
setPadding(dp(8), dp(8), dp(8), dp(8))
|
||||||
.setMultiChoiceItems(targets.map { it.label() }.toTypedArray(), checked) { _, index, selected -> checked[index] = selected }
|
}
|
||||||
.setNegativeButton("Cancel", null)
|
val popup = PopupWindow(popupContent, binding!!.copyTo.width.coerceAtLeast(dp(200)), LinearLayout.LayoutParams.WRAP_CONTENT, true).apply {
|
||||||
.setNeutralButton("All", null)
|
isOutsideTouchable = true
|
||||||
.setPositiveButton("Done") { _, _ ->
|
elevation = dp(8).toFloat()
|
||||||
selectedCopyTargets = targets.filterIndexed { index, _ -> checked[index] }.toSet()
|
setBackgroundDrawable(ColorDrawable(MaterialColors.getColor(requireContext(), com.google.android.material.R.attr.colorSurface, Color.WHITE)))
|
||||||
updateCopyButton()
|
}
|
||||||
|
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 {
|
popupContent.addView(View(requireContext()).apply {
|
||||||
dialog.getButton(androidx.appcompat.app.AlertDialog.BUTTON_NEUTRAL).setOnClickListener {
|
layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 1).apply {
|
||||||
val selectAll = checked.any { !it }
|
setMargins(0, dp(4), 0, dp(4))
|
||||||
checked.indices.forEach { index ->
|
}
|
||||||
checked[index] = selectAll
|
setBackgroundColor(0x33000000)
|
||||||
dialog.listView.setItemChecked(index, selectAll)
|
})
|
||||||
|
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)
|
private fun isListenerEnabled(): Boolean = requireContext().getSystemService(android.app.NotificationManager::class.java)
|
||||||
.isNotificationListenerAccessGranted(ComponentName(requireContext(), NotificationCaptureService::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 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") }
|
private enum class ExportFormat(val extension: String) { CSV("csv"), FORMATTED("txt"), HTML_ZIP("zip") }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,19 +54,48 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="24dp"
|
android:layout_marginTop="24dp"
|
||||||
android:text="Copy event settings" />
|
android:text="Copy settings between pages" />
|
||||||
|
|
||||||
<Spinner
|
<LinearLayout
|
||||||
android:id="@+id/copy_from"
|
|
||||||
android:layout_width="match_parent"
|
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:layout_height="wrap_content"
|
||||||
android:enabled="false"
|
android:gravity="center_vertical"
|
||||||
android:text="Choose targets" />
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Copy from" />
|
||||||
|
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/copy_from"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="to" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/copy_to"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:enabled="false"
|
||||||
|
android:gravity="start|center_vertical"
|
||||||
|
android:text="Destination" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/copy_event_settings"
|
android:id="@+id/copy_event_settings"
|
||||||
|
|||||||
@@ -5,15 +5,10 @@
|
|||||||
android:id="@+id/nav_view_logs"
|
android:id="@+id/nav_view_logs"
|
||||||
android:title="@string/page_view_logs" />
|
android:title="@string/page_view_logs" />
|
||||||
</group>
|
</group>
|
||||||
<item
|
|
||||||
android:id="@+id/nav_settings_header"
|
|
||||||
android:checkable="false"
|
|
||||||
android:enabled="false"
|
|
||||||
android:title="@string/navigation_settings_header" />
|
|
||||||
<group android:checkableBehavior="single">
|
<group android:checkableBehavior="single">
|
||||||
<item
|
<item
|
||||||
android:id="@+id/nav_settings"
|
android:id="@+id/nav_settings"
|
||||||
android:title="@string/navigation_indented_settings" />
|
android:title="@string/navigation_settings_header" />
|
||||||
<item
|
<item
|
||||||
android:id="@+id/nav_appearing"
|
android:id="@+id/nav_appearing"
|
||||||
android:title="@string/navigation_indented_appearing" />
|
android:title="@string/navigation_indented_appearing" />
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<string name="notification_listener_label">Notification Log listener</string>
|
<string name="notification_listener_label">Notification Log listener</string>
|
||||||
<string name="navigation_open">Open navigation</string>
|
<string name="navigation_open">Open navigation</string>
|
||||||
<string name="navigation_close">Close navigation</string>
|
<string name="navigation_close">Close navigation</string>
|
||||||
<string name="navigation_settings_header">Settings:</string>
|
<string name="navigation_settings_header">Settings</string>
|
||||||
<string name="page_view_logs">View logs</string>
|
<string name="page_view_logs">View logs</string>
|
||||||
<string name="page_settings">Settings</string>
|
<string name="page_settings">Settings</string>
|
||||||
<string name="page_appearing">Appearing</string>
|
<string name="page_appearing">Appearing</string>
|
||||||
@@ -13,7 +13,6 @@
|
|||||||
<string name="page_text_content">Text content</string>
|
<string name="page_text_content">Text content</string>
|
||||||
<string name="page_image_content">Image content</string>
|
<string name="page_image_content">Image content</string>
|
||||||
<string name="page_edits">Edits</string>
|
<string name="page_edits">Edits</string>
|
||||||
<string name="navigation_indented_settings">    Settings</string>
|
|
||||||
<string name="navigation_indented_appearing">    Appearing</string>
|
<string name="navigation_indented_appearing">    Appearing</string>
|
||||||
<string name="navigation_indented_disappearing">    Disappearing</string>
|
<string name="navigation_indented_disappearing">    Disappearing</string>
|
||||||
<string name="navigation_indented_text_content">    Text content</string>
|
<string name="navigation_indented_text_content">    Text content</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user