simplify web section list

This commit is contained in:
Arnaud Vergnet 2021-05-11 08:47:54 +02:00
parent 3cb6ddd7f9
commit 35a4b377f8
8 changed files with 60 additions and 100 deletions

View file

@ -26,8 +26,8 @@ import * as Animatable from 'react-native-animatable';
import { REQUEST_CODES, REQUEST_STATUS } from '../../utils/Requests';
type Props = {
status?: Exclude<REQUEST_STATUS, REQUEST_STATUS.SUCCESS>;
code?: Exclude<REQUEST_CODES, REQUEST_CODES.SUCCESS>;
status?: REQUEST_STATUS;
code?: REQUEST_CODES;
icon?: string;
message?: string;
loading?: boolean;

View file

@ -4,7 +4,7 @@ import { useRequestLogic } from '../../utils/customHooks';
import { useFocusEffect } from '@react-navigation/native';
import BasicLoadingScreen from './BasicLoadingScreen';
import i18n from 'i18n-js';
import { REQUEST_STATUS } from '../../utils/Requests';
import { REQUEST_CODES, REQUEST_STATUS } from '../../utils/Requests';
export type RequestScreenProps<T> = {
request: () => Promise<T>;
@ -13,7 +13,7 @@ export type RequestScreenProps<T> = {
loading: boolean,
refreshData: (newRequest?: () => Promise<T>) => void,
status: REQUEST_STATUS,
code: number | undefined
code?: REQUEST_CODES
) => React.ReactElement;
cache?: T;
onCacheUpdate?: (newCache: T) => void;

View file

@ -21,22 +21,19 @@ import React, { useState } from 'react';
import i18n from 'i18n-js';
import { Snackbar } from 'react-native-paper';
import {
NativeScrollEvent,
NativeSyntheticEvent,
RefreshControl,
SectionListData,
SectionListRenderItemInfo,
SectionListProps,
StyleSheet,
View,
} from 'react-native';
import * as Animatable from 'react-native-animatable';
import ErrorView from './ErrorView';
import BasicLoadingScreen from './BasicLoadingScreen';
import { TAB_BAR_HEIGHT } from '../Tabbar/CustomTabBar';
import { ERROR_TYPE } from '../../utils/WebData';
import CollapsibleSectionList from '../Collapsible/CollapsibleSectionList';
import GENERAL_STYLES from '../../constants/Styles';
import RequestScreen from './RequestScreen';
import RequestScreen, { RequestScreenProps } from './RequestScreen';
import { CollapsibleComponentPropsType } from '../Collapsible/CollapsibleComponent';
import { REQUEST_CODES, REQUEST_STATUS } from '../../utils/Requests';
export type SectionListDataType<ItemT> = Array<{
title: string;
@ -45,20 +42,27 @@ export type SectionListDataType<ItemT> = Array<{
keyExtractor?: (data: ItemT) => string;
}>;
type Props<ItemT, RawData> = {
request: () => Promise<RawData>;
refreshOnFocus: boolean;
renderItem: (data: SectionListRenderItemInfo<ItemT>) => React.ReactNode;
type Props<ItemT, RawData> = Omit<
CollapsibleComponentPropsType,
'children' | 'paddedProps'
> &
Omit<
RequestScreenProps<RawData>,
| 'render'
| 'showLoading'
| 'showError'
| 'refresh'
| 'onFinish'
| 'onMajorError'
> &
Omit<
SectionListProps<ItemT>,
'sections' | 'getItemLayout' | 'ListHeaderComponent' | 'ListEmptyComponent'
> & {
createDataset: (
data: RawData | undefined,
isLoading: boolean
) => SectionListDataType<ItemT>;
onScroll?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
showError?: boolean;
itemHeight?: number | null;
autoRefreshTime?: number;
updateData?: number | string;
renderListHeaderComponent?: (
data?: RawData
) => React.ComponentType<any> | React.ReactElement | null;
@ -66,9 +70,7 @@ type Props<ItemT, RawData> = {
data: { section: SectionListData<ItemT> },
isLoading: boolean
) => React.ReactElement | null;
stickyHeader?: boolean;
cache?: RawData;
onCacheUpdate?: (newCache: RawData) => void;
itemHeight?: number | null;
};
const styles = StyleSheet.create({
@ -100,48 +102,12 @@ function WebSectionList<ItemT, RawData>(props: Props<ItemT, RawData>) {
};
};
const getRenderSectionHeader = (
data: { section: SectionListData<ItemT> },
loading: boolean
) => {
const { renderSectionHeader } = props;
if (renderSectionHeader) {
return (
<Animatable.View
animation={'fadeInUp'}
duration={500}
useNativeDriver={true}
>
{renderSectionHeader(data, loading)}
</Animatable.View>
);
}
return null;
};
const getRenderItem = (data: SectionListRenderItemInfo<ItemT>) => {
const { renderItem } = props;
return (
<Animatable.View
animation={'fadeInUp'}
duration={500}
useNativeDriver={true}
>
{renderItem(data)}
</Animatable.View>
);
};
const onScroll = (event: NativeSyntheticEvent<NativeScrollEvent>) => {
if (props.onScroll) {
props.onScroll(event);
}
};
const render = (
data: RawData | undefined,
loading: boolean,
refreshData: (newRequest?: () => Promise<RawData>) => void
refreshData: (newRequest?: () => Promise<RawData>) => void,
status: REQUEST_STATUS,
code?: REQUEST_CODES
) => {
const { itemHeight } = props;
const dataset = props.createDataset(data, loading);
@ -150,8 +116,8 @@ function WebSectionList<ItemT, RawData>(props: Props<ItemT, RawData>) {
}
return (
<CollapsibleSectionList
{...props}
sections={dataset}
extraData={props.updateData}
paddedProps={(paddingTop) => ({
refreshControl: (
<RefreshControl
@ -161,9 +127,7 @@ function WebSectionList<ItemT, RawData>(props: Props<ItemT, RawData>) {
/>
),
})}
renderSectionHeader={(info) => getRenderSectionHeader(info, loading)}
renderItem={getRenderItem}
stickySectionHeadersEnabled={props.stickyHeader}
renderItem={props.renderItem}
style={styles.container}
ListHeaderComponent={
props.renderListHeaderComponent != null
@ -171,11 +135,10 @@ function WebSectionList<ItemT, RawData>(props: Props<ItemT, RawData>) {
: null
}
ListEmptyComponent={
loading ? (
<BasicLoadingScreen />
) : (
loading ? undefined : (
<ErrorView
status={ERROR_TYPE.CONNECTION_ERROR}
status={status}
code={code}
button={{
icon: 'refresh',
text: i18n.t('general.retry'),
@ -187,8 +150,6 @@ function WebSectionList<ItemT, RawData>(props: Props<ItemT, RawData>) {
getItemLayout={
itemHeight ? (d, i) => getItemLayout(itemHeight, d, i) : undefined
}
onScroll={onScroll}
hasTab={true}
/>
);
};

View file

@ -26,7 +26,7 @@ import {
StyleSheet,
} from 'react-native';
import i18n from 'i18n-js';
import { ActivityIndicator, Headline, withTheme } from 'react-native-paper';
import { Headline, withTheme } from 'react-native-paper';
import { CommonActions } from '@react-navigation/native';
import { StackNavigationProp } from '@react-navigation/stack';
import * as Animatable from 'react-native-animatable';
@ -315,11 +315,11 @@ class HomeScreen extends React.Component<PropsType, StateType> {
*/
getRenderItem = ({ item }: { item: FeedItemType }) => this.getFeedItem(item);
getRenderSectionHeader = (
data: { section: SectionListData<FeedItemType> },
isLoading: boolean
) => {
getRenderSectionHeader = (data: {
section: SectionListData<FeedItemType>;
}) => {
const { props } = this;
const icon = data.section.icon;
if (data.section.data.length > 0) {
return (
<Headline style={styles.sectionHeader}>{data.section.title}</Headline>
@ -335,16 +335,14 @@ class HomeScreen extends React.Component<PropsType, StateType> {
>
{data.section.title}
</Headline>
{isLoading ? (
<ActivityIndicator style={styles.activityIndicator} />
) : (
{icon ? (
<MaterialCommunityIcons
name="access-point-network-off"
name={icon}
size={100}
color={props.theme.colors.textDisabled}
style={GENERAL_STYLES.center}
/>
)}
) : null}
</View>
);
};
@ -406,6 +404,7 @@ class HomeScreen extends React.Component<PropsType, StateType> {
): Array<{
title: string;
data: [] | Array<FeedItemType>;
icon?: string;
id: string;
}> => {
if (fetchedData) {
@ -433,6 +432,7 @@ class HomeScreen extends React.Component<PropsType, StateType> {
? i18n.t('screens.home.feedLoading')
: i18n.t('screens.home.feedError'),
data: [],
icon: isLoading ? undefined : 'access-point-network-off',
id: SECTIONS_ID[1],
},
];
@ -473,7 +473,6 @@ class HomeScreen extends React.Component<PropsType, StateType> {
renderItem={this.getRenderItem}
itemHeight={FEED_ITEM_HEIGHT}
onScroll={this.onScroll}
showError={false}
renderSectionHeader={this.getRenderSectionHeader}
renderListHeaderComponent={this.getListHeader}
/>

View file

@ -259,7 +259,7 @@ function GroupSelectionScreen() {
createDataset={createDataset}
refreshOnFocus={true}
renderItem={getRenderItem}
updateData={currentSearchString + favoriteGroups.length}
extraData={currentSearchString + favoriteGroups.length}
cache={groups}
onCacheUpdate={setGroups}
/>

View file

@ -512,7 +512,7 @@ class ProxiwashScreen extends React.Component<PropsType, StateType> {
renderSectionHeader={this.getRenderSectionHeader}
autoRefreshTime={REFRESH_TIME}
refreshOnFocus={true}
updateData={state.machinesWatched.length}
extraData={state.machinesWatched.length}
/>
</View>
<MascotPopup

View file

@ -367,7 +367,7 @@ function ProximoListScreen(props: Props) {
createDataset={createDataset}
refreshOnFocus={true}
renderItem={getRenderItem}
updateData={currentSearchString + currentSortMode}
extraData={currentSearchString + currentSortMode}
itemHeight={LIST_ITEM_HEIGHT}
cache={articles}
onCacheUpdate={setArticles}

View file

@ -201,7 +201,7 @@ class SelfMenuScreen extends React.Component<PropsType> {
refreshOnFocus={true}
renderItem={this.getRenderItem}
renderSectionHeader={this.getRenderSectionHeader}
stickyHeader={true}
stickySectionHeadersEnabled={true}
/>
);
}