android: pin and archive a note someone shared with you
CI & Build / Python lint (push) Successful in 2s
CI & Build / Build now, or wait for Android? (push) Successful in 2s
Android / Build, or is the channel already serving this? (push) Successful in 2s
Desktop (Tauri) / Build, or is the channel already serving this? (push) Successful in 2s
CI & Build / Web typecheck and unit tests (push) Successful in 9s
CI & Build / Python tests (push) Successful in 11s
CI & Build / integration (push) Successful in 1m24s
CI & Build / Build & push image (push) Skipped
Desktop (Tauri) / Web tests, clippy, Rust tests and rustfmt (push) Failing after 1m30s
Desktop (Tauri) / Tauri desktop (Linux) (push) Skipped
Desktop (Tauri) / Windows installer (cross-compiled) (push) Skipped
Desktop (Tauri) / Update manifest (push) Skipped
Android / Kotlin + Rust (APK) (push) Successful in 7m17s
CI & Build / Python lint (push) Successful in 2s
CI & Build / Build now, or wait for Android? (push) Successful in 2s
Android / Build, or is the channel already serving this? (push) Successful in 2s
Desktop (Tauri) / Build, or is the channel already serving this? (push) Successful in 2s
CI & Build / Web typecheck and unit tests (push) Successful in 9s
CI & Build / Python tests (push) Successful in 11s
CI & Build / integration (push) Successful in 1m24s
CI & Build / Build & push image (push) Skipped
Desktop (Tauri) / Web tests, clippy, Rust tests and rustfmt (push) Failing after 1m30s
Desktop (Tauri) / Tauri desktop (Linux) (push) Skipped
Desktop (Tauri) / Windows installer (cross-compiled) (push) Skipped
Desktop (Tauri) / Update manifest (push) Skipped
Android / Kotlin + Rust (APK) (push) Successful in 7m17s
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 <noreply@anthropic.com>
This commit is contained in:
@@ -85,8 +85,9 @@ fun EditorTopBar(
|
|||||||
onConfirmDelete: () -> Unit,
|
onConfirmDelete: () -> Unit,
|
||||||
onAction: (EditorAction) -> Unit,
|
onAction: (EditorAction) -> Unit,
|
||||||
) {
|
) {
|
||||||
// Someone else's note (#5175): its text is all that may change here, so the bar
|
// Someone else's note (#5175): its text, at `edit`, and this account's own pin
|
||||||
// keeps the checklist button and nothing that is the owner's to do.
|
// 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 owner = access == NoteAccess.OWNER
|
||||||
val dark = isSystemInDarkTheme()
|
val dark = isSystemInDarkTheme()
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
@@ -133,10 +134,10 @@ fun EditorTopBar(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (owner) {
|
if (owner || !note.trashed) {
|
||||||
OverflowMenu(
|
OverflowMenu(
|
||||||
note = note,
|
note = note,
|
||||||
readOnly = readOnly,
|
owner = owner,
|
||||||
onPicker = onPicker,
|
onPicker = onPicker,
|
||||||
onShare = onShare,
|
onShare = onShare,
|
||||||
onConfirmDelete = onConfirmDelete,
|
onConfirmDelete = onConfirmDelete,
|
||||||
@@ -278,7 +279,7 @@ private fun savedLabel(
|
|||||||
@Composable
|
@Composable
|
||||||
private fun OverflowMenu(
|
private fun OverflowMenu(
|
||||||
note: Note,
|
note: Note,
|
||||||
readOnly: Boolean,
|
owner: Boolean,
|
||||||
onPicker: (Picker) -> Unit,
|
onPicker: (Picker) -> Unit,
|
||||||
onShare: () -> Unit,
|
onShare: () -> Unit,
|
||||||
onConfirmDelete: () -> Unit,
|
onConfirmDelete: () -> Unit,
|
||||||
@@ -291,7 +292,7 @@ private fun OverflowMenu(
|
|||||||
Icon(Icons.Filled.MoreVert, contentDescription = stringResource(R.string.editor_more))
|
Icon(Icons.Filled.MoreVert, contentDescription = stringResource(R.string.editor_more))
|
||||||
}
|
}
|
||||||
DropdownMenu(expanded = open, onDismissRequest = close) {
|
DropdownMenu(expanded = open, onDismissRequest = close) {
|
||||||
if (readOnly) {
|
if (note.trashed) {
|
||||||
MenuItem(R.string.editor_restore, close) { onAction(EditorAction.Restore) }
|
MenuItem(R.string.editor_restore, close) { onAction(EditorAction.Restore) }
|
||||||
MenuItem(R.string.editor_delete_forever, close, onConfirmDelete)
|
MenuItem(R.string.editor_delete_forever, close, onConfirmDelete)
|
||||||
} else {
|
} else {
|
||||||
@@ -299,20 +300,24 @@ private fun OverflowMenu(
|
|||||||
if (note.pinned) R.string.editor_unpin else R.string.editor_pin,
|
if (note.pinned) R.string.editor_unpin else R.string.editor_pin,
|
||||||
close,
|
close,
|
||||||
) { onAction(EditorAction.SetPinned(!note.pinned)) }
|
) { onAction(EditorAction.SetPinned(!note.pinned)) }
|
||||||
|
if (owner) {
|
||||||
MenuItem(R.string.editor_labels, close) { onPicker(Picker.LABELS) }
|
MenuItem(R.string.editor_labels, close) { onPicker(Picker.LABELS) }
|
||||||
|
}
|
||||||
// Not on a draft: the server has nothing to share until it is saved.
|
// 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(R.string.editor_share, close, onShare)
|
||||||
}
|
}
|
||||||
MenuItem(
|
MenuItem(
|
||||||
if (note.archived) R.string.editor_unarchive else R.string.editor_archive,
|
if (note.archived) R.string.editor_unarchive else R.string.editor_archive,
|
||||||
close,
|
close,
|
||||||
) { onAction(EditorAction.SetArchived(!note.archived)) }
|
) { onAction(EditorAction.SetArchived(!note.archived)) }
|
||||||
|
if (owner) {
|
||||||
MenuItem(R.string.editor_trash, close) { onAction(EditorAction.Trash) }
|
MenuItem(R.string.editor_trash, close) { onAction(EditorAction.Trash) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The note's labels, each removable.
|
* The note's labels, each removable.
|
||||||
|
|||||||
@@ -5,9 +5,10 @@ import com.fabledsword.inkwell.core.Note
|
|||||||
/**
|
/**
|
||||||
* How this account holds a note (#5175), read from the core's `permission`.
|
* 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
|
* Someone else's note at [EDIT] may have its TEXT changed here; at [VIEW] it may
|
||||||
* else; at [VIEW] nothing changes here at all. The core refuses the rest anyway —
|
* not. Either way its pin and archive are this account's own (#5176). The core
|
||||||
* this only keeps the editor from offering what would be refused.
|
* refuses the rest anyway — this only keeps the editor from offering what would be
|
||||||
|
* refused.
|
||||||
*/
|
*/
|
||||||
enum class NoteAccess { OWNER, EDIT, VIEW }
|
enum class NoteAccess { OWNER, EDIT, VIEW }
|
||||||
|
|
||||||
@@ -19,10 +20,10 @@ val Note.access: NoteAccess
|
|||||||
else -> NoteAccess.OWNER
|
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
|
val Note.readOnlyHere: Boolean
|
||||||
get() = trashed || access == NoteAccess.VIEW
|
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
|
val Note.ownerControlsHere: Boolean
|
||||||
get() = !readOnlyHere && access == NoteAccess.OWNER
|
get() = !readOnlyHere && access == NoteAccess.OWNER
|
||||||
|
|||||||
@@ -229,9 +229,11 @@ private fun NoteMenu(
|
|||||||
onAction: (EditorAction) -> Unit,
|
onAction: (EditorAction) -> Unit,
|
||||||
onConfirmDelete: () -> Unit,
|
onConfirmDelete: () -> Unit,
|
||||||
) {
|
) {
|
||||||
// Every item here is the owner's to do, so someone else's note has no menu at all
|
// Pin and archive are this account's own on someone else's note too (#5176);
|
||||||
// rather than an empty one (#5175).
|
// trash is the owner's. A note shared with us never reaches our Trash, so the
|
||||||
DropdownMenu(expanded = expanded && note.access == NoteAccess.OWNER, onDismissRequest = onDismiss) {
|
// 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) {
|
if (note.trashed) {
|
||||||
MenuItem(R.string.editor_restore, onDismiss) { onAction(EditorAction.Restore) }
|
MenuItem(R.string.editor_restore, onDismiss) { onAction(EditorAction.Restore) }
|
||||||
MenuItem(R.string.editor_delete_forever, onDismiss, onConfirmDelete)
|
MenuItem(R.string.editor_delete_forever, onDismiss, onConfirmDelete)
|
||||||
@@ -244,10 +246,12 @@ private fun NoteMenu(
|
|||||||
if (note.archived) R.string.editor_unarchive else R.string.editor_archive,
|
if (note.archived) R.string.editor_unarchive else R.string.editor_archive,
|
||||||
onDismiss,
|
onDismiss,
|
||||||
) { onAction(EditorAction.SetArchived(!note.archived)) }
|
) { onAction(EditorAction.SetArchived(!note.archived)) }
|
||||||
|
if (owner) {
|
||||||
MenuItem(R.string.editor_trash, onDismiss) { onAction(EditorAction.Trash) }
|
MenuItem(R.string.editor_trash, onDismiss) { onAction(EditorAction.Trash) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The note's body, with its checklist drawn where it actually sits.
|
* The note's body, with its checklist drawn where it actually sits.
|
||||||
|
|||||||
Reference in New Issue
Block a user