Skip to content

Commit 12de92c

Browse files
committed
Up: scrollHelper design
1 parent 6249f6b commit 12de92c

5 files changed

Lines changed: 69 additions & 32 deletions

File tree

app/components/button/IconButton.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ import Icon from 'react-native-vector-icons/FontAwesome';
55
import { ThemeContext } from '~/contexts/theme';
66
import mainStyles from '~/styles/main';
77

8-
const IconButton = ({ icon, size = 23, color = undefined, style = {}, onPress, onLongPress = null, delayLongPress = 200 }) => {
8+
const IconButton = ({ icon, size = 23, color = undefined, style = {}, styleIcon = {}, pressEffect = true, onPress, onLongPress = null, delayLongPress = 200 }) => {
99
const theme = React.useContext(ThemeContext)
1010
return (
1111
<Pressable
12-
style={({ pressed }) => ([mainStyles.opacity({ pressed }), { justifyContent: 'center' }, StyleSheet.flatten(style)])}
12+
style={({ pressed }) => ([mainStyles.opacity({ pressed, enable: pressEffect }), { justifyContent: 'center' }, StyleSheet.flatten(style)])}
1313
onLongPress={onLongPress}
1414
delayLongPress={delayLongPress}
1515
onPress={onPress}
@@ -18,7 +18,7 @@ const IconButton = ({ icon, size = 23, color = undefined, style = {}, onPress, o
1818
if (onLongPress) onLongPress()
1919
}}
2020
>
21-
<Icon name={icon} size={size} color={color ? color : theme.primaryTouch} />
21+
<Icon name={icon} size={size} color={color ? color : theme.primaryTouch} style={styleIcon} />
2222
</Pressable>
2323
)
2424
}

app/components/lists/CustomFlat.js

Lines changed: 59 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,71 @@
11
import React from 'react';
2-
import { View, FlatList, StyleSheet } from 'react-native';
2+
import { View, FlatList, StyleSheet, useWindowDimensions } from 'react-native';
33

4-
import { SettingsContext } from '~/contexts/settings';
54
import { ThemeContext } from '~/contexts/theme';
5+
import { SettingsContext } from '~/contexts/settings';
66
import IconButton from '~/components/button/IconButton';
77
import size from '~/styles/size';
88

9-
const CustomFlat = ({ data, renderItem, style = { width: '100%' }, contentContainerStyle = { paddingHorizontal: 20, columnGap: 10 } }) => {
9+
const CustomFlat = ({ data, renderItem, style = { width: '100%' }, contentContainerStyle = { paddingHorizontal: 20, columnGap: 10 }, widthItem = 0 }) => {
1010
const theme = React.useContext(ThemeContext)
1111
const settings = React.useContext(SettingsContext)
1212
const indexScroll = React.useRef(0)
1313
const refScroll = React.useRef(null)
14+
const [isScrollHelper, setIsScrollHelper] = React.useState(false)
15+
const { width } = useWindowDimensions()
16+
const visibleItems = React.useMemo(() => {
17+
if (widthItem > 0) return width / widthItem
18+
else return 3
19+
}, [width, widthItem])
20+
const [isLeftVisible, setIsLeftVisible] = React.useState(false);
21+
const [isRightVisible, setIsRightVisible] = React.useState(true);
1422

1523
const goRight = () => {
16-
if (indexScroll.current + 3 >= data.length) indexScroll.current = data.length - 1
17-
else indexScroll.current = indexScroll.current + 3
24+
if (Math.floor(indexScroll.current) + Math.floor(visibleItems) >= data.length) indexScroll.current = data.length - 1
25+
else indexScroll.current = Math.floor(indexScroll.current) + Math.floor(visibleItems)
26+
setVisibility()
1827
refScroll.current.scrollToIndex({ index: indexScroll.current, animated: true, viewOffset: 20 })
1928
}
2029

2130
const goLeft = () => {
22-
if (indexScroll.current < 3) indexScroll.current = 0
23-
else indexScroll.current = indexScroll.current - 3
31+
if (indexScroll.current < Math.floor(visibleItems)) indexScroll.current = 0
32+
else indexScroll.current = indexScroll.current - Math.floor(visibleItems)
33+
setVisibility()
2434
refScroll.current.scrollToIndex({ index: indexScroll.current, animated: true, viewOffset: 20 })
2535
}
2636

37+
const setVisibility = () => {
38+
if (indexScroll.current === 0) setIsLeftVisible(false)
39+
else setIsLeftVisible(true)
40+
if (indexScroll.current + visibleItems >= data.length) setIsRightVisible(false)
41+
else setIsRightVisible(true)
42+
}
43+
2744
// https://github.com/facebook/react-native/issues/39421
2845
if (!data || data.length === 0) return null;
2946

30-
// View is necessary to show the scroll helper
3147
return (
32-
<View>
48+
<View
49+
onPointerEnter={() => setIsScrollHelper(settings.scrollHelper && true)}
50+
onPointerLeave={() => setIsScrollHelper(false)}
51+
>
52+
{
53+
(isScrollHelper && isLeftVisible) ? (
54+
<View style={[styles.scrollContainer, { left: 0 }]}>
55+
<IconButton icon="angle-left" size={size.icon.tiny} onPress={goLeft} color={theme.primaryText} pressEffect={false}
56+
styleIcon={{ lineHeight: size.icon.tiny }}
57+
style={styles.scrollHelper(theme)} />
58+
</View>
59+
) : null
60+
}
3361
{
34-
settings?.scrollHelper && (
35-
<View style={styles.scrollContainer}>
36-
<IconButton icon="chevron-left" size={size.icon.tiny} onPress={goLeft} color={theme.secondaryText} style={styles.scrollHelper(theme)} />
37-
<IconButton icon="chevron-right" size={size.icon.tiny} onPress={goRight} color={theme.secondaryText} style={styles.scrollHelper(theme)} />
62+
(isScrollHelper && isRightVisible) ? (
63+
<View style={[styles.scrollContainer, { right: 0 }]}>
64+
<IconButton icon="angle-right" size={size.icon.tiny} onPress={goRight} color={theme.primaryText}
65+
pressEffect={false}
66+
style={styles.scrollHelper(theme)} />
3867
</View>
39-
)
68+
) : null
4069
}
4170
<FlatList
4271
ref={refScroll}
@@ -45,6 +74,14 @@ const CustomFlat = ({ data, renderItem, style = { width: '100%' }, contentContai
4574
renderItem={renderItem}
4675
horizontal={true}
4776
style={style}
77+
onScroll={({ nativeEvent }) => {
78+
if (widthItem > 0) {
79+
const index = nativeEvent.contentOffset.x / widthItem
80+
if (index < 0) indexScroll.current = 0
81+
else indexScroll.current = index
82+
setVisibility()
83+
}
84+
}}
4885
onScrollToIndexFailed={() => { }}
4986
contentContainerStyle={contentContainerStyle}
5087
showsHorizontalScrollIndicator={false}
@@ -57,19 +94,18 @@ const styles = StyleSheet.create({
5794
scrollContainer: {
5895
position: 'absolute',
5996
zIndex: 1,
60-
flexDirection: 'row',
61-
right: 10,
62-
top: -40,
63-
columnGap: 1,
97+
top: 0,
98+
bottom: 0,
99+
justifyContent: 'center',
64100
},
65101
scrollHelper: theme => ({
66-
backgroundColor: theme.secondaryBack,
67-
height: 30,
68-
width: 30,
69-
borderTopLeftRadius: 5,
70-
borderBottomLeftRadius: 5,
102+
width: size.icon.tiny + 20,
103+
height: size.icon.tiny + 20,
71104
justifyContent: 'center',
72105
alignItems: 'center',
106+
backgroundColor: theme.secondaryBack,
107+
borderRadius: size.radius.circle,
108+
marginHorizontal: 10,
73109
}),
74110
})
75111

app/components/lists/HorizontalAlbums.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@ const HorizontalAlbums = ({ albums, year = false, onPress = () => { } }) => {
4444
<>
4545
<CustomFlat
4646
data={albums}
47-
renderItem={renderItem} />
47+
renderItem={renderItem}
48+
widthItem={size.image.large + 10}
49+
/>
4850
<OptionsAlbum
4951
albums={albums}
5052
indexOptions={indexOptions}

app/components/player/FullScreenHorizontalPlayer.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import React from 'react'
2-
import { Modal, View, Text, Image, FlatList, Pressable, StyleSheet } from 'react-native'
3-
import Icon from 'react-native-vector-icons/FontAwesome'
2+
import { Modal, View, Text, Image, FlatList, Pressable, StyleSheet, useWindowDimensions } from 'react-native'
43
import { useSafeAreaInsets } from 'react-native-safe-area-context'
5-
import { useWindowDimensions } from 'react-native'
4+
import Icon from 'react-native-vector-icons/FontAwesome'
65

76
import { ConfigContext } from '~/contexts/config'
87
import { SongContext, SongDispatchContext } from '~/contexts/song'

app/styles/main.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ export default StyleSheet.create({
5454
borderRadius: 10,
5555
marginEnd: 10
5656
},
57-
opacity: ({ pressed }) => ({
58-
opacity: pressed ? 0.5 : 1,
57+
opacity: ({ pressed, enable = true }) => ({
58+
opacity: (pressed && enable) ? 0.5 : 1,
5959
}),
6060
smallText: color => ({
6161
color: color,

0 commit comments

Comments
 (0)