|
|
|
@@ -108,75 +108,7 @@ fun NoteCard(
|
|
|
|
|
.border(1.dp, if (dark) CARD_EDGE_DARK else CARD_EDGE_LIGHT, RoundedCornerShape(CARD_RADIUS))
|
|
|
|
|
.padding(12.dp),
|
|
|
|
|
) {
|
|
|
|
|
// TAGS FIRST, on a row of their own above the body: a board is scanned, and
|
|
|
|
|
// what a note is about should be the first thing the eye lands on. Not beside
|
|
|
|
|
// the body, whose first line is the note's name.
|
|
|
|
|
//
|
|
|
|
|
// Only labels whose text is not still in the note (`via_tag` is false). A tag
|
|
|
|
|
// left in prose is tinted in place instead (see [tintTags]), so this row holds
|
|
|
|
|
// what the body cannot say: a tag lifted off its own line, or one added by hand.
|
|
|
|
|
val chips = note.labels.filterNot { it.viaTag }
|
|
|
|
|
if (chips.isNotEmpty()) {
|
|
|
|
|
LabelChips(labels = chips)
|
|
|
|
|
Spacer(Modifier.height(8.dp))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// A note that is NOTHING but a URL renders as its preview and nothing
|
|
|
|
|
// else — printing the raw address under a card that already says where it
|
|
|
|
|
// goes is saying the same thing twice, badly. Until the unfurl lands, or
|
|
|
|
|
// if it never does, `preview` is null and the body falls through to
|
|
|
|
|
// NoteBody, which shows the URL. Never a blank card.
|
|
|
|
|
val lonePreview = remember(note.body, note.previews) { loneUrlPreview(note) }
|
|
|
|
|
|
|
|
|
|
// Body then checklist, in order — a note can carry both (M13 step 2). The
|
|
|
|
|
// first line of the body IS the note's name, at the same weight as the rest of
|
|
|
|
|
// it (M13 steps 3 and 4).
|
|
|
|
|
if (lonePreview != null) {
|
|
|
|
|
LinkPreviewCard(preview = lonePreview, compact = false)
|
|
|
|
|
} else if (note.body.isNotBlank()) {
|
|
|
|
|
// A note shared with us to view has inert boxes (#5175): ticking one is
|
|
|
|
|
// changing its text, which is not ours to do.
|
|
|
|
|
NoteBody(
|
|
|
|
|
note = note,
|
|
|
|
|
onToggleItem = if (note.access == NoteAccess.VIEW) INERT_TOGGLE else onToggleItem,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Links mentioned INSIDE a note: a compact strip at the foot of the card,
|
|
|
|
|
// under the note's own words rather than stacked on top of them. Putting
|
|
|
|
|
// them above would set a stranger's headline where the note's first line
|
|
|
|
|
// should be — the web learned that in M13 and moved them down.
|
|
|
|
|
if (!isLoneUrl(note) && note.previews.isNotEmpty()) {
|
|
|
|
|
Spacer(Modifier.height(8.dp))
|
|
|
|
|
note.previews.forEach { preview ->
|
|
|
|
|
LinkPreviewCard(preview = preview, compact = true)
|
|
|
|
|
Spacer(Modifier.height(4.dp))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Under the words and the links, like the web's card: a photo is often what a
|
|
|
|
|
// note is ABOUT, but its first line is still its name.
|
|
|
|
|
if (note.attachments.isNotEmpty()) {
|
|
|
|
|
CardAttachments(attachments = note.attachments)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// A note with nothing in it still has to occupy the board legibly — otherwise
|
|
|
|
|
// it reads as a rendering bug.
|
|
|
|
|
if (note.body.isBlank() && note.previews.isEmpty() && note.attachments.isEmpty()) {
|
|
|
|
|
Text(
|
|
|
|
|
text = stringResource(R.string.board_empty_note),
|
|
|
|
|
style = MaterialTheme.typography.bodyMedium,
|
|
|
|
|
fontStyle = FontStyle.Italic,
|
|
|
|
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
note.remindAt?.let { at ->
|
|
|
|
|
Spacer(Modifier.height(8.dp))
|
|
|
|
|
ReminderChip(instant = at, recurrence = note.recurrence)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SharedChip(note)
|
|
|
|
|
CardContents(note = note, onToggleItem = onToggleItem)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NoteMenu(
|
|
|
|
@@ -189,6 +121,83 @@ fun NoteCard(
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** What a card shows, top to bottom: tags, body, links, attachments, reminder, sharing. */
|
|
|
|
|
@Composable
|
|
|
|
|
private fun CardContents(
|
|
|
|
|
note: Note,
|
|
|
|
|
onToggleItem: (Int, Boolean) -> Unit,
|
|
|
|
|
) {
|
|
|
|
|
// TAGS FIRST, on a row of their own above the body: a board is scanned, and
|
|
|
|
|
// what a note is about should be the first thing the eye lands on. Not beside
|
|
|
|
|
// the body, whose first line is the note's name.
|
|
|
|
|
//
|
|
|
|
|
// Only labels whose text is not still in the note (`via_tag` is false). A tag
|
|
|
|
|
// left in prose is tinted in place instead (see [tintTags]), so this row holds
|
|
|
|
|
// what the body cannot say: a tag lifted off its own line, or one added by hand.
|
|
|
|
|
val chips = note.labels.filterNot { it.viaTag }
|
|
|
|
|
if (chips.isNotEmpty()) {
|
|
|
|
|
LabelChips(labels = chips)
|
|
|
|
|
Spacer(Modifier.height(8.dp))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// A note that is NOTHING but a URL renders as its preview and nothing
|
|
|
|
|
// else — printing the raw address under a card that already says where it
|
|
|
|
|
// goes is saying the same thing twice, badly. Until the unfurl lands, or
|
|
|
|
|
// if it never does, `preview` is null and the body falls through to
|
|
|
|
|
// NoteBody, which shows the URL. Never a blank card.
|
|
|
|
|
val lonePreview = remember(note.body, note.previews) { loneUrlPreview(note) }
|
|
|
|
|
|
|
|
|
|
// Body then checklist, in order — a note can carry both (M13 step 2). The
|
|
|
|
|
// first line of the body IS the note's name, at the same weight as the rest of
|
|
|
|
|
// it (M13 steps 3 and 4).
|
|
|
|
|
if (lonePreview != null) {
|
|
|
|
|
LinkPreviewCard(preview = lonePreview, compact = false)
|
|
|
|
|
} else if (note.body.isNotBlank()) {
|
|
|
|
|
// A note shared with us to view has inert boxes (#5175): ticking one is
|
|
|
|
|
// changing its text, which is not ours to do.
|
|
|
|
|
NoteBody(
|
|
|
|
|
note = note,
|
|
|
|
|
onToggleItem = if (note.access == NoteAccess.VIEW) INERT_TOGGLE else onToggleItem,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Links mentioned INSIDE a note: a compact strip at the foot of the card,
|
|
|
|
|
// under the note's own words rather than stacked on top of them. Putting
|
|
|
|
|
// them above would set a stranger's headline where the note's first line
|
|
|
|
|
// should be — the web learned that in M13 and moved them down.
|
|
|
|
|
if (!isLoneUrl(note) && note.previews.isNotEmpty()) {
|
|
|
|
|
Spacer(Modifier.height(8.dp))
|
|
|
|
|
note.previews.forEach { preview ->
|
|
|
|
|
LinkPreviewCard(preview = preview, compact = true)
|
|
|
|
|
Spacer(Modifier.height(4.dp))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Under the words and the links, like the web's card: a photo is often what a
|
|
|
|
|
// note is ABOUT, but its first line is still its name.
|
|
|
|
|
if (note.attachments.isNotEmpty()) {
|
|
|
|
|
CardAttachments(attachments = note.attachments)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// A note with nothing in it still has to occupy the board legibly — otherwise
|
|
|
|
|
// it reads as a rendering bug.
|
|
|
|
|
if (note.body.isBlank() && note.previews.isEmpty() && note.attachments.isEmpty()) {
|
|
|
|
|
Text(
|
|
|
|
|
text = stringResource(R.string.board_empty_note),
|
|
|
|
|
style = MaterialTheme.typography.bodyMedium,
|
|
|
|
|
fontStyle = FontStyle.Italic,
|
|
|
|
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
note.remindAt?.let { at ->
|
|
|
|
|
Spacer(Modifier.height(8.dp))
|
|
|
|
|
ReminderChip(instant = at, recurrence = note.recurrence)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SharedChip(note)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* What you can do to a note without opening it, on a long press.
|
|
|
|
|
*
|
|
|
|
|