Skip to content

Commit 2688968

Browse files
committed
strings: Add auto-updating UserStatusString
This is needed to have an online status label that auto-updates when the status is updated and when time passes (needed to e.g. update the string from "50 minutes ago" to "51 minutes ago").
1 parent 426ab41 commit 2688968

File tree

3 files changed

+86
-9
lines changed

3 files changed

+86
-9
lines changed

src/session/content/chat_info_window.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use tdlib::functions;
88
use tdlib::types::{BasicGroupFullInfo, SupergroupFullInfo};
99

1010
use crate::i18n::ngettext_f;
11-
use crate::tdlib::{BasicGroup, BoxedUserStatus, Chat, ChatType, Supergroup, User};
11+
use crate::tdlib::{BasicGroup, Chat, ChatType, Supergroup, User};
1212
use crate::utils::spawn;
1313
use crate::{expressions, strings};
1414

@@ -134,13 +134,9 @@ impl ChatInfoWindow {
134134
if let UserType::Bot(_) = user.type_().0 {
135135
imp.subtitle_label.set_label(&gettext("bot"));
136136
} else {
137-
User::this_expression("status")
138-
.chain_closure::<String>(closure!(
139-
|_: Option<glib::Object>, status: BoxedUserStatus| {
140-
strings::user_status(&status.0)
141-
}
142-
))
143-
.bind(&*imp.subtitle_label, "label", Some(user));
137+
gtk::ConstantExpression::new(&strings::UserStatusString::new(user.clone()))
138+
.chain_property::<strings::UserStatusString>("string")
139+
.bind(&*imp.subtitle_label, "label", glib::Object::NONE);
144140
}
145141

146142
// Phone number

src/strings.rs renamed to src/strings/mod.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
mod user_status_string;
2+
3+
pub(crate) use user_status_string::UserStatusString;
4+
15
use ellipse::Ellipse;
26
use gettextrs::gettext;
37
use gtk::glib;
@@ -28,7 +32,6 @@ pub(crate) fn user_status(status: &UserStatus) -> String {
2832
let was_online = glib::DateTime::from_unix_local(data.was_online as i64).unwrap();
2933
let time_span = now.difference(&was_online);
3034

31-
// TODO: Add a way to update the string when time passes
3235
if time_span.as_days() > 1 {
3336
// Translators: This is an online status with the date
3437
was_online.format(&gettext("last seen %x")).unwrap().into()

src/strings/user_status_string.rs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
use glib::clone;
2+
use gtk::glib;
3+
use gtk::prelude::*;
4+
use gtk::subclass::prelude::*;
5+
use tdlib::enums::UserStatus;
6+
7+
use crate::strings;
8+
use crate::tdlib::User;
9+
10+
mod imp {
11+
use super::*;
12+
use once_cell::sync::Lazy;
13+
use once_cell::unsync::OnceCell;
14+
15+
#[derive(Debug, Default)]
16+
pub(crate) struct UserStatusString(pub(super) OnceCell<User>);
17+
18+
#[glib::object_subclass]
19+
impl ObjectSubclass for UserStatusString {
20+
const NAME: &'static str = "UserStatusString";
21+
type Type = super::UserStatusString;
22+
}
23+
24+
impl ObjectImpl for UserStatusString {
25+
fn properties() -> &'static [glib::ParamSpec] {
26+
static PROPERTIES: Lazy<Vec<glib::ParamSpec>> =
27+
Lazy::new(|| vec![glib::ParamSpecString::builder("string").read_only().build()]);
28+
PROPERTIES.as_ref()
29+
}
30+
31+
fn property(&self, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
32+
let obj = self.obj();
33+
34+
match pspec.name() {
35+
"string" => obj.string().to_value(),
36+
_ => unimplemented!(),
37+
}
38+
}
39+
}
40+
}
41+
42+
glib::wrapper! {
43+
pub(crate) struct UserStatusString(ObjectSubclass<imp::UserStatusString>);
44+
}
45+
46+
impl UserStatusString {
47+
pub(crate) fn new(user: User) -> UserStatusString {
48+
let obj: UserStatusString = glib::Object::builder().build();
49+
50+
user.connect_notify_local(
51+
Some("status"),
52+
clone!(@weak obj => move |_, _| {
53+
obj.notify("string");
54+
}),
55+
);
56+
57+
// TODO: Maybe sync with the seconds of the last
58+
// offline state so that we're always precise.
59+
glib::timeout_add_seconds_local(
60+
60,
61+
clone!(@weak obj => @default-return glib::Continue(false), move || {
62+
let user = obj.imp().0.get().unwrap();
63+
if let UserStatus::Offline(_) = user.status().0 {
64+
obj.notify("string");
65+
}
66+
glib::Continue(true)
67+
}),
68+
);
69+
70+
obj.imp().0.set(user).unwrap();
71+
obj
72+
}
73+
74+
pub(crate) fn string(&self) -> String {
75+
let user = self.imp().0.get().unwrap();
76+
strings::user_status(&user.status().0)
77+
}
78+
}

0 commit comments

Comments
 (0)