create-du-app 0.1.3 → 0.1.5

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 (455) hide show
  1. package/README.md +15 -9
  2. package/package.json +6 -5
  3. package/src/generate.js +15 -2
  4. package/src/index.js +15 -9
  5. package/src/prompts.js +1 -1
  6. package/templates/mobile/expo/.env.example +5 -0
  7. package/templates/mobile/expo/.eslintrc.js +7 -0
  8. package/templates/mobile/expo/.prettierrc.js +7 -0
  9. package/templates/mobile/expo/.svgrrc.js +9 -0
  10. package/templates/mobile/expo/README.md +70 -7
  11. package/templates/mobile/expo/_gitignore +20 -0
  12. package/templates/mobile/expo/_package.json +60 -1
  13. package/templates/mobile/expo/app.json +26 -0
  14. package/templates/mobile/expo/babel.config.js +21 -0
  15. package/templates/mobile/expo/index.js +7 -0
  16. package/templates/mobile/expo/metro.config.js +31 -0
  17. package/templates/mobile/expo/src/app/App.tsx +24 -0
  18. package/templates/mobile/expo/src/app/app-provider.tsx +40 -0
  19. package/templates/mobile/expo/src/app/config/translation.ts +30 -0
  20. package/templates/mobile/expo/src/app/index.ts +1 -0
  21. package/templates/mobile/expo/src/app/navigation/app-route-type.ts +27 -0
  22. package/templates/mobile/expo/src/app/navigation/bottom-tabs.tsx +34 -0
  23. package/templates/mobile/expo/src/app/navigation/index.tsx +14 -0
  24. package/templates/mobile/expo/src/app/stores/auth.store.ts +33 -0
  25. package/templates/mobile/expo/src/app/stores/common.store.ts +19 -0
  26. package/templates/mobile/expo/src/app/stores/index.ts +3 -0
  27. package/templates/mobile/expo/src/app/stores/loading.store.ts +22 -0
  28. package/templates/mobile/expo/src/assets/Images/empty-list.png +0 -0
  29. package/templates/mobile/expo/src/assets/Images/index.ts +5 -0
  30. package/templates/mobile/expo/src/assets/Images/screen-bg-gradian.png +0 -0
  31. package/templates/mobile/expo/src/assets/i18n/en.json +28 -0
  32. package/templates/mobile/expo/src/assets/i18n/fr.json +28 -0
  33. package/templates/mobile/expo/src/assets/lotties/index.ts +3 -0
  34. package/templates/mobile/expo/src/assets/lotties/loading.json +1 -0
  35. package/templates/mobile/expo/src/assets/svgs/arrow-left.svg +3 -0
  36. package/templates/mobile/expo/src/assets/svgs/arrow-right.svg +3 -0
  37. package/templates/mobile/expo/src/assets/svgs/calendar.svg +12 -0
  38. package/templates/mobile/expo/src/assets/svgs/check.svg +3 -0
  39. package/templates/mobile/expo/src/assets/svgs/close.svg +3 -0
  40. package/templates/mobile/expo/src/assets/svgs/eye-hide.svg +3 -0
  41. package/templates/mobile/expo/src/assets/svgs/eye.svg +4 -0
  42. package/templates/mobile/expo/src/assets/svgs/index.ts +29 -0
  43. package/templates/mobile/expo/src/assets/svgs/minus.svg +3 -0
  44. package/templates/mobile/expo/src/assets/svgs/plus.svg +3 -0
  45. package/templates/mobile/expo/src/assets/svgs/search.svg +3 -0
  46. package/templates/mobile/expo/src/assets/svgs/toast-error.svg +5 -0
  47. package/templates/mobile/expo/src/assets/svgs/toast-success.svg +4 -0
  48. package/templates/mobile/expo/src/core/api/endpoints.ts +8 -0
  49. package/templates/mobile/expo/src/core/api/example.api.ts +53 -0
  50. package/templates/mobile/expo/src/core/api/index.ts +4 -0
  51. package/templates/mobile/expo/src/core/components/common/index.ts +1 -0
  52. package/templates/mobile/expo/src/core/components/common/list-empty/index.ts +2 -0
  53. package/templates/mobile/expo/src/core/components/common/list-empty/list-empty.tsx +30 -0
  54. package/templates/mobile/expo/src/core/components/common/list-empty/list-empty.type.ts +5 -0
  55. package/templates/mobile/expo/src/core/components/forms/date-time-picker.modal.tsx +116 -0
  56. package/templates/mobile/expo/src/core/components/forms/hf-date-time.tsx +293 -0
  57. package/templates/mobile/expo/src/core/components/forms/hf-password-input.tsx +153 -0
  58. package/templates/mobile/expo/src/core/components/forms/hf-text-input.tsx +59 -0
  59. package/templates/mobile/expo/src/core/components/forms/hf-time-picker.tsx +116 -0
  60. package/templates/mobile/expo/src/core/components/forms/index.ts +4 -0
  61. package/templates/mobile/expo/src/core/components/index.ts +5 -0
  62. package/templates/mobile/expo/src/core/components/loading/index.ts +1 -0
  63. package/templates/mobile/expo/src/core/components/loading/loading-app/index.ts +1 -0
  64. package/templates/mobile/expo/src/core/components/loading/loading-app/loading-app.tsx +50 -0
  65. package/templates/mobile/expo/src/core/components/offline/index.ts +1 -0
  66. package/templates/mobile/expo/src/core/components/offline/offline-banner.tsx +186 -0
  67. package/templates/mobile/expo/src/core/components/screen/index.ts +1 -0
  68. package/templates/mobile/expo/src/core/components/screen/screen-container/index.ts +1 -0
  69. package/templates/mobile/expo/src/core/components/screen/screen-container/screen-container.tsx +248 -0
  70. package/templates/mobile/expo/src/core/components/splash/index.ts +1 -0
  71. package/templates/mobile/expo/src/core/components/splash/splash-overlay/index.ts +1 -0
  72. package/templates/mobile/expo/src/core/components/splash/splash-overlay/splash-overlay.tsx +93 -0
  73. package/templates/mobile/expo/src/core/components/ui/animated-list-item/animated-list-item.tsx +48 -0
  74. package/templates/mobile/expo/src/core/components/ui/animated-list-item/animated-list-item.type.ts +10 -0
  75. package/templates/mobile/expo/src/core/components/ui/animated-list-item/index.ts +2 -0
  76. package/templates/mobile/expo/src/core/components/ui/app-image/app-image.tsx +101 -0
  77. package/templates/mobile/expo/src/core/components/ui/app-image/app-image.type.ts +19 -0
  78. package/templates/mobile/expo/src/core/components/ui/app-image/index.ts +2 -0
  79. package/templates/mobile/expo/src/core/components/ui/asset-placeholder/asset-placeholder.tsx +76 -0
  80. package/templates/mobile/expo/src/core/components/ui/asset-placeholder/index.ts +1 -0
  81. package/templates/mobile/expo/src/core/components/ui/avatar-image/avatar-image.tsx +90 -0
  82. package/templates/mobile/expo/src/core/components/ui/avatar-image/index.ts +1 -0
  83. package/templates/mobile/expo/src/core/components/ui/bottom-sheet/bottom-sheet.tsx +145 -0
  84. package/templates/mobile/expo/src/core/components/ui/bottom-sheet/bottom-sheet.type.ts +10 -0
  85. package/templates/mobile/expo/src/core/components/ui/bottom-sheet/index.ts +2 -0
  86. package/templates/mobile/expo/src/core/components/ui/button/button.style.ts +146 -0
  87. package/templates/mobile/expo/src/core/components/ui/button/button.tsx +97 -0
  88. package/templates/mobile/expo/src/core/components/ui/button/button.type.ts +47 -0
  89. package/templates/mobile/expo/src/core/components/ui/button/index.ts +4 -0
  90. package/templates/mobile/expo/src/core/components/ui/checkbox/checkbox.tsx +127 -0
  91. package/templates/mobile/expo/src/core/components/ui/checkbox/checkbox.type.ts +24 -0
  92. package/templates/mobile/expo/src/core/components/ui/checkbox/index.ts +2 -0
  93. package/templates/mobile/expo/src/core/components/ui/collapsible-section/collapsible-section.tsx +141 -0
  94. package/templates/mobile/expo/src/core/components/ui/collapsible-section/collapsible-section.type.ts +10 -0
  95. package/templates/mobile/expo/src/core/components/ui/collapsible-section/index.ts +2 -0
  96. package/templates/mobile/expo/src/core/components/ui/components.registry.json +313 -0
  97. package/templates/mobile/expo/src/core/components/ui/field/field-frame.tsx +62 -0
  98. package/templates/mobile/expo/src/core/components/ui/field/field.shared.ts +31 -0
  99. package/templates/mobile/expo/src/core/components/ui/header/header.tsx +196 -0
  100. package/templates/mobile/expo/src/core/components/ui/header/header.type.ts +30 -0
  101. package/templates/mobile/expo/src/core/components/ui/header/index.ts +2 -0
  102. package/templates/mobile/expo/src/core/components/ui/icon-button/icon-button.style.ts +23 -0
  103. package/templates/mobile/expo/src/core/components/ui/icon-button/icon-button.tsx +66 -0
  104. package/templates/mobile/expo/src/core/components/ui/icon-button/icon-button.type.ts +25 -0
  105. package/templates/mobile/expo/src/core/components/ui/icon-button/index.ts +2 -0
  106. package/templates/mobile/expo/src/core/components/ui/image-slider/image-slider.tsx +107 -0
  107. package/templates/mobile/expo/src/core/components/ui/image-slider/image-slider.type.ts +10 -0
  108. package/templates/mobile/expo/src/core/components/ui/image-slider/index.ts +2 -0
  109. package/templates/mobile/expo/src/core/components/ui/index.ts +25 -0
  110. package/templates/mobile/expo/src/core/components/ui/label/index.ts +2 -0
  111. package/templates/mobile/expo/src/core/components/ui/label/label.tsx +36 -0
  112. package/templates/mobile/expo/src/core/components/ui/label/label.type.ts +12 -0
  113. package/templates/mobile/expo/src/core/components/ui/modal/index.ts +2 -0
  114. package/templates/mobile/expo/src/core/components/ui/modal/modal.tsx +62 -0
  115. package/templates/mobile/expo/src/core/components/ui/modal/modal.type.ts +11 -0
  116. package/templates/mobile/expo/src/core/components/ui/otp-input/index.ts +2 -0
  117. package/templates/mobile/expo/src/core/components/ui/otp-input/otp-input.tsx +129 -0
  118. package/templates/mobile/expo/src/core/components/ui/otp-input/otp-input.type.ts +20 -0
  119. package/templates/mobile/expo/src/core/components/ui/page-dots/index.ts +1 -0
  120. package/templates/mobile/expo/src/core/components/ui/page-dots/page-dots.tsx +60 -0
  121. package/templates/mobile/expo/src/core/components/ui/radio/index.ts +2 -0
  122. package/templates/mobile/expo/src/core/components/ui/radio/radio.tsx +121 -0
  123. package/templates/mobile/expo/src/core/components/ui/radio/radio.type.ts +20 -0
  124. package/templates/mobile/expo/src/core/components/ui/screen/index.ts +1 -0
  125. package/templates/mobile/expo/src/core/components/ui/screen/screen-gradient.tsx +33 -0
  126. package/templates/mobile/expo/src/core/components/ui/search-box/index.ts +2 -0
  127. package/templates/mobile/expo/src/core/components/ui/search-box/search-box.tsx +162 -0
  128. package/templates/mobile/expo/src/core/components/ui/search-box/search-box.type.ts +26 -0
  129. package/templates/mobile/expo/src/core/components/ui/segmented-control/index.ts +2 -0
  130. package/templates/mobile/expo/src/core/components/ui/segmented-control/segmented-control.tsx +86 -0
  131. package/templates/mobile/expo/src/core/components/ui/segmented-control/segmented-control.type.ts +22 -0
  132. package/templates/mobile/expo/src/core/components/ui/skeleton/index.ts +2 -0
  133. package/templates/mobile/expo/src/core/components/ui/skeleton/skeleton.tsx +106 -0
  134. package/templates/mobile/expo/src/core/components/ui/skeleton/skeleton.type.ts +8 -0
  135. package/templates/mobile/expo/src/core/components/ui/success-state/index.ts +1 -0
  136. package/templates/mobile/expo/src/core/components/ui/success-state/success-state.tsx +68 -0
  137. package/templates/mobile/expo/src/core/components/ui/tabs/index.ts +2 -0
  138. package/templates/mobile/expo/src/core/components/ui/tabs/tabs.tsx +273 -0
  139. package/templates/mobile/expo/src/core/components/ui/tabs/tabs.type.ts +21 -0
  140. package/templates/mobile/expo/src/core/components/ui/tag-input/index.ts +2 -0
  141. package/templates/mobile/expo/src/core/components/ui/tag-input/tag-input.tsx +146 -0
  142. package/templates/mobile/expo/src/core/components/ui/tag-input/tag-input.type.ts +22 -0
  143. package/templates/mobile/expo/src/core/components/ui/text-area/index.ts +2 -0
  144. package/templates/mobile/expo/src/core/components/ui/text-area/text-area.tsx +90 -0
  145. package/templates/mobile/expo/src/core/components/ui/text-area/text-area.type.ts +20 -0
  146. package/templates/mobile/expo/src/core/components/ui/text-field/index.ts +2 -0
  147. package/templates/mobile/expo/src/core/components/ui/text-field/text-field.tsx +116 -0
  148. package/templates/mobile/expo/src/core/components/ui/text-field/text-field.type.ts +21 -0
  149. package/templates/mobile/expo/src/core/components/ui/toggle/index.ts +2 -0
  150. package/templates/mobile/expo/src/core/components/ui/toggle/toggle.tsx +110 -0
  151. package/templates/mobile/expo/src/core/components/ui/toggle/toggle.type.ts +19 -0
  152. package/templates/mobile/expo/src/core/constants/external-urls.constant.ts +5 -0
  153. package/templates/mobile/expo/src/core/constants/hard-data.constant.ts +0 -0
  154. package/templates/mobile/expo/src/core/constants/index.ts +2 -0
  155. package/templates/mobile/expo/src/core/constants/type.constant.ts +3 -0
  156. package/templates/mobile/expo/src/core/context/index.ts +1 -0
  157. package/templates/mobile/expo/src/core/context/shared-transition-context.tsx +35 -0
  158. package/templates/mobile/expo/src/core/hook/index.ts +8 -0
  159. package/templates/mobile/expo/src/core/hook/useActiveRouteName.ts +63 -0
  160. package/templates/mobile/expo/src/core/hook/useAppNavigation.tsx +7 -0
  161. package/templates/mobile/expo/src/core/hook/useBottomInset.tsx +26 -0
  162. package/templates/mobile/expo/src/core/hook/useDebounce.tsx +16 -0
  163. package/templates/mobile/expo/src/core/hook/useEndReached.tsx +46 -0
  164. package/templates/mobile/expo/src/core/hook/useManualRefetch.ts +56 -0
  165. package/templates/mobile/expo/src/core/hook/useNetworkStatus.ts +68 -0
  166. package/templates/mobile/expo/src/core/hook/useTimeout.tsx +30 -0
  167. package/templates/mobile/expo/src/core/index.ts +7 -0
  168. package/templates/mobile/expo/src/core/services/api.service.ts +230 -0
  169. package/templates/mobile/expo/src/core/services/device-id.service.ts +37 -0
  170. package/templates/mobile/expo/src/core/services/index.ts +3 -0
  171. package/templates/mobile/expo/src/core/services/session-end.bridge.ts +26 -0
  172. package/templates/mobile/expo/src/core/theme/dark.theme.ts +10 -0
  173. package/templates/mobile/expo/src/core/theme/index.ts +5 -0
  174. package/templates/mobile/expo/src/core/theme/light.theme.ts +44 -0
  175. package/templates/mobile/expo/src/core/theme/theme-context.tsx +82 -0
  176. package/templates/mobile/expo/src/core/theme/theme.types.ts +26 -0
  177. package/templates/mobile/expo/src/core/theme/use-themed-styles.ts +25 -0
  178. package/templates/mobile/expo/src/core/utils/color.util.tsx +198 -0
  179. package/templates/mobile/expo/src/core/utils/date.util.ts +97 -0
  180. package/templates/mobile/expo/src/core/utils/device-locale.util.ts +24 -0
  181. package/templates/mobile/expo/src/core/utils/emitter/index.ts +161 -0
  182. package/templates/mobile/expo/src/core/utils/emitter/type.ts +40 -0
  183. package/templates/mobile/expo/src/core/utils/enum.util.tsx +15 -0
  184. package/templates/mobile/expo/src/core/utils/font.util.tsx +42 -0
  185. package/templates/mobile/expo/src/core/utils/func.util.ts +48 -0
  186. package/templates/mobile/expo/src/core/utils/greeting.util.ts +20 -0
  187. package/templates/mobile/expo/src/core/utils/image-format.util.ts +117 -0
  188. package/templates/mobile/expo/src/core/utils/image-picker.util.ts +63 -0
  189. package/templates/mobile/expo/src/core/utils/index.ts +18 -0
  190. package/templates/mobile/expo/src/core/utils/linking.util.ts +16 -0
  191. package/templates/mobile/expo/src/core/utils/navigation.util.tsx +100 -0
  192. package/templates/mobile/expo/src/core/utils/number-format.ts +28 -0
  193. package/templates/mobile/expo/src/core/utils/query-client.util.ts +35 -0
  194. package/templates/mobile/expo/src/core/utils/query-persister.util.ts +31 -0
  195. package/templates/mobile/expo/src/core/utils/schema.util.tsx +2713 -0
  196. package/templates/mobile/expo/src/core/utils/size.util.tsx +74 -0
  197. package/templates/mobile/expo/src/core/utils/storage.util.tsx +53 -0
  198. package/templates/mobile/expo/src/core/utils/toast.util.tsx +151 -0
  199. package/templates/mobile/expo/src/core/utils/translator.util.tsx +23 -0
  200. package/templates/mobile/expo/src/core/utils/typography.util.tsx +69 -0
  201. package/templates/mobile/expo/src/core/utils/validate.util.tsx +13 -0
  202. package/templates/mobile/expo/src/declarations.d.ts +54 -0
  203. package/templates/mobile/expo/src/modules/home/home.screen.tsx +110 -0
  204. package/templates/mobile/expo/src/modules/profile/profile.screen.tsx +29 -0
  205. package/templates/mobile/expo/src/scripts/link-fonts.js +60 -0
  206. package/templates/mobile/expo/src/scripts/sync-images.js +56 -0
  207. package/templates/mobile/expo/src/scripts/sync-svgs.js +50 -0
  208. package/templates/mobile/expo/src/types/models.d.ts +24 -0
  209. package/templates/mobile/expo/tsconfig.json +19 -0
  210. package/templates/mobile/rn/.bundle/config +2 -0
  211. package/templates/mobile/rn/.env.example +5 -0
  212. package/templates/mobile/rn/.eslintrc.js +7 -0
  213. package/templates/mobile/rn/.prettierrc.js +7 -0
  214. package/templates/mobile/rn/.svgrrc.js +9 -0
  215. package/templates/mobile/rn/.watchmanconfig +1 -0
  216. package/templates/mobile/rn/Gemfile +17 -0
  217. package/templates/mobile/rn/README.md +72 -7
  218. package/templates/mobile/rn/_gitignore +24 -0
  219. package/templates/mobile/rn/_package.json +69 -1
  220. package/templates/mobile/rn/android/app/build.gradle +126 -0
  221. package/templates/mobile/rn/android/app/debug.keystore +0 -0
  222. package/templates/mobile/rn/android/app/proguard-rules.pro +10 -0
  223. package/templates/mobile/rn/android/app/src/main/AndroidManifest.xml +27 -0
  224. package/templates/mobile/rn/android/app/src/main/java/com/dumobile/MainActivity.kt +22 -0
  225. package/templates/mobile/rn/android/app/src/main/java/com/dumobile/MainApplication.kt +27 -0
  226. package/templates/mobile/rn/android/app/src/main/res/drawable/rn_edit_text_material.xml +37 -0
  227. package/templates/mobile/rn/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
  228. package/templates/mobile/rn/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
  229. package/templates/mobile/rn/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
  230. package/templates/mobile/rn/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
  231. package/templates/mobile/rn/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
  232. package/templates/mobile/rn/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
  233. package/templates/mobile/rn/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  234. package/templates/mobile/rn/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
  235. package/templates/mobile/rn/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
  236. package/templates/mobile/rn/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
  237. package/templates/mobile/rn/android/app/src/main/res/values/strings.xml +3 -0
  238. package/templates/mobile/rn/android/app/src/main/res/values/styles.xml +9 -0
  239. package/templates/mobile/rn/android/build.gradle +21 -0
  240. package/templates/mobile/rn/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  241. package/templates/mobile/rn/android/gradle/wrapper/gradle-wrapper.properties +7 -0
  242. package/templates/mobile/rn/android/gradle.properties +44 -0
  243. package/templates/mobile/rn/android/gradlew +248 -0
  244. package/templates/mobile/rn/android/gradlew.bat +98 -0
  245. package/templates/mobile/rn/android/settings.gradle +21 -0
  246. package/templates/mobile/rn/app.json +4 -0
  247. package/templates/mobile/rn/babel.config.js +18 -0
  248. package/templates/mobile/rn/index.js +10 -0
  249. package/templates/mobile/rn/ios/.xcode.env +11 -0
  250. package/templates/mobile/rn/ios/DuMobile/AppDelegate.swift +48 -0
  251. package/templates/mobile/rn/ios/DuMobile/Images.xcassets/AppIcon.appiconset/Contents.json +53 -0
  252. package/templates/mobile/rn/ios/DuMobile/Images.xcassets/Contents.json +6 -0
  253. package/templates/mobile/rn/ios/DuMobile/Info.plist +59 -0
  254. package/templates/mobile/rn/ios/DuMobile/LaunchScreen.storyboard +47 -0
  255. package/templates/mobile/rn/ios/DuMobile/PrivacyInfo.xcprivacy +37 -0
  256. package/templates/mobile/rn/ios/DuMobile.xcodeproj/project.pbxproj +475 -0
  257. package/templates/mobile/rn/ios/DuMobile.xcodeproj/xcshareddata/xcschemes/DuMobile.xcscheme +88 -0
  258. package/templates/mobile/rn/ios/Podfile +34 -0
  259. package/templates/mobile/rn/metro.config.js +33 -0
  260. package/templates/mobile/rn/src/app/App.tsx +24 -0
  261. package/templates/mobile/rn/src/app/app-provider.tsx +41 -0
  262. package/templates/mobile/rn/src/app/config/translation.ts +29 -0
  263. package/templates/mobile/rn/src/app/index.ts +1 -0
  264. package/templates/mobile/rn/src/app/navigation/app-route-type.ts +27 -0
  265. package/templates/mobile/rn/src/app/navigation/bottom-tabs.tsx +34 -0
  266. package/templates/mobile/rn/src/app/navigation/index.tsx +14 -0
  267. package/templates/mobile/rn/src/app/stores/auth.store.ts +33 -0
  268. package/templates/mobile/rn/src/app/stores/common.store.ts +19 -0
  269. package/templates/mobile/rn/src/app/stores/index.ts +3 -0
  270. package/templates/mobile/rn/src/app/stores/loading.store.ts +22 -0
  271. package/templates/mobile/rn/src/assets/Images/empty-list.png +0 -0
  272. package/templates/mobile/rn/src/assets/Images/index.ts +5 -0
  273. package/templates/mobile/rn/src/assets/Images/screen-bg-gradian.png +0 -0
  274. package/templates/mobile/rn/src/assets/i18n/en.json +22 -0
  275. package/templates/mobile/rn/src/assets/i18n/fr.json +22 -0
  276. package/templates/mobile/rn/src/assets/lotties/index.ts +3 -0
  277. package/templates/mobile/rn/src/assets/lotties/loading.json +1 -0
  278. package/templates/mobile/rn/src/assets/svgs/arrow-left.svg +3 -0
  279. package/templates/mobile/rn/src/assets/svgs/arrow-right.svg +3 -0
  280. package/templates/mobile/rn/src/assets/svgs/calendar.svg +12 -0
  281. package/templates/mobile/rn/src/assets/svgs/check.svg +3 -0
  282. package/templates/mobile/rn/src/assets/svgs/close.svg +3 -0
  283. package/templates/mobile/rn/src/assets/svgs/eye-hide.svg +3 -0
  284. package/templates/mobile/rn/src/assets/svgs/eye.svg +4 -0
  285. package/templates/mobile/rn/src/assets/svgs/index.ts +29 -0
  286. package/templates/mobile/rn/src/assets/svgs/minus.svg +3 -0
  287. package/templates/mobile/rn/src/assets/svgs/plus.svg +3 -0
  288. package/templates/mobile/rn/src/assets/svgs/search.svg +3 -0
  289. package/templates/mobile/rn/src/assets/svgs/toast-error.svg +5 -0
  290. package/templates/mobile/rn/src/assets/svgs/toast-success.svg +4 -0
  291. package/templates/mobile/rn/src/core/api/endpoints.ts +8 -0
  292. package/templates/mobile/rn/src/core/api/example.api.ts +53 -0
  293. package/templates/mobile/rn/src/core/api/index.ts +4 -0
  294. package/templates/mobile/rn/src/core/components/common/index.ts +1 -0
  295. package/templates/mobile/rn/src/core/components/common/list-empty/index.ts +2 -0
  296. package/templates/mobile/rn/src/core/components/common/list-empty/list-empty.tsx +30 -0
  297. package/templates/mobile/rn/src/core/components/common/list-empty/list-empty.type.ts +5 -0
  298. package/templates/mobile/rn/src/core/components/forms/hf-date-time.tsx +301 -0
  299. package/templates/mobile/rn/src/core/components/forms/hf-password-input.tsx +153 -0
  300. package/templates/mobile/rn/src/core/components/forms/hf-text-input.tsx +59 -0
  301. package/templates/mobile/rn/src/core/components/forms/hf-time-picker.tsx +117 -0
  302. package/templates/mobile/rn/src/core/components/forms/index.ts +4 -0
  303. package/templates/mobile/rn/src/core/components/index.ts +5 -0
  304. package/templates/mobile/rn/src/core/components/loading/index.ts +1 -0
  305. package/templates/mobile/rn/src/core/components/loading/loading-app/index.ts +1 -0
  306. package/templates/mobile/rn/src/core/components/loading/loading-app/loading-app.tsx +50 -0
  307. package/templates/mobile/rn/src/core/components/offline/index.ts +1 -0
  308. package/templates/mobile/rn/src/core/components/offline/offline-banner.tsx +186 -0
  309. package/templates/mobile/rn/src/core/components/screen/index.ts +1 -0
  310. package/templates/mobile/rn/src/core/components/screen/screen-container/index.ts +1 -0
  311. package/templates/mobile/rn/src/core/components/screen/screen-container/screen-container.tsx +252 -0
  312. package/templates/mobile/rn/src/core/components/splash/index.ts +1 -0
  313. package/templates/mobile/rn/src/core/components/splash/splash-overlay/index.ts +1 -0
  314. package/templates/mobile/rn/src/core/components/splash/splash-overlay/splash-overlay.tsx +93 -0
  315. package/templates/mobile/rn/src/core/components/ui/animated-list-item/animated-list-item.tsx +48 -0
  316. package/templates/mobile/rn/src/core/components/ui/animated-list-item/animated-list-item.type.ts +10 -0
  317. package/templates/mobile/rn/src/core/components/ui/animated-list-item/index.ts +2 -0
  318. package/templates/mobile/rn/src/core/components/ui/app-image/app-image.tsx +104 -0
  319. package/templates/mobile/rn/src/core/components/ui/app-image/app-image.type.ts +19 -0
  320. package/templates/mobile/rn/src/core/components/ui/app-image/index.ts +2 -0
  321. package/templates/mobile/rn/src/core/components/ui/asset-placeholder/asset-placeholder.tsx +76 -0
  322. package/templates/mobile/rn/src/core/components/ui/asset-placeholder/index.ts +1 -0
  323. package/templates/mobile/rn/src/core/components/ui/avatar-image/avatar-image.tsx +90 -0
  324. package/templates/mobile/rn/src/core/components/ui/avatar-image/index.ts +1 -0
  325. package/templates/mobile/rn/src/core/components/ui/bottom-sheet/bottom-sheet.tsx +145 -0
  326. package/templates/mobile/rn/src/core/components/ui/bottom-sheet/bottom-sheet.type.ts +10 -0
  327. package/templates/mobile/rn/src/core/components/ui/bottom-sheet/index.ts +2 -0
  328. package/templates/mobile/rn/src/core/components/ui/button/button.style.ts +146 -0
  329. package/templates/mobile/rn/src/core/components/ui/button/button.tsx +97 -0
  330. package/templates/mobile/rn/src/core/components/ui/button/button.type.ts +47 -0
  331. package/templates/mobile/rn/src/core/components/ui/button/index.ts +4 -0
  332. package/templates/mobile/rn/src/core/components/ui/checkbox/checkbox.tsx +127 -0
  333. package/templates/mobile/rn/src/core/components/ui/checkbox/checkbox.type.ts +24 -0
  334. package/templates/mobile/rn/src/core/components/ui/checkbox/index.ts +2 -0
  335. package/templates/mobile/rn/src/core/components/ui/collapsible-section/collapsible-section.tsx +141 -0
  336. package/templates/mobile/rn/src/core/components/ui/collapsible-section/collapsible-section.type.ts +10 -0
  337. package/templates/mobile/rn/src/core/components/ui/collapsible-section/index.ts +2 -0
  338. package/templates/mobile/rn/src/core/components/ui/components.registry.json +313 -0
  339. package/templates/mobile/rn/src/core/components/ui/field/field-frame.tsx +62 -0
  340. package/templates/mobile/rn/src/core/components/ui/field/field.shared.ts +31 -0
  341. package/templates/mobile/rn/src/core/components/ui/header/header.tsx +196 -0
  342. package/templates/mobile/rn/src/core/components/ui/header/header.type.ts +30 -0
  343. package/templates/mobile/rn/src/core/components/ui/header/index.ts +2 -0
  344. package/templates/mobile/rn/src/core/components/ui/icon-button/icon-button.style.ts +23 -0
  345. package/templates/mobile/rn/src/core/components/ui/icon-button/icon-button.tsx +66 -0
  346. package/templates/mobile/rn/src/core/components/ui/icon-button/icon-button.type.ts +25 -0
  347. package/templates/mobile/rn/src/core/components/ui/icon-button/index.ts +2 -0
  348. package/templates/mobile/rn/src/core/components/ui/image-slider/image-slider.tsx +107 -0
  349. package/templates/mobile/rn/src/core/components/ui/image-slider/image-slider.type.ts +10 -0
  350. package/templates/mobile/rn/src/core/components/ui/image-slider/index.ts +2 -0
  351. package/templates/mobile/rn/src/core/components/ui/index.ts +25 -0
  352. package/templates/mobile/rn/src/core/components/ui/label/index.ts +2 -0
  353. package/templates/mobile/rn/src/core/components/ui/label/label.tsx +36 -0
  354. package/templates/mobile/rn/src/core/components/ui/label/label.type.ts +12 -0
  355. package/templates/mobile/rn/src/core/components/ui/modal/index.ts +2 -0
  356. package/templates/mobile/rn/src/core/components/ui/modal/modal.tsx +62 -0
  357. package/templates/mobile/rn/src/core/components/ui/modal/modal.type.ts +11 -0
  358. package/templates/mobile/rn/src/core/components/ui/otp-input/index.ts +2 -0
  359. package/templates/mobile/rn/src/core/components/ui/otp-input/otp-input.tsx +129 -0
  360. package/templates/mobile/rn/src/core/components/ui/otp-input/otp-input.type.ts +20 -0
  361. package/templates/mobile/rn/src/core/components/ui/page-dots/index.ts +1 -0
  362. package/templates/mobile/rn/src/core/components/ui/page-dots/page-dots.tsx +60 -0
  363. package/templates/mobile/rn/src/core/components/ui/radio/index.ts +2 -0
  364. package/templates/mobile/rn/src/core/components/ui/radio/radio.tsx +121 -0
  365. package/templates/mobile/rn/src/core/components/ui/radio/radio.type.ts +20 -0
  366. package/templates/mobile/rn/src/core/components/ui/screen/index.ts +1 -0
  367. package/templates/mobile/rn/src/core/components/ui/screen/screen-gradient.tsx +33 -0
  368. package/templates/mobile/rn/src/core/components/ui/search-box/index.ts +2 -0
  369. package/templates/mobile/rn/src/core/components/ui/search-box/search-box.tsx +162 -0
  370. package/templates/mobile/rn/src/core/components/ui/search-box/search-box.type.ts +26 -0
  371. package/templates/mobile/rn/src/core/components/ui/segmented-control/index.ts +2 -0
  372. package/templates/mobile/rn/src/core/components/ui/segmented-control/segmented-control.tsx +86 -0
  373. package/templates/mobile/rn/src/core/components/ui/segmented-control/segmented-control.type.ts +22 -0
  374. package/templates/mobile/rn/src/core/components/ui/skeleton/index.ts +2 -0
  375. package/templates/mobile/rn/src/core/components/ui/skeleton/skeleton.tsx +106 -0
  376. package/templates/mobile/rn/src/core/components/ui/skeleton/skeleton.type.ts +8 -0
  377. package/templates/mobile/rn/src/core/components/ui/success-state/index.ts +1 -0
  378. package/templates/mobile/rn/src/core/components/ui/success-state/success-state.tsx +68 -0
  379. package/templates/mobile/rn/src/core/components/ui/tabs/index.ts +2 -0
  380. package/templates/mobile/rn/src/core/components/ui/tabs/tabs.tsx +273 -0
  381. package/templates/mobile/rn/src/core/components/ui/tabs/tabs.type.ts +21 -0
  382. package/templates/mobile/rn/src/core/components/ui/tag-input/index.ts +2 -0
  383. package/templates/mobile/rn/src/core/components/ui/tag-input/tag-input.tsx +146 -0
  384. package/templates/mobile/rn/src/core/components/ui/tag-input/tag-input.type.ts +22 -0
  385. package/templates/mobile/rn/src/core/components/ui/text-area/index.ts +2 -0
  386. package/templates/mobile/rn/src/core/components/ui/text-area/text-area.tsx +90 -0
  387. package/templates/mobile/rn/src/core/components/ui/text-area/text-area.type.ts +20 -0
  388. package/templates/mobile/rn/src/core/components/ui/text-field/index.ts +2 -0
  389. package/templates/mobile/rn/src/core/components/ui/text-field/text-field.tsx +116 -0
  390. package/templates/mobile/rn/src/core/components/ui/text-field/text-field.type.ts +21 -0
  391. package/templates/mobile/rn/src/core/components/ui/toggle/index.ts +2 -0
  392. package/templates/mobile/rn/src/core/components/ui/toggle/toggle.tsx +110 -0
  393. package/templates/mobile/rn/src/core/components/ui/toggle/toggle.type.ts +19 -0
  394. package/templates/mobile/rn/src/core/constants/external-urls.constant.ts +5 -0
  395. package/templates/mobile/rn/src/core/constants/hard-data.constant.ts +0 -0
  396. package/templates/mobile/rn/src/core/constants/index.ts +2 -0
  397. package/templates/mobile/rn/src/core/constants/type.constant.ts +3 -0
  398. package/templates/mobile/rn/src/core/context/index.ts +1 -0
  399. package/templates/mobile/rn/src/core/context/shared-transition-context.tsx +35 -0
  400. package/templates/mobile/rn/src/core/hook/index.ts +8 -0
  401. package/templates/mobile/rn/src/core/hook/useActiveRouteName.ts +63 -0
  402. package/templates/mobile/rn/src/core/hook/useAppNavigation.tsx +7 -0
  403. package/templates/mobile/rn/src/core/hook/useBottomInset.tsx +26 -0
  404. package/templates/mobile/rn/src/core/hook/useDebounce.tsx +16 -0
  405. package/templates/mobile/rn/src/core/hook/useEndReached.tsx +46 -0
  406. package/templates/mobile/rn/src/core/hook/useManualRefetch.ts +56 -0
  407. package/templates/mobile/rn/src/core/hook/useNetworkStatus.ts +68 -0
  408. package/templates/mobile/rn/src/core/hook/useTimeout.tsx +30 -0
  409. package/templates/mobile/rn/src/core/index.ts +7 -0
  410. package/templates/mobile/rn/src/core/services/api.service.ts +230 -0
  411. package/templates/mobile/rn/src/core/services/device-id.service.ts +23 -0
  412. package/templates/mobile/rn/src/core/services/index.ts +3 -0
  413. package/templates/mobile/rn/src/core/services/session-end.bridge.ts +26 -0
  414. package/templates/mobile/rn/src/core/theme/dark.theme.ts +10 -0
  415. package/templates/mobile/rn/src/core/theme/index.ts +5 -0
  416. package/templates/mobile/rn/src/core/theme/light.theme.ts +44 -0
  417. package/templates/mobile/rn/src/core/theme/theme-context.tsx +82 -0
  418. package/templates/mobile/rn/src/core/theme/theme.types.ts +26 -0
  419. package/templates/mobile/rn/src/core/theme/use-themed-styles.ts +25 -0
  420. package/templates/mobile/rn/src/core/utils/color.util.tsx +198 -0
  421. package/templates/mobile/rn/src/core/utils/date.util.ts +97 -0
  422. package/templates/mobile/rn/src/core/utils/device-locale.util.ts +22 -0
  423. package/templates/mobile/rn/src/core/utils/emitter/index.ts +161 -0
  424. package/templates/mobile/rn/src/core/utils/emitter/type.ts +40 -0
  425. package/templates/mobile/rn/src/core/utils/enum.util.tsx +15 -0
  426. package/templates/mobile/rn/src/core/utils/font.util.tsx +42 -0
  427. package/templates/mobile/rn/src/core/utils/func.util.ts +48 -0
  428. package/templates/mobile/rn/src/core/utils/greeting.util.ts +20 -0
  429. package/templates/mobile/rn/src/core/utils/image-format.util.ts +117 -0
  430. package/templates/mobile/rn/src/core/utils/image-picker.util.ts +84 -0
  431. package/templates/mobile/rn/src/core/utils/index.ts +18 -0
  432. package/templates/mobile/rn/src/core/utils/linking.util.ts +16 -0
  433. package/templates/mobile/rn/src/core/utils/navigation.util.tsx +100 -0
  434. package/templates/mobile/rn/src/core/utils/number-format.ts +28 -0
  435. package/templates/mobile/rn/src/core/utils/query-client.util.ts +35 -0
  436. package/templates/mobile/rn/src/core/utils/query-persister.util.ts +36 -0
  437. package/templates/mobile/rn/src/core/utils/schema.util.tsx +2713 -0
  438. package/templates/mobile/rn/src/core/utils/size.util.tsx +74 -0
  439. package/templates/mobile/rn/src/core/utils/storage.util.tsx +53 -0
  440. package/templates/mobile/rn/src/core/utils/toast.util.tsx +151 -0
  441. package/templates/mobile/rn/src/core/utils/translator.util.tsx +23 -0
  442. package/templates/mobile/rn/src/core/utils/typography.util.tsx +69 -0
  443. package/templates/mobile/rn/src/core/utils/validate.util.tsx +13 -0
  444. package/templates/mobile/rn/src/declarations.d.ts +54 -0
  445. package/templates/mobile/rn/src/modules/home/home.screen.tsx +67 -0
  446. package/templates/mobile/rn/src/modules/profile/profile.screen.tsx +29 -0
  447. package/templates/mobile/rn/src/scripts/link-fonts.js +60 -0
  448. package/templates/mobile/rn/src/scripts/sync-images.js +56 -0
  449. package/templates/mobile/rn/src/scripts/sync-svgs.js +50 -0
  450. package/templates/mobile/rn/src/types/models.d.ts +24 -0
  451. package/templates/mobile/rn/tsconfig.json +21 -0
  452. package/templates/shared/src/api-endpoints.ts +8 -0
  453. package/templates/shared/src/enums.ts +34 -0
  454. package/templates/shared/src/external-urls.ts +5 -0
  455. package/templates/shared/src/index.ts +6 -3
@@ -0,0 +1,117 @@
1
+ import React, { useState } from 'react';
2
+ import { useController, useFormContext } from 'react-hook-form';
3
+ import {
4
+ StyleProp,
5
+ StyleSheet,
6
+ TouchableOpacity,
7
+ ViewStyle,
8
+ } from 'react-native';
9
+ import DatePicker from 'react-native-date-picker';
10
+ import { Font, fontSize, horizontalScale, verticalScale, Radius } from '../../utils';
11
+ import { ThemeColors, useThemedStyles } from '@src/core/theme';
12
+ import { Label } from '../ui';
13
+
14
+ type Props = {
15
+ containerStyle?: StyleProp<ViewStyle>;
16
+ name: string;
17
+ placeholder?: string;
18
+ onTimeSelected?: (time: string) => void;
19
+ };
20
+
21
+ const formatTime = (date: Date) => {
22
+ const hours = `0${date.getHours()}`.slice(-2);
23
+ const minutes = `0${date.getMinutes()}`.slice(-2);
24
+ return `${hours}:${minutes}`;
25
+ };
26
+
27
+ const parseTime = (timeString?: string) => {
28
+ if (!timeString) {
29
+ return new Date();
30
+ }
31
+ const [hours, minutes] = timeString.split(':').map(Number);
32
+ const date = new Date();
33
+ date.setHours(hours || 0);
34
+ date.setMinutes(minutes || 0);
35
+ return date;
36
+ };
37
+
38
+ const HFTimePicker = (props: Props) => {
39
+ const {
40
+ containerStyle = {},
41
+ name,
42
+ placeholder = 'HH:MM',
43
+ onTimeSelected,
44
+ } = props;
45
+
46
+ const formContext = useFormContext();
47
+ const { field } = useController({
48
+ name,
49
+ control: formContext.control,
50
+ defaultValue: '',
51
+ });
52
+
53
+ const styles = useThemedStyles(makeStyles);
54
+
55
+ const [open, setOpen] = useState(false);
56
+ const [time, setTime] = useState<Date>(parseTime(field.value));
57
+
58
+ const handleOpen = () => {
59
+ setTime(parseTime(field.value));
60
+ setOpen(true);
61
+ };
62
+
63
+ const handleConfirm = (selectedTime: Date) => {
64
+ setOpen(false);
65
+ setTime(selectedTime);
66
+ const formatted = formatTime(selectedTime);
67
+ field.onChange(formatted);
68
+ onTimeSelected?.(formatted);
69
+ };
70
+
71
+ return (
72
+ <>
73
+ <TouchableOpacity
74
+ activeOpacity={0.7}
75
+ onPress={handleOpen}
76
+ style={[styles.container, containerStyle]}
77
+ >
78
+ <Label
79
+ style={[styles.text, !field.value && styles.placeholder]}
80
+ value={field.value || placeholder}
81
+ />
82
+ </TouchableOpacity>
83
+ <DatePicker
84
+ modal
85
+ mode="time"
86
+ open={open}
87
+ date={time}
88
+ onConfirm={handleConfirm}
89
+ onCancel={() => setOpen(false)}
90
+ />
91
+ </>
92
+ );
93
+ };
94
+
95
+ export default HFTimePicker;
96
+
97
+ const makeStyles = (c: ThemeColors) =>
98
+ StyleSheet.create({
99
+ container: {
100
+ alignItems: 'center',
101
+ borderRadius: Radius.radius_lg,
102
+ backgroundColor: c.bg_page_normal_faded,
103
+ height: verticalScale(44),
104
+ paddingHorizontal: horizontalScale(16),
105
+ justifyContent: 'center',
106
+ borderWidth: 0.5,
107
+ borderColor: 'rgba(3, 7, 18, 0.2)',
108
+ },
109
+ text: {
110
+ fontSize: fontSize(14),
111
+ color: c.text_primary,
112
+ fontFamily: Font.rethinkSansRegular,
113
+ },
114
+ placeholder: {
115
+ color: c.sub_text,
116
+ },
117
+ });
@@ -0,0 +1,4 @@
1
+ export { default as HFPasswordInput } from './hf-password-input';
2
+ export { default as HFTextInput } from './hf-text-input';
3
+ export { default as HFDateTime } from './hf-date-time';
4
+ export { default as HFTimePicker } from './hf-time-picker';
@@ -0,0 +1,5 @@
1
+ export * from './ui';
2
+ export * from './forms';
3
+ export * from './loading';
4
+ export * from './common';
5
+ export * from './splash';
@@ -0,0 +1 @@
1
+ export * from './loading-app';
@@ -0,0 +1 @@
1
+ export { default as LoadingApp } from './loading-app';
@@ -0,0 +1,50 @@
1
+ import { useLoadingStore } from '@src/app/stores';
2
+ import { LottieLoading } from '@src/assets/lotties';
3
+ import { ThemeColors, useThemedStyles } from '@src/core/theme';
4
+ import { horizontalScale } from '@src/core/utils';
5
+ import LottieView from 'lottie-react-native';
6
+ import React from 'react';
7
+ import { StyleSheet, View } from 'react-native';
8
+
9
+ const LoadingApp = () => {
10
+ const styles = useThemedStyles(makeStyles);
11
+ const isLoading = useLoadingStore(state => state.isLoading);
12
+
13
+ return isLoading ? (
14
+ <View style={styles.container}>
15
+ <View style={styles.loading}>
16
+ <LottieView source={LottieLoading} autoPlay loop style={styles.lottie} />
17
+ </View>
18
+ </View>
19
+ ) : null;
20
+ };
21
+
22
+ const makeStyles = (c: ThemeColors) =>
23
+ StyleSheet.create({
24
+ container: {
25
+ ...StyleSheet.absoluteFill,
26
+ justifyContent: 'center',
27
+ alignItems: 'center',
28
+ backgroundColor: 'rgba(0, 0, 0, 0.5)',
29
+ },
30
+ content: {
31
+ justifyContent: 'center',
32
+ alignItems: 'center',
33
+ height: '100%',
34
+ width: '100%',
35
+ },
36
+ loading: {
37
+ width: 65,
38
+ height: 65,
39
+ borderRadius: horizontalScale(12),
40
+ backgroundColor: c.bg_page_normal_faded,
41
+ justifyContent: 'center',
42
+ alignItems: 'center',
43
+ },
44
+ lottie: {
45
+ width: 55,
46
+ height: 55,
47
+ },
48
+ });
49
+
50
+ export default LoadingApp;
@@ -0,0 +1 @@
1
+ export * from './offline-banner';
@@ -0,0 +1,186 @@
1
+ import React, { useEffect, useRef, useState } from 'react';
2
+ import { StyleSheet, View } from 'react-native';
3
+ import Animated, {
4
+ runOnJS,
5
+ useAnimatedStyle,
6
+ useSharedValue,
7
+ withTiming,
8
+ } from 'react-native-reanimated';
9
+ import { useSafeAreaInsets } from 'react-native-safe-area-context';
10
+ import { useTranslation } from 'react-i18next';
11
+ import { useActiveRouteName, useNetworkStatus } from '@src/core/hook';
12
+ import { Font, fontSize, Spacing, verticalScale } from '@src/core/utils';
13
+ import { Screen } from '@src/app/navigation/app-route-type';
14
+ import { ThemeColors, useThemedStyles } from '@src/core/theme';
15
+ import { Label } from '@src/core';
16
+
17
+ /** How long the green "back online" confirmation stays before sliding away. */
18
+ const BACK_ONLINE_DISMISS_MS = 2000;
19
+ const SLIDE_DURATION_MS = 250;
20
+ const BANNER_HEIGHT = verticalScale(34);
21
+
22
+ type BannerMode = 'offline' | 'backOnline';
23
+
24
+ /**
25
+ * A thin status banner that slides down from under the status bar when the
26
+ * device loses internet, and — once reconnected — briefly flips to a green
27
+ * "back online" confirmation before sliding away. It never blocks touches: the
28
+ * app keeps showing cached content underneath (offline-first), so this is a
29
+ * passive status hint, not a gate.
30
+ *
31
+ * Mount once at the app shell, above the navigator, so a single banner covers
32
+ * every tab/screen. Replaces the old full-screen OfflineGate overlay.
33
+ */
34
+ export const OfflineBanner = () => {
35
+ const { t } = useTranslation();
36
+ const { top } = useSafeAreaInsets();
37
+ const styles = useThemedStyles(makeStyles);
38
+ const { isOffline } = useNetworkStatus();
39
+ const activeRoute = useActiveRouteName();
40
+
41
+ // Some routes are offline-by-design and the banner is noise there:
42
+ // • Library tab — lists saved/downloaded audio that plays without a network.
43
+ // • Full-screen player — once a track is loaded it plays from cache/buffer,
44
+ // and the banner would overlap the immersive player chrome.
45
+ // Treat the device as connected while either is focused so the banner never
46
+ // appears (and the green "back online" confirmation is skipped too).
47
+ const bannerSuppressedRoutes: (string | undefined)[] = [
48
+ Screen.LibraryMain,
49
+ Screen.PlayerFull,
50
+ ];
51
+ const effectiveOffline =
52
+ isOffline && !bannerSuppressedRoutes.includes(activeRoute);
53
+
54
+ // What the banner currently shows, and whether it's on screen at all.
55
+ const [mode, setMode] = useState<BannerMode>('offline');
56
+ const [visible, setVisible] = useState(false);
57
+
58
+ // Tracks whether we were offline, so a transition offline→online can show
59
+ // the "back online" confirmation (but not on a fresh launch that was
60
+ // already online).
61
+ const wasOffline = useRef(false);
62
+ const dismissTimer = useRef<ReturnType<typeof setTimeout>>(undefined);
63
+
64
+ const translateY = useSharedValue(-(BANNER_HEIGHT + top));
65
+ const slideOut = () =>
66
+ (translateY.value = withTiming(
67
+ -(BANNER_HEIGHT + top),
68
+ { duration: SLIDE_DURATION_MS },
69
+ finished => finished && runOnJS(setVisible)(false),
70
+ ));
71
+
72
+ useEffect(() => {
73
+ if (dismissTimer.current) clearTimeout(dismissTimer.current);
74
+
75
+ if (effectiveOffline) {
76
+ wasOffline.current = true;
77
+ setMode('offline');
78
+ setVisible(true);
79
+ translateY.value = withTiming(0, { duration: SLIDE_DURATION_MS });
80
+ return;
81
+ }
82
+
83
+ // We're not showing the offline state. Only celebrate "back online" when
84
+ // the internet genuinely returned (we were offline AND are now truly
85
+ // online). If instead the banner was suppressed because the user moved
86
+ // to the Library while still offline, slide it away silently — no green
87
+ // confirmation, and keep `wasOffline` so leaving the Library re-shows it.
88
+ if (wasOffline.current && !isOffline) {
89
+ wasOffline.current = false;
90
+ setMode('backOnline');
91
+ setVisible(true);
92
+ translateY.value = withTiming(0, { duration: SLIDE_DURATION_MS });
93
+ dismissTimer.current = setTimeout(slideOut, BACK_ONLINE_DISMISS_MS);
94
+ } else if (wasOffline.current) {
95
+ // Still offline, just hidden on the Library tab — retract quietly.
96
+ slideOut();
97
+ }
98
+
99
+ return () => {
100
+ if (dismissTimer.current) clearTimeout(dismissTimer.current);
101
+ };
102
+ // translateY/slideOut are stable refs; network state + active tab drive this.
103
+ // eslint-disable-next-line react-hooks/exhaustive-deps
104
+ }, [effectiveOffline, isOffline, top]);
105
+
106
+ const animatedStyle = useAnimatedStyle(() => ({
107
+ transform: [{ translateY: translateY.value }],
108
+ }));
109
+
110
+ if (!visible) return null;
111
+
112
+ const isBackOnline = mode === 'backOnline';
113
+ return (
114
+ <Animated.View
115
+ pointerEvents="none"
116
+ style={[
117
+ styles.container,
118
+ {
119
+ paddingTop: top,
120
+ // Paint the status-bar inset the same colour as the bar so
121
+ // the banner reads as one solid strip under the notch.
122
+ backgroundColor: isBackOnline
123
+ ? styles.barOnline.backgroundColor
124
+ : styles.barOffline.backgroundColor,
125
+ },
126
+ animatedStyle,
127
+ ]}
128
+ >
129
+ <View
130
+ style={[
131
+ styles.bar,
132
+ isBackOnline ? styles.barOnline : styles.barOffline,
133
+ ]}
134
+ >
135
+ <View
136
+ style={[
137
+ styles.dot,
138
+ isBackOnline ? styles.dotOnline : styles.dotOffline,
139
+ ]}
140
+ />
141
+ <Label
142
+ style={styles.text}
143
+ value={t(
144
+ isBackOnline
145
+ ? 'offline.banner.backOnline'
146
+ : 'offline.banner.offline',
147
+ )}
148
+ />
149
+ </View>
150
+ </Animated.View>
151
+ );
152
+ };
153
+
154
+ const makeStyles = (c: ThemeColors) =>
155
+ StyleSheet.create({
156
+ container: {
157
+ position: 'absolute',
158
+ top: 0,
159
+ left: 0,
160
+ right: 0,
161
+ zIndex: 9999,
162
+ },
163
+ bar: {
164
+ height: BANNER_HEIGHT,
165
+ flexDirection: 'row',
166
+ alignItems: 'center',
167
+ justifyContent: 'center',
168
+ gap: Spacing.spacing_sm, // 8
169
+ },
170
+ barOffline: { backgroundColor: c.bg_danger_faded },
171
+ barOnline: { backgroundColor: c.bd_success_normal },
172
+ dot: {
173
+ width: verticalScale(7),
174
+ height: verticalScale(7),
175
+ borderRadius: verticalScale(7),
176
+ },
177
+ dotOffline: { backgroundColor: c.fg_danger_on_background },
178
+ dotOnline: { backgroundColor: c.fg_success_on_background },
179
+ text: {
180
+ fontSize: fontSize(13),
181
+ fontFamily: Font.rethinkSansMedium,
182
+ color: c.fg_neutral_normal,
183
+ },
184
+ });
185
+
186
+ export default OfflineBanner;
@@ -0,0 +1 @@
1
+ export * from './screen-container';
@@ -0,0 +1 @@
1
+ export { default as ScreenContainer } from './screen-container';
@@ -0,0 +1,252 @@
1
+ // ScreenContainer.tsx — Design-System scaffold (Life-Master-Design).
2
+ //
3
+ // Rewritten from the legacy imoni light-theme container. The public prop API is
4
+ // kept backwards-compatible (legacy screens keep compiling) while the rendering
5
+ // now uses the themed DS background + the DS `Header`. New screens should use
6
+ // the DS props: `headerVariant`, `onBackPress`, `backLabel`, `headerLeft`,
7
+ // `headerRightNode`, `scroll`.
8
+ import { Font, fontSize, horizontalScale, isIOS, Spacing } from '@src/core/utils';
9
+ import { ThemeColors, useTheme, useThemedStyles } from '@src/core/theme';
10
+ import React, { PropsWithChildren, ReactNode } from 'react';
11
+ import {
12
+ Image,
13
+ ImageSourcePropType,
14
+ NativeScrollEvent,
15
+ NativeSyntheticEvent,
16
+ StatusBar,
17
+ StyleProp,
18
+ StyleSheet,
19
+ View,
20
+ ViewStyle,
21
+ } from 'react-native';
22
+ import { ScrollView } from 'react-native-gesture-handler';
23
+ import { KeyboardAwareScrollView } from 'react-native-keyboard-controller';
24
+ import { Edge, SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context';
25
+ import { ImgScreenBgGradian } from '@src/assets/Images';
26
+ import Header from '../../ui/header/header';
27
+ import { HeaderVariant } from '../../ui/header/header.type';
28
+
29
+ interface Props {
30
+ style?: StyleProp<ViewStyle>;
31
+ /** Apply the top safe-area inset (status bar / notch). @default true */
32
+ safeTop?: boolean;
33
+ /** Apply the bottom safe-area inset (home indicator). @default true */
34
+ safeBottom?: boolean;
35
+ /** @deprecated legacy background switch — ignored by the DS scaffold. */
36
+ bgType?: 'default' | 'full';
37
+ renderBottom?: () => React.ReactNode;
38
+ /**
39
+ * Full-screen background image. Defaults to the dark gradient in dark mode
40
+ * and to no image (flat themed background) in light mode.
41
+ */
42
+ background?: ImageSourcePropType;
43
+ /** Keyboard-aware scroll for forms. @default true */
44
+ isForm?: boolean;
45
+ /**
46
+ * Extra breathing space (px) kept between the focused input and the top of
47
+ * the keyboard while `isForm`. The scroll view animates the whole form up by
48
+ * this much past the keyboard. @default Spacing.spacing_2xl (32)
49
+ */
50
+ bottomOffset?: number;
51
+ /**
52
+ * Let the built-in `KeyboardAwareScrollView` auto-scroll the focused input
53
+ * into view. Set `false` when the screen drives its own keyboard animation
54
+ * (e.g. a translateY/height worklet) so the two don't fight. @default true
55
+ */
56
+ keyboardAware?: boolean;
57
+ showHeader?: boolean;
58
+ /** @deprecated Use typeButtonBack instead */
59
+ buttonBackType?: 'default' | 'white' | 'blur';
60
+ onScroll?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
61
+ onContentSizeChange?: (contentWidth: number, contentHeight: number) => void;
62
+
63
+ // --- DS props (additive) ---
64
+ /** DS Header layout. @default 'default' (or 'back' when only a back action is set) */
65
+ headerVariant?: HeaderVariant;
66
+ /** Header title (rendered by the `welcome` / `default` variants). */
67
+ title?: string;
68
+ /** Header subtitle under the title. */
69
+ subtitle?: string;
70
+ /** Back handler for the `back`/`step` header. */
71
+ onBackPress?: () => void;
72
+ /** Label for the `back` header variant. */
73
+ backLabel?: string;
74
+ /** Left slot node for the DS Header. */
75
+ headerLeft?: ReactNode;
76
+ /** Right slot node for the DS Header (e.g. avatar, skip). */
77
+ headerRightNode?: ReactNode;
78
+ }
79
+
80
+ const ScreenContainer = (props: PropsWithChildren<Props>) => {
81
+ const { colors, resolved } = useTheme();
82
+ const styles = useThemedStyles(makeStyles);
83
+ const {
84
+ children,
85
+ style = {},
86
+ safeTop = true,
87
+ safeBottom = true,
88
+ renderBottom = () => null,
89
+ // Dark mode keeps the gradient artwork; light mode falls back to the flat
90
+ // themed background until a light gradient asset is provided.
91
+ background = resolved === 'dark' ? ImgScreenBgGradian : undefined,
92
+ isForm = true,
93
+ bottomOffset = Spacing.spacing_2xl, // 32
94
+ keyboardAware = true,
95
+ showHeader = true,
96
+ onScroll,
97
+ onContentSizeChange,
98
+ headerVariant = 'default',
99
+ title,
100
+ subtitle,
101
+ onBackPress,
102
+ backLabel,
103
+ headerLeft,
104
+ headerRightNode,
105
+ } = props;
106
+
107
+ // SafeAreaView handles the TOP inset (status bar / notch) only. The bottom
108
+ // edge is applied manually below: on Android `insets.bottom` is ~0 on
109
+ // 3-button-nav devices, so SafeAreaView's `bottom` edge leaves no padding.
110
+ // We pad with `bottomInset` (floored on Android) instead — gated on
111
+ // `safeBottom` so screens that opt out keep zero bottom padding.
112
+ const resolvedEdges: Edge[] = [...(safeTop ? (['top'] as const) : [])];
113
+
114
+ const rawInsets = useSafeAreaInsets();
115
+ // Applied as paddingBottom on the inner wrapper below — i.e. exactly where
116
+ // SafeAreaView's `bottom` edge used to pad, so iOS layout is unchanged. iOS
117
+ // keeps the real home-indicator inset; Android floors to 16 so the padding
118
+ // never collapses on devices that report ~0 (3-button nav).
119
+ const bottomInset = safeBottom
120
+ ? isIOS
121
+ ? rawInsets.bottom
122
+ : Math.max(rawInsets.bottom, 16)
123
+ : 0;
124
+
125
+
126
+ const renderHeader = () => {
127
+ if (!showHeader) {
128
+ return null;
129
+ }
130
+ return (
131
+ <View style={styles.header}>
132
+ <Header
133
+ variant={headerVariant}
134
+ title={title}
135
+ subtitle={subtitle}
136
+ left={headerLeft}
137
+ right={headerRightNode}
138
+ onBackPress={onBackPress}
139
+ backLabel={backLabel}
140
+ />
141
+ </View>
142
+ );
143
+ };
144
+
145
+ // The `back`/`step` Header variants don't render the title; show it as a
146
+ // centered block at the top of the body (matches the Figma auth screens).
147
+ const body = (
148
+ <>
149
+ {children}
150
+ </>
151
+ );
152
+
153
+ return (
154
+ <View style={styles.container}>
155
+ <StatusBar
156
+ barStyle={resolved === 'dark' ? 'light-content' : 'dark-content'}
157
+ backgroundColor={colors.transparent}
158
+ translucent
159
+ />
160
+ {background ? (
161
+ <Image source={background} style={styles.background} resizeMode="cover" />
162
+ ) : null}
163
+ <SafeAreaView style={styles.safe} edges={resolvedEdges}>
164
+ <View style={[styles.safe, { paddingBottom: bottomInset }]}>
165
+ {renderHeader()}
166
+
167
+ {isForm ? (
168
+ <KeyboardAwareScrollView
169
+ ScrollViewComponent={ScrollView as any}
170
+ showsVerticalScrollIndicator={false}
171
+ onScroll={onScroll}
172
+ scrollEventThrottle={16}
173
+ onContentSizeChange={onContentSizeChange}
174
+ // Animate the whole form up past the keyboard (UI-thread,
175
+ // Reanimated) and keep `bottomOffset` of breathing room
176
+ // above the focused caret. `mode="layout"` makes the flex
177
+ // layout (topSpacer / marginTop:auto actions / gap) reflow
178
+ // around the keyboard space so inputs are never covered.
179
+ bottomOffset={bottomOffset}
180
+ mode="layout"
181
+ // When false, the screen drives its own keyboard animation
182
+ // (translateY/height worklet) and this view stops auto-scrolling.
183
+ enabled={keyboardAware}
184
+ keyboardDismissMode="interactive"
185
+ keyboardShouldPersistTaps="handled"
186
+ contentContainerStyle={[styles.content, style]}
187
+ >
188
+ {body}
189
+ </KeyboardAwareScrollView>
190
+ ) : (
191
+ // Non-form screens (e.g. the auth screens) render a plain View.
192
+ <View style={[styles.content, styles.flex, style]}>{body}</View>
193
+ )}
194
+
195
+ <View style={styles.bottom}>{renderBottom()}</View>
196
+ </View>
197
+ </SafeAreaView>
198
+ </View>
199
+ );
200
+ };
201
+
202
+ export default ScreenContainer;
203
+
204
+ const makeStyles = (c: ThemeColors) =>
205
+ StyleSheet.create({
206
+ container: {
207
+ flex: 1,
208
+ backgroundColor: c.bg_elevation_level_1_normal,
209
+ },
210
+ background: {
211
+ ...StyleSheet.absoluteFill,
212
+ width: '100%',
213
+ height: '100%',
214
+ },
215
+ safe: {
216
+ flex: 1,
217
+ },
218
+ header: {
219
+ paddingHorizontal: horizontalScale(Spacing.spacing_base), // 16
220
+ paddingBottom: Spacing.spacing_sm,
221
+ },
222
+ content: {
223
+ paddingHorizontal: horizontalScale(Spacing.spacing_xl), // 24
224
+ paddingTop: Spacing.spacing_base,
225
+ flex: 1,
226
+ },
227
+ flex: {
228
+ flex: 1,
229
+ },
230
+ bottom: {
231
+ paddingHorizontal: horizontalScale(Spacing.spacing_xl), // 24
232
+ },
233
+ titleBlock: {
234
+ alignItems: 'center',
235
+ gap: Spacing.spacing_s_nudge, // 6
236
+ marginBottom: Spacing.spacing_2xl, // 32
237
+ },
238
+ title: {
239
+ fontFamily: Font.dmSansSemiBold,
240
+ fontSize: fontSize(28),
241
+ lineHeight: 36,
242
+ color: c.fg_neutral_normal,
243
+ textAlign: 'center',
244
+ },
245
+ subtitle: {
246
+ fontFamily: Font.dmSansRegular,
247
+ fontSize: fontSize(12),
248
+ lineHeight: 18,
249
+ color: c.fg_neutral_faded,
250
+ textAlign: 'center',
251
+ },
252
+ });
@@ -0,0 +1 @@
1
+ export * from './splash-overlay';
@@ -0,0 +1 @@
1
+ export { default as SplashOverlay } from './splash-overlay';