pub struct Appearance { /* private fields */ }Expand description
The appearance section of a settings page or a setup wizard: language, theme, icons and reduced
motion as the ecosystem shares them, and the pillar, as rows of a
SettingsList; and, where the application asks for its updates, the
ecosystem’s update notice with updates.
Each shared row has a box under it, “In every Quvyta application”, checked while the
application follows the ecosystem: a change then goes to the ecosystem’s shared file and every
application that follows it changes too. Cleared, the change stays in the application’s own
file. The pillar is the application’s own. The update notice is one switch
for the whole ecosystem, kept in the shared file; see Ecosystem::update_notice. Its switch
can be written in the background, so a settings page never waits for the disk; see
updates_in_background. A change is applied at once
and saved at once, each file read again right before it is written; see
Ecosystem::set. When the QUVYTA_REDUCED_MOTION environment variable decides, the reduced
motion row and its box are disabled and the row says why. Texts come from the framework’s language files.
use qframe::i18n::I18n;
use qframe::prelude::*;
use qframe::storage::{Ecosystem, Settings};
use qframe::widgets::{Appearance, AppearanceChange, SettingsList};
struct Code {
settings: Settings,
appearance: Appearance,
}
#[derive(Debug, Clone)]
enum Msg {
Appearance(AppearanceChange),
}
impl App for Code {
type Msg = Msg;
fn update(&mut self, msg: Msg) -> Command<Msg> {
match msg {
Msg::Appearance(change) => self.appearance.update(change, &mut self.settings),
}
}
fn view(&self, ui: &mut View<'_, Msg>) {
SettingsList::show(ui, |list| self.appearance.section(list, Msg::Appearance));
}
}
let ecosystem = Ecosystem::QUVYTA;
// An application passes `ecosystem.preferences("code", &i18n)`; the example stays in a folder of its own.
let preferences = ecosystem.preferences_in(&folder, "code", &I18n::builtin());
let appearance = Appearance::new(ecosystem, "code", preferences).in_folder(&folder);
let settings = Settings::open(folder.join("code.conf")).member_of(&ecosystem);
let mut app = Harness::new(Code { settings, appearance }, 60, 20);
assert!(app.screen().contains("In every Quvyta application"));Implementations§
Source§impl Appearance
impl Appearance
Sourcepub fn label(i18n: &I18n, key: Shared) -> String
pub fn label(i18n: &I18n, key: Shared) -> String
The title the Appearance box gives the row of key, in the language of i18n, so an
application that shows the same preference elsewhere, such as in a table of what follows
the ecosystem, calls it by the same name.
Sourcepub fn new(
ecosystem: Ecosystem,
app: impl Into<String>,
preferences: Preferences,
) -> Self
pub fn new( ecosystem: Ecosystem, app: impl Into<String>, preferences: Preferences, ) -> Self
The appearance of application app of ecosystem, starting from the preferences
Ecosystem::preferences resolved for it. Changes are saved in the ecosystem’s folder.
Sourcepub fn in_folder(self, folder: impl Into<PathBuf>) -> Self
pub fn in_folder(self, folder: impl Into<PathBuf>) -> Self
Saves changes in folder as the ecosystem’s folder instead of this platform’s, for a test
or a demo that must leave the user’s own files alone; see Ecosystem::set_in.
Sourcepub fn without_saving(self) -> Self
pub fn without_saving(self) -> Self
Applies every change without writing a file: the shared preferences
and the settings given to update take it, the screen shows it, and the
files are left to whoever writes them later.
For the first step of a setup wizard, which writes both files only when the wizard finishes, so a wizard closed half-way leaves nothing behind.
Sourcepub fn updates_in_background(self) -> Self
pub fn updates_in_background(self) -> Self
Has the update notice row write the shared file on a thread of its own,
so a settings page never waits for the disk to turn the switch over: the switch shows the
new value at once and the file takes it behind the screen. A file that cannot be written
puts the switch back where the person left it and says so as an
AppearanceSave, which the application shows as a toast.
The application hands every change to update_saving instead of
update, and the outcome back to saved. Every other row
is written as update writes it, on the thread that draws.
Sourcepub fn preferences(&self) -> &Preferences
pub fn preferences(&self) -> &Preferences
The shared preferences as they stand after the changes made so far.
Sourcepub fn refresh(&mut self, preferences: Preferences)
pub fn refresh(&mut self, preferences: Preferences)
Takes preferences resolved again after the files changed while the section is open, such
as the ones App::preferences hears when another
application switches the theme for the whole ecosystem. The rows then show the new values
and the box under each shared row whether the application follows the ecosystem now, and
the next change is saved where that box says.
Nothing is written and nothing is applied: the runtime has already switched the screen. What the person is doing on the section stays as it is: an open list stays open, and a reason a change could not be saved stays under its row until the next change.
Sourcepub fn section<Msg: Clone + 'static>(
&self,
list: &mut SettingsRows<'_, Msg>,
message: impl Fn(AppearanceChange) -> Msg + Clone + 'static,
)
pub fn section<Msg: Clone + 'static>( &self, list: &mut SettingsRows<'_, Msg>, message: impl Fn(AppearanceChange) -> Msg + Clone + 'static, )
Adds an “Appearance” heading, the three shared rows, reduced motion with its
box and the application’s own pillar to list.
Sourcepub fn updates<Msg: Clone + 'static>(
&self,
list: &mut SettingsRows<'_, Msg>,
message: impl Fn(AppearanceChange) -> Msg + Clone + 'static,
)
pub fn updates<Msg: Clone + 'static>( &self, list: &mut SettingsRows<'_, Msg>, message: impl Fn(AppearanceChange) -> Msg + Clone + 'static, )
Adds the ecosystem’s update notice switch to list, with the text saying what it asks and
what it never sends: for an application that asks whether a newer version of itself is out
(Command::check_for_update), right after
section. The switch is the ecosystem’s, one for every application, kept in
the shared file; see Ecosystem::update_notice. An application that never asks leaves the
row out, so its settings offer nothing that does nothing there.
The change is written where the section is drawn, unless the application asked for
updates_in_background.
Sourcepub fn rows<Msg: Clone + 'static>(
&self,
list: &mut SettingsRows<'_, Msg>,
message: impl Fn(AppearanceChange) -> Msg + Clone + 'static,
)
pub fn rows<Msg: Clone + 'static>( &self, list: &mut SettingsRows<'_, Msg>, message: impl Fn(AppearanceChange) -> Msg + Clone + 'static, )
Adds the three rows the ecosystem shares, language, theme and icons, each with its box, to
list, without a heading and without the application’s own rows: what the first step of a
setup wizard asks, on a page that names the section itself. Every change is
sent as message.
Sourcepub fn update<Msg: Send + 'static>(
&mut self,
change: AppearanceChange,
settings: &mut Settings,
) -> Command<Msg>
pub fn update<Msg: Send + 'static>( &mut self, change: AppearanceChange, settings: &mut Settings, ) -> Command<Msg>
Saves change and returns the command that shows it at once. settings are the
application’s own settings as it holds them in memory; they take the change too, so a
later Settings::save writes what the file now says instead of what it said before.
A change that cannot be saved is still applied, and the row it was made on says why it was not saved until the next change.
Sourcepub fn update_saving<Msg: Send + 'static>(
&mut self,
change: AppearanceChange,
settings: &mut Settings,
saved: impl FnOnce(AppearanceSave) -> Msg + Send + 'static,
) -> Command<Msg>
pub fn update_saving<Msg: Send + 'static>( &mut self, change: AppearanceChange, settings: &mut Settings, saved: impl FnOnce(AppearanceSave) -> Msg + Send + 'static, ) -> Command<Msg>
update, and the command that writes the ecosystem’s update notice in the
background when updates_in_background is on: the switch
shows the new value at once and saved is called with what became of the write once it is
done, so the application can show it as a toast and hand it to saved.
Without the option every change is written as update writes it, on the
thread that draws, and saved is never called; an application can then turn the option on
without touching this line.
use qframe::prelude::*;
use qframe::storage::{Ecosystem, Settings};
use qframe::widgets::{Appearance, AppearanceChange, AppearanceSave, SettingsList};
struct Code {
settings: Settings,
appearance: Appearance,
/// What the last background write left.
saved: Option<AppearanceSave>,
}
#[derive(Debug, Clone)]
enum Msg {
Appearance(AppearanceChange),
Saved(AppearanceSave),
}
impl App for Code {
type Msg = Msg;
fn update(&mut self, msg: Msg) -> Command<Msg> {
match msg {
Msg::Appearance(change) => {
self.appearance.update_saving(change, &mut self.settings, Msg::Saved)
}
Msg::Saved(save) => {
self.saved = Some(save.clone());
self.appearance.saved(&save);
Command::none()
}
}
}
fn view(&self, ui: &mut View<'_, Msg>) {
SettingsList::show(ui, |list| {
self.appearance.section(list, Msg::Appearance);
self.appearance.updates(list, Msg::Appearance);
});
}
}
// An application passes `ecosystem.preferences("code", &i18n)`; the example stays in a folder of its own.
let appearance = Appearance::new(ecosystem, "code", preferences).in_folder(&folder).updates_in_background();
let settings = Settings::open(folder.join("code.conf")).member_of(&ecosystem);
let mut app = Harness::new(Code { settings, appearance, saved: None }, 60, 20);
// The row's change is written off the drawing thread and its outcome comes back as a message.
app.send(Msg::Appearance(AppearanceChange::UpdateNotice(false)));
assert_eq!(app.app().saved, Some(AppearanceSave::Saved), "the file took the new value");
let shared = std::fs::read_to_string(folder.join("quvyta.conf")).expect("the shared file");
assert!(shared.contains("update-notice = false"), "{shared}");Sourcepub fn saved(&mut self, save: &AppearanceSave)
pub fn saved(&mut self, save: &AppearanceSave)
Takes what became of a change the rows saved in the background, as
update_saving and updates_in_background
say. A value the file could not take leaves the row showing what the file still says, so
the switch is where the person left it. Nothing is written under the row: the application
has the outcome and shows it itself, as a toast.
Trait Implementations§
Source§impl Clone for Appearance
impl Clone for Appearance
Auto Trait Implementations§
impl Freeze for Appearance
impl RefUnwindSafe for Appearance
impl Send for Appearance
impl Sync for Appearance
impl Unpin for Appearance
impl UnsafeUnpin for Appearance
impl UnwindSafe for Appearance
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more