feat: memorize last active page between instances
This commit is contained in:
parent
2709dcfee5
commit
9d3c3405a2
23 changed files with 252 additions and 87 deletions
84
Cargo.lock
generated
84
Cargo.lock
generated
|
|
@ -179,6 +179,27 @@ version = "3.12.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535"
|
checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bytecheck"
|
||||||
|
version = "0.6.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d11cac2c12b5adc6570dad2ee1b87eff4955dac476fe12d81e5fdd352e52406f"
|
||||||
|
dependencies = [
|
||||||
|
"bytecheck_derive",
|
||||||
|
"ptr_meta",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bytecheck_derive"
|
||||||
|
version = "0.6.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "13e576ebe98e605500b3c8041bb888e966653577172df6dd97398714eb30b9bf"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytemuck"
|
name = "bytemuck"
|
||||||
version = "1.13.0"
|
version = "1.13.0"
|
||||||
|
|
@ -397,12 +418,15 @@ name = "cosmic-settings"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"apply",
|
"apply",
|
||||||
|
"bytecheck",
|
||||||
"derive_setters",
|
"derive_setters",
|
||||||
|
"dirs",
|
||||||
"i18n-embed",
|
"i18n-embed",
|
||||||
"i18n-embed-fl",
|
"i18n-embed-fl",
|
||||||
"libcosmic",
|
"libcosmic",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"regex",
|
"regex",
|
||||||
|
"rkyv",
|
||||||
"rust-embed",
|
"rust-embed",
|
||||||
"slotmap",
|
"slotmap",
|
||||||
]
|
]
|
||||||
|
|
@ -2545,6 +2569,26 @@ version = "1.0.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "74605f360ce573babfe43964cbe520294dcb081afbf8c108fc6e23036b4da2df"
|
checksum = "74605f360ce573babfe43964cbe520294dcb081afbf8c108fc6e23036b4da2df"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ptr_meta"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1"
|
||||||
|
dependencies = [
|
||||||
|
"ptr_meta_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ptr_meta_derive"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quick-xml"
|
name = "quick-xml"
|
||||||
version = "0.23.1"
|
version = "0.23.1"
|
||||||
|
|
@ -2719,6 +2763,15 @@ version = "0.6.28"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
|
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rend"
|
||||||
|
version = "0.3.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "79af64b4b6362ffba04eef3a4e10829718a4896dac19daa741851c86781edf95"
|
||||||
|
dependencies = [
|
||||||
|
"bytecheck",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "renderdoc-sys"
|
name = "renderdoc-sys"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
|
|
@ -2750,6 +2803,31 @@ dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rkyv"
|
||||||
|
version = "0.7.39"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cec2b3485b07d96ddfd3134767b8a447b45ea4eb91448d0a35180ec0ffd5ed15"
|
||||||
|
dependencies = [
|
||||||
|
"bytecheck",
|
||||||
|
"hashbrown",
|
||||||
|
"ptr_meta",
|
||||||
|
"rend",
|
||||||
|
"rkyv_derive",
|
||||||
|
"seahash",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rkyv_derive"
|
||||||
|
version = "0.7.39"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6eaedadc88b53e36dd32d940ed21ae4d850d5916f2581526921f553a72ac34c4"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ron"
|
name = "ron"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
|
|
@ -2901,6 +2979,12 @@ dependencies = [
|
||||||
"tiny-skia 0.7.0",
|
"tiny-skia 0.7.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "seahash"
|
||||||
|
version = "4.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "self_cell"
|
name = "self_cell"
|
||||||
version = "0.10.2"
|
version = "0.10.2"
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,9 @@ once_cell = "1.17.0"
|
||||||
regex = "1.7.1"
|
regex = "1.7.1"
|
||||||
rust-embed = "6.4.2"
|
rust-embed = "6.4.2"
|
||||||
slotmap = "1.0.6"
|
slotmap = "1.0.6"
|
||||||
|
dirs = "4.0.0"
|
||||||
|
rkyv = { version = "0.7.39", features = ["validation"]}
|
||||||
|
bytecheck = "0.6.9"
|
||||||
|
|
||||||
[dependencies.i18n-embed]
|
[dependencies.i18n-embed]
|
||||||
version = "0.13.8"
|
version = "0.13.8"
|
||||||
|
|
@ -22,4 +25,4 @@ features = ["fluent-system", "desktop-requester"]
|
||||||
git = "https://github.com/pop-os/libcosmic"
|
git = "https://github.com/pop-os/libcosmic"
|
||||||
branch = "settings-improv"
|
branch = "settings-improv"
|
||||||
default-features = false
|
default-features = false
|
||||||
features = ["debug", "winit", "dyrend"]
|
features = ["debug", "winit", "dyrend"]
|
||||||
|
|
|
||||||
33
src/app.rs
33
src/app.rs
|
|
@ -18,6 +18,7 @@ use cosmic::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
config::{self, Config},
|
||||||
page::{self, desktop, section, sound, system, time, Page},
|
page::{self, desktop, section, sound, system, time, Page},
|
||||||
widget::{page_title, parent_page_button, search_header, sub_page_button},
|
widget::{page_title, parent_page_button, search_header, sub_page_button},
|
||||||
};
|
};
|
||||||
|
|
@ -27,6 +28,7 @@ use crate::{
|
||||||
pub struct SettingsApp {
|
pub struct SettingsApp {
|
||||||
pub active_page: page::Entity,
|
pub active_page: page::Entity,
|
||||||
pub config: Config,
|
pub config: Config,
|
||||||
|
pub config_path: config::PathManager,
|
||||||
pub debug: bool,
|
pub debug: bool,
|
||||||
pub is_condensed: bool,
|
pub is_condensed: bool,
|
||||||
pub nav_bar_toggled_condensed: bool,
|
pub nav_bar_toggled_condensed: bool,
|
||||||
|
|
@ -43,11 +45,6 @@ pub struct SettingsApp {
|
||||||
pub window_width: u32,
|
pub window_width: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
|
||||||
pub struct Config {
|
|
||||||
nav_page: &'static str,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Message {
|
pub enum Message {
|
||||||
|
|
@ -73,11 +70,12 @@ impl Application for SettingsApp {
|
||||||
type Theme = Theme;
|
type Theme = Theme;
|
||||||
|
|
||||||
fn new(_flags: ()) -> (Self, Command<Self::Message>) {
|
fn new(_flags: ()) -> (Self, Command<Self::Message>) {
|
||||||
|
let mut config_path = config::PathManager::new();
|
||||||
|
|
||||||
let mut app = SettingsApp {
|
let mut app = SettingsApp {
|
||||||
active_page: page::Entity::default(),
|
active_page: page::Entity::default(),
|
||||||
config: Config {
|
config: config_path.config("main", Config::deserialize),
|
||||||
nav_page: "desktop",
|
config_path,
|
||||||
},
|
|
||||||
debug: false,
|
debug: false,
|
||||||
is_condensed: false,
|
is_condensed: false,
|
||||||
nav_bar: segmented_button::Model::default(),
|
nav_bar: segmented_button::Model::default(),
|
||||||
|
|
@ -119,7 +117,12 @@ impl Application for SettingsApp {
|
||||||
// app.insert_page::<accessibility::Page>();
|
// app.insert_page::<accessibility::Page>();
|
||||||
// app.insert_page::<applications::Page>();
|
// app.insert_page::<applications::Page>();
|
||||||
|
|
||||||
app.activate_navbar(app.active_page);
|
for (id, info) in app.pages.pages.iter() {
|
||||||
|
if info.id == &*app.config.active_page {
|
||||||
|
app.activate_page(id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
(app, Command::none())
|
(app, Command::none())
|
||||||
}
|
}
|
||||||
|
|
@ -299,8 +302,15 @@ impl SettingsApp {
|
||||||
/// Activates a page.
|
/// Activates a page.
|
||||||
fn activate_page(&mut self, page: page::Entity) {
|
fn activate_page(&mut self, page: page::Entity) {
|
||||||
self.nav_bar_toggled_condensed = false;
|
self.nav_bar_toggled_condensed = false;
|
||||||
|
let current_page = self.active_page;
|
||||||
self.active_page = page;
|
self.active_page = page;
|
||||||
|
|
||||||
|
if current_page != page {
|
||||||
|
self.config.active_page = Box::from(self.pages.pages[page].id);
|
||||||
|
self.config_path
|
||||||
|
.config("main", |path| self.config.serialize(path));
|
||||||
|
}
|
||||||
|
|
||||||
self.search_clear();
|
self.search_clear();
|
||||||
self.search.state = search::State::Inactive;
|
self.search.state = search::State::Inactive;
|
||||||
self.activate_navbar(page);
|
self.activate_navbar(page);
|
||||||
|
|
@ -320,13 +330,8 @@ impl SettingsApp {
|
||||||
/// Adds a main page to the settings application.
|
/// Adds a main page to the settings application.
|
||||||
fn insert_page<P: Page>(&mut self) -> page::Insert {
|
fn insert_page<P: Page>(&mut self) -> page::Insert {
|
||||||
let id = self.pages.register::<P>().id();
|
let id = self.pages.register::<P>().id();
|
||||||
|
|
||||||
self.navbar_insert(id);
|
self.navbar_insert(id);
|
||||||
|
|
||||||
if P::PERSISTENT_ID == self.config.nav_page {
|
|
||||||
self.active_page = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
page::Insert {
|
page::Insert {
|
||||||
model: &mut self.pages,
|
model: &mut self.pages,
|
||||||
id,
|
id,
|
||||||
|
|
|
||||||
100
src/config.rs
Normal file
100
src/config.rs
Normal file
|
|
@ -0,0 +1,100 @@
|
||||||
|
// Copyright 2023 System76 <info@system76.com>
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
|
mod path {
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
|
||||||
|
pub struct Manager {
|
||||||
|
base: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Manager {
|
||||||
|
#[allow(clippy::new_without_default)]
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let mut base = dirs::config_dir()
|
||||||
|
.expect("XDG config directory missing")
|
||||||
|
.join("cosmic-settings")
|
||||||
|
.into_os_string()
|
||||||
|
.into_string()
|
||||||
|
.expect("XDG config path is not UTF-8");
|
||||||
|
|
||||||
|
base.push('/');
|
||||||
|
|
||||||
|
if !Path::new(&base).exists() {
|
||||||
|
let _res = std::fs::create_dir_all(&base);
|
||||||
|
}
|
||||||
|
|
||||||
|
Self { base }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn config<T>(&mut self, page: &str, with: impl Fn(&Path) -> T) -> T {
|
||||||
|
let truncate_length = self.base.len();
|
||||||
|
|
||||||
|
self.base.push_str(page);
|
||||||
|
self.base.push_str(".config");
|
||||||
|
|
||||||
|
let output = with(Path::new(&self.base));
|
||||||
|
self.base.truncate(truncate_length);
|
||||||
|
output
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use path::Manager as PathManager;
|
||||||
|
|
||||||
|
use bytecheck::CheckBytes;
|
||||||
|
use rkyv::{ser::Serializer, Archive, Deserialize, Serialize};
|
||||||
|
use std::{io::Read, path::Path};
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Archive, Debug, Deserialize, Serialize)]
|
||||||
|
#[archive_attr(derive(CheckBytes, Debug))]
|
||||||
|
pub struct Config {
|
||||||
|
pub active_page: Box<str>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Config {
|
||||||
|
pub fn deserialize(path: &Path) -> Self {
|
||||||
|
let Ok(mut file) = std::fs::File::open(path) else {
|
||||||
|
return Self::default();
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut buffer = Vec::with_capacity(128);
|
||||||
|
if file.read_to_end(&mut buffer).is_err() {
|
||||||
|
return Self::default();
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.shrink_to_fit();
|
||||||
|
|
||||||
|
let Ok(archived) = rkyv::check_archived_root::<Self>(buffer.as_slice()) else {
|
||||||
|
return Self::default();
|
||||||
|
};
|
||||||
|
|
||||||
|
archived
|
||||||
|
.deserialize(&mut rkyv::Infallible)
|
||||||
|
.unwrap_or_default()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn serialize(&self, path: &Path) {
|
||||||
|
let mut serializer = rkyv::ser::serializers::AllocSerializer::<0>::default();
|
||||||
|
|
||||||
|
if serializer.serialize_value(self).is_err() {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let bytes = serializer.into_serializer().into_inner();
|
||||||
|
|
||||||
|
let _res = std::fs::write(path, &bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Config {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
active_page: Box::from("desktop"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -9,6 +9,8 @@
|
||||||
pub mod app;
|
pub mod app;
|
||||||
pub use app::{Message, SettingsApp};
|
pub use app::{Message, SettingsApp};
|
||||||
|
|
||||||
|
pub mod config;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod localize;
|
pub mod localize;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,10 @@ pub struct Page;
|
||||||
impl page::Page for Page {
|
impl page::Page for Page {
|
||||||
type Model = super::Model;
|
type Model = super::Model;
|
||||||
|
|
||||||
const PERSISTENT_ID: &'static str = "appearance";
|
|
||||||
|
|
||||||
fn page() -> page::Meta {
|
fn page() -> page::Meta {
|
||||||
page::Meta::default()
|
page::Meta::new("appearance", "preferences-pop-desktop-appearance-symbolic")
|
||||||
.title(fl!("appearance"))
|
.title(fl!("appearance"))
|
||||||
.description(fl!("appearance", "desc"))
|
.description(fl!("appearance", "desc"))
|
||||||
.icon_name("preferences-pop-desktop-appearance-symbolic")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn content(sections: &mut SlotMap<section::Entity, Section>) -> Option<Content> {
|
fn content(sections: &mut SlotMap<section::Entity, Section>) -> Option<Content> {
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,10 @@ pub struct Page;
|
||||||
impl page::Page for Page {
|
impl page::Page for Page {
|
||||||
type Model = super::Model;
|
type Model = super::Model;
|
||||||
|
|
||||||
const PERSISTENT_ID: &'static str = "dock";
|
|
||||||
|
|
||||||
fn page() -> page::Meta {
|
fn page() -> page::Meta {
|
||||||
page::Meta::default()
|
page::Meta::new("dock", "preferences-pop-desktop-dock-symbolic")
|
||||||
.title(fl!("dock"))
|
.title(fl!("dock"))
|
||||||
.description(fl!("dock", "desc"))
|
.description(fl!("dock", "desc"))
|
||||||
.icon_name("preferences-pop-desktop-dock-symbolic")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn content(sections: &mut SlotMap<section::Entity, Section>) -> Option<Content> {
|
fn content(sections: &mut SlotMap<section::Entity, Section>) -> Option<Content> {
|
||||||
|
|
|
||||||
|
|
@ -15,12 +15,8 @@ pub struct Page;
|
||||||
impl page::Page for Page {
|
impl page::Page for Page {
|
||||||
type Model = super::Model;
|
type Model = super::Model;
|
||||||
|
|
||||||
const PERSISTENT_ID: &'static str = "desktop";
|
|
||||||
|
|
||||||
fn page() -> page::Meta {
|
fn page() -> page::Meta {
|
||||||
page::Meta::default()
|
page::Meta::new("desktop", "video-display-symbolic").title(fl!("desktop"))
|
||||||
.title(fl!("desktop"))
|
|
||||||
.icon_name("video-display-symbolic")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sub_pages(page: page::Insert) -> page::Insert {
|
fn sub_pages(page: page::Insert) -> page::Insert {
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,10 @@ pub struct Page;
|
||||||
impl page::Page for Page {
|
impl page::Page for Page {
|
||||||
type Model = super::Model;
|
type Model = super::Model;
|
||||||
|
|
||||||
const PERSISTENT_ID: &'static str = "notifications";
|
|
||||||
|
|
||||||
fn page() -> page::Meta {
|
fn page() -> page::Meta {
|
||||||
page::Meta::default()
|
page::Meta::new("notifications", "preferences-system-notifications-symbolic")
|
||||||
.title(fl!("notifications"))
|
.title(fl!("notifications"))
|
||||||
.description(fl!("notifications", "desc"))
|
.description(fl!("notifications", "desc"))
|
||||||
.icon_name("preferences-system-notifications-symbolic")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn content(sections: &mut SlotMap<section::Entity, Section>) -> Option<Content> {
|
fn content(sections: &mut SlotMap<section::Entity, Section>) -> Option<Content> {
|
||||||
|
|
|
||||||
|
|
@ -19,13 +19,10 @@ pub struct Page;
|
||||||
impl page::Page for Page {
|
impl page::Page for Page {
|
||||||
type Model = super::Model;
|
type Model = super::Model;
|
||||||
|
|
||||||
const PERSISTENT_ID: &'static str = "desktop-options";
|
|
||||||
|
|
||||||
fn page() -> page::Meta {
|
fn page() -> page::Meta {
|
||||||
page::Meta::default()
|
page::Meta::new("desktop-options", "video-display-symbolic")
|
||||||
.title(fl!("desktop-options"))
|
.title(fl!("desktop-options"))
|
||||||
.description(fl!("desktop-options", "desc"))
|
.description(fl!("desktop-options", "desc"))
|
||||||
.icon_name("video-display-symbolic")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_lines)]
|
#[allow(clippy::too_many_lines)]
|
||||||
|
|
|
||||||
|
|
@ -19,13 +19,10 @@ pub struct Page;
|
||||||
impl page::Page for Page {
|
impl page::Page for Page {
|
||||||
type Model = super::Model;
|
type Model = super::Model;
|
||||||
|
|
||||||
const PERSISTENT_ID: &'static str = "wallpaper";
|
|
||||||
|
|
||||||
fn page() -> page::Meta {
|
fn page() -> page::Meta {
|
||||||
page::Meta::default()
|
page::Meta::new("wallpaper", "preferences-desktop-wallpaper-symbolic")
|
||||||
.title(fl!("wallpaper"))
|
.title(fl!("wallpaper"))
|
||||||
.description(fl!("wallpaper", "desc"))
|
.description(fl!("wallpaper", "desc"))
|
||||||
.icon_name("preferences-desktop-wallpaper-symbolic")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn content(sections: &mut SlotMap<section::Entity, Section>) -> Option<Content> {
|
fn content(sections: &mut SlotMap<section::Entity, Section>) -> Option<Content> {
|
||||||
|
|
|
||||||
|
|
@ -12,13 +12,10 @@ pub struct Page;
|
||||||
impl page::Page for Page {
|
impl page::Page for Page {
|
||||||
type Model = super::Model;
|
type Model = super::Model;
|
||||||
|
|
||||||
const PERSISTENT_ID: &'static str = "workspaces";
|
|
||||||
|
|
||||||
fn page() -> page::Meta {
|
fn page() -> page::Meta {
|
||||||
page::Meta::default()
|
page::Meta::new("workspaces", "preferences-pop-desktop-workspaces-symbolic")
|
||||||
.title(fl!("workspaces"))
|
.title(fl!("workspaces"))
|
||||||
.description(fl!("workspaces", "desc"))
|
.description(fl!("workspaces", "desc"))
|
||||||
.icon_name("preferences-pop-desktop-workspaces-symbolic")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn content(sections: &mut SlotMap<section::Entity, Section>) -> Option<Content> {
|
fn content(sections: &mut SlotMap<section::Entity, Section>) -> Option<Content> {
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,6 @@ slotmap::new_key_type! {
|
||||||
pub trait Page {
|
pub trait Page {
|
||||||
type Model: Default + 'static;
|
type Model: Default + 'static;
|
||||||
|
|
||||||
/// A unique identity that is the same between application runs.
|
|
||||||
const PERSISTENT_ID: &'static str;
|
|
||||||
|
|
||||||
fn page() -> Meta;
|
fn page() -> Meta;
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
|
@ -41,17 +38,40 @@ pub trait Page {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Setters)]
|
#[derive(Setters)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub struct Meta {
|
pub struct Meta {
|
||||||
|
/// A unique identity that is the same between application runs.
|
||||||
|
#[setters(skip)]
|
||||||
|
pub id: &'static str,
|
||||||
|
|
||||||
|
/// The icon associated with the page.
|
||||||
|
#[setters(skip)]
|
||||||
|
pub icon_name: &'static str,
|
||||||
|
|
||||||
|
/// The title of the page.
|
||||||
#[setters(into)]
|
#[setters(into)]
|
||||||
pub title: String,
|
pub title: String,
|
||||||
#[setters(into)]
|
|
||||||
pub icon_name: &'static str,
|
/// A description of the page.
|
||||||
#[setters(into)]
|
#[setters(into)]
|
||||||
pub description: String,
|
pub description: String,
|
||||||
|
|
||||||
|
/// The parent of the page.
|
||||||
#[setters(strip_option)]
|
#[setters(strip_option)]
|
||||||
pub parent: Option<Entity>,
|
pub parent: Option<Entity>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Meta {
|
||||||
|
pub const fn new(id: &'static str, icon_name: &'static str) -> Self {
|
||||||
|
Self {
|
||||||
|
title: String::new(),
|
||||||
|
icon_name,
|
||||||
|
id,
|
||||||
|
description: String::new(),
|
||||||
|
parent: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub type Content = Vec<section::Entity>;
|
pub type Content = Vec<section::Entity>;
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,7 @@
|
||||||
use crate::page;
|
use crate::page;
|
||||||
|
|
||||||
pub fn page() -> page::Meta {
|
pub fn page() -> page::Meta {
|
||||||
page::Meta::default()
|
page::Meta::new("online-accounts", "goa-panel-symbolic")
|
||||||
.title(fl!("online-accounts"))
|
.title(fl!("online-accounts"))
|
||||||
.description(fl!("online-accounts", "desc"))
|
.description(fl!("online-accounts", "desc"))
|
||||||
.icon_name("goa-panel-symbolic")
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,7 @@
|
||||||
use crate::page;
|
use crate::page;
|
||||||
|
|
||||||
pub fn page() -> page::Meta {
|
pub fn page() -> page::Meta {
|
||||||
page::Meta::default()
|
page::Meta::new("wired", "network-workgroup-symbolic")
|
||||||
.title(fl!("wired"))
|
.title(fl!("wired"))
|
||||||
.description(fl!("wired", "desc"))
|
.description(fl!("wired", "desc"))
|
||||||
.icon_name("network-workgroup-symbolic")
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,13 +15,10 @@ pub struct Page;
|
||||||
impl page::Page for Page {
|
impl page::Page for Page {
|
||||||
type Model = Sound;
|
type Model = Sound;
|
||||||
|
|
||||||
const PERSISTENT_ID: &'static str = "sound";
|
|
||||||
|
|
||||||
fn page() -> page::Meta {
|
fn page() -> page::Meta {
|
||||||
page::Meta::default()
|
page::Meta::new("sound", "multimedia-volume-control-symbolic")
|
||||||
.title(fl!("sound"))
|
.title(fl!("sound"))
|
||||||
.description(fl!("sound", "desc"))
|
.description(fl!("sound", "desc"))
|
||||||
.icon_name("multimedia-volume-control-symbolic")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn content(sections: &mut SlotMap<section::Entity, Section>) -> Option<Content> {
|
fn content(sections: &mut SlotMap<section::Entity, Section>) -> Option<Content> {
|
||||||
|
|
|
||||||
|
|
@ -16,13 +16,10 @@ pub struct Page;
|
||||||
impl page::Page for Page {
|
impl page::Page for Page {
|
||||||
type Model = super::Model;
|
type Model = super::Model;
|
||||||
|
|
||||||
const PERSISTENT_ID: &'static str = "about";
|
|
||||||
|
|
||||||
fn page() -> page::Meta {
|
fn page() -> page::Meta {
|
||||||
page::Meta::default()
|
page::Meta::new("about", "help-about-symbolic")
|
||||||
.title(fl!("about"))
|
.title(fl!("about"))
|
||||||
.description(fl!("about", "desc"))
|
.description(fl!("about", "desc"))
|
||||||
.icon_name("help-about-symbolic")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn content(sections: &mut SlotMap<page::section::Entity, Section>) -> Option<Content> {
|
fn content(sections: &mut SlotMap<page::section::Entity, Section>) -> Option<Content> {
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,10 @@ pub struct Page;
|
||||||
impl page::Page for Page {
|
impl page::Page for Page {
|
||||||
type Model = super::Model;
|
type Model = super::Model;
|
||||||
|
|
||||||
const PERSISTENT_ID: &'static str = "firmware";
|
|
||||||
|
|
||||||
fn page() -> page::Meta {
|
fn page() -> page::Meta {
|
||||||
page::Meta::default()
|
page::Meta::new("firmware", "firmware-manager-symbolic")
|
||||||
.title(fl!("firmware"))
|
.title(fl!("firmware"))
|
||||||
.description(fl!("firmware", "desc"))
|
.description(fl!("firmware", "desc"))
|
||||||
.icon_name("firmware-manager-symbolic")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn content(sections: &mut SlotMap<section::Entity, Section>) -> Option<Content> {
|
fn content(sections: &mut SlotMap<section::Entity, Section>) -> Option<Content> {
|
||||||
|
|
|
||||||
|
|
@ -12,12 +12,8 @@ pub struct Page;
|
||||||
impl page::Page for Page {
|
impl page::Page for Page {
|
||||||
type Model = Model;
|
type Model = Model;
|
||||||
|
|
||||||
const PERSISTENT_ID: &'static str = "system";
|
|
||||||
|
|
||||||
fn page() -> page::Meta {
|
fn page() -> page::Meta {
|
||||||
page::Meta::default()
|
page::Meta::new("system", "system-users-symbolic").title(fl!("system"))
|
||||||
.title(fl!("system"))
|
|
||||||
.icon_name("system-users-symbolic")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sub_pages(page: page::Insert) -> page::Insert {
|
fn sub_pages(page: page::Insert) -> page::Insert {
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,10 @@ pub struct Page;
|
||||||
impl page::Page for Page {
|
impl page::Page for Page {
|
||||||
type Model = super::Model;
|
type Model = super::Model;
|
||||||
|
|
||||||
const PERSISTENT_ID: &'static str = "users";
|
|
||||||
|
|
||||||
fn page() -> page::Meta {
|
fn page() -> page::Meta {
|
||||||
page::Meta::default()
|
page::Meta::new("users", "system-users-symbolic")
|
||||||
.title(fl!("users"))
|
.title(fl!("users"))
|
||||||
.description(fl!("users", "desc"))
|
.description(fl!("users", "desc"))
|
||||||
.icon_name("system-users-symbolic")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn content(sections: &mut SlotMap<section::Entity, Section>) -> Option<Content> {
|
fn content(sections: &mut SlotMap<section::Entity, Section>) -> Option<Content> {
|
||||||
|
|
|
||||||
|
|
@ -38,13 +38,10 @@ pub struct Page;
|
||||||
impl page::Page for Page {
|
impl page::Page for Page {
|
||||||
type Model = Model;
|
type Model = Model;
|
||||||
|
|
||||||
const PERSISTENT_ID: &'static str = "time-date";
|
|
||||||
|
|
||||||
fn page() -> page::Meta {
|
fn page() -> page::Meta {
|
||||||
page::Meta::default()
|
page::Meta::new("time-date", "preferences-system-time-symbolic")
|
||||||
.title(fl!("time-date"))
|
.title(fl!("time-date"))
|
||||||
.description(fl!("time-date", "desc"))
|
.description(fl!("time-date", "desc"))
|
||||||
.icon_name("preferences-system-time-symbolic")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn content(sections: &mut SlotMap<section::Entity, Section>) -> Option<Content> {
|
fn content(sections: &mut SlotMap<section::Entity, Section>) -> Option<Content> {
|
||||||
|
|
|
||||||
|
|
@ -11,13 +11,10 @@ pub struct Page;
|
||||||
impl page::Page for Page {
|
impl page::Page for Page {
|
||||||
type Model = ();
|
type Model = ();
|
||||||
|
|
||||||
const PERSISTENT_ID: &'static str = "time";
|
|
||||||
|
|
||||||
fn page() -> page::Meta {
|
fn page() -> page::Meta {
|
||||||
page::Meta::default()
|
page::Meta::new("time", "preferences-system-time-symbolic")
|
||||||
.title(fl!("time"))
|
.title(fl!("time"))
|
||||||
.description(fl!("time", "desc"))
|
.description(fl!("time", "desc"))
|
||||||
.icon_name("preferences-system-time-symbolic")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sub_pages(page: page::Insert) -> page::Insert {
|
fn sub_pages(page: page::Insert) -> page::Insert {
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,10 @@ pub struct Page;
|
||||||
impl page::Page for Page {
|
impl page::Page for Page {
|
||||||
type Model = ();
|
type Model = ();
|
||||||
|
|
||||||
const PERSISTENT_ID: &'static str = "time-region";
|
|
||||||
|
|
||||||
fn page() -> page::Meta {
|
fn page() -> page::Meta {
|
||||||
page::Meta::default()
|
page::Meta::new("time-region", "preferences-desktop-locale-symbolic")
|
||||||
.title(fl!("time-region"))
|
.title(fl!("time-region"))
|
||||||
.description(fl!("time-region", "desc"))
|
.description(fl!("time-region", "desc"))
|
||||||
.icon_name("preferences-desktop-locale-symbolic")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn content(sections: &mut SlotMap<section::Entity, Section>) -> Option<Content> {
|
fn content(sections: &mut SlotMap<section::Entity, Section>) -> Option<Content> {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue