Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

strings: Add auto-updating UserStatusString #405

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 6 additions & 9 deletions src/session/content/chat_info_window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;
Expand Down Expand Up @@ -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::<String>(closure!(
|_: Option<glib::Object>, status: BoxedUserStatus| {
strings::user_status(&status.0)
}
))
.bind(&*imp.subtitle_label, "label", Some(user));
gtk::ConstantExpression::new(&UserStatusString::new(user.clone()))
.chain_property::<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");
}),
);

// 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)
}
}