Files
notesnook/apps/mobile/src/components/SimpleList/index.js

380 lines
9.4 KiB
JavaScript
Raw Normal View History

2020-09-18 20:47:52 +05:00
import React, {useEffect, useState} from 'react';
2020-09-21 15:40:19 +05:00
import {Dimensions, Platform, RefreshControl, Text, View} from 'react-native';
2020-09-18 20:47:52 +05:00
import {useSafeAreaInsets} from 'react-native-safe-area-context';
2020-09-09 14:55:59 +05:00
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
2020-09-18 20:47:52 +05:00
import {DataProvider, LayoutProvider, RecyclerListView} from 'recyclerlistview';
import {COLORS_NOTE, SIZE, WEIGHT} from '../../common/common';
import {useTracked} from '../../provider';
import {ACTIONS} from '../../provider/actions';
import {eSendEvent} from '../../services/eventManager';
2020-08-16 18:59:07 +05:00
import {
eClearSearch,
eOpenLoginDialog,
2020-09-18 20:47:52 +05:00
eScrollEvent,
2020-08-16 18:59:07 +05:00
} from '../../services/events';
2020-09-21 15:40:19 +05:00
import {db, ToastEvent} from '../../utils/utils';
2020-09-18 20:47:52 +05:00
import {PressableButton} from '../PressableButton';
let {width, height} = Dimensions.get('window');
const header = {
type: 'MAIN_HEADER',
};
2020-05-10 22:19:23 +05:00
2020-03-09 20:06:55 +05:00
const SimpleList = ({
data,
type,
placeholder,
2020-05-10 22:19:23 +05:00
RenderItem,
2020-03-09 20:06:55 +05:00
focused,
2020-04-26 16:36:51 +05:00
customRefresh,
customRefreshing,
2020-03-09 20:06:55 +05:00
}) => {
const [state, dispatch] = useTracked();
2020-09-21 13:13:18 +05:00
const {colors, selectionMode, user} = state;
2020-04-20 09:16:01 +05:00
const searchResults = {...state.searchResults};
2020-04-26 16:15:59 +05:00
const [refreshing, setRefreshing] = useState(false);
2020-09-24 23:02:49 +05:00
const [dataProvider, setDataProvider] = useState(
new DataProvider((r1, r2) => {
return r1 !== r2;
}).cloneWithRows([]),
);
2020-09-14 13:35:30 +05:00
const insets = useSafeAreaInsets();
2020-09-23 14:04:05 +05:00
const listData = data;
2020-09-07 19:19:54 +05:00
const _onScroll = (event) => {
2020-03-09 20:06:55 +05:00
if (!event) return;
let y = event.nativeEvent.contentOffset.y;
eSendEvent(eScrollEvent, y);
};
2020-09-18 20:47:52 +05:00
useEffect(() => {
let mainData =
searchResults.type === type && focused && searchResults.results.length > 0
? searchResults.results
2020-09-23 14:04:05 +05:00
: listData;
2020-09-18 20:47:52 +05:00
let d = [header, ...mainData];
/* for (var i = 0; i < 10000; i++) {
d = [...d,...data];
} */
2020-09-24 23:02:49 +05:00
console.log(d, 'D');
2020-09-18 20:47:52 +05:00
setDataProvider(
new DataProvider((r1, r2) => {
return r1 !== r2;
}).cloneWithRows(d),
);
2020-09-23 14:04:05 +05:00
}, [listData]);
2020-09-18 20:47:52 +05:00
2020-09-23 14:04:05 +05:00
const _ListFooterComponent = listData[0] ? (
2020-03-09 20:06:55 +05:00
<View
style={{
height: 150,
alignItems: 'center',
justifyContent: 'center',
}}>
<Text
style={{
2020-09-07 21:23:38 +05:00
color: colors.nav,
2020-03-09 20:06:55 +05:00
fontSize: SIZE.sm,
fontFamily: WEIGHT.regular,
}}>
- End -
</Text>
</View>
) : null;
2020-09-18 20:47:52 +05:00
const RenderSectionHeader = ({item}) => (
2020-04-20 10:54:58 +05:00
<Text
style={{
fontFamily: WEIGHT.bold,
fontSize: SIZE.xs + 1,
color: colors.accent,
paddingHorizontal: 12,
width: '100%',
alignSelf: 'center',
marginTop: 15,
2020-09-24 23:02:49 +05:00
height: 18,
2020-04-20 10:54:58 +05:00
paddingBottom: 5,
}}>
2020-09-18 20:47:52 +05:00
{item.title}
2020-04-20 10:54:58 +05:00
</Text>
);
2020-04-26 16:15:59 +05:00
const _onRefresh = async () => {
if (Platform.OS === 'ios') {
dispatch({
type: ACTIONS.SYNCING,
syncing: true,
});
} else {
setRefreshing(true);
}
try {
let user = await db.user.get();
dispatch({type: ACTIONS.USER, user: user});
await db.sync();
ToastEvent.show('Sync Complete', 'success');
} catch (e) {
2020-09-14 09:42:46 +05:00
ToastEvent.show(
e.message,
'error',
'global',
5000,
() => {
2020-09-14 13:35:30 +05:00
eSendEvent(eOpenLoginDialog);
2020-09-14 09:42:46 +05:00
},
'Login',
);
2020-09-21 13:13:18 +05:00
} finally {
if (Platform.OS === 'ios') {
dispatch({
type: ACTIONS.SYNCING,
syncing: false,
});
} else {
setRefreshing(false);
}
dispatch({type: ACTIONS.ALL});
2020-04-26 16:15:59 +05:00
}
2020-09-18 20:47:52 +05:00
};
2020-03-09 20:06:55 +05:00
const _ListEmptyComponent = (
<View
style={{
2020-09-18 20:47:52 +05:00
height: '100%',
2020-03-09 20:06:55 +05:00
width: '100%',
alignItems: 'center',
alignSelf: 'center',
justifyContent: 'center',
2020-03-19 11:04:47 +05:00
opacity: 1,
2020-09-18 20:47:52 +05:00
backgroundColor: colors.bg,
2020-03-09 20:06:55 +05:00
}}>
2020-08-16 18:59:07 +05:00
<>{placeholder}</>
2020-03-09 20:06:55 +05:00
</View>
);
2020-09-18 20:47:52 +05:00
const _layoutProvider = new LayoutProvider(
(index) => {
return dataProvider.getDataForIndex(index).type;
},
(type, dim) => {
switch (type) {
case 'note':
dim.width = width;
dim.height = 100;
break;
case 'notebook':
dim.width = width;
dim.height = 110;
break;
case 'topic':
dim.width = width;
dim.height = 80;
break;
case 'tag':
dim.width = width;
dim.height = 80;
break;
case 'header':
dim.width = width;
2020-09-24 23:02:49 +05:00
dim.height = 18;
2020-09-18 20:47:52 +05:00
break;
case 'MAIN_HEADER':
dim.width = width;
2020-09-24 23:02:49 +05:00
dim.height =
(user && user.Id) || !listData[0] || selectionMode ? 0 : 40;
2020-09-18 20:47:52 +05:00
break;
default:
dim.width = width;
dim.height = 0;
2020-04-20 10:54:58 +05:00
}
2020-09-18 20:47:52 +05:00
},
);
const _renderRow = (type, data, index) => {
switch (type) {
case 'note':
return <RenderItem item={data} pinned={data.pinned} index={index} />;
case 'MAIN_HEADER':
2020-09-23 14:04:05 +05:00
return <ListHeaderComponent type={type} data={listData} />;
2020-09-18 20:47:52 +05:00
case 'header':
return <RenderSectionHeader item={data} />;
default:
return null;
}
};
2020-09-23 14:04:05 +05:00
return !listData || listData.length === 0 ? (
2020-09-18 20:47:52 +05:00
_ListEmptyComponent
) : (
<RecyclerListView
layoutProvider={_layoutProvider}
dataProvider={dataProvider}
rowRenderer={_renderRow}
2020-04-20 10:54:58 +05:00
onScroll={_onScroll}
2020-09-18 20:47:52 +05:00
scrollViewProps={{
refreshControl: (
<RefreshControl
tintColor={colors.accent}
colors={[colors.accent]}
progressViewOffset={150}
onRefresh={customRefresh ? customRefresh : _onRefresh}
refreshing={customRefresh ? customRefreshing : refreshing}
/>
),
contentContainerStyle: {
width: '100%',
alignSelf: 'center',
minHeight: '100%',
},
2020-04-20 10:54:58 +05:00
}}
2020-03-09 20:06:55 +05:00
style={{
height: '100%',
2020-05-10 22:19:23 +05:00
backgroundColor: colors.bg,
2020-09-18 20:47:52 +05:00
width: '100%',
paddingTop:
Platform.OS == 'ios'
2020-09-24 09:51:15 +05:00
? listData[0] && !selectionMode
2020-09-18 20:47:52 +05:00
? 115
: 115 - 60
2020-09-24 09:51:15 +05:00
: listData[0] && !selectionMode
2020-09-18 20:47:52 +05:00
? 155 - insets.top
: 155 - insets.top - 60,
2020-03-09 20:06:55 +05:00
}}
/>
);
};
export default SimpleList;
2020-09-21 13:13:18 +05:00
const SearchHeader = () => {
const [state, dispatch] = useTracked();
const {colors} = state;
const searchResults = {...state.searchResults};
return (
<View
style={{
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
paddingHorizontal: 12,
height: 40,
}}>
<Text
style={{
fontFamily: WEIGHT.bold,
color: colors.accent,
fontSize: SIZE.xs,
}}>
Showing Results for {searchResults.keyword}
</Text>
<Text
onPress={() => {
eSendEvent(eClearSearch);
}}
style={{
fontFamily: WEIGHT.regular,
color: colors.errorText,
fontSize: SIZE.xs,
}}>
Clear
</Text>
</View>
);
};
2020-09-24 09:51:15 +05:00
const LoginCard = ({type, data}) => {
2020-09-21 13:13:18 +05:00
const [state, dispatch] = useTracked();
const {colors, selectionMode, user, currentScreen} = state;
return (
<View>
2020-09-24 23:02:49 +05:00
{(user && user.Id) || !data[0] || selectionMode ? null : (
2020-09-21 13:13:18 +05:00
<PressableButton
onPress={() => {
eSendEvent(eOpenLoginDialog);
}}
color={
COLORS_NOTE[currentScreen]
? COLORS_NOTE[currentScreen]
: colors.shade
}
selectedColor={
COLORS_NOTE[currentScreen]
? COLORS_NOTE[currentScreen]
: colors.accent
}
alpha={!colors.night ? -0.02 : 0.1}
opacity={0.12}
customStyle={{
width: '100%',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'flex-start',
paddingHorizontal: 12,
alignSelf: 'center',
height: 40,
borderRadius: 0,
position: 'relative',
}}>
<View
style={{
width: 25,
backgroundColor: COLORS_NOTE[currentScreen]
? COLORS_NOTE[currentScreen]
: colors.accent,
height: 25,
borderRadius: 100,
alignItems: 'center',
justifyContent: 'center',
}}>
<Icon
style={{
textAlign: 'center',
textAlignVertical: 'center',
}}
name="account-outline"
color="white"
size={SIZE.xs}
/>
</View>
<View
style={{
marginLeft: 10,
}}>
<Text
style={{
fontFamily: WEIGHT.regular,
color: colors.icon,
fontSize: SIZE.xxs - 1,
}}>
You are not logged in
</Text>
<Text
style={{
color: COLORS_NOTE[currentScreen]
? COLORS_NOTE[currentScreen]
: colors.accent,
fontSize: SIZE.xxs,
}}>
Login to sync your {type}.
</Text>
</View>
</PressableButton>
)}
</View>
);
};
2020-09-24 09:51:15 +05:00
const ListHeaderComponent = ({type, data}) => {
2020-09-21 13:13:18 +05:00
const [state, dispatch] = useTracked();
const searchResults = {...state.searchResults};
return searchResults.type === type && searchResults.results.length > 0 ? (
<SearchHeader />
) : (
2020-09-23 14:04:05 +05:00
<LoginCard type={type} data={data} />
2020-09-21 13:13:18 +05:00
);
};