Add 'loading more' spinner to feeds
parent
2b27be31e6
commit
8501cf1c7d
|
@ -1,6 +1,12 @@
|
||||||
import React, {MutableRefObject} from 'react'
|
import React, {MutableRefObject} from 'react'
|
||||||
import {observer} from 'mobx-react-lite'
|
import {observer} from 'mobx-react-lite'
|
||||||
import {View, FlatList, StyleProp, ViewStyle} from 'react-native'
|
import {
|
||||||
|
ActivityIndicator,
|
||||||
|
View,
|
||||||
|
FlatList,
|
||||||
|
StyleProp,
|
||||||
|
ViewStyle,
|
||||||
|
} from 'react-native'
|
||||||
import {PostFeedLoadingPlaceholder} from '../util/LoadingPlaceholder'
|
import {PostFeedLoadingPlaceholder} from '../util/LoadingPlaceholder'
|
||||||
import {EmptyState} from '../util/EmptyState'
|
import {EmptyState} from '../util/EmptyState'
|
||||||
import {ErrorMessage} from '../util/ErrorMessage'
|
import {ErrorMessage} from '../util/ErrorMessage'
|
||||||
|
@ -57,6 +63,14 @@ export const Feed = observer(function Feed({
|
||||||
data = [COMPOSE_PROMPT_ITEM].concat(feed.feed)
|
data = [COMPOSE_PROMPT_ITEM].concat(feed.feed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const FeedFooter = () =>
|
||||||
|
feed.isLoading ? (
|
||||||
|
<View style={{paddingTop: 20}}>
|
||||||
|
<ActivityIndicator />
|
||||||
|
</View>
|
||||||
|
) : (
|
||||||
|
<View />
|
||||||
|
)
|
||||||
return (
|
return (
|
||||||
<View style={style}>
|
<View style={style}>
|
||||||
{!data && <ComposePrompt onPressCompose={onPressCompose} />}
|
{!data && <ComposePrompt onPressCompose={onPressCompose} />}
|
||||||
|
@ -75,6 +89,7 @@ export const Feed = observer(function Feed({
|
||||||
data={data}
|
data={data}
|
||||||
keyExtractor={item => item._reactKey}
|
keyExtractor={item => item._reactKey}
|
||||||
renderItem={renderItem}
|
renderItem={renderItem}
|
||||||
|
ListFooterComponent={FeedFooter}
|
||||||
refreshing={feed.isRefreshing}
|
refreshing={feed.isRefreshing}
|
||||||
contentContainerStyle={{paddingBottom: 100}}
|
contentContainerStyle={{paddingBottom: 100}}
|
||||||
onRefresh={onRefresh}
|
onRefresh={onRefresh}
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import React, {useEffect, useState, useMemo} from 'react'
|
import React, {useEffect, useState} from 'react'
|
||||||
import {FlatList, StyleSheet, View} from 'react-native'
|
import {FlatList, View} from 'react-native'
|
||||||
import {Selector} from './Selector'
|
import {Selector} from './Selector'
|
||||||
import {HorzSwipe} from './gestures/HorzSwipe'
|
import {HorzSwipe} from './gestures/HorzSwipe'
|
||||||
import {useAnimatedValue} from '../../lib/useAnimatedValue'
|
import {useAnimatedValue} from '../../lib/useAnimatedValue'
|
||||||
import {useStores} from '../../../state'
|
|
||||||
|
|
||||||
const HEADER_ITEM = {_reactKey: '__header__'}
|
const HEADER_ITEM = {_reactKey: '__header__'}
|
||||||
const SELECTOR_ITEM = {_reactKey: '__selector__'}
|
const SELECTOR_ITEM = {_reactKey: '__selector__'}
|
||||||
|
@ -16,6 +15,7 @@ export function ViewSelector({
|
||||||
swipeEnabled,
|
swipeEnabled,
|
||||||
renderHeader,
|
renderHeader,
|
||||||
renderItem,
|
renderItem,
|
||||||
|
ListFooterComponent,
|
||||||
onSelectView,
|
onSelectView,
|
||||||
onRefresh,
|
onRefresh,
|
||||||
onEndReached,
|
onEndReached,
|
||||||
|
@ -26,11 +26,15 @@ export function ViewSelector({
|
||||||
swipeEnabled?: boolean
|
swipeEnabled?: boolean
|
||||||
renderHeader?: () => JSX.Element
|
renderHeader?: () => JSX.Element
|
||||||
renderItem: (item: any) => JSX.Element
|
renderItem: (item: any) => JSX.Element
|
||||||
|
ListFooterComponent?:
|
||||||
|
| React.ComponentType<any>
|
||||||
|
| React.ReactElement
|
||||||
|
| null
|
||||||
|
| undefined
|
||||||
onSelectView?: (viewIndex: number) => void
|
onSelectView?: (viewIndex: number) => void
|
||||||
onRefresh?: () => void
|
onRefresh?: () => void
|
||||||
onEndReached?: (info: {distanceFromEnd: number}) => void
|
onEndReached?: (info: {distanceFromEnd: number}) => void
|
||||||
}) {
|
}) {
|
||||||
const store = useStores()
|
|
||||||
const [selectedIndex, setSelectedIndex] = useState<number>(0)
|
const [selectedIndex, setSelectedIndex] = useState<number>(0)
|
||||||
const panX = useAnimatedValue(0)
|
const panX = useAnimatedValue(0)
|
||||||
|
|
||||||
|
@ -83,6 +87,7 @@ export function ViewSelector({
|
||||||
data={data}
|
data={data}
|
||||||
keyExtractor={item => item._reactKey}
|
keyExtractor={item => item._reactKey}
|
||||||
renderItem={renderItemInternal}
|
renderItem={renderItemInternal}
|
||||||
|
ListFooterComponent={ListFooterComponent}
|
||||||
stickyHeaderIndices={STICKY_HEADER_INDICES}
|
stickyHeaderIndices={STICKY_HEADER_INDICES}
|
||||||
refreshing={refreshing}
|
refreshing={refreshing}
|
||||||
onRefresh={onRefresh}
|
onRefresh={onRefresh}
|
||||||
|
@ -91,5 +96,3 @@ export function ViewSelector({
|
||||||
</HorzSwipe>
|
</HorzSwipe>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({})
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React, {useEffect, useState, useMemo} from 'react'
|
import React, {useEffect, useState, useMemo} from 'react'
|
||||||
import {StyleSheet, Text, View} from 'react-native'
|
import {ActivityIndicator, StyleSheet, Text, View} from 'react-native'
|
||||||
import {observer} from 'mobx-react-lite'
|
import {observer} from 'mobx-react-lite'
|
||||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||||
import {ViewSelector} from '../com/util/ViewSelector'
|
import {ViewSelector} from '../com/util/ViewSelector'
|
||||||
|
@ -97,6 +97,7 @@ export const Profile = observer(({navIdx, visible, params}: ScreenParams) => {
|
||||||
return <ProfileHeader view={uiState.profile} onRefreshAll={onRefresh} />
|
return <ProfileHeader view={uiState.profile} onRefreshAll={onRefresh} />
|
||||||
}
|
}
|
||||||
let renderItem
|
let renderItem
|
||||||
|
let Footer
|
||||||
let items: any[] = []
|
let items: any[] = []
|
||||||
if (uiState) {
|
if (uiState) {
|
||||||
if (uiState.isInitialLoading) {
|
if (uiState.isInitialLoading) {
|
||||||
|
@ -132,6 +133,8 @@ export const Profile = observer(({navIdx, visible, params}: ScreenParams) => {
|
||||||
}
|
}
|
||||||
if (!uiState.feed.hasMore) {
|
if (!uiState.feed.hasMore) {
|
||||||
items = items.concat([END_ITEM])
|
items = items.concat([END_ITEM])
|
||||||
|
} else {
|
||||||
|
Footer = LoadingMoreFooter
|
||||||
}
|
}
|
||||||
renderItem = (item: any) => {
|
renderItem = (item: any) => {
|
||||||
if (item === END_ITEM) {
|
if (item === END_ITEM) {
|
||||||
|
@ -246,6 +249,7 @@ export const Profile = observer(({navIdx, visible, params}: ScreenParams) => {
|
||||||
items={items}
|
items={items}
|
||||||
renderHeader={renderHeader}
|
renderHeader={renderHeader}
|
||||||
renderItem={renderItem}
|
renderItem={renderItem}
|
||||||
|
ListFooterComponent={Footer}
|
||||||
refreshing={uiState.isRefreshing || false}
|
refreshing={uiState.isRefreshing || false}
|
||||||
onSelectView={onSelectView}
|
onSelectView={onSelectView}
|
||||||
onRefresh={onRefresh}
|
onRefresh={onRefresh}
|
||||||
|
@ -258,6 +262,14 @@ export const Profile = observer(({navIdx, visible, params}: ScreenParams) => {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function LoadingMoreFooter() {
|
||||||
|
return (
|
||||||
|
<View style={{paddingVertical: 20}}>
|
||||||
|
<ActivityIndicator />
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
|
|
Loading…
Reference in New Issue