From 4f5459cb9432e42d3fa5c0f393cce011b91c4e50 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Wed, 7 Oct 2026 17:13:58 -0400 Subject: [PATCH] android: pin and archive a note someone shared with you The card's long-press menu and the editor's overflow now open on shared notes with Pin and Archive; Labels, Share and Move to trash stay the owner's. Co-Authored-By: Claude Opus 5.5 --- .../fabledsword/inkwell/ui/EditorChrome.kt | 23 +++++++++++-------- .../com/fabledsword/inkwell/ui/NoteAccess.kt | 11 +++++---- .../com/fabledsword/inkwell/ui/NoteCard.kt | 12 ++++++---- 3 files changed, 28 insertions(+), 18 deletions(-) diff --git a/android/app/src/main/java/com/fabledsword/inkwell/ui/EditorChrome.kt b/android/app/src/main/java/com/fabledsword/inkwell/ui/EditorChrome.kt index bc84244..a521d3e 100644 --- a/android/app/src/main/java/com/fabledsword/inkwell/ui/EditorChrome.kt +++ b/android/app/src/main/java/com/fabledsword/inkwell/ui/EditorChrome.kt @@ -85,8 +85,9 @@ fun EditorTopBar( onConfirmDelete: () -> Unit, onAction: (EditorAction) -> Unit, ) { - // Someone else's note (#5175): its text is all that may change here, so the bar - // keeps the checklist button and nothing that is the owner's to do. + // Someone else's note (#5175): its text, at `edit`, and this account's own pin + // and archive (#5176) are all that may change here, so the bar keeps the + // checklist button and an overflow of those two, and nothing that is the owner's. val owner = access == NoteAccess.OWNER val dark = isSystemInDarkTheme() TopAppBar( @@ -133,10 +134,10 @@ fun EditorTopBar( ) } } - if (owner) { + if (owner || !note.trashed) { OverflowMenu( note = note, - readOnly = readOnly, + owner = owner, onPicker = onPicker, onShare = onShare, onConfirmDelete = onConfirmDelete, @@ -278,7 +279,7 @@ private fun savedLabel( @Composable private fun OverflowMenu( note: Note, - readOnly: Boolean, + owner: Boolean, onPicker: (Picker) -> Unit, onShare: () -> Unit, onConfirmDelete: () -> Unit, @@ -291,7 +292,7 @@ private fun OverflowMenu( Icon(Icons.Filled.MoreVert, contentDescription = stringResource(R.string.editor_more)) } DropdownMenu(expanded = open, onDismissRequest = close) { - if (readOnly) { + if (note.trashed) { MenuItem(R.string.editor_restore, close) { onAction(EditorAction.Restore) } MenuItem(R.string.editor_delete_forever, close, onConfirmDelete) } else { @@ -299,16 +300,20 @@ private fun OverflowMenu( if (note.pinned) R.string.editor_unpin else R.string.editor_pin, close, ) { onAction(EditorAction.SetPinned(!note.pinned)) } - MenuItem(R.string.editor_labels, close) { onPicker(Picker.LABELS) } + if (owner) { + MenuItem(R.string.editor_labels, close) { onPicker(Picker.LABELS) } + } // Not on a draft: the server has nothing to share until it is saved. - if (note.id != DRAFT_ID) { + if (owner && note.id != DRAFT_ID) { MenuItem(R.string.editor_share, close, onShare) } MenuItem( if (note.archived) R.string.editor_unarchive else R.string.editor_archive, close, ) { onAction(EditorAction.SetArchived(!note.archived)) } - MenuItem(R.string.editor_trash, close) { onAction(EditorAction.Trash) } + if (owner) { + MenuItem(R.string.editor_trash, close) { onAction(EditorAction.Trash) } + } } } } diff --git a/android/app/src/main/java/com/fabledsword/inkwell/ui/NoteAccess.kt b/android/app/src/main/java/com/fabledsword/inkwell/ui/NoteAccess.kt index b860cd8..2540a05 100644 --- a/android/app/src/main/java/com/fabledsword/inkwell/ui/NoteAccess.kt +++ b/android/app/src/main/java/com/fabledsword/inkwell/ui/NoteAccess.kt @@ -5,9 +5,10 @@ import com.fabledsword.inkwell.core.Note /** * How this account holds a note (#5175), read from the core's `permission`. * - * Someone else's note at [EDIT] is theirs to have its TEXT changed here and nothing - * else; at [VIEW] nothing changes here at all. The core refuses the rest anyway — - * this only keeps the editor from offering what would be refused. + * Someone else's note at [EDIT] may have its TEXT changed here; at [VIEW] it may + * not. Either way its pin and archive are this account's own (#5176). The core + * refuses the rest anyway — this only keeps the editor from offering what would be + * refused. */ enum class NoteAccess { OWNER, EDIT, VIEW } @@ -19,10 +20,10 @@ val Note.access: NoteAccess else -> NoteAccess.OWNER } -/** Nothing changes here: the note is in the trash, or shared with us to view. */ +/** Its content can't change here: it is in the trash, or shared with us to view. */ val Note.readOnlyHere: Boolean get() = trashed || access == NoteAccess.VIEW -/** The owner's own controls apply: tags, reminder, files, previews, the menu. */ +/** The owner's own controls apply: tags, reminder, files, previews, share, trash. */ val Note.ownerControlsHere: Boolean get() = !readOnlyHere && access == NoteAccess.OWNER diff --git a/android/app/src/main/java/com/fabledsword/inkwell/ui/NoteCard.kt b/android/app/src/main/java/com/fabledsword/inkwell/ui/NoteCard.kt index 04ca2e9..b9b8442 100644 --- a/android/app/src/main/java/com/fabledsword/inkwell/ui/NoteCard.kt +++ b/android/app/src/main/java/com/fabledsword/inkwell/ui/NoteCard.kt @@ -229,9 +229,11 @@ private fun NoteMenu( onAction: (EditorAction) -> Unit, onConfirmDelete: () -> Unit, ) { - // Every item here is the owner's to do, so someone else's note has no menu at all - // rather than an empty one (#5175). - DropdownMenu(expanded = expanded && note.access == NoteAccess.OWNER, onDismissRequest = onDismiss) { + // Pin and archive are this account's own on someone else's note too (#5176); + // trash is the owner's. A note shared with us never reaches our Trash, so the + // trashed set is only ever the owner's. + val owner = note.access == NoteAccess.OWNER + DropdownMenu(expanded = expanded && (owner || !note.trashed), onDismissRequest = onDismiss) { if (note.trashed) { MenuItem(R.string.editor_restore, onDismiss) { onAction(EditorAction.Restore) } MenuItem(R.string.editor_delete_forever, onDismiss, onConfirmDelete) @@ -244,7 +246,9 @@ private fun NoteMenu( if (note.archived) R.string.editor_unarchive else R.string.editor_archive, onDismiss, ) { onAction(EditorAction.SetArchived(!note.archived)) } - MenuItem(R.string.editor_trash, onDismiss) { onAction(EditorAction.Trash) } + if (owner) { + MenuItem(R.string.editor_trash, onDismiss) { onAction(EditorAction.Trash) } + } } } }