@@ -19,13 +19,12 @@ import { getSystemLocale, showToast } from '../../helpers/utils'
19
19
****
20
20
* Introduction
21
21
*
22
- * You can add a new setting in three different methods.
22
+ * You can add a new setting in two different methods.
23
23
*
24
- * The first two methods benefit from the auto-generation of
24
+ * The first method benefits from the auto-generation of
25
25
* a getter, a mutation and a few actions related to the setting.
26
- * Those two methods should be preferred whenever possible:
26
+ * This method should be preferred whenever possible:
27
27
* - `state`
28
- * - `stateWithSideEffects`
29
28
*
30
29
* The last one DOES NOT feature any kind of auto-generation and should
31
30
* only be used in scenarios that don't fall under the other 2 options:
@@ -51,7 +50,7 @@ import { getSystemLocale, showToast } from '../../helpers/utils'
51
50
*
52
51
* 2) You want to add a more complex setting that interacts
53
52
* with other parts of the app and tech stack.
54
- * -> Please consult the `state` and `stateWithSideEffects ` sections.
53
+ * -> Please consult the `state` and `sideEffectHandlers ` sections.
55
54
*
56
55
* 3) You want to add a completely custom state based setting
57
56
* that does not work like the usual settings.
@@ -77,32 +76,26 @@ import { getSystemLocale, showToast } from '../../helpers/utils'
77
76
* and calls `setExample` with it)
78
77
*
79
78
***
80
- * `stateWithSideEffects `
81
- * This object contains settings that have SIDE EFFECTS.
79
+ * `sideEffectHandlers `
80
+ * This object contains the side-effect handlers for settings that have SIDE EFFECTS.
82
81
*
83
- * Each one of these settings must specify an object
84
- * with the following properties:
85
- * - `defaultValue`
86
- * (which is the value you would put down if
87
- * you were to add the setting to the regular `state` object)
82
+ * Each one of these settings must specify a handler,
83
+ * which should essentially be a callback of type
84
+ * `(store, value) => void` (the same as you would use for an `action`)
85
+ * that deals with the side effects for that setting
88
86
*
89
- * - `sideEffectsHandler`
90
- * (which should essentially be a callback of type
91
- * `(store, value) => void`
92
- * that deals with the side effects for that setting)
93
- *
94
- * NOTE: Example implementations of such settings can be found
95
- * in the `stateWithSideEffects` object in case
87
+ * NOTE: Example implementations of such handlers can be found
88
+ * in the `sideEffectHandlers` object in case
96
89
* the explanation isn't clear enough.
97
90
*
98
91
* All functions auto-generated for settings in `state`
99
92
* (if you haven't read the `state` section, do it now),
100
- * are also auto-generated for settings in `stateWithSideEffects` ,
93
+ * are also auto-generated for settings in `sideEffectHandlers ,
101
94
* with a few key differences (exemplified with setting 'example'):
102
95
*
103
96
* - an additional action is auto-generated:
104
97
* - `triggerExampleSideEffects`
105
- * (triggers the `sideEffectsHandler ` for that setting;
98
+ * (triggers the `handler ` for that setting;
106
99
* you'll most likely never call this directly)
107
100
*
108
101
* - the behavior of `updateExample` changes a bit:
@@ -128,12 +121,6 @@ import { getSystemLocale, showToast } from '../../helpers/utils'
128
121
* to evaluate if it is truly necessary
129
122
* and to ensure that the implementation works as intended.
130
123
*
131
- * A good example of a setting of this type would be `usingElectron`.
132
- * This setting doesn't need to be persisted in the database
133
- * and it doesn't change over time.
134
- * Therefore, it needs a getter (which we add to `customGetters`), but
135
- * has no need for a mutation or any sort of action.
136
- *
137
124
****
138
125
* ENDING NOTES
139
126
*
@@ -153,7 +140,7 @@ import { getSystemLocale, showToast } from '../../helpers/utils'
153
140
*/
154
141
155
142
// HELPERS
156
- const capitalize = str => str . replace ( / ^ \w / , c => c . toUpperCase ( ) )
143
+ const capitalize = str => str . charAt ( 0 ) . toUpperCase ( ) + str . slice ( 1 )
157
144
const defaultGetterId = settingId => 'get' + capitalize ( settingId )
158
145
const defaultMutationId = settingId => 'set' + capitalize ( settingId )
159
146
const defaultUpdaterId = settingId => 'update' + capitalize ( settingId )
@@ -311,115 +298,109 @@ const state = {
311
298
// If the playlist is removed quick bookmark is disabled
312
299
quickBookmarkTargetPlaylistId : 'favorites' ,
313
300
generalAutoLoadMorePaginatedItemsEnabled : false ,
301
+
302
+ // The settings below have side effects
303
+ currentLocale : 'system' ,
304
+ defaultInvidiousInstance : '' ,
305
+ defaultVolume : 1 ,
306
+ uiScale : 100 ,
314
307
}
315
308
316
- const stateWithSideEffects = {
317
- currentLocale : {
318
- defaultValue : 'system' ,
319
- sideEffectsHandler : async function ( { dispatch } , value ) {
320
- const fallbackLocale = 'en-US'
321
-
322
- let targetLocale = value
323
- if ( value === 'system' ) {
324
- const systemLocaleName = ( await getSystemLocale ( ) ) . replace ( '_' , '-' ) // ex: en-US
325
- const systemLocaleSplit = systemLocaleName . split ( '-' ) // ex: en
326
- const targetLocaleOptions = allLocales . filter ( ( locale ) => {
327
- // filter out other languages
328
- const localeLang = locale . split ( '-' ) [ 0 ]
329
- return localeLang . includes ( systemLocaleSplit [ 0 ] )
330
- } ) . sort ( ( aLocaleName , bLocaleName ) => {
331
- const aLocale = aLocaleName . split ( '-' ) // ex: [en, US]
332
- const bLocale = bLocaleName . split ( '-' )
333
-
334
- if ( aLocaleName === systemLocaleName ) { // country & language match, prefer a
335
- return - 1
336
- } else if ( bLocaleName === systemLocaleName ) { // country & language match, prefer b
337
- return 1
338
- } else if ( aLocale . length === 1 ) { // no country code for a, prefer a
339
- return - 1
340
- } else if ( bLocale . length === 1 ) { // no country code for b, prefer b
341
- return 1
342
- } else { // a & b have different country code from system, sort alphabetically
343
- return aLocaleName . localeCompare ( bLocaleName )
344
- }
345
- } )
346
-
347
- if ( targetLocaleOptions . length > 0 ) {
348
- targetLocale = targetLocaleOptions [ 0 ]
349
- } else {
350
- // Go back to default value if locale is unavailable
351
- targetLocale = fallbackLocale
352
- // Translating this string isn't necessary
353
- // because the user will always see it in the default locale
354
- // (in this case, English (US))
355
- showToast ( `Locale not found, defaulting to ${ fallbackLocale } ` )
309
+ const sideEffectHandlers = {
310
+ currentLocale : async ( { dispatch } , value ) => {
311
+ const fallbackLocale = 'en-US'
312
+
313
+ let targetLocale = value
314
+ if ( value === 'system' ) {
315
+ const systemLocaleName = ( await getSystemLocale ( ) ) . replace ( '_' , '-' ) // ex: en-US
316
+ const systemLocaleSplit = systemLocaleName . split ( '-' ) // ex: en
317
+ const targetLocaleOptions = allLocales . filter ( ( locale ) => {
318
+ // filter out other languages
319
+ const localeLang = locale . split ( '-' ) [ 0 ]
320
+ return localeLang . includes ( systemLocaleSplit [ 0 ] )
321
+ } ) . sort ( ( aLocaleName , bLocaleName ) => {
322
+ const aLocale = aLocaleName . split ( '-' ) // ex: [en, US]
323
+ const bLocale = bLocaleName . split ( '-' )
324
+
325
+ if ( aLocaleName === systemLocaleName ) { // country & language match, prefer a
326
+ return - 1
327
+ } else if ( bLocaleName === systemLocaleName ) { // country & language match, prefer b
328
+ return 1
329
+ } else if ( aLocale . length === 1 ) { // no country code for a, prefer a
330
+ return - 1
331
+ } else if ( bLocale . length === 1 ) { // no country code for b, prefer b
332
+ return 1
333
+ } else { // a & b have different country code from system, sort alphabetically
334
+ return aLocaleName . localeCompare ( bLocaleName )
356
335
}
357
- }
358
-
359
- const loadPromises = [ ]
360
-
361
- if ( targetLocale !== fallbackLocale ) {
362
- // "en-US" is used as a fallback for missing strings in other locales
363
- loadPromises . push (
364
- loadLocale ( fallbackLocale )
365
- )
366
- }
336
+ } )
367
337
368
- // "es" is used as a fallback for "es-AR" and "es-MX"
369
- if ( targetLocale === 'es-AR' || targetLocale === 'es-MX' ) {
370
- loadPromises . push (
371
- loadLocale ( 'es' )
372
- )
338
+ if ( targetLocaleOptions . length > 0 ) {
339
+ targetLocale = targetLocaleOptions [ 0 ]
340
+ } else {
341
+ // Go back to default value if locale is unavailable
342
+ targetLocale = fallbackLocale
343
+ // Translating this string isn't necessary
344
+ // because the user will always see it in the default locale
345
+ // (in this case, English (US))
346
+ showToast ( `Locale not found, defaulting to ${ fallbackLocale } ` )
373
347
}
348
+ }
374
349
375
- // "pt" is used as a fallback for "pt-PT" and "pt-BR"
376
- if ( targetLocale === 'pt-PT' || targetLocale === 'pt-BR' ) {
377
- loadPromises . push (
378
- loadLocale ( 'pt' )
379
- )
380
- }
350
+ const loadPromises = [ ]
381
351
352
+ if ( targetLocale !== fallbackLocale ) {
353
+ // "en-US" is used as a fallback for missing strings in other locales
382
354
loadPromises . push (
383
- loadLocale ( targetLocale )
355
+ loadLocale ( fallbackLocale )
384
356
)
357
+ }
385
358
386
- await Promise . allSettled ( loadPromises )
359
+ // "es" is used as a fallback for "es-AR" and "es-MX"
360
+ if ( targetLocale === 'es-AR' || targetLocale === 'es-MX' ) {
361
+ loadPromises . push (
362
+ loadLocale ( 'es' )
363
+ )
364
+ }
387
365
388
- i18n . locale = targetLocale
389
- await dispatch ( 'getRegionData' , targetLocale )
366
+ // "pt" is used as a fallback for "pt-PT" and "pt-BR"
367
+ if ( targetLocale === 'pt-PT' || targetLocale === 'pt-BR' ) {
368
+ loadPromises . push (
369
+ loadLocale ( 'pt' )
370
+ )
390
371
}
372
+
373
+ loadPromises . push (
374
+ loadLocale ( targetLocale )
375
+ )
376
+
377
+ await Promise . allSettled ( loadPromises )
378
+
379
+ i18n . locale = targetLocale
380
+ await dispatch ( 'getRegionData' , targetLocale )
391
381
} ,
392
382
393
- defaultInvidiousInstance : {
394
- defaultValue : '' ,
395
- sideEffectsHandler : ( { commit, rootState } , value ) => {
396
- if ( value !== '' && rootState . invidious . currentInvidiousInstance !== value ) {
397
- commit ( 'setCurrentInvidiousInstance' , value )
398
- }
383
+ defaultInvidiousInstance : ( { commit, rootState } , value ) => {
384
+ if ( value !== '' && rootState . invidious . currentInvidiousInstance !== value ) {
385
+ commit ( 'setCurrentInvidiousInstance' , value )
399
386
}
400
387
} ,
401
388
402
- defaultVolume : {
403
- defaultValue : 1 ,
404
- sideEffectsHandler : ( _ , value ) => {
405
- sessionStorage . setItem ( 'volume' , value )
406
- value === 0 ? sessionStorage . setItem ( 'muted' , 'true' ) : sessionStorage . setItem ( 'muted' , 'false' )
407
- sessionStorage . setItem ( 'defaultVolume' , value )
408
- }
389
+ defaultVolume : ( _ , value ) => {
390
+ sessionStorage . setItem ( 'volume' , value )
391
+ value === 0 ? sessionStorage . setItem ( 'muted' , 'true' ) : sessionStorage . setItem ( 'muted' , 'false' )
392
+ sessionStorage . setItem ( 'defaultVolume' , value )
409
393
} ,
410
394
411
- uiScale : {
412
- defaultValue : 100 ,
413
- sideEffectsHandler : ( _ , value ) => {
414
- if ( process . env . IS_ELECTRON ) {
415
- const { webFrame } = require ( 'electron' )
416
- webFrame . setZoomFactor ( value / 100 )
417
- }
395
+ uiScale : ( _ , value ) => {
396
+ if ( process . env . IS_ELECTRON ) {
397
+ const { webFrame } = require ( 'electron' )
398
+ webFrame . setZoomFactor ( value / 100 )
418
399
}
419
400
}
420
401
}
421
402
422
- const settingsWithSideEffects = Object . keys ( stateWithSideEffects )
403
+ const settingsWithSideEffects = Object . keys ( sideEffectHandlers )
423
404
424
405
const customState = {
425
406
}
@@ -430,24 +411,30 @@ const customGetters = {
430
411
const customMutations = { }
431
412
432
413
const customActions = {
433
- grabUserSettings : async ( { commit, dispatch } ) => {
414
+ grabUserSettings : async ( { commit, dispatch, state } ) => {
434
415
try {
435
- // Assigning default settings for settings that have side effects
436
- const userSettings = Object . entries ( Object . assign ( { } ,
437
- Object . fromEntries ( Object . entries ( stateWithSideEffects ) . map ( ( [ _id , { defaultValue } ] ) => { return [ _id , defaultValue ] } ) ) ,
438
- Object . fromEntries ( ( await DBSettingHandlers . find ( ) ) . map ( ( { _id , value } ) => { return [ _id , value ] } ) ) )
439
- )
416
+ const userSettings = await DBSettingHandlers . find ( )
417
+
418
+ const mutationIds = Object . keys ( mutations )
419
+
420
+ const alreadyTriggeredSideEffects = [ ]
440
421
441
- for ( const setting of userSettings ) {
442
- const [ _id , value ] = setting
422
+ for ( const { _id, value } of userSettings ) {
443
423
if ( settingsWithSideEffects . includes ( _id ) ) {
444
424
dispatch ( defaultSideEffectsTriggerId ( _id ) , value )
425
+ alreadyTriggeredSideEffects . push ( _id )
445
426
}
446
427
447
- if ( Object . keys ( mutations ) . includes ( defaultMutationId ( _id ) ) ) {
428
+ if ( mutationIds . includes ( defaultMutationId ( _id ) ) ) {
448
429
commit ( defaultMutationId ( _id ) , value )
449
430
}
450
431
}
432
+
433
+ for ( const _id of settingsWithSideEffects ) {
434
+ if ( ! alreadyTriggeredSideEffects . includes ( _id ) ) {
435
+ dispatch ( defaultSideEffectsTriggerId ( _id ) , state [ _id ] )
436
+ }
437
+ }
451
438
} catch ( errMessage ) {
452
439
console . error ( errMessage )
453
440
}
@@ -619,45 +606,41 @@ const getters = {}
619
606
const mutations = { }
620
607
const actions = { }
621
608
622
- // Add settings that contain side effects to the state
623
- Object . assign (
624
- state ,
625
- Object . fromEntries (
626
- Object . keys ( stateWithSideEffects ) . map (
627
- ( key ) => [
628
- key ,
629
- stateWithSideEffects [ key ] . defaultValue
630
- ]
631
- )
632
- )
633
- )
634
-
635
609
// Build default getters, mutations and actions for every setting id
636
610
for ( const settingId of Object . keys ( state ) ) {
637
611
const getterId = defaultGetterId ( settingId )
638
612
const mutationId = defaultMutationId ( settingId )
639
613
const updaterId = defaultUpdaterId ( settingId )
640
- const triggerId = defaultSideEffectsTriggerId ( settingId )
641
614
642
615
getters [ getterId ] = ( state ) => state [ settingId ]
643
616
mutations [ mutationId ] = ( state , value ) => { state [ settingId ] = value }
644
617
645
- // If setting has side effects, generate action to handle them
646
618
if ( settingsWithSideEffects . includes ( settingId ) ) {
647
- actions [ triggerId ] = stateWithSideEffects [ settingId ] . sideEffectsHandler
648
- }
619
+ const triggerId = defaultSideEffectsTriggerId ( settingId )
649
620
650
- actions [ updaterId ] = async ( { commit, dispatch } , value ) => {
651
- try {
652
- await DBSettingHandlers . upsert ( settingId , value )
621
+ // If setting has side effects, generate action to handle them
622
+ actions [ triggerId ] = sideEffectHandlers [ settingId ]
623
+
624
+ actions [ updaterId ] = async ( { commit, dispatch } , value ) => {
625
+ try {
626
+ await DBSettingHandlers . upsert ( settingId , value )
653
627
654
- if ( settingsWithSideEffects . includes ( settingId ) ) {
655
628
dispatch ( triggerId , value )
656
- }
657
629
658
- commit ( mutationId , value )
659
- } catch ( errMessage ) {
660
- console . error ( errMessage )
630
+ commit ( mutationId , value )
631
+ } catch ( errMessage ) {
632
+ console . error ( errMessage )
633
+ }
634
+ }
635
+ } else {
636
+ actions [ updaterId ] = async ( { commit } , value ) => {
637
+ try {
638
+ await DBSettingHandlers . upsert ( settingId , value )
639
+
640
+ commit ( mutationId , value )
641
+ } catch ( errMessage ) {
642
+ console . error ( errMessage )
643
+ }
661
644
}
662
645
}
663
646
}
0 commit comments