[APP-635] Mutelists (#601)

* Add lists and profilelist screens

* Implement lists screen and lists-list in profiles

* Add empty states to the lists screen

* Switch (mostly) from blocklists to mutelists

* Rework: create a new moderation screen and move everything related under it

* Fix moderation screen on desktop web

* Tune the empty state code

* Change content moderation modal to content filtering

* Add CreateMuteList modal

* Implement mutelist creation

* Add lists listings

* Add the ability to create new mutelists

* Add 'add to list' tool

* Satisfy the hashtag hyphen haters

* Add update/delete/subscribe/unsubscribe to lists

* Show which list caused a mute

* Add list un/subscribe

* Add the mute override when viewing a profile's posts

* Update to latest backend

* Add simulation tests and tune some behaviors

* Fix lint

* Bump deps

* Fix list refresh after creation

* Mute list subscriptions -> Mute lists
This commit is contained in:
Paul Frazee 2023-05-11 16:08:21 -05:00 committed by GitHub
parent 34d8fa5991
commit ebcd633386
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
48 changed files with 2984 additions and 151 deletions

View file

@ -2,13 +2,19 @@ import {makeAutoObservable} from 'mobx'
import {RootStoreModel} from '../root-store'
import {ProfileModel} from '../content/profile'
import {PostsFeedModel} from '../feeds/posts'
import {ListsListModel} from '../lists/lists-list'
export enum Sections {
Posts = 'Posts',
PostsWithReplies = 'Posts & replies',
Lists = 'Lists',
}
const USER_SELECTOR_ITEMS = [Sections.Posts, Sections.PostsWithReplies]
const USER_SELECTOR_ITEMS = [
Sections.Posts,
Sections.PostsWithReplies,
Sections.Lists,
]
export interface ProfileUiParams {
user: string
@ -22,6 +28,7 @@ export class ProfileUiModel {
// data
profile: ProfileModel
feed: PostsFeedModel
lists: ListsListModel
// ui state
selectedViewIndex = 0
@ -43,14 +50,17 @@ export class ProfileUiModel {
actor: params.user,
limit: 10,
})
this.lists = new ListsListModel(rootStore, params.user)
}
get currentView(): PostsFeedModel {
get currentView(): PostsFeedModel | ListsListModel {
if (
this.selectedView === Sections.Posts ||
this.selectedView === Sections.PostsWithReplies
) {
return this.feed
} else if (this.selectedView === Sections.Lists) {
return this.lists
}
throw new Error(`Invalid selector value: ${this.selectedViewIndex}`)
}
@ -100,6 +110,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 {
arr = arr.concat([ProfileUiModel.EMPTY_ITEM])
}
@ -113,6 +129,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
}
@ -133,6 +151,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() {

View file

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