Fix stale 'Syncing…' status and folder/file counts in the browser

- MainActivity: the periodic safety-net worker sits in ENQUEUED between runs,
  so observing it reset the status line to 'Syncing…' forever. Only a RUNNING
  periodic job now counts; one-shot ENQUEUED still shows progress.
- FileBrowserActivity: the action-bar subtitle counted files only, so folders
  with no files displayed '0 items'. It now reads e.g. '4 folders · 1 file'.
This commit is contained in:
2026-10-14 11:20:07 -07:00
parent 514092a8bc
commit 2e7bf11055
2 changed files with 45 additions and 10 deletions

View File

@@ -142,11 +142,26 @@ class FileBrowserActivity : AppCompatActivity() {
currentDir = dirKey
adapter.submit(entries)
supportActionBar?.title = src.displayName(dirKey)
supportActionBar?.subtitle = "${src.title} · ${entries.count { !it.isDirectory }} items"
supportActionBar?.subtitle = browseSubtitle(src.title, entries)
if (entries.isEmpty()) showMessage(getString(R.string.browse_empty)) else showGrid()
}
}
/** e.g. "Phone storage · 4 folders · 1 file" — folders and files counted separately. */
private fun browseSubtitle(sourceTitle: String, entries: List<TileEntry>): String {
val folders = entries.count { it.isDirectory }
val files = entries.size - folders
val parts = buildList {
if (folders > 0) add("$folders ${if (folders == 1) "folder" else "folders"}")
if (files > 0) add("$files ${if (files == 1) "file" else "files"}")
}
return if (parts.isEmpty()) {
"$sourceTitle · empty"
} else {
(listOf(sourceTitle) + parts).joinToString(" · ")
}
}
private fun navigateUp() {
val src = source
val cur = currentDir

View File

@@ -36,6 +36,12 @@ class MainActivity : AppCompatActivity() {
private lateinit var etDecadeFormat: EditText
private lateinit var etMonthFormat: EditText
/** True while a manual/one-shot sync is queued or running. */
private var oneShotSyncActive = false
/** True only while the periodic safety-net worker is actually running. */
private var periodicSyncRunning = false
private val mediaPermissionLauncher =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { }
@@ -212,6 +218,15 @@ class MainActivity : AppCompatActivity() {
statusText.text = p.lastStatus.ifBlank { getString(R.string.status_idle) }
}
/** Repaints the status line from whatever sync is in flight right now. */
private fun renderStatus() {
statusText.text = if (oneShotSyncActive || periodicSyncRunning) {
"Syncing…"
} else {
Prefs(this).lastStatus.ifBlank { getString(R.string.status_idle) }
}
}
private fun requestMediaPermission() {
if (!PhotoStore.hasPermission(this)) {
mediaPermissionLauncher.launch(PhotoStore.mediaPermission)
@@ -241,15 +256,20 @@ class MainActivity : AppCompatActivity() {
private fun observeWork() {
val wm = WorkManager.getInstance(this)
fun applyState(infos: List<WorkInfo>) {
val latest = infos.lastOrNull() ?: return
when (latest.state) {
WorkInfo.State.ENQUEUED, WorkInfo.State.RUNNING ->
statusText.text = "Syncing…"
else -> refreshStatus()
}
wm.getWorkInfosForUniqueWorkLiveData(Prefs.WORK_ONESHOT).observe(this) { infos ->
// ENQUEUED means "queued, waiting for a network/slot", which is still
// an active sync from the user's point of view.
val state = infos.lastOrNull()?.state
oneShotSyncActive =
state == WorkInfo.State.ENQUEUED || state == WorkInfo.State.RUNNING
renderStatus()
}
wm.getWorkInfosForUniqueWorkLiveData(Prefs.WORK_PERIODIC).observe(this) { infos ->
// The periodic safety-net job sits in ENQUEUED while it waits for its
// next window, so only a RUNNING job counts as a live sync.
periodicSyncRunning = infos.lastOrNull()?.state == WorkInfo.State.RUNNING
renderStatus()
}
wm.getWorkInfosForUniqueWorkLiveData(Prefs.WORK_ONESHOT).observe(this) { applyState(it) }
wm.getWorkInfosForUniqueWorkLiveData(Prefs.WORK_PERIODIC).observe(this) { applyState(it) }
}
}