mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-11-04 12:57:45 +00:00
core, ui: terminal chat layout for LLM and service bot chats (#7811)
* plan: UI improvements to improve LLM usage via SimpleX * core, ui: types for chat layout * core, ui: settings for alternative terminal-like chat layout for managing LLMs or other service bots * plan: message priority * fixes * query plan * update plans * remove silent messages plan * rename migrations * implement layout * amend * fix * fix * fix * improve * time on the right, sender name in blue * no avatar in direct chats * better previews * update, fixes * update * time gap * changes * ui: terminal layout line heights, gaps and time placement * ui: simplify terminal meta layout, correct its docs and tests * ui: right-to-left emoji edge in terminal rows, time placement tests * android, desktop: raise Kotlin compiler memory to 4 GB * ui: terminal captions as follow-up text, classic event separators * ui: terminal media edge and overlay time, plan decisions * ui: simplify terminal row separation, correct doc line references * ui: keep the media time inside terminal rows, restore caption conditions * ui: terminal heading capitals at large font scales, idle live message time * ui: rename the classic voice-with-text flag, correct the meta copy docs * ui: smaller terminal layout diff, sender gap and meta names * ui: terminal row as tall as the media time * docs: remove the chat layout section from the bots readme * docs: shorten the terminal layout section of the chat view * core: address settings API as on master, /auto_accept reads the stored layout * ui: smaller terminal headings * ui: classic sender rows and avatar rule as on master * ui: classic reply quote text colour as on master * ios: keep the chat layout setting with other UI settings * ui: go-to button at the end of terminal rows, no gutter in direct chats * ui: forwarded arrow on the header line of terminal rows, above the time * ui: forwarded arrow centred above the time line of terminal rows --------- Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
This commit is contained in:
1 parent
4f81c6f632
commit
7810fc4752
103 files changed
+5098
-901
No files matched your search
@@ -88,7 +88,7 @@ Common Module (commonMain)
|
||||
| API | [spec/api.md](api.md) | ChatController command dispatch, ~150 API functions in 11 categories, CC/CR/API types |
|
||||
| Database | [spec/database.md](database.md) | SQLite database files, migrations, encryption, backup/restore |
|
||||
| Impact | [spec/impact.md](impact.md) | Source file → product concept mapping for change impact analysis |
|
||||
| Chat View | [spec/client/chat-view.md](client/chat-view.md) | ChatView, ChatItemView, message rendering, item interactions |
|
||||
| Chat View | [spec/client/chat-view.md](client/chat-view.md) | ChatView, ChatItemView, message rendering, item interactions, terminal layout (TerminalItemView) |
|
||||
| Chat List | [spec/client/chat-list.md](client/chat-list.md) | ChatListView, ChatPreviewView, filtering, search, tags |
|
||||
| Compose | [spec/client/compose.md](client/compose.md) | ComposeView, SendMsgView, ComposeState, attachments, mentions |
|
||||
| Navigation | [spec/client/navigation.md](client/navigation.md) | App screen routing, onboarding, settings, new chat flows |
|
||||
@@ -104,7 +104,7 @@ Common Module (commonMain)
|
||||
| Category | Path | Topic |
|
||||
|---|---|---|
|
||||
| Overview | [product/README.md](../product/README.md) | Product overview, capability map, navigation map |
|
||||
| Concepts | [product/concepts.md](../product/concepts.md) | 30 product concepts (PC1-PC30) mapped to docs + source |
|
||||
| Concepts | [product/concepts.md](../product/concepts.md) | 32 product concepts (PC1-PC32) mapped to docs + source |
|
||||
| Glossary | [product/glossary.md](../product/glossary.md) | Domain term definitions (9 sections) |
|
||||
| Rules | [product/rules.md](../product/rules.md) | 18 business rules in 6 categories |
|
||||
| Gaps | [product/gaps.md](../product/gaps.md) | 8 known gaps with recommendations |
|
||||
|
||||
@@ -15,12 +15,13 @@ Source: `common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt
|
||||
7. [ChatInfoView](#7-chatinfoview)
|
||||
8. [GroupChatInfoView](#8-groupchatinfoview)
|
||||
9. [Source Files](#9-source-files)
|
||||
10. [Terminal Layout](#10-terminal-layout)
|
||||
|
||||
---
|
||||
|
||||
## Executive Summary
|
||||
|
||||
The Chat View is the primary message display and interaction surface in SimpleX Chat. It is built around the `ChatView` composable (line ~96 in `ChatView.kt`), which orchestrates a `ChatLayout` containing a reverse-scrolling `LazyColumn` of `ChatItemView` items and a `ComposeView` for message input. The view supports direct chats, group chats, local notes, and contact connections, with per-chat theming, search/filter, multi-select, and side-panel info modals. Message rendering is delegated to type-specific composables in the `views/chat/item/` package.
|
||||
The Chat View is the primary message display and interaction surface in SimpleX Chat. It is built around the [`ChatView`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt#L99) composable, which orchestrates a `ChatLayout` containing a reverse-scrolling `LazyColumn` of `ChatItemView` items and a `ComposeView` for message input. The view supports direct chats, group chats, local notes, and contact connections, with per-chat theming, search/filter, multi-select, and side-panel info modals. Message rendering is delegated to type-specific composables in the `views/chat/item/` package.
|
||||
|
||||
---
|
||||
|
||||
@@ -36,7 +37,10 @@ ChatView
|
||||
| | | |-- DateSeparator
|
||||
| | | |-- MemberNameAndRole (group received messages)
|
||||
| | | |-- MemberImage (group received messages)
|
||||
| | | +-- ChatItemView (message type routing)
|
||||
| | | |-- ChatItemView (message type routing)
|
||||
| | | +-- TerminalChatItemRow (terminal layout, replaces the three lines above)
|
||||
| | | |-- sender row, avatar in groups
|
||||
| | | +-- ChatItemView
|
||||
| | |-- ChatBannerView (first item: chat profile banner)
|
||||
| | +-- FloatingButtons (scroll-to-bottom, unread counter)
|
||||
| |-- ComposeView (message composition area)
|
||||
@@ -56,7 +60,7 @@ ChatView
|
||||
|
||||
## 2. ChatView Composable
|
||||
|
||||
**Location:** [`ChatView.kt#L97`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt#L97)
|
||||
**Location:** [`ChatView.kt#L98`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt#L98)
|
||||
|
||||
```kotlin
|
||||
fun ChatView(
|
||||
@@ -84,7 +88,7 @@ fun ChatView(
|
||||
|
||||
### Chat Loading
|
||||
|
||||
On chat ID change (via `snapshotFlow` on `chatModel.chatId.value`, line ~162):
|
||||
On chat ID change (via [`snapshotFlow` on `chatModel.chatId.value`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt#L180)):
|
||||
|
||||
1. Marks unread chat as read (`markUnreadChatAsRead`)
|
||||
2. Clears group members state
|
||||
@@ -95,7 +99,7 @@ On chat ID change (via `snapshotFlow` on `chatModel.chatId.value`, line ~162):
|
||||
|
||||
### Chat Type Routing
|
||||
|
||||
The outer `when (chatInfo)` (line ~229) branches:
|
||||
The outer [`when (chatInfo)`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt#L274) branches:
|
||||
|
||||
| ChatInfo Type | Behavior |
|
||||
|---|---|
|
||||
@@ -107,13 +111,13 @@ The outer `when (chatInfo)` (line ~229) branches:
|
||||
|
||||
## 3. Message List
|
||||
|
||||
**Location:** [`ChatView.kt#L1592`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt#L1592) (`ChatItemsList` composable)
|
||||
**Location:** [`ChatView.kt#L1757`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt#L1757) (`ChatItemsList` composable)
|
||||
|
||||
The message list is a `LazyColumnWithScrollBar` with `reverseLayout = true`, meaning index 0 is the newest message at the bottom of the screen.
|
||||
|
||||
### Key Behaviors
|
||||
|
||||
- **Merged Items:** Messages are grouped via `MergedItems.create()` (line ~1653), which collapses consecutive similar system events into expandable groups. Revealed state is tracked in `revealedItems`.
|
||||
- **Merged Items:** Messages are grouped via [`MergedItems.create()`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt#L1821), which collapses consecutive similar system events into expandable groups. Revealed state is tracked in `revealedItems`; `MergedItem.revealed` is true for a single item and for a revealed group row.
|
||||
- **Pagination:** `PreloadItems` triggers `loadMessages` with `ChatPagination.Before` (older) or `ChatPagination.Last` (newer) when the user scrolls near list boundaries.
|
||||
- **Scroll To Item:** `scrollToItem` lambda supports animated scrolling to a specific item ID, used by search result taps and quoted message navigation.
|
||||
- **Unread Marking:** `MarkItemsReadAfterDelay` composable marks newly visible received items as read after a brief delay.
|
||||
@@ -127,6 +131,7 @@ The message list is a `LazyColumnWithScrollBar` with `reverseLayout = true`, mea
|
||||
- **Group received without avatar:** Indented to align with avatar-bearing messages.
|
||||
- **Sent messages (group or direct):** Right-aligned with larger start padding.
|
||||
- **Direct messages:** Symmetric padding (76dp opposite side).
|
||||
- **Terminal layout:** When `LocalTerminalLayout.current` is true, all chat types render through `TerminalChatItemRow`, which wraps `ChatItemView`, instead of the branches above (see section 10). The selection offset applies to sent items too.
|
||||
|
||||
---
|
||||
|
||||
@@ -134,7 +139,7 @@ The message list is a `LazyColumnWithScrollBar` with `reverseLayout = true`, mea
|
||||
|
||||
## 4. ChatItemView
|
||||
|
||||
**Location:** [`item/ChatItemView.kt#L66`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/ChatItemView.kt#L66)
|
||||
**Location:** [`item/ChatItemView.kt#L70`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/ChatItemView.kt#L70)
|
||||
|
||||
```kotlin
|
||||
fun ChatItemView(
|
||||
@@ -171,6 +176,37 @@ The composable routes based on `cItem.content` and `cItem.meta.itemDeleted`:
|
||||
|
||||
Long-press or right-click opens a dropdown menu with context-sensitive actions (see section 6).
|
||||
|
||||
### Terminal Layout Adjustments
|
||||
|
||||
When `LocalTerminalLayout.current` is true, `ChatItemView` and the item views it calls keep their content and start at one text edge, `CHAT_ITEM_TEXT_PADDING` (12dp) inside the item; messages are drawn without the bubble fill and tail:
|
||||
|
||||
- Items are start-aligned for both directions ([`alignEnd`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/ChatItemView.kt#L125)). The item click has no indication; the row draws it (section 10). `GoToItemButton` is placed as described in section 10 ([L345](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/ChatItemView.kt#L345), [L817](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/ChatItemView.kt#L817)). Voice items use the arrangement of received items for both directions.
|
||||
- [`chatItemTailEnabled()`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/ChatItemView.kt#L1220) returns false, so `shapeStyle` draws no tail.
|
||||
- `FramedItemView` has a transparent background. Headers (report, moderated, blocked, deleted, live, forwarded) and the quote have no background and start at the text edge. The quote has the bar of Markdown quotes ([`Modifier.quoteBar`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/MarkdownBlocks.kt#L151)), its text in `onSurface` at 70%, 15sp. The bar and the padding, `TERMINAL_BLOCK_TOP_GAP` (5.75sp) above and `TERMINAL_BLOCK_BOTTOM_GAP` (5sp) below, span the whole quote row, including an image or video thumbnail; the thumbnail has the message corner clip of media (`thumbnailClip`, `clipChatItem`, rounded by the `chatItemRoundness` preference, square at 0); the file, voice and chat link icons of the quote have no top padding. Headers: `TERMINAL_HEADER_TOP_GAP` (2.5sp) above, `TERMINAL_HEADER_BOTTOM_GAP` (1.5sp) below; the header text uses `terminalTextStyle` at its size in `secondary`, and the icon is centred on it and takes no height (`Modifier.inlineIcon()`).
|
||||
- Images, videos, link previews and chat link cards start at the text edge, `TERMINAL_BLOCK_TOP_GAP` below the part above them, and keep the message corner clip ([`mediaModifier`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/FramedItemView.kt#L56)). Link previews and chat links are cards in the quote colour ([`cardModifier`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/FramedItemView.kt#L58)). The item itself is not clipped (`clipChatItem` of `FramedItemView` and `ChatItemView` is skipped), so headings and emoji are drawn whole. An image or video without caption, or a chat link card without text (`gapBelowBlock`, computed with `metaReserved`, which is passed to `ItemWithMeta`), has `TERMINAL_BLOCK_BOTTOM_GAP` below it, outside `ItemWithMeta`. Captions are selected by the classic conditions.
|
||||
- Captions (user, D30): the text below an image, video, link preview, chat link card, voice message or file is laid out as the text of a close follow-up message, the time on it only. `PriorityLayout` measures it in the full width of the item (`limitToPriorityWidth = false`; classic: the width of the media) and places the elements at the start edge in both directions (`placeRelative`), the caption of a link preview has no width limit (classic: `DEFAULT_MAX_IMAGE_WIDTH`), and a chat link card keeps its own width (`width(IntrinsicSize.Max)`). Its gap below the media is the gap from the same media without text to a close follow-up message. An image or video without caption keeps the classic limit (`limitToPriorityWidth = true`): a quote or header above it takes the width of the media, so the white time over the media stays on its bottom end corner.
|
||||
- [`CIMarkdownText`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/FramedItemView.kt#L481): top padding `terminalTop` (required): 0 below the sender row, a header, the quote, a voice message or a file, `TERMINAL_BLOCK_BOTTOM_GAP` below an image, video, link preview or chat link card; plus [`terminalHeadingGap(item)`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/TerminalItemView.kt#L121-L122), `TERMINAL_LEVEL_STEP` when the text starts with a heading and is not at the top of the item (below a quote, a header or a block); no bottom padding. Its text style: `body1` in `messageTextColor()`, merged with `terminalTextStyle` at the `body1` size. The default style of `MarkdownText` is classic and is used outside the rows (the compose context preview).
|
||||
- Code block cards, table cards and rules of `MarkdownBlocks`: `TERMINAL_BLOCK_TOP_GAP` above, `TERMINAL_BLOCK_BOTTOM_GAP` below, except the last block of a message without a meta line (`marksLastBlock`; a live message has the meta line with the typing indicator, so its last block keeps the gap). That block has no bottom margin and is marked with `messageLastBlock()`: `TERMINAL_BLOCK_BOTTOM_GAP` is added below it when the time stays beside it, and the time moved under it is `TERMINAL_META_GAP` below its edge (section 10). In a message of rules only, the rules are at least as wide as the copy of the time (`ruleMinWidth` of `MarkdownBlocks`, measured by `MarkdownText`; user, D31), as in classic, where the meta line sets the width; the time stays beside them unless a wider quote or header widens the item so that the rule leaves no room for the time.
|
||||
- Text blocks of [`MarkdownBlocks`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/MarkdownBlocks.kt#L59): a paragraph break, and a heading that does not start the text, add `TERMINAL_LEVEL_STEP` (4.75sp) (classic: half the line height, before a paragraph break only); above a heading that starts the text, the gap is added by `terminalRowGap` or `terminalHeadingGap`. A block after a heading, other than a heading, has `TERMINAL_HEADING_BOTTOM_GAP` (half of `TERMINAL_LEVEL_STEP`, 2.375sp) above it instead, so a heading is nearer to its own text than to the text above it.
|
||||
- Text styles: [`terminalTextStyle(fontSize, color)`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/TerminalItemView.kt#L78-L84) sets the line height to font size × `TERMINAL_LINE_HEIGHT_RATIO` (22/16) × f(w) and `LineHeightStyle(Proportional, Trim.None)`. Every line takes the full line height, one-line texts included. The space added to a line is split in the ratio of the font's ascent to its descent. On desktop each run of a line is given its own line box; with this alignment, runs of different sizes (the 12sp time in the copy of the meta) are placed on one baseline in a line of the body line height. f(w) = 1 − `TERMINAL_LINE_HEIGHT_CONTRAST_SLOPE` (0.1515) × (1 − w); w: the L* contrast of the text colour against `MaterialTheme.colors.background`, divided by that of `messageTextColor()`, limited to 0…1, and 1 when the message text has no contrast. Used for message text and captions (the style of `CIMarkdownText`), Markdown quotes (text colour at 70%), code, headings (body line height × scale), quote text and the quote's sender (in `body1`, Inter, in terminal rows), the sender name and role, event texts ([`chatEventTextStyle(base)`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIEventView.kt#L22-L28): 12sp, `secondary`, merged into `base`, by default `LocalTextStyle.current`; classic: `base`; in both layouts the text direction is left unspecified, which Compose resolves to the layout direction, so that an event starting with a name in the opposite direction keeps the copy of the time at the end of the row), header texts and the time (classic: unchanged). For names and the white time over media (`lineHeightColor` of `CIMetaView`), f is computed with the message text colour. Line heights in the light and dark themes: message text 22sp, quote text 19.6sp and 20.1sp, event text and time 15.1sp and 15.5sp.
|
||||
- Headings: body size × `TERMINAL_HEADING_RATIO` (1.3125) to the power 2, 1, 0 for levels 1, 2, 3, 27.6, 21 and 16sp for 16sp text; levels 4–6 also at the body size; all bold (classic: 1.5, 1.3, 1.15); line heights scaled the same. `Modifier.headingBox` lays a heading out with the space of a body line above its capitals and below its last baseline (Inter cap height 2048/2816 em). It uses the px ratio of the body and heading font sizes: Android scales font sizes non-linearly from font scale 1.03 and, above 1.05, sets line heights in proportion to the font size in px, so the capitals are placed as body capitals at every font scale (within 1px at 1, 1.15 and 1.3).
|
||||
- Files: `TERMINAL_FILE_TOP_GAP` (2sp) above the file row, no padding below, no padding of its icon. Voice messages drawn by `FramedItemView` (with a caption, a quote or a header; `hasText = true`): the layout of a voice message drawn alone (4sp above, 6sp below, its indicator), without its own time; no padding below the item.
|
||||
- Emoji-only items, also under a quote or a header: `TERMINAL_EMOJI_TOP_GAP` (4.25sp) above, `TERMINAL_EMOJI_BOTTOM_GAP` (1.5sp) below (classic: 8dp; under a quote or header 6dp above, 8dp below). Under a quote or a header the emoji is not stretched to the item width, so its reported last line is the emoji itself; `PriorityLayout` places it at the start edge in both directions.
|
||||
- Item gaps: one gap above each row, [`terminalRowGap(item, older, separated, largeGap, hasSenderRow)`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/TerminalItemView.kt#L118-L119), passed by `ChatItemsList` as `topGap` of the row. It is `TERMINAL_LEVEL_STEP` when an older item exists, the rows are not separated and one of these holds: the gap to the older item is large; the row shows a sender row; either item is an event (content without a terminal sender); the text of the item is at its top (text or unknown content without a file, without quote, header, deletion, live state or report) and its first block is a heading. Otherwise it is 0. `separated` (`terminalRowsSeparated`): a date separator is drawn between the two rows (the older row is revealed, a single item or a revealed group row, and its date differs from that of the oldest item of the row), or the older item is the chat banner. For a collapsed group, `older` is the item older than the group, and `largeGap` is computed against the oldest item of the group. The bottom of a row is `TERMINAL_LEVEL_STEP` when a date separator is drawn below it, 8dp for the newest row, as classic, otherwise 0 (`ChatItemBox(top, bottom)`; classic: 1dp or 4dp above, 1dp or 4dp below). Above a sender row, `TERMINAL_SENDER_TOP_GAP` (6.5sp) is added; below the name, `TERMINAL_SENDER_BOTTOM_GAP` (5.5sp). The gaps are constants in sp at the top of `TerminalItemView.kt`, converted to dp with the font scale. The bottom padding of call items (8dp), the paddings of voice messages drawn without `FramedItemView` (no caption, quote, header, deletion or live state; 4sp above, 6sp below) and the 6dp between the two rows of the forwarded-from header are classic.
|
||||
- Vertical gaps, measured from the baseline (or a block's bottom edge) to the top of the tallest letter, a heading's capitals, or a block's top edge:
|
||||
|
||||
```
|
||||
level 1 lines of a quote
|
||||
level 2 lines of a message; messages of one sender within 60 seconds; a block against the text line or block next to it
|
||||
level 3 messages of one sender 60 seconds or more apart; sender name → message or header; paragraph break; above a heading, also at the start of a message
|
||||
level 4 last line of a message → next sender name; above and below an event
|
||||
```
|
||||
- Event, feature and member-created items use [`chatEventPadding(vertical)`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIEventView.kt#L30-L33): in terminal rows the text edge at the sides, `TERMINAL_EVENT_TOP_GAP` (8.25sp) above and `TERMINAL_EVENT_BOTTOM_GAP` (1.5sp) below, so that the capitals of the event text are where the capitals of a sender name would be and its last baseline is as far from the row end as that of a message line (classic: 6dp at the sides, `vertical` above and below, 6dp by default, 8dp for the merged feature icons). The icons of feature and preference items are centred on the text and take no height (`Modifier.inlineIcon()`); the row of merged feature icons is one event text line high. `CIEventView` has no line limit in terminal rows, so the copy of the time stays at the end of the text (user, D23; classic: 4 lines). Voice and call items and reactions start at the text edge.
|
||||
- Time and status: placed at the end of the row by [`ItemWithMeta`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/TerminalItemView.kt#L200-L214), the baseline of the time on the last baseline of the content (section 10). Message text ends with [`terminalReserveSpaceForMeta`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIMetaView.kt#L227-L270): a transparent copy of the meta joined to the last word by no-break spaces, in `FontWeight.Normal`. The copy starts with a word joiner (U+2060), which forbids a line break before the copy, also after the three spaces of an idle live message (`noTyping`), so the time is not moved alone to the next line. The direction mark of its paragraph follows (U+200E left-to-right, U+200F right-to-left), so that the bidirectional algorithm places the copy at the end of the line, also after words in the other direction on a wrapped last line. Its spaces and texts are appended by [`reserveSpaceForMeta`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIMetaView.kt#L145-L225), which has the conditions of `CIMetaText`, except that the timer is reserved for every timed message, and returns the classic string unchanged, through span parameters: icon spaces and the spaces between them are no-break spaces at the `body1` size in dp (16dp converted to sp with the density, so that they keep their width at every font scale, as the icons do; also after a heading and in event text), 18dp for each icon, wider than a 12dp icon with its spacer (15dp or 16dp); after the 17dp icons one more space is added (22.5dp against 21dp): the sent and received status icons (`tallStatusIcon`, also used by `CIMetaText`) and the via-proxy icon; the time and the timer text of a disappearing message are at 12sp. The copy includes the file encryption and signature icons (`encrypted` and `signedFileVerified` of `MarkdownText`, passed by `CIMarkdownText` from the item). When the last word and the copy do not fit in the line, the last word moves to the next line with the time. Text whose paragraph direction (`textLayoutDirection`: right-to-left when the first 50 characters of the message text hold a right-to-left character; all blocks and lines of a message take it) differs from the outer direction (`parentDirection`, passed by the blocks and by the meta line of a live message; otherwise `LocalLayoutDirection`) ends with a line break instead of the copy, so the time is placed on an added empty line. Emoji, and the last code block, table or rule of a message, report their width (`Modifier.messageLastLine()`, `Modifier.messageLastBlock()`); the time moves under them when the row leaves no room for it beside them. The meta line with the time is drawn under such a block only for live messages, for the typing indicator. File text keeps the space reserved for the time at the end of its size line. Images and videos without a caption (`captionlessMedia`) keep the meta in `secondary` beside the media when it fits in the row, otherwise the meta is drawn over the bottom end of the media in white, as in the classic layout (`overlayMeta`). Event items are wrapped in [`ChatEventWithMeta`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIEventView.kt#L35-L48), which passes the separator and the end of the event text apart (`separator`, `ts`): in the classic layout two spaces and the time without a style, in the terminal layout three transparent no-break spaces in `chatEventStyle` and the transparent `terminalReserveSpaceForMeta` of the meta without status and edit icons, so the last word of the event text is moved to the next line with the time when they do not fit. Each view puts the separator where the classic layout has two spaces (user, D28): after the event text, or in the "Open" and "Accept" links, so the classic output is unchanged.
|
||||
- Group invitations, deleted items and error items (`IntegrityErrorItemView`, `CIRcvDecryptionError`) keep their rounded coloured card.
|
||||
|
||||
Both layouts: `MarkdownText` draws message text in [`messageTextColor()`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/TextItemView.kt#L54), `onSurface` at 87% in dark themes.
|
||||
|
||||
---
|
||||
|
||||
## 5. Message Types
|
||||
@@ -316,6 +352,7 @@ Key sections: group profile, group link, member list with roles, group preferenc
|
||||
| `MarkdownFileView.kt` | Markdown file viewer, formatted or as text |
|
||||
| `IntegrityErrorItemView.kt` | Message integrity error |
|
||||
| `MarkedDeletedItemView.kt` | Marked-as-deleted / moderated message |
|
||||
| `TerminalItemView.kt` | Terminal layout: `LocalTerminalLayout`, sender row rule, `TerminalChatItemRow`, `ItemWithMeta` |
|
||||
| `TextItemView.kt` | Plain text message with markdown; blocks of `markdownBlocks` drawn as a column of views by `MarkdownBlocks` (`MarkdownBlocks.kt`) |
|
||||
|
||||
### `views/chat/group/`
|
||||
@@ -343,3 +380,139 @@ Key sections: group profile, group link, member list with roles, group preferenc
|
||||
When a relay operator runs `/leave #channel`, the relay sends `x.grp.relay.reject` over the owner-relay direct contact channel. Owner-side handling: the corresponding `GroupRelay.relayStatus` transitions `RSInvited → RSRejected`; the relay's `GroupMember.memberStatus` is set to `MemLeft` so the owner UI renders the rejected relay identically to one that explicitly ran `/leave` (`MemRejected` is reserved for the knocking-admission flow). In `GroupMemberInfoView`, an additional "Status: rejected by relay operator" `InfoRow` appears when `groupRelay?.relayStatus == RelayStatus.RsRejected`. The status is final on the owner side — clearable only by the relay operator running `/group allow #<channel>`, which has no owner-facing event.
|
||||
|
||||
The `RelayStatusIndicator` composable in `AddChannelView.kt` renders `RsRejected` with a red dot and "rejected" text, matching the `connFailed`/`removed` rendering.
|
||||
|
||||
---
|
||||
|
||||
<a id="TerminalLayout"></a>
|
||||
|
||||
## 10. Terminal Layout
|
||||
|
||||
**Location:** [`item/TerminalItemView.kt`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/TerminalItemView.kt)
|
||||
|
||||
Rendering of a chat whose [`ChatInfo.activeChatLayout`](../state.md) is `ChatLayoutMode.Terminal`: full-width start-aligned rows, the sender name once per group of messages, avatars in groups only, messages without bubbles (item-level changes: section 4). Android and desktop; iOS draws the classic layout.
|
||||
|
||||
### Activation
|
||||
|
||||
| Step | Location |
|
||||
|---|---|
|
||||
| `terminal = chatInfo.activeChatLayout(user) == ChatLayoutMode.Terminal` | [`ChatView`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt#L268) |
|
||||
| `LocalTerminalLayout provides terminal`, next to `LocalAppBarHandler` and `LocalSelectionManager` | [`ChatView`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt#L269-L273) |
|
||||
| `drawWallpaperImage = false` of `chatViewBackgroundModifier` | [`ChatLayout` composable](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt#L1010) |
|
||||
|
||||
[`LocalTerminalLayout`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/TerminalItemView.kt#L56) is `false` outside `ChatView` and the theme screens (below); chat item info keeps the classic look. The value applies to every `ChatView` of the chat: main view, member support chats and reports.
|
||||
|
||||
Colours: the app, user and chat themes apply as in the classic layout. Wallpaper: `chatViewBackgroundModifier` fills the chat with the background colour of the wallpaper (preset or custom) and omits the image.
|
||||
|
||||
### Functions
|
||||
|
||||
| Function | Purpose |
|
||||
|---|---|
|
||||
| [`terminalTextStyle(fontSize, color)`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/TerminalItemView.kt#L78-L84) | Terminal: line height and line height style of a text in the rows (section 4); classic: `TextStyle.Default`, so that merging it changes nothing |
|
||||
| [`terminalItemShowsSender(item, older)`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/TerminalItemView.kt#L102-L103) | Whether a row shows the sender row (sender rule below). `older`: the next older item in the list |
|
||||
| [`sameSender(item, older)`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/TerminalItemView.kt#L105-L113) | Private; same sender for grouping |
|
||||
| [`terminalRowGap(item, older, separated, largeGap, hasSenderRow)`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/TerminalItemView.kt#L118-L119) | The gap above a row (section 4, item gaps): `TERMINAL_LEVEL_STEP` or 0. Used by `ChatItemsList` and the theme preview |
|
||||
| [`terminalHeadingGap(item)`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/TerminalItemView.kt#L121-L122) | `TERMINAL_LEVEL_STEP` above a heading that starts the text of an item below a quote, a header or a block; added to the top padding of `CIMarkdownText` |
|
||||
| [`ChatItem.hasQuoteOrHeader`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/ChatItemView.kt#L836-L837) | A quote, a forwarded header, a deletion, the live state or a report: the item is drawn by `FramedItemView` with a quote or header above its content. Used by `ChatItemView` to choose `EmojiItemView` or `CIVoiceView` and by the heading gaps |
|
||||
| [`CIContent.hasTerminalSender`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/TerminalItemView.kt#L130-L137) | Private. True for sent messages, sent deleted and moderated items, sent calls and group invitations, and received content with `showMemberName` (messages, deleted, moderated and blocked items, calls, errors, group invitations, invalid JSON); false for events, feature and preference changes, E2EE info and the chat banner |
|
||||
| [`TerminalRowInteractionSource`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/TerminalItemView.kt#L139-L153) | Interaction source of the row and its item: press interactions are emitted at the position where the pointer went down in the row, so the ripple starts there |
|
||||
| [`Modifier.terminalRowIndication(source)`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/TerminalItemView.kt#L155-L166) | Records the pointer-down position; hover and press indication of the whole row |
|
||||
| [`Modifier.terminalStartOffset(offset)`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/TerminalItemView.kt#L168-L173) | Shifts the row by the selection offset and narrows it by the same amount |
|
||||
| [`Modifier.messageLastLine()`, `Modifier.messageLastBlock()`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/TerminalItemView.kt#L179-L187) | `messageLastLine()` sets the private alignment lines `LastLineLeft` and `LastLineRight` to the left and right edges of the element: emoji. `messageLastBlock()` also sets `LastBlockBottom` at the bottom edge of the element: the last code block, table or rule of a message without a meta line, which has no bottom margin |
|
||||
| [`Modifier.inlineIcon()`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/TerminalItemView.kt#L189-L198) | Terminal: lays the element out with no height, centred on its position, so that a row with `Alignment.CenterVertically` takes the height of its text and centres the element on it: icons of feature and preference items and of message headers. Classic: the modifier unchanged |
|
||||
| [`ItemWithMeta(meta, overlayMeta, metaReserved, endButton, content)`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/TerminalItemView.kt#L200-L214) | Classic: `content` with the meta passed as `inlineMeta`. Terminal: `content` without meta, and the meta in a box with 12dp end padding at the end of the available width, the message column of the row (private [`TerminalMetaLayout`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/TerminalItemView.kt#L216-L256)). `endButton`, in a box with the same end padding, is placed at the end of the row, centred vertically between the content top and the top of the time box (the whole content when the time is over media); the content is measured in the width less the wider of this box and, without `metaReserved`, the time box. The meta is measured first. Without `metaReserved` and `overlayMeta`, the content is measured in the width less the width of the box, so that it does not reach under the time. `metaReserved` is true for content with its own reserve of the space or a reported last line: text with the transparent copy (`metaReserved` of `FramedItemView`), files, emoji and event items. The first baseline of the box (the baseline of the time; without a time, the baseline of a 12sp time centred in the box) is placed on the last baseline of the content. When the content reports its last line and the line and the box together are wider than the row, the box is placed `TERMINAL_META_GAP` (6sp) under the content and the bottom of the row moves down by that gap and the height of the box. When the box stays beside a last block reported with `LastBlockBottom` at the content bottom (a table, or a code card or rule, which span the width of the item), `TERMINAL_BLOCK_BOTTOM_GAP` is added below the content. Content without a baseline (a message of a rule only, a failed call), and captionless media with `overlayMeta`: the box ends `TERMINAL_META_GAP` above the content bottom; when the content and the box together are wider than the row, the `overlayMeta` box is placed at the bottom end of the content instead, `TERMINAL_META_GAP` above its bottom. Either box is placed at the top of the content at most, and the row is at least as tall as the box. When the rule leaves room for the time beside it, the time stays on the baseline of the last text line above it (D24); otherwise it is placed under the rule. |
|
||||
| [`ChatItemSender`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/TerminalItemView.kt#L258) | Name, badge, role label, `own`, avatar |
|
||||
| [`chatItemSender(chatInfo, cItem, range, reversedChatItems, showMemberInfo, showChatInfo)`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/TerminalItemView.kt#L260-L307) | Sender of a row (table below) |
|
||||
| [`SenderNameAndRole(sender, modifier)`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/TerminalItemView.kt#L312-L335) | Private; name and badge (13.5sp; primary for own items, secondary otherwise) and role label |
|
||||
| [`terminalGutter(chatInfo)`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/TerminalItemView.kt#L337-L339) | Gutter width: the member image size (scaled by `fontSizeSqrtMultiplier`) plus 4dp in groups, 0 in other chats |
|
||||
| [`TerminalChatItemRow(sender, gutter, topGap, modifier, senderTopGap, content)`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/TerminalItemView.kt#L341-L383) | Row layout below |
|
||||
|
||||
In `ChatView.kt`, shared with the classic date separator:
|
||||
|
||||
| Function | Purpose |
|
||||
|---|---|
|
||||
| [`terminalRowsSeparated(olderRow)`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt#L3817-L3820) | A date separator or the chat banner between a row and the older row: the newest item of the older row is the banner, or [`rowItemSeparation(row)`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt#L3812-L3815) of the older row has a date. False without an older row |
|
||||
| `rowItemSeparation(row)` | Private; the separation of a row, also used by `ChatItemsList` for the date separator it draws: `getItemSeparation` of the newest item of the row and the next newer item (the oldest item of the newer row) when the row is revealed (`MergedItem.revealed`: a single item or a revealed group row), without the newer item otherwise (user, D32) |
|
||||
|
||||
### Row Layout
|
||||
|
||||
```
|
||||
row padding top: topGap (terminalRowGap), plus senderTopGap (TERMINAL_SENDER_TOP_GAP, 6.5sp) with a sender row; start 8dp; end 12dp
|
||||
gutter terminalGutter(chatInfo)
|
||||
avatar top of the gutter, sender rows of groups only
|
||||
message column starts at the gutter
|
||||
sender row name and badge (13.5sp; primary for own messages, secondary otherwise), role label; start padding CHAT_ITEM_TEXT_PADDING; text style terminalTextStyle(13.5sp)
|
||||
item ChatItemView; TERMINAL_SENDER_BOTTOM_GAP (5.5sp) below the sender row
|
||||
```
|
||||
|
||||
`ChatItemsList` passes [`showAvatar`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt#L2460) = `terminalItemShowsSender(item, merged.oldest().nextItem)`, and the row gets `chatItemSender(...)` when it is true, `null` otherwise; the [gap above the row](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt#L2461-L2466), with `terminalRowsSeparated` of the older row (the next merged item of the reversed list), is passed to `ChatViewListItem` as `terminalGap`.
|
||||
|
||||
### Sender Rule
|
||||
|
||||
`terminalItemShowsSender`: a row shows the sender row when the item has a sender (`hasTerminalSender`) and one of these holds:
|
||||
|
||||
- it is the oldest loaded item;
|
||||
- the older item has no sender (an event);
|
||||
- `sameSender` is false.
|
||||
|
||||
The time between the items and a date change do not repeat the sender row.
|
||||
|
||||
`sameSender`: when either item is posted as the channel (`ChannelRcv`, or `GroupSnd` with `meta.showGroupAsSender`), both must be; two `GroupRcv` items need the same `memberId`; other items need the same direction class.
|
||||
|
||||
### Sender Resolution
|
||||
|
||||
| Direction | Name and badge | Role label | Avatar | Avatar click | Own colour |
|
||||
|---|---|---|---|---|---|
|
||||
| `ChannelRcv`, `GroupSnd` with `showGroupAsSender` | Channel name | "channel" (`channel_role_label`) | `ProfileImage` of the group, as in the classic layout | `showChatInfo` | For `GroupSnd` |
|
||||
| `DirectRcv` | Contact display name and badge | None | None | None | No |
|
||||
| `GroupRcv` | `memberNames` of the merged members; badge for one member | Member role when above `Member`, for one member | `MemberImage` | `showMemberInfo` | No |
|
||||
| `GroupSnd` | `groupInfo.membership` display name and badge | Membership role when above `Member` | `MemberImage(membership)` | None | Yes |
|
||||
| Other, incognito chat | "Incognito" | None | None | None | Yes |
|
||||
| Other (`DirectSnd`, `LocalSnd`, `LocalRcv`) | Current user display name and badge | None | None | None | Yes |
|
||||
|
||||
The sender row has no time; the time of every item is placed by `ItemWithMeta`.
|
||||
|
||||
### Row Background
|
||||
|
||||
| State | Background |
|
||||
|---|---|
|
||||
| Selected (selection mode) | `primary` at 10% |
|
||||
| Highlighted (`highlightedItems` contains the item, e.g. after jumping to a quoted message) | `primary` at 14% |
|
||||
| Otherwise | Transparent |
|
||||
|
||||
Hover and press are drawn by `terminalRowIndication` over the whole row.
|
||||
|
||||
### Go-to Button
|
||||
|
||||
[`GoToItemButton`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/ChatItemView.kt#L290) is activated by the row hover (`parentActivated`; the row interaction source is passed as `bubbleInteractionSource`).
|
||||
|
||||
- Search results: the search icon is drawn by `ChatItemView` after the item, as for classic received items: at the end of the row, centred on the item; every row of the results is narrowed by the button and its 13dp start padding, so their times stay aligned.
|
||||
- Forwarded items drawn by `FramedItemView`: the arrow is passed as `endButton` and placed by `ItemWithMeta` at the end of the row, centred on the item above the line with the time (the forwarded header line for a one-line message); the text is narrowed by the arrow, and the time keeps its place.
|
||||
- Forwarded items shown as marked deleted (`markedDeleted`, no header line): the arrow after the item, as in search results.
|
||||
|
||||
### Selection and Swipe
|
||||
|
||||
The selection checkbox (8dp start padding) and the full-row selection click overlay are shared with the classic layout. The row is moved by `Modifier.terminalStartOffset` for sent and received items alike. Swipe to reply uses the `swipeableModifier` of the classic layout on the whole row (Android; off in selection mode).
|
||||
|
||||
### Theme Screens
|
||||
|
||||
`LocalTerminalLayout` is provided to the theme screens of a terminal chat or profile:
|
||||
|
||||
| Screen | Value |
|
||||
|---|---|
|
||||
| Chat theme ([`ChatWallpaperEditorModal`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatInfoView.kt#L1300)) | `activeChatLayout` of the chat |
|
||||
| Appearance › Themes, preset selector ([`ThemesSection`](../../common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/Appearance.kt#L581)) | `profileChatLayout` of the current user, or of none for the app theme destination |
|
||||
| Customize theme, profile theme, colour editors | the same, through `profileLayoutIsTerminal` and the `terminal` parameter of `editColor` |
|
||||
|
||||
With the value true:
|
||||
|
||||
- the preview draws two terminal rows ("alice", then "bob" in the own colour) without gutter, the gap between them by `terminalRowGap` and `TERMINAL_SENDER_TOP_GAP`, as in the chat; [`PreviewInEitherLayout`](../../common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/Appearance.kt#L337) measures both layouts and shows the active one centred in the larger height, so a layout switch keeps the preview height;
|
||||
- the preview and the preset tiles show the wallpaper colour without the image;
|
||||
- the custom image tile, the image scale, the scale slider and the wallpaper accent row are hidden.
|
||||
|
||||
Layout controls:
|
||||
|
||||
| Control | Values | Stored in |
|
||||
|---|---|---|
|
||||
| Chat theme screen, first section ([`ChatLayoutSection`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatInfoView.kt#L1313)) | the chat default, "(chat)" when the chat layout is the default, otherwise "(default)"; the other layout | chat theme record, by [`setChatLayout`](../../common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatInfoView.kt#L1382) and `apiSetChatUIThemes` |
|
||||
| Appearance › Themes, app theme destination ([`ChatLayoutRow`](../../common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/Appearance.kt#L950)) | Classic, Terminal; the selection is `profileChatLayout(null)` | `appPrefs.chatLayout` |
|
||||
| Appearance › Themes, profile destination | `profileChatLayout(null)` "(default)"; the other layout | profile theme record, by `saveThemeToDatabase` and `apiSetUserUIThemes` |
|
||||
@@ -41,6 +41,7 @@
|
||||
| PC29 | User Address |
|
||||
| PC30 | Member Support Chat |
|
||||
| PC31 | Channels (Relays) |
|
||||
| PC32 | Terminal Chat Layout |
|
||||
|
||||
---
|
||||
|
||||
@@ -52,13 +53,13 @@ Path prefix: `common/src/commonMain/kotlin/chat/simplex/common/`
|
||||
|
||||
| Source File | Product Concepts Affected | Risk Level | Notes |
|
||||
|-------------|--------------------------|------------|-------|
|
||||
| `App.kt` | PC1 through PC31 | High | Root composable — navigation scaffold for all features |
|
||||
| `App.kt` | PC1 through PC32 | High | Root composable — navigation scaffold for all features |
|
||||
| `AppLock.kt` | PC22 | Medium | App lock state and authorization lifecycle |
|
||||
| `model/ChatModel.kt` | PC1 through PC31 | High | Central state object — every feature reads or writes here |
|
||||
| `model/SimpleXAPI.kt` | PC1 through PC31 | High | FFI bridge to Haskell core — all commands and responses |
|
||||
| `model/ChatModel.kt` | PC1 through PC32 | High | Central state object — every feature reads or writes here |
|
||||
| `model/SimpleXAPI.kt` | PC1 through PC32 | High | FFI bridge to Haskell core — all commands and responses |
|
||||
| `model/CryptoFile.kt` | PC10, PC23 | Medium | Encrypted file read/write helpers |
|
||||
| `platform/Core.kt` | PC1 through PC31 | High | Native FFI declarations (`chatMigrateInit`, `chatSendCmd`, etc.) — all API traffic |
|
||||
| `platform/AppCommon.kt` | PC1 through PC31 | Medium | Shared app initialization logic |
|
||||
| `platform/Core.kt` | PC1 through PC32 | High | Native FFI declarations (`chatMigrateInit`, `chatSendCmd`, etc.) — all API traffic |
|
||||
| `platform/AppCommon.kt` | PC1 through PC32 | Medium | Shared app initialization logic |
|
||||
| `platform/Files.kt` | PC10, PC23, PC26 | Medium | File path resolution, temp dirs, encryption utilities |
|
||||
| `platform/NtfManager.kt` | PC18 | High | Notification manager expect declarations |
|
||||
| `platform/Notifications.kt` | PC18 | Medium | Notification channel and permission abstractions |
|
||||
@@ -68,7 +69,7 @@ Path prefix: `common/src/commonMain/kotlin/chat/simplex/common/`
|
||||
| `platform/Cryptor.kt` | PC23 | Medium | Keystore encryption expect declarations |
|
||||
| `platform/Share.kt` | PC10, PC12 | Low | Share sheet abstractions |
|
||||
| `platform/Images.kt` | PC10, PC19 | Low | Image processing utilities |
|
||||
| `platform/Platform.kt` | PC1 through PC31 | Low | Platform detection and capability flags |
|
||||
| `platform/Platform.kt` | PC1 through PC32 | Low | Platform detection and capability flags |
|
||||
| `platform/PlatformTextField.kt` | PC4 | Low | Native text input expect declarations |
|
||||
| `platform/Back.kt` | PC1 | Low | Back navigation handling |
|
||||
| `platform/UI.kt` | PC24 | Low | UI density and locale helpers |
|
||||
@@ -82,7 +83,7 @@ Path prefix: `common/src/commonMain/kotlin/chat/simplex/common/`
|
||||
| Source File | Product Concepts Affected | Risk Level | Notes |
|
||||
|-------------|--------------------------|------------|-------|
|
||||
| `ui/theme/ThemeManager.kt` | PC24 | Medium | Theme resolution engine — all color and wallpaper logic |
|
||||
| `ui/theme/Theme.kt` | PC24 | Medium | Theme composables and `SimpleXTheme` |
|
||||
| `ui/theme/Theme.kt` | PC24, PC32 | Medium | Theme composables and `SimpleXTheme` |
|
||||
| `ui/theme/Color.kt` | PC24 | Low | Color palette definitions |
|
||||
| `ui/theme/Shape.kt` | PC24 | Low | Shape token definitions |
|
||||
| `ui/theme/Type.kt` | PC24 | Low | Typography definitions |
|
||||
@@ -108,7 +109,7 @@ Path prefix: `common/src/commonMain/kotlin/chat/simplex/common/`
|
||||
|
||||
| Source File | Product Concepts Affected | Risk Level | Notes |
|
||||
|-------------|--------------------------|------------|-------|
|
||||
| `views/chat/ChatView.kt` | PC2, PC3, PC4, PC5, PC6, PC7, PC8, PC9, PC11 | High | Core conversation UI — most messaging features |
|
||||
| `views/chat/ChatView.kt` | PC2, PC3, PC4, PC5, PC6, PC7, PC8, PC9, PC11, PC32 | High | Core conversation UI — most messaging features |
|
||||
| `views/chat/ComposeView.kt` | PC4, PC6, PC9, PC10, PC11 | High | Message composition — send path for all messages |
|
||||
| `views/chat/SendMsgView.kt` | PC4, PC9 | Medium | Send button and voice record toggle |
|
||||
| `views/chat/ComposeEmojiPicker.kt` | PC4 | Low | Emoji button expect declaration, emoji insertion |
|
||||
@@ -117,11 +118,11 @@ Path prefix: `common/src/commonMain/kotlin/chat/simplex/common/`
|
||||
| `views/chat/ComposeImageView.kt` | PC10 | Low | Image attachment preview in compose area |
|
||||
| `views/chat/ContextItemView.kt` | PC6 | Low | Reply/edit quote preview |
|
||||
| `views/chat/SelectableChatItemToolbars.kt` | PC7, PC10 | Medium | Multi-select toolbar (delete, forward) |
|
||||
| `views/chat/ChatInfoView.kt` | PC2, PC13, PC20 | Medium | Contact details and verification |
|
||||
| `views/chat/ChatInfoView.kt` | PC2, PC13, PC20, PC32 | Medium | Contact details and verification |
|
||||
| `views/chat/ContactPreferences.kt` | PC2, PC8 | Medium | Per-contact feature preferences |
|
||||
| `views/chat/ChatItemInfoView.kt` | PC2, PC3 | Low | Message delivery detail |
|
||||
| `views/chat/ChatItemsLoader.kt` | PC2, PC3 | Medium | Pagination and message loading logic |
|
||||
| `views/chat/ChatItemsMerger.kt` | PC2, PC3 | Medium | Merges incremental message updates |
|
||||
| `views/chat/ChatItemsMerger.kt` | PC2, PC3, PC32 | Medium | Merges incremental message updates |
|
||||
| `views/chat/VerifyCodeView.kt` | PC13 | Medium | Contact security code verification |
|
||||
| `views/chat/ScanCodeView.kt` | PC13 | Low | QR code scanning for verification |
|
||||
| `views/chat/CommandsMenuView.kt` | PC4 | Low | Slash-command menu |
|
||||
@@ -134,28 +135,30 @@ Path prefix: `common/src/commonMain/kotlin/chat/simplex/common/`
|
||||
|
||||
| Source File | Product Concepts Affected | Risk Level | Notes |
|
||||
|-------------|--------------------------|------------|-------|
|
||||
| `views/chat/item/ChatItemView.kt` | PC2, PC3, PC5, PC6, PC7, PC8 | High | Root chat item renderer with context menus |
|
||||
| `views/chat/item/TextItemView.kt` | PC2, PC3, PC4 | Medium | Text message bubble rendering |
|
||||
| `views/chat/item/FramedItemView.kt` | PC4, PC6, PC10, PC11 | Medium | Framed (quoted/forwarded) message container |
|
||||
| `views/chat/item/ChatItemView.kt` | PC2, PC3, PC5, PC6, PC7, PC8, PC32 | High | Root chat item renderer with context menus |
|
||||
| `views/chat/item/TextItemView.kt` | PC2, PC3, PC4, PC32 | Medium | Text message bubble rendering |
|
||||
| `views/chat/item/MarkdownBlocks.kt` | PC4, PC32 | Medium | Block Markdown rendering; terminal block gaps and headings |
|
||||
| `views/chat/item/FramedItemView.kt` | PC4, PC6, PC10, PC11, PC32 | Medium | Framed (quoted/forwarded) message container |
|
||||
| `views/chat/item/TerminalItemView.kt` | PC2, PC3, PC32 | Medium | Terminal layout rows, sender rows, time placement |
|
||||
| `views/chat/item/CIImageView.kt` | PC10 | Medium | Image message rendering |
|
||||
| `views/chat/item/CIVideoView.kt` | PC10 | Medium | Video message rendering |
|
||||
| `views/chat/item/CIFileView.kt` | PC10 | Medium | File message rendering |
|
||||
| `views/chat/item/CIVoiceView.kt` | PC9 | Medium | Voice message rendering and playback |
|
||||
| `views/chat/item/EmojiItemView.kt` | PC5 | Low | Emoji reaction display |
|
||||
| `views/chat/item/CIMetaView.kt` | PC2, PC3, PC8 | Low | Timestamp, delivery status, timed message indicator |
|
||||
| `views/chat/item/CICallItemView.kt` | PC17 | Low | Call event item rendering |
|
||||
| `views/chat/item/CIEventView.kt` | PC3, PC14, PC16 | Low | Group event item rendering |
|
||||
| `views/chat/item/CIGroupInvitationView.kt` | PC3, PC14 | Low | Group invitation item rendering |
|
||||
| `views/chat/item/CIMemberCreatedContactView.kt` | PC3, PC12 | Low | Member-created contact event |
|
||||
| `views/chat/item/CIChatFeatureView.kt` | PC8 | Low | Feature change event rendering |
|
||||
| `views/chat/item/CIFeaturePreferenceView.kt` | PC8 | Low | Feature preference change rendering |
|
||||
| `views/chat/item/CIRcvDecryptionError.kt` | PC2, PC3 | Low | Decryption error display |
|
||||
| `views/chat/item/DeletedItemView.kt` | PC7 | Low | Deleted message placeholder |
|
||||
| `views/chat/item/MarkedDeletedItemView.kt` | PC7 | Low | Moderated/marked-deleted placeholder |
|
||||
| `views/chat/item/CIFileView.kt` | PC10, PC32 | Medium | File message rendering |
|
||||
| `views/chat/item/CIVoiceView.kt` | PC9, PC32 | Medium | Voice message rendering and playback |
|
||||
| `views/chat/item/EmojiItemView.kt` | PC5, PC32 | Low | Emoji reaction display |
|
||||
| `views/chat/item/CIMetaView.kt` | PC2, PC3, PC8, PC32 | Low | Timestamp, delivery status, timed message indicator |
|
||||
| `views/chat/item/CICallItemView.kt` | PC17, PC32 | Low | Call event item rendering |
|
||||
| `views/chat/item/CIEventView.kt` | PC3, PC14, PC16, PC32 | Low | Group event item rendering |
|
||||
| `views/chat/item/CIGroupInvitationView.kt` | PC3, PC14, PC32 | Low | Group invitation item rendering |
|
||||
| `views/chat/item/CIMemberCreatedContactView.kt` | PC3, PC12, PC32 | Low | Member-created contact event |
|
||||
| `views/chat/item/CIChatFeatureView.kt` | PC8, PC32 | Low | Feature change event rendering |
|
||||
| `views/chat/item/CIFeaturePreferenceView.kt` | PC8, PC32 | Low | Feature preference change rendering |
|
||||
| `views/chat/item/CIRcvDecryptionError.kt` | PC2, PC3, PC32 | Low | Decryption error display |
|
||||
| `views/chat/item/DeletedItemView.kt` | PC7, PC32 | Low | Deleted message placeholder |
|
||||
| `views/chat/item/MarkedDeletedItemView.kt` | PC7, PC32 | Low | Moderated/marked-deleted placeholder |
|
||||
| `views/chat/item/ImageFullScreenView.kt` | PC10 | Low | Full-screen image viewer |
|
||||
| `views/chat/item/CIBrokenComposableView.kt` | — | Low | Fallback for render failures |
|
||||
| `views/chat/item/CIInvalidJSONView.kt` | — | Low | Fallback for malformed items |
|
||||
| `views/chat/item/IntegrityErrorItemView.kt` | PC2, PC3 | Low | Message integrity error display |
|
||||
| `views/chat/item/IntegrityErrorItemView.kt` | PC2, PC3, PC32 | Low | Message integrity error display |
|
||||
|
||||
### 1.6 Views — Groups
|
||||
|
||||
@@ -207,13 +210,13 @@ Path prefix: `common/src/commonMain/kotlin/chat/simplex/common/`
|
||||
| Source File | Product Concepts Affected | Risk Level | Notes |
|
||||
|-------------|--------------------------|------------|-------|
|
||||
| `views/usersettings/SettingsView.kt` | PC18, PC22, PC23, PC24, PC25, PC29 | Medium | Settings navigation hub |
|
||||
| `views/usersettings/Appearance.kt` | PC24 | Low | Theme and appearance customization |
|
||||
| `views/usersettings/Appearance.kt` | PC24, PC32 | Low | Theme and appearance customization |
|
||||
| `views/usersettings/PrivacySettings.kt` | PC20, PC22 | Medium | Privacy and lock settings |
|
||||
| `views/usersettings/UserProfileView.kt` | PC19 | Medium | Profile display name and image editing |
|
||||
| `views/usersettings/UserProfilesView.kt` | PC19, PC21 | Medium | Multi-profile management |
|
||||
| `views/usersettings/HiddenProfileView.kt` | PC21 | Medium | Hidden profile access |
|
||||
| `views/usersettings/IncognitoView.kt` | PC20 | Low | Incognito mode explanation |
|
||||
| `views/usersettings/UserAddressView.kt` | PC29 | Medium | User SimpleX address management |
|
||||
| `views/usersettings/UserAddressView.kt` | PC29, PC32 | Medium | User SimpleX address management |
|
||||
| `views/usersettings/UserAddressLearnMore.kt` | PC29 | Low | Address educational content |
|
||||
| `views/usersettings/NotificationsSettingsView.kt` | PC18 | Medium | Notification mode configuration |
|
||||
| `views/usersettings/CallSettings.kt` | PC17 | Low | Call-related settings |
|
||||
@@ -271,15 +274,15 @@ Path prefix: `common/src/commonMain/kotlin/chat/simplex/common/`
|
||||
|
||||
| Source File | Product Concepts Affected | Risk Level | Notes |
|
||||
|-------------|--------------------------|------------|-------|
|
||||
| `views/helpers/AlertManager.kt` | PC1 through PC31 | Medium | Modal alert system used across all features |
|
||||
| `views/helpers/ModalView.kt` | PC1 through PC31 | Medium | Modal navigation stack |
|
||||
| `views/helpers/Utils.kt` | PC1 through PC31 | Low | Shared formatting, clipboard, and utility functions |
|
||||
| `views/helpers/AlertManager.kt` | PC1 through PC32 | Medium | Modal alert system used across all features |
|
||||
| `views/helpers/ModalView.kt` | PC1 through PC32 | Medium | Modal navigation stack |
|
||||
| `views/helpers/Utils.kt` | PC1 through PC32 | Low | Shared formatting, clipboard, and utility functions |
|
||||
| `views/helpers/DatabaseUtils.kt` | PC23 | Medium | Keystore passphrase and database helpers |
|
||||
| `views/helpers/LinkPreviews.kt` | PC11 | Medium | Link preview fetching and rendering |
|
||||
| `views/helpers/LocalAuthentication.kt` | PC22 | Medium | Biometric/passcode authentication expect |
|
||||
| `views/helpers/ChatWallpaper.kt` | PC24 | Low | Chat wallpaper rendering |
|
||||
| `views/helpers/ChatInfoImage.kt` | PC19 | Low | Profile image composable |
|
||||
| `views/helpers/ThemeModeEditor.kt` | PC24 | Low | Theme mode toggle |
|
||||
| `views/helpers/ThemeModeEditor.kt` | PC24, PC32 | Low | Theme mode toggle |
|
||||
| `views/helpers/ChooseAttachmentView.kt` | PC10 | Low | Attachment picker |
|
||||
| `views/helpers/GetImageView.kt` | PC10, PC19 | Low | Image capture and crop |
|
||||
| `views/helpers/TextEditor.kt` | PC4 | Low | Rich text editor helpers |
|
||||
@@ -326,8 +329,8 @@ Path prefix: `android/src/main/java/chat/simplex/app/`
|
||||
|
||||
| Source File | Product Concepts Affected | Risk Level | Notes |
|
||||
|-------------|--------------------------|------------|-------|
|
||||
| `SimplexApp.kt` | PC1 through PC31 | High | Application class — initializes core, preferences, and notification channels |
|
||||
| `MainActivity.kt` | PC1 through PC31 | High | Single-activity host — intent handling, lifecycle, deep links |
|
||||
| `SimplexApp.kt` | PC1 through PC32 | High | Application class — initializes core, preferences, and notification channels |
|
||||
| `MainActivity.kt` | PC1 through PC32 | High | Single-activity host — intent handling, lifecycle, deep links |
|
||||
| `SimplexService.kt` | PC18 | High | Foreground service — keeps message receiver alive |
|
||||
| `CallService.kt` | PC17 | Medium | Foreground service for active calls |
|
||||
| `MessagesFetcherWorker.kt` | PC18 | Medium | WorkManager periodic message fetch |
|
||||
@@ -341,7 +344,7 @@ Path prefix: `common/src/androidMain/kotlin/chat/simplex/common/`
|
||||
|
||||
| Source File | Product Concepts Affected | Risk Level | Notes |
|
||||
|-------------|--------------------------|------------|-------|
|
||||
| `platform/AppCommon.android.kt` | PC1 through PC31 | Medium | Android app initialization actual declarations |
|
||||
| `platform/AppCommon.android.kt` | PC1 through PC32 | Medium | Android app initialization actual declarations |
|
||||
| `platform/SimplexService.android.kt` | PC18 | Medium | Android foreground service actual implementation |
|
||||
| `platform/Files.android.kt` | PC10, PC23, PC26 | Medium | Android file paths and content-URI resolution |
|
||||
| `platform/Cryptor.android.kt` | PC23 | Medium | Android Keystore encryption actual implementation |
|
||||
@@ -408,7 +411,7 @@ Path prefix: `desktop/src/jvmMain/kotlin/chat/simplex/desktop/`
|
||||
|
||||
| Source File | Product Concepts Affected | Risk Level | Notes |
|
||||
|-------------|--------------------------|------------|-------|
|
||||
| `Main.kt` | PC1 through PC31 | High | JVM entry point — Haskell init, migrations, app launch |
|
||||
| `Main.kt` | PC1 through PC32 | High | JVM entry point — Haskell init, migrations, app launch |
|
||||
|
||||
### 3.2 Desktop Platform Implementations (desktopMain)
|
||||
|
||||
@@ -423,7 +426,7 @@ Path prefix: `common/src/desktopMain/kotlin/chat/simplex/common/`
|
||||
| `WindowActivation.kt` | — | Low | `_NET_ACTIVE_WINDOW` request that raises the window on X11 and XWayland |
|
||||
| `platform/AppLinkScheme.desktop.kt` | — | Medium | Runtime `simplexchat:` and `simplex:` scheme registration (Windows HKCU, AppImage desktop entry) |
|
||||
| `model/NtfManager.desktop.kt` | PC18 | Medium | Desktop system tray notification display |
|
||||
| `platform/AppCommon.desktop.kt` | PC1 through PC31 | Medium | Desktop app initialization actual declarations |
|
||||
| `platform/AppCommon.desktop.kt` | PC1 through PC32 | Medium | Desktop app initialization actual declarations |
|
||||
| `platform/SimplexService.desktop.kt` | PC18 | Low | Desktop background receiver (no foreground service) |
|
||||
| `platform/Files.desktop.kt` | PC10, PC23, PC26 | Medium | Desktop file path resolution |
|
||||
| `platform/Cryptor.desktop.kt` | PC23 | Medium | Desktop keystore encryption actual implementation |
|
||||
@@ -487,14 +490,14 @@ The Haskell core is compiled as a shared native library (`libsimplex.so` / `libs
|
||||
|
||||
| Source File | Product Concepts Affected | Risk Level | Notes |
|
||||
|-------------|--------------------------|------------|-------|
|
||||
| `src/Simplex/Chat.hs` | PC1 through PC31 | High | Main chat module — top-level orchestration |
|
||||
| `src/Simplex/Chat/Controller.hs` | PC1 through PC31 | High | Command processor — all API commands dispatched here |
|
||||
| `src/Simplex/Chat/Types.hs` | PC1 through PC31 | High | Core data types shared across all features |
|
||||
| `src/Simplex/Chat/Core.hs` | PC1 through PC31 | High | Chat engine lifecycle (start, stop, subscribe) |
|
||||
| `src/Simplex/Chat/Library/Commands.hs` | PC1 through PC31 | High | API command handler implementations |
|
||||
| `src/Simplex/Chat/Library/Internal.hs` | PC1 through PC31 | High | Internal helpers for command processing |
|
||||
| `src/Simplex/Chat/Library/Subscriber.hs` | PC1 through PC31 | High | Event subscriber — incoming message routing |
|
||||
| `src/Simplex/Chat/Protocol.hs` | PC2, PC3, PC4, PC5, PC6, PC7 | High | Chat-level message protocol (x-events) |
|
||||
| `src/Simplex/Chat.hs` | PC1 through PC32 | High | Main chat module — top-level orchestration |
|
||||
| `src/Simplex/Chat/Controller.hs` | PC1 through PC32 | High | Command processor — all API commands dispatched here |
|
||||
| `src/Simplex/Chat/Types.hs` | PC1 through PC32 | High | Core data types shared across all features |
|
||||
| `src/Simplex/Chat/Core.hs` | PC1 through PC32 | High | Chat engine lifecycle (start, stop, subscribe) |
|
||||
| `src/Simplex/Chat/Library/Commands.hs` | PC1 through PC32 | High | API command handler implementations |
|
||||
| `src/Simplex/Chat/Library/Internal.hs` | PC1 through PC32 | High | Internal helpers for command processing |
|
||||
| `src/Simplex/Chat/Library/Subscriber.hs` | PC1 through PC32 | High | Event subscriber — incoming message routing |
|
||||
| `src/Simplex/Chat/Protocol.hs` | PC2, PC3, PC4, PC5, PC6, PC7, PC32 | High | Chat-level message protocol (x-events) |
|
||||
| `src/Simplex/Chat/Messages.hs` | PC2, PC3, PC4, PC5, PC6, PC7, PC8, PC9 | High | Message types and content |
|
||||
| `src/Simplex/Chat/Messages/CIContent.hs` | PC4, PC5, PC6, PC7, PC8, PC9, PC11 | Medium | Chat item content variants |
|
||||
| `src/Simplex/Chat/Messages/CIContent/Events.hs` | PC3, PC14, PC16 | Medium | Group event content types |
|
||||
@@ -503,15 +506,15 @@ The Haskell core is compiled as a shared native library (`libsimplex.so` / `libs
|
||||
| `src/Simplex/Chat/Files.hs` | PC10 | Medium | File transfer orchestration |
|
||||
| `src/Simplex/Chat/Delivery.hs` | PC2, PC3 | Medium | Message delivery engine |
|
||||
| `src/Simplex/Chat/Markdown.hs` | PC4 | Low | Markdown parsing for message formatting |
|
||||
| `src/Simplex/Chat/Store.hs` | PC1 through PC31 | High | Database store interface |
|
||||
| `src/Simplex/Chat/Store/Shared.hs` | PC1 through PC31 | Medium | Shared store utilities |
|
||||
| `src/Simplex/Chat/Store.hs` | PC1 through PC32 | High | Database store interface |
|
||||
| `src/Simplex/Chat/Store/Shared.hs` | PC1 through PC32 | Medium | Shared store utilities |
|
||||
| `src/Simplex/Chat/Store/Messages.hs` | PC4, PC5, PC6, PC7, PC8 | High | Message persistence |
|
||||
| `src/Simplex/Chat/Store/Groups.hs` | PC3, PC14, PC15, PC16, PC30 | High | Group persistence |
|
||||
| `src/Simplex/Chat/Store/Direct.hs` | PC2, PC12, PC13 | High | Contact persistence |
|
||||
| `src/Simplex/Chat/Store/Groups.hs` | PC3, PC14, PC15, PC16, PC30, PC32 | High | Group persistence |
|
||||
| `src/Simplex/Chat/Store/Direct.hs` | PC2, PC12, PC13, PC32 | High | Contact persistence |
|
||||
| `src/Simplex/Chat/Store/Files.hs` | PC10 | Medium | File transfer persistence |
|
||||
| `src/Simplex/Chat/Store/Profiles.hs` | PC19, PC21 | Medium | User profile persistence |
|
||||
| `src/Simplex/Chat/Store/Connections.hs` | PC2, PC12 | High | Connection persistence and entity resolution |
|
||||
| `src/Simplex/Chat/Store/ContactRequest.hs` | PC12 | Medium | Contact request persistence |
|
||||
| `src/Simplex/Chat/Store/Profiles.hs` | PC19, PC21, PC32 | Medium | User profile persistence |
|
||||
| `src/Simplex/Chat/Store/Connections.hs` | PC2, PC12, PC32 | High | Connection persistence and entity resolution |
|
||||
| `src/Simplex/Chat/Store/ContactRequest.hs` | PC12, PC32 | Medium | Contact request persistence |
|
||||
| `src/Simplex/Chat/Store/NoteFolders.hs` | PC1 | Low | Note folder (self-chat) persistence |
|
||||
| `src/Simplex/Chat/Store/Delivery.hs` | PC2, PC3 | Medium | Delivery task persistence |
|
||||
| `src/Simplex/Chat/Store/AppSettings.hs` | PC25 | Low | App settings persistence |
|
||||
@@ -525,19 +528,19 @@ The Haskell core is compiled as a shared native library (`libsimplex.so` / `libs
|
||||
| `src/Simplex/Chat/Remote/RevHTTP.hs` | PC27 | Low | Reverse HTTP for remote desktop |
|
||||
| `src/Simplex/Chat/Remote/AppVersion.hs` | PC27 | Low | Remote version negotiation |
|
||||
| `src/Simplex/Chat/ProfileGenerator.hs` | PC20 | Low | Random profile generation for incognito |
|
||||
| `src/Simplex/Chat/Types/UITheme.hs` | PC24 | Low | Theme data types for UI customization |
|
||||
| `src/Simplex/Chat/Types/UITheme.hs` | PC24, PC32 | Low | Theme data types for UI customization |
|
||||
| `src/Simplex/Chat/Types/Preferences.hs` | PC2, PC3, PC8 | Medium | Chat feature preferences (timed messages, etc.) |
|
||||
| `src/Simplex/Chat/Types/Shared.hs` | PC3, PC16 | Medium | Shared types including GroupMemberRole |
|
||||
| `src/Simplex/Chat/Types/MemberRelations.hs` | PC3, PC16, PC30 | Medium | Member relationship state machine |
|
||||
| `src/Simplex/Chat/Operators.hs` | PC25 | Medium | Server operator management |
|
||||
| `src/Simplex/Chat/Operators/Presets.hs` | PC25 | Low | Preset server operators |
|
||||
| `src/Simplex/Chat/Operators/Conditions.hs` | PC25 | Low | Operator usage conditions |
|
||||
| `src/Simplex/Chat/AppSettings.hs` | PC25 | Low | App settings sync types |
|
||||
| `src/Simplex/Chat/Mobile.hs` | PC1 through PC31 | High | C FFI exports — JNI bridge target |
|
||||
| `src/Simplex/Chat/AppSettings.hs` | PC25, PC32 | Low | App settings sync types |
|
||||
| `src/Simplex/Chat/Mobile.hs` | PC1 through PC32 | High | C FFI exports — JNI bridge target |
|
||||
| `src/Simplex/Chat/Mobile/File.hs` | PC10 | Medium | Mobile file read/write FFI |
|
||||
| `src/Simplex/Chat/Mobile/Shared.hs` | PC1 through PC31 | Medium | Shared FFI helpers |
|
||||
| `src/Simplex/Chat/Mobile/Shared.hs` | PC1 through PC32 | Medium | Shared FFI helpers |
|
||||
| `src/Simplex/Chat/Mobile/WebRTC.hs` | PC17 | Low | WebRTC FFI helpers |
|
||||
| `src/Simplex/Chat/View.hs` | PC1 through PC31 | Low | Terminal view rendering (not used by mobile/desktop UI) |
|
||||
| `src/Simplex/Chat/View.hs` | PC1 through PC32 | Low | Terminal view rendering (not used by mobile/desktop UI) |
|
||||
| `src/Simplex/Chat/Stats.hs` | PC25 | Low | Server statistics tracking |
|
||||
| `src/Simplex/Chat/Util.hs` | — | Low | General Haskell utilities |
|
||||
| `src/Simplex/Chat/Styled.hs` | — | Low | Terminal styled text (not used by mobile/desktop UI) |
|
||||
|
||||
@@ -139,7 +139,7 @@ Converts `Color` to `#AARRGGBB` hex string with intelligent alpha handling.
|
||||
|
||||
## 3. Default Themes
|
||||
|
||||
[`Theme.kt`](../../common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt#L26):
|
||||
[`Theme.kt`](../../common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt#L27):
|
||||
|
||||
```kotlin
|
||||
enum class DefaultTheme {
|
||||
@@ -160,7 +160,7 @@ enum class DefaultTheme {
|
||||
|
||||
`SYSTEM` is a virtual theme name that resolves to LIGHT or the configured dark variant at runtime.
|
||||
|
||||
`DefaultThemeMode` ([line 46](../../common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt#L46)): `LIGHT` or `DARK`, serialized as `"light"` / `"dark"`.
|
||||
`DefaultThemeMode` ([line 47](../../common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt#L47)): `LIGHT` or `DARK`, serialized as `"light"` / `"dark"`.
|
||||
|
||||
---
|
||||
|
||||
@@ -168,9 +168,9 @@ enum class DefaultTheme {
|
||||
|
||||
<a id="AppColors"></a>
|
||||
|
||||
### AppColors (line 53)
|
||||
### AppColors (line 54)
|
||||
|
||||
[`Theme.kt` L53](../../common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt#L53):
|
||||
[`Theme.kt` L54](../../common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt#L54):
|
||||
|
||||
```kotlin
|
||||
@Stable
|
||||
@@ -188,9 +188,9 @@ Mutable state properties (for efficient recomposition) representing chat-specifi
|
||||
|
||||
<a id="AppWallpaper"></a>
|
||||
|
||||
### AppWallpaper (line 106)
|
||||
### AppWallpaper (line 107)
|
||||
|
||||
[`Theme.kt` L106](../../common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt#L106):
|
||||
[`Theme.kt` L107](../../common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt#L107):
|
||||
|
||||
```kotlin
|
||||
@Stable
|
||||
@@ -205,7 +205,7 @@ Represents the active wallpaper state with optional background color, tint overl
|
||||
|
||||
<a id="ThemeColor"></a>
|
||||
|
||||
### ThemeColor (line 140)
|
||||
### ThemeColor (line 141)
|
||||
|
||||
Enum of all customizable color slots:
|
||||
|
||||
@@ -215,17 +215,17 @@ Each has a `fromColors()` method to extract the current value and a `text` prope
|
||||
|
||||
<a id="ThemeColors"></a>
|
||||
|
||||
### ThemeColors (line 183)
|
||||
### ThemeColors (line 184)
|
||||
|
||||
[`Theme.kt` L183](../../common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt#L183):
|
||||
[`Theme.kt` L184](../../common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt#L184):
|
||||
|
||||
Serializable data class with optional hex color strings for each slot. Uses `@SerialName` annotations for YAML compatibility (`accent` for `primary`, `accentVariant` for `primaryVariant`, `menus` for `surface`, etc.).
|
||||
|
||||
<a id="ThemeWallpaper"></a>
|
||||
|
||||
### ThemeWallpaper (line 224)
|
||||
### ThemeWallpaper (line 225)
|
||||
|
||||
[`Theme.kt` L224](../../common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt#L224):
|
||||
[`Theme.kt` L225](../../common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt#L225):
|
||||
|
||||
```kotlin
|
||||
@Serializable
|
||||
@@ -248,9 +248,9 @@ Key methods:
|
||||
|
||||
<a id="ThemeOverrides"></a>
|
||||
|
||||
### ThemeOverrides (line 304)
|
||||
### ThemeOverrides (line 305)
|
||||
|
||||
[`Theme.kt` L304](../../common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt#L304):
|
||||
[`Theme.kt` L305](../../common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt#L305):
|
||||
|
||||
```kotlin
|
||||
@Serializable
|
||||
@@ -269,25 +269,29 @@ A complete theme override entry. Multiple can coexist (one per wallpaper type pe
|
||||
|
||||
<a id="ThemeModeOverrides"></a>
|
||||
|
||||
### ThemeModeOverrides (line 475)
|
||||
### ThemeModeOverrides (line 476)
|
||||
|
||||
[`Theme.kt` L475](../../common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt#L475):
|
||||
[`Theme.kt` L476](../../common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt#L476):
|
||||
|
||||
```kotlin
|
||||
@Serializable
|
||||
data class ThemeModeOverrides(
|
||||
val light: ThemeModeOverride? = null,
|
||||
val dark: ThemeModeOverride? = null,
|
||||
val chatLayout: ChatLayoutMode? = null
|
||||
)
|
||||
```
|
||||
|
||||
Container for per-user or per-chat overrides, with separate light and dark mode variants. Stored on the `User` model as `uiThemes`.
|
||||
Container for per-user or per-chat overrides, with separate light and dark mode variants, and the chat layout chosen for the profile or the chat (both colour modes). Stored on the `User` model as `uiThemes`.
|
||||
|
||||
- `layoutOnly()`: the overrides with the colours and wallpapers removed, `null` without a layout. Used by "Reset to app theme", "Remove image" and the app theme destination of Appearance, so the layout is kept.
|
||||
- `ThemeModeOverrides?.withChatLayout(chatLayout)`: the overrides with the layout set, `null` when empty.
|
||||
|
||||
<a id="ThemeModeOverride"></a>
|
||||
|
||||
### ThemeModeOverride (line 487)
|
||||
### ThemeModeOverride (line 494)
|
||||
|
||||
[`Theme.kt` L487](../../common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt#L487):
|
||||
[`Theme.kt` L494](../../common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt#L494):
|
||||
|
||||
```kotlin
|
||||
@Serializable
|
||||
|
||||
@@ -300,6 +300,18 @@ data class ChatStats(
|
||||
| `ChatInfo.ContactConnection` | `"contactConnection"` | `contactConnection: PendingContactConnection` |
|
||||
| `ChatInfo.InvalidJSON` | `"invalidJSON"` | `json: String` |
|
||||
|
||||
[`ChatInfo.activeChatLayout(user)`](../common/src/commonMain/kotlin/chat/simplex/common/model/ChatModel.kt#L1876) is computed in the app, skipping `ChatLayoutMode.Unknown` values:
|
||||
|
||||
```
|
||||
chat choice ChatInfo.uiThemes.chatLayout (contact or group theme record)
|
||||
chat layout ChatInfo.chatLayout: groupProfile.chatLayout of a group; Contact.chatLayout (address link data, stored when the contact is prepared)
|
||||
profile choice User.uiThemes.chatLayout (profileChatLayout)
|
||||
app choice appPrefs.chatLayout
|
||||
otherwise ChatLayoutMode.Classic
|
||||
```
|
||||
|
||||
[`defaultChatLayout(user)`](../common/src/commonMain/kotlin/chat/simplex/common/model/ChatModel.kt#L1873) is the same without the chat choice. Note folders have no chat values, so the profile and app choices apply. `ChatView` reads `chatModel.currentUser`, and `profileChatLayout` reads `appPrefs.chatLayout.state`, so a change of either recomposes the open chat; the chat list is not reloaded. The chat choice is written with `apiSetChatUIThemes` (`setChatLayout`, `ChatInfoView.kt`), the profile choice with `apiSetUserUIThemes` (`ChatLayoutRow`, `Appearance.kt`), together with the colours of the same record.
|
||||
|
||||
### RelayStatus (Channels)
|
||||
|
||||
`RelayStatus` is an `enum class` at [`ChatModel.kt line 2288`](../common/src/commonMain/kotlin/chat/simplex/common/model/ChatModel.kt#L2288) modelling a relay's lifecycle for a channel on the owner's side. Serialized as a lowercase string via `@SerialName`.
|
||||
@@ -450,6 +462,7 @@ val appPrefs: AppPreferences by lazy { AppPreferences() }
|
||||
|---|---|---|---|
|
||||
| `oneHandUI` | `Boolean` | `true` | One-hand mode |
|
||||
| `chatBottomBar` | `Boolean` | `true` | Bottom bar in chat |
|
||||
| `chatLayout` | `ChatLayoutMode` | `Classic` | App chat layout (`activeChatLayout`) |
|
||||
|
||||
#### Remote Access (lines 238-243)
|
||||
|
||||
|
||||
Reference in new issue
Block a user