@focus8/settings-registry 0.1.0

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.
@@ -0,0 +1,318 @@
1
+ /**
2
+ * Settings Registry — single source of truth for ALL FocusPlanner app settings.
3
+ *
4
+ * This shared package defines every setting key, its category, data type,
5
+ * default value, and whether it should be synced to the server.
6
+ *
7
+ * Used by:
8
+ * - The mobile app (local SQLite settings table, React Query hooks)
9
+ * - The API (validate & serialize settings profiles)
10
+ * - The web portal (render settings viewer/editor)
11
+ *
12
+ * App-specific defaults (theme, locale, enrolled mode) are parameterized
13
+ * via `createRegistry(config)`.
14
+ */
15
+ export type ThemeSetting = 'light' | 'dark' | 'system';
16
+ export type AlarmSound = 'none' | 'alarm1' | 'alarm2' | 'alarm3' | 'alarm4' | 'alarm5' | 'alarm6' | 'alarm7' | 'alarm8' | 'alarm9';
17
+ export type LocaleCode = 'en' | 'nb';
18
+ export type CalendarType = 'chronological' | 'time-based';
19
+ export type ClockType = 'digital' | 'analog';
20
+ export type TimePickerMode = 'dials' | 'keypad';
21
+ export type AlarmTimeout = 1 | 2 | 3 | 5 | 10;
22
+ export declare const ALARM_TIMEOUTS: AlarmTimeout[];
23
+ export type CalendarViewMode = 'day' | '3-days' | '5-days' | '7-days' | 'week' | 'month' | 'overview';
24
+ export type CalendarDayViewCellZoom = 15 | 30 | 60;
25
+ export type InactivityTimeoutMinutes = 1 | 5 | 10 | 15 | 30 | 45;
26
+ export type LockScreenClockDisplay = 'none' | 'digital' | 'analog';
27
+ export type LockScreenImageMode = 'none' | 'background' | 'photoFrame';
28
+ export type PhotoFrameIntervalSeconds = 30 | 60 | 120 | 300;
29
+ export type EventVisibility = 'Public' | 'Private' | 'Custom';
30
+ export type SuggestEndTimeUnit = 'minutes' | 'hours';
31
+ export type WeatherLocation = {
32
+ address: string;
33
+ name?: string;
34
+ latitude: number;
35
+ longitude: number;
36
+ placeId?: string;
37
+ };
38
+ export type LockScreenImage = {
39
+ uri: string;
40
+ filePath: string;
41
+ fileName?: string;
42
+ fileSize?: number;
43
+ width?: number;
44
+ height?: number;
45
+ order: number;
46
+ };
47
+ export declare const LOCK_SCREEN_MAX_IMAGES = 10;
48
+ export type AllDayPreset = {
49
+ daysBefore: number;
50
+ time: string;
51
+ };
52
+ export declare const SETTINGS_CATEGORIES: readonly ["appearance", "calendarView", "calendars", "sound", "timer", "media", "lockScreen", "touch", "device", "language", "notification", "chronological", "eventForm", "chronologicalEventForm"];
53
+ export type SettingsCategory = (typeof SETTINGS_CATEGORIES)[number];
54
+ export type SettingsDataType = 'string' | 'number' | 'boolean' | 'json';
55
+ export type SettingDef<T = unknown> = {
56
+ category: SettingsCategory;
57
+ type: SettingsDataType;
58
+ default: T;
59
+ /** Whether this setting should be synced to the server. Default true. */
60
+ sync: boolean;
61
+ };
62
+ export type RegistryConfig = {
63
+ /** Whether the device is in enrolled/kiosk mode */
64
+ isEnrolled: boolean;
65
+ /** Default theme code */
66
+ defaultTheme: ThemeSetting;
67
+ /** Default locale code */
68
+ defaultLocale: LocaleCode;
69
+ };
70
+ /** Default config for non-enrolled mode */
71
+ export declare const DEFAULT_REGISTRY_CONFIG: RegistryConfig;
72
+ declare function buildEntries(config: RegistryConfig): {
73
+ readonly 'appearance.theme': SettingDef<ThemeSetting>;
74
+ readonly 'appearance.clockType': SettingDef<ClockType>;
75
+ readonly 'appearance.enableDayColors': SettingDef<boolean>;
76
+ readonly 'calendarView.type': SettingDef<CalendarType>;
77
+ readonly 'calendarView.view': SettingDef<CalendarViewMode>;
78
+ readonly 'calendarView.dayViewZoom': SettingDef<CalendarDayViewCellZoom>;
79
+ readonly 'calendarView.weekViewZoom': SettingDef<CalendarDayViewCellZoom>;
80
+ readonly 'calendarView.splitView': SettingDef<boolean>;
81
+ readonly 'calendarView.showCalendarNames': SettingDef<boolean>;
82
+ readonly 'calendarView.calendarColumns': SettingDef<unknown[]>;
83
+ readonly 'calendarView.autoReturnToTodayEnabled': SettingDef<boolean>;
84
+ readonly 'calendarView.autoReturnToTodayTimeoutSeconds': SettingDef<number>;
85
+ readonly 'calendarView.showWeatherOnEvents': SettingDef<boolean>;
86
+ readonly 'calendarView.showWeatherOnTimeline': SettingDef<boolean>;
87
+ readonly 'calendarView.weatherLocation': SettingDef<WeatherLocation | null>;
88
+ readonly 'eventForm.recurrence': SettingDef<boolean>;
89
+ readonly 'eventForm.reminders': SettingDef<boolean>;
90
+ readonly 'eventForm.emailReminders': SettingDef<boolean>;
91
+ readonly 'eventForm.location': SettingDef<boolean>;
92
+ readonly 'eventForm.travelTime': SettingDef<boolean>;
93
+ readonly 'eventForm.description': SettingDef<boolean>;
94
+ readonly 'eventForm.checklist': SettingDef<boolean>;
95
+ readonly 'eventForm.images': SettingDef<boolean>;
96
+ readonly 'eventForm.audioClips': SettingDef<boolean>;
97
+ readonly 'eventForm.notificationReceivers': SettingDef<boolean>;
98
+ readonly 'eventForm.visibility': SettingDef<boolean>;
99
+ readonly 'sound.timerVolume': SettingDef<number>;
100
+ readonly 'sound.reminderVolume': SettingDef<number>;
101
+ readonly 'sound.mediaVolume': SettingDef<number>;
102
+ readonly 'sound.alarmSound': SettingDef<AlarmSound>;
103
+ readonly 'sound.reminderAlarmSound': SettingDef<AlarmSound>;
104
+ readonly 'sound.timerAlarmSound': SettingDef<AlarmSound>;
105
+ readonly 'sound.timerAlarmTimeout': SettingDef<AlarmTimeout>;
106
+ readonly 'sound.reminderAlarmTimeout': SettingDef<AlarmTimeout>;
107
+ readonly 'sound.allowCustomReminderSounds': SettingDef<boolean>;
108
+ readonly 'sound.ttsEnabled': SettingDef<boolean>;
109
+ readonly 'sound.ttsRate': SettingDef<number>;
110
+ readonly 'timer.showTimeRemaining': SettingDef<boolean>;
111
+ readonly 'timer.showEndTime': SettingDef<boolean>;
112
+ readonly 'timer.showRestartButton': SettingDef<boolean>;
113
+ readonly 'timer.showPauseButton': SettingDef<boolean>;
114
+ readonly 'lockScreen.pin': SettingDef<string>;
115
+ readonly 'lockScreen.inactivityLockEnabled': SettingDef<boolean>;
116
+ readonly 'lockScreen.inactivityTimeoutMinutes': SettingDef<InactivityTimeoutMinutes>;
117
+ readonly 'lockScreen.clockDisplay': SettingDef<LockScreenClockDisplay>;
118
+ readonly 'lockScreen.showDate': SettingDef<boolean>;
119
+ readonly 'lockScreen.showHourNumbers': SettingDef<boolean>;
120
+ readonly 'lockScreen.imageMode': SettingDef<LockScreenImageMode>;
121
+ readonly 'lockScreen.backgroundImage': SettingDef<string | null>;
122
+ readonly 'lockScreen.photoFrameImages': SettingDef<LockScreenImage[]>;
123
+ readonly 'lockScreen.photoFrameIntervalSeconds': SettingDef<PhotoFrameIntervalSeconds>;
124
+ readonly 'touch.enableTapToCreate': SettingDef<boolean>;
125
+ readonly 'touch.enableDragDrop': SettingDef<boolean>;
126
+ readonly 'device.id': SettingDef<string>;
127
+ readonly 'device.timePickerMode': SettingDef<TimePickerMode>;
128
+ readonly 'device.devMenuEnabled': SettingDef<boolean>;
129
+ readonly 'device.authWarningDismissTtlDays': SettingDef<number>;
130
+ readonly 'language.locale': SettingDef<LocaleCode>;
131
+ readonly 'notification.enabled': SettingDef<boolean>;
132
+ readonly 'notification.notifyAllCalendars': SettingDef<boolean>;
133
+ readonly 'notification.enabledCalendarIds': SettingDef<string[]>;
134
+ readonly 'notification.hasBeenPrompted': SettingDef<boolean>;
135
+ readonly 'chronological.header.showNavigationArrows': SettingDef<boolean>;
136
+ readonly 'chronological.header.showClock': SettingDef<boolean>;
137
+ readonly 'chronological.header.showCurrentYearInDate': SettingDef<boolean>;
138
+ readonly 'chronological.header.showTimeOfDay': SettingDef<boolean>;
139
+ readonly 'chronological.footer.showMenuButton': SettingDef<boolean>;
140
+ readonly 'chronological.footer.showViewSwitcherDay': SettingDef<boolean>;
141
+ readonly 'chronological.footer.showViewSwitcherWeek': SettingDef<boolean>;
142
+ readonly 'chronological.footer.showViewSwitcherMonth': SettingDef<boolean>;
143
+ readonly 'chronological.footer.showTimerButton': SettingDef<boolean>;
144
+ readonly 'chronological.footer.showNewEventButton': SettingDef<boolean>;
145
+ readonly 'chronological.footer.showSettingsButton': SettingDef<boolean>;
146
+ readonly 'chronological.timer.showNewCountdown': SettingDef<boolean>;
147
+ readonly 'chronological.timer.showFromTemplate': SettingDef<boolean>;
148
+ readonly 'chronological.timer.showEditTemplate': SettingDef<boolean>;
149
+ readonly 'chronological.timer.showDeleteTemplate': SettingDef<boolean>;
150
+ readonly 'chronological.timer.showAddTemplate': SettingDef<boolean>;
151
+ readonly 'chronological.menu.showSettingsButton': SettingDef<boolean>;
152
+ readonly 'chronological.quickSettings.showTimerVolume': SettingDef<boolean>;
153
+ readonly 'chronological.quickSettings.showReminderVolume': SettingDef<boolean>;
154
+ readonly 'chronological.quickSettings.showMediaVolume': SettingDef<boolean>;
155
+ readonly 'chronological.quickSettings.showBrightness': SettingDef<boolean>;
156
+ readonly 'chronological.quickSettings.showLockScreen': SettingDef<boolean>;
157
+ readonly 'chronological.timeOfDay.morningStart': SettingDef<number>;
158
+ readonly 'chronological.timeOfDay.forenoonStart': SettingDef<number>;
159
+ readonly 'chronological.timeOfDay.afternoonStart': SettingDef<number>;
160
+ readonly 'chronological.timeOfDay.eveningStart': SettingDef<number>;
161
+ readonly 'chronological.timeOfDay.nightStart': SettingDef<number>;
162
+ readonly 'chronologicalEventForm.field.description': SettingDef<boolean>;
163
+ readonly 'chronologicalEventForm.field.recurrence': SettingDef<boolean>;
164
+ readonly 'chronologicalEventForm.field.acknowledge': SettingDef<boolean>;
165
+ readonly 'chronologicalEventForm.field.checklist': SettingDef<boolean>;
166
+ readonly 'chronologicalEventForm.field.extraImages': SettingDef<boolean>;
167
+ readonly 'chronologicalEventForm.field.reminders': SettingDef<boolean>;
168
+ readonly 'chronologicalEventForm.field.audioClips': SettingDef<boolean>;
169
+ readonly 'chronologicalEventForm.fixedField.allDay': SettingDef<boolean>;
170
+ readonly 'chronologicalEventForm.fixedField.endTime': SettingDef<boolean>;
171
+ readonly 'chronologicalEventForm.fixedField.visibility': SettingDef<boolean>;
172
+ readonly 'chronologicalEventForm.suggestEndTime.enabled': SettingDef<boolean>;
173
+ readonly 'chronologicalEventForm.suggestEndTime.value': SettingDef<number>;
174
+ readonly 'chronologicalEventForm.suggestEndTime.unit': SettingDef<SuggestEndTimeUnit>;
175
+ readonly 'chronologicalEventForm.defaultVisibility': SettingDef<EventVisibility>;
176
+ readonly 'chronologicalEventForm.reminderPresets.timed': SettingDef<number[]>;
177
+ readonly 'chronologicalEventForm.reminderPresets.allDay': SettingDef<AllDayPreset[]>;
178
+ };
179
+ type SettingsEntries = ReturnType<typeof buildEntries>;
180
+ /** Union type of every valid setting key */
181
+ export type SettingKey = keyof SettingsEntries;
182
+ /** Type-safe value type for a given setting key */
183
+ export type SettingValue<K extends SettingKey> = SettingsEntries[K]['default'];
184
+ /** Complete settings map — all keys resolved to their value types */
185
+ export type SettingsMap = {
186
+ [K in SettingKey]: SettingValue<K>;
187
+ };
188
+ export declare class SettingsRegistry {
189
+ /** The raw setting definitions (category, type, default, sync) */
190
+ readonly entries: SettingsEntries;
191
+ /** All setting keys as an array */
192
+ readonly keys: SettingKey[];
193
+ constructor(config?: Partial<RegistryConfig>);
194
+ /** Get the default value for a setting */
195
+ getDefault<K extends SettingKey>(key: K): SettingValue<K>;
196
+ /** Get a complete map of all default values */
197
+ getAllDefaults(): SettingsMap;
198
+ /** Get the data type for a setting key */
199
+ getDataType(key: SettingKey): SettingsDataType;
200
+ /** Check whether a setting should be synced */
201
+ isSynced(key: SettingKey): boolean;
202
+ /** Get all setting keys for a category */
203
+ getByCategory(category: SettingsCategory): SettingKey[];
204
+ /** Serialize a setting value to a string for DB storage */
205
+ serialize(key: SettingKey, value: unknown): string;
206
+ /** Deserialize a DB string back to a typed setting value */
207
+ deserialize<K extends SettingKey>(key: K, raw: string | null): SettingValue<K>;
208
+ }
209
+ export declare const defaultRegistry: SettingsRegistry;
210
+ export declare function createSettingsRegistry(config?: Partial<RegistryConfig>): {
211
+ readonly 'appearance.theme': SettingDef<ThemeSetting>;
212
+ readonly 'appearance.clockType': SettingDef<ClockType>;
213
+ readonly 'appearance.enableDayColors': SettingDef<boolean>;
214
+ readonly 'calendarView.type': SettingDef<CalendarType>;
215
+ readonly 'calendarView.view': SettingDef<CalendarViewMode>;
216
+ readonly 'calendarView.dayViewZoom': SettingDef<CalendarDayViewCellZoom>;
217
+ readonly 'calendarView.weekViewZoom': SettingDef<CalendarDayViewCellZoom>;
218
+ readonly 'calendarView.splitView': SettingDef<boolean>;
219
+ readonly 'calendarView.showCalendarNames': SettingDef<boolean>;
220
+ readonly 'calendarView.calendarColumns': SettingDef<unknown[]>;
221
+ readonly 'calendarView.autoReturnToTodayEnabled': SettingDef<boolean>;
222
+ readonly 'calendarView.autoReturnToTodayTimeoutSeconds': SettingDef<number>;
223
+ readonly 'calendarView.showWeatherOnEvents': SettingDef<boolean>;
224
+ readonly 'calendarView.showWeatherOnTimeline': SettingDef<boolean>;
225
+ readonly 'calendarView.weatherLocation': SettingDef<WeatherLocation | null>;
226
+ readonly 'eventForm.recurrence': SettingDef<boolean>;
227
+ readonly 'eventForm.reminders': SettingDef<boolean>;
228
+ readonly 'eventForm.emailReminders': SettingDef<boolean>;
229
+ readonly 'eventForm.location': SettingDef<boolean>;
230
+ readonly 'eventForm.travelTime': SettingDef<boolean>;
231
+ readonly 'eventForm.description': SettingDef<boolean>;
232
+ readonly 'eventForm.checklist': SettingDef<boolean>;
233
+ readonly 'eventForm.images': SettingDef<boolean>;
234
+ readonly 'eventForm.audioClips': SettingDef<boolean>;
235
+ readonly 'eventForm.notificationReceivers': SettingDef<boolean>;
236
+ readonly 'eventForm.visibility': SettingDef<boolean>;
237
+ readonly 'sound.timerVolume': SettingDef<number>;
238
+ readonly 'sound.reminderVolume': SettingDef<number>;
239
+ readonly 'sound.mediaVolume': SettingDef<number>;
240
+ readonly 'sound.alarmSound': SettingDef<AlarmSound>;
241
+ readonly 'sound.reminderAlarmSound': SettingDef<AlarmSound>;
242
+ readonly 'sound.timerAlarmSound': SettingDef<AlarmSound>;
243
+ readonly 'sound.timerAlarmTimeout': SettingDef<AlarmTimeout>;
244
+ readonly 'sound.reminderAlarmTimeout': SettingDef<AlarmTimeout>;
245
+ readonly 'sound.allowCustomReminderSounds': SettingDef<boolean>;
246
+ readonly 'sound.ttsEnabled': SettingDef<boolean>;
247
+ readonly 'sound.ttsRate': SettingDef<number>;
248
+ readonly 'timer.showTimeRemaining': SettingDef<boolean>;
249
+ readonly 'timer.showEndTime': SettingDef<boolean>;
250
+ readonly 'timer.showRestartButton': SettingDef<boolean>;
251
+ readonly 'timer.showPauseButton': SettingDef<boolean>;
252
+ readonly 'lockScreen.pin': SettingDef<string>;
253
+ readonly 'lockScreen.inactivityLockEnabled': SettingDef<boolean>;
254
+ readonly 'lockScreen.inactivityTimeoutMinutes': SettingDef<InactivityTimeoutMinutes>;
255
+ readonly 'lockScreen.clockDisplay': SettingDef<LockScreenClockDisplay>;
256
+ readonly 'lockScreen.showDate': SettingDef<boolean>;
257
+ readonly 'lockScreen.showHourNumbers': SettingDef<boolean>;
258
+ readonly 'lockScreen.imageMode': SettingDef<LockScreenImageMode>;
259
+ readonly 'lockScreen.backgroundImage': SettingDef<string | null>;
260
+ readonly 'lockScreen.photoFrameImages': SettingDef<LockScreenImage[]>;
261
+ readonly 'lockScreen.photoFrameIntervalSeconds': SettingDef<PhotoFrameIntervalSeconds>;
262
+ readonly 'touch.enableTapToCreate': SettingDef<boolean>;
263
+ readonly 'touch.enableDragDrop': SettingDef<boolean>;
264
+ readonly 'device.id': SettingDef<string>;
265
+ readonly 'device.timePickerMode': SettingDef<TimePickerMode>;
266
+ readonly 'device.devMenuEnabled': SettingDef<boolean>;
267
+ readonly 'device.authWarningDismissTtlDays': SettingDef<number>;
268
+ readonly 'language.locale': SettingDef<LocaleCode>;
269
+ readonly 'notification.enabled': SettingDef<boolean>;
270
+ readonly 'notification.notifyAllCalendars': SettingDef<boolean>;
271
+ readonly 'notification.enabledCalendarIds': SettingDef<string[]>;
272
+ readonly 'notification.hasBeenPrompted': SettingDef<boolean>;
273
+ readonly 'chronological.header.showNavigationArrows': SettingDef<boolean>;
274
+ readonly 'chronological.header.showClock': SettingDef<boolean>;
275
+ readonly 'chronological.header.showCurrentYearInDate': SettingDef<boolean>;
276
+ readonly 'chronological.header.showTimeOfDay': SettingDef<boolean>;
277
+ readonly 'chronological.footer.showMenuButton': SettingDef<boolean>;
278
+ readonly 'chronological.footer.showViewSwitcherDay': SettingDef<boolean>;
279
+ readonly 'chronological.footer.showViewSwitcherWeek': SettingDef<boolean>;
280
+ readonly 'chronological.footer.showViewSwitcherMonth': SettingDef<boolean>;
281
+ readonly 'chronological.footer.showTimerButton': SettingDef<boolean>;
282
+ readonly 'chronological.footer.showNewEventButton': SettingDef<boolean>;
283
+ readonly 'chronological.footer.showSettingsButton': SettingDef<boolean>;
284
+ readonly 'chronological.timer.showNewCountdown': SettingDef<boolean>;
285
+ readonly 'chronological.timer.showFromTemplate': SettingDef<boolean>;
286
+ readonly 'chronological.timer.showEditTemplate': SettingDef<boolean>;
287
+ readonly 'chronological.timer.showDeleteTemplate': SettingDef<boolean>;
288
+ readonly 'chronological.timer.showAddTemplate': SettingDef<boolean>;
289
+ readonly 'chronological.menu.showSettingsButton': SettingDef<boolean>;
290
+ readonly 'chronological.quickSettings.showTimerVolume': SettingDef<boolean>;
291
+ readonly 'chronological.quickSettings.showReminderVolume': SettingDef<boolean>;
292
+ readonly 'chronological.quickSettings.showMediaVolume': SettingDef<boolean>;
293
+ readonly 'chronological.quickSettings.showBrightness': SettingDef<boolean>;
294
+ readonly 'chronological.quickSettings.showLockScreen': SettingDef<boolean>;
295
+ readonly 'chronological.timeOfDay.morningStart': SettingDef<number>;
296
+ readonly 'chronological.timeOfDay.forenoonStart': SettingDef<number>;
297
+ readonly 'chronological.timeOfDay.afternoonStart': SettingDef<number>;
298
+ readonly 'chronological.timeOfDay.eveningStart': SettingDef<number>;
299
+ readonly 'chronological.timeOfDay.nightStart': SettingDef<number>;
300
+ readonly 'chronologicalEventForm.field.description': SettingDef<boolean>;
301
+ readonly 'chronologicalEventForm.field.recurrence': SettingDef<boolean>;
302
+ readonly 'chronologicalEventForm.field.acknowledge': SettingDef<boolean>;
303
+ readonly 'chronologicalEventForm.field.checklist': SettingDef<boolean>;
304
+ readonly 'chronologicalEventForm.field.extraImages': SettingDef<boolean>;
305
+ readonly 'chronologicalEventForm.field.reminders': SettingDef<boolean>;
306
+ readonly 'chronologicalEventForm.field.audioClips': SettingDef<boolean>;
307
+ readonly 'chronologicalEventForm.fixedField.allDay': SettingDef<boolean>;
308
+ readonly 'chronologicalEventForm.fixedField.endTime': SettingDef<boolean>;
309
+ readonly 'chronologicalEventForm.fixedField.visibility': SettingDef<boolean>;
310
+ readonly 'chronologicalEventForm.suggestEndTime.enabled': SettingDef<boolean>;
311
+ readonly 'chronologicalEventForm.suggestEndTime.value': SettingDef<number>;
312
+ readonly 'chronologicalEventForm.suggestEndTime.unit': SettingDef<SuggestEndTimeUnit>;
313
+ readonly 'chronologicalEventForm.defaultVisibility': SettingDef<EventVisibility>;
314
+ readonly 'chronologicalEventForm.reminderPresets.timed': SettingDef<number[]>;
315
+ readonly 'chronologicalEventForm.reminderPresets.allDay': SettingDef<AllDayPreset[]>;
316
+ };
317
+ export {};
318
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,293 @@
1
+ /**
2
+ * Settings Registry — single source of truth for ALL FocusPlanner app settings.
3
+ *
4
+ * This shared package defines every setting key, its category, data type,
5
+ * default value, and whether it should be synced to the server.
6
+ *
7
+ * Used by:
8
+ * - The mobile app (local SQLite settings table, React Query hooks)
9
+ * - The API (validate & serialize settings profiles)
10
+ * - The web portal (render settings viewer/editor)
11
+ *
12
+ * App-specific defaults (theme, locale, enrolled mode) are parameterized
13
+ * via `createRegistry(config)`.
14
+ */
15
+ export const ALARM_TIMEOUTS = [1, 2, 3, 5, 10];
16
+ export const LOCK_SCREEN_MAX_IMAGES = 10;
17
+ // ---------------------------------------------------------------------------
18
+ // Setting categories — used for UI grouping and profile organization
19
+ // ---------------------------------------------------------------------------
20
+ export const SETTINGS_CATEGORIES = [
21
+ 'appearance',
22
+ 'calendarView',
23
+ 'calendars',
24
+ 'sound',
25
+ 'timer',
26
+ 'media',
27
+ 'lockScreen',
28
+ 'touch',
29
+ 'device',
30
+ 'language',
31
+ 'notification',
32
+ 'chronological',
33
+ 'eventForm',
34
+ 'chronologicalEventForm',
35
+ ];
36
+ /** Default config for non-enrolled mode */
37
+ export const DEFAULT_REGISTRY_CONFIG = {
38
+ isEnrolled: false,
39
+ defaultTheme: 'system',
40
+ defaultLocale: 'nb',
41
+ };
42
+ // ---------------------------------------------------------------------------
43
+ // Helper
44
+ // ---------------------------------------------------------------------------
45
+ function def(category, type, defaultValue, sync = true) {
46
+ return { category, type, default: defaultValue, sync };
47
+ }
48
+ // ---------------------------------------------------------------------------
49
+ // Entry builder (internal — used by SettingsRegistry class and factory)
50
+ // ---------------------------------------------------------------------------
51
+ function buildEntries(config) {
52
+ return {
53
+ // ═══════════════════════════════════════════════════════════════════════
54
+ // Appearance
55
+ // ═══════════════════════════════════════════════════════════════════════
56
+ 'appearance.theme': def('appearance', 'string', config.defaultTheme),
57
+ 'appearance.clockType': def('appearance', 'string', 'digital'),
58
+ 'appearance.enableDayColors': def('appearance', 'boolean', false),
59
+ // ═══════════════════════════════════════════════════════════════════════
60
+ // Calendar view
61
+ // ═══════════════════════════════════════════════════════════════════════
62
+ 'calendarView.type': def('calendarView', 'string', 'time-based'),
63
+ 'calendarView.view': def('calendarView', 'string', 'day'),
64
+ 'calendarView.dayViewZoom': def('calendarView', 'number', 60),
65
+ 'calendarView.weekViewZoom': def('calendarView', 'number', 60),
66
+ 'calendarView.splitView': def('calendarView', 'boolean', false),
67
+ 'calendarView.showCalendarNames': def('calendarView', 'boolean', true),
68
+ 'calendarView.calendarColumns': def('calendarView', 'json', []),
69
+ 'calendarView.autoReturnToTodayEnabled': def('calendarView', 'boolean', config.isEnrolled),
70
+ 'calendarView.autoReturnToTodayTimeoutSeconds': def('calendarView', 'number', 300),
71
+ 'calendarView.showWeatherOnEvents': def('calendarView', 'boolean', false),
72
+ 'calendarView.showWeatherOnTimeline': def('calendarView', 'boolean', false),
73
+ 'calendarView.weatherLocation': def('calendarView', 'json', null),
74
+ // ═══════════════════════════════════════════════════════════════════════
75
+ // Event form field visibility (time-based)
76
+ // ═══════════════════════════════════════════════════════════════════════
77
+ 'eventForm.recurrence': def('eventForm', 'boolean', true),
78
+ 'eventForm.reminders': def('eventForm', 'boolean', true),
79
+ 'eventForm.emailReminders': def('eventForm', 'boolean', false),
80
+ 'eventForm.location': def('eventForm', 'boolean', true),
81
+ 'eventForm.travelTime': def('eventForm', 'boolean', false),
82
+ 'eventForm.description': def('eventForm', 'boolean', true),
83
+ 'eventForm.checklist': def('eventForm', 'boolean', true),
84
+ 'eventForm.images': def('eventForm', 'boolean', false),
85
+ 'eventForm.audioClips': def('eventForm', 'boolean', false),
86
+ 'eventForm.notificationReceivers': def('eventForm', 'boolean', true),
87
+ 'eventForm.visibility': def('eventForm', 'boolean', false),
88
+ // ═══════════════════════════════════════════════════════════════════════
89
+ // Sound & alerts
90
+ // ═══════════════════════════════════════════════════════════════════════
91
+ 'sound.timerVolume': def('sound', 'number', 0.5),
92
+ 'sound.reminderVolume': def('sound', 'number', 0.5),
93
+ 'sound.mediaVolume': def('sound', 'number', 0.5),
94
+ 'sound.alarmSound': def('sound', 'string', 'alarm1'),
95
+ 'sound.reminderAlarmSound': def('sound', 'string', 'alarm1'),
96
+ 'sound.timerAlarmSound': def('sound', 'string', 'alarm1'),
97
+ 'sound.timerAlarmTimeout': def('sound', 'number', 3),
98
+ 'sound.reminderAlarmTimeout': def('sound', 'number', 3),
99
+ 'sound.allowCustomReminderSounds': def('sound', 'boolean', false),
100
+ 'sound.ttsEnabled': def('sound', 'boolean', config.isEnrolled),
101
+ 'sound.ttsRate': def('sound', 'number', 1.0),
102
+ // ═══════════════════════════════════════════════════════════════════════
103
+ // Timer
104
+ // ═══════════════════════════════════════════════════════════════════════
105
+ 'timer.showTimeRemaining': def('timer', 'boolean', true),
106
+ 'timer.showEndTime': def('timer', 'boolean', true),
107
+ 'timer.showRestartButton': def('timer', 'boolean', true),
108
+ 'timer.showPauseButton': def('timer', 'boolean', true),
109
+ // ═══════════════════════════════════════════════════════════════════════
110
+ // Lock screen
111
+ // ═══════════════════════════════════════════════════════════════════════
112
+ 'lockScreen.pin': def('lockScreen', 'string', ''),
113
+ 'lockScreen.inactivityLockEnabled': def('lockScreen', 'boolean', false),
114
+ 'lockScreen.inactivityTimeoutMinutes': def('lockScreen', 'number', 5),
115
+ 'lockScreen.clockDisplay': def('lockScreen', 'string', 'digital'),
116
+ 'lockScreen.showDate': def('lockScreen', 'boolean', true),
117
+ 'lockScreen.showHourNumbers': def('lockScreen', 'boolean', true),
118
+ 'lockScreen.imageMode': def('lockScreen', 'string', 'none'),
119
+ 'lockScreen.backgroundImage': def('lockScreen', 'json', null),
120
+ 'lockScreen.photoFrameImages': def('lockScreen', 'json', []),
121
+ 'lockScreen.photoFrameIntervalSeconds': def('lockScreen', 'number', 60),
122
+ // ═══════════════════════════════════════════════════════════════════════
123
+ // Touch / gestures
124
+ // ═══════════════════════════════════════════════════════════════════════
125
+ 'touch.enableTapToCreate': def('touch', 'boolean', false),
126
+ 'touch.enableDragDrop': def('touch', 'boolean', false),
127
+ // ═══════════════════════════════════════════════════════════════════════
128
+ // Device (not synced unless noted)
129
+ // ═══════════════════════════════════════════════════════════════════════
130
+ 'device.id': def('device', 'string', '', false),
131
+ 'device.timePickerMode': def('device', 'string', 'dials'),
132
+ 'device.devMenuEnabled': def('device', 'boolean', false, false),
133
+ 'device.authWarningDismissTtlDays': def('device', 'number', 3, false),
134
+ // ═══════════════════════════════════════════════════════════════════════
135
+ // Language
136
+ // ═══════════════════════════════════════════════════════════════════════
137
+ 'language.locale': def('language', 'string', config.defaultLocale),
138
+ // ═══════════════════════════════════════════════════════════════════════
139
+ // Notifications
140
+ // ═══════════════════════════════════════════════════════════════════════
141
+ 'notification.enabled': def('notification', 'boolean', false),
142
+ 'notification.notifyAllCalendars': def('notification', 'boolean', true),
143
+ 'notification.enabledCalendarIds': def('notification', 'json', []),
144
+ 'notification.hasBeenPrompted': def('notification', 'boolean', false, false),
145
+ // ═══════════════════════════════════════════════════════════════════════
146
+ // Chronological features (header, footer, menu, quick settings, timer)
147
+ // ═══════════════════════════════════════════════════════════════════════
148
+ // Header
149
+ 'chronological.header.showNavigationArrows': def('chronological', 'boolean', true),
150
+ 'chronological.header.showClock': def('chronological', 'boolean', true),
151
+ 'chronological.header.showCurrentYearInDate': def('chronological', 'boolean', false),
152
+ 'chronological.header.showTimeOfDay': def('chronological', 'boolean', false),
153
+ // Footer
154
+ 'chronological.footer.showMenuButton': def('chronological', 'boolean', true),
155
+ 'chronological.footer.showViewSwitcherDay': def('chronological', 'boolean', true),
156
+ 'chronological.footer.showViewSwitcherWeek': def('chronological', 'boolean', true),
157
+ 'chronological.footer.showViewSwitcherMonth': def('chronological', 'boolean', true),
158
+ 'chronological.footer.showTimerButton': def('chronological', 'boolean', true),
159
+ 'chronological.footer.showNewEventButton': def('chronological', 'boolean', true),
160
+ 'chronological.footer.showSettingsButton': def('chronological', 'boolean', true),
161
+ // Timer features
162
+ 'chronological.timer.showNewCountdown': def('chronological', 'boolean', true),
163
+ 'chronological.timer.showFromTemplate': def('chronological', 'boolean', true),
164
+ 'chronological.timer.showEditTemplate': def('chronological', 'boolean', true),
165
+ 'chronological.timer.showDeleteTemplate': def('chronological', 'boolean', true),
166
+ 'chronological.timer.showAddTemplate': def('chronological', 'boolean', true),
167
+ // Menu
168
+ 'chronological.menu.showSettingsButton': def('chronological', 'boolean', true),
169
+ // Quick settings
170
+ 'chronological.quickSettings.showTimerVolume': def('chronological', 'boolean', true),
171
+ 'chronological.quickSettings.showReminderVolume': def('chronological', 'boolean', true),
172
+ 'chronological.quickSettings.showMediaVolume': def('chronological', 'boolean', true),
173
+ 'chronological.quickSettings.showBrightness': def('chronological', 'boolean', true),
174
+ 'chronological.quickSettings.showLockScreen': def('chronological', 'boolean', true),
175
+ // Time-of-day periods
176
+ 'chronological.timeOfDay.morningStart': def('chronological', 'number', 6),
177
+ 'chronological.timeOfDay.forenoonStart': def('chronological', 'number', 9),
178
+ 'chronological.timeOfDay.afternoonStart': def('chronological', 'number', 12),
179
+ 'chronological.timeOfDay.eveningStart': def('chronological', 'number', 18),
180
+ 'chronological.timeOfDay.nightStart': def('chronological', 'number', 0),
181
+ // ═══════════════════════════════════════════════════════════════════════
182
+ // Chronological event form
183
+ // ═══════════════════════════════════════════════════════════════════════
184
+ // Toggleable fields
185
+ 'chronologicalEventForm.field.description': def('chronologicalEventForm', 'boolean', true),
186
+ 'chronologicalEventForm.field.recurrence': def('chronologicalEventForm', 'boolean', true),
187
+ 'chronologicalEventForm.field.acknowledge': def('chronologicalEventForm', 'boolean', true),
188
+ 'chronologicalEventForm.field.checklist': def('chronologicalEventForm', 'boolean', true),
189
+ 'chronologicalEventForm.field.extraImages': def('chronologicalEventForm', 'boolean', true),
190
+ 'chronologicalEventForm.field.reminders': def('chronologicalEventForm', 'boolean', true),
191
+ 'chronologicalEventForm.field.audioClips': def('chronologicalEventForm', 'boolean', true),
192
+ // Fixed fields
193
+ 'chronologicalEventForm.fixedField.allDay': def('chronologicalEventForm', 'boolean', true),
194
+ 'chronologicalEventForm.fixedField.endTime': def('chronologicalEventForm', 'boolean', true),
195
+ 'chronologicalEventForm.fixedField.visibility': def('chronologicalEventForm', 'boolean', true),
196
+ // Suggest end time
197
+ 'chronologicalEventForm.suggestEndTime.enabled': def('chronologicalEventForm', 'boolean', false),
198
+ 'chronologicalEventForm.suggestEndTime.value': def('chronologicalEventForm', 'number', 30),
199
+ 'chronologicalEventForm.suggestEndTime.unit': def('chronologicalEventForm', 'string', 'minutes'),
200
+ // Default visibility
201
+ 'chronologicalEventForm.defaultVisibility': def('chronologicalEventForm', 'string', 'Private'),
202
+ // Reminder presets
203
+ 'chronologicalEventForm.reminderPresets.timed': def('chronologicalEventForm', 'json', [5, 15, 30, 60, 120, 1440]),
204
+ 'chronologicalEventForm.reminderPresets.allDay': def('chronologicalEventForm', 'json', [
205
+ { daysBefore: 0, time: '09:00' },
206
+ { daysBefore: 1, time: '18:00' },
207
+ { daysBefore: 2, time: '09:00' },
208
+ ]),
209
+ };
210
+ }
211
+ // ---------------------------------------------------------------------------
212
+ // Registry class
213
+ // ---------------------------------------------------------------------------
214
+ export class SettingsRegistry {
215
+ constructor(config = {}) {
216
+ const full = { ...DEFAULT_REGISTRY_CONFIG, ...config };
217
+ this.entries = buildEntries(full);
218
+ this.keys = Object.keys(this.entries);
219
+ }
220
+ /** Get the default value for a setting */
221
+ getDefault(key) {
222
+ return this.entries[key].default;
223
+ }
224
+ /** Get a complete map of all default values */
225
+ getAllDefaults() {
226
+ const defaults = {};
227
+ for (const key of this.keys) {
228
+ defaults[key] = this.entries[key].default;
229
+ }
230
+ return defaults;
231
+ }
232
+ /** Get the data type for a setting key */
233
+ getDataType(key) {
234
+ return this.entries[key].type;
235
+ }
236
+ /** Check whether a setting should be synced */
237
+ isSynced(key) {
238
+ return this.entries[key].sync;
239
+ }
240
+ /** Get all setting keys for a category */
241
+ getByCategory(category) {
242
+ return this.keys.filter((key) => this.entries[key].category === category);
243
+ }
244
+ /** Serialize a setting value to a string for DB storage */
245
+ serialize(key, value) {
246
+ const dataType = this.getDataType(key);
247
+ switch (dataType) {
248
+ case 'string':
249
+ return String(value ?? '');
250
+ case 'number':
251
+ return String(value ?? 0);
252
+ case 'boolean':
253
+ return value ? 'true' : 'false';
254
+ case 'json':
255
+ return JSON.stringify(value);
256
+ }
257
+ }
258
+ /** Deserialize a DB string back to a typed setting value */
259
+ deserialize(key, raw) {
260
+ if (raw === null || raw === undefined) {
261
+ return this.getDefault(key);
262
+ }
263
+ const dataType = this.getDataType(key);
264
+ switch (dataType) {
265
+ case 'string':
266
+ return raw;
267
+ case 'number':
268
+ return Number(raw);
269
+ case 'boolean':
270
+ return (raw === 'true');
271
+ case 'json':
272
+ try {
273
+ return JSON.parse(raw);
274
+ }
275
+ catch {
276
+ return this.getDefault(key);
277
+ }
278
+ }
279
+ }
280
+ }
281
+ // ---------------------------------------------------------------------------
282
+ // Default registry instance (non-enrolled, system theme, nb locale)
283
+ // ---------------------------------------------------------------------------
284
+ export const defaultRegistry = new SettingsRegistry();
285
+ // ---------------------------------------------------------------------------
286
+ // Factory function — returns raw entry map for local type derivation.
287
+ // Consumers that need precise generic inference (e.g. useQuery<K>) can use
288
+ // this to anchor types on a local const variable.
289
+ // ---------------------------------------------------------------------------
290
+ export function createSettingsRegistry(config = {}) {
291
+ return buildEntries({ ...DEFAULT_REGISTRY_CONFIG, ...config });
292
+ }
293
+ //# sourceMappingURL=index.js.map