Browse Source

room-history: Allow to view full room title and description in a popover

Also allows to click any link.
merge-requests/1716/head
Kévin Commaille 2 years ago
parent
commit
4d0f22f36e
No known key found for this signature in database
GPG Key ID: C971D9DBC9D678D
  1. 24
      data/resources/style.css
  2. 1
      po/POTFILES.in
  3. 105
      src/components/room_title.rs
  4. 174
      src/components/room_title.ui

24
data/resources/style.css

@ -772,22 +772,34 @@ room-history-row expander-widget > box > :not(title) {
padding: 12px;
}
roomtitle {
room-title {
margin-top: -6px;
margin-bottom: -6px;
min-height: 12px;
}
roomtitle .title {
room-title menubutton, room-title menubutton .toggle {
padding: 0;
}
room-title menubutton .toggle {
padding: 0;
padding-left: 12px;
padding-right: 12px;
}
room-title menubutton image.arrow {
transform: rotate(-0.5turn);
}
room-title .title {
padding: 0;
font-weight: bold;
}
roomtitle .subtitle {
font-size: smaller;
padding-left: 12px;
padding-right: 12px;
room-title .subtitle {
padding: 0;
font-weight: normal;
}
sender-avatar {

1
po/POTFILES.in

@ -29,6 +29,7 @@ src/components/media/location_viewer.rs
src/components/reaction_chooser.ui
src/components/pill/at_room.rs
src/components/power_level_selection/popover.ui
src/components/room_title.ui
src/components/rows/loading_row.ui
src/components/user_page.rs
src/components/user_page.ui

105
src/components/room_title.rs

@ -1,10 +1,10 @@
use adw::subclass::prelude::*;
use gtk::{glib, prelude::*, CompositeTemplate};
use adw::{prelude::*, subclass::prelude::*};
use gtk::{glib, CompositeTemplate};
use crate::{prelude::*, utils::string::linkify};
mod imp {
use std::cell::RefCell;
use std::cell::{OnceCell, RefCell};
use glib::subclass::InitializingObject;
@ -17,13 +17,24 @@ mod imp {
// The title of the room.
#[property(get, set = Self::set_title, explicit_notify)]
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.
#[property(get, set = Self::set_subtitle, explicit_notify)]
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]
pub title_label: TemplateChild<gtk::Label>,
pub stack: TemplateChild<gtk::Stack>,
#[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]
@ -35,7 +46,7 @@ mod imp {
fn class_init(klass: &mut Self::Class) {
Self::bind_template(klass);
klass.set_css_name("roomtitle");
klass.set_css_name("room-title");
}
fn instance_init(obj: &InitializingObject<Self>) {
@ -44,39 +55,91 @@ mod imp {
}
#[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 BinImpl for RoomTitle {}
impl RoomTitle {
/// Set the title of the room.
fn set_title(&self, title: Option<String>) {
let title = title.map(|s| to_pango_markup(&s));
fn set_title(&self, original_title: Option<String>) {
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 {
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_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.
pub fn set_subtitle(&self, subtitle: Option<String>) {
let subtitle = subtitle.map(|s| to_pango_markup(&s));
pub fn set_subtitle(&self, original_subtitle: Option<String>) {
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 {
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_label
.set_visible(self.subtitle.borrow().is_some());
self.subtitle_excerpt.replace(subtitle_excerpt);
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()
}
}
/// 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
}

174
src/components/room_title.ui

@ -2,40 +2,154 @@
<interface>
<template class="RoomTitle" parent="AdwBin">
<child>
<object class="GtkBox" id="box">
<property name="orientation">vertical</property>
<property name="halign">center</property>
<property name="valign">center</property>
<object class="GtkStack" id="stack">
<child>
<object class="GtkLabel" id="title_label">
<property name="focusable">True</property>
<property name="ellipsize">end</property>
<property name="halign">center</property>
<property name="wrap">False</property>
<property name="single-line-mode">True</property>
<property name="use-markup">True</property>
<property name="width-chars">5</property>
<property name="label" bind-source="RoomTitle" bind-property="title" bind-flags="sync-create"/>
<property name="tooltip-markup" bind-source="RoomTitle" bind-property="title" bind-flags="sync-create"/>
<style>
<class name="title"/>
</style>
<object class="GtkStackPage">
<property name="name">title-only</property>
<property name="child">
<object class="GtkLabel">
<property name="focusable">True</property>
<property name="ellipsize">end</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="wrap">False</property>
<property name="single-line-mode">True</property>
<property name="use-markup">True</property>
<property name="width-chars">5</property>
<property name="label" bind-source="RoomTitle" bind-property="title-excerpt" bind-flags="sync-create"/>
<property name="tooltip-markup" bind-source="RoomTitle" bind-property="title-excerpt" bind-flags="sync-create"/>
<style>
<class name="title"/>
</style>
</object>
</property>
</object>
</child>
<child>
<object class="GtkLabel" id="subtitle_label">
<property name="focusable">True</property>
<property name="ellipsize">end</property>
<property name="halign">center</property>
<property name="wrap">False</property>
<property name="single-line-mode">True</property>
<property name="use-markup">True</property>
<property name="visible">False</property>
<property name="label" bind-source="RoomTitle" bind-property="subtitle" bind-flags="sync-create"/>
<property name="tooltip-markup" bind-source="RoomTitle" bind-property="subtitle" bind-flags="sync-create"/>
<style>
<class name="subtitle"/>
</style>
<object class="GtkStackPage">
<property name="name">button</property>
<property name="child">
<object class="GtkMenuButton">
<style>
<class name="flat"/>
</style>
<property name="tooltip-text" translatable="yes">Click to Expand</property>
<property name="child">
<object class="GtkBox">
<property name="halign">center</property>
<property name="valign">center</property>
<property name="accessible-role">group</property>
<property name="spacing">6</property>
<child>
<!-- Widget to compensate for the arrow on the right for centering the title -->
<object class="AdwBin" id="start_bin">
<property name="halign">start</property>
<property name="accessible-role">presentation</property>
</object>
</child>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="accessible-role">group</property>
<child>
<object class="GtkLabel" id="title_excerpt_label">
<property name="focusable">True</property>
<property name="ellipsize">end</property>
<property name="halign">center</property>
<property name="wrap">False</property>
<property name="single-line-mode">True</property>
<property name="use-markup">True</property>
<property name="width-chars">5</property>
<property name="label" bind-source="RoomTitle" bind-property="title-excerpt" bind-flags="sync-create"/>
<style>
<class name="title"/>
</style>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="ellipsize">end</property>
<property name="halign">center</property>
<property name="wrap">False</property>
<property name="single-line-mode">True</property>
<property name="use-markup">True</property>
<property name="label" bind-source="RoomTitle" bind-property="subtitle-excerpt" bind-flags="sync-create"/>
<style>
<class name="subtitle"/>
</style>
</object>
</child>
</object>
</child>
<child>
<object class="GtkImage" id="arrow_icon">
<property name="halign">end</property>
<property name="valign">center</property>
<property name="icon-name">expander-arrow-symbolic</property>
<property name="accessible-role">presentation</property>
<style>
<class name="arrow" />
</style>
</object>
</child>
</object>
</property>
<property name="popover">
<object class="GtkPopover">
<property name="has-arrow">False</property>
<property name="child">
<object class="GtkScrolledWindow">
<property name="hscrollbar-policy">never</property>
<property name="propagate-natural-height">True</property>
<property name="propagate-natural-width">True</property>
<property name="child">
<object class="AdwClamp">
<property name="maximum-size">500</property>
<property name="tightening-threshold">500</property>
<property name="child">
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="accessible-role">group</property>
<property name="spacing">6</property>
<property name="margin-bottom">6</property>
<child>
<object class="GtkLabel">
<property name="focusable">True</property>
<property name="wrap">True</property>
<property name="wrap-mode">word-char</property>
<property name="use-markup">True</property>
<property name="selectable">True</property>
<property name="label" bind-source="RoomTitle" bind-property="title" bind-flags="sync-create"/>
<style>
<class name="heading"/>
</style>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="focusable">True</property>
<property name="wrap">True</property>
<property name="wrap-mode">word-char</property>
<property name="use-markup">True</property>
<property name="selectable">True</property>
<property name="label" bind-source="RoomTitle" bind-property="subtitle" bind-flags="sync-create"/>
<style>
<class name="body"/>
</style>
</object>
</child>
</object>
</property>
</object>
</property>
</object>
</property>
</object>
</property>
</object>
</property>
</object>
</child>
</object>

Loading…
Cancel
Save