about summary refs log tree commit diff
path: root/src/state/preferences
diff options
context:
space:
mode:
authorPaul Frazee <pfrazee@gmail.com>2023-11-08 09:38:28 -0800
committerGitHub <noreply@github.com>2023-11-08 09:38:28 -0800
commit5843e212c0ebbfc6c3831929bbbaa72e1a289aba (patch)
tree08b6beed54700c56b65edbff32dc32baae0a4208 /src/state/preferences
parente75b2d508baf9b19e7340657ac2951e9f057b735 (diff)
downloadvoidsky-5843e212c0ebbfc6c3831929bbbaa72e1a289aba.tar.zst
Move language preferences to new persistence + context (#1837)
Diffstat (limited to 'src/state/preferences')
-rw-r--r--src/state/preferences/index.tsx8
-rw-r--r--src/state/preferences/languages.tsx122
2 files changed, 130 insertions, 0 deletions
diff --git a/src/state/preferences/index.tsx b/src/state/preferences/index.tsx
new file mode 100644
index 000000000..56c93f812
--- /dev/null
+++ b/src/state/preferences/index.tsx
@@ -0,0 +1,8 @@
+import React from 'react'
+import {Provider as LanguagesProvider} from './languages'
+
+export {useLanguagePrefs, useSetLanguagePrefs} from './languages'
+
+export function Provider({children}: React.PropsWithChildren<{}>) {
+  return <LanguagesProvider>{children}</LanguagesProvider>
+}
diff --git a/src/state/preferences/languages.tsx b/src/state/preferences/languages.tsx
new file mode 100644
index 000000000..49b63550d
--- /dev/null
+++ b/src/state/preferences/languages.tsx
@@ -0,0 +1,122 @@
+import React from 'react'
+import * as persisted from '#/state/persisted'
+
+type SetStateCb = (
+  v: persisted.Schema['languagePrefs'],
+) => persisted.Schema['languagePrefs']
+type StateContext = persisted.Schema['languagePrefs']
+type SetContext = (fn: SetStateCb) => void
+
+const stateContext = React.createContext<StateContext>(
+  persisted.defaults.languagePrefs,
+)
+const setContext = React.createContext<SetContext>((_: SetStateCb) => {})
+
+export function Provider({children}: React.PropsWithChildren<{}>) {
+  const [state, setState] = React.useState(persisted.get('languagePrefs'))
+
+  const setStateWrapped = React.useCallback(
+    (fn: SetStateCb) => {
+      const v = fn(persisted.get('languagePrefs'))
+      setState(v)
+      persisted.write('languagePrefs', v)
+    },
+    [setState],
+  )
+
+  React.useEffect(() => {
+    return persisted.onUpdate(() => {
+      setState(persisted.get('languagePrefs'))
+    })
+  }, [setStateWrapped])
+
+  return (
+    <stateContext.Provider value={state}>
+      <setContext.Provider value={setStateWrapped}>
+        {children}
+      </setContext.Provider>
+    </stateContext.Provider>
+  )
+}
+
+export function useLanguagePrefs() {
+  return React.useContext(stateContext)
+}
+
+export function useSetLanguagePrefs() {
+  return React.useContext(setContext)
+}
+
+export function getContentLanguages() {
+  return persisted.get('languagePrefs').contentLanguages
+}
+
+export function toggleContentLanguage(
+  state: StateContext,
+  setState: SetContext,
+  code2: string,
+) {
+  if (state.contentLanguages.includes(code2)) {
+    setState(v => ({
+      ...v,
+      contentLanguages: v.contentLanguages.filter(lang => lang !== code2),
+    }))
+  } else {
+    setState(v => ({
+      ...v,
+      contentLanguages: v.contentLanguages.concat(code2),
+    }))
+  }
+}
+
+export function toPostLanguages(postLanguage: string): string[] {
+  // filter out empty strings if exist
+  return postLanguage.split(',').filter(Boolean)
+}
+
+export function hasPostLanguage(postLanguage: string, code2: string): boolean {
+  return toPostLanguages(postLanguage).includes(code2)
+}
+
+export function togglePostLanguage(
+  state: StateContext,
+  setState: SetContext,
+  code2: string,
+) {
+  if (hasPostLanguage(state.postLanguage, code2)) {
+    setState(v => ({
+      ...v,
+      postLanguage: toPostLanguages(v.postLanguage)
+        .filter(lang => lang !== code2)
+        .join(','),
+    }))
+  } else {
+    // sort alphabetically for deterministic comparison in context menu
+    setState(v => ({
+      ...v,
+      postLanguage: toPostLanguages(v.postLanguage)
+        .concat([code2])
+        .sort((a, b) => a.localeCompare(b))
+        .join(','),
+    }))
+  }
+}
+
+/**
+ * Saves whatever language codes are currently selected into a history array,
+ * which is then used to populate the language selector menu.
+ */
+export function savePostLanguageToHistory(setState: SetContext) {
+  // filter out duplicate `this.postLanguage` if exists, and prepend
+  // value to start of array
+  setState(v => ({
+    ...v,
+    postLanguageHistory: [v.postLanguage]
+      .concat(
+        v.postLanguageHistory.filter(
+          commaSeparatedLangCodes => commaSeparatedLangCodes !== v.postLanguage,
+        ),
+      )
+      .slice(0, 6),
+  }))
+}