Skip to content

Commit

Permalink
strings: Add auto-updating UserStatusString
Browse files Browse the repository at this point in the history
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").
  • Loading branch information
melix99 committed Nov 19, 2022
1 parent 426ab41 commit 2688968
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 9 deletions.
12 changes: 4 additions & 8 deletions src/session/content/chat_info_window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use tdlib::functions;
use tdlib::types::{BasicGroupFullInfo, SupergroupFullInfo};

use crate::i18n::ngettext_f;
use crate::tdlib::{BasicGroup, BoxedUserStatus, Chat, ChatType, Supergroup, User};
use crate::tdlib::{BasicGroup, Chat, ChatType, Supergroup, User};
use crate::utils::spawn;
use crate::{expressions, strings};

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

// Phone number
Expand Down
5 changes: 4 additions & 1 deletion src/strings.rs → src/strings/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
mod user_status_string;

pub(crate) use user_status_string::UserStatusString;

use ellipse::Ellipse;
use gettextrs::gettext;
use gtk::glib;
Expand Down Expand Up @@ -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()
Expand Down
78 changes: 78 additions & 0 deletions src/strings/user_status_string.rs
Original file line number Diff line number Diff line change
@@ -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<User>);

#[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<Vec<glib::ParamSpec>> =
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<imp::UserStatusString>);
}

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");
}),
);

// TODO: Maybe sync with the seconds of the last
// offline state so that we're always precise.
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)
}
}

0 comments on commit 2688968

Please sign in to comment.