@umituz/react-native-settings 4.17.27 → 4.17.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/package.json +15 -4
  2. package/src/domains/about/presentation/components/AboutSection.tsx +14 -71
  3. package/src/domains/appearance/application/ports/IAppearanceRepository.ts +8 -0
  4. package/src/domains/appearance/hooks/index.ts +1 -1
  5. package/src/domains/appearance/hooks/useAppearance.ts +18 -58
  6. package/src/domains/appearance/hooks/useAppearanceActions.ts +20 -128
  7. package/src/domains/appearance/infrastructure/repositories/AppearanceRepository.ts +34 -0
  8. package/src/domains/appearance/infrastructure/services/AppearanceService.ts +51 -0
  9. package/src/domains/appearance/presentation/components/AppearanceSection.tsx +2 -2
  10. package/src/domains/appearance/presentation/hooks/mutations/useAppearanceMutations.ts +36 -0
  11. package/src/domains/appearance/presentation/hooks/queries/useAppearanceQuery.ts +15 -0
  12. package/src/domains/disclaimer/presentation/components/DisclaimerModal.tsx +37 -40
  13. package/src/domains/faqs/presentation/components/FAQSection.tsx +1 -1
  14. package/src/domains/faqs/presentation/screens/FAQScreen.tsx +1 -1
  15. package/src/domains/feedback/presentation/components/FeedbackModal.tsx +11 -15
  16. package/src/domains/feedback/presentation/components/SupportSection.tsx +2 -2
  17. package/src/domains/legal/presentation/components/LegalItem.tsx +13 -129
  18. package/src/index.ts +19 -9
  19. package/src/infrastructure/repositories/SettingsRepository.ts +105 -0
  20. package/src/infrastructure/services/SettingsService.ts +47 -0
  21. package/src/presentation/components/SettingItem.tsx +77 -129
  22. package/src/presentation/components/SettingsFooter.tsx +9 -25
  23. package/src/presentation/components/SettingsSection.tsx +9 -20
  24. package/src/presentation/hooks/mutations/useSettingsMutations.ts +58 -0
  25. package/src/presentation/hooks/queries/useSettingsQuery.ts +27 -0
  26. package/src/presentation/hooks/useSettings.ts +45 -0
  27. package/src/presentation/screens/components/SettingsContent.tsx +20 -247
  28. package/src/presentation/screens/components/sections/CustomSettingsList.tsx +31 -0
  29. package/src/presentation/screens/components/sections/FeatureSettingsSection.tsx +68 -0
  30. package/src/presentation/screens/components/sections/IdentitySettingsSection.tsx +43 -0
  31. package/src/presentation/screens/components/sections/ProfileSectionLoader.tsx +47 -0
  32. package/src/presentation/screens/components/sections/SubscriptionSettingsItem.tsx +157 -0
  33. package/src/presentation/screens/components/sections/SupportSettingsSection.tsx +84 -0
  34. package/src/presentation/screens/hooks/useFeatureDetection.ts +1 -16
  35. package/src/presentation/screens/types/FeatureConfig.ts +35 -10
  36. package/src/presentation/screens/types/SettingsConfig.ts +7 -0
  37. package/src/presentation/screens/types/index.ts +1 -0
  38. package/src/domains/appearance/infrastructure/services/appearanceService.ts +0 -301
  39. package/src/domains/appearance/infrastructure/storage/appearanceStorage.ts +0 -120
  40. package/src/domains/appearance/infrastructure/stores/appearanceStore.ts +0 -132
  41. package/src/infrastructure/storage/SettingsStore.ts +0 -189
  42. package/src/infrastructure/storage/__tests__/SettingsStore.test.tsx +0 -302
  43. package/src/presentation/components/CloudSyncSetting.tsx +0 -58
  44. /package/src/{domain/repositories → application/ports}/ISettingsRepository.ts +0 -0
@@ -0,0 +1,84 @@
1
+ import React from "react";
2
+ import { useLocalization } from "@umituz/react-native-localization";
3
+ import { SupportSection } from "../../../../domains/feedback/presentation/components/SupportSection";
4
+ import { FAQSection } from "../../../../domains/faqs/presentation/components/FAQSection";
5
+ import { SettingsSection } from "../../../components/SettingsSection";
6
+ import { SettingItem } from "../../../components/SettingItem";
7
+
8
+ interface SupportSettingsSectionProps {
9
+ features: any;
10
+ normalizedConfig: any;
11
+ }
12
+
13
+ export const SupportSettingsSection: React.FC<SupportSettingsSectionProps> = ({
14
+ features,
15
+ normalizedConfig,
16
+ }) => {
17
+ const { t } = useLocalization();
18
+
19
+ if (!(features.feedback || features.rating || features.faqs)) return null;
20
+
21
+ return (
22
+ <SettingsSection title={t("settings.support.title")}>
23
+ {(features.feedback || features.rating) && (
24
+ <SupportSection
25
+ renderSection={(props: any) => <>{props.children}</>}
26
+ renderItem={(props: any) => <SettingItem {...props} />}
27
+ feedbackConfig={{
28
+ enabled: features.feedback,
29
+ config: {
30
+ ...normalizedConfig.feedback.config,
31
+ title: normalizedConfig.feedback.config?.title || t("settings.feedback.title"),
32
+ description: normalizedConfig.feedback.config?.description || t("settings.feedback.description"),
33
+ }
34
+ }}
35
+ ratingConfig={{
36
+ enabled: features.rating,
37
+ config: {
38
+ ...normalizedConfig.rating.config,
39
+ title: normalizedConfig.rating.config?.title || t("settings.rating.title"),
40
+ description: normalizedConfig.rating.config?.description || t("settings.rating.description"),
41
+ }
42
+ }}
43
+ feedbackModalTexts={{
44
+ title: t("settings.feedback.modal.title"),
45
+ ratingLabel: t("settings.feedback.modal.ratingLabel"),
46
+ descriptionPlaceholder: t("settings.feedback.modal.descriptionPlaceholder"),
47
+ submitButton: t("settings.feedback.modal.submitButton"),
48
+ submittingButton: t("settings.feedback.modal.submittingButton"),
49
+ feedbackTypes: [
50
+ { type: 'general', label: t("settings.feedback.types.general") },
51
+ { type: 'bug_report', label: t("settings.feedback.types.bugReport") },
52
+ { type: 'feature_request', label: t("settings.feedback.types.featureRequest") },
53
+ { type: 'improvement', label: t("settings.feedback.types.improvement") },
54
+ { type: 'other', label: t("settings.feedback.types.other") },
55
+ ],
56
+ defaultTitle: (type) => {
57
+ const titles: Record<string, string> = {
58
+ general: t("settings.feedback.types.general"),
59
+ bug_report: t("settings.feedback.types.bugReport"),
60
+ feature_request: t("settings.feedback.types.featureRequest"),
61
+ improvement: t("settings.feedback.types.improvement"),
62
+ other: t("settings.feedback.types.other"),
63
+ };
64
+ return titles[type] || type;
65
+ },
66
+ }}
67
+ />
68
+ )}
69
+
70
+ {features.faqs && (
71
+ <FAQSection
72
+ renderSection={(props: any) => <>{props.children}</>}
73
+ renderItem={(props: any) => <SettingItem {...props} />}
74
+ config={{
75
+ enabled: features.faqs,
76
+ ...normalizedConfig.faqs.config,
77
+ title: normalizedConfig.faqs.config?.title || t("settings.faqs.title"),
78
+ description: normalizedConfig.faqs.config?.description || t("settings.faqs.description"),
79
+ }}
80
+ />
81
+ )}
82
+ </SettingsSection>
83
+ );
84
+ };
@@ -6,20 +6,6 @@
6
6
  import { useMemo } from "react";
7
7
  import type { NormalizedConfig } from "../utils/normalizeConfig";
8
8
 
9
- // Optional notification service
10
- let notificationService: {
11
- hasPermissions?: () => Promise<boolean>;
12
- requestPermissions?: () => Promise<void>;
13
- } | null = null;
14
- try {
15
- // eslint-disable-next-line @typescript-eslint/no-require-imports
16
- const module = require("@umituz/react-native-notifications");
17
- if (module?.notificationService && typeof module.notificationService === 'object') {
18
- notificationService = module.notificationService;
19
- }
20
- } catch {
21
- // Package not available
22
- }
23
9
 
24
10
  /**
25
11
  * Check if navigation screen exists
@@ -75,8 +61,7 @@ export function useFeatureDetection(
75
61
  faqs,
76
62
  } = normalizedConfig;
77
63
 
78
- const notificationServiceAvailable =
79
- options?.notificationServiceAvailable ?? notificationService !== null;
64
+ const notificationServiceAvailable = !!options?.notificationServiceAvailable;
80
65
 
81
66
  return {
82
67
  appearance:
@@ -149,22 +149,29 @@ export interface UserProfileConfig {
149
149
  accountSettingsRoute?: string;
150
150
  }
151
151
 
152
+ /**
153
+ * Subscription Settings Item Config
154
+ * Simplified config for settings list item display
155
+ */
156
+ export interface SubscriptionSettingsItemConfig {
157
+ title: string;
158
+ description?: string;
159
+ isPremium: boolean;
160
+ statusLabel: string;
161
+ icon?: string;
162
+ onPress?: () => void;
163
+ }
164
+
152
165
  /**
153
166
  * Subscription Settings Configuration
154
- * App must provide all data via sectionConfig (no internal fetch)
167
+ * App must provide all data via props (no internal fetch)
155
168
  */
156
169
  export interface SubscriptionConfig {
157
170
  /** Show subscription section */
158
171
  enabled?: FeatureVisibility;
159
- /** Custom subscription title */
160
- title?: string;
161
- /** Custom subscription description */
162
- description?: string;
163
- /** Custom icon name (Ionicons) */
164
- icon?: string;
165
- /** Custom section title for grouping */
166
- sectionTitle?: string;
167
- /** Section configuration (app provides all data) */
172
+ /** Settings item configuration (for settings list display) */
173
+ settingsItem?: SubscriptionSettingsItemConfig;
174
+ /** Detail section configuration (for detail screen) */
168
175
  sectionConfig?: {
169
176
  statusType: "active" | "expired" | "none";
170
177
  isPremium: boolean;
@@ -248,3 +255,21 @@ export interface RatingConfig {
248
255
  /** Custom handler for rating action (e.g. open store review) */
249
256
  onRate?: () => void;
250
257
  }
258
+
259
+ /**
260
+ * Cloud Sync Settings Configuration
261
+ */
262
+ export interface CloudSyncConfig {
263
+ /** Enable cloud sync feature */
264
+ enabled?: FeatureVisibility;
265
+ /** Custom title for the sync section */
266
+ title?: string;
267
+ /** Custom description for the sync toggle */
268
+ description?: string;
269
+ /** Custom icon name (Ionicons) */
270
+ icon?: string;
271
+ /** Custom section title for grouping */
272
+ sectionTitle?: string;
273
+ /** Firestore collection name */
274
+ collectionName?: string;
275
+ }
@@ -16,6 +16,7 @@ import type {
16
16
  FeedbackConfig,
17
17
  RatingConfig,
18
18
  FAQConfig,
19
+ CloudSyncConfig,
19
20
  } from "./FeatureConfig";
20
21
 
21
22
  /**
@@ -115,6 +116,12 @@ export interface SettingsConfig {
115
116
  */
116
117
  faqs?: FeatureVisibility | FAQConfig;
117
118
 
119
+ /**
120
+ * Cloud sync settings configuration
121
+ * @default false
122
+ */
123
+ cloudSync?: FeatureVisibility | CloudSyncConfig;
124
+
118
125
  /**
119
126
  * Custom empty state text when no settings are available
120
127
  */
@@ -13,6 +13,7 @@ export type {
13
13
  DisclaimerConfig,
14
14
  UserProfileConfig,
15
15
  SubscriptionConfig,
16
+ SubscriptionSettingsItemConfig,
16
17
  FeedbackConfig,
17
18
  RatingConfig,
18
19
  FAQConfig,
@@ -1,301 +0,0 @@
1
- /**
2
- * Appearance Service
3
- *
4
- * Business logic for appearance management
5
- * Single Responsibility: Business logic only, no presentation logic
6
- */
7
-
8
- import { AppearanceStorage } from "../storage/appearanceStorage";
9
- import { useAppearanceStore } from "../stores/appearanceStore";
10
- import {
11
- useTheme,
12
- useDesignSystemTheme,
13
- type ThemeMode,
14
- type CustomThemeColors,
15
- } from "@umituz/react-native-design-system";
16
- import { getSystemTheme } from "./systemThemeDetection";
17
- import { validateAppearanceSettings } from "./validation";
18
- import type { AppearanceSettings } from "../../types";
19
-
20
- export class AppearanceService {
21
- private readonly DEFAULT_THEME_MODE: ThemeMode = "light"; // Use system preference as default
22
- private _isInitialized = false;
23
- private initPromise: Promise<void> | null = null;
24
-
25
- /**
26
- * Initialize appearance settings
27
- * Business logic: Coordinate initialization process
28
- */
29
- async initialize(): Promise<void> {
30
- // Prevent multiple initializations
31
- if (this._isInitialized || this.initPromise) {
32
- return this.initPromise || Promise.resolve();
33
- }
34
-
35
- this.initPromise = this._performInitialization();
36
- return this.initPromise;
37
- }
38
-
39
- private async _performInitialization(): Promise<void> {
40
- try {
41
- if (__DEV__) {
42
- console.log("[AppearanceService] Initializing appearance settings");
43
- }
44
-
45
- const savedSettings = await AppearanceStorage.getSettings();
46
-
47
- if (savedSettings) {
48
- // Load saved settings
49
- useAppearanceStore.getState().setSettings(savedSettings);
50
- useAppearanceStore.getState().setInitialized(true);
51
-
52
- // Sync with design system theme
53
- await this.syncWithDesignSystem(savedSettings);
54
- } else {
55
- // Use system theme as default, fallback to light
56
- const systemTheme = getSystemTheme();
57
- const defaultSettings: AppearanceSettings = {
58
- themeMode: systemTheme || this.DEFAULT_THEME_MODE,
59
- };
60
-
61
- useAppearanceStore.getState().setSettings(defaultSettings);
62
- useAppearanceStore.getState().setInitialized(true);
63
-
64
- // Sync with design system theme
65
- await this.syncWithDesignSystem(defaultSettings);
66
- }
67
-
68
- this._isInitialized = true;
69
- } catch (error) {
70
- if (__DEV__) {
71
- console.error("[AppearanceService] Initialization failed:", error);
72
- }
73
-
74
- // Fallback to system theme or light mode on error
75
- const systemTheme = getSystemTheme();
76
- const fallbackSettings: AppearanceSettings = {
77
- themeMode: systemTheme || this.DEFAULT_THEME_MODE,
78
- };
79
-
80
- useAppearanceStore.getState().setSettings(fallbackSettings);
81
- useAppearanceStore.getState().setInitialized(true);
82
-
83
- await this.syncWithDesignSystem(fallbackSettings);
84
- this._isInitialized = true;
85
- } finally {
86
- this.initPromise = null;
87
- }
88
- }
89
-
90
- /**
91
- * Get current theme mode
92
- * Business logic: Provide theme mode data
93
- */
94
- getThemeMode(): ThemeMode {
95
- return useAppearanceStore.getState().settings.themeMode;
96
- }
97
-
98
- /**
99
- * Set theme mode
100
- * Business logic: Validate and apply theme mode
101
- */
102
- async setThemeMode(mode: ThemeMode): Promise<void> {
103
- try {
104
- if (__DEV__) {
105
- console.log("[AppearanceService] Setting theme mode:", mode);
106
- }
107
-
108
- // Validate theme mode
109
- if (!mode || (mode !== 'light' && mode !== 'dark')) {
110
- throw new Error(`Invalid theme mode: ${mode}`);
111
- }
112
-
113
- const currentSettings = useAppearanceStore.getState().settings;
114
- const newSettings: AppearanceSettings = {
115
- ...currentSettings,
116
- themeMode: mode,
117
- };
118
-
119
- // Update store
120
- useAppearanceStore.getState().updateThemeMode(mode);
121
-
122
- // Persist to storage
123
- await AppearanceStorage.setSettings(newSettings);
124
-
125
- // Sync with design system
126
- await this.syncWithDesignSystem(newSettings);
127
- } catch (error) {
128
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
129
- if (__DEV__) {
130
- console.error("[AppearanceService] Failed to set theme mode:", errorMessage);
131
- }
132
- throw error;
133
- }
134
- }
135
-
136
- /**
137
- * Toggle theme mode
138
- * Business logic: Toggle between light and dark
139
- */
140
- async toggleTheme(): Promise<void> {
141
- try {
142
- const currentMode = this.getThemeMode();
143
- const newMode: ThemeMode =
144
- currentMode === "light" ? "dark" : "light";
145
-
146
- await this.setThemeMode(newMode);
147
- } catch (error) {
148
- if (__DEV__) {
149
- console.error("[AppearanceService] Failed to toggle theme:", error);
150
- }
151
- throw error;
152
- }
153
- }
154
-
155
- /**
156
- * Get custom colors
157
- * Business logic: Provide custom colors data
158
- */
159
- getCustomColors(): CustomThemeColors | undefined {
160
- return useAppearanceStore.getState().settings.customColors;
161
- }
162
-
163
- /**
164
- * Set custom colors
165
- * Business logic: Validate and apply custom colors
166
- */
167
- async setCustomColors(colors: CustomThemeColors): Promise<void> {
168
- try {
169
- if (__DEV__) {
170
- console.log("[AppearanceService] Setting custom colors:", colors);
171
- }
172
-
173
- // Validate custom colors
174
- const validation = validateAppearanceSettings({ customColors: colors });
175
- if (!validation.isValid) {
176
- throw new Error(`Invalid custom colors: ${validation.errors.join(', ')}`);
177
- }
178
-
179
- const currentSettings = useAppearanceStore.getState().settings;
180
- const newSettings: AppearanceSettings = {
181
- ...currentSettings,
182
- customColors: {
183
- ...currentSettings.customColors,
184
- ...colors,
185
- },
186
- };
187
-
188
- // Update store
189
- useAppearanceStore.getState().updateCustomColors(newSettings.customColors);
190
-
191
- // Persist to storage
192
- await AppearanceStorage.setSettings(newSettings);
193
-
194
- // Sync with design system
195
- await this.syncWithDesignSystem(newSettings);
196
- } catch (error) {
197
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
198
- if (__DEV__) {
199
- console.error("[AppearanceService] Failed to set custom colors:", errorMessage);
200
- }
201
- throw error;
202
- }
203
- }
204
-
205
- /**
206
- * Reset custom colors to defaults
207
- * Business logic: Reset custom colors
208
- */
209
- async resetCustomColors(): Promise<void> {
210
- try {
211
- if (__DEV__) {
212
- console.log("[AppearanceService] Resetting custom colors");
213
- }
214
-
215
- const currentSettings = useAppearanceStore.getState().settings;
216
- const newSettings: AppearanceSettings = {
217
- ...currentSettings,
218
- customColors: undefined,
219
- };
220
-
221
- // Update store
222
- useAppearanceStore.getState().updateCustomColors(undefined);
223
-
224
- // Persist to storage
225
- await AppearanceStorage.setSettings(newSettings);
226
-
227
- // Sync with design System
228
- await this.syncWithDesignSystem(newSettings);
229
- } catch (error) {
230
- if (__DEV__) {
231
- console.error("[AppearanceService] Failed to reset custom colors:", error);
232
- }
233
- throw error;
234
- }
235
- }
236
-
237
- /**
238
- * Reset all appearance settings
239
- * Business logic: Reset all settings
240
- */
241
- async reset(): Promise<void> {
242
- try {
243
- if (__DEV__) {
244
- console.log("[AppearanceService] Resetting all appearance settings");
245
- }
246
-
247
- // Clear storage
248
- await AppearanceStorage.clear();
249
-
250
- // Reset store to defaults
251
- useAppearanceStore.getState().resetState();
252
-
253
- // Reset design system theme to system preference
254
- const systemTheme = getSystemTheme();
255
- const defaultSettings: AppearanceSettings = {
256
- themeMode: systemTheme || this.DEFAULT_THEME_MODE,
257
- };
258
-
259
- await this.syncWithDesignSystem(defaultSettings);
260
- } catch (error) {
261
- if (__DEV__) {
262
- console.error("[AppearanceService] Failed to reset appearance:", error);
263
- }
264
- throw error;
265
- }
266
- }
267
-
268
- /**
269
- * Check if appearance is initialized
270
- * Business logic: Provide initialization status
271
- */
272
- isInitialized(): boolean {
273
- return useAppearanceStore.getState().isInitialized;
274
- }
275
-
276
- /**
277
- * Sync appearance settings with design system
278
- * Private helper method
279
- */
280
- private async syncWithDesignSystem(settings: AppearanceSettings): Promise<void> {
281
- try {
282
- // Sync theme mode
283
- useTheme.getState().setThemeMode(settings.themeMode);
284
- useDesignSystemTheme.getState().setThemeMode(settings.themeMode);
285
-
286
- // Sync custom colors
287
- useDesignSystemTheme.getState().setCustomColors(settings.customColors);
288
-
289
- if (__DEV__) {
290
- console.log("[AppearanceService] Synced with design system:", settings);
291
- }
292
- } catch (error) {
293
- if (__DEV__) {
294
- console.error("[AppearanceService] Failed to sync with design system:", error);
295
- }
296
- throw error;
297
- }
298
- }
299
- }
300
-
301
- export const appearanceService = new AppearanceService();
@@ -1,120 +0,0 @@
1
- /**
2
- * Appearance Storage Service
3
- *
4
- * Handles persistence of appearance settings using AsyncStorage
5
- * Single Responsibility: Pure storage operations only
6
- */
7
-
8
- import { storageRepository, unwrap } from "@umituz/react-native-storage";
9
- import type { ThemeMode } from "@umituz/react-native-design-system";
10
- import type { AppearanceSettings } from "../../types";
11
-
12
- const STORAGE_KEYS = {
13
- APPEARANCE_SETTINGS: "@appearance_settings",
14
- } as const;
15
-
16
- const DEFAULT_SETTINGS: AppearanceSettings = {
17
- themeMode: "dark",
18
- };
19
-
20
- export class AppearanceStorage {
21
- /**
22
- * Get saved appearance settings
23
- * Pure storage operation - no business logic
24
- */
25
- static async getSettings(): Promise<AppearanceSettings | null> {
26
- try {
27
- const result = await storageRepository.getItem<AppearanceSettings>(
28
- STORAGE_KEYS.APPEARANCE_SETTINGS,
29
- DEFAULT_SETTINGS,
30
- );
31
- const data = unwrap(result, DEFAULT_SETTINGS);
32
- return data;
33
- } catch (error) {
34
- return null;
35
- }
36
- }
37
-
38
- /**
39
- * Save appearance settings
40
- * Pure storage operation - no business logic
41
- */
42
- static async setSettings(settings: AppearanceSettings): Promise<void> {
43
- const result = await storageRepository.setItem(
44
- STORAGE_KEYS.APPEARANCE_SETTINGS,
45
- settings,
46
- );
47
- if (!result.success) {
48
- throw new Error("Failed to save appearance settings");
49
- }
50
- }
51
-
52
- /**
53
- * Get saved theme mode
54
- * Pure storage operation - no business logic
55
- */
56
- static async getThemeMode(): Promise<ThemeMode | null> {
57
- try {
58
- const settings = await this.getSettings();
59
- return settings?.themeMode || null;
60
- } catch (error) {
61
- return null;
62
- }
63
- }
64
-
65
- /**
66
- * Save theme mode
67
- * Pure storage operation - no business logic
68
- */
69
- static async setThemeMode(themeMode: ThemeMode): Promise<void> {
70
- const currentSettings = (await this.getSettings()) || {
71
- themeMode: "dark",
72
- };
73
- await this.setSettings({
74
- ...currentSettings,
75
- themeMode,
76
- });
77
- }
78
-
79
- /**
80
- * Get custom theme colors
81
- * Pure storage operation - no business logic
82
- */
83
- static async getCustomColors() {
84
- try {
85
- const settings = await this.getSettings();
86
- return settings?.customColors || null;
87
- } catch (error) {
88
- return null;
89
- }
90
- }
91
-
92
- /**
93
- * Save custom theme colors
94
- * Pure storage operation - no business logic
95
- */
96
- static async setCustomColors(
97
- customColors: AppearanceSettings["customColors"],
98
- ): Promise<void> {
99
- const currentSettings = (await this.getSettings()) || {
100
- themeMode: "dark",
101
- };
102
- await this.setSettings({
103
- ...currentSettings,
104
- customColors,
105
- });
106
- }
107
-
108
- /**
109
- * Clear all appearance settings
110
- * Pure storage operation - no business logic
111
- */
112
- static async clear(): Promise<void> {
113
- const result = await storageRepository.removeItem(
114
- STORAGE_KEYS.APPEARANCE_SETTINGS,
115
- );
116
- if (!result.success) {
117
- throw new Error("Failed to clear appearance settings");
118
- }
119
- }
120
- }