diff --git a/android/app/src/main/java/com/fabledsword/inkwell/TagViews.kt b/android/app/src/main/java/com/fabledsword/inkwell/TagViews.kt new file mode 100644 index 0000000..051d2ea --- /dev/null +++ b/android/app/src/main/java/com/fabledsword/inkwell/TagViews.kt @@ -0,0 +1,31 @@ +package com.fabledsword.inkwell + +import android.content.Context + +/** + * When each tag's lens was last opened on this phone, for the drawer's recent tags + * (#5931). Opening a tag counts as using it, alongside the notes that carry it. + * + * Kept on the device rather than synced: it is a convenience about where this + * person's thumb goes on this screen, and losing it costs one tap. + */ +class TagViews( + context: Context, +) { + // applicationContext, as in SyncSettings: this must not hold an Activity. + private val prefs = + context.applicationContext.getSharedPreferences(FILE, Context.MODE_PRIVATE) + + fun all(): Map = prefs.all.mapNotNull { (id, at) -> (at as? Long)?.let { id to it } }.toMap() + + /** Records a view now and returns every view, this one included. */ + fun record(tagId: String): Map { + val now = System.currentTimeMillis() + prefs.edit().putLong(tagId, now).apply() + return all() + (tagId to now) + } + + private companion object { + const val FILE = "inkwell-tag-views" + } +} diff --git a/android/app/src/main/java/com/fabledsword/inkwell/ui/BoardScreen.kt b/android/app/src/main/java/com/fabledsword/inkwell/ui/BoardScreen.kt index 238e92a..3ac40fe 100644 --- a/android/app/src/main/java/com/fabledsword/inkwell/ui/BoardScreen.kt +++ b/android/app/src/main/java/com/fabledsword/inkwell/ui/BoardScreen.kt @@ -60,6 +60,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.rememberUpdatedState import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment @@ -68,11 +69,13 @@ import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.layout.boundsInRoot import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.unit.dp import androidx.compose.ui.zIndex import com.fabledsword.inkwell.R +import com.fabledsword.inkwell.TagViews import com.fabledsword.inkwell.core.Label import com.fabledsword.inkwell.core.Note import kotlinx.coroutines.launch @@ -96,6 +99,15 @@ fun BoardScreen( ) { val drawerState = rememberDrawerState(DrawerValue.Closed) val scope = rememberCoroutineScope() + + // Opening a tag's lens counts as using it, however it was opened: from the + // drawer, or a tag on a card (#5931). + val context = LocalContext.current + val tagViews = remember(context) { TagViews(context) } + var views by remember { mutableStateOf(tagViews.all()) } + LaunchedEffect(state.destination) { + (state.destination as? Destination.WithLabel)?.let { views = tagViews.record(it.id) } + } val snackbars = remember { SnackbarHostState() } // Held HERE rather than on the card. A card lives in a lazy grid and is disposed @@ -143,6 +155,7 @@ fun BoardScreen( NavigationDrawer( current = state.destination, labels = state.labels, + recency = tagRecency(state.labels, state.notes, views), syncSummary = sync.summary, onOpen = { onOpen(it) @@ -401,11 +414,16 @@ private fun SearchBar( private fun NavigationDrawer( current: Destination, labels: List