add community ui
This commit is contained in:
@@ -147,6 +147,9 @@ crates/community_ui/src/lib.rs init + CommunityPanel
|
||||
crates/community_ui/src/message.rs one message row's rendering
|
||||
```
|
||||
|
||||
`community` re-exports the types the panel names, as `chat` already does for
|
||||
`Message`: `ChatMessage`, `ReplyRef`, `ChannelId`, `CommunityId`.
|
||||
|
||||
```rust
|
||||
pub fn init(community: Entity<Community>, window: &mut Window, cx: &mut App) -> Entity<CommunityPanel>;
|
||||
|
||||
@@ -156,11 +159,10 @@ pub struct CommunityPanel {
|
||||
community: WeakEntity<Community>,
|
||||
channel: Option<ChannelId>, // the selected channel
|
||||
messages: Vec<ChatMessage>, // ascending, bottom-aligned list
|
||||
message_index: HashMap<EventId, usize>,
|
||||
list_state: ListState,
|
||||
input: Entity<TextareaState>,
|
||||
tasks: Vec<Task<Result<()>>>,
|
||||
subscriptions: SmallVec<[Subscription; 2]>,
|
||||
_subscriptions: SmallVec<[Subscription; 2]>,
|
||||
}
|
||||
```
|
||||
|
||||
@@ -168,18 +170,19 @@ pub struct CommunityPanel {
|
||||
`cx.subscribe_in(&community, window, ...)` while it has it, and keeps only the
|
||||
weak handle afterwards (`ChatPanel::subscribe_room_events` is the same split).
|
||||
It picks `channels().first()` (the genesis `#general`) and, in the subscription,
|
||||
`CommunityEvent::Updated(id)` reloads the open channel while
|
||||
`CommunityEvent::Error(error)` becomes a window notification. A `cx.defer_in` does
|
||||
the first `backfill` + `messages` load, exactly as `ChatPanel::new` defers `connect`.
|
||||
`CommunityEvent::Updated(id)` reloads the open channel through `cx.defer_in`,
|
||||
because the emit sits inside the community's own update; `CommunityEvent::Error(error)`
|
||||
becomes a window notification. A `cx.defer_in` does the first `backfill` + `messages`
|
||||
load, exactly as `ChatPanel::new` defers `connect`.
|
||||
- The channel and member lists are read live in `render` through the weak entity
|
||||
(as the sidebar reads `Community::channels()`), so a new channel or member needs no
|
||||
invalidation; a dropped entity renders an empty state instead.
|
||||
- `select_channel(channel, window, cx)` swaps the selection, resets the list and
|
||||
loads: `backfill` once per channel, then `messages`.
|
||||
- `reload(cx)` awaits `community.messages(&channel, cx)`, replaces `messages`,
|
||||
rebuilds `message_index` and `list_state.reset(len)` (then `scroll_to_end`).
|
||||
Edits, deletes and reactions are folded server-side of the UI, so a full replace
|
||||
is the honest update and stays small at `MESSAGE_LIMIT`.
|
||||
- `reload(cx)` awaits `community.messages(&channel, cx)`, replaces `messages` and
|
||||
`list_state.reset(len)` (then `scroll_to_end`). Edits, deletes and reactions are
|
||||
folded server-side of the UI, so a full replace is the honest update and stays
|
||||
small at `MESSAGE_LIMIT`. A failed load becomes a window notification.
|
||||
- `send(window, cx)` reads `self.input`, calls `community.send(...)`, clears the
|
||||
input, and reloads when the task resolves. Empty input is refused with a
|
||||
notification, like `ChatPanel`.
|
||||
@@ -194,7 +197,7 @@ pub struct CommunityPanel {
|
||||
`message::render(...)` and `Scrollbar::vertical(&self.list_state)`, then the
|
||||
composer row: `Textarea` (`InputEvent::PressEnter` sends) and a
|
||||
`Button::new("send").icon(IconName::PaperPlaneFill)`.
|
||||
- A message row: author name (person profile, "Unknown" fallback), `at_ago()` from
|
||||
- A message row: author name (person profile, "Unknown" fallback), `to_ago()` from
|
||||
`common::TimestampExt`, the content as plain text (no markdown, media or file
|
||||
rendering in this pass), a muted `(edited)` marker when `edited_at` is set, an
|
||||
emoji summary line from `reactions`, and `"Message deleted"` in
|
||||
|
||||
Reference in New Issue
Block a user