Skip to content

Commit 7e35bcf

Browse files
authored
Feat/drawer left toggle (#844)
* Adding leftToggle functionality * adding 'leftToggleHapticTrigger' prop to pass haptic trigger function * fix right items layout bug * moving style to styleSheet * Remove delay from item move on release * actions names change * adding left toggle on drag threshold * pr comments
1 parent 69a7911 commit 7e35bcf

File tree

3 files changed

+157
-55
lines changed

3 files changed

+157
-55
lines changed

demo/src/screens/componentScreens/DrawerScreen.js

Lines changed: 76 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import {
88
Drawer,
99
Text,
1010
Button,
11-
Avatar
11+
Avatar,
12+
Badge
1213
} from 'react-native-ui-lib'; //eslint-disable-line
1314
import {gestureHandlerRootHOC} from 'react-native-gesture-handler';
1415
import conversations from '../../data/conversations';
@@ -46,7 +47,8 @@ class DrawerScreen extends Component {
4647
showRightItems: true,
4748
fullSwipeRight: true,
4849
showLeftItem: true,
49-
fullSwipeLeft: true
50+
fullSwipeLeft: true,
51+
unread: true
5052
};
5153
}
5254

@@ -56,7 +58,7 @@ class DrawerScreen extends Component {
5658
}
5759
}
5860

59-
onFullSwipe = () => {
61+
deleteItem = () => {
6062
// TODO: consider including this functionality as part of the drawer component
6163
setTimeout(() => {
6264
LayoutAnimation.configureNext({
@@ -75,6 +77,14 @@ class DrawerScreen extends Component {
7577
}, 200);
7678
};
7779

80+
toggleReadState = () => {
81+
this.setState({unread: !this.state.unread}); // setState will close the Drawer
82+
}
83+
84+
triggerLeftToggleHaptic = () => {
85+
// console.warn('haptic trigger here');
86+
}
87+
7888
showItem = () => {
7989
this.setState({hideItem: false});
8090
};
@@ -89,6 +99,11 @@ class DrawerScreen extends Component {
8999
this.ref.openLeftFull();
90100
}
91101
};
102+
toggleLeftDrawer = () => {
103+
if (this.ref) {
104+
this.ref.toggleLeft();
105+
}
106+
};
92107
openRightDrawer = () => {
93108
if (this.ref) {
94109
this.ref.openRight();
@@ -110,38 +125,50 @@ class DrawerScreen extends Component {
110125
<View center marginB-s4>
111126
<Text text70>Actions</Text>
112127
<View row>
113-
<Button
114-
onPress={this.openLeftDrawer}
115-
label="Open left"
116-
style={{margin: 3}}
117-
size={'xSmall'}
118-
/>
119-
<Button
120-
onPress={this.closeDrawer}
121-
label="Close"
122-
style={{margin: 3}}
123-
size={'xSmall'}
124-
/>
125-
<Button
126-
onPress={this.openRightDrawer}
127-
label="Open right"
128-
style={{margin: 3}}
129-
size={'xSmall'}
130-
/>
131-
</View>
132-
<View row>
133-
<Button
134-
onPress={this.openLeftDrawerFull}
135-
label="Open left full"
136-
style={{margin: 3}}
137-
size={'xSmall'}
138-
/>
139-
<Button
140-
onPress={this.openRightDrawerFull}
141-
label="Open right full"
142-
style={{margin: 3}}
143-
size={'xSmall'}
144-
/>
128+
<View>
129+
<Button
130+
onPress={this.openLeftDrawer}
131+
label="Open left"
132+
style={{margin: 3}}
133+
size={'xSmall'}
134+
/>
135+
<Button
136+
onPress={this.openLeftDrawerFull}
137+
label="Full left swipe"
138+
style={{margin: 3}}
139+
size={'xSmall'}
140+
/>
141+
<Button
142+
onPress={this.toggleLeftDrawer}
143+
label="Left toggle"
144+
style={{margin: 3}}
145+
size={'xSmall'}
146+
/>
147+
</View>
148+
149+
<View marginH-20>
150+
<Button
151+
onPress={this.closeDrawer}
152+
label="Close"
153+
style={{margin: 3}}
154+
size={'xSmall'}
155+
/>
156+
</View>
157+
158+
<View>
159+
<Button
160+
onPress={this.openRightDrawer}
161+
label="Open right"
162+
style={{margin: 3}}
163+
size={'xSmall'}
164+
/>
165+
<Button
166+
onPress={this.openRightDrawerFull}
167+
label="Full right swipe"
168+
style={{margin: 3}}
169+
size={'xSmall'}
170+
/>
171+
</View>
145172
</View>
146173
</View>
147174
);
@@ -157,9 +184,10 @@ class DrawerScreen extends Component {
157184
centerV
158185
style={{borderBottomWidth: 1, borderColor: Colors.grey60}}
159186
>
160-
<Avatar source={{uri: conversations[0].thumbnail}} />
187+
{this.state.unread && <Badge size={'pimpleBig'} backgroundColor={Colors.purple30} containerStyle={{marginRight: 8}}/>}
188+
<Avatar source={{uri: conversations[0].thumbnail}}/>
161189
<View marginL-20>
162-
<Text text70R>{conversations[0].name}</Text>
190+
<Text text70R={!this.state.unread} text70BO={this.state.unread}>{conversations[0].name}</Text>
163191
<Text text80 marginT-2>
164192
{conversations[0].text}
165193
</Text>
@@ -186,16 +214,23 @@ class DrawerScreen extends Component {
186214
bounciness,
187215
ref: (component) => (this.ref = component),
188216
fullSwipeRight,
189-
onFullSwipeRight: this.onFullSwipe,
217+
onFullSwipeRight: this.deleteItem,
190218
fullSwipeLeft,
191-
onWillFullSwipeLeft: this.onFullSwipe
219+
onWillFullSwipeLeft: this.deleteItem,
220+
onToggleSwipeLeft: this.toggleReadState,
221+
leftToggleHapticTrigger: this.triggerLeftToggleHaptic
192222
};
193223
if (showRightItems) {
194-
drawerProps.rightItems = [ITEMS.read, ITEMS.archive];
224+
drawerProps.rightItems = [{...ITEMS.delete, onPress: this.deleteItem}, ITEMS.archive];
195225
}
196226

197227
if (showLeftItem) {
198-
drawerProps.leftItem = ITEMS.delete;
228+
drawerProps.leftItem = {
229+
icon: require('../../assets/icons/mail.png'),
230+
text: this.state.unread ? 'Read' : 'Unread',
231+
background: this.state.unread ? Colors.green30 : Colors.purple30,
232+
onPress: this.toggleReadState
233+
};
199234
}
200235

201236
return (

src/components/drawer/Swipeable.tsx

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {Constants} from '../../helpers';
1414

1515

1616
const DRAG_TOSS = 0.05;
17+
const LEFT_TOGGLE_THRESHOLD = 0.6;
1718

1819
// Math.sign polyfill for iOS 8.x
1920
if (!Math.sign) {
@@ -43,6 +44,7 @@ export type PropType = {
4344
onSwipeableWillOpen?: Function,
4445
onSwipeableWillClose?: Function,
4546
onFullSwipeLeft?: Function,
47+
onToggleSwipeLeft?: Function,
4648
onWillFullSwipeLeft?: Function,
4749
onFullSwipeRight?: Function,
4850
onWillFullSwipeRight?: Function,
@@ -88,6 +90,7 @@ export default class Swipeable extends Component<PropType, StateType> {
8890
// 1 -> closing to the left
8991
// -1 -> closing to the right
9092
this.rowState = 0;
93+
this.dragFired = false;
9194

9295
this.state = {
9396
dragX,
@@ -101,10 +104,25 @@ export default class Swipeable extends Component<PropType, StateType> {
101104
this._updateAnimatedEvent(props, this.state);
102105

103106
this._onGestureEvent = Animated.event([{nativeEvent: {translationX: dragX}}], {
104-
useNativeDriver: props.useNativeAnimations
107+
useNativeDriver: props.useNativeAnimations,
108+
listener: this._handleDrag
105109
});
106110
}
107111

112+
_handleDrag = (e) => {
113+
const {onToggleSwipeLeft} = this.props;
114+
115+
if (onToggleSwipeLeft && !this.dragFired) {
116+
const {rowWidth, leftWidth} = this.state;
117+
const x = e.nativeEvent.translationX;
118+
const threshold = rowWidth * LEFT_TOGGLE_THRESHOLD;
119+
if (x >= threshold && x < threshold + 10) {
120+
this.dragFired = true;
121+
onToggleSwipeLeft({rowWidth, leftWidth, dragX: x});
122+
}
123+
}
124+
}
125+
108126
// TODO: change to componentDidUpdate
109127
UNSAFE_componentWillUpdate(props: PropType, state: StateType) {
110128
if (
@@ -197,14 +215,18 @@ export default class Swipeable extends Component<PropType, StateType> {
197215
const {leftWidth = 0, rowWidth = 0} = this.state;
198216
const {rightOffset = rowWidth} = this.state;
199217
const rightWidth = rowWidth - rightOffset;
200-
const {fullSwipeLeft, fullSwipeRight, friction, leftThreshold = leftWidth / 2, rightThreshold = rightWidth / 2, fullLeftThreshold, fullRightThreshold} = this.props;
218+
const {fullSwipeLeft, fullSwipeRight, friction, leftThreshold = leftWidth / 2, rightThreshold = rightWidth / 2, fullLeftThreshold, fullRightThreshold, onToggleSwipeLeft} = this.props;
201219

202220
const startOffsetX = this._currentOffset() + dragX / friction;
203221
const translationX = (dragX + DRAG_TOSS * velocityX) / friction;
204222

205223
let toValue = 0;
206224
if (this.rowState === 0) {
207-
if (fullSwipeLeft && translationX > rowWidth * fullLeftThreshold) {
225+
if (onToggleSwipeLeft && translationX > leftWidth) {
226+
if (!this.dragFired) {
227+
toValue = rowWidth * LEFT_TOGGLE_THRESHOLD;
228+
}
229+
} else if (fullSwipeLeft && translationX > rowWidth * fullLeftThreshold) {
208230
toValue = rowWidth;
209231
} else if (fullSwipeRight && translationX < -rowWidth * fullRightThreshold) {
210232
toValue = -rowWidth;
@@ -229,7 +251,7 @@ export default class Swipeable extends Component<PropType, StateType> {
229251
};
230252

231253
_animateRow = (fromValue, toValue, velocityX) => {
232-
const {dragX, rowTranslation, rowWidth} = this.state;
254+
const {dragX, rowTranslation, rowWidth, leftWidth} = this.state;
233255
const {
234256
useNativeAnimations,
235257
animationOptions,
@@ -242,6 +264,8 @@ export default class Swipeable extends Component<PropType, StateType> {
242264
onSwipeableWillClose,
243265
onSwipeableWillOpen,
244266
onFullSwipeLeft,
267+
fullSwipeLeft,
268+
onToggleSwipeLeft,
245269
onWillFullSwipeLeft,
246270
onFullSwipeRight,
247271
onWillFullSwipeRight
@@ -260,7 +284,7 @@ export default class Swipeable extends Component<PropType, StateType> {
260284
useNativeDriver: useNativeAnimations,
261285
...animationOptions
262286
}).start(({finished}) => {
263-
if (finished) {
287+
if (finished) {
264288
if (toValue === rowWidth && onFullSwipeLeft) {
265289
onFullSwipeLeft();
266290
} else if (toValue === -rowWidth && onFullSwipeRight) {
@@ -279,7 +303,9 @@ export default class Swipeable extends Component<PropType, StateType> {
279303
}
280304
});
281305

282-
if (toValue === rowWidth && onWillFullSwipeLeft) {
306+
if (toValue === rowWidth * LEFT_TOGGLE_THRESHOLD && onToggleSwipeLeft) {
307+
onToggleSwipeLeft({rowWidth, leftWidth});
308+
} else if (toValue === rowWidth && onWillFullSwipeLeft) {
283309
onWillFullSwipeLeft()
284310
} else if (toValue === -rowWidth && onWillFullSwipeRight) {
285311
onWillFullSwipeRight()
@@ -323,6 +349,11 @@ export default class Swipeable extends Component<PropType, StateType> {
323349
this._animateRow(this._currentOffset(), rowWidth);
324350
};
325351

352+
toggleLeft = () => {
353+
const {rowWidth} = this.state;
354+
this._animateRow(this._currentOffset(), rowWidth * LEFT_TOGGLE_THRESHOLD);
355+
};
356+
326357
openRight = () => {
327358
const {rowWidth = 0} = this.state;
328359
const {rightOffset = rowWidth} = this.state;

0 commit comments

Comments
 (0)