fix list top padding on ios

This commit is contained in:
ammarahm-ed
2020-10-13 10:29:16 +05:00
parent b9efa42170
commit df614585ca

View File

@@ -1,7 +1,5 @@
import React, {useCallback, useEffect, useMemo, useState} from 'react'; import React, {useCallback, useEffect, useMemo, useState} from 'react';
import {StyleSheet, useWindowDimensions} from 'react-native'; import {Platform, RefreshControl, StyleSheet, Text, useWindowDimensions, View} from 'react-native';
import {Dimensions, Platform, RefreshControl, Text, View} from 'react-native';
import Orientation from 'react-native-orientation';
import {initialWindowMetrics} from 'react-native-safe-area-context'; import {initialWindowMetrics} from 'react-native-safe-area-context';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons'; import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import {DataProvider, LayoutProvider, RecyclerListView} from 'recyclerlistview'; import {DataProvider, LayoutProvider, RecyclerListView} from 'recyclerlistview';
@@ -9,385 +7,383 @@ import {COLORS_NOTE, SIZE, WEIGHT} from '../../common/common';
import {useTracked} from '../../provider'; import {useTracked} from '../../provider';
import {ACTIONS} from '../../provider/actions'; import {ACTIONS} from '../../provider/actions';
import {eSendEvent} from '../../services/eventManager'; import {eSendEvent} from '../../services/eventManager';
import { import {eClearSearch, eOpenLoginDialog, eScrollEvent,} from '../../services/events';
eClearSearch,
eOpenLoginDialog,
eScrollEvent,
} from '../../services/events';
import {db, ToastEvent} from '../../utils/utils'; import {db, ToastEvent} from '../../utils/utils';
import {PressableButton} from '../PressableButton'; import {PressableButton} from '../PressableButton';
const header = { const header = {
type: 'MAIN_HEADER', type: 'MAIN_HEADER',
}; };
const SimpleList = ({ const SimpleList = ({
data, data,
type, type,
placeholder, placeholder,
RenderItem, RenderItem,
focused, focused,
customRefresh, customRefresh,
customRefreshing, customRefreshing,
refreshCallback, refreshCallback,
}) => { }) => {
const [state, dispatch] = useTracked(); const [state, dispatch] = useTracked();
const {colors, selectionMode, user} = state; const {colors, selectionMode, user} = state;
const searchResults = {...state.searchResults}; const searchResults = {...state.searchResults};
const [refreshing, setRefreshing] = useState(false); const [refreshing, setRefreshing] = useState(false);
const [dataProvider, setDataProvider] = useState( const [dataProvider, setDataProvider] = useState(
new DataProvider((r1, r2) => { new DataProvider((r1, r2) => {
return r1 !== r2; return r1 !== r2;
}).cloneWithRows([]), }).cloneWithRows([]),
);
const {width, height, fontScale,scale} = useWindowDimensions();
const listData = data;
const dataType = type;
const _onScroll = (event) => {
if (!event) return;
let y = event.nativeEvent.contentOffset.y;
eSendEvent(eScrollEvent, y);
};
useEffect(() => {
loadData();
}, [listData]);
const loadData = useCallback(() => {
let mainData =
searchResults.type === type &&
focused() &&
searchResults.results.length > 0
? searchResults.results
: listData;
let d = [header, ...mainData];
/* for (var i = 0; i < 10000; i++) {
d = [...d,...data];
} */
setDataProvider(
new DataProvider((r1, r2) => {
return r1 !== r2;
}).cloneWithRows(d),
); );
}, [listData]); const {width, fontScale} = useWindowDimensions();
const RenderSectionHeader = ({item}) => ( const listData = data;
<Text const dataType = type;
style={[ const _onScroll = (event) => {
{ if (!event) return;
color: colors.accent, let y = event.nativeEvent.contentOffset.y;
}, eSendEvent(eScrollEvent, y);
styles.sectionHeader,
]}>
{item.title}
</Text>
);
const _onRefresh = useCallback(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) {
ToastEvent.show(
e.message,
'error',
'global',
5000,
() => {
eSendEvent(eOpenLoginDialog);
},
'Login',
);
} finally {
if (Platform.OS === 'ios') {
dispatch({
type: ACTIONS.SYNCING,
syncing: false,
});
} else {
setRefreshing(false);
}
if (refreshCallback) {
refreshCallback();
}
dispatch({type: ACTIONS.ALL});
}
}, []);
const _ListEmptyComponent = (
<View
style={[
{
backgroundColor: colors.bg,
},
styles.emptyList,
]}>
<>{placeholder}</>
</View>
);
const _layoutProvider = new LayoutProvider(
(index) => {
return dataProvider.getDataForIndex(index).type;
},
(type, dim) => {
switch (type) {
case 'note':
dim.width = width;
dim.height = 100 * fontScale;
break;
case 'notebook':
dim.width = width;
dim.height = 110 * fontScale;
break;
case 'topic':
dim.width = width;
dim.height = 80 * fontScale;
break;
case 'tag':
dim.width = width;
dim.height = 80 * fontScale;
break;
case 'header':
dim.width = width;
dim.height = 30 * fontScale;
break;
case 'MAIN_HEADER':
dim.width = width;
dim.height =
(user && user.Id) || !listData[0] || selectionMode ? 0 : 40 * fontScale;
break;
default:
dim.width = width;
dim.height = 0;
}
},
);
const _renderRow = (type, data, index) => {
switch (type) {
case 'note':
return <RenderItem item={data} pinned={data.pinned} index={index} />;
case 'MAIN_HEADER':
return <ListHeaderComponent type={dataType} data={listData} />;
case 'header':
return <RenderSectionHeader item={data} />;
default:
return null;
}
};
const listStyle = useMemo(() => {
return {
height: '100%',
backgroundColor: colors.bg,
width: '100%',
paddingTop:
Platform.OS == 'ios'
? listData[0] && !selectionMode
? 115
: 115 - 60
: listData[0] && !selectionMode
? 155 - initialWindowMetrics.insets.top
: 155 - initialWindowMetrics.insets.top - 60,
}; };
}, [selectionMode, listData, colors]);
return !listData || listData.length === 0 || !dataProvider ? ( useEffect(() => {
_ListEmptyComponent loadData();
) : ( }, [listData]);
<RecyclerListView
layoutProvider={_layoutProvider} const loadData = useCallback(() => {
dataProvider={dataProvider} let mainData =
rowRenderer={_renderRow} searchResults.type === type &&
onScroll={_onScroll} focused() &&
scrollViewProps={{ searchResults.results.length > 0
refreshControl: ( ? searchResults.results
<RefreshControl : listData;
tintColor={colors.accent}
colors={[colors.accent]} let d = [header, ...mainData];
progressViewOffset={150} /* for (var i = 0; i < 10000; i++) {
onRefresh={customRefresh ? customRefresh : _onRefresh} d = [...d,...data];
refreshing={customRefresh ? customRefreshing : refreshing} } */
/> setDataProvider(
), new DataProvider((r1, r2) => {
contentContainerStyle: { return r1 !== r2;
width: '100%', }).cloneWithRows(d),
alignSelf: 'center', );
minHeight: '100%', }, [listData]);
const RenderSectionHeader = ({item}) => (
<Text
style={[
{
color: colors.accent,
},
styles.sectionHeader,
]}>
{item.title}
</Text>
);
const _onRefresh = useCallback(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) {
ToastEvent.show(
e.message,
'error',
'global',
5000,
() => {
eSendEvent(eOpenLoginDialog);
},
'Login',
);
} finally {
if (Platform.OS === 'ios') {
dispatch({
type: ACTIONS.SYNCING,
syncing: false,
});
} else {
setRefreshing(false);
}
if (refreshCallback) {
refreshCallback();
}
dispatch({type: ACTIONS.ALL});
}
}, []);
const _ListEmptyComponent = (
<View
style={[
{
backgroundColor: colors.bg,
},
styles.emptyList,
]}>
<>{placeholder}</>
</View>
);
const _layoutProvider = new LayoutProvider(
(index) => {
return dataProvider.getDataForIndex(index).type;
}, },
}} (type, dim) => {
style={listStyle} switch (type) {
/> case 'note':
); dim.width = width;
dim.height = 100 * fontScale;
break;
case 'notebook':
dim.width = width;
dim.height = 110 * fontScale;
break;
case 'topic':
dim.width = width;
dim.height = 80 * fontScale;
break;
case 'tag':
dim.width = width;
dim.height = 80 * fontScale;
break;
case 'header':
dim.width = width;
dim.height = 30 * fontScale;
break;
case 'MAIN_HEADER':
dim.width = width;
dim.height =
(user && user.Id) || !listData[0] || selectionMode
? 0
: 40 * fontScale;
break;
default:
dim.width = width;
dim.height = 0;
}
},
);
const _renderRow = (type, data, index) => {
switch (type) {
case 'note':
return <RenderItem item={data} pinned={data.pinned} index={index}/>;
case 'MAIN_HEADER':
return <ListHeaderComponent type={dataType} data={listData}/>;
case 'header':
return <RenderSectionHeader item={data}/>;
default:
s
return null;
}
};
const listStyle = useMemo(() => {
return {
height: '100%',
backgroundColor: colors.bg,
width: '100%',
paddingTop:
Platform.OS === 'ios'
? listData[0] && !selectionMode
? 130
: 130 - 60
: listData[0] && !selectionMode
? 155 - initialWindowMetrics.insets.top
: 155 - initialWindowMetrics.insets.top - 60,
};
}, [selectionMode, listData, colors]);
return !listData || listData.length === 0 || !dataProvider ? (
_ListEmptyComponent
) : (
<RecyclerListView
layoutProvider={_layoutProvider}
dataProvider={dataProvider}
rowRenderer={_renderRow}
onScroll={_onScroll}
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%',
},
}}
style={listStyle}
/>
);
}; };
export default SimpleList; export default SimpleList;
const SearchHeader = () => { const SearchHeader = () => {
const [state, dispatch] = useTracked(); const [state,] = useTracked();
const {colors} = state; const {colors} = state;
const searchResults = {...state.searchResults}; const searchResults = {...state.searchResults};
return ( return (
<View style={styles.searchHeader}> <View style={styles.searchHeader}>
<Text <Text
style={{ style={{
fontFamily: WEIGHT.bold, fontFamily: WEIGHT.bold,
color: colors.accent, color: colors.accent,
fontSize: SIZE.xs, fontSize: SIZE.xs,
}}> }}>
Showing Results for {searchResults.keyword} Showing Results for {searchResults.keyword}
</Text> </Text>
<Text <Text
onPress={() => { onPress={() => {
eSendEvent(eClearSearch); eSendEvent(eClearSearch);
}} }}
style={{ style={{
fontFamily: WEIGHT.regular, fontFamily: WEIGHT.regular,
color: colors.errorText, color: colors.errorText,
fontSize: SIZE.xs, fontSize: SIZE.xs,
}}> }}>
Clear Clear
</Text> </Text>
</View> </View>
); );
}; };
const LoginCard = ({type, data}) => { const LoginCard = ({type, data}) => {
const [state, dispatch] = useTracked(); const [state,] = useTracked();
const {colors, selectionMode, user, currentScreen} = state; const {colors, selectionMode, user, currentScreen} = state;
return ( return (
<View> <View>
{(user && user.Id) || !data[0] || selectionMode ? null : ( {(user && user.Id) || !data[0] || selectionMode ? null : (
<PressableButton <PressableButton
onPress={() => { onPress={() => {
eSendEvent(eOpenLoginDialog); eSendEvent(eOpenLoginDialog);
}} }}
color={ color={
COLORS_NOTE[currentScreen] COLORS_NOTE[currentScreen]
? COLORS_NOTE[currentScreen] ? COLORS_NOTE[currentScreen]
: colors.shade : colors.shade
} }
selectedColor={ selectedColor={
COLORS_NOTE[currentScreen] COLORS_NOTE[currentScreen]
? COLORS_NOTE[currentScreen] ? COLORS_NOTE[currentScreen]
: colors.accent : colors.accent
} }
alpha={!colors.night ? -0.02 : 0.1} alpha={!colors.night ? -0.02 : 0.1}
opacity={0.12} opacity={0.12}
customStyle={styles.loginCard}> customStyle={styles.loginCard}>
<View <View
style={{ style={{
width: 25, width: 25,
backgroundColor: COLORS_NOTE[currentScreen] backgroundColor: COLORS_NOTE[currentScreen]
? COLORS_NOTE[currentScreen] ? COLORS_NOTE[currentScreen]
: colors.accent, : colors.accent,
height: 25, height: 25,
borderRadius: 100, borderRadius: 100,
alignItems: 'center', alignItems: 'center',
justifyContent: 'center', justifyContent: 'center',
}}> }}>
<Icon <Icon
style={styles.loginIcon} style={styles.loginIcon}
name="account-outline" name="account-outline"
color="white" color="white"
size={SIZE.xs} size={SIZE.xs}
/> />
</View> </View>
<View <View
style={{ style={{
marginLeft: 10, marginLeft: 10,
}}> }}>
<Text <Text
style={{ style={{
fontFamily: WEIGHT.regular, fontFamily: WEIGHT.regular,
color: colors.icon, color: colors.icon,
fontSize: SIZE.xxs - 1, fontSize: SIZE.xxs - 1,
}}> }}>
You are not logged in You are not logged in
</Text> </Text>
<Text <Text
style={{ style={{
color: COLORS_NOTE[currentScreen] color: COLORS_NOTE[currentScreen]
? COLORS_NOTE[currentScreen] ? COLORS_NOTE[currentScreen]
: colors.accent, : colors.accent,
fontSize: SIZE.xxs, fontSize: SIZE.xxs,
}}> }}>
Login to sync your {type}. Login to sync your {type}.
</Text> </Text>
</View> </View>
</PressableButton> </PressableButton>
)} )}
</View> </View>
); );
}; };
const ListHeaderComponent = ({type, data}) => { const ListHeaderComponent = ({type, data}) => {
const [state, dispatch] = useTracked(); const [state, ] = useTracked();
const searchResults = {...state.searchResults}; const searchResults = {...state.searchResults};
return searchResults.type === type && searchResults.results.length > 0 ? ( return searchResults.type === type && searchResults.results.length > 0 ? (
<SearchHeader /> <SearchHeader/>
) : ( ) : (
<LoginCard type={type} data={data} /> <LoginCard type={type} data={data}/>
); );
}; };
const styles = StyleSheet.create({ const styles = StyleSheet.create({
loginCard: { loginCard: {
width: '100%', width: '100%',
flexDirection: 'row', flexDirection: 'row',
alignItems: 'center', alignItems: 'center',
justifyContent: 'flex-start', justifyContent: 'flex-start',
paddingHorizontal: 12, paddingHorizontal: 12,
alignSelf: 'center', alignSelf: 'center',
height: 40, height: 40,
borderRadius: 0, borderRadius: 0,
position: 'relative', position: 'relative',
}, },
loginIcon: { loginIcon: {
textAlign: 'center', textAlign: 'center',
textAlignVertical: 'center', textAlignVertical: 'center',
}, },
searchHeader: { searchHeader: {
flexDirection: 'row', flexDirection: 'row',
alignItems: 'center', alignItems: 'center',
justifyContent: 'space-between', justifyContent: 'space-between',
paddingHorizontal: 12, paddingHorizontal: 12,
height: 40, height: 40,
}, },
sectionHeader: { sectionHeader: {
fontFamily: WEIGHT.bold, fontFamily: WEIGHT.bold,
fontSize: SIZE.xs + 1, fontSize: SIZE.xs + 1,
paddingHorizontal: 12, paddingHorizontal: 12,
width: '100%', width: '100%',
alignSelf: 'center', alignSelf: 'center',
marginTop: 10, marginTop: 10,
height: 25, height: 25,
textAlignVertical: 'center', textAlignVertical: 'center',
}, },
emptyList: { emptyList: {
height: '100%', height: '100%',
width: '100%', width: '100%',
alignItems: 'center', alignItems: 'center',
alignSelf: 'center', alignSelf: 'center',
justifyContent: 'center', justifyContent: 'center',
opacity: 1, opacity: 1,
}, },
}); });