Skip to content

Commit

Permalink
make message view work properly
Browse files Browse the repository at this point in the history
  • Loading branch information
0chroma committed Sep 12, 2024
1 parent d5d5249 commit c88a43b
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 67 deletions.
2 changes: 1 addition & 1 deletion src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ impl SimpleComponent for App {

fn update(&mut self, message: Self::Input, _sender: ComponentSender<Self>) {
match message {
AppMsg::Send => self.chat_feed.emit(ChatFeedMsg::AddMsg),
AppMsg::Send => self.chat_feed.emit(ChatFeedMsg::Append),
AppMsg::Quit => main_application().quit(),
}
}
Expand Down
181 changes: 115 additions & 66 deletions src/chat_feed.rs
Original file line number Diff line number Diff line change
@@ -1,73 +1,43 @@
use gtk::prelude::{OrientableExt, WidgetExt};
use relm4::factory::{DynamicIndex, FactoryComponent, FactorySender, FactoryVecDeque};
use relm4::{adw, gtk, ComponentParts, ComponentSender, SimpleComponent};
use gtk::prelude::{GridExt, WidgetExt};

pub struct ChatLine {
id: String,
message: String,
username: String,
use relm4::{
binding::StringBinding,
prelude::*,
typed_view::list::{RelmListItem, TypedListView},
RelmObjectExt,
};

pub struct ChatFeed {
message_list: TypedListView<ChatLine, gtk::NoSelection>,
}

#[derive(Debug)]
pub enum ChatLineMsg {
pub enum ChatFeedMsg {
Append,
//TODO: updates ie msg deleted
}

#[derive(Debug)]
pub enum ChatLineOutput {
pub enum ChatFeedOutput {
//TODO: mod actions
}

#[relm4::factory(pub)]
impl FactoryComponent for ChatLine {
type Init = ChatLine;
type Input = ChatLineMsg;
type Output = ChatLineOutput;
type CommandOutput = ();
type ParentWidget = gtk::Box;

view! {
gtk::Box {
set_orientation: gtk::Orientation::Horizontal,
gtk::Label {
set_label: format!("{}: {}", self.username, self.message).as_str(),
}
}
}

fn init_model(value: Self, _index: &DynamicIndex, _sender: FactorySender<Self>) -> Self {
value
}

fn update(&mut self, msg: Self::Input, _sender: FactorySender<Self>) {
match msg {}
}
}

pub struct ChatFeed {
messages: FactoryVecDeque<ChatLine>,
}

#[derive(Debug)]
pub enum ChatFeedMsg {
AddMsg,
}

#[relm4::component(pub)]
impl SimpleComponent for ChatFeed {
type Init = ();
type Input = ChatFeedMsg;
type Output = ();
type Output = ChatFeedOutput;

view! {
#[root]
adw::ClampScrollable {
gtk::ScrolledWindow {
set_vexpand: true,
set_valign: gtk::Align::Start,

#[local_ref]
message_list -> gtk::Box {
set_orientation: gtk::Orientation::Horizontal,
adw::ClampScrollable {
#[local_ref]
message_list_view -> gtk::ListView {
add_css_class: "navigation-sidebar"
}
}
}
}
Expand All @@ -77,31 +47,110 @@ impl SimpleComponent for ChatFeed {
root: Self::Root,
_sender: ComponentSender<Self>,
) -> ComponentParts<Self> {
let mut messages = FactoryVecDeque::builder().launch_default().detach();
let message_list: TypedListView<ChatLine, gtk::NoSelection> = TypedListView::new();

messages.guard().push_back(ChatLine {
id: "1234".to_string(),
message: "hi".to_string(),
username: "chat".to_string(),
});

let model = ChatFeed { messages: messages };

let message_list = model.messages.widget();
let model = ChatFeed { message_list };
let message_list_view = &model.message_list.view;

let widgets = view_output!();
ComponentParts { model, widgets }
}

fn update(&mut self, msg: Self::Input, _sender: ComponentSender<Self>) {
match msg {
ChatFeedMsg::AddMsg => {
self.messages.guard().push_back(ChatLine {
id: "1234".to_string(),
message: "hi".to_string(),
username: "username".to_string(),
});
ChatFeedMsg::Append => {
self.message_list.append(ChatLine::new(
"1234".to_string(),
"Some User".to_string(),
"Hello, this is a sample message. It is very long to test if text wrapping works correctly. Chat, is this real?".to_string(),
));
}
}
}
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct ChatLine {
id: String,
username: StringBinding,
message: StringBinding,
}

//TODO hook chat messages up to this https://relm4.org/book/stable/threads_and_async/commands.html

impl ChatLine {
fn new(id: String, username: String, message: String) -> Self {
Self {
id,
username: StringBinding::new(username),
message: StringBinding::new(message),
}
}
}

pub struct Widgets {
avatar: adw::Avatar,
username: gtk::Label,
message: gtk::Label,
}

impl RelmListItem for ChatLine {
type Root = gtk::Grid;
type Widgets = Widgets;

fn setup(_item: &gtk::ListItem) -> (Self::Root, Widgets) {
relm4::view! {
line = gtk::Grid {
set_column_spacing: 15,
set_row_spacing: 5,

set_margin_start: 6,
set_margin_end: 6,
set_margin_top: 6,
set_margin_bottom: 6,

#[name = "avatar"]
attach[0, 0, 1, 2] = &adw::Avatar {
set_show_initials: true,
set_size: 40,
set_valign: gtk::Align::Start,
},

#[name = "username"]
attach[1, 0, 1, 1] = &gtk::Label {
set_wrap: true,
add_css_class: "heading",
set_justify: gtk::Justification::Fill,
set_align: gtk::Align::Start,
},

#[name = "message"]
attach[1, 1, 1, 1] = &gtk::Label {
set_wrap: true,
set_justify: gtk::Justification::Fill,
set_align: gtk::Align::Start,
},
}
}

let widgets = Widgets {
avatar,
username,
message,
};

(line, widgets)
}

fn bind(&mut self, widgets: &mut Self::Widgets, _root: &mut Self::Root) {
let Widgets {
avatar,
username,
message,
} = widgets;

avatar.add_write_only_binding(&self.username, "text");
username.add_write_only_binding(&self.username, "label");
message.add_write_only_binding(&self.message, "label");
}
}

0 comments on commit c88a43b

Please sign in to comment.