bsky-app/src/state/models/ui/preferences.ts
Paul Frazee 6f1c4ec9a9
[APP-549] Language controls for Whats Hot (#563)
* Add a content-language preference control

* Update whats hot to only show the selected languages and to refresh on lang pref changes

* Fix lint

* Fix tests

* Add missing accessibility role
2023-05-02 23:06:55 -05:00

111 lines
3 KiB
TypeScript

import {makeAutoObservable} from 'mobx'
import {getLocales} from 'expo-localization'
import {isObj, hasProp} from 'lib/type-guards'
import {ComAtprotoLabelDefs} from '@atproto/api'
import {LabelValGroup} from 'lib/labeling/types'
import {getLabelValueGroup} from 'lib/labeling/helpers'
import {UNKNOWN_LABEL_GROUP, ILLEGAL_LABEL_GROUP} from 'lib/labeling/const'
const deviceLocales = getLocales()
export type LabelPreference = 'show' | 'warn' | 'hide'
export class LabelPreferencesModel {
nsfw: LabelPreference = 'warn'
nudity: LabelPreference = 'show'
suggestive: LabelPreference = 'show'
gore: LabelPreference = 'warn'
hate: LabelPreference = 'hide'
spam: LabelPreference = 'hide'
impersonation: LabelPreference = 'warn'
constructor() {
makeAutoObservable(this, {}, {autoBind: true})
}
}
export class PreferencesModel {
contentLanguages: string[] =
deviceLocales?.map?.(locale => locale.languageCode) || []
contentLabels = new LabelPreferencesModel()
constructor() {
makeAutoObservable(this, {}, {autoBind: true})
}
serialize() {
return {
contentLanguages: this.contentLanguages,
contentLabels: this.contentLabels,
}
}
hydrate(v: unknown) {
if (isObj(v)) {
if (
hasProp(v, 'contentLanguages') &&
Array.isArray(v.contentLanguages) &&
typeof v.contentLanguages.every(item => typeof item === 'string')
) {
this.contentLanguages = v.contentLanguages
}
if (hasProp(v, 'contentLabels') && typeof v.contentLabels === 'object') {
Object.assign(this.contentLabels, v.contentLabels)
} else {
// default to the device languages
this.contentLanguages = deviceLocales.map(locale => locale.languageCode)
}
}
}
hasContentLanguage(code2: string) {
return this.contentLanguages.includes(code2)
}
toggleContentLanguage(code2: string) {
if (this.hasContentLanguage(code2)) {
this.contentLanguages = this.contentLanguages.filter(
lang => lang !== code2,
)
} else {
this.contentLanguages = this.contentLanguages.concat([code2])
}
}
setContentLabelPref(
key: keyof LabelPreferencesModel,
value: LabelPreference,
) {
this.contentLabels[key] = value
}
getLabelPreference(labels: ComAtprotoLabelDefs.Label[] | undefined): {
pref: LabelPreference
desc: LabelValGroup
} {
let res: {pref: LabelPreference; desc: LabelValGroup} = {
pref: 'show',
desc: UNKNOWN_LABEL_GROUP,
}
if (!labels?.length) {
return res
}
for (const label of labels) {
const group = getLabelValueGroup(label.val)
if (group.id === 'illegal') {
return {pref: 'hide', desc: ILLEGAL_LABEL_GROUP}
} else if (group.id === 'unknown') {
continue
}
let pref = this.contentLabels[group.id]
if (pref === 'hide') {
res.pref = 'hide'
res.desc = group
} else if (pref === 'warn' && res.pref === 'show') {
res.pref = 'warn'
res.desc = group
}
}
return res
}
}