Skip to content

Commit

Permalink
WIP: content: Add pinned messages bar and view
Browse files Browse the repository at this point in the history
  • Loading branch information
melix99 committed Mar 30, 2023
1 parent 3b2cbed commit ffa58a2
Show file tree
Hide file tree
Showing 10 changed files with 299 additions and 15 deletions.
3 changes: 3 additions & 0 deletions data/resources/ui/content-chat-history.ui
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@
</child>
</object>
</child>
<child type="top">
<object class="PinnedMessagesBar" id="pinned_messages_bar"/>
</child>
<property name="content">
<object class="MessageListView" id="message_list_view"/>
</property>
Expand Down
10 changes: 7 additions & 3 deletions data/resources/ui/content.blp
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,13 @@ template Content : Adw.Bin {
};
}

.ContentChatHistory chat_history {
compact: bind Content.compact;
chat: bind Content.chat;
Adw.Leaflet chat_leaflet {
can-unfold: false;

.ContentChatHistory chat_history {
compact: bind Content.compact;
chat: bind Content.chat;
}
}
}
}
11 changes: 9 additions & 2 deletions src/components/message_list_view/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ use crate::Session;

const MIN_N_ITEMS: u32 = 20;

#[derive(Debug, Default, Clone, Copy)]
pub(crate) enum MessageListViewType {
#[default]
ChatHistory,
PinnedMessages,
}

mod imp {
use super::*;
use once_cell::unsync::OnceCell;
Expand Down Expand Up @@ -146,9 +153,9 @@ glib::wrapper! {
}

impl MessageListView {
pub(crate) fn load_messages(&self, chat: &Chat) {
pub(crate) fn load_messages(&self, type_: MessageListViewType, chat: &Chat) {
let imp = self.imp();
let model = MessageListViewModel::new(chat);
let model = MessageListViewModel::new(type_, chat);

// Request sponsored message, if needed
let list_view_model: gio::ListModel = if matches!(chat.type_(), ChatType::Supergroup(supergroup) if supergroup.is_channel())
Expand Down
23 changes: 20 additions & 3 deletions src/components/message_list_view/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ use gtk::prelude::*;
use gtk::subclass::prelude::*;
use gtk::{gio, glib};
use std::cmp::Ordering;
use tdlib::enums::SearchMessagesFilter;
use thiserror::Error;

use super::{MessageListViewItem, MessageListViewItemType};
use super::{MessageListViewItem, MessageListViewItemType, MessageListViewType};
use crate::tdlib::{Chat, Message};

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

#[derive(Debug, Default)]
pub(crate) struct MessageListViewModel {
pub(super) type_: Cell<MessageListViewType>,
pub(super) chat: WeakRef<Chat>,
pub(super) is_loading: Cell<bool>,
pub(super) list: RefCell<VecDeque<MessageListViewItem>>,
Expand Down Expand Up @@ -82,9 +84,10 @@ glib::wrapper! {
}

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

obj.imp().type_.set(type_);
obj.imp().chat.set(Some(chat));

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

imp.is_loading.set(true);

let result = self.chat().get_chat_history(oldest_message_id, limit).await;
let result = match imp.type_.get() {
MessageListViewType::ChatHistory => {
self.chat().get_chat_history(oldest_message_id, limit).await
}
MessageListViewType::PinnedMessages => {
self.chat()
.search_messages(
String::new(),
oldest_message_id,
limit,
Some(SearchMessagesFilter::Pinned),
)
.await
}
};

imp.is_loading.set(false);

Expand Down
2 changes: 1 addition & 1 deletion src/components/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ mod sticker;

pub(crate) use self::avatar::Avatar;
pub(crate) use self::message_entry::MessageEntry;
pub(crate) use self::message_list_view::MessageListView;
pub(crate) use self::message_list_view::{MessageListView, MessageListViewType};
pub(crate) use self::snow::Snow;
pub(crate) use self::sticker::Sticker;
9 changes: 6 additions & 3 deletions src/session/content/chat_history.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use gtk::{glib, CompositeTemplate};
use tdlib::enums::ChatMemberStatus;
use tdlib::functions;

use super::{ChatActionBar, ChatInfoWindow};
use crate::components::MessageListView;
use super::{ChatActionBar, ChatInfoWindow, PinnedMessagesBar};
use crate::components::{MessageListView, MessageListViewType};
use crate::expressions;
use crate::tdlib::{Chat, ChatType};

Expand All @@ -24,6 +24,8 @@ mod imp {
#[template_child]
pub(super) window_title: TemplateChild<adw::WindowTitle>,
#[template_child]
pub(super) pinned_messages_bar: TemplateChild<PinnedMessagesBar>,
#[template_child]
pub(super) message_list_view: TemplateChild<MessageListView>,
#[template_child]
pub(super) chat_action_bar: TemplateChild<ChatActionBar>,
Expand Down Expand Up @@ -202,7 +204,8 @@ impl ChatHistory {
},
);

imp.message_list_view.load_messages(chat);
imp.message_list_view
.load_messages(MessageListViewType::ChatHistory, chat);
}

imp.chat.replace(chat);
Expand Down
55 changes: 53 additions & 2 deletions src/session/content/mod.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
mod chat_action_bar;
mod chat_history;
mod chat_info_window;
mod pinned_messages_bar;
mod pinned_messages_view;
mod send_photo_dialog;

use self::chat_action_bar::ChatActionBar;
use self::chat_history::ChatHistory;
use self::chat_info_window::ChatInfoWindow;
use self::pinned_messages_bar::PinnedMessagesBar;
use self::pinned_messages_view::PinnedMessagesView;
use self::send_photo_dialog::SendPhotoDialog;

use gtk::glib;
Expand All @@ -31,6 +35,8 @@ mod imp {
#[template_child]
pub(super) unselected_chat_view: TemplateChild<adw::ToolbarView>,
#[template_child]
pub(super) chat_leaflet: TemplateChild<adw::Leaflet>,
#[template_child]
pub(super) chat_history: TemplateChild<ChatHistory>,
}

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

fn class_init(klass: &mut Self::Class) {
ChatHistory::static_type();
klass.bind_template();

klass.install_action("content.go-back", None, move |widget, _, _| {
widget.go_back();
});
klass.install_action("content.show-pinned-messages", None, move |widget, _, _| {
widget.show_pinned_messages();
});
}

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

fn go_back(&self) {
self.imp()
.chat_leaflet
.navigate(adw::NavigationDirection::Back);
}

fn show_pinned_messages(&self) {
if let Some(chat) = self.chat() {
let imp = self.imp();

let next_child = imp
.chat_leaflet
.adjacent_child(adw::NavigationDirection::Forward);
let cached = if let Some(pinned_messages_view) =
next_child.and_downcast::<PinnedMessagesView>()
{
pinned_messages_view.chat() == chat
} else {
false
};

if !cached {
let pinned_messages = PinnedMessagesView::new(&chat);
imp.chat_leaflet.append(&pinned_messages);
}

imp.chat_leaflet.navigate(adw::NavigationDirection::Forward);
}
}

pub(crate) fn chat(&self) -> Option<Chat> {
self.imp().chat.borrow().clone()
}
Expand All @@ -125,7 +167,16 @@ impl Content {

let imp = self.imp();
if chat.is_some() {
imp.stack.set_visible_child(&imp.chat_history.get());
// Remove every leaflet page except the first one (the first chat history)
imp.chat_leaflet
.pages()
.iter::<adw::LeafletPage>()
.map(|p| p.unwrap())
.enumerate()
.filter(|(i, _)| i > &0)
.for_each(|(_, p)| imp.chat_leaflet.remove(&p.child()));

imp.stack.set_visible_child(&imp.chat_leaflet.get());
} else {
imp.stack.set_visible_child(&imp.unselected_chat_view.get());
}
Expand Down
66 changes: 66 additions & 0 deletions src/session/content/pinned_messages_bar.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
use gtk::subclass::prelude::*;
use gtk::{glib, CompositeTemplate};

mod imp {
use super::*;

#[derive(Debug, Default, CompositeTemplate)]
#[template(string = r#"
template PinnedMessagesBar {
Box content_box {
styles ["toolbar"]
Box {
orientation: vertical;
hexpand: true;
Inscription {
}
Inscription {
}
}
Button {
icon-name: "view-list-symbolic";
action-name: "content.show-pinned-messages";
}
}
}
"#)]
pub(crate) struct PinnedMessagesBar {
#[template_child]
pub(super) content_box: TemplateChild<gtk::Box>,
}

#[glib::object_subclass]
impl ObjectSubclass for PinnedMessagesBar {
const NAME: &'static str = "PinnedMessagesBar";
type Type = super::PinnedMessagesBar;
type ParentType = gtk::Widget;

fn class_init(klass: &mut Self::Class) {
klass.bind_template();
klass.set_layout_manager_type::<gtk::BinLayout>();
}

fn instance_init(obj: &glib::subclass::InitializingObject<Self>) {
obj.init_template();
}
}

impl ObjectImpl for PinnedMessagesBar {
fn dispose(&self) {
self.dispose_template();
}
}

impl WidgetImpl for PinnedMessagesBar {}
}

glib::wrapper! {
pub(crate) struct PinnedMessagesBar(ObjectSubclass<imp::PinnedMessagesBar>)
@extends gtk::Widget;
}
Loading

0 comments on commit ffa58a2

Please sign in to comment.