Skip to content

Commit c4ca9e9

Browse files
committed
chat-info-members: Add GtkListBox with chat members
1 parent ee55310 commit c4ca9e9

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="GtkLabel" id="subtitle_label">
65+
<property name="wrap">True</property>
66+
<property name="justify">center</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="GtkLabel" id="subtitle_label">
53-
<property name="wrap">True</property>
54-
<property name="justify">center</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::Label>,
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]
@@ -214,6 +220,11 @@ impl ChatInfoWindow {
214220
imp.info_list.append(&row);
215221
}
216222

223+
imp.members_page.set_visible(true);
224+
spawn(clone!(@weak self as obj => async move {
225+
obj.append_members(basic_group_full_info.members).await;
226+
}));
227+
217228
self.update_info_list_visibility();
218229
}
219230

@@ -251,7 +262,7 @@ impl ChatInfoWindow {
251262
let result = functions::get_supergroup_full_info(supergroup_id, client_id).await;
252263
match result {
253264
Ok(tdlib::enums::SupergroupFullInfo::SupergroupFullInfo(full_info)) => {
254-
obj.setup_supergroup_full_info(full_info);
265+
obj.setup_supergroup_full_info(supergroup_id, full_info);
255266
}
256267
Err(e) => {
257268
log::warn!("Failed to get supergroup full info: {e:?}");
@@ -260,7 +271,12 @@ impl ChatInfoWindow {
260271
}));
261272
}
262273

263-
fn setup_supergroup_full_info(&self, supergroup_full_info: SupergroupFullInfo) {
274+
fn setup_supergroup_full_info(
275+
&self,
276+
supergroup_id: i64,
277+
supergroup_full_info: SupergroupFullInfo,
278+
) {
279+
let client_id = self.chat().unwrap().session().client_id();
264280
let imp = self.imp();
265281

266282
// Description
@@ -273,9 +289,111 @@ impl ChatInfoWindow {
273289
imp.info_list.append(&row);
274290
}
275291

292+
if supergroup_full_info.can_get_members {
293+
imp.members_page.set_visible(true);
294+
spawn(clone!(@weak self as obj => async move {
295+
let limit = 200;
296+
let mut offset = 0;
297+
while let Ok(TdChatMembers(ChatMembers {members, total_count})) = functions::get_supergroup_members(
298+
supergroup_id,
299+
None,
300+
offset,
301+
limit,
302+
client_id,
303+
).await
304+
{
305+
if offset > total_count {
306+
break;
307+
}
308+
309+
obj.append_members(members).await;
310+
311+
offset += limit;
312+
}
313+
}));
314+
}
315+
276316
self.update_info_list_visibility();
277317
}
278318

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

0 commit comments

Comments
 (0)