mirror of
https://github.com/zhigang1992/devhub.git
synced 2026-06-17 02:51:16 +08:00
Show loading indicator
This commit is contained in:
@@ -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>
|
||||
)}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user