Skip to content

Commit ffa58a2

Browse files
committed
WIP: content: Add pinned messages bar and view
1 parent 3b2cbed commit ffa58a2

File tree

10 files changed

+299
-15
lines changed

10 files changed

+299
-15
lines changed

data/resources/ui/content-chat-history.ui

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@
3333
</child>
3434
</object>
3535
</child>
36+
<child type="top">
37+
<object class="PinnedMessagesBar" id="pinned_messages_bar"/>
38+
</child>
3639
<property name="content">
3740
<object class="MessageListView" id="message_list_view"/>
3841
</property>

data/resources/ui/content.blp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,13 @@ template Content : Adw.Bin {
3232
};
3333
}
3434

35-
.ContentChatHistory chat_history {
36-
compact: bind Content.compact;
37-
chat: bind Content.chat;
35+
Adw.Leaflet chat_leaflet {
36+
can-unfold: false;
37+
38+
.ContentChatHistory chat_history {
39+
compact: bind Content.compact;
40+
chat: bind Content.chat;
41+
}
3842
}
3943
}
4044
}

src/components/message_list_view/mod.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ use crate::Session;
2222

2323
const MIN_N_ITEMS: u32 = 20;
2424

25+
#[derive(Debug, Default, Clone, Copy)]
26+
pub(crate) enum MessageListViewType {
27+
#[default]
28+
ChatHistory,
29+
PinnedMessages,
30+
}
31+
2532
mod imp {
2633
use super::*;
2734
use once_cell::unsync::OnceCell;
@@ -146,9 +153,9 @@ glib::wrapper! {
146153
}
147154

148155
impl MessageListView {
149-
pub(crate) fn load_messages(&self, chat: &Chat) {
156+
pub(crate) fn load_messages(&self, type_: MessageListViewType, chat: &Chat) {
150157
let imp = self.imp();
151-
let model = MessageListViewModel::new(chat);
158+
let model = MessageListViewModel::new(type_, chat);
152159

153160
// Request sponsored message, if needed
154161
let list_view_model: gio::ListModel = if matches!(chat.type_(), ChatType::Supergroup(supergroup) if supergroup.is_channel())

src/components/message_list_view/model.rs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ use gtk::prelude::*;
33
use gtk::subclass::prelude::*;
44
use gtk::{gio, glib};
55
use std::cmp::Ordering;
6+
use tdlib::enums::SearchMessagesFilter;
67
use thiserror::Error;
78

8-
use super::{MessageListViewItem, MessageListViewItemType};
9+
use super::{MessageListViewItem, MessageListViewItemType, MessageListViewType};
910
use crate::tdlib::{Chat, Message};
1011

1112
#[derive(Error, Debug)]
@@ -25,6 +26,7 @@ mod imp {
2526

2627
#[derive(Debug, Default)]
2728
pub(crate) struct MessageListViewModel {
29+
pub(super) type_: Cell<MessageListViewType>,
2830
pub(super) chat: WeakRef<Chat>,
2931
pub(super) is_loading: Cell<bool>,
3032
pub(super) list: RefCell<VecDeque<MessageListViewItem>>,
@@ -82,9 +84,10 @@ glib::wrapper! {
8284
}
8385

8486
impl MessageListViewModel {
85-
pub(crate) fn new(chat: &Chat) -> Self {
87+
pub(crate) fn new(type_: MessageListViewType, chat: &Chat) -> Self {
8688
let obj: MessageListViewModel = glib::Object::new();
8789

90+
obj.imp().type_.set(type_);
8891
obj.imp().chat.set(Some(chat));
8992

9093
chat.connect_new_message(clone!(@weak obj => move |_, message| {
@@ -121,7 +124,21 @@ impl MessageListViewModel {
121124

122125
imp.is_loading.set(true);
123126

124-
let result = self.chat().get_chat_history(oldest_message_id, limit).await;
127+
let result = match imp.type_.get() {
128+
MessageListViewType::ChatHistory => {
129+
self.chat().get_chat_history(oldest_message_id, limit).await
130+
}
131+
MessageListViewType::PinnedMessages => {
132+
self.chat()
133+
.search_messages(
134+
String::new(),
135+
oldest_message_id,
136+
limit,
137+
Some(SearchMessagesFilter::Pinned),
138+
)
139+
.await
140+
}
141+
};
125142

126143
imp.is_loading.set(false);
127144

src/components/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@ mod sticker;
66

77
pub(crate) use self::avatar::Avatar;
88
pub(crate) use self::message_entry::MessageEntry;
9-
pub(crate) use self::message_list_view::MessageListView;
9+
pub(crate) use self::message_list_view::{MessageListView, MessageListViewType};
1010
pub(crate) use self::snow::Snow;
1111
pub(crate) use self::sticker::Sticker;

src/session/content/chat_history.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ use gtk::{glib, CompositeTemplate};
55
use tdlib::enums::ChatMemberStatus;
66
use tdlib::functions;
77

8-
use super::{ChatActionBar, ChatInfoWindow};
9-
use crate::components::MessageListView;
8+
use super::{ChatActionBar, ChatInfoWindow, PinnedMessagesBar};
9+
use crate::components::{MessageListView, MessageListViewType};
1010
use crate::expressions;
1111
use crate::tdlib::{Chat, ChatType};
1212

@@ -24,6 +24,8 @@ mod imp {
2424
#[template_child]
2525
pub(super) window_title: TemplateChild<adw::WindowTitle>,
2626
#[template_child]
27+
pub(super) pinned_messages_bar: TemplateChild<PinnedMessagesBar>,
28+
#[template_child]
2729
pub(super) message_list_view: TemplateChild<MessageListView>,
2830
#[template_child]
2931
pub(super) chat_action_bar: TemplateChild<ChatActionBar>,
@@ -202,7 +204,8 @@ impl ChatHistory {
202204
},
203205
);
204206

205-
imp.message_list_view.load_messages(chat);
207+
imp.message_list_view
208+
.load_messages(MessageListViewType::ChatHistory, chat);
206209
}
207210

208211
imp.chat.replace(chat);

src/session/content/mod.rs

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
mod chat_action_bar;
22
mod chat_history;
33
mod chat_info_window;
4+
mod pinned_messages_bar;
5+
mod pinned_messages_view;
46
mod send_photo_dialog;
57

68
use self::chat_action_bar::ChatActionBar;
79
use self::chat_history::ChatHistory;
810
use self::chat_info_window::ChatInfoWindow;
11+
use self::pinned_messages_bar::PinnedMessagesBar;
12+
use self::pinned_messages_view::PinnedMessagesView;
913
use self::send_photo_dialog::SendPhotoDialog;
1014

1115
use gtk::glib;
@@ -31,6 +35,8 @@ mod imp {
3135
#[template_child]
3236
pub(super) unselected_chat_view: TemplateChild<adw::ToolbarView>,
3337
#[template_child]
38+
pub(super) chat_leaflet: TemplateChild<adw::Leaflet>,
39+
#[template_child]
3440
pub(super) chat_history: TemplateChild<ChatHistory>,
3541
}
3642

@@ -41,8 +47,14 @@ mod imp {
4147
type ParentType = adw::Bin;
4248

4349
fn class_init(klass: &mut Self::Class) {
44-
ChatHistory::static_type();
4550
klass.bind_template();
51+
52+
klass.install_action("content.go-back", None, move |widget, _, _| {
53+
widget.go_back();
54+
});
55+
klass.install_action("content.show-pinned-messages", None, move |widget, _, _| {
56+
widget.show_pinned_messages();
57+
});
4658
}
4759

4860
fn instance_init(obj: &glib::subclass::InitializingObject<Self>) {
@@ -114,6 +126,36 @@ impl Content {
114126
self.imp().chat_history.handle_paste_action();
115127
}
116128

129+
fn go_back(&self) {
130+
self.imp()
131+
.chat_leaflet
132+
.navigate(adw::NavigationDirection::Back);
133+
}
134+
135+
fn show_pinned_messages(&self) {
136+
if let Some(chat) = self.chat() {
137+
let imp = self.imp();
138+
139+
let next_child = imp
140+
.chat_leaflet
141+
.adjacent_child(adw::NavigationDirection::Forward);
142+
let cached = if let Some(pinned_messages_view) =
143+
next_child.and_downcast::<PinnedMessagesView>()
144+
{
145+
pinned_messages_view.chat() == chat
146+
} else {
147+
false
148+
};
149+
150+
if !cached {
151+
let pinned_messages = PinnedMessagesView::new(&chat);
152+
imp.chat_leaflet.append(&pinned_messages);
153+
}
154+
155+
imp.chat_leaflet.navigate(adw::NavigationDirection::Forward);
156+
}
157+
}
158+
117159
pub(crate) fn chat(&self) -> Option<Chat> {
118160
self.imp().chat.borrow().clone()
119161
}
@@ -125,7 +167,16 @@ impl Content {
125167

126168
let imp = self.imp();
127169
if chat.is_some() {
128-
imp.stack.set_visible_child(&imp.chat_history.get());
170+
// Remove every leaflet page except the first one (the first chat history)
171+
imp.chat_leaflet
172+
.pages()
173+
.iter::<adw::LeafletPage>()
174+
.map(|p| p.unwrap())
175+
.enumerate()
176+
.filter(|(i, _)| i > &0)
177+
.for_each(|(_, p)| imp.chat_leaflet.remove(&p.child()));
178+
179+
imp.stack.set_visible_child(&imp.chat_leaflet.get());
129180
} else {
130181
imp.stack.set_visible_child(&imp.unselected_chat_view.get());
131182
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
use gtk::subclass::prelude::*;
2+
use gtk::{glib, CompositeTemplate};
3+
4+
mod imp {
5+
use super::*;
6+
7+
#[derive(Debug, Default, CompositeTemplate)]
8+
#[template(string = r#"
9+
template PinnedMessagesBar {
10+
Box content_box {
11+
styles ["toolbar"]
12+
13+
Box {
14+
orientation: vertical;
15+
hexpand: true;
16+
17+
Inscription {
18+
19+
}
20+
21+
Inscription {
22+
23+
}
24+
}
25+
26+
Button {
27+
icon-name: "view-list-symbolic";
28+
action-name: "content.show-pinned-messages";
29+
}
30+
}
31+
}
32+
"#)]
33+
pub(crate) struct PinnedMessagesBar {
34+
#[template_child]
35+
pub(super) content_box: TemplateChild<gtk::Box>,
36+
}
37+
38+
#[glib::object_subclass]
39+
impl ObjectSubclass for PinnedMessagesBar {
40+
const NAME: &'static str = "PinnedMessagesBar";
41+
type Type = super::PinnedMessagesBar;
42+
type ParentType = gtk::Widget;
43+
44+
fn class_init(klass: &mut Self::Class) {
45+
klass.bind_template();
46+
klass.set_layout_manager_type::<gtk::BinLayout>();
47+
}
48+
49+
fn instance_init(obj: &glib::subclass::InitializingObject<Self>) {
50+
obj.init_template();
51+
}
52+
}
53+
54+
impl ObjectImpl for PinnedMessagesBar {
55+
fn dispose(&self) {
56+
self.dispose_template();
57+
}
58+
}
59+
60+
impl WidgetImpl for PinnedMessagesBar {}
61+
}
62+
63+
glib::wrapper! {
64+
pub(crate) struct PinnedMessagesBar(ObjectSubclass<imp::PinnedMessagesBar>)
65+
@extends gtk::Widget;
66+
}

0 commit comments

Comments
 (0)