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,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,248 @@
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
+ KeyboardAvoidingView,
15
+ NativeScrollEvent,
16
+ NativeSyntheticEvent,
17
+ StatusBar,
18
+ StyleProp,
19
+ StyleSheet,
20
+ View,
21
+ ViewStyle,
22
+ } from 'react-native';
23
+ import { ScrollView } from 'react-native-gesture-handler';
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 above the keyboard while `isForm` — passed
47
+ * to KeyboardAvoidingView as `keyboardVerticalOffset`.
48
+ * @default Spacing.spacing_2xl (32)
49
+ */
50
+ bottomOffset?: number;
51
+ /**
52
+ * @deprecated No longer used — kept for API compatibility. Keyboard handling
53
+ * now uses React Native's KeyboardAvoidingView (Expo Go compatible).
54
+ */
55
+ keyboardAware?: boolean;
56
+ showHeader?: boolean;
57
+ /** @deprecated Use typeButtonBack instead */
58
+ buttonBackType?: 'default' | 'white' | 'blur';
59
+ onScroll?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
60
+ onContentSizeChange?: (contentWidth: number, contentHeight: number) => void;
61
+
62
+ // --- DS props (additive) ---
63
+ /** DS Header layout. @default 'default' (or 'back' when only a back action is set) */
64
+ headerVariant?: HeaderVariant;
65
+ /** Header title (rendered by the `welcome` / `default` variants). */
66
+ title?: string;
67
+ /** Header subtitle under the title. */
68
+ subtitle?: string;
69
+ /** Back handler for the `back`/`step` header. */
70
+ onBackPress?: () => void;
71
+ /** Label for the `back` header variant. */
72
+ backLabel?: string;
73
+ /** Left slot node for the DS Header. */
74
+ headerLeft?: ReactNode;
75
+ /** Right slot node for the DS Header (e.g. avatar, skip). */
76
+ headerRightNode?: ReactNode;
77
+ }
78
+
79
+ const ScreenContainer = (props: PropsWithChildren<Props>) => {
80
+ const { colors, resolved } = useTheme();
81
+ const styles = useThemedStyles(makeStyles);
82
+ const {
83
+ children,
84
+ style = {},
85
+ safeTop = true,
86
+ safeBottom = true,
87
+ renderBottom = () => null,
88
+ // Dark mode keeps the gradient artwork; light mode falls back to the flat
89
+ // themed background until a light gradient asset is provided.
90
+ background = resolved === 'dark' ? ImgScreenBgGradian : undefined,
91
+ isForm = true,
92
+ bottomOffset = Spacing.spacing_2xl, // 32
93
+ showHeader = true,
94
+ onScroll,
95
+ onContentSizeChange,
96
+ headerVariant = 'default',
97
+ title,
98
+ subtitle,
99
+ onBackPress,
100
+ backLabel,
101
+ headerLeft,
102
+ headerRightNode,
103
+ } = props;
104
+
105
+ // SafeAreaView handles the TOP inset (status bar / notch) only. The bottom
106
+ // edge is applied manually below: on Android `insets.bottom` is ~0 on
107
+ // 3-button-nav devices, so SafeAreaView's `bottom` edge leaves no padding.
108
+ // We pad with `bottomInset` (floored on Android) instead — gated on
109
+ // `safeBottom` so screens that opt out keep zero bottom padding.
110
+ const resolvedEdges: Edge[] = [...(safeTop ? (['top'] as const) : [])];
111
+
112
+ const rawInsets = useSafeAreaInsets();
113
+ // Applied as paddingBottom on the inner wrapper below — i.e. exactly where
114
+ // SafeAreaView's `bottom` edge used to pad, so iOS layout is unchanged. iOS
115
+ // keeps the real home-indicator inset; Android floors to 16 so the padding
116
+ // never collapses on devices that report ~0 (3-button nav).
117
+ const bottomInset = safeBottom
118
+ ? isIOS
119
+ ? rawInsets.bottom
120
+ : Math.max(rawInsets.bottom, 16)
121
+ : 0;
122
+
123
+
124
+ const renderHeader = () => {
125
+ if (!showHeader) {
126
+ return null;
127
+ }
128
+ return (
129
+ <View style={styles.header}>
130
+ <Header
131
+ variant={headerVariant}
132
+ title={title}
133
+ subtitle={subtitle}
134
+ left={headerLeft}
135
+ right={headerRightNode}
136
+ onBackPress={onBackPress}
137
+ backLabel={backLabel}
138
+ />
139
+ </View>
140
+ );
141
+ };
142
+
143
+ // The `back`/`step` Header variants don't render the title; show it as a
144
+ // centered block at the top of the body (matches the Figma auth screens).
145
+ const body = (
146
+ <>
147
+ {children}
148
+ </>
149
+ );
150
+
151
+ return (
152
+ <View style={styles.container}>
153
+ <StatusBar
154
+ barStyle={resolved === 'dark' ? 'light-content' : 'dark-content'}
155
+ backgroundColor={colors.transparent}
156
+ translucent
157
+ />
158
+ {background ? (
159
+ <Image source={background} style={styles.background} resizeMode="cover" />
160
+ ) : null}
161
+ <SafeAreaView style={styles.safe} edges={resolvedEdges}>
162
+ <View style={[styles.safe, { paddingBottom: bottomInset }]}>
163
+ {renderHeader()}
164
+
165
+ {isForm ? (
166
+ // KeyboardAvoidingView (RN core) lifts the form above the
167
+ // keyboard — works in Expo Go without a custom dev build.
168
+ // `bottomOffset` keeps breathing room above the focused input.
169
+ <KeyboardAvoidingView
170
+ style={styles.flex}
171
+ behavior={isIOS ? 'padding' : undefined}
172
+ keyboardVerticalOffset={bottomOffset}
173
+ >
174
+ <ScrollView
175
+ showsVerticalScrollIndicator={false}
176
+ onScroll={onScroll}
177
+ scrollEventThrottle={16}
178
+ onContentSizeChange={onContentSizeChange}
179
+ keyboardDismissMode="interactive"
180
+ keyboardShouldPersistTaps="handled"
181
+ contentContainerStyle={[styles.content, style]}
182
+ >
183
+ {body}
184
+ </ScrollView>
185
+ </KeyboardAvoidingView>
186
+ ) : (
187
+ // Non-form screens (e.g. the auth screens) render a plain View.
188
+ <View style={[styles.content, styles.flex, style]}>{body}</View>
189
+ )}
190
+
191
+ <View style={styles.bottom}>{renderBottom()}</View>
192
+ </View>
193
+ </SafeAreaView>
194
+ </View>
195
+ );
196
+ };
197
+
198
+ export default ScreenContainer;
199
+
200
+ const makeStyles = (c: ThemeColors) =>
201
+ StyleSheet.create({
202
+ container: {
203
+ flex: 1,
204
+ backgroundColor: c.bg_elevation_level_1_normal,
205
+ },
206
+ background: {
207
+ ...StyleSheet.absoluteFill,
208
+ width: '100%',
209
+ height: '100%',
210
+ },
211
+ safe: {
212
+ flex: 1,
213
+ },
214
+ header: {
215
+ paddingHorizontal: horizontalScale(Spacing.spacing_base), // 16
216
+ paddingBottom: Spacing.spacing_sm,
217
+ },
218
+ content: {
219
+ paddingHorizontal: horizontalScale(Spacing.spacing_xl), // 24
220
+ paddingTop: Spacing.spacing_base,
221
+ flex: 1,
222
+ },
223
+ flex: {
224
+ flex: 1,
225
+ },
226
+ bottom: {
227
+ paddingHorizontal: horizontalScale(Spacing.spacing_xl), // 24
228
+ },
229
+ titleBlock: {
230
+ alignItems: 'center',
231
+ gap: Spacing.spacing_s_nudge, // 6
232
+ marginBottom: Spacing.spacing_2xl, // 32
233
+ },
234
+ title: {
235
+ fontFamily: Font.dmSansSemiBold,
236
+ fontSize: fontSize(28),
237
+ lineHeight: 36,
238
+ color: c.fg_neutral_normal,
239
+ textAlign: 'center',
240
+ },
241
+ subtitle: {
242
+ fontFamily: Font.dmSansRegular,
243
+ fontSize: fontSize(12),
244
+ lineHeight: 18,
245
+ color: c.fg_neutral_faded,
246
+ textAlign: 'center',
247
+ },
248
+ });
@@ -0,0 +1 @@
1
+ export * from './splash-overlay';
@@ -0,0 +1 @@
1
+ export { default as SplashOverlay } from './splash-overlay';
@@ -0,0 +1,93 @@
1
+ import { ImgScreenBgGradian } from '@src/assets/Images';
2
+ import { verticalScale } from '@src/core';
3
+ import React, { useEffect } from 'react';
4
+ import { Image, Platform, StyleSheet } from 'react-native';
5
+ import Animated, {
6
+ useAnimatedStyle,
7
+ useSharedValue,
8
+ withTiming,
9
+ } from 'react-native-reanimated';
10
+
11
+ const LOGO = require('@src/assets/splash/logo-white.png');
12
+
13
+ const FADE_OUT_MS = 350;
14
+
15
+ interface SplashOverlayProps {
16
+ /**
17
+ * Flip to `true` once the app is ready (launch route resolved + native
18
+ * splash hidden). The overlay then fades out and unmounts itself.
19
+ */
20
+ hidden: boolean;
21
+ }
22
+
23
+ /**
24
+ * Android-only fake splash.
25
+ *
26
+ * iOS renders a full-bleed gradient splash via the native storyboard
27
+ * (with-splash-screen-fix plugin). Android 12+ can only show a centred icon on
28
+ * a solid colour, so after the native splash hands off we cover the first
29
+ * frames with this React overlay — the shared `ImgScreenBgGradian` background
30
+ * + logo — then fade it out, giving Android a gradient launch look. No-op on
31
+ * iOS, which keeps its full-bleed native storyboard splash.
32
+ */
33
+ const SplashOverlay = ({ hidden }: SplashOverlayProps) => {
34
+ const opacity = useSharedValue(1);
35
+ const gone = useSharedValue(false);
36
+
37
+ useEffect(() => {
38
+ if (hidden) {
39
+ opacity.value = withTiming(0, { duration: FADE_OUT_MS }, finished => {
40
+ if (finished) {
41
+ gone.value = true;
42
+ }
43
+ });
44
+ }
45
+ }, [hidden, opacity, gone]);
46
+
47
+ const animatedStyle = useAnimatedStyle(() => ({
48
+ opacity: opacity.value,
49
+ // Drop out of the tree (and stop intercepting touches) once faded.
50
+ display: gone.value ? 'none' : 'flex',
51
+ }));
52
+
53
+ if (Platform.OS !== 'android') {
54
+ return null;
55
+ }
56
+
57
+ return (
58
+ <Animated.View
59
+ style={[styles.container, animatedStyle]}
60
+ pointerEvents="none">
61
+ <Image
62
+ source={ImgScreenBgGradian}
63
+ style={styles.image}
64
+ />
65
+
66
+ <Image source={LOGO} style={styles.logo} resizeMode="contain" />
67
+ </Animated.View>
68
+ );
69
+ };
70
+
71
+ const styles = StyleSheet.create({
72
+ container: {
73
+ position: 'absolute',
74
+ top: 0,
75
+ left: 0,
76
+ right: 0,
77
+ bottom: 0,
78
+ zIndex: 9999,
79
+ justifyContent: 'center',
80
+ alignItems: 'center',
81
+ },
82
+ image: {
83
+ position: 'absolute',
84
+ height: '100%',
85
+ width: '100%'
86
+ },
87
+ logo: {
88
+ height: verticalScale(160),
89
+ width: verticalScale(110)
90
+ },
91
+ });
92
+
93
+ export default SplashOverlay;
@@ -0,0 +1,48 @@
1
+ import React from 'react';
2
+ import { Pressable } from 'react-native';
3
+ import Animated, { FadeInRight, FadeOutRight, Layout } from 'react-native-reanimated';
4
+ import { AnimatedListItemProps } from './animated-list-item.type';
5
+
6
+ const ANIMATION_DELAY_STAGGER = 50;
7
+ const ANIMATION_DURATION = 200;
8
+ const ENTERING_BASE = FadeInRight.duration(ANIMATION_DURATION).springify();
9
+ const EXITING = FadeOutRight.duration(ANIMATION_DURATION);
10
+ const LAYOUT = Layout.springify();
11
+ const PressableAnimated = Animated.createAnimatedComponent(Pressable);
12
+
13
+ const AnimatedListItem: React.FC<AnimatedListItemProps> = ({
14
+ children,
15
+ index,
16
+ style,
17
+ delayStagger = ANIMATION_DELAY_STAGGER,
18
+ onPress,
19
+ }) => {
20
+ const entering = ENTERING_BASE.delay(index * delayStagger);
21
+
22
+ if (onPress) {
23
+ return (
24
+ <PressableAnimated
25
+ entering={entering}
26
+ exiting={EXITING}
27
+ layout={LAYOUT}
28
+ style={style}
29
+ onPress={onPress}
30
+ >
31
+ {children}
32
+ </PressableAnimated>
33
+ );
34
+ }
35
+
36
+ return (
37
+ <Animated.View
38
+ entering={entering}
39
+ exiting={EXITING}
40
+ layout={LAYOUT}
41
+ style={style}
42
+ >
43
+ {children}
44
+ </Animated.View>
45
+ );
46
+ };
47
+
48
+ export default AnimatedListItem;
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import { StyleProp, ViewStyle } from 'react-native';
3
+
4
+ export interface AnimatedListItemProps {
5
+ children: React.ReactNode;
6
+ index: number;
7
+ style?: StyleProp<ViewStyle>;
8
+ delayStagger?: number;
9
+ onPress?: () => void;
10
+ }
@@ -0,0 +1,2 @@
1
+ export { default as AnimatedListItem } from './animated-list-item';
2
+ export * from './animated-list-item.type';