Show loading indicator

This commit is contained in:
Bruno Lemos
2018-11-27 20:41:34 -02:00
parent f0e72534a8
commit e4a3be1a3f
6 changed files with 86 additions and 22 deletions

View File

@@ -1,5 +1,5 @@
import React, { useContext } from 'react'
import { Text, View } from 'react-native'
import { ActivityIndicator, Text, View } from 'react-native'
import { contentPadding } from '../../styles/variables'
import { Button } from '../common/Button'
@@ -33,11 +33,14 @@ const emoji = getRandomEmoji()
export interface EmptyCardsProps {
fetchNextPage: ((params?: { perPage?: number }) => void) | undefined
state: 'loading' | 'loading_first' | 'loading_more' | 'loaded'
}
export function EmptyCards(props: EmptyCardsProps) {
const { theme } = useContext(ThemeContext)
const { fetchNextPage, state } = props
return (
<TransparentTextOverlay
color={theme.backgroundColor}
@@ -54,17 +57,23 @@ export function EmptyCards(props: EmptyCardsProps) {
padding: contentPadding,
}}
>
<Text style={{ color: theme.foregroundColorMuted50 }}>
{clearMessage} {emoji}
</Text>
{state === 'loading_first' ? (
<ActivityIndicator color={theme.foregroundColor} />
) : (
<Text style={{ color: theme.foregroundColorMuted50 }}>
{clearMessage} {emoji}
</Text>
)}
</View>
<View style={{ minHeight: 40 + 2 * contentPadding }}>
{!!props.fetchNextPage && (
{!!fetchNextPage && (
<View style={{ padding: contentPadding }}>
<Button
onPress={() => props.fetchNextPage!()}
children="Load more"
disabled={state !== 'loaded'}
loading={state === 'loading_more'}
onPress={() => fetchNextPage()}
/>
</View>
)}

View File

@@ -16,6 +16,7 @@ export interface EventCardsProps {
events: EnhancedGitHubEvent[]
fetchNextPage: ((params?: { perPage?: number }) => void) | undefined
repoIsKnown?: boolean
state: 'loading' | 'loading_first' | 'loading_more' | 'loaded'
swipeable?: boolean
}
@@ -47,22 +48,27 @@ export class EventCards extends PureComponent<
}
renderFooter = () => {
const { fetchNextPage } = this.props
const { fetchNextPage, state } = this.props
if (!fetchNextPage) return null
return (
<View style={{ padding: contentPadding }}>
<Button onPress={() => fetchNextPage()} children="Load more" />
<Button
disabled={state !== 'loaded'}
loading={state === 'loading_more'}
onPress={() => fetchNextPage()}
children="Load more"
/>
</View>
)
}
render() {
const { events, fetchNextPage } = this.props
const { events, fetchNextPage, state } = this.props
if (!(events && events.length))
return <EmptyCards fetchNextPage={fetchNextPage} />
return <EmptyCards fetchNextPage={fetchNextPage} state={state} />
return (
<ThemeConsumer>
@@ -74,6 +80,7 @@ export class EventCards extends PureComponent<
>
<FlatList
data={events}
extraData={state}
ItemSeparatorComponent={CardItemSeparator}
ListFooterComponent={this.renderFooter}
keyExtractor={this.keyExtractor}

View File

@@ -16,6 +16,7 @@ export interface NotificationCardsProps {
fetchNextPage: ((params?: { perPage?: number }) => void) | undefined
notifications: GitHubNotification[]
repoIsKnown?: boolean
state: 'loading' | 'loading_first' | 'loading_more' | 'loaded'
swipeable?: boolean
}
@@ -50,22 +51,27 @@ export class NotificationCards extends PureComponent<
}
renderFooter = () => {
const { fetchNextPage } = this.props
const { fetchNextPage, state } = this.props
if (!fetchNextPage) return null
return (
<View style={{ padding: contentPadding }}>
<Button onPress={() => fetchNextPage()} children="Load more" />
<Button
children="Load more"
disabled={state !== 'loaded'}
loading={state === 'loading_more'}
onPress={() => fetchNextPage()}
/>
</View>
)
}
render() {
const { fetchNextPage, notifications } = this.props
const { fetchNextPage, state, notifications } = this.props
if (!(notifications && notifications.length))
return <EmptyCards fetchNextPage={fetchNextPage} />
return <EmptyCards fetchNextPage={fetchNextPage} state={state} />
return (
<ThemeConsumer>
@@ -80,6 +86,7 @@ export class NotificationCards extends PureComponent<
ItemSeparatorComponent={CardItemSeparator}
ListFooterComponent={this.renderFooter}
data={notifications}
extraData={state}
keyExtractor={this.keyExtractor}
removeClippedSubviews
renderItem={this.renderItem}

View File

@@ -1,17 +1,28 @@
import React from 'react'
import { Text, TouchableOpacity, TouchableOpacityProps } from 'react-native'
import {
ActivityIndicator,
Text,
TouchableOpacity,
TouchableOpacityProps,
View,
} from 'react-native'
import * as colors from '../../styles/colors'
import { contentPadding, radius } from '../../styles/variables'
import { ThemeConsumer } from '../context/ThemeContext'
import { Spacer } from './Spacer'
export interface ButtonProps extends TouchableOpacityProps {
disabled?: boolean
loading?: boolean
onPress: TouchableOpacityProps['onPress']
useBrandColor?: boolean
}
export const Button: React.SFC<ButtonProps> = ({
children,
disabled,
loading,
style,
useBrandColor,
...props
@@ -35,7 +46,9 @@ export const Button: React.SFC<ButtonProps> = ({
style,
]}
>
{typeof children === 'string' ? (
{loading ? (
<ActivityIndicator color={theme.foregroundColor} size="small" />
) : typeof children === 'string' ? (
<Text
style={{
fontWeight: '500',

View File

@@ -15,7 +15,7 @@ import { getActivity } from '../libs/github'
export type EventCardsContainerProps = Omit<
EventCardsProps,
'events' | 'fetchNextPage'
'events' | 'fetchNextPage' | 'state'
> & {
column: Column
subscriptions: ColumnSubscription[]
@@ -27,6 +27,7 @@ export interface EventCardsContainerState {
events: GitHubEvent[]
page: number
perPage: number
state: 'loading' | 'loading_first' | 'loading_more' | 'loaded'
}
export class EventCardsContainer extends PureComponent<
@@ -41,6 +42,7 @@ export class EventCardsContainer extends PureComponent<
events: [],
page: 1,
perPage: 20,
state: 'loading_first',
}
componentDidMount() {
@@ -79,6 +81,15 @@ export class EventCardsContainer extends PureComponent<
subtype: activityType,
} = subscriptions[0] as ActivitySubscription
try {
this.setState(state => ({
state:
page > 1
? 'loading_more'
: !state.state || state.state === 'loading_first'
? 'loading_first'
: 'loading',
}))
const params = { ..._params, page, per_page: perPage }
const response = await getActivity(activityType, params, {
subscriptionId,
@@ -90,11 +101,13 @@ export class EventCardsContainer extends PureComponent<
canFetchMore: response.data.length >= perPage,
events,
page,
state: 'loaded',
})
} else {
this.setState({ canFetchMore: false, page })
this.setState({ canFetchMore: false, page, state: 'loaded' })
}
} catch (error) {
this.setState({ state: 'loaded' })
console.error('Failed to load GitHub activity', error)
}
}
@@ -118,13 +131,14 @@ export class EventCardsContainer extends PureComponent<
}
render() {
const { canFetchMore, enhancedEvents } = this.state
const { canFetchMore, enhancedEvents, state } = this.state
return (
<EventCards
{...this.props}
events={enhancedEvents}
fetchNextPage={canFetchMore ? this.fetchNextPage : undefined}
state={state}
/>
)
}

View File

@@ -16,7 +16,7 @@ import { getNotifications } from '../libs/github'
export type NotificationCardsContainerProps = Omit<
NotificationCardsProps,
'fetchNextPage' | 'notifications'
'fetchNextPage' | 'notifications' | 'state'
> & {
column: Column
subscriptions: ColumnSubscription[]
@@ -28,6 +28,7 @@ export interface NotificationCardsContainerState {
notifications: NotificationCardsProps['notifications']
page: number
perPage: number
state: 'loading' | 'loading_first' | 'loading_more' | 'loaded'
}
export class NotificationCardsContainer extends PureComponent<
@@ -42,6 +43,7 @@ export class NotificationCardsContainer extends PureComponent<
notifications: [],
page: 1,
perPage: 20,
state: 'loading_first',
}
componentDidMount() {
@@ -79,6 +81,15 @@ export class NotificationCardsContainer extends PureComponent<
const { params: _params } = subscription
const params = { ..._params, page, per_page: perPage }
this.setState(state => ({
state:
page > 1
? 'loading_more'
: !state.state || state.state === 'loading_first'
? 'loading_first'
: 'loading',
}))
try {
const response = await getNotifications(params, {
subscriptionId: subscription.id,
@@ -93,11 +104,13 @@ export class NotificationCardsContainer extends PureComponent<
canFetchMore: response.data.length >= perPage,
notifications,
page,
state: 'loaded',
})
} else {
this.setState({ canFetchMore: false, page })
this.setState({ canFetchMore: false, page, state: 'loaded' })
}
} catch (error) {
this.setState({ state: 'loaded' })
console.error('Failed to load GitHub notifications', error)
}
}
@@ -121,13 +134,14 @@ export class NotificationCardsContainer extends PureComponent<
}
render() {
const { canFetchMore, enhancedNotifications } = this.state
const { canFetchMore, enhancedNotifications, state } = this.state
return (
<NotificationCards
{...this.props}
notifications={enhancedNotifications}
fetchNextPage={canFetchMore ? this.fetchNextPage : undefined}
state={state}
/>
)
}