diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/state/models/feed-view.ts | 28 | ||||
-rw-r--r-- | src/view/index.ts | 2 | ||||
-rw-r--r-- | src/view/screens/Home.tsx | 56 |
3 files changed, 83 insertions, 3 deletions
diff --git a/src/state/models/feed-view.ts b/src/state/models/feed-view.ts index 436b47038..a746993cf 100644 --- a/src/state/models/feed-view.ts +++ b/src/state/models/feed-view.ts @@ -149,6 +149,7 @@ export class FeedModel { // state isLoading = false isRefreshing = false + hasNewLatest = false hasLoaded = false error = '' params: GetTimeline.QueryParams | GetAuthorFeed.QueryParams @@ -195,6 +196,10 @@ export class FeedModel { return this.hasLoaded && !this.hasContent } + setHasNewLatest(v: boolean) { + this.hasNewLatest = v + } + // public api // = @@ -209,6 +214,7 @@ export class FeedModel { return this._loadPromise } await this._pendingWork() + this.setHasNewLatest(false) this._loadPromise = this._initialLoad(isRefreshing) await this._loadPromise this._loadPromise = undefined @@ -242,6 +248,7 @@ export class FeedModel { return this._loadLatestPromise } await this._pendingWork() + this.setHasNewLatest(false) this._loadLatestPromise = this._loadLatest() await this._loadLatestPromise this._loadLatestPromise = undefined @@ -260,6 +267,21 @@ export class FeedModel { this._updatePromise = undefined } + /** + * Check if new postrs are available + */ + async checkForLatest() { + if (this.hasNewLatest) { + return + } + await this._pendingWork() + const res = await this._getFeed({limit: 1}) + this.setHasNewLatest( + res.data.feed[0] && + (this.feed.length === 0 || res.data.feed[0].uri !== this.feed[0]?.uri), + ) + } + // state transitions // = @@ -380,10 +402,14 @@ export class FeedModel { private _prependAll(res: GetTimeline.Response | GetAuthorFeed.Response) { let counter = this.feed.length + const toPrepend = [] for (const item of res.data.feed) { if (this.feed.find(item2 => item2.uri === item.uri)) { - return // stop here - we've hit a post we already ahve + return // stop here - we've hit a post we already have } + toPrepend.unshift(item) // reverse the order + } + for (const item of toPrepend) { this._prepend(counter++, item) } } diff --git a/src/view/index.ts b/src/view/index.ts index 3b9a92ebd..e38e1debf 100644 --- a/src/view/index.ts +++ b/src/view/index.ts @@ -6,6 +6,7 @@ import {faAngleLeft} from '@fortawesome/free-solid-svg-icons/faAngleLeft' import {faAngleRight} from '@fortawesome/free-solid-svg-icons/faAngleRight' import {faArrowLeft} from '@fortawesome/free-solid-svg-icons/faArrowLeft' import {faArrowRight} from '@fortawesome/free-solid-svg-icons/faArrowRight' +import {faArrowUp} from '@fortawesome/free-solid-svg-icons/faArrowUp' import {faArrowRightFromBracket} from '@fortawesome/free-solid-svg-icons' import {faArrowUpFromBracket} from '@fortawesome/free-solid-svg-icons/faArrowUpFromBracket' import {faArrowUpRightFromSquare} from '@fortawesome/free-solid-svg-icons/faArrowUpRightFromSquare' @@ -64,6 +65,7 @@ export function setup() { faAngleRight, faArrowLeft, faArrowRight, + faArrowUp, faArrowRightFromBracket, faArrowUpFromBracket, faArrowUpRightFromSquare, diff --git a/src/view/screens/Home.tsx b/src/view/screens/Home.tsx index 04ce2d0cb..7abbfdbd9 100644 --- a/src/view/screens/Home.tsx +++ b/src/view/screens/Home.tsx @@ -1,13 +1,15 @@ import React, {useState, useEffect, useMemo} from 'react' -import {View} from 'react-native' +import {StyleSheet, Text, TouchableOpacity, View} from 'react-native' import {observer} from 'mobx-react-lite' +import useAppState from 'react-native-appstate-hook' +import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {ViewHeader} from '../com/util/ViewHeader' import {Feed} from '../com/posts/Feed' import {FAB} from '../com/util/FloatingActionButton' import {useStores} from '../../state' import {FeedModel} from '../../state/models/feed-view' import {ScreenParams} from '../routes' -import {s} from '../lib/styles' +import {s, colors} from '../lib/styles' export const Home = observer(function Home({ visible, @@ -15,6 +17,9 @@ export const Home = observer(function Home({ }: ScreenParams) { const store = useStores() const [hasSetup, setHasSetup] = useState<boolean>(false) + const {appState} = useAppState({ + onForeground: () => doPoll(true), + }) const defaultFeedView = useMemo<FeedModel>( () => new FeedModel(store, 'home', { @@ -23,9 +28,24 @@ export const Home = observer(function Home({ [store], ) + const doPoll = (knownActive = false) => { + if ((!knownActive && appState !== 'active') || !visible) { + return + } + if (defaultFeedView.isLoading) { + return + } + console.log('Polling home feed') + defaultFeedView.checkForLatest().catch(e => { + console.error('Failed to poll feed', e) + }) + } + useEffect(() => { let aborted = false + const pollInterval = setInterval(() => doPoll(), 15e3) if (!visible) { + console.log('hit') return } if (hasSetup) { @@ -40,6 +60,7 @@ export const Home = observer(function Home({ }) } return () => { + clearInterval(pollInterval) aborted = true } }, [visible, store]) @@ -53,6 +74,10 @@ export const Home = observer(function Home({ const onPressTryAgain = () => { defaultFeedView.refresh() } + const onPressLoadLatest = () => { + defaultFeedView.refresh() + scrollElRef?.current?.scrollToOffset({offset: 0}) + } return ( <View style={s.flex1}> @@ -64,7 +89,34 @@ export const Home = observer(function Home({ style={{flex: 1}} onPressTryAgain={onPressTryAgain} /> + {defaultFeedView.hasNewLatest ? ( + <TouchableOpacity style={styles.loadLatest} onPress={onPressLoadLatest}> + <FontAwesomeIcon icon="arrow-up" style={{color: colors.white}} /> + <Text style={styles.loadLatestText}>Load new posts</Text> + </TouchableOpacity> + ) : undefined} <FAB icon="pen-nib" onPress={onComposePress} /> </View> ) }) + +const styles = StyleSheet.create({ + loadLatest: { + flexDirection: 'row', + position: 'absolute', + left: 10, + bottom: 15, + backgroundColor: colors.pink3, + paddingHorizontal: 10, + paddingVertical: 8, + borderRadius: 30, + shadowColor: '#000', + shadowOpacity: 0.3, + shadowOffset: {width: 0, height: 1}, + }, + loadLatestText: { + color: colors.white, + fontWeight: 'bold', + marginLeft: 5, + }, +}) |