@ccrf01/react-native-template 0.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (233) hide show
  1. package/.github/workflows/npm-publish.yml +28 -0
  2. package/.vscode/settings.json +15 -0
  3. package/README.md +58 -0
  4. package/package.json +16 -0
  5. package/template/.bundle/config +2 -0
  6. package/template/.env.development +1 -0
  7. package/template/.env.production +1 -0
  8. package/template/.eslintrc.js +392 -0
  9. package/template/.java-version +1 -0
  10. package/template/.prettierrc.js +5 -0
  11. package/template/.ruby-version +1 -0
  12. package/template/.watchmanconfig +1 -0
  13. package/template/Gemfile +23 -0
  14. package/template/Gemfile.lock +330 -0
  15. package/template/README.md +97 -0
  16. package/template/ReactotronConfig.js +17 -0
  17. package/template/__tests__/App.test.tsx +13 -0
  18. package/template/_gitignore +75 -0
  19. package/template/_node-version +1 -0
  20. package/template/android/app/build.gradle +162 -0
  21. package/template/android/app/debug.keystore +0 -0
  22. package/template/android/app/proguard-rules.pro +10 -0
  23. package/template/android/app/src/debug/AndroidManifest.xml +9 -0
  24. package/template/android/app/src/main/AndroidManifest.xml +26 -0
  25. package/template/android/app/src/main/java/com/projectname/MainActivity.kt +30 -0
  26. package/template/android/app/src/main/java/com/projectname/MainApplication.kt +27 -0
  27. package/template/android/app/src/main/res/drawable/rn_edit_text_material.xml +37 -0
  28. package/template/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
  29. package/template/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
  30. package/template/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
  31. package/template/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
  32. package/template/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
  33. package/template/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
  34. package/template/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  35. package/template/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
  36. package/template/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
  37. package/template/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
  38. package/template/android/app/src/main/res/values/strings.xml +3 -0
  39. package/template/android/app/src/main/res/values/styles.xml +9 -0
  40. package/template/android/build.gradle +37 -0
  41. package/template/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  42. package/template/android/gradle/wrapper/gradle-wrapper.properties +7 -0
  43. package/template/android/gradle.properties +48 -0
  44. package/template/android/gradlew +251 -0
  45. package/template/android/gradlew.bat +99 -0
  46. package/template/android/keystore/keystore.properties +4 -0
  47. package/template/android/settings.gradle +6 -0
  48. package/template/android/version.properties +2 -0
  49. package/template/app.json +4 -0
  50. package/template/babel.config.js +38 -0
  51. package/template/fastlane/Fastfile +136 -0
  52. package/template/fastlane/Pluginfile +9 -0
  53. package/template/fastlane/README.md +46 -0
  54. package/template/index.js +9 -0
  55. package/template/ios/.xcode.env +11 -0
  56. package/template/ios/Podfile +35 -0
  57. package/template/ios/Podfile.lock +3669 -0
  58. package/template/ios/ProjectName/AppDelegate.swift +48 -0
  59. package/template/ios/ProjectName/Images.xcassets/AppIcon.appiconset/Contents.json +53 -0
  60. package/template/ios/ProjectName/Images.xcassets/Contents.json +6 -0
  61. package/template/ios/ProjectName/Info.plist +66 -0
  62. package/template/ios/ProjectName/LaunchScreen.storyboard +47 -0
  63. package/template/ios/ProjectName/PrivacyInfo.xcprivacy +47 -0
  64. package/template/ios/ProjectName.xcodeproj/project.pbxproj +482 -0
  65. package/template/ios/ProjectName.xcodeproj/xcshareddata/xcschemes/ProjectName.xcscheme +88 -0
  66. package/template/ios/ProjectName.xcworkspace/contents.xcworkspacedata +10 -0
  67. package/template/jest.config.js +3 -0
  68. package/template/metro.config.js +20 -0
  69. package/template/package-lock.json +17073 -0
  70. package/template/package.json +156 -0
  71. package/template/src/@types/emotion.d.ts +12 -0
  72. package/template/src/@types/env.d.ts +3 -0
  73. package/template/src/@types/redux-persist-transform-immutable.d.ts +1 -0
  74. package/template/src/@types/typing.d.ts +17 -0
  75. package/template/src/AppContainer.tsx +109 -0
  76. package/template/src/assets/images/143.png +0 -0
  77. package/template/src/assets/index.ts +13 -0
  78. package/template/src/components/basic/BackButton/index.tsx +34 -0
  79. package/template/src/components/basic/Body/index.tsx +68 -0
  80. package/template/src/components/basic/Button/index.tsx +181 -0
  81. package/template/src/components/basic/Button/utils.ts +78 -0
  82. package/template/src/components/basic/ButtonGroup/index.tsx +182 -0
  83. package/template/src/components/basic/Card/index.tsx +3 -0
  84. package/template/src/components/basic/Container/index.tsx +38 -0
  85. package/template/src/components/basic/Content/index.tsx +87 -0
  86. package/template/src/components/basic/DropDown/index.tsx +354 -0
  87. package/template/src/components/basic/ExpandableOverlay/index.tsx +113 -0
  88. package/template/src/components/basic/Header/index.tsx +216 -0
  89. package/template/src/components/basic/Header/styles.ts +0 -0
  90. package/template/src/components/basic/Icons/index.tsx +131 -0
  91. package/template/src/components/basic/InputLabel/index.tsx +19 -0
  92. package/template/src/components/basic/LoadingOverlay/index.tsx +68 -0
  93. package/template/src/components/basic/MaterialTextInput/index.tsx +153 -0
  94. package/template/src/components/basic/NumberInput/index.tsx +53 -0
  95. package/template/src/components/basic/Picker/PickerContext.ts +7 -0
  96. package/template/src/components/basic/Picker/PickerHeader.tsx +130 -0
  97. package/template/src/components/basic/Picker/PickerItem.tsx +105 -0
  98. package/template/src/components/basic/Picker/PickerItemsList.tsx +135 -0
  99. package/template/src/components/basic/Picker/PickerPresenter.ts +54 -0
  100. package/template/src/components/basic/Picker/hooks/useImperativePickerHandle.ts +27 -0
  101. package/template/src/components/basic/Picker/hooks/usePickerLabel.ts +74 -0
  102. package/template/src/components/basic/Picker/hooks/usePickerSearch.ts +37 -0
  103. package/template/src/components/basic/Picker/hooks/usePickerSelection.ts +57 -0
  104. package/template/src/components/basic/Picker/index.tsx +284 -0
  105. package/template/src/components/basic/Picker/types.tsx +229 -0
  106. package/template/src/components/basic/PressableOpacity/index.tsx +20 -0
  107. package/template/src/components/basic/RootDialog/Dialog.tsx +246 -0
  108. package/template/src/components/basic/RootDialog/Manager.tsx +110 -0
  109. package/template/src/components/basic/RootDialog/animations/Animation.ts +29 -0
  110. package/template/src/components/basic/RootDialog/animations/FadeAnimation.ts +40 -0
  111. package/template/src/components/basic/RootDialog/animations/ScaleAnimation.ts +37 -0
  112. package/template/src/components/basic/RootDialog/animations/SlideAnimation.ts +89 -0
  113. package/template/src/components/basic/RootDialog/components/Backdrop.tsx +60 -0
  114. package/template/src/components/basic/RootDialog/components/BaseDialog.tsx +564 -0
  115. package/template/src/components/basic/RootDialog/components/BottomDialog.tsx +32 -0
  116. package/template/src/components/basic/RootDialog/components/DialogButton.tsx +87 -0
  117. package/template/src/components/basic/RootDialog/components/DialogContent.tsx +26 -0
  118. package/template/src/components/basic/RootDialog/components/DialogContext.tsx +8 -0
  119. package/template/src/components/basic/RootDialog/components/DialogFooter.tsx +42 -0
  120. package/template/src/components/basic/RootDialog/components/DialogTitle.tsx +53 -0
  121. package/template/src/components/basic/RootDialog/components/DraggableView.tsx +271 -0
  122. package/template/src/components/basic/RootDialog/index.ts +21 -0
  123. package/template/src/components/basic/RootDialog/type.ts +102 -0
  124. package/template/src/components/basic/Text/index.tsx +8 -0
  125. package/template/src/components/basic/index.ts +35 -0
  126. package/template/src/configs/constants/type/APIStatus.type.ts +8 -0
  127. package/template/src/configs/constants/type/Locale.type.ts +7 -0
  128. package/template/src/configs/constants/type/StorageKey.type.ts +7 -0
  129. package/template/src/configs/constants/type/ThemeType.type.ts +6 -0
  130. package/template/src/configs/constants/type/index.ts +11 -0
  131. package/template/src/configs/index.ts +22 -0
  132. package/template/src/contexts/ThemeContext.ts +6 -0
  133. package/template/src/hooks/useAppLoading.ts +26 -0
  134. package/template/src/hooks/useAppState.ts +36 -0
  135. package/template/src/hooks/useArray.ts +47 -0
  136. package/template/src/hooks/useAsync.ts +42 -0
  137. package/template/src/hooks/useAsyncStorage.ts +41 -0
  138. package/template/src/hooks/useBoolean.ts +21 -0
  139. package/template/src/hooks/useBuildTheme.ts +249 -0
  140. package/template/src/hooks/useCountDown.ts +111 -0
  141. package/template/src/hooks/useCounter.ts +27 -0
  142. package/template/src/hooks/useDebounce.ts +25 -0
  143. package/template/src/hooks/useDebouncedValidate.ts +32 -0
  144. package/template/src/hooks/useDebugInformation.ts +38 -0
  145. package/template/src/hooks/useDeviceToken.ts +20 -0
  146. package/template/src/hooks/useEncryptedStorage.ts +41 -0
  147. package/template/src/hooks/useFontFamily.ts +13 -0
  148. package/template/src/hooks/useHttp.ts +18 -0
  149. package/template/src/hooks/useInterval.ts +24 -0
  150. package/template/src/hooks/useIsForeground.ts +17 -0
  151. package/template/src/hooks/useMMKVStorage.ts +0 -0
  152. package/template/src/hooks/usePrevious.ts +12 -0
  153. package/template/src/hooks/useRenderCount.ts +10 -0
  154. package/template/src/hooks/useTheme.ts +17 -0
  155. package/template/src/hooks/useTimeCountDown.ts +91 -0
  156. package/template/src/index.tsx +65 -0
  157. package/template/src/infrastructures/NetClient/AbstractClient.ts +66 -0
  158. package/template/src/infrastructures/NetClient/ApiResponse.ts +16 -0
  159. package/template/src/infrastructures/NetClient/ApisauceClient.ts +76 -0
  160. package/template/src/infrastructures/NetClient/AxiosClient.ts +80 -0
  161. package/template/src/infrastructures/NetClient/FetchNetClient.ts +120 -0
  162. package/template/src/infrastructures/NetClient/config.ts +3 -0
  163. package/template/src/infrastructures/NetClient/interfaces/INetClient.ts +6 -0
  164. package/template/src/infrastructures/Storage/IStorage.ts +7 -0
  165. package/template/src/infrastructures/Storage/MMKVStorage.ts +41 -0
  166. package/template/src/infrastructures/common/Timeout.ts +27 -0
  167. package/template/src/infrastructures/common/colorUtils.ts +82 -0
  168. package/template/src/infrastructures/common/dateUtils.ts +39 -0
  169. package/template/src/infrastructures/common/logger.ts +115 -0
  170. package/template/src/locales/en-US/general.json +26 -0
  171. package/template/src/locales/en-US/index.ts +9 -0
  172. package/template/src/locales/en-US/screens.json +4 -0
  173. package/template/src/locales/en-US/setting.json +3 -0
  174. package/template/src/locales/i18n.ts +109 -0
  175. package/template/src/locales/zh-TW/general.json +26 -0
  176. package/template/src/locales/zh-TW/index.ts +9 -0
  177. package/template/src/locales/zh-TW/screens.json +4 -0
  178. package/template/src/locales/zh-TW/setting.json +3 -0
  179. package/template/src/models/index.ts +5 -0
  180. package/template/src/models/request.model.ts +50 -0
  181. package/template/src/navigators/DrawerNav/DrawerContent.tsx +66 -0
  182. package/template/src/navigators/DrawerNav/DrawerItem.tsx +261 -0
  183. package/template/src/navigators/DrawerNav/index.tsx +39 -0
  184. package/template/src/navigators/DrawerNav/props.ts +12 -0
  185. package/template/src/navigators/DrawerNav/types.ts +8 -0
  186. package/template/src/navigators/MainBottomTabNav/index.tsx +83 -0
  187. package/template/src/navigators/MainBottomTabNav/props.ts +16 -0
  188. package/template/src/navigators/MainBottomTabNav/types.ts +6 -0
  189. package/template/src/navigators/RootStack.tsx +43 -0
  190. package/template/src/navigators/index.tsx +40 -0
  191. package/template/src/navigators/props.ts +14 -0
  192. package/template/src/navigators/types.ts +18 -0
  193. package/template/src/navigators/utils.ts +68 -0
  194. package/template/src/redux/api/api.ts +41 -0
  195. package/template/src/redux/reducers/appSlice.ts +26 -0
  196. package/template/src/redux/reducers/index.ts +21 -0
  197. package/template/src/redux/reducers/nonPersistSlice.ts +51 -0
  198. package/template/src/redux/reducers/settingSlice.ts +48 -0
  199. package/template/src/redux/reducers/themeSlice.ts +55 -0
  200. package/template/src/redux/saga/index.ts +5 -0
  201. package/template/src/redux/saga/settingSaga.ts +21 -0
  202. package/template/src/redux/selectors/app.ts +9 -0
  203. package/template/src/redux/selectors/nonPersist.ts +23 -0
  204. package/template/src/redux/selectors/setting.ts +29 -0
  205. package/template/src/redux/selectors/theme.ts +13 -0
  206. package/template/src/redux/store/index.ts +79 -0
  207. package/template/src/redux/store/types.d.ts +5 -0
  208. package/template/src/screens/Home/index.tsx +146 -0
  209. package/template/src/screens/Settings/components/Item.tsx +45 -0
  210. package/template/src/screens/Settings/index.tsx +97 -0
  211. package/template/src/screens/Splash/index.tsx +53 -0
  212. package/template/src/services/Dialogs.tsx +226 -0
  213. package/template/src/services/PermissionCheck.ts +257 -0
  214. package/template/src/theme/Common.ts +48 -0
  215. package/template/src/theme/Fonts.ts +196 -0
  216. package/template/src/theme/Gutters.ts +63 -0
  217. package/template/src/theme/Icons.ts +28 -0
  218. package/template/src/theme/Images.ts +13 -0
  219. package/template/src/theme/Layout.ts +106 -0
  220. package/template/src/theme/Variables.ts +167 -0
  221. package/template/src/theme/components/Buttons.ts +37 -0
  222. package/template/src/theme/index.ts +8 -0
  223. package/template/src/theme/metrics.ts +57 -0
  224. package/template/src/theme/themes/default_dark/Images.ts +7 -0
  225. package/template/src/theme/themes/default_dark/Variables.ts +84 -0
  226. package/template/src/theme/themes/default_dark/index.ts +2 -0
  227. package/template/src/theme/themes/index.ts +8 -0
  228. package/template/src/theme/types.ts +152 -0
  229. package/template/src/utils/encrypt-helper.ts +118 -0
  230. package/template/src/utils/index.ts +76 -0
  231. package/template/src/utils/sys-info-data.ts +17 -0
  232. package/template/tsconfig.json +44 -0
  233. package/template.config.js +8 -0
@@ -0,0 +1,42 @@
1
+ import React, { Children, cloneElement } from 'react'
2
+ import { PixelRatio, StyleSheet, View } from 'react-native'
3
+
4
+ import type { DialogFooterProps } from '../type'
5
+
6
+ const styles = StyleSheet.create({
7
+ border: {
8
+ borderColor: '#CCD0D5',
9
+ borderTopWidth: 1 / PixelRatio.get(),
10
+ },
11
+ actionsVertical: {
12
+ height: 200,
13
+ flexDirection: 'column',
14
+ },
15
+ actionsHorizontal: { flexDirection: 'row' },
16
+ })
17
+
18
+ const DialogActionList = ({ bordered = true, children, style }: DialogFooterProps) => {
19
+ const containerStyle = children.length > 2
20
+ ? styles.actionsVertical
21
+ : styles.actionsHorizontal
22
+
23
+ const border = bordered
24
+ ? styles.border
25
+ : null
26
+
27
+ // apply horizontal border if actions legnth is 2 & bordered is true
28
+ // const content = children.length === 2
29
+ // ? Children.map(children, ((child, index) => cloneElement(child, {
30
+ // bordered: (1 % index === 0 && bordered),
31
+ // })))
32
+ // : children
33
+ // const content = children
34
+
35
+ return (
36
+ <View style={[containerStyle, border, style]}>
37
+ {children}
38
+ </View>
39
+ )
40
+ }
41
+
42
+ export default DialogActionList
@@ -0,0 +1,53 @@
1
+ import React from 'react'
2
+ import { PixelRatio, Platform, StyleSheet, View } from 'react-native'
3
+ import { Text } from 'react-native-paper'
4
+
5
+ import useTheme from '@/hooks/useTheme'
6
+
7
+ import type { DialogTitleProps } from '../type'
8
+
9
+ const isAndroid = Platform.OS === 'android'
10
+
11
+ const styles = StyleSheet.create({
12
+ title: {
13
+ padding: 14,
14
+ paddingHorizontal: 18,
15
+ borderTopLeftRadius: 8,
16
+ borderTopRightRadius: 8,
17
+ },
18
+ titleBar: {
19
+ borderBottomWidth: 1 / PixelRatio.get(),
20
+ backgroundColor: '#F9F9FB',
21
+ borderColor: '#DAD9DC',
22
+ },
23
+ text: {
24
+ // fontWeight: isAndroid ? '400' : '500',
25
+ // fontFamily: isAndroid ? 'sans-serif-medium' : 'System',
26
+ // fontSize: isAndroid ? 19 : 15,
27
+ color: '#151822',
28
+ // ...titleFontStyle,
29
+ },
30
+ })
31
+
32
+ const ModalTitle = ({
33
+ align = 'center', hasTitleBar = true, style, textStyle, title,
34
+ }: DialogTitleProps) => {
35
+ const titleBar = hasTitleBar ? styles.titleBar : null
36
+ const titleAlign = { alignItems: align }
37
+ const { Fonts } = useTheme()
38
+
39
+ return (
40
+ <View style={[styles.title, titleAlign, titleBar, style]}>
41
+ <Text style={[
42
+ styles.text,
43
+ Fonts.title,
44
+ textStyle,
45
+ ]}
46
+ >
47
+ {title}
48
+ </Text>
49
+ </View>
50
+ )
51
+ }
52
+
53
+ export default ModalTitle
@@ -0,0 +1,271 @@
1
+ /* eslint-disable @typescript-eslint/no-unsafe-assignment */
2
+ /* eslint-disable @typescript-eslint/no-empty-function */
3
+ import { isArray } from 'lodash'
4
+ import React, { Component, ReactNode } from 'react'
5
+ import {
6
+ Animated,
7
+ Dimensions,
8
+ GestureResponderEvent,
9
+ LayoutChangeEvent,
10
+ LayoutRectangle,
11
+ PanResponder,
12
+ PanResponderGestureState,
13
+ ViewStyle,
14
+ } from 'react-native'
15
+
16
+ // import type { ViewLayoutEvent } from 'react-native/Libraries/Components/View/ViewPropTypes';
17
+ import type { DragEvent, SwipeDirection } from '../type'
18
+
19
+ type Props = {
20
+ style?: ViewStyle
21
+ onMove?: (event: DragEvent) => void
22
+ onSwiping?: (event: DragEvent) => void
23
+ onRelease?: (event: DragEvent) => void
24
+ onSwipingOut?: (event: DragEvent) => void
25
+ onSwipeOut?: (event: DragEvent) => void
26
+ swipeThreshold?: number
27
+ swipeDirection?: SwipeDirection | SwipeDirection[]
28
+ children: ({ onLayout, pan }: {
29
+ onLayout: (event: LayoutChangeEvent) => void
30
+ pan: Animated.ValueXY
31
+ }) => ReactNode
32
+ }
33
+ type State = {
34
+ x: number
35
+ y: number
36
+ }
37
+
38
+ export default class DraggableView extends Component<Props, State> {
39
+ static defaultProps = {
40
+ style: null,
41
+ onMove: () => { },
42
+ onSwiping: () => { },
43
+ onSwipingOut: () => { },
44
+ onSwipeOut: null,
45
+ onRelease: () => { },
46
+ swipeThreshold: 100,
47
+ swipeDirection: [],
48
+ }
49
+
50
+ pan: Animated.ValueXY
51
+ allowedDirections: SwipeDirection[]
52
+ layout: LayoutRectangle
53
+ panEventListenerId: any
54
+ currentSwipeDirection: string | null
55
+ constructor(props: Props) {
56
+ super(props)
57
+
58
+ this.pan = new Animated.ValueXY()
59
+ this.allowedDirections = isArray(props.swipeDirection) ? props.swipeDirection?.slice() || [] : (props.swipeDirection ? [props.swipeDirection] : [])
60
+ this.layout = {
61
+ x: 0,
62
+ y: 0,
63
+ width: 0,
64
+ height: 0,
65
+ }
66
+ this.currentSwipeDirection = null
67
+ this.state = {
68
+ x: 0,
69
+ y: 0,
70
+ }
71
+ }
72
+
73
+ componentDidMount() {
74
+ this.panEventListenerId = this.pan.addListener((axis) => {
75
+ this.setState({
76
+ ...axis,
77
+ })
78
+ if (this.props.onMove) {
79
+ this.props.onMove(this.createDragEvent(axis))
80
+ }
81
+ })
82
+ }
83
+
84
+ componentWillUnmount() {
85
+ this.pan.removeListener(this.panEventListenerId)
86
+ }
87
+
88
+ onLayout = (event: LayoutChangeEvent) => {
89
+ this.layout = event.nativeEvent.layout
90
+ }
91
+
92
+ getSwipeDirection(gestureState: PanResponderGestureState) {
93
+ if (this.isValidHorizontalSwipe(gestureState)) {
94
+ return (gestureState.dx > 0) ? 'right' : 'left'
95
+ } else if (this.isValidVerticalSwipe(gestureState)) {
96
+ return (gestureState.dy > 0) ? 'down' : 'up'
97
+ }
98
+
99
+ return null
100
+ }
101
+
102
+ getDisappearDirection() {
103
+ const { height, width } = Dimensions.get('window')
104
+ const vertical = ((height / 2) + (this.layout.height / 2))
105
+ const horizontal = ((width / 2) + (this.layout.width / 2))
106
+ // let toValue = {}
107
+ if (this.currentSwipeDirection === 'up') {
108
+ return {
109
+ x: 0,
110
+ y: -vertical,
111
+ }
112
+ } else if (this.currentSwipeDirection === 'down') {
113
+ return {
114
+ x: 0,
115
+ y: vertical,
116
+ }
117
+ } else if (this.currentSwipeDirection === 'left') {
118
+ return {
119
+ x: -horizontal,
120
+ y: 0,
121
+ }
122
+ } else if (this.currentSwipeDirection === 'right') {
123
+ return {
124
+ x: horizontal,
125
+ y: 0,
126
+ }
127
+ }
128
+
129
+ return null
130
+ }
131
+
132
+ isValidHorizontalSwipe({ dy, vx }: { vx: number; dy: number }) {
133
+ return this.isValidSwipe(vx, dy)
134
+ }
135
+
136
+ isValidVerticalSwipe({ dx, vy }: { vy: number; dx: number }) {
137
+ return this.isValidSwipe(vy, dx)
138
+ }
139
+
140
+ // eslint-disable-next-line class-methods-use-this
141
+ isValidSwipe(velocity: number, directionalOffset: number) {
142
+ const velocityThreshold = 0.3
143
+ const directionalOffsetThreshold = 80
144
+
145
+ // eslint-disable-next-line max-len
146
+ return Math.abs(velocity) > velocityThreshold && Math.abs(directionalOffset) < directionalOffsetThreshold
147
+ }
148
+
149
+ isAllowedDirection({ dx, dy }: { dx: number; dy: number }) {
150
+ const draggedDown = dy > 0
151
+ const draggedUp = dy < 0
152
+ const draggedLeft = dx < 0
153
+ const draggedRight = dx > 0
154
+ const isAllowedDirection = (d: any) => (
155
+ this.currentSwipeDirection === d && this.allowedDirections.includes(d)
156
+ )
157
+ if (draggedDown && isAllowedDirection('down')) {
158
+ return true
159
+ } else if (draggedUp && isAllowedDirection('up')) {
160
+ return true
161
+ } else if (draggedLeft && isAllowedDirection('left')) {
162
+ return true
163
+ } else if (draggedRight && isAllowedDirection('right')) {
164
+ return true
165
+ }
166
+
167
+ return false
168
+ }
169
+
170
+ createDragEvent(axis: { x: number; y: number }): DragEvent {
171
+ return {
172
+ axis,
173
+ layout: this.layout,
174
+ swipeDirection: this.currentSwipeDirection,
175
+ }
176
+ }
177
+
178
+ panResponder = PanResponder.create({
179
+ onMoveShouldSetPanResponder: (evt, gestureState) => (
180
+ gestureState.dx !== 0 && gestureState.dy !== 0
181
+ ),
182
+ onStartShouldSetPanResponder: () => true,
183
+ onPanResponderMove: (event: GestureResponderEvent, gestureState: PanResponderGestureState) => {
184
+ const isVerticalSwipe = (d: any) => ['up', 'down'].includes(d)
185
+ const isHorizontalSwipe = (d: any) => ['left', 'right'].includes(d)
186
+
187
+ const newSwipeDirection = this.getSwipeDirection(gestureState)
188
+ const isSameDirection =
189
+ isVerticalSwipe(this.currentSwipeDirection) === isVerticalSwipe(newSwipeDirection) ||
190
+ isHorizontalSwipe(this.currentSwipeDirection) === isHorizontalSwipe(newSwipeDirection)
191
+ // newDirection & currentSwipeDirection must be same direction
192
+ if (newSwipeDirection && isSameDirection) {
193
+ this.currentSwipeDirection = newSwipeDirection
194
+ }
195
+ if (this.isAllowedDirection(gestureState)) {
196
+ let animEvent = {}
197
+ if (isVerticalSwipe(this.currentSwipeDirection)) {
198
+ animEvent = { dy: this.pan.y }
199
+ } else if (isHorizontalSwipe(this.currentSwipeDirection)) {
200
+ animEvent = { dx: this.pan.x }
201
+ }
202
+ Animated.event([null, animEvent])(event, gestureState)
203
+ if (this.props.onSwiping) {
204
+ this.props.onSwiping(this.createDragEvent({
205
+ x: this.state.x,
206
+ y: this.state.y,
207
+ }))
208
+ }
209
+ }
210
+ },
211
+ onPanResponderRelease: () => {
212
+ this.pan.flattenOffset()
213
+ const event = this.createDragEvent({
214
+ x: this.state.x,
215
+ y: this.state.y,
216
+ })
217
+ // on swipe out
218
+ if (
219
+ this.props.onSwipeOut &&
220
+ Math.abs(this.state.x) > (this.props.swipeThreshold || 100) ||
221
+ Math.abs(this.state.y) > (this.props.swipeThreshold || 100)
222
+ ) {
223
+ if (this.props.onSwipingOut) this.props.onSwipingOut(event)
224
+ const toValue = this.getDisappearDirection()
225
+ if (toValue !== null) {
226
+ Animated.spring(this.pan, {
227
+ toValue: toValue,
228
+ velocity: 0,
229
+ tension: 65,
230
+ friction: 11,
231
+ useNativeDriver: false,
232
+ }).start(() => {
233
+ if (this.props.onSwipeOut) this.props.onSwipeOut(event)
234
+ })
235
+ }
236
+
237
+ return
238
+ }
239
+ // on release
240
+ this.currentSwipeDirection = null
241
+ if (this.props.onRelease) this.props.onRelease(event)
242
+ Animated.spring(this.pan, {
243
+ toValue: {
244
+ x: 0,
245
+ y: 0,
246
+ },
247
+ velocity: 0,
248
+ tension: 65,
249
+ friction: 11,
250
+ useNativeDriver: false,
251
+ }).start()
252
+ },
253
+ })
254
+
255
+ render() {
256
+ const { children: renderContent, style } = this.props
257
+ const content = renderContent({
258
+ pan: this.pan,
259
+ onLayout: this.onLayout,
260
+ })
261
+
262
+ return (
263
+ <Animated.View
264
+ {...this.panResponder.panHandlers}
265
+ style={style}
266
+ >
267
+ { content}
268
+ </Animated.View >
269
+ )
270
+ }
271
+ }
@@ -0,0 +1,21 @@
1
+ import FadeAnimation from './animations/FadeAnimation'
2
+ import ScaleAnimation from './animations/ScaleAnimation'
3
+ import SlideAnimation from './animations/SlideAnimation'
4
+ import DialogButton from './components/DialogButton'
5
+ import DialogContent from './components/DialogContent'
6
+ import DialogFooter from './components/DialogFooter'
7
+ import DialogTitle from './components/DialogTitle'
8
+ import Dialog from './Dialog'
9
+ import DialogManager from './Manager'
10
+
11
+ export {
12
+ Dialog,
13
+ DialogButton,
14
+ DialogContent,
15
+ DialogFooter,
16
+ DialogTitle,
17
+ FadeAnimation,
18
+ ScaleAnimation,
19
+ SlideAnimation,
20
+ }
21
+ export default new DialogManager()
@@ -0,0 +1,102 @@
1
+ import { PropsWithChildren, ReactElement, ReactNode } from 'react'
2
+ import { StyleProp, TextStyle, ViewStyle } from 'react-native'
3
+
4
+ import { IButtonProps } from '@/components/basic/Button'
5
+
6
+ import Animation from './animations/Animation'
7
+ import DialogButton from './components/DialogButton'
8
+
9
+ export type SwipeDirection = 'up' | 'down' | 'left' | 'right'
10
+
11
+ export type DragEvent = {
12
+ axis: {
13
+ x: number
14
+ y: number
15
+ }
16
+ layout: {
17
+ x: number
18
+ y: number
19
+ width: number
20
+ height: number
21
+ }
22
+ swipeDirection: string | null
23
+ }
24
+
25
+ export type DialogProps = PropsWithChildren<{
26
+ visible: boolean
27
+ children: ReactElement<any>
28
+ width?: number
29
+ height?: number
30
+ rounded?: boolean
31
+ hasOverlay?: boolean
32
+ overlayPointerEvents?: 'auto' | 'none'
33
+ overlayBackgroundColor?: string
34
+ overlayOpacity?: number
35
+ modalTitle?: ReactElement<any>
36
+ modalAnimation?: Animation
37
+ modalStyle?: StyleProp<ViewStyle>
38
+ style?: StyleProp<ViewStyle>
39
+ animationDuration?: number
40
+ onTouchOutside?: () => void
41
+ onHardwareBackPress?: () => boolean
42
+ onShow?: () => void
43
+ onDismiss?: () => void
44
+ footer?: ReactElement<any>
45
+ onMove?: (event: DragEvent) => void
46
+ onSwiping?: (event :DragEvent) => void
47
+ onSwipeRelease?: (event: DragEvent) => void
48
+ onSwipingOut?: (event: DragEvent) => void
49
+ onSwipeOut?: (event: DragEvent) => void
50
+ swipeDirection?: SwipeDirection | SwipeDirection[]
51
+ swipeThreshold?: number
52
+ useNativeDriver?: boolean
53
+ theme?: any
54
+ }>
55
+
56
+ export type DialogFooterActionList = ReactElement<typeof DialogButton>[]
57
+
58
+ export type DialogFooterProps = {
59
+ children: DialogFooterActionList
60
+ style?: StyleProp<ViewStyle>
61
+ bordered?: boolean
62
+ }
63
+
64
+ // export type DialogButtonProps = {
65
+ // label: string
66
+ // onPress: () => void
67
+ // mode?: 'text' | 'outlined' | 'contained'
68
+ // align?: 'center' | 'flex-start' | 'flex-end'
69
+ // color?: string
70
+ // contentStyle?: StyleProp<ViewStyle>
71
+ // style?: StyleProp<ViewStyle>
72
+ // labelStyle?: StyleProp<TextStyle>
73
+ // disabled?: boolean
74
+ // activeOpacity?: number
75
+ // }
76
+
77
+ export type DialogButtonProps = IButtonProps & {
78
+ isCancel?: boolean
79
+ }
80
+
81
+ export type DialogTitleProps = {
82
+ title: string
83
+ style?: StyleProp<ViewStyle>
84
+ textStyle?: any
85
+ align?: 'flex-start'|'flex-end'|'center'
86
+ hasTitleBar?: boolean
87
+ }
88
+
89
+ export type DialogContentProps = {
90
+ children: any
91
+ style?: StyleProp<ViewStyle>
92
+ }
93
+
94
+ export type BackdropProps = {
95
+ visible: boolean
96
+ opacity: number
97
+ onPress?: () => void
98
+ backgroundColor?: string
99
+ animationDuration?: number
100
+ pointerEvents?: 'box-none' | 'none' | 'box-only' | 'auto'
101
+ useNativeDriver?: boolean
102
+ }
@@ -0,0 +1,8 @@
1
+ import { customText } from 'react-native-paper'
2
+
3
+ import { FontType } from '@/theme/Fonts'
4
+
5
+ type Variant = keyof FontType
6
+ const Text = customText<Variant>()
7
+
8
+ export default Text
@@ -0,0 +1,35 @@
1
+ import BackButton from './BackButton'
2
+ import Body from './Body'
3
+ import Button from './Button'
4
+ import ButtonGroup from './ButtonGroup'
5
+ import Container from './Container'
6
+ import Content from './Content'
7
+ import DropDown from './DropDown'
8
+ import Header from './Header'
9
+ import IconX from './Icons'
10
+ import InputLabel from './InputLabel'
11
+ import LoadingOverlay from './LoadingOverlay'
12
+ import MaterialTextInput from './MaterialTextInput'
13
+ import Picker from './Picker'
14
+ import PressableOpacity from './PressableOpacity'
15
+ import DialogManager from './RootDialog'
16
+ import Text from './Text'
17
+
18
+ export {
19
+ BackButton,
20
+ Body,
21
+ Button,
22
+ ButtonGroup,
23
+ Container,
24
+ Content,
25
+ DialogManager,
26
+ DropDown,
27
+ Header,
28
+ IconX,
29
+ InputLabel,
30
+ LoadingOverlay,
31
+ MaterialTextInput,
32
+ Picker,
33
+ PressableOpacity,
34
+ Text,
35
+ }
@@ -0,0 +1,8 @@
1
+ export const APIStatus = {
2
+ IDLE: 'idle',
3
+ LOADING: 'loading',
4
+ SUCCEEDED: 'succeeded',
5
+ FAILED: 'failed',
6
+ } as const
7
+
8
+ export type APIStatus = typeof APIStatus[keyof typeof APIStatus]
@@ -0,0 +1,7 @@
1
+ export const Locale = {
2
+ enUS: 'en_US',
3
+ zhTW: 'zh_TW',
4
+ zhCN: 'zh_CN',
5
+ }
6
+
7
+ export type Locale = typeof Locale[keyof typeof Locale]
@@ -0,0 +1,7 @@
1
+ export const StorageKey = {
2
+ token: 'token',
3
+ appLang: 'appLang',
4
+ deviceToken: 'deviceToken',
5
+ } as const
6
+
7
+ export type StorageKey = typeof StorageKey[keyof typeof StorageKey]
@@ -0,0 +1,6 @@
1
+ export const ThemeType = {
2
+ LIGHT: 'light',
3
+ DARK: 'dark',
4
+ } as const
5
+
6
+ export type ThemeType = typeof ThemeType[keyof typeof ThemeType]
@@ -0,0 +1,11 @@
1
+ import { APIStatus } from './APIStatus.type'
2
+ import { Locale } from './Locale.type'
3
+ import { StorageKey } from './StorageKey.type'
4
+ import { ThemeType } from './ThemeType.type'
5
+
6
+ export {
7
+ APIStatus,
8
+ Locale,
9
+ StorageKey,
10
+ ThemeType,
11
+ }
@@ -0,0 +1,22 @@
1
+ /* eslint-disable @typescript-eslint/naming-convention */
2
+
3
+ export const BundleId = {
4
+ ios: 'com.ccctech.exampleapp',
5
+ android: 'com.ccctech.exampleapp',
6
+ }
7
+
8
+ export const PW_MAX_LENGTH = 6
9
+ export const API_ENDPOINT = 'http://experia.loyalty.loongxy.com/loyalty/api/app/'
10
+ export const API_TIMEOUT = 30000
11
+ export const PRELOAD_IMAGE_URL = [
12
+ 'https://scontent-tpe1-1.xx.fbcdn.net/v/t31.18172-8/13415650_10153570662337190_2356323871202729430_o.jpg?_nc_cat=1&ccb=1-7&_nc_sid=09cbfe&_nc_ohc=XifvSQERhSQAX-Ayhjj&_nc_ht=scontent-tpe1-1.xx&oh=00_AfBr02YqWv1kH_tJOyCuFT_nCiQjK_hhrRSPplAFRSRkFQ&oe=640A7806',
13
+ 'https://img.freepik.com/free-vector/abstract-triangular-arrow-logo-sign-symbol-vector-illustration_1284-46135.jpg?w=1380&t=st=1675833270~exp=1675833870~hmac=a080104c6c06e1bc944f31ca81660525e06378e53044ee1d993308420456e92b',
14
+ ]
15
+
16
+ export const RESEND_OTP_TIME = 30
17
+ export const POPUP_TIME = 3
18
+
19
+ export const FONT_FAMILY = {
20
+ ENG: undefined, // ArialRoundedMTBold, Arial Rounded MT Bold
21
+ CHI: undefined, // MicrosoftYaHei, Microsoft YaHei
22
+ }
@@ -0,0 +1,6 @@
1
+ import React from 'react'
2
+
3
+ import { Theme } from '@/theme/types'
4
+
5
+ export const ThemeContext = React.createContext<Theme|undefined>(undefined)
6
+ ThemeContext.displayName = 'ThemeContext'
@@ -0,0 +1,26 @@
1
+ import { useCallback, useEffect } from 'react'
2
+ import { BackHandler, Keyboard } from 'react-native'
3
+ import { useSelector } from 'react-redux'
4
+
5
+ import { hideAllLoading, hideLoading, showLoading } from '@/redux/reducers/nonPersistSlice'
6
+ import { selectLoading } from '@/redux/selectors/nonPersist'
7
+ import { useAppDispatch } from '@/redux/store'
8
+
9
+ export default () => {
10
+ const dispatch = useAppDispatch()
11
+
12
+ return {
13
+ hideLoading: () => {
14
+ Keyboard.dismiss()
15
+ dispatch(hideLoading())
16
+ },
17
+ showLoading: () => {
18
+ Keyboard.dismiss()
19
+ dispatch(showLoading())
20
+ },
21
+ hideAllLoading: () => {
22
+ Keyboard.dismiss()
23
+ dispatch(hideAllLoading())
24
+ },
25
+ }
26
+ }
@@ -0,0 +1,36 @@
1
+ import { useEffect, useState } from 'react'
2
+ import { AppState, AppStateStatus } from 'react-native'
3
+
4
+ type Setting = {
5
+ onChange?: (newState: AppStateStatus) => void
6
+ onForeground?: () => void
7
+ onBackground?: () => void
8
+ }
9
+
10
+ const isValidFunction = (func: unknown) => {
11
+ return func && typeof func === 'function'
12
+ }
13
+
14
+ const useAppState = (settings: Setting) => {
15
+ const { onBackground = () => {}, onChange = (value) => {}, onForeground = () => {} } = settings
16
+ const [appState, setAppState] = useState<AppStateStatus>(AppState.currentState)
17
+
18
+ useEffect(() => {
19
+ const handleAppStateChange = (nextAppState: AppStateStatus) => {
20
+ if (nextAppState === 'active' && appState !== 'active') {
21
+ onForeground()
22
+ } else if (appState === 'active' && nextAppState.match(/inactive|background/)) {
23
+ onBackground()
24
+ }
25
+ setAppState(nextAppState)
26
+ onChange(nextAppState)
27
+ }
28
+ const unsub = AppState.addEventListener('change', handleAppStateChange)
29
+
30
+ return () => unsub.remove()
31
+ })
32
+
33
+ return { appState }
34
+ }
35
+
36
+ export default useAppState