Remove obsolete UI scaffolding

This commit is contained in:
ajp_anton
2026-09-03 00:49:14 +00:00
parent 99f999d4e0
commit 78bf4bde8c
9 changed files with 48 additions and 121 deletions
+2 -2
View File
@@ -41,8 +41,8 @@ android {
applicationId = "se.ajpanton.notificationsmaster" applicationId = "se.ajpanton.notificationsmaster"
minSdk = 34 minSdk = 34
targetSdk = 36 targetSdk = 36
versionCode = project.findProperty("notificationLogVersionCode")?.toString()?.toIntOrNull() ?: 1 versionCode = project.findProperty("notificationsMasterVersionCode")?.toString()?.toIntOrNull() ?: 1
versionName = project.findProperty("notificationLogVersionName")?.toString() ?: "0.1" versionName = project.findProperty("notificationsMasterVersionName")?.toString() ?: "0.1"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
} }
+2 -2
View File
@@ -17,7 +17,7 @@
tools:ignore="QueryAllPackagesPermission" /> tools:ignore="QueryAllPackagesPermission" />
<application <application
android:name=".NotificationLogApplication" android:name=".NotificationsMasterApplication"
android:allowBackup="false" android:allowBackup="false"
android:dataExtractionRules="@xml/data_extraction_rules" android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules" android:fullBackupContent="@xml/backup_rules"
@@ -25,7 +25,7 @@
android:label="@string/app_name" android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.NotificationLog"> android:theme="@style/Theme.NotificationsMaster">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
@@ -85,7 +85,6 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
refreshLogProtection(requestUnlock = hasWindowFocus()) refreshLogProtection(requestUnlock = hasWindowFocus())
syncDrawerSelection(currentItemId) syncDrawerSelection(currentItemId)
title = getString(page.titleRes) title = getString(page.titleRes)
binding.root.post(::applyPageTitleVisibility)
} }
applyNavigationDrawerInsets() applyNavigationDrawerInsets()
syncDrawerToggle() syncDrawerToggle()
@@ -171,23 +170,21 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
supportFragmentManager.commit { supportFragmentManager.commit {
replace( replace(
R.id.content_frame, R.id.content_frame,
when { when (page) {
page == Page.VIEW_LOGS -> ViewLogsFragment() Page.VIEW_LOGS -> ViewLogsFragment()
page == Page.SETTINGS -> SettingsFragment() Page.SETTINGS -> SettingsFragment()
page == Page.ALERTS -> AlertsFragment() Page.ALERTS -> AlertsFragment()
page == Page.PROFILES -> ProfilesFragment() Page.PROFILES -> ProfilesFragment()
page == Page.RULES -> RulesFragment() Page.RULES -> RulesFragment()
page == Page.APPS -> AppsFragment() Page.APPS -> AppsFragment()
page == Page.NOTIFICATION_VISIBILITY -> NotificationVisibilityFragment() Page.NOTIFICATION_VISIBILITY -> NotificationVisibilityFragment()
page == Page.CARDS_LAYOUT -> CardsLayoutFragment() Page.CARDS_LAYOUT -> CardsLayoutFragment()
page == Page.MISCELLANEOUS -> MiscellaneousFragment() Page.MISCELLANEOUS -> MiscellaneousFragment()
page == Page.LOG_DISPLAY -> LogDisplayFragment() Page.LOG_DISPLAY -> LogDisplayFragment()
page == Page.FILTER_LOGGING -> FilterLoggingFragment() Page.FILTER_LOGGING -> FilterLoggingFragment()
page == Page.FILTER_APPS -> FilterAppsFragment.newInstance() Page.FILTER_APPS -> FilterAppsFragment.newInstance()
else -> PageFragment.newInstance(page.titleRes)
}, },
) )
runOnCommit(::applyPageTitleVisibility)
} }
title = getString(page.titleRes) title = getString(page.titleRes)
invalidateOptionsMenu() invalidateOptionsMenu()
@@ -306,7 +303,6 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
} }
updateNavigationHeaderHeight(binding.navViewDrawer) updateNavigationHeaderHeight(binding.navViewDrawer)
updateNavigationHeaderHeight(binding.navViewPermanent) updateNavigationHeaderHeight(binding.navViewPermanent)
applyPageTitleVisibility()
} }
private fun updateNavigationHeaderHeight(navigationView: NavigationView) { private fun updateNavigationHeaderHeight(navigationView: NavigationView) {
@@ -332,11 +328,6 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
return visible return visible
} }
private fun applyPageTitleVisibility() {
(supportFragmentManager.findFragmentById(R.id.content_frame) as? PageFragment)
?.setPageTitleVisible(permanentSidebar)
}
private fun syncDrawerToggle() { private fun syncDrawerToggle() {
drawerToggle.syncState() drawerToggle.syncState()
drawerToggle.drawerArrowDrawable.color = getColor(R.color.on_primary) drawerToggle.drawerArrowDrawable.color = getColor(R.color.on_primary)
@@ -9,12 +9,12 @@ import se.ajpanton.notificationsmaster.settings.NotificationListenerComponentCon
import se.ajpanton.notificationsmaster.settings.PerAppEventSettingsStore import se.ajpanton.notificationsmaster.settings.PerAppEventSettingsStore
import se.ajpanton.notificationsmaster.visibility.VisibilityPolicyStore import se.ajpanton.notificationsmaster.visibility.VisibilityPolicyStore
class NotificationLogApplication : Application() { class NotificationsMasterApplication : Application() {
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
synchronizeListenerComponent() synchronizeListenerComponent()
VisibilityPolicySync.publishStored(this) VisibilityPolicySync.publishStored(this)
Thread(::removeStaleAppStorage, "notification-log-storage-cleanup").start() Thread(::removeStaleAppStorage, "notifications-master-storage-cleanup").start()
} }
/** /**
@@ -1,34 +0,0 @@
package se.ajpanton.notificationsmaster
import android.os.Bundle
import android.view.View
import androidx.annotation.StringRes
import androidx.fragment.app.Fragment
import se.ajpanton.notificationsmaster.databinding.FragmentPageBinding
class PageFragment : Fragment(R.layout.fragment_page) {
private var binding: FragmentPageBinding? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = FragmentPageBinding.bind(view)
binding?.pageTitle?.setText(requireArguments().getInt(ARG_TITLE))
}
override fun onDestroyView() {
binding = null
super.onDestroyView()
}
fun setPageTitleVisible(visible: Boolean) {
binding?.pageTitle?.visibility = if (visible) View.VISIBLE else View.GONE
}
companion object {
private const val ARG_TITLE = "title"
fun newInstance(@StringRes titleRes: Int) = PageFragment().apply {
arguments = Bundle().apply { putInt(ARG_TITLE, titleRes) }
}
}
}
@@ -45,7 +45,7 @@ import kotlinx.coroutines.withContext
class ViewLogsFragment : Fragment(R.layout.fragment_view_logs) { class ViewLogsFragment : Fragment(R.layout.fragment_view_logs) {
private var binding: FragmentViewLogsBinding? = null private var binding: FragmentViewLogsBinding? = null
private val expandedIds = mutableSetOf<String>() private val expandedIds = mutableSetOf<String>()
private val rows = mutableListOf<LogRow>() private val rows = mutableListOf<NotificationLogEntry>()
private var nextCursor: NewestLogCursor? = null private var nextCursor: NewestLogCursor? = null
private var loading = false private var loading = false
private var noMoreRows = false private var noMoreRows = false
@@ -106,7 +106,7 @@ class ViewLogsFragment : Fragment(R.layout.fragment_view_logs) {
nextCursor = page.nextCursor nextCursor = page.nextCursor
noMoreRows = nextCursor == null noMoreRows = nextCursor == null
val visibleBefore = visibleRows(LogViewSettingsStore(requireContext()).load()).size val visibleBefore = visibleRows(LogViewSettingsStore(requireContext()).load()).size
rows += page.entries.map(::LogRow) rows += page.entries
binding?.let(::render) binding?.let(::render)
val visibleAfter = visibleRows(LogViewSettingsStore(requireContext()).load()).size val visibleAfter = visibleRows(LogViewSettingsStore(requireContext()).load()).size
val skipFilteredPage = appFilterStore.selectedPackages().isNotEmpty() && val skipFilteredPage = appFilterStore.selectedPackages().isNotEmpty() &&
@@ -181,15 +181,15 @@ class ViewLogsFragment : Fragment(R.layout.fragment_view_logs) {
loadLogs(reset = true) loadLogs(reset = true)
} }
private fun visibleRows(settings: LogViewSettings): List<LogRow> { private fun visibleRows(settings: LogViewSettings): List<NotificationLogEntry> {
val selectedPackages = appFilterStore.selectedPackages() val selectedPackages = appFilterStore.selectedPackages()
return rows.filter { row -> return rows.filter { entry ->
eventFor(row.entry.action) in settings.visibleEvents && eventFor(entry.action) in settings.visibleEvents &&
(selectedPackages.isEmpty() || row.entry.packageName in selectedPackages) (selectedPackages.isEmpty() || entry.packageName in selectedPackages)
} }
} }
private fun logRowView(row: LogRow, settings: LogViewSettings, metadataColumnWidth: Int): View = LinearLayout(requireContext()).apply { private fun logRowView(entry: NotificationLogEntry, settings: LogViewSettings, metadataColumnWidth: Int): View = LinearLayout(requireContext()).apply {
orientation = LinearLayout.HORIZONTAL orientation = LinearLayout.HORIZONTAL
gravity = android.view.Gravity.TOP gravity = android.view.Gravity.TOP
layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT).apply { layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT).apply {
@@ -198,14 +198,14 @@ class ViewLogsFragment : Fragment(R.layout.fragment_view_logs) {
fun renderExpanded(expanded: Boolean) { fun renderExpanded(expanded: Boolean) {
removeAllViews() removeAllViews()
val metadata = metadataValues(row.entry, settings) val metadata = metadataValues(entry, settings)
val contents = fieldValue(LogField.CONTENTS, row.entry, settings) val contents = entry.contents
val hasContents = LogField.CONTENTS in settings.visibleFields && !contents.isNullOrEmpty() val hasContents = LogField.CONTENTS in settings.visibleFields && !contents.isNullOrEmpty()
val toggleExpanded = { val toggleExpanded = {
val collapsing = expanded val collapsing = expanded
val collapseAnchor = if (collapsing) captureCollapseAnchor(this@apply) else null val collapseAnchor = if (collapsing) captureCollapseAnchor(this@apply) else null
if (!expandedIds.add(row.entry.id)) expandedIds.remove(row.entry.id) if (!expandedIds.add(entry.id)) expandedIds.remove(entry.id)
renderExpanded(row.entry.id in expandedIds) renderExpanded(entry.id in expandedIds)
if (collapsing) { if (collapsing) {
val highlight = { highlightCollapsedRow(this@apply) } val highlight = { highlightCollapsedRow(this@apply) }
if (collapseAnchor != null) { if (collapseAnchor != null) {
@@ -216,7 +216,7 @@ class ViewLogsFragment : Fragment(R.layout.fragment_view_logs) {
} }
Unit Unit
} }
val metadataCell = metadataCell(metadata, expanded, toggleExpanded, row.entry.id).apply { val metadataCell = metadataCell(metadata, expanded, toggleExpanded, entry.id).apply {
layoutParams = LinearLayout.LayoutParams( layoutParams = LinearLayout.LayoutParams(
if (hasContents) metadataColumnWidth else LinearLayout.LayoutParams.MATCH_PARENT, if (hasContents) metadataColumnWidth else LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT,
@@ -226,7 +226,7 @@ class ViewLogsFragment : Fragment(R.layout.fragment_view_logs) {
} }
if (metadata.isNotEmpty()) addView(metadataCell) if (metadata.isNotEmpty()) addView(metadataCell)
if (hasContents) { if (hasContents) {
val contentsCell = contentsCell(row, contents!!, metadata.size.coerceAtLeast(1), expanded, toggleExpanded).apply { val contentsCell = contentsCell(entry, contents!!, metadata.size.coerceAtLeast(1), expanded, toggleExpanded).apply {
layoutParams = LinearLayout.LayoutParams( layoutParams = LinearLayout.LayoutParams(
if (metadata.isNotEmpty()) 0 else LinearLayout.LayoutParams.MATCH_PARENT, if (metadata.isNotEmpty()) 0 else LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT,
@@ -237,9 +237,9 @@ class ViewLogsFragment : Fragment(R.layout.fragment_view_logs) {
} }
} }
renderExpanded(row.entry.id in expandedIds) renderExpanded(entry.id in expandedIds)
setOnLongClickListener { setOnLongClickListener {
showDeleteDialog(row.entry.id) showDeleteDialog(entry.id)
} }
} }
@@ -273,7 +273,7 @@ class ViewLogsFragment : Fragment(R.layout.fragment_view_logs) {
} }
private fun contentsCell( private fun contentsCell(
row: LogRow, entry: NotificationLogEntry,
contents: String, contents: String,
collapsedLines: Int, collapsedLines: Int,
expanded: Boolean, expanded: Boolean,
@@ -290,15 +290,15 @@ class ViewLogsFragment : Fragment(R.layout.fragment_view_logs) {
setLineSpacing(0f, 1f) setLineSpacing(0f, 1f)
} }
addView(message) addView(message)
if (expanded && row.entry.action == NotificationAction.EDITED && !row.entry.previousContents.isNullOrEmpty()) { if (expanded && entry.action == NotificationAction.EDITED && !entry.previousContents.isNullOrEmpty()) {
addView(previousDivider()) addView(previousDivider())
addView(TextView(context).apply { addView(TextView(context).apply {
text = row.entry.previousContents text = entry.previousContents
setLineSpacing(0f, 1f) setLineSpacing(0f, 1f)
}) })
} }
if (expanded && row.entry.imageId != null) { if (expanded && entry.imageId != null) {
val imageId = row.entry.imageId val imageId = entry.imageId
val appContext = requireContext().applicationContext val appContext = requireContext().applicationContext
val contentsContainer = this val contentsContainer = this
viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.lifecycleScope.launch {
@@ -324,7 +324,7 @@ class ViewLogsFragment : Fragment(R.layout.fragment_view_logs) {
} }
} }
setOnClickListener { onToggleExpanded() } setOnClickListener { onToggleExpanded() }
setOnLongClickListener { showDeleteDialog(row.entry.id) } setOnLongClickListener { showDeleteDialog(entry.id) }
} }
private fun previousDivider(): LinearLayout = LinearLayout(requireContext()).apply { private fun previousDivider(): LinearLayout = LinearLayout(requireContext()).apply {
@@ -352,14 +352,6 @@ class ViewLogsFragment : Fragment(R.layout.fragment_view_logs) {
if (LogField.ACTION in settings.visibleFields) add(MetadataValue(actionLabel(entry.action), 14f, indented = true)) if (LogField.ACTION in settings.visibleFields) add(MetadataValue(actionLabel(entry.action), 14f, indented = true))
} }
private fun fieldValue(field: LogField, entry: NotificationLogEntry, settings: LogViewSettings): String? = when (field) {
LogField.TIMESTAMP -> timestamp(entry.recordedAtEpochMillis, settings, entry.eventTimeZoneId)
LogField.APP_NAME -> entry.appName
LogField.PACKAGE_NAME -> entry.packageName
LogField.ACTION -> actionLabel(entry.action)
LogField.CONTENTS -> entry.contents
}
private fun actionLabel(action: NotificationAction): String = when (action) { private fun actionLabel(action: NotificationAction): String = when (action) {
NotificationAction.APPEARED -> "Appeared" NotificationAction.APPEARED -> "Appeared"
NotificationAction.ALREADY_ACTIVE -> "Already active" NotificationAction.ALREADY_ACTIVE -> "Already active"
@@ -382,8 +374,8 @@ class ViewLogsFragment : Fragment(R.layout.fragment_view_logs) {
.getSystemService(NotificationManager::class.java) .getSystemService(NotificationManager::class.java)
.isNotificationListenerAccessGranted(ComponentName(requireContext(), NotificationCaptureService::class.java)) .isNotificationListenerAccessGranted(ComponentName(requireContext(), NotificationCaptureService::class.java))
private fun metadataColumnWidth(availableWidth: Int, rows: List<LogRow>, settings: LogViewSettings): Int { private fun metadataColumnWidth(availableWidth: Int, rows: List<NotificationLogEntry>, settings: LogViewSettings): Int {
val values = rows.flatMap { metadataValues(it.entry, settings) } val values = rows.flatMap { metadataValues(it, settings) }
val widestTimestamp = values.filter { it.isTimestamp } val widestTimestamp = values.filter { it.isTimestamp }
.maxOfOrNull(::metadataTextWidth) .maxOfOrNull(::metadataTextWidth)
?: 0 ?: 0
@@ -418,11 +410,11 @@ class ViewLogsFragment : Fragment(R.layout.fragment_view_logs) {
} }
private inner class LogAdapter : RecyclerView.Adapter<LogAdapter.Holder>() { private inner class LogAdapter : RecyclerView.Adapter<LogAdapter.Holder>() {
private var rows: List<LogRow> = emptyList() private var rows: List<NotificationLogEntry> = emptyList()
private var settings = LogViewSettings() private var settings = LogViewSettings()
private var metadataWidth = 0 private var metadataWidth = 0
fun submit(rows: List<LogRow>, settings: LogViewSettings, metadataWidth: Int) { fun submit(rows: List<NotificationLogEntry>, settings: LogViewSettings, metadataWidth: Int) {
val previous = this.rows val previous = this.rows
this.rows = rows this.rows = rows
this.settings = settings this.settings = settings
@@ -431,7 +423,7 @@ class ViewLogsFragment : Fragment(R.layout.fragment_view_logs) {
override fun getOldListSize() = previous.size override fun getOldListSize() = previous.size
override fun getNewListSize() = rows.size override fun getNewListSize() = rows.size
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int) = override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int) =
previous[oldItemPosition].entry.id == rows[newItemPosition].entry.id previous[oldItemPosition].id == rows[newItemPosition].id
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int) = override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int) =
previous[oldItemPosition] == rows[newItemPosition] previous[oldItemPosition] == rows[newItemPosition]
}).dispatchUpdatesTo(this) }).dispatchUpdatesTo(this)
@@ -547,7 +539,6 @@ class ViewLogsFragment : Fragment(R.layout.fragment_view_logs) {
resources.displayMetrics, resources.displayMetrics,
) )
private data class LogRow(val entry: NotificationLogEntry)
private data class LoggedApp(val name: String, val packageName: String) private data class LoggedApp(val name: String, val packageName: String)
private data class MetadataValue( private data class MetadataValue(
val text: String, val text: String,
@@ -567,7 +558,6 @@ class ViewLogsFragment : Fragment(R.layout.fragment_view_logs) {
private companion object { private companion object {
const val SCROLL_TO_TOP_THRESHOLD_DP = 120 const val SCROLL_TO_TOP_THRESHOLD_DP = 120
const val LOAD_MORE_THRESHOLD_DP = 480
const val PAGE_SIZE = 80 const val PAGE_SIZE = 80
const val IMAGE_VIEWER_TAG = "image-viewer" const val IMAGE_VIEWER_TAG = "image-viewer"
const val MINIMUM_METADATA_COLUMN_DP = 120 const val MINIMUM_METADATA_COLUMN_DP = 120
+1 -1
View File
@@ -39,7 +39,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@color/primary" android:background="@color/primary"
android:elevation="0dp" android:elevation="0dp"
android:theme="@style/ThemeOverlay.NotificationLog.Toolbar" android:theme="@style/ThemeOverlay.NotificationsMaster.Toolbar"
android:layout_alignParentTop="true" android:layout_alignParentTop="true"
app:navigationIconTint="@color/on_primary" app:navigationIconTint="@color/on_primary"
app:titleTextColor="@color/on_primary" /> app:titleTextColor="@color/on_primary" />
-20
View File
@@ -1,20 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="@dimen/page_padding">
<TextView
android:id="@+id/page_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?attr/textAppearanceHeadline5"
android:textColor="?attr/colorOnBackground" />
</LinearLayout>
</ScrollView>
+2 -2
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<style name="Theme.NotificationLog" parent="Theme.MaterialComponents.DayNight.NoActionBar"> <style name="Theme.NotificationsMaster" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<item name="colorPrimary">@color/primary</item> <item name="colorPrimary">@color/primary</item>
<item name="colorOnPrimary">@color/on_primary</item> <item name="colorOnPrimary">@color/on_primary</item>
<item name="colorSurface">@color/surface</item> <item name="colorSurface">@color/surface</item>
@@ -12,5 +12,5 @@
<item name="android:windowLightNavigationBar">true</item> <item name="android:windowLightNavigationBar">true</item>
</style> </style>
<style name="ThemeOverlay.NotificationLog.Toolbar" parent="ThemeOverlay.MaterialComponents.Dark.ActionBar" /> <style name="ThemeOverlay.NotificationsMaster.Toolbar" parent="ThemeOverlay.MaterialComponents.Dark.ActionBar" />
</resources> </resources>