diff --git a/app/src/main/java/se/ajpanton/notificationlog/MainActivity.kt b/app/src/main/java/se/ajpanton/notificationlog/MainActivity.kt index 8b86c79..8b83fbe 100644 --- a/app/src/main/java/se/ajpanton/notificationlog/MainActivity.kt +++ b/app/src/main/java/se/ajpanton/notificationlog/MainActivity.kt @@ -104,9 +104,6 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte } override fun onNavigationItemSelected(item: MenuItem): Boolean { - if (item.itemId == R.id.nav_settings_header) { - return false - } navigateTo(item.itemId) if (!permanentSidebar) { binding.drawerLayout.closeDrawer(GravityCompat.START) @@ -149,12 +146,8 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte val menu = navigationView.menu ?: return for (index in 0 until menu.size()) { val item = menu.getItem(index) - if (item.itemId == R.id.nav_settings_header) { - item.isCheckable = false - } else { - item.isCheckable = true - item.isChecked = item.itemId == itemId - } + item.isCheckable = true + item.isChecked = item.itemId == itemId } navigationView.invalidate() } diff --git a/app/src/main/java/se/ajpanton/notificationlog/SettingsFragment.kt b/app/src/main/java/se/ajpanton/notificationlog/SettingsFragment.kt index 6653d6a..12f4aff 100644 --- a/app/src/main/java/se/ajpanton/notificationlog/SettingsFragment.kt +++ b/app/src/main/java/se/ajpanton/notificationlog/SettingsFragment.kt @@ -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() + 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") } } diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml index 1dcf113..5471069 100644 --- a/app/src/main/res/layout/fragment_settings.xml +++ b/app/src/main/res/layout/fragment_settings.xml @@ -54,19 +54,48 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="24dp" - android:text="Copy event settings" /> + android:text="Copy settings between pages" /> - - -