|
@@ -3,6 +3,7 @@ import {withTheme} from 'react-native-paper';
|
3
|
3
|
import TabIcon from "./TabIcon";
|
4
|
4
|
import TabHomeIcon from "./TabHomeIcon";
|
5
|
5
|
import {Animated} from 'react-native';
|
|
6
|
+import {Collapsible} from "react-navigation-collapsible";
|
6
|
7
|
|
7
|
8
|
type Props = {
|
8
|
9
|
state: Object,
|
|
@@ -24,41 +25,69 @@ const TAB_ICONS = {
|
24
|
25
|
planex: 'clock',
|
25
|
26
|
};
|
26
|
27
|
|
27
|
|
-/**
|
28
|
|
- * Abstraction layer for Agenda component, using custom configuration
|
29
|
|
- */
|
30
|
28
|
class CustomTabBar extends React.Component<Props, State> {
|
31
|
29
|
|
32
|
30
|
static TAB_BAR_HEIGHT = 48;
|
33
|
31
|
|
34
|
32
|
state = {
|
35
|
33
|
translateY: new Animated.Value(0),
|
36
|
|
- barSynced: false,// Is the bar synced with the header for animations?
|
37
|
34
|
}
|
38
|
35
|
|
|
36
|
+ syncTabBar = (route, index) => {
|
|
37
|
+ const state = this.props.state;
|
|
38
|
+ const isFocused = state.index === index;
|
|
39
|
+ if (isFocused) {
|
|
40
|
+ const stackState = route.state;
|
|
41
|
+ const stackRoute = stackState ? stackState.routes[stackState.index] : undefined;
|
|
42
|
+ const params: { collapsible: Collapsible } = stackRoute ? stackRoute.params : undefined;
|
|
43
|
+ const collapsible = params ? params.collapsible : undefined;
|
|
44
|
+ if (collapsible) {
|
|
45
|
+ this.setState({
|
|
46
|
+ translateY: Animated.multiply(-1.5, collapsible.translateY), // Hide tab bar faster than header bar
|
|
47
|
+ });
|
|
48
|
+ }
|
|
49
|
+ }
|
|
50
|
+ };
|
|
51
|
+
|
|
52
|
+ /**
|
|
53
|
+ * Navigates to the given route if it is different from the current one
|
|
54
|
+ *
|
|
55
|
+ * @param route Destination route
|
|
56
|
+ * @param currentIndex The current route index
|
|
57
|
+ * @param destIndex The destination route index
|
|
58
|
+ */
|
39
|
59
|
onItemPress(route: Object, currentIndex: number, destIndex: number) {
|
40
|
60
|
const event = this.props.navigation.emit({
|
41
|
61
|
type: 'tabPress',
|
42
|
62
|
target: route.key,
|
43
|
63
|
canPreventDefault: true,
|
44
|
64
|
});
|
45
|
|
- if (currentIndex !== destIndex && !event.defaultPrevented) {
|
46
|
|
- this.state.translateY = new Animated.Value(0);
|
|
65
|
+ if (currentIndex !== destIndex && !event.defaultPrevented)
|
47
|
66
|
this.props.navigation.navigate(route.name);
|
48
|
|
- }
|
49
|
67
|
}
|
50
|
68
|
|
|
69
|
+ /**
|
|
70
|
+ * Navigates to tetris screen on home button long press
|
|
71
|
+ *
|
|
72
|
+ * @param route
|
|
73
|
+ */
|
51
|
74
|
onItemLongPress(route: Object) {
|
52
|
75
|
const event = this.props.navigation.emit({
|
53
|
76
|
type: 'tabLongPress',
|
54
|
77
|
target: route.key,
|
55
|
78
|
canPreventDefault: true,
|
56
|
79
|
});
|
57
|
|
- if (route.name === "home" && !event.defaultPrevented) {
|
|
80
|
+ if (route.name === "home" && !event.defaultPrevented)
|
58
|
81
|
this.props.navigation.navigate('tetris');
|
59
|
|
- }
|
60
|
82
|
}
|
61
|
83
|
|
|
84
|
+ /**
|
|
85
|
+ * Gets an icon for the given route if it is not the home one as it uses a custom button
|
|
86
|
+ *
|
|
87
|
+ * @param route
|
|
88
|
+ * @param focused
|
|
89
|
+ * @returns {null}
|
|
90
|
+ */
|
62
|
91
|
tabBarIcon = (route, focused) => {
|
63
|
92
|
let icon = TAB_ICONS[route.name];
|
64
|
93
|
icon = focused ? icon : icon + ('-outline');
|
|
@@ -68,39 +97,34 @@ class CustomTabBar extends React.Component<Props, State> {
|
68
|
97
|
return null;
|
69
|
98
|
};
|
70
|
99
|
|
71
|
|
-
|
|
100
|
+ /**
|
|
101
|
+ * Finds the active route and syncs the tab bar animation with the header bar
|
|
102
|
+ */
|
72
|
103
|
onRouteChange = () => {
|
73
|
|
- this.setState({barSynced: false});
|
|
104
|
+ this.props.state.routes.map(this.syncTabBar)
|
74
|
105
|
}
|
75
|
106
|
|
|
107
|
+ /**
|
|
108
|
+ * Gets a tab icon render.
|
|
109
|
+ * If the given route is focused, it syncs the tab bar and header bar animations together
|
|
110
|
+ *
|
|
111
|
+ * @param route The route for the icon
|
|
112
|
+ * @param index The index of the current route
|
|
113
|
+ * @returns {*}
|
|
114
|
+ */
|
76
|
115
|
renderIcon = (route, index) => {
|
77
|
116
|
const state = this.props.state;
|
78
|
117
|
const {options} = this.props.descriptors[route.key];
|
79
|
118
|
const label =
|
80
|
|
- options.tabBarLabel !== undefined
|
|
119
|
+ options.tabBarLabel != null
|
81
|
120
|
? options.tabBarLabel
|
82
|
|
- : options.title !== undefined
|
|
121
|
+ : options.title != null
|
83
|
122
|
? options.title
|
84
|
123
|
: route.name;
|
85
|
124
|
|
86
|
|
- const isFocused = state.index === index;
|
87
|
|
-
|
88
|
125
|
const onPress = () => this.onItemPress(route, state.index, index);
|
89
|
|
-
|
90
|
126
|
const onLongPress = () => this.onItemLongPress(route);
|
91
|
|
-
|
92
|
|
- if (isFocused) {
|
93
|
|
- const stackState = route.state;
|
94
|
|
- const stackRoute = route.state ? stackState.routes[stackState.index] : undefined;
|
95
|
|
- const params = stackRoute ? stackRoute.params : undefined;
|
96
|
|
- const collapsible = params ? params.collapsible : undefined;
|
97
|
|
- if (collapsible && !this.state.barSynced) {
|
98
|
|
- this.setState({
|
99
|
|
- translateY: Animated.multiply(-1.5, collapsible.translateY),
|
100
|
|
- barSynced: true,
|
101
|
|
- });
|
102
|
|
- }
|
103
|
|
- }
|
|
127
|
+ const isFocused = state.index === index;
|
104
|
128
|
|
105
|
129
|
const color = isFocused ? this.props.theme.colors.primary : this.props.theme.colors.tabIcon;
|
106
|
130
|
if (route.name !== "home") {
|
|
@@ -124,8 +148,13 @@ class CustomTabBar extends React.Component<Props, State> {
|
124
|
148
|
/>
|
125
|
149
|
};
|
126
|
150
|
|
|
151
|
+ getIcons() {
|
|
152
|
+ return this.props.state.routes.map(this.renderIcon);
|
|
153
|
+ }
|
|
154
|
+
|
127
|
155
|
render() {
|
128
|
156
|
this.props.navigation.addListener('state', this.onRouteChange);
|
|
157
|
+ const icons = this.getIcons();
|
129
|
158
|
return (
|
130
|
159
|
<Animated.View
|
131
|
160
|
useNativeDriver
|
|
@@ -140,7 +169,7 @@ class CustomTabBar extends React.Component<Props, State> {
|
140
|
169
|
transform: [{translateY: this.state.translateY}],
|
141
|
170
|
}}
|
142
|
171
|
>
|
143
|
|
- {this.props.state.routes.map(this.renderIcon)}
|
|
172
|
+ {icons}
|
144
|
173
|
</Animated.View>
|
145
|
174
|
);
|
146
|
175
|
}
|