Remove scenes from the profile view
This commit is contained in:
@@ -8,17 +8,9 @@ import {FeedModel} from './feed-view'
|
|||||||
export enum Sections {
|
export enum Sections {
|
||||||
Posts = 'Posts',
|
Posts = 'Posts',
|
||||||
PostsWithReplies = 'Posts & replies',
|
PostsWithReplies = 'Posts & replies',
|
||||||
Scenes = 'Scenes',
|
|
||||||
Trending = 'Trending',
|
|
||||||
Members = 'Members',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const USER_SELECTOR_ITEMS = [
|
const USER_SELECTOR_ITEMS = [Sections.Posts, Sections.PostsWithReplies]
|
||||||
Sections.Posts,
|
|
||||||
Sections.PostsWithReplies,
|
|
||||||
Sections.Scenes,
|
|
||||||
]
|
|
||||||
const SCENE_SELECTOR_ITEMS = [Sections.Trending, Sections.Members]
|
|
||||||
|
|
||||||
export interface ProfileUiParams {
|
export interface ProfileUiParams {
|
||||||
user: string
|
user: string
|
||||||
@@ -28,8 +20,6 @@ export class ProfileUiModel {
|
|||||||
// data
|
// data
|
||||||
profile: ProfileViewModel
|
profile: ProfileViewModel
|
||||||
feed: FeedModel
|
feed: FeedModel
|
||||||
memberships: MembershipsViewModel
|
|
||||||
members: MembersViewModel
|
|
||||||
|
|
||||||
// ui state
|
// ui state
|
||||||
selectedViewIndex = 0
|
selectedViewIndex = 0
|
||||||
@@ -51,24 +41,15 @@ export class ProfileUiModel {
|
|||||||
author: params.user,
|
author: params.user,
|
||||||
limit: 10,
|
limit: 10,
|
||||||
})
|
})
|
||||||
this.memberships = new MembershipsViewModel(rootStore, {actor: params.user})
|
|
||||||
this.members = new MembersViewModel(rootStore, {actor: params.user})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get currentView(): FeedModel | MembershipsViewModel | MembersViewModel {
|
get currentView(): FeedModel | MembershipsViewModel | MembersViewModel {
|
||||||
if (
|
if (
|
||||||
this.selectedView === Sections.Posts ||
|
this.selectedView === Sections.Posts ||
|
||||||
this.selectedView === Sections.PostsWithReplies ||
|
this.selectedView === Sections.PostsWithReplies
|
||||||
this.selectedView === Sections.Trending
|
|
||||||
) {
|
) {
|
||||||
return this.feed
|
return this.feed
|
||||||
}
|
}
|
||||||
if (this.selectedView === Sections.Scenes) {
|
|
||||||
return this.memberships
|
|
||||||
}
|
|
||||||
if (this.selectedView === Sections.Members) {
|
|
||||||
return this.members
|
|
||||||
}
|
|
||||||
throw new Error(`Invalid selector value: ${this.selectedViewIndex}`)
|
throw new Error(`Invalid selector value: ${this.selectedViewIndex}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,15 +66,9 @@ export class ProfileUiModel {
|
|||||||
return this.profile.isUser
|
return this.profile.isUser
|
||||||
}
|
}
|
||||||
|
|
||||||
get isScene() {
|
|
||||||
return this.profile.isScene
|
|
||||||
}
|
|
||||||
|
|
||||||
get selectorItems() {
|
get selectorItems() {
|
||||||
if (this.isUser) {
|
if (this.isUser) {
|
||||||
return USER_SELECTOR_ITEMS
|
return USER_SELECTOR_ITEMS
|
||||||
} else if (this.isScene) {
|
|
||||||
return SCENE_SELECTOR_ITEMS
|
|
||||||
} else {
|
} else {
|
||||||
return USER_SELECTOR_ITEMS
|
return USER_SELECTOR_ITEMS
|
||||||
}
|
}
|
||||||
@@ -119,16 +94,6 @@ export class ProfileUiModel {
|
|||||||
.setup()
|
.setup()
|
||||||
.catch(err => this.rootStore.log.error('Failed to fetch feed', err)),
|
.catch(err => this.rootStore.log.error('Failed to fetch feed', err)),
|
||||||
])
|
])
|
||||||
if (this.isUser) {
|
|
||||||
await this.memberships
|
|
||||||
.setup()
|
|
||||||
.catch(err => this.rootStore.log.error('Failed to fetch members', err))
|
|
||||||
}
|
|
||||||
if (this.isScene) {
|
|
||||||
await this.members
|
|
||||||
.setup()
|
|
||||||
.catch(err => this.rootStore.log.error('Failed to fetch members', err))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async update() {
|
async update() {
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import {RootStoreModel} from './root-store'
|
|||||||
import * as apilib from '../lib/api'
|
import * as apilib from '../lib/api'
|
||||||
|
|
||||||
export const ACTOR_TYPE_USER = 'app.bsky.system.actorUser'
|
export const ACTOR_TYPE_USER = 'app.bsky.system.actorUser'
|
||||||
export const ACTOR_TYPE_SCENE = 'app.bsky.system.actorScene'
|
|
||||||
|
|
||||||
export class ProfileViewMyStateModel {
|
export class ProfileViewMyStateModel {
|
||||||
follow?: string
|
follow?: string
|
||||||
@@ -85,10 +84,6 @@ export class ProfileViewModel {
|
|||||||
return this.declaration.actorType === ACTOR_TYPE_USER
|
return this.declaration.actorType === ACTOR_TYPE_USER
|
||||||
}
|
}
|
||||||
|
|
||||||
get isScene() {
|
|
||||||
return this.declaration.actorType === ACTOR_TYPE_SCENE
|
|
||||||
}
|
|
||||||
|
|
||||||
// public api
|
// public api
|
||||||
// =
|
// =
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,12 @@
|
|||||||
import React, {useMemo} from 'react'
|
import React from 'react'
|
||||||
import {observer} from 'mobx-react-lite'
|
import {observer} from 'mobx-react-lite'
|
||||||
import {StyleSheet, TouchableOpacity, View} from 'react-native'
|
import {StyleSheet, TouchableOpacity, View} from 'react-native'
|
||||||
import LinearGradient from 'react-native-linear-gradient'
|
import LinearGradient from 'react-native-linear-gradient'
|
||||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||||
import {AtUri} from '../../../third-party/uri'
|
|
||||||
import {ProfileViewModel} from '../../../state/models/profile-view'
|
import {ProfileViewModel} from '../../../state/models/profile-view'
|
||||||
import {useStores} from '../../../state'
|
import {useStores} from '../../../state'
|
||||||
import {
|
import {
|
||||||
ConfirmModal,
|
|
||||||
EditProfileModal,
|
EditProfileModal,
|
||||||
InviteToSceneModal,
|
|
||||||
ReportAccountModal,
|
ReportAccountModal,
|
||||||
ProfileImageLightbox,
|
ProfileImageLightbox,
|
||||||
} from '../../../state/models/shell-ui'
|
} from '../../../state/models/shell-ui'
|
||||||
@@ -23,7 +20,6 @@ import {Text} from '../util/text/Text'
|
|||||||
import {RichText} from '../util/text/RichText'
|
import {RichText} from '../util/text/RichText'
|
||||||
import {UserAvatar} from '../util/UserAvatar'
|
import {UserAvatar} from '../util/UserAvatar'
|
||||||
import {UserBanner} from '../util/UserBanner'
|
import {UserBanner} from '../util/UserBanner'
|
||||||
import {UserInfoText} from '../util/UserInfoText'
|
|
||||||
import {usePalette} from '../../lib/hooks/usePalette'
|
import {usePalette} from '../../lib/hooks/usePalette'
|
||||||
|
|
||||||
export const ProfileHeader = observer(function ProfileHeader({
|
export const ProfileHeader = observer(function ProfileHeader({
|
||||||
@@ -35,10 +31,6 @@ export const ProfileHeader = observer(function ProfileHeader({
|
|||||||
}) {
|
}) {
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
const store = useStores()
|
const store = useStores()
|
||||||
const isMember = useMemo(
|
|
||||||
() => view.isScene && view.myState.member,
|
|
||||||
[view.myState.member],
|
|
||||||
)
|
|
||||||
|
|
||||||
const onPressAvi = () => {
|
const onPressAvi = () => {
|
||||||
store.shell.openLightbox(new ProfileImageLightbox(view))
|
store.shell.openLightbox(new ProfileImageLightbox(view))
|
||||||
@@ -64,31 +56,6 @@ export const ProfileHeader = observer(function ProfileHeader({
|
|||||||
const onPressFollows = () => {
|
const onPressFollows = () => {
|
||||||
store.nav.navigate(`/profile/${view.handle}/follows`)
|
store.nav.navigate(`/profile/${view.handle}/follows`)
|
||||||
}
|
}
|
||||||
const onPressMembers = () => {
|
|
||||||
store.nav.navigate(`/profile/${view.handle}/members`)
|
|
||||||
}
|
|
||||||
const onPressInviteMembers = () => {
|
|
||||||
store.shell.openModal(new InviteToSceneModal(view))
|
|
||||||
}
|
|
||||||
const onPressLeaveScene = () => {
|
|
||||||
store.shell.openModal(
|
|
||||||
new ConfirmModal(
|
|
||||||
'Leave this scene?',
|
|
||||||
`You'll be able to come back unless your invite is revoked.`,
|
|
||||||
onPressConfirmLeaveScene,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
const onPressConfirmLeaveScene = async () => {
|
|
||||||
if (view.myState.member) {
|
|
||||||
await store.api.app.bsky.graph.confirmation.delete({
|
|
||||||
did: store.me.did || '',
|
|
||||||
rkey: new AtUri(view.myState.member).rkey,
|
|
||||||
})
|
|
||||||
Toast.show(`Scene left`)
|
|
||||||
}
|
|
||||||
onRefreshAll()
|
|
||||||
}
|
|
||||||
const onPressMuteAccount = async () => {
|
const onPressMuteAccount = async () => {
|
||||||
try {
|
try {
|
||||||
await view.muteAccount()
|
await view.muteAccount()
|
||||||
@@ -157,7 +124,6 @@ export const ProfileHeader = observer(function ProfileHeader({
|
|||||||
// =
|
// =
|
||||||
const gradient = getGradient(view.handle)
|
const gradient = getGradient(view.handle)
|
||||||
const isMe = store.me.did === view.did
|
const isMe = store.me.did === view.did
|
||||||
const isCreator = view.isScene && view.creator === store.me.did
|
|
||||||
let dropdownItems: DropdownItem[] | undefined
|
let dropdownItems: DropdownItem[] | undefined
|
||||||
if (!isMe) {
|
if (!isMe) {
|
||||||
dropdownItems = dropdownItems || []
|
dropdownItems = dropdownItems || []
|
||||||
@@ -170,21 +136,6 @@ export const ProfileHeader = observer(function ProfileHeader({
|
|||||||
onPress: onPressReportAccount,
|
onPress: onPressReportAccount,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (isCreator || isMember) {
|
|
||||||
dropdownItems = dropdownItems || []
|
|
||||||
if (isCreator) {
|
|
||||||
dropdownItems.push({
|
|
||||||
label: 'Edit Profile',
|
|
||||||
onPress: onPressEditProfile,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (isMember) {
|
|
||||||
dropdownItems.push({
|
|
||||||
label: 'Leave Scene...',
|
|
||||||
onPress: onPressLeaveScene,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
<View style={pal.view}>
|
<View style={pal.view}>
|
||||||
<UserBanner handle={view.handle} banner={view.banner} />
|
<UserBanner handle={view.handle} banner={view.banner} />
|
||||||
@@ -244,15 +195,6 @@ export const ProfileHeader = observer(function ProfileHeader({
|
|||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.handleLine}>
|
<View style={styles.handleLine}>
|
||||||
{view.isScene ? (
|
|
||||||
<View
|
|
||||||
style={[
|
|
||||||
styles.typeLabelWrapper,
|
|
||||||
{backgroundColor: pal.colors.backgroundLight},
|
|
||||||
]}>
|
|
||||||
<Text style={[styles.typeLabel, pal.textLight]}>Scene</Text>
|
|
||||||
</View>
|
|
||||||
) : undefined}
|
|
||||||
<Text style={pal.textLight}>@{view.handle}</Text>
|
<Text style={pal.textLight}>@{view.handle}</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.metricsLine}>
|
<View style={styles.metricsLine}>
|
||||||
@@ -278,18 +220,6 @@ export const ProfileHeader = observer(function ProfileHeader({
|
|||||||
</Text>
|
</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
{view.isScene ? (
|
|
||||||
<TouchableOpacity
|
|
||||||
style={[s.flexRow, s.mr10]}
|
|
||||||
onPress={onPressMembers}>
|
|
||||||
<Text type="body2" style={[s.bold, s.mr2, pal.text]}>
|
|
||||||
{view.membersCount}
|
|
||||||
</Text>
|
|
||||||
<Text type="body2" style={[pal.textLight]}>
|
|
||||||
{pluralize(view.membersCount, 'member')}
|
|
||||||
</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
) : undefined}
|
|
||||||
<View style={[s.flexRow, s.mr10]}>
|
<View style={[s.flexRow, s.mr10]}>
|
||||||
<Text type="body2" style={[s.bold, s.mr2, pal.text]}>
|
<Text type="body2" style={[s.bold, s.mr2, pal.text]}>
|
||||||
{view.postsCount}
|
{view.postsCount}
|
||||||
@@ -307,35 +237,6 @@ export const ProfileHeader = observer(function ProfileHeader({
|
|||||||
entities={view.descriptionEntities}
|
entities={view.descriptionEntities}
|
||||||
/>
|
/>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
{view.isScene && view.creator ? (
|
|
||||||
<View style={styles.detailLine}>
|
|
||||||
<FontAwesomeIcon
|
|
||||||
icon={['far', 'user']}
|
|
||||||
style={[pal.textLight, s.mr5]}
|
|
||||||
/>
|
|
||||||
<Text type="body2" style={[s.mr2, pal.textLight]}>
|
|
||||||
Created by
|
|
||||||
</Text>
|
|
||||||
<UserInfoText
|
|
||||||
type="body2"
|
|
||||||
style={[pal.link]}
|
|
||||||
did={view.creator}
|
|
||||||
prefix="@"
|
|
||||||
asLink
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
) : undefined}
|
|
||||||
{view.isScene && view.myState.member ? (
|
|
||||||
<View style={styles.detailLine}>
|
|
||||||
<FontAwesomeIcon
|
|
||||||
icon={['far', 'circle-check']}
|
|
||||||
style={[pal.textLight, s.mr5]}
|
|
||||||
/>
|
|
||||||
<Text type="body2" style={[s.mr2, pal.textLight]}>
|
|
||||||
You are a member
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
) : undefined}
|
|
||||||
{view.myState.muted ? (
|
{view.myState.muted ? (
|
||||||
<View style={[styles.detailLine, pal.btn, s.p5]}>
|
<View style={[styles.detailLine, pal.btn, s.p5]}>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
@@ -348,26 +249,6 @@ export const ProfileHeader = observer(function ProfileHeader({
|
|||||||
</View>
|
</View>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
</View>
|
</View>
|
||||||
{view.isScene && view.creator === store.me.did ? (
|
|
||||||
<View style={[styles.sceneAdminContainer, pal.border]}>
|
|
||||||
<TouchableOpacity onPress={onPressInviteMembers}>
|
|
||||||
<LinearGradient
|
|
||||||
colors={[gradient[1], gradient[0]]}
|
|
||||||
start={{x: 0, y: 0}}
|
|
||||||
end={{x: 1, y: 1}}
|
|
||||||
style={[styles.btn, styles.gradientBtn, styles.sceneAdminBtn]}>
|
|
||||||
<FontAwesomeIcon
|
|
||||||
icon="user-plus"
|
|
||||||
style={[s.mr5, s.white]}
|
|
||||||
size={15}
|
|
||||||
/>
|
|
||||||
<Text type="button" style={[s.bold, s.white]}>
|
|
||||||
Invite Members
|
|
||||||
</Text>
|
|
||||||
</LinearGradient>
|
|
||||||
</TouchableOpacity>
|
|
||||||
</View>
|
|
||||||
) : undefined}
|
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={[pal.view, {borderColor: pal.colors.background}, styles.avi]}
|
style={[pal.view, {borderColor: pal.colors.background}, styles.avi]}
|
||||||
onPress={onPressAvi}>
|
onPress={onPressAvi}>
|
||||||
@@ -435,15 +316,6 @@ const styles = StyleSheet.create({
|
|||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
marginBottom: 8,
|
marginBottom: 8,
|
||||||
},
|
},
|
||||||
typeLabelWrapper: {
|
|
||||||
paddingHorizontal: 4,
|
|
||||||
borderRadius: 4,
|
|
||||||
marginRight: 5,
|
|
||||||
},
|
|
||||||
typeLabel: {
|
|
||||||
fontSize: 15,
|
|
||||||
fontWeight: 'bold',
|
|
||||||
},
|
|
||||||
|
|
||||||
metricsLine: {
|
metricsLine: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
@@ -459,14 +331,4 @@ const styles = StyleSheet.create({
|
|||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
marginBottom: 5,
|
marginBottom: 5,
|
||||||
},
|
},
|
||||||
|
|
||||||
sceneAdminContainer: {
|
|
||||||
borderTopWidth: 1,
|
|
||||||
borderBottomWidth: 1,
|
|
||||||
paddingVertical: 12,
|
|
||||||
paddingHorizontal: 12,
|
|
||||||
},
|
|
||||||
sceneAdminBtn: {
|
|
||||||
paddingVertical: 8,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user