first pass of merging in warp (doesn't build)

This commit is contained in:
Ryan Ward
2026-07-01 16:08:58 -05:00
parent 2f64909469
commit 4770ac06b5
3662 changed files with 414574 additions and 89772 deletions
+106 -39
View File
@@ -4,21 +4,21 @@ pub mod manager;
pub mod schema;
// Re-export commonly used types and traits
pub use macros::SettingSection;
pub use manager::SettingsManager;
use std::fmt::Debug;
use std::ops::Deref;
// Re-export crates used by macro expansions in downstream crates.
#[doc(hidden)]
pub use inventory as _inventory;
pub use macros::SettingSection;
pub use manager::SettingsManager;
#[doc(hidden)]
pub use schemars as _schemars;
#[doc(hidden)]
pub use settings_value as _settings_value;
pub use settings_value::SettingsValue;
use std::fmt::Debug;
use std::ops::Deref;
use std::sync::atomic::{AtomicBool, Ordering};
// Re-export galaxyui_core for use by macros.
pub use galaxyui_core;
/// Extracts the storage key (last segment after the final `.`) from a toml_path.
///
@@ -59,31 +59,12 @@ pub const fn toml_path_hierarchy(path: &str) -> Option<&str> {
}
use anyhow::{Context, Result};
use galaxyui::{AppContext, Entity, ModelContext};
use serde::Serialize;
use serde::de::DeserializeOwned;
use galaxy_features::FeatureFlag;
use galaxyui_core::{AppContext, Entity, ModelContext};
use galaxyui_extras::secure_storage::{self, AppContextExt as _};
use galaxyui_extras::user_preferences::UserPreferences;
use serde::{Serialize, de::DeserializeOwned};
/// Whether the TOML-backed settings file is active.
///
/// Set once during startup via [`set_settings_file_enabled`]. When `false`,
/// public settings fall back to the private (platform-native) backend so
/// that all settings share a single instance.
static SETTINGS_FILE_ENABLED: AtomicBool = AtomicBool::new(false);
/// Records whether the TOML-backed settings file feature is active.
///
/// Call this once during startup after checking `FeatureFlag::SettingsFile`.
/// The value is read by [`Setting::preferences_for_setting`] and
/// [`SettingsManager::read_local_setting_value`] to decide which backend
/// to use for public settings.
pub fn set_settings_file_enabled(enabled: bool) {
SETTINGS_FILE_ENABLED.store(enabled, Ordering::Relaxed);
}
/// Returns whether the TOML-backed settings file is currently active.
pub fn is_settings_file_enabled() -> bool {
SETTINGS_FILE_ENABLED.load(Ordering::Relaxed)
}
/// A newtype wrapper for the public preferences backend.
///
@@ -122,11 +103,11 @@ impl PublicPreferences {
}
}
impl galaxyui::Entity for PublicPreferences {
impl galaxyui_core::Entity for PublicPreferences {
type Event = ();
}
impl galaxyui::SingletonEntity for PublicPreferences {}
impl galaxyui_core::SingletonEntity for PublicPreferences {}
/// A newtype wrapper for the private preferences backend.
///
@@ -150,11 +131,11 @@ impl Deref for PrivatePreferences {
}
}
impl galaxyui::Entity for PrivatePreferences {
impl galaxyui_core::Entity for PrivatePreferences {
type Event = ();
}
impl galaxyui::SingletonEntity for PrivatePreferences {}
impl galaxyui_core::SingletonEntity for PrivatePreferences {}
/// An enum representing the different platforms a setting could apply to.
#[derive(Debug, Clone)]
@@ -204,7 +185,10 @@ impl SupportedPlatforms {
cfg!(all(not(target_family = "wasm"), target_os = "macos"))
}
SupportedPlatforms::LINUX => {
cfg!(all(not(target_family = "wasm"), target_os = "linux"))
cfg!(all(
not(target_family = "wasm"),
any(target_os = "linux", target_os = "freebsd")
))
}
SupportedPlatforms::WINDOWS => {
cfg!(all(not(target_family = "wasm"), target_os = "windows"))
@@ -370,7 +354,7 @@ pub trait Setting {
fn set_value_from_cloud_sync(
&mut self,
new_value: Self::Value,
ctx: &mut galaxyui::ModelContext<Self::Group>,
ctx: &mut galaxyui_core::ModelContext<Self::Group>,
) -> anyhow::Result<()>;
/// Sets the value of the setting persisting it to storage.
@@ -386,7 +370,7 @@ pub trait Setting {
/// Sets the value of the setting to its default and persists it to storage.
fn set_value_to_default(
&mut self,
ctx: &mut galaxyui::ModelContext<Self::Group>,
ctx: &mut galaxyui_core::ModelContext<Self::Group>,
) -> anyhow::Result<()> {
self.set_value(Self::default_value(), ctx)
}
@@ -396,11 +380,11 @@ pub trait Setting {
/// Private settings use the platform-native store; public settings use
/// the main preferences backend (which may be the TOML settings file).
fn preferences_for_setting(ctx: &AppContext) -> &dyn UserPreferences {
use galaxyui::SingletonEntity;
use galaxyui_core::SingletonEntity;
if Self::is_private() {
<PrivatePreferences as SingletonEntity>::as_ref(ctx).deref()
} else if is_settings_file_enabled() {
} else if FeatureFlag::SettingsFile.is_enabled() {
<PublicPreferences as SingletonEntity>::as_ref(ctx).as_preferences()
} else {
// When the settings file is disabled, fall back to the private
@@ -573,6 +557,89 @@ pub trait Setting {
fn is_value_explicitly_set(&self) -> bool;
}
/// Shared persistence operations for typed settings backed by secure storage.
///
/// Implementors remain responsible for routing their [`Setting`] lifecycle
/// methods through this trait and for keeping the setting private and
/// non-synced when the value must not be exposed through ordinary settings
/// storage.
pub trait SecureSetting: Setting {
/// Writes this setting's serialized value through its selected secure-storage path.
fn write_secure_storage_value(
storage: &dyn secure_storage::SecureStorage,
key: &str,
value: &str,
) -> Result<(), secure_storage::Error> {
storage.write_value(key, value)
}
/// Reads and deserializes this setting from secure storage.
///
/// Missing, unreadable, or malformed values return `None`, allowing the
/// setting to fail closed to its default value.
fn read_from_secure_storage(ctx: &AppContext) -> Option<Self::Value> {
let value = match ctx.secure_storage().read_value(Self::storage_key()) {
Ok(value) => value,
Err(secure_storage::Error::NotFound) => return None,
Err(err) => {
log::error!(
"Failed to read {} from secure storage: {err:#}",
Self::setting_name()
);
return None;
}
};
match serde_json::from_str(&value) {
Ok(value) => Some(value),
Err(err) => {
log::error!(
"Failed to deserialize {} from secure storage: {err:#}",
Self::setting_name()
);
None
}
}
}
/// Persists this setting to secure storage if its typed value changed.
fn write_to_secure_storage(new_value: &Self::Value, ctx: &AppContext) -> Result<bool> {
let stored_value_matches = match ctx.secure_storage().read_value(Self::storage_key()) {
Ok(stored) => serde_json::from_str::<Self::Value>(&stored)
.is_ok_and(|stored| stored == *new_value),
Err(secure_storage::Error::NotFound) => false,
Err(err) => {
return Err(anyhow::anyhow!(err)).context(format!(
"Failed to read existing {} from secure storage",
Self::setting_name()
));
}
};
if stored_value_matches {
return Ok(false);
}
let serialized = serde_json::to_string(new_value).context(format!(
"Failed to serialize {} for secure storage",
Self::setting_name()
))?;
Self::write_secure_storage_value(ctx.secure_storage(), Self::storage_key(), &serialized)
.context(format!(
"Failed to write {} to secure storage",
Self::setting_name()
))?;
Ok(true)
}
/// Removes this setting from secure storage.
fn clear_from_secure_storage(ctx: &AppContext) -> Result<()> {
match ctx.secure_storage().remove_value(Self::storage_key()) {
Ok(()) | Err(secure_storage::Error::NotFound) => Ok(()),
Err(err) => Err(anyhow::anyhow!(err)).context(format!(
"Failed to clear {} from secure storage",
Self::setting_name()
)),
}
}
}
/// A trait for settings that can be toggled between two values.
pub trait ToggleableSetting: Setting {
/// Toggles the value of the setting and persists it to storage, returning
+23 -36
View File
@@ -39,7 +39,7 @@
//! ```
//!
//! The macro also generates an `Event` type that is passed to subscribers of the
//! setting group model. The name of the type is created by appended 'ChangedEvent'
//! setting group model. The name of the type is created by appending 'ChangedEvent'
//! to the name of the setting group:
//!
//! ```
@@ -109,10 +109,11 @@
//! Once you've defined a setting, usage is straightforward:
//!
//! ```
//! # use galaxyui::*;
//! # use settings::macros::*;
//! # use settings::manager::SettingsManager;
//! # use settings::*;
//! # use galaxyui_core::prelude::*;
//! # use galaxyui_core::{elements, App};
//! # use galaxyui_extras::user_preferences;
//! define_settings_group!(ExampleGroup, settings: [
//! bool_setting: BoolSetting {
@@ -312,7 +313,7 @@ macro_rules! define_setting {
fn clear_value(
&mut self,
ctx: &mut galaxyui::ModelContext<Self::Group>,
ctx: &mut $crate::galaxyui_core::ModelContext<Self::Group>,
) -> anyhow::Result<()> {
use $crate::ChangeEventReason;
Self::clear_from_preferences(Self::preferences_for_setting(ctx))?;
@@ -327,9 +328,8 @@ macro_rules! define_setting {
fn set_value_from_cloud_sync(
&mut self,
new_value: Self::Value,
ctx: &mut galaxyui::ModelContext<Self::Group>,
ctx: &mut $crate::galaxyui_core::ModelContext<Self::Group>,
) -> anyhow::Result<()> {
use $crate::ChangeEventReason;
let changed_in_storage =
Self::write_to_preferences(&new_value, Self::preferences_for_setting(ctx))?;
if self.value() != &new_value || changed_in_storage {
@@ -345,9 +345,8 @@ macro_rules! define_setting {
fn set_value(
&mut self,
new_value: Self::Value,
ctx: &mut galaxyui::ModelContext<Self::Group>,
ctx: &mut $crate::galaxyui_core::ModelContext<Self::Group>,
) -> anyhow::Result<()> {
use $crate::ChangeEventReason;
let changed_in_storage =
Self::write_to_preferences(&new_value, Self::preferences_for_setting(ctx))?;
if self.value() != &new_value || changed_in_storage {
@@ -364,9 +363,8 @@ macro_rules! define_setting {
&mut self,
new_value: Self::Value,
explicitly_set: bool,
ctx: &mut galaxyui::ModelContext<Self::Group>,
ctx: &mut $crate::galaxyui_core::ModelContext<Self::Group>,
) -> anyhow::Result<()> {
use $crate::ChangeEventReason;
let validated = self.validate(new_value);
if self.value() != &validated || self.is_explicitly_set != explicitly_set {
self.inner = validated;
@@ -582,9 +580,8 @@ macro_rules! implement_setting_for_enum {
fn clear_value(
&mut self,
ctx: &mut galaxyui::ModelContext<Self::Group>,
ctx: &mut $crate::galaxyui_core::ModelContext<Self::Group>,
) -> anyhow::Result<()> {
use $crate::ChangeEventReason;
Self::clear_from_preferences(Self::preferences_for_setting(ctx))?;
*self = self.validate(Self::default_value());
ctx.emit($crate::macros::concat_idents!(EventName = $group, ChangedEvent { EventName::$name {
@@ -596,9 +593,8 @@ macro_rules! implement_setting_for_enum {
fn set_value_from_cloud_sync(
&mut self,
new_value: Self::Value,
ctx: &mut galaxyui::ModelContext<Self::Group>,
ctx: &mut $crate::galaxyui_core::ModelContext<Self::Group>,
) -> anyhow::Result<()> {
use $crate::ChangeEventReason;
let changed_in_storage =
Self::write_to_preferences(&new_value, Self::preferences_for_setting(ctx))?;
if self.value() != &new_value || changed_in_storage {
@@ -613,9 +609,8 @@ macro_rules! implement_setting_for_enum {
fn set_value(
&mut self,
new_value: Self::Value,
ctx: &mut galaxyui::ModelContext<Self::Group>,
ctx: &mut $crate::galaxyui_core::ModelContext<Self::Group>,
) -> anyhow::Result<()> {
use $crate::ChangeEventReason;
let changed_in_storage =
Self::write_to_preferences(&new_value, Self::preferences_for_setting(ctx))?;
if self.value() != &new_value || changed_in_storage {
@@ -631,9 +626,8 @@ macro_rules! implement_setting_for_enum {
&mut self,
new_value: Self::Value,
_explicitly_set: bool,
ctx: &mut galaxyui::ModelContext<Self::Group>,
ctx: &mut $crate::galaxyui_core::ModelContext<Self::Group>,
) -> anyhow::Result<()> {
use $crate::ChangeEventReason;
let validated = self.validate(new_value);
if self.value() != &validated {
*self = validated;
@@ -714,8 +708,7 @@ macro_rules! define_settings_group {
impl $group {
#[allow(dead_code)]
fn new_from_storage(ctx: &mut galaxyui::ModelContext<Self>) -> Self {
use $crate::Setting;
fn new_from_storage(ctx: &mut $crate::galaxyui_core::ModelContext<Self>) -> Self {
Self {
$(
$var: <$setting>::new_from_storage(ctx),
@@ -725,8 +718,7 @@ macro_rules! define_settings_group {
#[cfg(any(test, feature = "integration_tests"))]
#[allow(dead_code)]
pub fn new_with_defaults(_ctx: &mut galaxyui::ModelContext<Self>) -> Self {
use $crate::Setting;
pub fn new_with_defaults(_ctx: &mut $crate::galaxyui_core::ModelContext<Self>) -> Self {
Self {
$(
$var: <$setting>::new(None),
@@ -735,7 +727,7 @@ macro_rules! define_settings_group {
}
#[allow(dead_code)]
pub fn register(ctx: &mut (impl galaxyui::GetSingletonModelHandle + galaxyui::AddSingletonModel + galaxyui::UpdateModel)) -> galaxyui::ModelHandle<Self> {
pub fn register(ctx: &mut (impl $crate::galaxyui_core::GetSingletonModelHandle + $crate::galaxyui_core::AddSingletonModel + $crate::galaxyui_core::UpdateModel)) -> $crate::galaxyui_core::ModelHandle<Self> {
let settings_group = ctx.add_singleton_model(|ctx| {
Self::new_from_storage(ctx)
});
@@ -758,7 +750,6 @@ macro_rules! define_settings_group {
/// If any of the settings in the setting group are supported, then the group is supported.
/// If none of the settings in the group are supported, then the group is not supported.
fn is_supported_on_current_platform(&self) -> bool {
use $crate::Setting;
$(
if self.$var.is_supported_on_current_platform() {
return true;
@@ -769,24 +760,23 @@ macro_rules! define_settings_group {
}
$crate::macros::concat_idents!(EventName = $group, ChangedEvent {
use $crate::ChangeEventReason;
#[derive(Debug)]
#[allow(clippy::enum_variant_names)]
pub enum EventName {
$(
$setting {
#[allow(dead_code)]
change_event_reason: ChangeEventReason,
change_event_reason: $crate::ChangeEventReason,
},
)*
}
impl galaxyui::Entity for $group {
impl $crate::galaxyui_core::Entity for $group {
type Event = EventName;
}
});
impl galaxyui::SingletonEntity for $group {}
impl $crate::galaxyui_core::SingletonEntity for $group {}
};
}
pub use define_settings_group;
@@ -816,21 +806,21 @@ macro_rules! generate_settings_event_fn {
#[allow(dead_code)]
#[allow(non_snake_case)]
fn fn_name(
settings_group: galaxyui::ModelHandle<$group>,
settings_group: $crate::galaxyui_core::ModelHandle<$group>,
ctx: &mut (
impl galaxyui::GetSingletonModelHandle
+ galaxyui::AddSingletonModel
+ galaxyui::UpdateModel
impl $crate::galaxyui_core::GetSingletonModelHandle
+ $crate::galaxyui_core::AddSingletonModel
+ $crate::galaxyui_core::UpdateModel
),
) {
use anyhow::anyhow;
use galaxyui::SingletonEntity;
use serde_json;
use $crate::Setting as _;
use $crate::manager::{SettingsEvent, SettingsManager};
use $crate::galaxyui_core::SingletonEntity;
SettingsManager::handle(ctx).update(ctx, |manager, ctx| {
// Propagate per settings change events through the SettingsManager
ctx.subscribe_to_model(&settings_group, |_manager, _, ctx| {
ctx.subscribe_to_model(&settings_group, |_manager, _, _, ctx| {
ctx.emit(SettingsEvent::LocalPreferencesUpdated {
storage_key: $setting::storage_key().to_string(),
sync_to_cloud: $setting::sync_to_cloud(),
@@ -861,7 +851,6 @@ macro_rules! generate_settings_event_fn {
$setting::max_table_depth(),
$setting::is_private(),
move |value, from_cloud_sync, ctx| {
use $crate::_settings_value::SettingsValue as _;
// Try SettingsValue first (handles snake_case enums etc.),
// then fall back to serde for cloud sync values.
let value = serde_json::from_str::<serde_json::Value>(&value)
@@ -901,7 +890,6 @@ macro_rules! generate_settings_event_fn {
})
},
move |value, explicitly_set, ctx| {
use $crate::_settings_value::SettingsValue as _;
let value = serde_json::from_str::<serde_json::Value>(&value)
.ok()
.and_then(|json_val| {
@@ -919,7 +907,6 @@ macro_rules! generate_settings_event_fn {
})
},
|left, right| {
use $crate::_settings_value::SettingsValue as _;
let parse =
|s: &str| -> anyhow::Result<<$setting as $crate::Setting>::Value> {
let json_val = serde_json::from_str::<serde_json::Value>(s)?;
+40 -66
View File
@@ -1,10 +1,8 @@
use anyhow::Result;
use galaxyui::{AppContext, SingletonEntity};
use galaxyui_core::{AppContext, SingletonEntity};
use crate::manager::SettingsManager;
use crate::{Setting, SupportedPlatforms, SyncToCloud};
use crate::*;
use crate::{Setting, SupportedPlatforms, SyncToCloud, *};
define_settings_group!(TestSettings, settings: [
simple_setting: SimpleSetting {
@@ -53,9 +51,9 @@ struct EventListener {
}
impl EventListener {
fn new(ctx: &mut galaxyui::ModelContext<Self>) -> Self {
fn new(ctx: &mut galaxyui_core::ModelContext<Self>) -> Self {
let test_settings = TestSettings::handle(ctx);
ctx.subscribe_to_model(&test_settings, |me, event, _ctx| {
ctx.subscribe_to_model(&test_settings, |me, _, event, _ctx| {
// Update our internal state if we get a change event for
// SimpleSetting.
if matches!(event, TestSettingsChangedEvent::SimpleSetting { .. }) {
@@ -67,7 +65,7 @@ impl EventListener {
}
}
impl galaxyui::Entity for EventListener {
impl galaxyui_core::Entity for EventListener {
type Event = ();
}
@@ -92,7 +90,7 @@ fn test_can_override_storage_key() {
#[test]
fn test_set_value_raises_changed_event_no_save() {
galaxyui::App::test((), |mut app| async move {
galaxyui_core::App::test((), |mut app| async move {
app.update(init_and_register_preferences);
app.add_singleton_model(|_| SettingsManager::default());
@@ -124,7 +122,7 @@ fn test_set_value_raises_changed_event_no_save() {
#[test]
fn test_set_value_raises_changed_event_save() {
galaxyui::App::test((), |mut app| async move {
galaxyui_core::App::test((), |mut app| async move {
app.update(init_and_register_preferences);
app.add_singleton_model(|_| SettingsManager::default());
@@ -156,7 +154,7 @@ fn test_set_value_raises_changed_event_save() {
#[test]
fn test_save_and_load_lifecycle() {
galaxyui::App::test((), |mut app| async move {
galaxyui_core::App::test((), |mut app| async move {
app.update(init_and_register_preferences);
app.add_singleton_model(|_| SettingsManager::default());
@@ -195,7 +193,7 @@ fn test_save_and_load_lifecycle() {
#[test]
fn test_toggleable_setting() -> Result<()> {
galaxyui::App::test((), |mut app| async move {
galaxyui_core::App::test((), |mut app| async move {
app.update(init_and_register_preferences);
app.add_singleton_model(|_| SettingsManager::default());
@@ -254,7 +252,7 @@ fn test_explicit_value_tracking_with_some() {
#[test]
fn test_explicit_value_tracking_after_set_value() {
galaxyui::App::test((), |mut app| async move {
galaxyui_core::App::test((), |mut app| async move {
app.update(init_and_register_preferences);
app.add_singleton_model(|_| SettingsManager::default());
@@ -284,7 +282,7 @@ fn test_explicit_value_tracking_after_set_value() {
#[test]
fn test_explicit_value_tracking_after_clear_value() {
galaxyui::App::test((), |mut app| async move {
galaxyui_core::App::test((), |mut app| async move {
app.update(init_and_register_preferences);
app.add_singleton_model(|_| SettingsManager::default());
@@ -325,7 +323,7 @@ fn test_explicit_value_tracking_after_clear_value() {
#[test]
fn test_explicit_value_tracking_from_storage() {
galaxyui::App::test((), |mut app| async move {
galaxyui_core::App::test((), |mut app| async move {
app.update(init_and_register_preferences);
app.add_singleton_model(|_| SettingsManager::default());
@@ -399,7 +397,7 @@ fn test_private_setting_storage_key_is_explicit_override() {
#[test]
fn test_load_value_updates_value_without_persisting() {
galaxyui::App::test((), |mut app| async move {
galaxyui_core::App::test((), |mut app| async move {
app.update(init_and_register_preferences);
app.add_singleton_model(|_| SettingsManager::default());
TestSettings::register(&mut app);
@@ -430,7 +428,7 @@ fn test_load_value_updates_value_without_persisting() {
#[test]
fn test_load_value_emits_event_on_change() {
galaxyui::App::test((), |mut app| async move {
galaxyui_core::App::test((), |mut app| async move {
app.update(init_and_register_preferences);
app.add_singleton_model(|_| SettingsManager::default());
TestSettings::register(&mut app);
@@ -461,7 +459,7 @@ fn test_load_value_emits_event_on_change() {
#[test]
fn test_load_value_skips_event_when_unchanged() {
galaxyui::App::test((), |mut app| async move {
galaxyui_core::App::test((), |mut app| async move {
app.update(init_and_register_preferences);
app.add_singleton_model(|_| SettingsManager::default());
TestSettings::register(&mut app);
@@ -490,7 +488,7 @@ fn test_load_value_skips_event_when_unchanged() {
#[test]
fn test_load_value_updates_explicitly_set_flag() {
galaxyui::App::test((), |mut app| async move {
galaxyui_core::App::test((), |mut app| async move {
app.update(init_and_register_preferences);
app.add_singleton_model(|_| SettingsManager::default());
TestSettings::register(&mut app);
@@ -526,7 +524,7 @@ fn test_load_value_updates_explicitly_set_flag() {
#[test]
fn test_load_value_resets_explicitly_set_flag() {
galaxyui::App::test((), |mut app| async move {
galaxyui_core::App::test((), |mut app| async move {
app.update(init_and_register_preferences);
app.add_singleton_model(|_| SettingsManager::default());
TestSettings::register(&mut app);
@@ -569,7 +567,7 @@ fn test_load_value_resets_explicitly_set_flag() {
#[test]
fn test_explicit_value_tracking_cloud_sync() {
galaxyui::App::test((), |mut app| async move {
galaxyui_core::App::test((), |mut app| async move {
app.update(init_and_register_preferences);
app.add_singleton_model(|_| SettingsManager::default());
@@ -627,11 +625,6 @@ mod file_transform_tests {
// Private / public settings split tests
// ---------------------------------------------------------------------------
// Tests that call `set_settings_file_enabled` are marked `#[serial_test::serial]`
// because they mutate the process-global `SETTINGS_FILE_ENABLED` AtomicBool and
// would race under `cargo test` (thread-based parallelism). This can be removed
// when the SettingsFile feature flag is cleaned up and the global flag is deleted.
#[test]
fn test_is_private_returns_false_for_public_setting() {
assert!(!SimpleSetting::is_private());
@@ -643,19 +636,9 @@ fn test_is_private_returns_true_for_private_setting() {
}
#[test]
#[serial_test::serial]
fn test_settings_file_enabled_flag_round_trip() {
crate::set_settings_file_enabled(true);
assert!(crate::is_settings_file_enabled());
crate::set_settings_file_enabled(false);
assert!(!crate::is_settings_file_enabled());
}
#[test]
#[serial_test::serial]
fn test_public_setting_writes_to_public_prefs_when_flag_enabled() {
crate::set_settings_file_enabled(true);
galaxyui::App::test((), |mut app| async move {
let _guard = galaxy_features::FeatureFlag::SettingsFile.override_enabled(true);
galaxyui_core::App::test((), |mut app| async move {
app.update(init_and_register_preferences);
app.add_singleton_model(|_| SettingsManager::default());
TestSettings::register(&mut app);
@@ -690,10 +673,9 @@ fn test_public_setting_writes_to_public_prefs_when_flag_enabled() {
}
#[test]
#[serial_test::serial]
fn test_private_setting_writes_to_private_prefs_when_flag_enabled() {
crate::set_settings_file_enabled(true);
galaxyui::App::test((), |mut app| async move {
let _guard = galaxy_features::FeatureFlag::SettingsFile.override_enabled(true);
galaxyui_core::App::test((), |mut app| async move {
app.update(init_and_register_preferences);
app.add_singleton_model(|_| SettingsManager::default());
TestSettings::register(&mut app);
@@ -737,10 +719,9 @@ fn test_private_setting_writes_to_private_prefs_when_flag_enabled() {
}
#[test]
#[serial_test::serial]
fn test_new_from_storage_reads_from_correct_backend_when_flag_enabled() {
crate::set_settings_file_enabled(true);
galaxyui::App::test((), |mut app| async move {
let _guard = galaxy_features::FeatureFlag::SettingsFile.override_enabled(true);
galaxyui_core::App::test((), |mut app| async move {
app.update(init_and_register_preferences);
app.add_singleton_model(|_| SettingsManager::default());
TestSettings::register(&mut app);
@@ -775,10 +756,9 @@ fn test_new_from_storage_reads_from_correct_backend_when_flag_enabled() {
}
#[test]
#[serial_test::serial]
fn test_clear_value_clears_from_correct_backend() {
crate::set_settings_file_enabled(true);
galaxyui::App::test((), |mut app| async move {
let _guard = galaxy_features::FeatureFlag::SettingsFile.override_enabled(true);
galaxyui_core::App::test((), |mut app| async move {
app.update(init_and_register_preferences);
app.add_singleton_model(|_| SettingsManager::default());
TestSettings::register(&mut app);
@@ -831,10 +811,9 @@ fn test_clear_value_clears_from_correct_backend() {
}
#[test]
#[serial_test::serial]
fn test_public_setting_uses_private_prefs_when_flag_disabled() {
crate::set_settings_file_enabled(false);
galaxyui::App::test((), |mut app| async move {
let _guard = galaxy_features::FeatureFlag::SettingsFile.override_enabled(false);
galaxyui_core::App::test((), |mut app| async move {
app.update(init_and_register_preferences);
app.add_singleton_model(|_| SettingsManager::default());
TestSettings::register(&mut app);
@@ -872,10 +851,9 @@ fn test_public_setting_uses_private_prefs_when_flag_disabled() {
}
#[test]
#[serial_test::serial]
fn test_private_setting_uses_private_prefs_when_flag_disabled() {
crate::set_settings_file_enabled(false);
galaxyui::App::test((), |mut app| async move {
let _guard = galaxy_features::FeatureFlag::SettingsFile.override_enabled(false);
galaxyui_core::App::test((), |mut app| async move {
app.update(init_and_register_preferences);
app.add_singleton_model(|_| SettingsManager::default());
TestSettings::register(&mut app);
@@ -906,10 +884,9 @@ fn test_private_setting_uses_private_prefs_when_flag_disabled() {
}
#[test]
#[serial_test::serial]
fn test_new_from_storage_reads_from_private_backend_when_flag_disabled() {
crate::set_settings_file_enabled(false);
galaxyui::App::test((), |mut app| async move {
let _guard = galaxy_features::FeatureFlag::SettingsFile.override_enabled(false);
galaxyui_core::App::test((), |mut app| async move {
app.update(init_and_register_preferences);
app.add_singleton_model(|_| SettingsManager::default());
TestSettings::register(&mut app);
@@ -950,7 +927,7 @@ fn test_new_from_storage_reads_from_private_backend_when_flag_disabled() {
#[test]
fn test_manager_is_private_for_storage_key() {
galaxyui::App::test((), |mut app| async move {
galaxyui_core::App::test((), |mut app| async move {
app.update(init_and_register_preferences);
app.add_singleton_model(|_| SettingsManager::default());
TestSettings::register(&mut app);
@@ -975,7 +952,7 @@ fn test_manager_is_private_for_storage_key() {
#[test]
fn test_manager_default_values_for_settings_file_excludes_private() {
galaxyui::App::test((), |mut app| async move {
galaxyui_core::App::test((), |mut app| async move {
app.update(init_and_register_preferences);
app.add_singleton_model(|_| SettingsManager::default());
TestSettings::register(&mut app);
@@ -1003,10 +980,9 @@ fn test_manager_default_values_for_settings_file_excludes_private() {
}
#[test]
#[serial_test::serial]
fn test_manager_read_local_setting_value_routes_when_flag_enabled() {
crate::set_settings_file_enabled(true);
galaxyui::App::test((), |mut app| async move {
let _guard = galaxy_features::FeatureFlag::SettingsFile.override_enabled(true);
galaxyui_core::App::test((), |mut app| async move {
app.update(init_and_register_preferences);
app.add_singleton_model(|_| SettingsManager::default());
TestSettings::register(&mut app);
@@ -1051,10 +1027,9 @@ fn test_manager_read_local_setting_value_routes_when_flag_enabled() {
}
#[test]
#[serial_test::serial]
fn test_manager_read_local_setting_value_falls_back_when_flag_disabled() {
crate::set_settings_file_enabled(false);
galaxyui::App::test((), |mut app| async move {
let _guard = galaxy_features::FeatureFlag::SettingsFile.override_enabled(false);
galaxyui_core::App::test((), |mut app| async move {
app.update(init_and_register_preferences);
app.add_singleton_model(|_| SettingsManager::default());
TestSettings::register(&mut app);
@@ -1102,15 +1077,14 @@ fn test_manager_read_local_setting_value_falls_back_when_flag_disabled() {
/// section like `[account]` are invisible to the SettingsManager and the
/// cloud preferences syncer clobbers them with stale cloud state.
#[test]
#[serial_test::serial]
fn test_manager_read_local_setting_value_respects_hierarchy_with_settings_file() {
use galaxyui_extras::user_preferences::toml_backed::TomlBackedUserPreferences;
crate::set_settings_file_enabled(true);
let _guard = galaxy_features::FeatureFlag::SettingsFile.override_enabled(true);
let dir = tempfile::tempdir().unwrap();
let file_path = dir.path().join("settings.toml");
galaxyui::App::test((), |mut app| async move {
galaxyui_core::App::test((), |mut app| async move {
// Use the TOML-backed store for public preferences so the hierarchy
// routing actually matters; in-memory preferences ignore hierarchy
// entirely and would hide this bug.
+5 -7
View File
@@ -1,14 +1,12 @@
use std::collections::HashMap;
use std::ops::Deref;
use anyhow::{Result, anyhow};
use galaxyui::{AppContext, Entity, ModelContext, SingletonEntity};
use galaxy_features::FeatureFlag;
use galaxyui_core::{AppContext, Entity, ModelContext, SingletonEntity};
use galaxyui_extras::user_preferences::UserPreferences;
use super::PrivatePreferences;
use super::{RespectUserSyncSetting, SupportedPlatforms, SyncToCloud};
use super::{PrivatePreferences, RespectUserSyncSetting, SupportedPlatforms, SyncToCloud};
type UpdateFn = Box<dyn FnMut(String, bool, &mut AppContext) -> Result<()>>;
@@ -94,7 +92,7 @@ pub enum SettingsEvent {
}
impl SettingsManager {
/// Registers a function that updates a a setting with the given storage key
/// Registers a function that updates a setting with the given storage key
/// to have a new value. Also tracks whether that storage key is for a cloud-synced
/// setting and what platforms it's supported on.
#[allow(clippy::too_many_arguments)]
@@ -232,7 +230,7 @@ impl SettingsManager {
<PrivatePreferences as SingletonEntity>::as_ref(ctx).deref();
let prefs: &dyn UserPreferences = if self.is_private_for_storage_key(storage_key) {
private
} else if super::is_settings_file_enabled() {
} else if FeatureFlag::SettingsFile.is_enabled() {
<super::PublicPreferences as SingletonEntity>::as_ref(ctx).as_preferences()
} else {
// When the settings file is disabled, fall back to the private
+13 -20
View File
@@ -1,9 +1,7 @@
use galaxyui::SingletonEntity;
use galaxyui_core::SingletonEntity;
use crate::manager::SettingsManager;
use crate::{Setting, SupportedPlatforms, SyncToCloud};
use crate::*;
use crate::{Setting, SupportedPlatforms, SyncToCloud, *};
define_settings_group!(TestSettings, settings: [
never_sync_setting: SimpleSetting {
@@ -63,7 +61,7 @@ pub fn init_and_register_user_preferences(ctx: &mut AppContext) {
#[test]
fn test_is_setting_syncable_on_current_platform() {
galaxyui::App::test((), |mut app| async move {
galaxyui_core::App::test((), |mut app| async move {
app.update(init_and_register_user_preferences);
app.add_singleton_model(|_| SettingsManager::default());
@@ -155,12 +153,7 @@ fn test_is_setting_syncable_on_current_platform() {
}
mod reload_all_public_settings_tests {
use galaxyui::SingletonEntity;
use crate::manager::SettingsManager;
use crate::{Setting, SupportedPlatforms, SyncToCloud};
use crate::*;
define_settings_group!(ReloadTestSettings, settings: [
public_flag: PublicFlag {
@@ -197,7 +190,7 @@ mod reload_all_public_settings_tests {
/// in the preferences backend.
#[test]
fn test_loads_present_keys() {
galaxyui::App::test((), |mut app| async move {
galaxyui_core::App::test((), |mut app| async move {
app.update(init_prefs);
app.add_singleton_model(|_| SettingsManager::default());
ReloadTestSettings::register(&mut app);
@@ -231,7 +224,7 @@ mod reload_all_public_settings_tests {
/// reload (the key-deletion scenario).
#[test]
fn test_resets_absent_keys_to_defaults() {
galaxyui::App::test((), |mut app| async move {
galaxyui_core::App::test((), |mut app| async move {
app.update(init_prefs);
app.add_singleton_model(|_| SettingsManager::default());
ReloadTestSettings::register(&mut app);
@@ -272,7 +265,7 @@ mod reload_all_public_settings_tests {
/// This is the property that prevents the infinite watcher loop.
#[test]
fn test_absent_keys_are_not_written_back() {
galaxyui::App::test((), |mut app| async move {
galaxyui_core::App::test((), |mut app| async move {
app.update(init_prefs);
app.add_singleton_model(|_| SettingsManager::default());
ReloadTestSettings::register(&mut app);
@@ -313,7 +306,7 @@ mod reload_all_public_settings_tests {
/// of settings that fail to deserialize (invalid value in file).
#[test]
fn test_reload_returns_failed_keys_for_invalid_values() {
galaxyui::App::test((), |mut app| async move {
galaxyui_core::App::test((), |mut app| async move {
app.update(init_prefs);
app.add_singleton_model(|_| SettingsManager::default());
ReloadTestSettings::register(&mut app);
@@ -354,7 +347,7 @@ mod reload_all_public_settings_tests {
/// when all values are valid.
#[test]
fn test_reload_returns_empty_vec_on_success() {
galaxyui::App::test((), |mut app| async move {
galaxyui_core::App::test((), |mut app| async move {
app.update(init_prefs);
app.add_singleton_model(|_| SettingsManager::default());
ReloadTestSettings::register(&mut app);
@@ -384,8 +377,8 @@ mod reload_all_public_settings_tests {
/// values without modifying in-memory state.
#[test]
fn test_validate_detects_invalid_values() {
galaxyui::App::test((), |mut app| async move {
crate::set_settings_file_enabled(true);
galaxyui_core::App::test((), |mut app| async move {
let _guard = galaxy_features::FeatureFlag::SettingsFile.override_enabled(true);
app.update(init_prefs);
app.add_singleton_model(|_| SettingsManager::default());
ReloadTestSettings::register(&mut app);
@@ -423,8 +416,8 @@ mod reload_all_public_settings_tests {
/// stored values are valid.
#[test]
fn test_validate_returns_empty_when_all_valid() {
galaxyui::App::test((), |mut app| async move {
crate::set_settings_file_enabled(true);
galaxyui_core::App::test((), |mut app| async move {
let _guard = galaxy_features::FeatureFlag::SettingsFile.override_enabled(true);
app.update(init_prefs);
app.add_singleton_model(|_| SettingsManager::default());
ReloadTestSettings::register(&mut app);
@@ -543,6 +536,7 @@ mod write_to_preferences_tests {
use galaxyui_extras::user_preferences::toml_backed::TomlBackedUserPreferences;
use std::collections::HashMap;
#[derive(
Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, schemars::JsonSchema,
)]
@@ -604,7 +598,6 @@ mod write_to_preferences_tests {
/// null-stripping and key-reordering happens.
#[test]
fn test_no_spurious_write_with_toml_backend() {
use galaxyui_extras::user_preferences::toml_backed::TomlBackedUserPreferences;
let dir = tempfile::tempdir().unwrap();
let file_path = dir.path().join("settings.toml");
+1 -2
View File
@@ -1,7 +1,6 @@
//! Schema metadata for settings, used by the JSON Schema generator.
use schemars::Schema;
use schemars::SchemaGenerator;
use schemars::{Schema, SchemaGenerator};
use crate::SupportedPlatforms;
+1 -2
View File
@@ -1,7 +1,6 @@
use std::collections::HashSet;
use schemars::JsonSchema;
use schemars::SchemaGenerator;
use schemars::{JsonSchema, SchemaGenerator};
use crate::schema::SettingSchemaEntry;