1import * as Haptics from 'expo-haptics'; 2import React from 'react'; 3import { SectionList, SectionListData, StyleSheet, Text, View, ViewStyle } from 'react-native'; 4 5import Button from '../components/Button'; 6import MonoText from '../components/MonoText'; 7import Colors from '../constants/Colors'; 8 9type SectionData = 10 // See: https://github.com/expo/expo/pull/10229#discussion_r490961694 11 // eslint-disable-next-line @typescript-eslint/ban-types 12 | {} 13 | { 14 accessor: string; 15 value: any; 16 }; 17 18const sections: SectionListData<SectionData>[] = [ 19 { 20 methodName: 'notificationAsync', 21 method: Haptics.notificationAsync, 22 data: [ 23 { 24 accessor: 'Haptics.NotificationFeedbackType.Success', 25 value: Haptics.NotificationFeedbackType.Success, 26 }, 27 { 28 accessor: 'Haptics.NotificationFeedbackType.Warning', 29 value: Haptics.NotificationFeedbackType.Warning, 30 }, 31 { 32 accessor: 'Haptics.NotificationFeedbackType.Error', 33 value: Haptics.NotificationFeedbackType.Error, 34 }, 35 ], 36 }, 37 { 38 methodName: 'impactAsync', 39 method: Haptics.impactAsync, 40 data: [ 41 { 42 accessor: 'Haptics.ImpactFeedbackStyle.Light', 43 value: Haptics.ImpactFeedbackStyle.Light, 44 }, 45 { 46 accessor: 'Haptics.ImpactFeedbackStyle.Medium', 47 value: Haptics.ImpactFeedbackStyle.Medium, 48 }, 49 { 50 accessor: 'Haptics.ImpactFeedbackStyle.Heavy', 51 value: Haptics.ImpactFeedbackStyle.Heavy, 52 }, 53 ], 54 }, 55 { 56 methodName: 'selectionAsync', 57 method: Haptics.selectionAsync, 58 data: [{}], 59 }, 60]; 61 62export default class HapticsScreen extends React.Component { 63 static navigationOptions = { 64 title: 'Haptics Feedback', 65 }; 66 67 renderItem = ({ 68 item, 69 section: { method }, 70 }: { 71 item: { accessor: string; value: any }; 72 section: { method: (type: string) => void }; 73 }) => <Item method={method} type={item} />; 74 75 renderSectionHeader = ({ section: { methodName } }: { section: { methodName: string } }) => ( 76 <Header title={methodName} /> 77 ); 78 79 keyExtractor = (data: SectionData) => { 80 if ('accessor' in data && 'value' in data) { 81 return `key-${data.accessor}-${data.value}`; 82 } 83 return 'key-undefined'; 84 }; 85 86 render() { 87 return ( 88 <View style={styles.container}> 89 <SectionList<SectionData> 90 style={styles.list} 91 sections={sections} 92 renderItem={this.renderItem as any} 93 renderSectionHeader={this.renderSectionHeader as any} 94 keyExtractor={this.keyExtractor} 95 /> 96 </View> 97 ); 98 } 99} 100 101class Item extends React.Component<{ 102 method: (type: string) => void; 103 type: { accessor: string; value: any }; 104}> { 105 get code() { 106 const { 107 method, 108 type: { accessor }, 109 } = this.props; 110 return `Haptics.${method.name}(${accessor || ''})`; 111 } 112 render() { 113 const { 114 method, 115 type: { value }, 116 } = this.props; 117 118 return ( 119 <View style={styles.itemContainer}> 120 <HapticButton style={styles.button} method={method} type={value} /> 121 <MonoText containerStyle={styles.itemText}>{this.code}</MonoText> 122 </View> 123 ); 124 } 125} 126 127const Header: React.FunctionComponent<{ title: string }> = ({ title }) => ( 128 <View style={styles.headerContainer}> 129 <Text style={styles.headerText}>{title}</Text> 130 </View> 131); 132 133class HapticButton extends React.Component<{ 134 method: (type: string) => void; 135 type: string; 136 style: ViewStyle; 137}> { 138 onPress = () => { 139 const { method, type } = this.props; 140 method(type); 141 }; 142 render() { 143 return <Button onPress={this.onPress} style={this.props.style} title="Run" />; 144 } 145} 146 147const styles = StyleSheet.create({ 148 container: { 149 paddingVertical: 16, 150 flex: 1, 151 backgroundColor: Colors.greyBackground, 152 }, 153 list: { 154 flex: 1, 155 paddingHorizontal: 12, 156 }, 157 headerContainer: { 158 alignItems: 'stretch', 159 borderBottomColor: Colors.border, 160 borderBottomWidth: StyleSheet.hairlineWidth, 161 backgroundColor: Colors.greyBackground, 162 }, 163 headerText: { 164 color: Colors.tintColor, 165 paddingVertical: 4, 166 fontSize: 14, 167 fontWeight: 'bold', 168 }, 169 itemContainer: { 170 flexDirection: 'row', 171 alignItems: 'center', 172 }, 173 itemText: { 174 borderWidth: 0, 175 flex: 1, 176 marginVertical: 8, 177 paddingVertical: 18, 178 paddingLeft: 12, 179 }, 180 button: { 181 marginRight: 16, 182 }, 183}); 184