diff --git a/src/session/content/chat_info_window.rs b/src/session/content/chat_info_window.rs index 297f79c53..7f3fefb98 100644 --- a/src/session/content/chat_info_window.rs +++ b/src/session/content/chat_info_window.rs @@ -7,10 +7,11 @@ use tdlib::enums::UserType; use tdlib::functions; use tdlib::types::{BasicGroupFullInfo, SupergroupFullInfo}; +use crate::expressions; use crate::i18n::ngettext_f; -use crate::tdlib::{BasicGroup, BoxedUserStatus, Chat, ChatType, Supergroup, User}; +use crate::strings::UserStatusString; +use crate::tdlib::{BasicGroup, Chat, ChatType, Supergroup, User}; use crate::utils::spawn; -use crate::{expressions, strings}; mod imp { use super::*; @@ -134,13 +135,9 @@ impl ChatInfoWindow { if let UserType::Bot(_) = user.type_().0 { imp.subtitle_label.set_label(&gettext("bot")); } else { - User::this_expression("status") - .chain_closure::(closure!( - |_: Option, status: BoxedUserStatus| { - strings::user_status(&status.0) - } - )) - .bind(&*imp.subtitle_label, "label", Some(user)); + gtk::ConstantExpression::new(&UserStatusString::new(user.clone())) + .chain_property::("string") + .bind(&*imp.subtitle_label, "label", glib::Object::NONE); } // Phone number diff --git a/src/strings.rs b/src/strings/mod.rs similarity index 99% rename from src/strings.rs rename to src/strings/mod.rs index f6b674392..d551037af 100644 --- a/src/strings.rs +++ b/src/strings/mod.rs @@ -1,3 +1,7 @@ +mod user_status_string; + +pub(crate) use user_status_string::UserStatusString; + use ellipse::Ellipse; use gettextrs::gettext; use gtk::glib; @@ -28,7 +32,6 @@ pub(crate) fn user_status(status: &UserStatus) -> String { let was_online = glib::DateTime::from_unix_local(data.was_online as i64).unwrap(); let time_span = now.difference(&was_online); - // TODO: Add a way to update the string when time passes if time_span.as_days() > 1 { // Translators: This is an online status with the date was_online.format(&gettext("last seen %x")).unwrap().into() diff --git a/src/strings/user_status_string.rs b/src/strings/user_status_string.rs new file mode 100644 index 000000000..4aca4d908 --- /dev/null +++ b/src/strings/user_status_string.rs @@ -0,0 +1,78 @@ +use glib::clone; +use gtk::glib; +use gtk::prelude::*; +use gtk::subclass::prelude::*; +use tdlib::enums::UserStatus; + +use crate::strings; +use crate::tdlib::User; + +mod imp { + use super::*; + use once_cell::sync::Lazy; + use once_cell::unsync::OnceCell; + + #[derive(Debug, Default)] + pub(crate) struct UserStatusString(pub(super) OnceCell); + + #[glib::object_subclass] + impl ObjectSubclass for UserStatusString { + const NAME: &'static str = "UserStatusString"; + type Type = super::UserStatusString; + } + + impl ObjectImpl for UserStatusString { + fn properties() -> &'static [glib::ParamSpec] { + static PROPERTIES: Lazy> = + Lazy::new(|| vec![glib::ParamSpecString::builder("string").read_only().build()]); + PROPERTIES.as_ref() + } + + fn property(&self, _id: usize, pspec: &glib::ParamSpec) -> glib::Value { + let obj = self.obj(); + + match pspec.name() { + "string" => obj.string().to_value(), + _ => unimplemented!(), + } + } + } +} + +glib::wrapper! { + pub(crate) struct UserStatusString(ObjectSubclass); +} + +impl UserStatusString { + pub(crate) fn new(user: User) -> UserStatusString { + let obj: UserStatusString = glib::Object::builder().build(); + + user.connect_notify_local( + Some("status"), + clone!(@weak obj => move |_, _| { + obj.notify("string"); + }), + ); + + // Notify the string every minute when the user is offline so that + // the "last seen" text is updated when time passes. + glib::timeout_add_seconds_local( + 60, + clone!(@weak obj => @default-return glib::Continue(false), move || { + let user = obj.imp().0.get().unwrap(); + if let UserStatus::Offline(_) = user.status().0 { + obj.notify("string"); + } + glib::Continue(true) + }), + ); + + obj.imp().0.set(user).unwrap(); + obj + } + + pub(crate) fn string(&self) -> String { + let user = self.imp().0.get().unwrap(); + strings::user_status(&user.status().0) + } +}