feat(date-time): select timezones from searchable context drawer

This commit is contained in:
Michael Aaron Murphy 2024-08-06 12:34:59 +02:00 committed by Michael Murphy
parent 648c4e24ab
commit fa0ce598e5
5 changed files with 125 additions and 45 deletions

34
Cargo.lock generated
View file

@ -1369,7 +1369,7 @@ dependencies = [
[[package]] [[package]]
name = "cosmic-config" name = "cosmic-config"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/pop-os/libcosmic#756f4b6ba69d11075eb0c34ea0fc837bd27ad63a" source = "git+https://github.com/pop-os/libcosmic#4dd0f72f155b8705a30c2d42282f0bf1e5159e10"
dependencies = [ dependencies = [
"atomicwrites", "atomicwrites",
"calloop 0.14.0", "calloop 0.14.0",
@ -1392,7 +1392,7 @@ dependencies = [
[[package]] [[package]]
name = "cosmic-config-derive" name = "cosmic-config-derive"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/pop-os/libcosmic#756f4b6ba69d11075eb0c34ea0fc837bd27ad63a" source = "git+https://github.com/pop-os/libcosmic#4dd0f72f155b8705a30c2d42282f0bf1e5159e10"
dependencies = [ dependencies = [
"quote", "quote",
"syn 1.0.109", "syn 1.0.109",
@ -1602,7 +1602,7 @@ dependencies = [
[[package]] [[package]]
name = "cosmic-theme" name = "cosmic-theme"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/pop-os/libcosmic#756f4b6ba69d11075eb0c34ea0fc837bd27ad63a" source = "git+https://github.com/pop-os/libcosmic#4dd0f72f155b8705a30c2d42282f0bf1e5159e10"
dependencies = [ dependencies = [
"almost", "almost",
"cosmic-config", "cosmic-config",
@ -2888,7 +2888,7 @@ dependencies = [
[[package]] [[package]]
name = "iced" name = "iced"
version = "0.12.0" version = "0.12.0"
source = "git+https://github.com/pop-os/libcosmic#756f4b6ba69d11075eb0c34ea0fc837bd27ad63a" source = "git+https://github.com/pop-os/libcosmic#4dd0f72f155b8705a30c2d42282f0bf1e5159e10"
dependencies = [ dependencies = [
"dnd", "dnd",
"iced_accessibility", "iced_accessibility",
@ -2907,7 +2907,7 @@ dependencies = [
[[package]] [[package]]
name = "iced_accessibility" name = "iced_accessibility"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/pop-os/libcosmic#756f4b6ba69d11075eb0c34ea0fc837bd27ad63a" source = "git+https://github.com/pop-os/libcosmic#4dd0f72f155b8705a30c2d42282f0bf1e5159e10"
dependencies = [ dependencies = [
"accesskit", "accesskit",
"accesskit_unix", "accesskit_unix",
@ -2916,7 +2916,7 @@ dependencies = [
[[package]] [[package]]
name = "iced_core" name = "iced_core"
version = "0.12.0" version = "0.12.0"
source = "git+https://github.com/pop-os/libcosmic#756f4b6ba69d11075eb0c34ea0fc837bd27ad63a" source = "git+https://github.com/pop-os/libcosmic#4dd0f72f155b8705a30c2d42282f0bf1e5159e10"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.6.0",
"dnd", "dnd",
@ -2938,7 +2938,7 @@ dependencies = [
[[package]] [[package]]
name = "iced_futures" name = "iced_futures"
version = "0.12.0" version = "0.12.0"
source = "git+https://github.com/pop-os/libcosmic#756f4b6ba69d11075eb0c34ea0fc837bd27ad63a" source = "git+https://github.com/pop-os/libcosmic#4dd0f72f155b8705a30c2d42282f0bf1e5159e10"
dependencies = [ dependencies = [
"futures", "futures",
"iced_core", "iced_core",
@ -2951,7 +2951,7 @@ dependencies = [
[[package]] [[package]]
name = "iced_graphics" name = "iced_graphics"
version = "0.12.0" version = "0.12.0"
source = "git+https://github.com/pop-os/libcosmic#756f4b6ba69d11075eb0c34ea0fc837bd27ad63a" source = "git+https://github.com/pop-os/libcosmic#4dd0f72f155b8705a30c2d42282f0bf1e5159e10"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.6.0",
"bytemuck", "bytemuck",
@ -2975,7 +2975,7 @@ dependencies = [
[[package]] [[package]]
name = "iced_renderer" name = "iced_renderer"
version = "0.12.0" version = "0.12.0"
source = "git+https://github.com/pop-os/libcosmic#756f4b6ba69d11075eb0c34ea0fc837bd27ad63a" source = "git+https://github.com/pop-os/libcosmic#4dd0f72f155b8705a30c2d42282f0bf1e5159e10"
dependencies = [ dependencies = [
"iced_graphics", "iced_graphics",
"iced_tiny_skia", "iced_tiny_skia",
@ -2987,7 +2987,7 @@ dependencies = [
[[package]] [[package]]
name = "iced_runtime" name = "iced_runtime"
version = "0.12.0" version = "0.12.0"
source = "git+https://github.com/pop-os/libcosmic#756f4b6ba69d11075eb0c34ea0fc837bd27ad63a" source = "git+https://github.com/pop-os/libcosmic#4dd0f72f155b8705a30c2d42282f0bf1e5159e10"
dependencies = [ dependencies = [
"dnd", "dnd",
"iced_accessibility", "iced_accessibility",
@ -3001,7 +3001,7 @@ dependencies = [
[[package]] [[package]]
name = "iced_sctk" name = "iced_sctk"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/pop-os/libcosmic#756f4b6ba69d11075eb0c34ea0fc837bd27ad63a" source = "git+https://github.com/pop-os/libcosmic#4dd0f72f155b8705a30c2d42282f0bf1e5159e10"
dependencies = [ dependencies = [
"enum-repr", "enum-repr",
"float-cmp", "float-cmp",
@ -3027,7 +3027,7 @@ dependencies = [
[[package]] [[package]]
name = "iced_style" name = "iced_style"
version = "0.12.0" version = "0.12.0"
source = "git+https://github.com/pop-os/libcosmic#756f4b6ba69d11075eb0c34ea0fc837bd27ad63a" source = "git+https://github.com/pop-os/libcosmic#4dd0f72f155b8705a30c2d42282f0bf1e5159e10"
dependencies = [ dependencies = [
"iced_core", "iced_core",
"once_cell", "once_cell",
@ -3037,7 +3037,7 @@ dependencies = [
[[package]] [[package]]
name = "iced_tiny_skia" name = "iced_tiny_skia"
version = "0.12.0" version = "0.12.0"
source = "git+https://github.com/pop-os/libcosmic#756f4b6ba69d11075eb0c34ea0fc837bd27ad63a" source = "git+https://github.com/pop-os/libcosmic#4dd0f72f155b8705a30c2d42282f0bf1e5159e10"
dependencies = [ dependencies = [
"bytemuck", "bytemuck",
"cosmic-text", "cosmic-text",
@ -3054,7 +3054,7 @@ dependencies = [
[[package]] [[package]]
name = "iced_wgpu" name = "iced_wgpu"
version = "0.12.0" version = "0.12.0"
source = "git+https://github.com/pop-os/libcosmic#756f4b6ba69d11075eb0c34ea0fc837bd27ad63a" source = "git+https://github.com/pop-os/libcosmic#4dd0f72f155b8705a30c2d42282f0bf1e5159e10"
dependencies = [ dependencies = [
"as-raw-xcb-connection", "as-raw-xcb-connection",
"bitflags 2.6.0", "bitflags 2.6.0",
@ -3083,7 +3083,7 @@ dependencies = [
[[package]] [[package]]
name = "iced_widget" name = "iced_widget"
version = "0.12.0" version = "0.12.0"
source = "git+https://github.com/pop-os/libcosmic#756f4b6ba69d11075eb0c34ea0fc837bd27ad63a" source = "git+https://github.com/pop-os/libcosmic#4dd0f72f155b8705a30c2d42282f0bf1e5159e10"
dependencies = [ dependencies = [
"dnd", "dnd",
"iced_renderer", "iced_renderer",
@ -3100,7 +3100,7 @@ dependencies = [
[[package]] [[package]]
name = "iced_winit" name = "iced_winit"
version = "0.12.0" version = "0.12.0"
source = "git+https://github.com/pop-os/libcosmic#756f4b6ba69d11075eb0c34ea0fc837bd27ad63a" source = "git+https://github.com/pop-os/libcosmic#4dd0f72f155b8705a30c2d42282f0bf1e5159e10"
dependencies = [ dependencies = [
"dnd", "dnd",
"iced_graphics", "iced_graphics",
@ -3907,7 +3907,7 @@ checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
[[package]] [[package]]
name = "libcosmic" name = "libcosmic"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/pop-os/libcosmic#756f4b6ba69d11075eb0c34ea0fc837bd27ad63a" source = "git+https://github.com/pop-os/libcosmic#4dd0f72f155b8705a30c2d42282f0bf1e5159e10"
dependencies = [ dependencies = [
"apply", "apply",
"ashpd 0.9.1", "ashpd 0.9.1",

View file

@ -308,7 +308,9 @@ impl cosmic::Application for SettingsApp {
} }
crate::pages::Message::DateAndTime(message) => { crate::pages::Message::DateAndTime(message) => {
page::update!(self.pages, message, time::date::Page); if let Some(page) = self.pages.page_mut::<time::date::Page>() {
return page.update(message).map(Into::into);
}
} }
crate::pages::Message::Desktop(message) => { crate::pages::Message::Desktop(message) => {

View file

@ -611,11 +611,11 @@ fn special_character_entry() -> Section<crate::pages::Message> {
let descriptions = &section.descriptions; let descriptions = &section.descriptions;
settings::view_section(&section.title) settings::view_section(&section.title)
.add(go_next_item( .add(crate::widget::go_next_item(
&*descriptions[alternate], &*descriptions[alternate],
Message::OpenSpecialCharacterContext(SpecialKey::AlternateCharacters), Message::OpenSpecialCharacterContext(SpecialKey::AlternateCharacters),
)) ))
.add(go_next_item( .add(crate::widget::go_next_item(
&*descriptions[compose], &*descriptions[compose],
Message::OpenSpecialCharacterContext(SpecialKey::Compose), Message::OpenSpecialCharacterContext(SpecialKey::Compose),
)) ))
@ -641,7 +641,7 @@ fn keyboard_shortcuts() -> Section<crate::pages::Message> {
.iter() .iter()
.find(|(_, v)| v.id == "keyboard-shortcuts") .find(|(_, v)| v.id == "keyboard-shortcuts")
{ {
section = section.add(go_next_item( section = section.add(crate::widget::go_next_item(
&descriptions[shortcuts_desc], &descriptions[shortcuts_desc],
crate::pages::Message::Page(shortcuts_entity), crate::pages::Message::Page(shortcuts_entity),
)); ));
@ -712,21 +712,3 @@ fn keyboard_typing_assist() -> Section<crate::pages::Message> {
.map(crate::pages::Message::Keyboard) .map(crate::pages::Message::Keyboard)
}) })
} }
fn go_next_control<Msg: Clone + 'static>() -> cosmic::Element<'static, Msg> {
widget::row::with_children(vec![
widget::horizontal_space(Length::Fill).into(),
icon::from_name("go-next-symbolic").size(16).icon().into(),
])
.into()
}
fn go_next_item<Msg: Clone + 'static>(description: &str, msg: Msg) -> cosmic::Element<'_, Msg> {
settings::item(description, go_next_control())
.apply(widget::container)
.style(cosmic::theme::Container::List)
.apply(button)
.style(theme::Button::Transparent)
.on_press(msg)
.into()
}

View file

@ -6,8 +6,10 @@ use std::str::FromStr;
use chrono::{Datelike, Timelike}; use chrono::{Datelike, Timelike};
use cosmic::{ use cosmic::{
cosmic_config::{self, ConfigGet, ConfigSet}, cosmic_config::{self, ConfigGet, ConfigSet},
iced::Length,
iced_core::text::Wrap,
widget::{self, dropdown, settings}, widget::{self, dropdown, settings},
Apply, Command, Apply, Command, Element,
}; };
use cosmic_settings_page::Section; use cosmic_settings_page::Section;
use cosmic_settings_page::{self as page, section}; use cosmic_settings_page::{self as page, section};
@ -16,6 +18,7 @@ use icu::{
datetime::DateTimeFormatter, datetime::DateTimeFormatter,
locid::Locale, locid::Locale,
}; };
use itertools::Itertools;
use slab::Slab; use slab::Slab;
use slotmap::SlotMap; use slotmap::SlotMap;
pub use timedate_zbus::TimeDateProxy; pub use timedate_zbus::TimeDateProxy;
@ -38,9 +41,11 @@ pub struct Page {
military_time: bool, military_time: bool,
ntp_enabled: bool, ntp_enabled: bool,
show_date_in_top_panel: bool, show_date_in_top_panel: bool,
timezone_context: bool,
local_time: Option<DateTime<Iso>>, local_time: Option<DateTime<Iso>>,
timezone: Option<usize>, timezone: Option<usize>,
timezone_list: Vec<String>, timezone_list: Vec<String>,
timezone_search: String,
formatted_date: String, formatted_date: String,
} }
@ -79,7 +84,9 @@ impl Default for Page {
ntp_enabled: false, ntp_enabled: false,
show_date_in_top_panel, show_date_in_top_panel,
timezone: None, timezone: None,
timezone_context: false,
timezone_list: Vec::new(), timezone_list: Vec::new(),
timezone_search: String::new(),
} }
} }
} }
@ -136,6 +143,14 @@ impl page::Page<crate::pages::Message> for Page {
}) })
.map(crate::pages::Message::DateAndTime) .map(crate::pages::Message::DateAndTime)
} }
fn context_drawer(&self) -> Option<Element<'_, crate::pages::Message>> {
if self.timezone_context {
return Some(self.timezone_context_view());
}
None
}
} }
impl Page { impl Page {
@ -165,6 +180,14 @@ impl Page {
}); });
} }
Message::TimezoneContext => {
self.timezone_search.clear();
self.timezone_context = true;
return cosmic::command::message(crate::app::Message::OpenContextDrawer(
fl!("time-zone").into(),
));
}
Message::MilitaryTime(enable) => { Message::MilitaryTime(enable) => {
self.military_time = enable; self.military_time = enable;
self.update_local_time(); self.update_local_time();
@ -193,6 +216,10 @@ impl Page {
} }
} }
Message::TimezoneSearch(text) => {
self.timezone_search = text;
}
Message::Timezone(timezone_id) => { Message::Timezone(timezone_id) => {
self.timezone = Some(timezone_id); self.timezone = Some(timezone_id);
@ -242,7 +269,40 @@ impl Page {
Command::none() Command::none()
} }
pub fn update_local_time(&mut self) { fn timezone_context_view(&self) -> Element<'_, crate::pages::Message> {
let search = widget::search_input(fl!("type-to-search"), &self.timezone_search)
.on_input(Message::TimezoneSearch)
.on_clear(Message::TimezoneSearch(String::new()));
let mut list = widget::list_column();
let search_input = &self.timezone_search.trim().to_lowercase();
for (id, timezone) in self.timezone_list.iter().enumerate() {
if search_input.is_empty() || timezone.to_lowercase().contains(search_input) {
list = list.add(self.timezone_context_item(id, timezone));
}
}
widget::column()
.spacing(32)
.push(search)
.push(widget::container(list).apply(widget::container))
.apply(Element::from)
.map(crate::pages::Message::DateAndTime)
}
fn timezone_context_item<'a>(&self, id: usize, timezone: &'a str) -> Element<'a, Message> {
widget::button(widget::settings::item_row(vec![
widget::text::body(timezone).wrap(Wrap::Word).into(),
widget::horizontal_space(Length::Fill).into(),
]))
.on_press(Message::Timezone(id))
.style(cosmic::theme::Button::Icon)
.into()
}
fn update_local_time(&mut self) {
self.local_time = Some(update_local_time()); self.local_time = Some(update_local_time());
self.formatted_date = match self.local_time { self.formatted_date = match self.local_time {
@ -262,6 +322,8 @@ pub enum Message {
Refresh(Info), Refresh(Info),
ShowDate(bool), ShowDate(bool),
Timezone(usize), Timezone(usize),
TimezoneContext,
TimezoneSearch(String),
UpdateTime, UpdateTime,
} }
@ -347,12 +409,30 @@ fn timezone() -> Section<crate::pages::Message> {
.title(fl!("time-zone")) .title(fl!("time-zone"))
.descriptions(descriptions) .descriptions(descriptions)
.view::<Page>(move |_binder, page, section| { .view::<Page>(move |_binder, page, section| {
let timezone_context_button = settings::item_row(vec![
widget::text(
page.timezone
.map(|id| &*page.timezone_list[id])
.unwrap_or_default(),
)
.wrap(Wrap::Word)
.into(),
widget::icon::from_name("go-next-symbolic")
.size(16)
.icon()
.into(),
])
.apply(widget::container)
.style(cosmic::theme::Container::List)
.apply(widget::button)
.style(cosmic::theme::Button::Transparent)
.on_press(Message::TimezoneContext);
settings::view_section(&section.title) settings::view_section(&section.title)
// Time zone select // Time zone select
.add( .add(
settings::item::builder(&*section.descriptions[time_zone]).control( settings::item::builder(&*section.descriptions[time_zone])
widget::dropdown(&page.timezone_list, page.timezone, Message::Timezone), .control(timezone_context_button),
),
) )
.apply(cosmic::Element::from) .apply(cosmic::Element::from)
.map(crate::pages::Message::DateAndTime) .map(crate::pages::Message::DateAndTime)

View file

@ -2,8 +2,10 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
use cosmic::iced::Length; use cosmic::iced::Length;
use cosmic::iced_core::text::Wrap;
use cosmic::widget::{ use cosmic::widget::{
button, column, container, divider, horizontal_space, icon, row, settings, text, vertical_space, self, button, column, container, divider, horizontal_space, icon, row, settings, text,
vertical_space,
}; };
use cosmic::{theme, Apply, Element}; use cosmic::{theme, Apply, Element};
use cosmic_settings_page as page; use cosmic_settings_page as page;
@ -120,3 +122,17 @@ pub fn sub_page_header<'a, Message: 'static + Clone>(
.width(Length::Shrink) .width(Length::Shrink)
.into() .into()
} }
pub fn go_next_item<Msg: Clone + 'static>(description: &str, msg: Msg) -> cosmic::Element<'_, Msg> {
settings::item_row(vec![
text(description).wrap(Wrap::Word).into(),
horizontal_space(Length::Fill).into(),
icon::from_name("go-next-symbolic").size(16).icon().into(),
])
.apply(widget::container)
.style(cosmic::theme::Container::List)
.apply(button)
.style(theme::Button::Transparent)
.on_press(msg)
.into()
}