|
|
|
@ -1,10 +1,10 @@ |
|
|
|
use adw::subclass::prelude::*; |
|
|
|
use adw::{prelude::*, subclass::prelude::*}; |
|
|
|
use gtk::{glib, prelude::*, CompositeTemplate}; |
|
|
|
use gtk::{glib, CompositeTemplate}; |
|
|
|
|
|
|
|
|
|
|
|
use crate::{prelude::*, utils::string::linkify}; |
|
|
|
use crate::{prelude::*, utils::string::linkify}; |
|
|
|
|
|
|
|
|
|
|
|
mod imp { |
|
|
|
mod imp { |
|
|
|
use std::cell::RefCell; |
|
|
|
use std::cell::{OnceCell, RefCell}; |
|
|
|
|
|
|
|
|
|
|
|
use glib::subclass::InitializingObject; |
|
|
|
use glib::subclass::InitializingObject; |
|
|
|
|
|
|
|
|
|
|
|
@ -17,13 +17,24 @@ mod imp { |
|
|
|
// The title of the room.
|
|
|
|
// The title of the room.
|
|
|
|
#[property(get, set = Self::set_title, explicit_notify)] |
|
|
|
#[property(get, set = Self::set_title, explicit_notify)] |
|
|
|
pub title: RefCell<Option<String>>, |
|
|
|
pub title: RefCell<Option<String>>, |
|
|
|
|
|
|
|
// The title of the room that can be presented on a single line.
|
|
|
|
|
|
|
|
#[property(get)] |
|
|
|
|
|
|
|
pub title_excerpt: RefCell<Option<String>>, |
|
|
|
// The subtitle of the room.
|
|
|
|
// The subtitle of the room.
|
|
|
|
#[property(get, set = Self::set_subtitle, explicit_notify)] |
|
|
|
#[property(get, set = Self::set_subtitle, explicit_notify)] |
|
|
|
pub subtitle: RefCell<Option<String>>, |
|
|
|
pub subtitle: RefCell<Option<String>>, |
|
|
|
|
|
|
|
// The subtitle of the room that can be presented on a single line.
|
|
|
|
|
|
|
|
#[property(get)] |
|
|
|
|
|
|
|
pub subtitle_excerpt: RefCell<Option<String>>, |
|
|
|
#[template_child] |
|
|
|
#[template_child] |
|
|
|
pub title_label: TemplateChild<gtk::Label>, |
|
|
|
pub stack: TemplateChild<gtk::Stack>, |
|
|
|
#[template_child] |
|
|
|
#[template_child] |
|
|
|
pub subtitle_label: TemplateChild<gtk::Label>, |
|
|
|
pub title_excerpt_label: TemplateChild<gtk::Label>, |
|
|
|
|
|
|
|
#[template_child] |
|
|
|
|
|
|
|
pub start_bin: TemplateChild<adw::Bin>, |
|
|
|
|
|
|
|
#[template_child] |
|
|
|
|
|
|
|
pub arrow_icon: TemplateChild<gtk::Image>, |
|
|
|
|
|
|
|
size_group: OnceCell<gtk::SizeGroup>, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#[glib::object_subclass] |
|
|
|
#[glib::object_subclass] |
|
|
|
@ -35,7 +46,7 @@ mod imp { |
|
|
|
fn class_init(klass: &mut Self::Class) { |
|
|
|
fn class_init(klass: &mut Self::Class) { |
|
|
|
Self::bind_template(klass); |
|
|
|
Self::bind_template(klass); |
|
|
|
|
|
|
|
|
|
|
|
klass.set_css_name("roomtitle"); |
|
|
|
klass.set_css_name("room-title"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn instance_init(obj: &InitializingObject<Self>) { |
|
|
|
fn instance_init(obj: &InitializingObject<Self>) { |
|
|
|
@ -44,39 +55,91 @@ mod imp { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#[glib::derived_properties] |
|
|
|
#[glib::derived_properties] |
|
|
|
impl ObjectImpl for RoomTitle {} |
|
|
|
impl ObjectImpl for RoomTitle { |
|
|
|
|
|
|
|
fn constructed(&self) { |
|
|
|
|
|
|
|
self.parent_constructed(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let size_group = self |
|
|
|
|
|
|
|
.size_group |
|
|
|
|
|
|
|
.get_or_init(|| gtk::SizeGroup::new(gtk::SizeGroupMode::Horizontal)); |
|
|
|
|
|
|
|
size_group.add_widget(&*self.start_bin); |
|
|
|
|
|
|
|
size_group.add_widget(&*self.arrow_icon); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
impl WidgetImpl for RoomTitle {} |
|
|
|
impl WidgetImpl for RoomTitle {} |
|
|
|
impl BinImpl for RoomTitle {} |
|
|
|
impl BinImpl for RoomTitle {} |
|
|
|
|
|
|
|
|
|
|
|
impl RoomTitle { |
|
|
|
impl RoomTitle { |
|
|
|
/// Set the title of the room.
|
|
|
|
/// Set the title of the room.
|
|
|
|
fn set_title(&self, title: Option<String>) { |
|
|
|
fn set_title(&self, original_title: Option<String>) { |
|
|
|
let title = title.map(|s| to_pango_markup(&s)); |
|
|
|
let title = original_title.as_deref().map(|s| { |
|
|
|
|
|
|
|
// Detect links.
|
|
|
|
|
|
|
|
let mut s = linkify(s); |
|
|
|
|
|
|
|
// Remove trailing spaces.
|
|
|
|
|
|
|
|
s.truncate_end_whitespaces(); |
|
|
|
|
|
|
|
s |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
if *self.title.borrow() == title { |
|
|
|
if *self.title.borrow() == title { |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let has_title = title.is_some(); |
|
|
|
|
|
|
|
let title_excerpt = original_title.map(|s| { |
|
|
|
|
|
|
|
// Remove newlines.
|
|
|
|
|
|
|
|
let mut s = s.replace('\n', ""); |
|
|
|
|
|
|
|
// Remove trailing spaces.
|
|
|
|
|
|
|
|
s.truncate_end_whitespaces(); |
|
|
|
|
|
|
|
s |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
self.title.replace(title); |
|
|
|
self.title.replace(title); |
|
|
|
self.title_label.set_visible(self.title.borrow().is_some()); |
|
|
|
self.title_excerpt.replace(title_excerpt); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let obj = self.obj(); |
|
|
|
|
|
|
|
obj.notify_title(); |
|
|
|
|
|
|
|
obj.notify_title_excerpt(); |
|
|
|
|
|
|
|
|
|
|
|
self.obj().notify_title(); |
|
|
|
self.title_excerpt_label.set_visible(has_title); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Set the subtitle of the room.
|
|
|
|
/// Set the subtitle of the room.
|
|
|
|
pub fn set_subtitle(&self, subtitle: Option<String>) { |
|
|
|
pub fn set_subtitle(&self, original_subtitle: Option<String>) { |
|
|
|
let subtitle = subtitle.map(|s| to_pango_markup(&s)); |
|
|
|
let subtitle = original_subtitle.as_deref().map(|s| { |
|
|
|
|
|
|
|
// Detect links.
|
|
|
|
|
|
|
|
let mut s = linkify(s); |
|
|
|
|
|
|
|
// Remove trailing spaces.
|
|
|
|
|
|
|
|
s.truncate_end_whitespaces(); |
|
|
|
|
|
|
|
s |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
if *self.subtitle.borrow() == subtitle { |
|
|
|
if *self.subtitle.borrow() == subtitle { |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let has_subtitle = subtitle.is_some(); |
|
|
|
|
|
|
|
let subtitle_excerpt = original_subtitle.map(|s| { |
|
|
|
|
|
|
|
// Remove newlines.
|
|
|
|
|
|
|
|
let mut s = s.replace('\n', ""); |
|
|
|
|
|
|
|
// Remove trailing spaces.
|
|
|
|
|
|
|
|
s.truncate_end_whitespaces(); |
|
|
|
|
|
|
|
s |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
self.subtitle.replace(subtitle); |
|
|
|
self.subtitle.replace(subtitle); |
|
|
|
self.subtitle_label |
|
|
|
self.subtitle_excerpt.replace(subtitle_excerpt); |
|
|
|
.set_visible(self.subtitle.borrow().is_some()); |
|
|
|
|
|
|
|
|
|
|
|
let obj = self.obj(); |
|
|
|
|
|
|
|
obj.notify_subtitle(); |
|
|
|
|
|
|
|
obj.notify_subtitle_excerpt(); |
|
|
|
|
|
|
|
|
|
|
|
self.obj().notify_subtitle(); |
|
|
|
// Show the button only if there is a subtitle.
|
|
|
|
|
|
|
|
if has_subtitle { |
|
|
|
|
|
|
|
self.stack.set_visible_child_name("button"); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
self.stack.set_visible_child_name("title-only"); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -98,13 +161,3 @@ impl Default for RoomTitle { |
|
|
|
Self::new() |
|
|
|
Self::new() |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Convert the given string to be used by Pango.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// This linkifies the text, removes newlines, escapes markup and removes
|
|
|
|
|
|
|
|
/// trailing spaces.
|
|
|
|
|
|
|
|
fn to_pango_markup(s: &str) -> String { |
|
|
|
|
|
|
|
let mut result = linkify(s).replace('\n', " "); |
|
|
|
|
|
|
|
result.truncate_end_whitespaces(); |
|
|
|
|
|
|
|
result |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|