feat(region): update datetime formatting on region change
Update military_time and first_day_of_week on region change to be of what is preferred in the region
This commit is contained in:
parent
836c1b09ba
commit
ce6158f6df
1 changed files with 104 additions and 28 deletions
|
|
@ -17,11 +17,15 @@ use cosmic_settings_page::{self as page, section};
|
||||||
use eyre::Context;
|
use eyre::Context;
|
||||||
use fixed_decimal::FixedDecimal;
|
use fixed_decimal::FixedDecimal;
|
||||||
use icu::calendar::DateTime;
|
use icu::calendar::DateTime;
|
||||||
use icu::datetime::DateTimeFormatter;
|
|
||||||
use icu::datetime::options::components::{self, Bag};
|
use icu::datetime::options::components::{self, Bag};
|
||||||
use icu::datetime::options::preferences;
|
use icu::datetime::options::length;
|
||||||
|
use icu::datetime::{DateTimeFormatter, DateTimeFormatterOptions};
|
||||||
use icu::decimal::FixedDecimalFormatter;
|
use icu::decimal::FixedDecimalFormatter;
|
||||||
use icu::decimal::options::FixedDecimalFormatterOptions;
|
use icu::decimal::options::FixedDecimalFormatterOptions;
|
||||||
|
use icu::{
|
||||||
|
calendar::{types::IsoWeekday, week},
|
||||||
|
locid::Locale,
|
||||||
|
};
|
||||||
use locales_rs as locale;
|
use locales_rs as locale;
|
||||||
use slotmap::{DefaultKey, SlotMap};
|
use slotmap::{DefaultKey, SlotMap};
|
||||||
|
|
||||||
|
|
@ -231,7 +235,10 @@ impl Page {
|
||||||
let region = region.lang_code.clone();
|
let region = region.lang_code.clone();
|
||||||
|
|
||||||
return cosmic::task::future(async move {
|
return cosmic::task::future(async move {
|
||||||
_ = set_locale(lang, region).await;
|
_ = set_locale(lang, region.clone()).await;
|
||||||
|
|
||||||
|
update_time_settings_after_region_change(region);
|
||||||
|
|
||||||
Message::Refresh(Arc::new(page_reload().await))
|
Message::Refresh(Arc::new(page_reload().await))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -439,23 +446,12 @@ impl Page {
|
||||||
return String::new();
|
return String::new();
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut bag = Bag::empty();
|
let bag = length::Bag::from_date_time_style(length::Date::Long, length::Time::Medium);
|
||||||
bag.hour = Some(components::Numeric::Numeric);
|
let options = DateTimeFormatterOptions::Length(bag);
|
||||||
bag.minute = Some(components::Numeric::Numeric);
|
|
||||||
bag.second = Some(components::Numeric::Numeric);
|
|
||||||
bag.preferences = Some(preferences::Bag::from_hour_cycle(
|
|
||||||
preferences::HourCycle::H12,
|
|
||||||
));
|
|
||||||
// bag.time_zone_name = Some(components::TimeZoneName::ShortSpecific);
|
|
||||||
bag.day = Some(components::Day::TwoDigitDayOfMonth);
|
|
||||||
bag.month = Some(components::Month::Short);
|
|
||||||
bag.year = Some(components::Year::Numeric);
|
|
||||||
|
|
||||||
let options = icu::datetime::DateTimeFormatterOptions::Components(bag);
|
|
||||||
|
|
||||||
let dtf = DateTimeFormatter::try_new_experimental(&locale.into(), options).unwrap();
|
let dtf = DateTimeFormatter::try_new_experimental(&locale.into(), options).unwrap();
|
||||||
|
|
||||||
let datetime = DateTime::try_new_gregorian_datetime(1776, 7, 4, 12, 0, 0)
|
let datetime = DateTime::try_new_gregorian_datetime(1776, 7, 4, 13, 0, 0)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_iso()
|
.to_iso()
|
||||||
.to_any();
|
.to_any();
|
||||||
|
|
@ -479,19 +475,11 @@ impl Page {
|
||||||
return String::new();
|
return String::new();
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut bag = Bag::empty();
|
let options = length::Bag::from_time_style(length::Time::Medium);
|
||||||
bag.hour = Some(components::Numeric::Numeric);
|
|
||||||
bag.minute = Some(components::Numeric::Numeric);
|
|
||||||
bag.second = Some(components::Numeric::Numeric);
|
|
||||||
bag.preferences = Some(preferences::Bag::from_hour_cycle(
|
|
||||||
preferences::HourCycle::H12,
|
|
||||||
));
|
|
||||||
|
|
||||||
let options = icu::datetime::DateTimeFormatterOptions::Components(bag);
|
let dtf = DateTimeFormatter::try_new_experimental(&locale.into(), options.into()).unwrap();
|
||||||
|
|
||||||
let dtf = DateTimeFormatter::try_new_experimental(&locale.into(), options).unwrap();
|
let datetime = DateTime::try_new_gregorian_datetime(1776, 7, 4, 13, 0, 0)
|
||||||
|
|
||||||
let datetime = DateTime::try_new_gregorian_datetime(1776, 7, 4, 12, 0, 0)
|
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_iso()
|
.to_iso()
|
||||||
.to_any();
|
.to_any();
|
||||||
|
|
@ -963,3 +951,91 @@ pub async fn set_locale(lang: String, region: String) {
|
||||||
.status()
|
.status()
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_locale(locale: String) -> Result<Locale, Box<dyn std::error::Error>> {
|
||||||
|
let locale = locale
|
||||||
|
.split('.')
|
||||||
|
.next()
|
||||||
|
.ok_or(format!("Can't split the locale {locale}"))?;
|
||||||
|
|
||||||
|
let locale = Locale::from_str(locale).map_err(|e| format!("{e:?}"))?;
|
||||||
|
Ok(locale)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_default_24h(locale: String) -> bool {
|
||||||
|
let Ok(locale) = parse_locale(locale) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
let test_time = icu::calendar::DateTime::try_new_gregorian_datetime(2024, 1, 1, 13, 0, 0)
|
||||||
|
.unwrap()
|
||||||
|
.to_iso();
|
||||||
|
|
||||||
|
let bag = icu::datetime::options::length::Bag::from_time_style(
|
||||||
|
icu::datetime::options::length::Time::Medium,
|
||||||
|
);
|
||||||
|
|
||||||
|
let Ok(dtf) =
|
||||||
|
icu::datetime::DateTimeFormatter::try_new_experimental(&locale.into(), bag.into())
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
let formatted = match dtf.format(&test_time.to_any()) {
|
||||||
|
Ok(formatted) => formatted.to_string(),
|
||||||
|
Err(_) => return false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// If we see "13" in the output, it's 24-hour format
|
||||||
|
// If we see "1" (but not "13"), it's 12-hour format
|
||||||
|
formatted.contains("13")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_default_first_day(locale: String) -> usize {
|
||||||
|
let Ok(locale) = parse_locale(locale) else {
|
||||||
|
return 6;
|
||||||
|
};
|
||||||
|
let Ok(week_calc) = week::WeekCalculator::try_new(&locale.into()) else {
|
||||||
|
return 6;
|
||||||
|
};
|
||||||
|
|
||||||
|
match week_calc.first_weekday {
|
||||||
|
IsoWeekday::Monday => 0,
|
||||||
|
IsoWeekday::Tuesday => 1,
|
||||||
|
IsoWeekday::Wednesday => 2,
|
||||||
|
IsoWeekday::Thursday => 3,
|
||||||
|
IsoWeekday::Friday => 4,
|
||||||
|
IsoWeekday::Saturday => 5,
|
||||||
|
IsoWeekday::Sunday => 6,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_time_settings_after_region_change(region: String) {
|
||||||
|
// Create the same config that date.rs uses
|
||||||
|
let cosmic_applet_config = match cosmic_config::Config::new("com.system76.CosmicAppletTime", 1)
|
||||||
|
{
|
||||||
|
Ok(config) => config,
|
||||||
|
Err(err) => {
|
||||||
|
tracing::error!(
|
||||||
|
?err,
|
||||||
|
"Failed to create cosmic applet config for time settings"
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update military_time based on new locale
|
||||||
|
let new_military_time = get_default_24h(region.clone());
|
||||||
|
if let Err(why) = cosmic_applet_config.set("military_time", new_military_time) {
|
||||||
|
tracing::error!(?why, "Failed to update military_time after region change");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update first_day_of_week based on new locale
|
||||||
|
let new_first_day = get_default_first_day(region);
|
||||||
|
if let Err(why) = cosmic_applet_config.set("first_day_of_week", new_first_day) {
|
||||||
|
tracing::error!(
|
||||||
|
?why,
|
||||||
|
"Failed to update first_day_of_week after region change"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue