about summary refs log tree commit diff
path: root/src/state/models/ui/preferences.ts
blob: ae3f712c439257bd62a534a479ad05a6ca043b9a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import {makeAutoObservable} from 'mobx'
import {getLocales} from 'expo-localization'
import {isObj, hasProp} from 'lib/type-guards'
import {ComAtprotoLabelDefs} from '@atproto/api'
import {getLabelValueGroup} from 'lib/labeling/helpers'
import {
  LabelValGroup,
  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[] | undefined
  contentLabels = new LabelPreferencesModel()

  constructor() {
    makeAutoObservable(this, {}, {autoBind: true})
  }

  // gives an array of BCP 47 language tags without region codes
  get contentLanguages() {
    if (this._contentLanguages) {
      return this._contentLanguages
    }
    return deviceLocales.map(locale => locale.languageCode)
  }

  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)
      }
    }
  }

  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
  }
}