Merge branch 'main' into custom-algos
This commit is contained in:
commit
7aa1d9010e
99 changed files with 4234 additions and 716 deletions
|
|
@ -1,7 +1,8 @@
|
|||
import {makeAutoObservable} from 'mobx'
|
||||
import {makeAutoObservable, runInAction} from 'mobx'
|
||||
import {getLocales} from 'expo-localization'
|
||||
import {isObj, hasProp} from 'lib/type-guards'
|
||||
import {ComAtprotoLabelDefs} from '@atproto/api'
|
||||
import {RootStoreModel} from '../root-store'
|
||||
import {ComAtprotoLabelDefs, AppBskyActorDefs} from '@atproto/api'
|
||||
import {LabelValGroup} from 'lib/labeling/types'
|
||||
import {getLabelValueGroup} from 'lib/labeling/helpers'
|
||||
import {
|
||||
|
|
@ -15,6 +16,15 @@ import {isIOS} from 'platform/detection'
|
|||
const deviceLocales = getLocales()
|
||||
|
||||
export type LabelPreference = 'show' | 'warn' | 'hide'
|
||||
const LABEL_GROUPS = [
|
||||
'nsfw',
|
||||
'nudity',
|
||||
'suggestive',
|
||||
'gore',
|
||||
'hate',
|
||||
'spam',
|
||||
'impersonation',
|
||||
]
|
||||
|
||||
export class LabelPreferencesModel {
|
||||
nsfw: LabelPreference = 'hide'
|
||||
|
|
@ -36,7 +46,7 @@ export class PreferencesModel {
|
|||
deviceLocales?.map?.(locale => locale.languageCode) || []
|
||||
contentLabels = new LabelPreferencesModel()
|
||||
|
||||
constructor() {
|
||||
constructor(public rootStore: RootStoreModel) {
|
||||
makeAutoObservable(this, {}, {autoBind: true})
|
||||
}
|
||||
|
||||
|
|
@ -65,6 +75,35 @@ export class PreferencesModel {
|
|||
}
|
||||
}
|
||||
|
||||
async sync() {
|
||||
const res = await this.rootStore.agent.app.bsky.actor.getPreferences({})
|
||||
runInAction(() => {
|
||||
for (const pref of res.data.preferences) {
|
||||
if (
|
||||
AppBskyActorDefs.isAdultContentPref(pref) &&
|
||||
AppBskyActorDefs.validateAdultContentPref(pref).success
|
||||
) {
|
||||
this.adultContentEnabled = pref.enabled
|
||||
} else if (
|
||||
AppBskyActorDefs.isContentLabelPref(pref) &&
|
||||
AppBskyActorDefs.validateAdultContentPref(pref).success
|
||||
) {
|
||||
if (LABEL_GROUPS.includes(pref.label)) {
|
||||
this.contentLabels[pref.label] = pref.visibility
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async update(cb: (prefs: AppBskyActorDefs.Preferences) => void) {
|
||||
const res = await this.rootStore.agent.app.bsky.actor.getPreferences({})
|
||||
cb(res.data.preferences)
|
||||
await this.rootStore.agent.app.bsky.actor.putPreferences({
|
||||
preferences: res.data.preferences,
|
||||
})
|
||||
}
|
||||
|
||||
hasContentLanguage(code2: string) {
|
||||
return this.contentLanguages.includes(code2)
|
||||
}
|
||||
|
|
@ -79,11 +118,48 @@ export class PreferencesModel {
|
|||
}
|
||||
}
|
||||
|
||||
setContentLabelPref(
|
||||
async setContentLabelPref(
|
||||
key: keyof LabelPreferencesModel,
|
||||
value: LabelPreference,
|
||||
) {
|
||||
this.contentLabels[key] = value
|
||||
|
||||
await this.update((prefs: AppBskyActorDefs.Preferences) => {
|
||||
const existing = prefs.find(
|
||||
pref =>
|
||||
AppBskyActorDefs.isContentLabelPref(pref) &&
|
||||
AppBskyActorDefs.validateAdultContentPref(pref).success &&
|
||||
pref.label === key,
|
||||
)
|
||||
if (existing) {
|
||||
existing.visibility = value
|
||||
} else {
|
||||
prefs.push({
|
||||
$type: 'app.bsky.actor.defs#contentLabelPref',
|
||||
label: key,
|
||||
visibility: value,
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async setAdultContentEnabled(v: boolean) {
|
||||
this.adultContentEnabled = v
|
||||
await this.update((prefs: AppBskyActorDefs.Preferences) => {
|
||||
const existing = prefs.find(
|
||||
pref =>
|
||||
AppBskyActorDefs.isAdultContentPref(pref) &&
|
||||
AppBskyActorDefs.validateAdultContentPref(pref).success,
|
||||
)
|
||||
if (existing) {
|
||||
existing.enabled = v
|
||||
} else {
|
||||
prefs.push({
|
||||
$type: 'app.bsky.actor.defs#adultContentPref',
|
||||
enabled: v,
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
getLabelPreference(labels: ComAtprotoLabelDefs.Label[] | undefined): {
|
||||
|
|
|
|||
|
|
@ -1,20 +1,23 @@
|
|||
import {makeAutoObservable} from 'mobx'
|
||||
import {AppBskyFeedDefs} from '@atproto/api'
|
||||
import {RootStoreModel} from '../root-store'
|
||||
import {ProfileModel} from '../content/profile'
|
||||
import {PostsFeedModel} from '../feeds/posts'
|
||||
import {ActorFeedsModel} from '../feeds/algo/actor'
|
||||
import {AppBskyFeedDefs} from '@atproto/api'
|
||||
import {ListsListModel} from '../lists/lists-list'
|
||||
|
||||
export enum Sections {
|
||||
Posts = 'Posts',
|
||||
PostsWithReplies = 'Posts & replies',
|
||||
CustomAlgorithms = 'Algos',
|
||||
Lists = 'Lists',
|
||||
}
|
||||
|
||||
const USER_SELECTOR_ITEMS = [
|
||||
Sections.Posts,
|
||||
Sections.PostsWithReplies,
|
||||
Sections.CustomAlgorithms,
|
||||
Sections.Lists,
|
||||
]
|
||||
|
||||
export interface ProfileUiParams {
|
||||
|
|
@ -30,6 +33,7 @@ export class ProfileUiModel {
|
|||
profile: ProfileModel
|
||||
feed: PostsFeedModel
|
||||
algos: ActorFeedsModel
|
||||
lists: ListsListModel
|
||||
|
||||
// ui state
|
||||
selectedViewIndex = 0
|
||||
|
|
@ -52,14 +56,17 @@ export class ProfileUiModel {
|
|||
limit: 10,
|
||||
})
|
||||
this.algos = new ActorFeedsModel(rootStore, {actor: params.user})
|
||||
this.lists = new ListsListModel(rootStore, params.user)
|
||||
}
|
||||
|
||||
get currentView(): PostsFeedModel | ActorFeedsModel {
|
||||
get currentView(): PostsFeedModel | ActorFeedsModel | ListsListModel {
|
||||
if (
|
||||
this.selectedView === Sections.Posts ||
|
||||
this.selectedView === Sections.PostsWithReplies
|
||||
) {
|
||||
return this.feed
|
||||
} else if (this.selectedView === Sections.Lists) {
|
||||
return this.lists
|
||||
}
|
||||
if (this.selectedView === Sections.CustomAlgorithms) {
|
||||
return this.algos
|
||||
|
|
@ -121,6 +128,12 @@ export class ProfileUiModel {
|
|||
} else if (this.feed.isEmpty) {
|
||||
arr = arr.concat([ProfileUiModel.EMPTY_ITEM])
|
||||
}
|
||||
} else if (this.selectedView === Sections.Lists) {
|
||||
if (this.lists.hasContent) {
|
||||
arr = this.lists.lists
|
||||
} else if (this.lists.isEmpty) {
|
||||
arr = arr.concat([ProfileUiModel.EMPTY_ITEM])
|
||||
}
|
||||
} else {
|
||||
// fallback, add empty item, to show empty message
|
||||
arr = arr.concat([ProfileUiModel.EMPTY_ITEM])
|
||||
|
|
@ -135,6 +148,8 @@ export class ProfileUiModel {
|
|||
this.selectedView === Sections.PostsWithReplies
|
||||
) {
|
||||
return this.feed.hasContent && this.feed.hasMore && this.feed.isLoading
|
||||
} else if (this.selectedView === Sections.Lists) {
|
||||
return this.lists.hasContent && this.lists.hasMore && this.lists.isLoading
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
@ -155,6 +170,11 @@ export class ProfileUiModel {
|
|||
.setup()
|
||||
.catch(err => this.rootStore.log.error('Failed to fetch feed', err)),
|
||||
])
|
||||
// HACK: need to use the DID as a param, not the username -prf
|
||||
this.lists.source = this.profile.did
|
||||
this.lists
|
||||
.loadMore()
|
||||
.catch(err => this.rootStore.log.error('Failed to fetch lists', err))
|
||||
}
|
||||
|
||||
async update() {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import {ProfileModel} from '../content/profile'
|
|||
import {isObj, hasProp} from 'lib/type-guards'
|
||||
import {Image as RNImage} from 'react-native-image-crop-picker'
|
||||
import {ImageModel} from '../media/image'
|
||||
import {ListModel} from '../content/list'
|
||||
import {GalleryModel} from '../media/gallery'
|
||||
|
||||
export interface ConfirmModal {
|
||||
|
|
@ -38,6 +39,19 @@ export interface ReportAccountModal {
|
|||
did: string
|
||||
}
|
||||
|
||||
export interface CreateOrEditMuteListModal {
|
||||
name: 'create-or-edit-mute-list'
|
||||
list?: ListModel
|
||||
onSave?: (uri: string) => void
|
||||
}
|
||||
|
||||
export interface ListAddRemoveUserModal {
|
||||
name: 'list-add-remove-user'
|
||||
subject: string
|
||||
displayName: string
|
||||
onUpdate?: () => void
|
||||
}
|
||||
|
||||
export interface EditImageModal {
|
||||
name: 'edit-image'
|
||||
image: ImageModel
|
||||
|
|
@ -102,9 +116,11 @@ export type Modal =
|
|||
| ContentFilteringSettingsModal
|
||||
| ContentLanguagesSettingsModal
|
||||
|
||||
// Reporting
|
||||
// Moderation
|
||||
| ReportAccountModal
|
||||
| ReportPostModal
|
||||
| CreateMuteListModal
|
||||
| ListAddRemoveUserModal
|
||||
|
||||
// Posts
|
||||
| AltTextImageModal
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue