Skip to content

Commit 266045e

Browse files
committed
chat-info-members: Add GtkListBox with chat members
1 parent eb4980f commit 266045e

File tree

2 files changed

+216
-45
lines changed

2 files changed

+216
-45
lines changed

data/resources/ui/content-chat-info-window.ui

Lines changed: 94 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<interface>
33
<template class="ContentChatInfoWindow" parent="AdwWindow">
4-
<property name="default-width">360</property>
4+
<property name="default-width">400</property>
5+
<property name="default-height">600</property>
56
<property name="modal">True</property>
67
<style>
78
<class name="chat-info"/>
@@ -12,10 +13,11 @@
1213
<object class="GtkBox">
1314
<property name="orientation">vertical</property>
1415
<child>
15-
<object class="GtkHeaderBar">
16+
<object class="AdwHeaderBar">
17+
<property name="centering-policy">strict</property>
1618
<property name="title-widget">
17-
<object class="AdwWindowTitle">
18-
<property name="visible">False</property>
19+
<object class="AdwViewSwitcherTitle" id="title">
20+
<property name="stack">stack</property>
1921
</object>
2022
</property>
2123
<style>
@@ -24,46 +26,97 @@
2426
</object>
2527
</child>
2628
<child>
27-
<object class="AdwClamp">
28-
<property name="child">
29-
<object class="GtkBox">
30-
<property name="orientation">vertical</property>
31-
<style>
32-
<class name="main-page"/>
33-
</style>
34-
<child>
35-
<object class="ComponentsAvatar">
36-
<property name="size">128</property>
37-
<binding name="item">
38-
<lookup name="chat">ContentChatInfoWindow</lookup>
39-
</binding>
29+
<object class="AdwViewStack" id="stack">
30+
<property name="vexpand">true</property>
31+
<child>
32+
<object class="AdwViewStackPage">
33+
<property name="name">info</property>
34+
<property name="title" translatable="yes">Info</property>
35+
<property name="icon-name">help-about-symbolic</property>
36+
<property name="child">
37+
<object class="GtkScrolledWindow">
38+
<property name="child">
39+
<object class="AdwClamp">
40+
<property name="child">
41+
<object class="GtkBox">
42+
<property name="orientation">vertical</property>
43+
<style>
44+
<class name="main-page"/>
45+
</style>
46+
<child>
47+
<object class="ComponentsAvatar">
48+
<property name="size">128</property>
49+
<binding name="item">
50+
<lookup name="chat">ContentChatInfoWindow</lookup>
51+
</binding>
52+
</object>
53+
</child>
54+
<child>
55+
<object class="GtkLabel" id="name_label">
56+
<property name="wrap">True</property>
57+
<property name="justify">center</property>
58+
<style>
59+
<class name="title-1"/>
60+
</style>
61+
</object>
62+
</child>
63+
<child>
64+
<object class="GtkInscription" id="subtitle_label">
65+
<property name="text-overflow">ellipsize-end</property>
66+
<property name="xalign">0.5</property>
67+
</object>
68+
</child>
69+
<child>
70+
<object class="GtkListBox" id="info_list">
71+
<property name="selection-mode">none</property>
72+
<style>
73+
<class name="boxed-list"/>
74+
</style>
75+
</object>
76+
</child>
77+
</object>
78+
</property>
79+
</object>
80+
</property>
4081
</object>
41-
</child>
42-
<child>
43-
<object class="GtkLabel" id="name_label">
44-
<property name="wrap">True</property>
45-
<property name="justify">center</property>
46-
<style>
47-
<class name="title-1"/>
48-
</style>
49-
</object>
50-
</child>
51-
<child>
52-
<object class="GtkInscription" id="subtitle_label">
53-
<property name="text-overflow">ellipsize-middle</property>
54-
<property name="xalign">0.5</property>
55-
</object>
56-
</child>
57-
<child>
58-
<object class="GtkListBox" id="info_list">
59-
<property name="selection-mode">none</property>
60-
<style>
61-
<class name="boxed-list"/>
62-
</style>
82+
</property>
83+
</object>
84+
</child>
85+
<child>
86+
<object class="AdwViewStackPage" id="members_page">
87+
<property name="name">members</property>
88+
<property name="title" translatable="yes">Members</property>
89+
<property name="icon-name">avatar-default-symbolic</property>
90+
<property name="visible">false</property>
91+
<property name="child">
92+
<object class="GtkScrolledWindow">
93+
<property name="child">
94+
<object class="AdwClamp">
95+
<property name="maximum-size">440</property>
96+
<property name="tightening-threshold">200</property>
97+
<property name="child">
98+
<object class="GtkListBox" id="members_list">
99+
<property name="valign">center</property>
100+
<property name="selection-mode">none</property>
101+
<style>
102+
<class name="boxed-list"/>
103+
</style>
104+
</object>
105+
</property>
106+
</object>
107+
</property>
63108
</object>
64-
</child>
109+
</property>
65110
</object>
66-
</property>
111+
</child>
112+
</object>
113+
</child>
114+
<child>
115+
<object class="AdwViewSwitcherBar">
116+
<property name="stack">stack</property>
117+
<binding name="reveal">
118+
<lookup name="title-visible">title</lookup>
119+
</binding>
67120
</object>
68121
</child>
69122
</object>

src/session/content/chat_info_window.rs

Lines changed: 122 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ use gettextrs::gettext;
33
use glib::{clone, closure};
44
use gtk::subclass::prelude::*;
55
use gtk::{glib, CompositeTemplate};
6-
use tdlib::enums::UserType;
6+
use tdlib::enums::ChatMembers::ChatMembers as TdChatMembers;
7+
use tdlib::enums::User::User as TdUser;
8+
use tdlib::enums::{ChatMemberStatus, MessageSender, UserType};
79
use tdlib::functions;
8-
use tdlib::types::{BasicGroupFullInfo, SupergroupFullInfo};
10+
use tdlib::types::{BasicGroupFullInfo, ChatMember, ChatMembers, SupergroupFullInfo};
911

1012
use crate::i18n::ngettext_f;
1113
use crate::tdlib::{BasicGroup, BoxedUserStatus, Chat, ChatType, Supergroup, User};
@@ -29,6 +31,10 @@ mod imp {
2931
pub(super) subtitle_label: TemplateChild<gtk::Inscription>,
3032
#[template_child]
3133
pub(super) info_list: TemplateChild<gtk::ListBox>,
34+
#[template_child]
35+
pub(super) members_page: TemplateChild<adw::ViewStackPage>,
36+
#[template_child]
37+
pub(super) members_list: TemplateChild<gtk::ListBox>,
3238
}
3339

3440
#[glib::object_subclass]
@@ -208,6 +214,11 @@ impl ChatInfoWindow {
208214
imp.info_list.append(&row);
209215
}
210216

217+
imp.members_page.set_visible(true);
218+
spawn(clone!(@weak self as obj => async move {
219+
obj.append_members(basic_group_full_info.members).await;
220+
}));
221+
211222
self.update_info_list_visibility();
212223
}
213224

@@ -245,7 +256,7 @@ impl ChatInfoWindow {
245256
let result = functions::get_supergroup_full_info(supergroup_id, client_id).await;
246257
match result {
247258
Ok(tdlib::enums::SupergroupFullInfo::SupergroupFullInfo(full_info)) => {
248-
obj.setup_supergroup_full_info(full_info);
259+
obj.setup_supergroup_full_info(supergroup_id, full_info);
249260
}
250261
Err(e) => {
251262
log::warn!("Failed to get supergroup full info: {e:?}");
@@ -254,7 +265,12 @@ impl ChatInfoWindow {
254265
}));
255266
}
256267

257-
fn setup_supergroup_full_info(&self, supergroup_full_info: SupergroupFullInfo) {
268+
fn setup_supergroup_full_info(
269+
&self,
270+
supergroup_id: i64,
271+
supergroup_full_info: SupergroupFullInfo,
272+
) {
273+
let client_id = self.chat().unwrap().session().client_id();
258274
let imp = self.imp();
259275

260276
// Description
@@ -267,9 +283,111 @@ impl ChatInfoWindow {
267283
imp.info_list.append(&row);
268284
}
269285

286+
if supergroup_full_info.can_get_members {
287+
imp.members_page.set_visible(true);
288+
spawn(clone!(@weak self as obj => async move {
289+
let limit = 200;
290+
let mut offset = 0;
291+
while let Ok(TdChatMembers(ChatMembers {members, total_count})) = functions::get_supergroup_members(
292+
supergroup_id,
293+
None,
294+
offset,
295+
limit,
296+
client_id,
297+
).await
298+
{
299+
if offset > total_count {
300+
break;
301+
}
302+
303+
obj.append_members(members).await;
304+
305+
offset += limit;
306+
}
307+
}));
308+
}
309+
270310
self.update_info_list_visibility();
271311
}
272312

313+
async fn append_members(&self, members: Vec<ChatMember>) {
314+
let session = self.chat().unwrap().session();
315+
let client_id = session.client_id();
316+
317+
let members_list = &self.imp().members_list;
318+
319+
for member in members {
320+
if let MessageSender::User(user) = member.member_id {
321+
if let Ok(TdUser(user)) = functions::get_user(user.user_id, client_id).await {
322+
let user_row = adw::ActionRow::new();
323+
user_row.set_title_lines(1);
324+
user_row.set_subtitle_lines(1);
325+
326+
let user = User::from_td_object(user, &session);
327+
328+
let user_expression = gtk::ObjectExpression::new(&user);
329+
let name_expression = expressions::user_display_name(&user_expression);
330+
name_expression.bind(&user_row, "title", Some(&user));
331+
332+
User::this_expression("status")
333+
.chain_closure::<String>(closure!(
334+
|_: Option<glib::Object>, status: BoxedUserStatus| {
335+
strings::user_status(&status.0)
336+
}
337+
))
338+
.bind(&user_row, "subtitle", Some(&user));
339+
340+
if let UserType::Bot(_) = user.type_().0 {
341+
user_row.set_subtitle(&gettext("bot"));
342+
} else {
343+
User::this_expression("status")
344+
.chain_closure::<String>(closure!(
345+
|_: Option<glib::Object>, status: BoxedUserStatus| {
346+
strings::user_status(&status.0)
347+
}
348+
))
349+
.bind(&user_row, "subtitle", Some(&user));
350+
};
351+
352+
let avatar = crate::session::components::Avatar::new();
353+
354+
avatar.set_item(Some(user.upcast()));
355+
avatar.set_size(32);
356+
user_row.add_prefix(&avatar);
357+
358+
let status = match member.status {
359+
ChatMemberStatus::Creator(owner) => {
360+
let title = if owner.custom_title.is_empty() {
361+
gettext("Owner")
362+
} else {
363+
owner.custom_title
364+
};
365+
Some(title)
366+
}
367+
ChatMemberStatus::Administrator(admin) => {
368+
let title = if admin.custom_title.is_empty() {
369+
gettext("Admin")
370+
} else {
371+
admin.custom_title
372+
};
373+
Some(title)
374+
}
375+
_ => None,
376+
};
377+
378+
if let Some(text) = status {
379+
let owner_label = gtk::Label::new(Some(&text));
380+
owner_label.set_yalign(0.2);
381+
owner_label.set_css_classes(&["caption", "accent"]);
382+
user_row.add_suffix(&owner_label);
383+
}
384+
385+
members_list.append(&user_row);
386+
}
387+
}
388+
}
389+
}
390+
273391
fn update_info_list_visibility(&self) {
274392
let info_list = &self.imp().info_list;
275393
info_list.set_visible(info_list.first_child().is_some());

0 commit comments

Comments
 (0)