Feeds tab fixes (#1486)
* Bold the saved feeds on mobile * Improve the saved feeds loading state * Add soft reset handler to feeds page * Show feed descriptions in profile listing * Add an 'about this feed' modal * Fix type assertionzio/stable
parent
753fb8bfbc
commit
971c8025e6
|
@ -8,6 +8,11 @@ export type MyFeedsItem =
|
||||||
_reactKey: string
|
_reactKey: string
|
||||||
type: 'spinner'
|
type: 'spinner'
|
||||||
}
|
}
|
||||||
|
| {
|
||||||
|
_reactKey: string
|
||||||
|
type: 'saved-feeds-loading'
|
||||||
|
numItems: number
|
||||||
|
}
|
||||||
| {
|
| {
|
||||||
_reactKey: string
|
_reactKey: string
|
||||||
type: 'discover-feeds-loading'
|
type: 'discover-feeds-loading'
|
||||||
|
@ -91,7 +96,8 @@ export class MyFeedsUIModel {
|
||||||
if (this.saved.isLoading) {
|
if (this.saved.isLoading) {
|
||||||
items.push({
|
items.push({
|
||||||
_reactKey: '__saved_feeds_loading__',
|
_reactKey: '__saved_feeds_loading__',
|
||||||
type: 'spinner',
|
type: 'saved-feeds-loading',
|
||||||
|
numItems: this.rootStore.preferences.savedFeeds.length || 3,
|
||||||
})
|
})
|
||||||
} else if (this.saved.hasError) {
|
} else if (this.saved.hasError) {
|
||||||
items.push({
|
items.push({
|
||||||
|
|
|
@ -185,6 +185,17 @@ export const CustomFeedScreenInner = observer(
|
||||||
})
|
})
|
||||||
}, [store, currentFeed])
|
}, [store, currentFeed])
|
||||||
|
|
||||||
|
const onPressAbout = React.useCallback(() => {
|
||||||
|
store.shell.openModal({
|
||||||
|
name: 'confirm',
|
||||||
|
title: currentFeed?.displayName || '',
|
||||||
|
message:
|
||||||
|
currentFeed?.data.description || 'This feed has no description.',
|
||||||
|
confirmBtnText: 'Close',
|
||||||
|
onPressConfirm() {},
|
||||||
|
})
|
||||||
|
}, [store, currentFeed])
|
||||||
|
|
||||||
const onPressViewAuthor = React.useCallback(() => {
|
const onPressViewAuthor = React.useCallback(() => {
|
||||||
navigation.navigate('Profile', {name: handleOrDid})
|
navigation.navigate('Profile', {name: handleOrDid})
|
||||||
}, [handleOrDid, navigation])
|
}, [handleOrDid, navigation])
|
||||||
|
@ -233,7 +244,21 @@ export const CustomFeedScreenInner = observer(
|
||||||
}, [store, onSoftReset, isScreenFocused])
|
}, [store, onSoftReset, isScreenFocused])
|
||||||
|
|
||||||
const dropdownItems: DropdownItem[] = React.useMemo(() => {
|
const dropdownItems: DropdownItem[] = React.useMemo(() => {
|
||||||
let items: DropdownItem[] = [
|
return [
|
||||||
|
currentFeed
|
||||||
|
? {
|
||||||
|
testID: 'feedHeaderDropdownAboutBtn',
|
||||||
|
label: 'About this feed',
|
||||||
|
onPress: onPressAbout,
|
||||||
|
icon: {
|
||||||
|
ios: {
|
||||||
|
name: 'info.circle',
|
||||||
|
},
|
||||||
|
android: '',
|
||||||
|
web: 'info',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
{
|
{
|
||||||
testID: 'feedHeaderDropdownViewAuthorBtn',
|
testID: 'feedHeaderDropdownViewAuthorBtn',
|
||||||
label: 'View author',
|
label: 'View author',
|
||||||
|
@ -292,10 +317,10 @@ export const CustomFeedScreenInner = observer(
|
||||||
web: 'share',
|
web: 'share',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]
|
].filter(Boolean) as DropdownItem[]
|
||||||
return items
|
|
||||||
}, [
|
}, [
|
||||||
currentFeed?.isSaved,
|
currentFeed,
|
||||||
|
onPressAbout,
|
||||||
onToggleSaved,
|
onToggleSaved,
|
||||||
onPressReport,
|
onPressReport,
|
||||||
onPressShare,
|
onPressShare,
|
||||||
|
|
|
@ -16,7 +16,10 @@ import {ComposeIcon2, CogIcon} from 'lib/icons'
|
||||||
import {s} from 'lib/styles'
|
import {s} from 'lib/styles'
|
||||||
import {SearchInput} from 'view/com/util/forms/SearchInput'
|
import {SearchInput} from 'view/com/util/forms/SearchInput'
|
||||||
import {UserAvatar} from 'view/com/util/UserAvatar'
|
import {UserAvatar} from 'view/com/util/UserAvatar'
|
||||||
import {FeedFeedLoadingPlaceholder} from 'view/com/util/LoadingPlaceholder'
|
import {
|
||||||
|
LoadingPlaceholder,
|
||||||
|
FeedFeedLoadingPlaceholder,
|
||||||
|
} from 'view/com/util/LoadingPlaceholder'
|
||||||
import {ErrorMessage} from 'view/com/util/error/ErrorMessage'
|
import {ErrorMessage} from 'view/com/util/error/ErrorMessage'
|
||||||
import debounce from 'lodash.debounce'
|
import debounce from 'lodash.debounce'
|
||||||
import {Text} from 'view/com/util/text/Text'
|
import {Text} from 'view/com/util/text/Text'
|
||||||
|
@ -42,7 +45,12 @@ export const FeedsScreen = withAuthRequired(
|
||||||
React.useCallback(() => {
|
React.useCallback(() => {
|
||||||
store.shell.setMinimalShellMode(false)
|
store.shell.setMinimalShellMode(false)
|
||||||
myFeeds.setup()
|
myFeeds.setup()
|
||||||
}, [store.shell, myFeeds]),
|
|
||||||
|
const softResetSub = store.onScreenSoftReset(() => myFeeds.refresh())
|
||||||
|
return () => {
|
||||||
|
softResetSub.remove()
|
||||||
|
}
|
||||||
|
}, [store, myFeeds]),
|
||||||
)
|
)
|
||||||
|
|
||||||
const onPressCompose = React.useCallback(() => {
|
const onPressCompose = React.useCallback(() => {
|
||||||
|
@ -119,6 +127,14 @@ export const FeedsScreen = withAuthRequired(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return <View />
|
return <View />
|
||||||
|
} else if (item.type === 'saved-feeds-loading') {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{Array.from(Array(item.numItems)).map((_, i) => (
|
||||||
|
<SavedFeedLoadingPlaceholder key={`placeholder-${i}`} />
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
)
|
||||||
} else if (item.type === 'saved-feed') {
|
} else if (item.type === 'saved-feed') {
|
||||||
return (
|
return (
|
||||||
<SavedFeed
|
<SavedFeed
|
||||||
|
@ -262,10 +278,7 @@ function SavedFeed({
|
||||||
asAnchor
|
asAnchor
|
||||||
anchorNoUnderline>
|
anchorNoUnderline>
|
||||||
<UserAvatar type="algo" size={28} avatar={avatar} />
|
<UserAvatar type="algo" size={28} avatar={avatar} />
|
||||||
<Text
|
<Text type="lg-medium" style={[pal.text, s.flex1]} numberOfLines={1}>
|
||||||
type={isMobile ? 'lg' : 'lg-medium'}
|
|
||||||
style={[pal.text, s.flex1]}
|
|
||||||
numberOfLines={1}>
|
|
||||||
{displayName}
|
{displayName}
|
||||||
</Text>
|
</Text>
|
||||||
{isMobile && (
|
{isMobile && (
|
||||||
|
@ -279,6 +292,22 @@ function SavedFeed({
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function SavedFeedLoadingPlaceholder() {
|
||||||
|
const pal = usePalette('default')
|
||||||
|
const {isMobile} = useWebMediaQueries()
|
||||||
|
return (
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
pal.border,
|
||||||
|
styles.savedFeed,
|
||||||
|
isMobile && styles.savedFeedMobile,
|
||||||
|
]}>
|
||||||
|
<LoadingPlaceholder width={28} height={28} style={{borderRadius: 4}} />
|
||||||
|
<LoadingPlaceholder width={140} height={12} />
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
|
|
|
@ -187,7 +187,9 @@ export const ProfileScreen = withAuthRequired(
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
} else if (item instanceof CustomFeedModel) {
|
} else if (item instanceof CustomFeedModel) {
|
||||||
return <CustomFeed item={item} showSaveBtn showLikes />
|
return (
|
||||||
|
<CustomFeed item={item} showSaveBtn showLikes showDescription />
|
||||||
|
)
|
||||||
}
|
}
|
||||||
// if section is posts or posts & replies
|
// if section is posts or posts & replies
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in New Issue