@umituz/react-native-settings 4.17.26 → 4.17.30

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 (41) hide show
  1. package/package.json +15 -6
  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/feedback/presentation/components/FeedbackModal.tsx +11 -15
  15. package/src/domains/feedback/presentation/components/SupportSection.tsx +2 -2
  16. package/src/domains/legal/presentation/components/LegalItem.tsx +13 -129
  17. package/src/index.ts +15 -9
  18. package/src/infrastructure/repositories/SettingsRepository.ts +105 -0
  19. package/src/infrastructure/services/SettingsService.ts +47 -0
  20. package/src/presentation/components/SettingItem.tsx +77 -129
  21. package/src/presentation/components/SettingsFooter.tsx +9 -25
  22. package/src/presentation/components/SettingsSection.tsx +9 -20
  23. package/src/presentation/hooks/mutations/useSettingsMutations.ts +58 -0
  24. package/src/presentation/hooks/queries/useSettingsQuery.ts +27 -0
  25. package/src/presentation/hooks/useSettings.ts +45 -0
  26. package/src/presentation/screens/components/SettingsContent.tsx +20 -247
  27. package/src/presentation/screens/components/sections/CustomSettingsList.tsx +31 -0
  28. package/src/presentation/screens/components/sections/FeatureSettingsSection.tsx +55 -0
  29. package/src/presentation/screens/components/sections/IdentitySettingsSection.tsx +43 -0
  30. package/src/presentation/screens/components/sections/ProfileSectionLoader.tsx +47 -0
  31. package/src/presentation/screens/components/sections/SupportSettingsSection.tsx +84 -0
  32. package/src/presentation/screens/hooks/useFeatureDetection.ts +1 -16
  33. package/src/presentation/screens/types/FeatureConfig.ts +18 -0
  34. package/src/presentation/screens/types/SettingsConfig.ts +7 -0
  35. package/src/domains/appearance/infrastructure/services/appearanceService.ts +0 -301
  36. package/src/domains/appearance/infrastructure/storage/appearanceStorage.ts +0 -120
  37. package/src/domains/appearance/infrastructure/stores/appearanceStore.ts +0 -132
  38. package/src/infrastructure/storage/SettingsStore.ts +0 -189
  39. package/src/infrastructure/storage/__tests__/SettingsStore.test.tsx +0 -302
  40. package/src/presentation/components/CloudSyncSetting.tsx +0 -58
  41. /package/src/{domain/repositories → application/ports}/ISettingsRepository.ts +0 -0
@@ -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
- }
@@ -1,132 +0,0 @@
1
- /**
2
- * Appearance Store
3
- *
4
- * Zustand store for appearance state management
5
- * Single Responsibility: Pure state management only
6
- */
7
-
8
- import { create } from "zustand";
9
- import type { AppearanceSettings, AppearanceState } from "../../types";
10
-
11
- interface AppearanceStoreActions {
12
- // Pure state mutations only
13
- setSettings: (settings: AppearanceSettings) => void;
14
- setInitialized: (initialized: boolean) => void;
15
- updateThemeMode: (mode: AppearanceSettings["themeMode"]) => void;
16
- updateCustomColors: (colors: AppearanceSettings["customColors"]) => void;
17
- resetState: () => void;
18
- }
19
-
20
- type AppearanceStore = AppearanceState & AppearanceStoreActions;
21
-
22
- const DEFAULT_SETTINGS: AppearanceSettings = {
23
- themeMode: "dark", // Use dark mode as default
24
- };
25
-
26
- export const useAppearanceStore = create<AppearanceStore>((set, get) => ({
27
- settings: DEFAULT_SETTINGS,
28
- isInitialized: false,
29
-
30
- // Pure state mutations with performance optimizations
31
- setSettings: (settings: AppearanceSettings) => {
32
- // Prevent unnecessary updates if settings are the same
33
- const currentSettings = get().settings;
34
- if (JSON.stringify(currentSettings) === JSON.stringify(settings)) {
35
- if (__DEV__) {
36
- console.log("[AppearanceStore] Skipping settings update - no changes");
37
- }
38
- return;
39
- }
40
-
41
- if (__DEV__) {
42
- console.log("[AppearanceStore] Setting appearance settings:", settings);
43
- }
44
- set({ settings });
45
- },
46
-
47
- setInitialized: (initialized: boolean) => {
48
- // Prevent unnecessary updates if state is the same
49
- const currentInitialized = get().isInitialized;
50
- if (currentInitialized === initialized) {
51
- if (__DEV__) {
52
- console.log("[AppearanceStore] Skipping initialized update - no change");
53
- }
54
- return;
55
- }
56
-
57
- if (__DEV__) {
58
- console.log("[AppearanceStore] Setting initialized state:", initialized);
59
- }
60
- set({ isInitialized: initialized });
61
- },
62
-
63
- updateThemeMode: (mode: AppearanceSettings["themeMode"]) => {
64
- const currentSettings = get().settings;
65
-
66
- // Prevent unnecessary updates if mode is the same
67
- if (currentSettings.themeMode === mode) {
68
- if (__DEV__) {
69
- console.log("[AppearanceStore] Skipping theme mode update - no change");
70
- }
71
- return;
72
- }
73
-
74
- const newSettings: AppearanceSettings = {
75
- ...currentSettings,
76
- themeMode: mode,
77
- };
78
-
79
- if (__DEV__) {
80
- console.log("[AppearanceStore] Updating theme mode:", mode);
81
- }
82
-
83
- set({ settings: newSettings });
84
- },
85
-
86
- updateCustomColors: (colors: AppearanceSettings["customColors"]) => {
87
- const currentSettings = get().settings;
88
-
89
- // Prevent unnecessary updates if colors are the same
90
- if (JSON.stringify(currentSettings.customColors) === JSON.stringify(colors)) {
91
- if (__DEV__) {
92
- console.log("[AppearanceStore] Skipping custom colors update - no changes");
93
- }
94
- return;
95
- }
96
-
97
- const newSettings: AppearanceSettings = {
98
- ...currentSettings,
99
- customColors: colors,
100
- };
101
-
102
- if (__DEV__) {
103
- console.log("[AppearanceStore] Updating custom colors:", colors);
104
- }
105
-
106
- set({ settings: newSettings });
107
- },
108
-
109
- resetState: () => {
110
- const currentState = get();
111
-
112
- // Prevent unnecessary reset if already at default
113
- if (
114
- currentState.isInitialized === false &&
115
- JSON.stringify(currentState.settings) === JSON.stringify(DEFAULT_SETTINGS)
116
- ) {
117
- if (__DEV__) {
118
- console.log("[AppearanceStore] Skipping reset - already at default state");
119
- }
120
- return;
121
- }
122
-
123
- if (__DEV__) {
124
- console.log("[AppearanceStore] Resetting to default state");
125
- }
126
-
127
- set({
128
- settings: DEFAULT_SETTINGS,
129
- isInitialized: false,
130
- });
131
- },
132
- }));