@amplitude/wizard 1.0.0-beta.2 → 1.0.0

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 (391) hide show
  1. package/README.md +171 -74
  2. package/dist/bin.js +338 -222
  3. package/dist/src/lib/agent-interface.js +64 -9
  4. package/dist/src/lib/agent-runner.js +1 -10
  5. package/dist/src/lib/api.d.ts +22 -4
  6. package/dist/src/lib/api.js +114 -12
  7. package/dist/src/lib/commandments.js +14 -1
  8. package/dist/src/lib/constants.d.ts +6 -5
  9. package/dist/src/lib/constants.js +13 -13
  10. package/dist/src/lib/credential-resolution.d.ts +45 -0
  11. package/dist/src/lib/credential-resolution.js +311 -0
  12. package/dist/src/lib/exit-codes.d.ts +10 -0
  13. package/dist/src/lib/exit-codes.js +12 -0
  14. package/dist/src/lib/health-checks/statuspage.d.ts +1 -0
  15. package/dist/src/lib/health-checks/statuspage.js +5 -1
  16. package/dist/src/lib/mode-config.d.ts +14 -0
  17. package/dist/src/lib/mode-config.js +14 -0
  18. package/dist/src/lib/session-checkpoint.d.ts +27 -0
  19. package/dist/src/lib/session-checkpoint.js +134 -0
  20. package/dist/src/lib/wizard-session.d.ts +44 -1
  21. package/dist/src/lib/wizard-session.js +70 -14
  22. package/dist/src/lib/wizard-tools.js +19 -4
  23. package/dist/src/steps/add-mcp-server-to-clients/clients/claude.d.ts +3 -0
  24. package/dist/src/steps/add-mcp-server-to-clients/clients/claude.js +6 -0
  25. package/dist/src/steps/add-mcp-server-to-clients/clients/cursor.js +3 -1
  26. package/dist/src/ui/agent-ui.d.ts +91 -0
  27. package/dist/src/ui/agent-ui.js +277 -0
  28. package/dist/src/ui/logging-ui.js +1 -1
  29. package/dist/src/ui/tui/App.d.ts +12 -0
  30. package/dist/src/ui/tui/App.js +29 -18
  31. package/dist/src/ui/tui/components/AmplitudeLogo.js +16 -17
  32. package/dist/src/ui/tui/components/AmplitudeTextLogo.d.ts +0 -2
  33. package/dist/src/ui/tui/components/AmplitudeTextLogo.js +53 -18
  34. package/dist/src/ui/tui/components/BrailleSpinner.d.ts +8 -0
  35. package/dist/src/ui/tui/components/BrailleSpinner.js +15 -0
  36. package/dist/src/ui/tui/components/ConsoleView.d.ts +8 -11
  37. package/dist/src/ui/tui/components/ConsoleView.js +51 -34
  38. package/dist/src/ui/tui/components/HeaderBar.d.ts +12 -0
  39. package/dist/src/ui/tui/components/HeaderBar.js +17 -0
  40. package/dist/src/ui/tui/components/JourneyStepper.d.ts +16 -0
  41. package/dist/src/ui/tui/components/JourneyStepper.js +83 -0
  42. package/dist/src/ui/tui/components/KeyHintBar.d.ts +19 -0
  43. package/dist/src/ui/tui/components/KeyHintBar.js +20 -0
  44. package/dist/src/ui/tui/console-commands.d.ts +1 -2
  45. package/dist/src/ui/tui/console-commands.js +48 -7
  46. package/dist/src/ui/tui/flows.d.ts +1 -1
  47. package/dist/src/ui/tui/flows.js +1 -1
  48. package/dist/src/ui/tui/hooks/useAsyncEffect.d.ts +15 -0
  49. package/dist/src/ui/tui/hooks/useAsyncEffect.js +35 -0
  50. package/dist/src/ui/tui/hooks/useWizardStore.d.ts +9 -0
  51. package/dist/src/ui/tui/hooks/useWizardStore.js +11 -0
  52. package/dist/src/ui/tui/ink-ui.js +1 -1
  53. package/dist/src/ui/tui/primitives/DissolveTransition.js +4 -5
  54. package/dist/src/ui/tui/primitives/EventPlanViewer.d.ts +3 -1
  55. package/dist/src/ui/tui/primitives/EventPlanViewer.js +8 -3
  56. package/dist/src/ui/tui/primitives/ProgressList.js +1 -1
  57. package/dist/src/ui/tui/primitives/SlashCommandInput.js +19 -4
  58. package/dist/src/ui/tui/primitives/SplitView.d.ts +2 -1
  59. package/dist/src/ui/tui/primitives/SplitView.js +10 -2
  60. package/dist/src/ui/tui/primitives/TabContainer.js +10 -2
  61. package/dist/src/ui/tui/primitives/index.d.ts +0 -1
  62. package/dist/src/ui/tui/primitives/index.js +0 -1
  63. package/dist/src/ui/tui/router.js +1 -1
  64. package/dist/src/ui/tui/screen-registry.d.ts +0 -7
  65. package/dist/src/ui/tui/screen-registry.js +13 -4
  66. package/dist/src/ui/tui/screens/ActivationOptionsScreen.d.ts +2 -2
  67. package/dist/src/ui/tui/screens/ActivationOptionsScreen.js +8 -8
  68. package/dist/src/ui/tui/screens/AuthScreen.js +57 -27
  69. package/dist/src/ui/tui/screens/ChecklistScreen.d.ts +2 -12
  70. package/dist/src/ui/tui/screens/ChecklistScreen.js +22 -33
  71. package/dist/src/ui/tui/screens/DataIngestionCheckScreen.d.ts +3 -12
  72. package/dist/src/ui/tui/screens/DataIngestionCheckScreen.js +109 -39
  73. package/dist/src/ui/tui/screens/DataSetupScreen.d.ts +3 -3
  74. package/dist/src/ui/tui/screens/DataSetupScreen.js +17 -10
  75. package/dist/src/ui/tui/screens/IntroScreen.d.ts +5 -3
  76. package/dist/src/ui/tui/screens/IntroScreen.js +132 -41
  77. package/dist/src/ui/tui/screens/LoginScreen.d.ts +1 -1
  78. package/dist/src/ui/tui/screens/LoginScreen.js +4 -4
  79. package/dist/src/ui/tui/screens/LogoutScreen.d.ts +4 -2
  80. package/dist/src/ui/tui/screens/LogoutScreen.js +17 -5
  81. package/dist/src/ui/tui/screens/McpScreen.d.ts +4 -4
  82. package/dist/src/ui/tui/screens/McpScreen.js +25 -17
  83. package/dist/src/ui/tui/screens/OutageScreen.d.ts +1 -1
  84. package/dist/src/ui/tui/screens/OutageScreen.js +5 -5
  85. package/dist/src/ui/tui/screens/OutroScreen.d.ts +5 -0
  86. package/dist/src/ui/tui/screens/OutroScreen.js +21 -14
  87. package/dist/src/ui/tui/screens/RegionSelectScreen.js +15 -13
  88. package/dist/src/ui/tui/screens/RunScreen.d.ts +7 -5
  89. package/dist/src/ui/tui/screens/RunScreen.js +102 -157
  90. package/dist/src/ui/tui/screens/SettingsOverrideScreen.d.ts +1 -1
  91. package/dist/src/ui/tui/screens/SettingsOverrideScreen.js +6 -5
  92. package/dist/src/ui/tui/screens/SetupScreen.d.ts +1 -1
  93. package/dist/src/ui/tui/screens/SetupScreen.js +7 -7
  94. package/dist/src/ui/tui/screens/SlackScreen.d.ts +2 -2
  95. package/dist/src/ui/tui/screens/SlackScreen.js +60 -35
  96. package/dist/src/ui/tui/session-constants.d.ts +41 -0
  97. package/dist/src/ui/tui/session-constants.js +38 -0
  98. package/dist/src/ui/tui/start-tui.d.ts +3 -1
  99. package/dist/src/ui/tui/start-tui.js +14 -10
  100. package/dist/src/ui/tui/store.d.ts +2 -1
  101. package/dist/src/ui/tui/store.js +33 -7
  102. package/dist/src/ui/tui/styles.d.ts +75 -19
  103. package/dist/src/ui/tui/styles.js +101 -19
  104. package/dist/src/ui/tui/utils/classify-error.d.ts +14 -0
  105. package/dist/src/ui/tui/utils/classify-error.js +90 -0
  106. package/dist/src/ui/tui/utils/diagnostics.d.ts +21 -0
  107. package/dist/src/ui/tui/utils/diagnostics.js +72 -0
  108. package/dist/src/ui/tui/utils/with-retry.d.ts +12 -0
  109. package/dist/src/ui/tui/utils/with-retry.js +32 -0
  110. package/dist/src/ui/tui/utils/with-timeout.d.ts +10 -0
  111. package/dist/src/ui/tui/utils/with-timeout.js +24 -0
  112. package/dist/src/utils/ampli-settings.d.ts +1 -1
  113. package/dist/src/utils/ampli-settings.js +15 -5
  114. package/dist/src/utils/api-key-store.js +5 -5
  115. package/dist/src/utils/atomic-write.d.ts +15 -0
  116. package/dist/src/utils/atomic-write.js +34 -0
  117. package/dist/src/utils/setup-utils.js +2 -2
  118. package/dist/src/utils/token-refresh.d.ts +22 -0
  119. package/dist/src/utils/token-refresh.js +79 -0
  120. package/dist/src/utils/wizard-abort.js +6 -1
  121. package/package.json +6 -6
  122. package/skills/instrumentation/add-analytics-instrumentation/SKILL.md +142 -0
  123. package/skills/instrumentation/diff-intake/SKILL.md +128 -0
  124. package/skills/instrumentation/discover-analytics-patterns/SKILL.md +185 -0
  125. package/skills/instrumentation/discover-event-surfaces/SKILL.md +322 -0
  126. package/skills/instrumentation/discover-event-surfaces/references/best-practices.md +563 -0
  127. package/skills/instrumentation/instrument-events/SKILL.md +169 -0
  128. package/skills/instrumentation/instrument-events/references/best-practices.md +563 -0
  129. package/skills/integration/integration-android/SKILL.md +49 -0
  130. package/skills/integration/integration-android/references/EXAMPLE.md +1977 -0
  131. package/skills/integration/integration-android/references/amplitude-quickstart.md +1845 -0
  132. package/skills/integration/integration-android/references/analytics.md +1778 -0
  133. package/skills/integration/integration-android/references/basic-integration-1.0-begin.md +43 -0
  134. package/skills/integration/integration-android/references/basic-integration-1.1-edit.md +35 -0
  135. package/skills/integration/integration-android/references/basic-integration-1.2-revise.md +23 -0
  136. package/skills/integration/integration-android/references/basic-integration-1.3-conclude.md +57 -0
  137. package/skills/integration/integration-angular/SKILL.md +49 -0
  138. package/skills/integration/integration-angular/references/EXAMPLE.md +899 -0
  139. package/skills/integration/integration-angular/references/amplitude-quickstart.md +1845 -0
  140. package/skills/integration/integration-angular/references/basic-integration-1.0-begin.md +43 -0
  141. package/skills/integration/integration-angular/references/basic-integration-1.1-edit.md +35 -0
  142. package/skills/integration/integration-angular/references/basic-integration-1.2-revise.md +23 -0
  143. package/skills/integration/integration-angular/references/basic-integration-1.3-conclude.md +57 -0
  144. package/skills/integration/integration-angular/references/browser-sdk-2.md +4680 -0
  145. package/skills/integration/integration-astro-hybrid/SKILL.md +56 -0
  146. package/skills/integration/integration-astro-hybrid/references/EXAMPLE.md +1095 -0
  147. package/skills/integration/integration-astro-hybrid/references/amplitude-quickstart.md +1845 -0
  148. package/skills/integration/integration-astro-hybrid/references/basic-integration-1.0-begin.md +43 -0
  149. package/skills/integration/integration-astro-hybrid/references/basic-integration-1.1-edit.md +35 -0
  150. package/skills/integration/integration-astro-hybrid/references/basic-integration-1.2-revise.md +23 -0
  151. package/skills/integration/integration-astro-hybrid/references/basic-integration-1.3-conclude.md +57 -0
  152. package/skills/integration/integration-astro-hybrid/references/browser-sdk-2.md +4680 -0
  153. package/skills/integration/integration-astro-ssr/SKILL.md +52 -0
  154. package/skills/integration/integration-astro-ssr/references/EXAMPLE.md +1106 -0
  155. package/skills/integration/integration-astro-ssr/references/amplitude-quickstart.md +1845 -0
  156. package/skills/integration/integration-astro-ssr/references/basic-integration-1.0-begin.md +43 -0
  157. package/skills/integration/integration-astro-ssr/references/basic-integration-1.1-edit.md +35 -0
  158. package/skills/integration/integration-astro-ssr/references/basic-integration-1.2-revise.md +23 -0
  159. package/skills/integration/integration-astro-ssr/references/basic-integration-1.3-conclude.md +57 -0
  160. package/skills/integration/integration-astro-ssr/references/browser-sdk-2.md +4680 -0
  161. package/skills/integration/integration-astro-static/SKILL.md +49 -0
  162. package/skills/integration/integration-astro-static/references/EXAMPLE.md +910 -0
  163. package/skills/integration/integration-astro-static/references/amplitude-quickstart.md +1845 -0
  164. package/skills/integration/integration-astro-static/references/basic-integration-1.0-begin.md +43 -0
  165. package/skills/integration/integration-astro-static/references/basic-integration-1.1-edit.md +35 -0
  166. package/skills/integration/integration-astro-static/references/basic-integration-1.2-revise.md +23 -0
  167. package/skills/integration/integration-astro-static/references/basic-integration-1.3-conclude.md +57 -0
  168. package/skills/integration/integration-astro-static/references/browser-sdk-2.md +4680 -0
  169. package/skills/integration/integration-astro-view-transitions/SKILL.md +51 -0
  170. package/skills/integration/integration-astro-view-transitions/references/EXAMPLE.md +979 -0
  171. package/skills/integration/integration-astro-view-transitions/references/amplitude-quickstart.md +1845 -0
  172. package/skills/integration/integration-astro-view-transitions/references/basic-integration-1.0-begin.md +43 -0
  173. package/skills/integration/integration-astro-view-transitions/references/basic-integration-1.1-edit.md +35 -0
  174. package/skills/integration/integration-astro-view-transitions/references/basic-integration-1.2-revise.md +23 -0
  175. package/skills/integration/integration-astro-view-transitions/references/basic-integration-1.3-conclude.md +57 -0
  176. package/skills/integration/integration-astro-view-transitions/references/browser-sdk-2.md +4680 -0
  177. package/skills/integration/integration-django/SKILL.md +57 -0
  178. package/skills/integration/integration-django/references/EXAMPLE.md +1005 -0
  179. package/skills/integration/integration-django/references/amplitude-quickstart.md +1845 -0
  180. package/skills/integration/integration-django/references/basic-integration-1.0-begin.md +43 -0
  181. package/skills/integration/integration-django/references/basic-integration-1.1-edit.md +35 -0
  182. package/skills/integration/integration-django/references/basic-integration-1.2-revise.md +23 -0
  183. package/skills/integration/integration-django/references/basic-integration-1.3-conclude.md +57 -0
  184. package/skills/integration/integration-django/references/python.md +1424 -0
  185. package/skills/integration/integration-expo/SKILL.md +53 -0
  186. package/skills/integration/integration-expo/references/EXAMPLE.md +1291 -0
  187. package/skills/integration/integration-expo/references/amplitude-quickstart.md +1845 -0
  188. package/skills/integration/integration-expo/references/basic-integration-1.0-begin.md +43 -0
  189. package/skills/integration/integration-expo/references/basic-integration-1.1-edit.md +35 -0
  190. package/skills/integration/integration-expo/references/basic-integration-1.2-revise.md +23 -0
  191. package/skills/integration/integration-expo/references/basic-integration-1.3-conclude.md +57 -0
  192. package/skills/integration/integration-expo/references/react-native-sdk.md +2819 -0
  193. package/skills/integration/integration-fastapi/SKILL.md +57 -0
  194. package/skills/integration/integration-fastapi/references/EXAMPLE.md +1389 -0
  195. package/skills/integration/integration-fastapi/references/amplitude-quickstart.md +1845 -0
  196. package/skills/integration/integration-fastapi/references/basic-integration-1.0-begin.md +43 -0
  197. package/skills/integration/integration-fastapi/references/basic-integration-1.1-edit.md +35 -0
  198. package/skills/integration/integration-fastapi/references/basic-integration-1.2-revise.md +23 -0
  199. package/skills/integration/integration-fastapi/references/basic-integration-1.3-conclude.md +57 -0
  200. package/skills/integration/integration-fastapi/references/python.md +1424 -0
  201. package/skills/integration/integration-flask/SKILL.md +56 -0
  202. package/skills/integration/integration-flask/references/EXAMPLE.md +1130 -0
  203. package/skills/integration/integration-flask/references/amplitude-quickstart.md +1845 -0
  204. package/skills/integration/integration-flask/references/basic-integration-1.0-begin.md +43 -0
  205. package/skills/integration/integration-flask/references/basic-integration-1.1-edit.md +35 -0
  206. package/skills/integration/integration-flask/references/basic-integration-1.2-revise.md +23 -0
  207. package/skills/integration/integration-flask/references/basic-integration-1.3-conclude.md +57 -0
  208. package/skills/integration/integration-flask/references/python.md +1424 -0
  209. package/skills/integration/integration-javascript_node/SKILL.md +54 -0
  210. package/skills/integration/integration-javascript_node/references/EXAMPLE.md +365 -0
  211. package/skills/integration/integration-javascript_node/references/amplitude-quickstart.md +1845 -0
  212. package/skills/integration/integration-javascript_node/references/analytics.md +1778 -0
  213. package/skills/integration/integration-javascript_node/references/basic-integration-1.0-begin.md +43 -0
  214. package/skills/integration/integration-javascript_node/references/basic-integration-1.1-edit.md +35 -0
  215. package/skills/integration/integration-javascript_node/references/basic-integration-1.2-revise.md +23 -0
  216. package/skills/integration/integration-javascript_node/references/basic-integration-1.3-conclude.md +57 -0
  217. package/skills/integration/integration-javascript_web/SKILL.md +58 -0
  218. package/skills/integration/integration-javascript_web/references/EXAMPLE.md +451 -0
  219. package/skills/integration/integration-javascript_web/references/amplitude-quickstart.md +1845 -0
  220. package/skills/integration/integration-javascript_web/references/basic-integration-1.0-begin.md +43 -0
  221. package/skills/integration/integration-javascript_web/references/basic-integration-1.1-edit.md +35 -0
  222. package/skills/integration/integration-javascript_web/references/basic-integration-1.2-revise.md +23 -0
  223. package/skills/integration/integration-javascript_web/references/basic-integration-1.3-conclude.md +57 -0
  224. package/skills/integration/integration-javascript_web/references/browser-sdk-2.md +4680 -0
  225. package/skills/integration/integration-laravel/SKILL.md +52 -0
  226. package/skills/integration/integration-laravel/references/EXAMPLE.md +2039 -0
  227. package/skills/integration/integration-laravel/references/amplitude-quickstart.md +1845 -0
  228. package/skills/integration/integration-laravel/references/analytics.md +1778 -0
  229. package/skills/integration/integration-laravel/references/basic-integration-1.0-begin.md +43 -0
  230. package/skills/integration/integration-laravel/references/basic-integration-1.1-edit.md +35 -0
  231. package/skills/integration/integration-laravel/references/basic-integration-1.2-revise.md +23 -0
  232. package/skills/integration/integration-laravel/references/basic-integration-1.3-conclude.md +57 -0
  233. package/skills/integration/integration-nextjs-app-router/SKILL.md +54 -0
  234. package/skills/integration/integration-nextjs-app-router/references/EXAMPLE.md +673 -0
  235. package/skills/integration/integration-nextjs-app-router/references/amplitude-quickstart.md +1845 -0
  236. package/skills/integration/integration-nextjs-app-router/references/basic-integration-1.0-begin.md +43 -0
  237. package/skills/integration/integration-nextjs-app-router/references/basic-integration-1.1-edit.md +35 -0
  238. package/skills/integration/integration-nextjs-app-router/references/basic-integration-1.2-revise.md +23 -0
  239. package/skills/integration/integration-nextjs-app-router/references/basic-integration-1.3-conclude.md +57 -0
  240. package/skills/integration/integration-nextjs-app-router/references/browser-sdk-2.md +4680 -0
  241. package/skills/integration/integration-nextjs-pages-router/SKILL.md +54 -0
  242. package/skills/integration/integration-nextjs-pages-router/references/EXAMPLE.md +735 -0
  243. package/skills/integration/integration-nextjs-pages-router/references/amplitude-quickstart.md +1845 -0
  244. package/skills/integration/integration-nextjs-pages-router/references/basic-integration-1.0-begin.md +43 -0
  245. package/skills/integration/integration-nextjs-pages-router/references/basic-integration-1.1-edit.md +35 -0
  246. package/skills/integration/integration-nextjs-pages-router/references/basic-integration-1.2-revise.md +23 -0
  247. package/skills/integration/integration-nextjs-pages-router/references/basic-integration-1.3-conclude.md +57 -0
  248. package/skills/integration/integration-nextjs-pages-router/references/browser-sdk-2.md +4680 -0
  249. package/skills/integration/integration-nuxt-3.6/SKILL.md +46 -0
  250. package/skills/integration/integration-nuxt-3.6/references/EXAMPLE.md +8422 -0
  251. package/skills/integration/integration-nuxt-3.6/references/amplitude-quickstart.md +1845 -0
  252. package/skills/integration/integration-nuxt-3.6/references/basic-integration-1.0-begin.md +43 -0
  253. package/skills/integration/integration-nuxt-3.6/references/basic-integration-1.1-edit.md +35 -0
  254. package/skills/integration/integration-nuxt-3.6/references/basic-integration-1.2-revise.md +23 -0
  255. package/skills/integration/integration-nuxt-3.6/references/basic-integration-1.3-conclude.md +57 -0
  256. package/skills/integration/integration-nuxt-3.6/references/browser-sdk-2.md +4680 -0
  257. package/skills/integration/integration-nuxt-4/SKILL.md +46 -0
  258. package/skills/integration/integration-nuxt-4/references/EXAMPLE.md +8670 -0
  259. package/skills/integration/integration-nuxt-4/references/amplitude-quickstart.md +1845 -0
  260. package/skills/integration/integration-nuxt-4/references/basic-integration-1.0-begin.md +43 -0
  261. package/skills/integration/integration-nuxt-4/references/basic-integration-1.1-edit.md +35 -0
  262. package/skills/integration/integration-nuxt-4/references/basic-integration-1.2-revise.md +23 -0
  263. package/skills/integration/integration-nuxt-4/references/basic-integration-1.3-conclude.md +57 -0
  264. package/skills/integration/integration-nuxt-4/references/browser-sdk-2.md +4680 -0
  265. package/skills/integration/integration-python/SKILL.md +53 -0
  266. package/skills/integration/integration-python/references/EXAMPLE.md +445 -0
  267. package/skills/integration/integration-python/references/amplitude-quickstart.md +1845 -0
  268. package/skills/integration/integration-python/references/basic-integration-1.0-begin.md +43 -0
  269. package/skills/integration/integration-python/references/basic-integration-1.1-edit.md +35 -0
  270. package/skills/integration/integration-python/references/basic-integration-1.2-revise.md +23 -0
  271. package/skills/integration/integration-python/references/basic-integration-1.3-conclude.md +57 -0
  272. package/skills/integration/integration-python/references/python.md +1424 -0
  273. package/skills/integration/integration-react-native/SKILL.md +49 -0
  274. package/skills/integration/integration-react-native/references/EXAMPLE.md +2253 -0
  275. package/skills/integration/integration-react-native/references/amplitude-quickstart.md +1845 -0
  276. package/skills/integration/integration-react-native/references/basic-integration-1.0-begin.md +43 -0
  277. package/skills/integration/integration-react-native/references/basic-integration-1.1-edit.md +35 -0
  278. package/skills/integration/integration-react-native/references/basic-integration-1.2-revise.md +23 -0
  279. package/skills/integration/integration-react-native/references/basic-integration-1.3-conclude.md +57 -0
  280. package/skills/integration/integration-react-native/references/react-native-sdk.md +2819 -0
  281. package/skills/integration/integration-react-react-router-6/SKILL.md +53 -0
  282. package/skills/integration/integration-react-react-router-6/references/EXAMPLE.md +570 -0
  283. package/skills/integration/integration-react-react-router-6/references/amplitude-quickstart.md +1845 -0
  284. package/skills/integration/integration-react-react-router-6/references/basic-integration-1.0-begin.md +43 -0
  285. package/skills/integration/integration-react-react-router-6/references/basic-integration-1.1-edit.md +35 -0
  286. package/skills/integration/integration-react-react-router-6/references/basic-integration-1.2-revise.md +23 -0
  287. package/skills/integration/integration-react-react-router-6/references/basic-integration-1.3-conclude.md +57 -0
  288. package/skills/integration/integration-react-react-router-6/references/browser-sdk-2.md +4680 -0
  289. package/skills/integration/integration-react-react-router-7-data/SKILL.md +53 -0
  290. package/skills/integration/integration-react-react-router-7-data/references/EXAMPLE.md +830 -0
  291. package/skills/integration/integration-react-react-router-7-data/references/amplitude-quickstart.md +1845 -0
  292. package/skills/integration/integration-react-react-router-7-data/references/basic-integration-1.0-begin.md +43 -0
  293. package/skills/integration/integration-react-react-router-7-data/references/basic-integration-1.1-edit.md +35 -0
  294. package/skills/integration/integration-react-react-router-7-data/references/basic-integration-1.2-revise.md +23 -0
  295. package/skills/integration/integration-react-react-router-7-data/references/basic-integration-1.3-conclude.md +57 -0
  296. package/skills/integration/integration-react-react-router-7-data/references/browser-sdk-2.md +4680 -0
  297. package/skills/integration/integration-react-react-router-7-declarative/SKILL.md +53 -0
  298. package/skills/integration/integration-react-react-router-7-declarative/references/EXAMPLE.md +609 -0
  299. package/skills/integration/integration-react-react-router-7-declarative/references/amplitude-quickstart.md +1845 -0
  300. package/skills/integration/integration-react-react-router-7-declarative/references/basic-integration-1.0-begin.md +43 -0
  301. package/skills/integration/integration-react-react-router-7-declarative/references/basic-integration-1.1-edit.md +35 -0
  302. package/skills/integration/integration-react-react-router-7-declarative/references/basic-integration-1.2-revise.md +23 -0
  303. package/skills/integration/integration-react-react-router-7-declarative/references/basic-integration-1.3-conclude.md +57 -0
  304. package/skills/integration/integration-react-react-router-7-declarative/references/browser-sdk-2.md +4680 -0
  305. package/skills/integration/integration-react-react-router-7-framework/SKILL.md +53 -0
  306. package/skills/integration/integration-react-react-router-7-framework/references/EXAMPLE.md +1081 -0
  307. package/skills/integration/integration-react-react-router-7-framework/references/amplitude-quickstart.md +1845 -0
  308. package/skills/integration/integration-react-react-router-7-framework/references/basic-integration-1.0-begin.md +43 -0
  309. package/skills/integration/integration-react-react-router-7-framework/references/basic-integration-1.1-edit.md +35 -0
  310. package/skills/integration/integration-react-react-router-7-framework/references/basic-integration-1.2-revise.md +23 -0
  311. package/skills/integration/integration-react-react-router-7-framework/references/basic-integration-1.3-conclude.md +57 -0
  312. package/skills/integration/integration-react-react-router-7-framework/references/browser-sdk-2.md +4680 -0
  313. package/skills/integration/integration-react-tanstack-router-code-based/SKILL.md +57 -0
  314. package/skills/integration/integration-react-tanstack-router-code-based/references/EXAMPLE.md +659 -0
  315. package/skills/integration/integration-react-tanstack-router-code-based/references/amplitude-quickstart.md +1845 -0
  316. package/skills/integration/integration-react-tanstack-router-code-based/references/basic-integration-1.0-begin.md +43 -0
  317. package/skills/integration/integration-react-tanstack-router-code-based/references/basic-integration-1.1-edit.md +35 -0
  318. package/skills/integration/integration-react-tanstack-router-code-based/references/basic-integration-1.2-revise.md +23 -0
  319. package/skills/integration/integration-react-tanstack-router-code-based/references/basic-integration-1.3-conclude.md +57 -0
  320. package/skills/integration/integration-react-tanstack-router-code-based/references/browser-sdk-2.md +4680 -0
  321. package/skills/integration/integration-react-tanstack-router-file-based/SKILL.md +57 -0
  322. package/skills/integration/integration-react-tanstack-router-file-based/references/EXAMPLE.md +777 -0
  323. package/skills/integration/integration-react-tanstack-router-file-based/references/amplitude-quickstart.md +1845 -0
  324. package/skills/integration/integration-react-tanstack-router-file-based/references/basic-integration-1.0-begin.md +43 -0
  325. package/skills/integration/integration-react-tanstack-router-file-based/references/basic-integration-1.1-edit.md +35 -0
  326. package/skills/integration/integration-react-tanstack-router-file-based/references/basic-integration-1.2-revise.md +23 -0
  327. package/skills/integration/integration-react-tanstack-router-file-based/references/basic-integration-1.3-conclude.md +57 -0
  328. package/skills/integration/integration-react-tanstack-router-file-based/references/browser-sdk-2.md +4680 -0
  329. package/skills/integration/integration-react-vite/SKILL.md +53 -0
  330. package/skills/integration/integration-react-vite/references/EXAMPLE.md +542 -0
  331. package/skills/integration/integration-react-vite/references/amplitude-quickstart.md +1845 -0
  332. package/skills/integration/integration-react-vite/references/basic-integration-1.0-begin.md +43 -0
  333. package/skills/integration/integration-react-vite/references/basic-integration-1.1-edit.md +35 -0
  334. package/skills/integration/integration-react-vite/references/basic-integration-1.2-revise.md +23 -0
  335. package/skills/integration/integration-react-vite/references/basic-integration-1.3-conclude.md +57 -0
  336. package/skills/integration/integration-react-vite/references/browser-sdk-2.md +4680 -0
  337. package/skills/integration/integration-ruby/SKILL.md +50 -0
  338. package/skills/integration/integration-ruby/references/EXAMPLE.md +420 -0
  339. package/skills/integration/integration-ruby/references/amplitude-quickstart.md +1845 -0
  340. package/skills/integration/integration-ruby/references/analytics.md +1778 -0
  341. package/skills/integration/integration-ruby/references/basic-integration-1.0-begin.md +43 -0
  342. package/skills/integration/integration-ruby/references/basic-integration-1.1-edit.md +35 -0
  343. package/skills/integration/integration-ruby/references/basic-integration-1.2-revise.md +23 -0
  344. package/skills/integration/integration-ruby/references/basic-integration-1.3-conclude.md +57 -0
  345. package/skills/integration/integration-ruby-on-rails/SKILL.md +55 -0
  346. package/skills/integration/integration-ruby-on-rails/references/EXAMPLE.md +1013 -0
  347. package/skills/integration/integration-ruby-on-rails/references/amplitude-quickstart.md +1845 -0
  348. package/skills/integration/integration-ruby-on-rails/references/analytics.md +1778 -0
  349. package/skills/integration/integration-ruby-on-rails/references/basic-integration-1.0-begin.md +43 -0
  350. package/skills/integration/integration-ruby-on-rails/references/basic-integration-1.1-edit.md +35 -0
  351. package/skills/integration/integration-ruby-on-rails/references/basic-integration-1.2-revise.md +23 -0
  352. package/skills/integration/integration-ruby-on-rails/references/basic-integration-1.3-conclude.md +57 -0
  353. package/skills/integration/integration-sveltekit/SKILL.md +47 -0
  354. package/skills/integration/integration-sveltekit/references/EXAMPLE.md +14121 -0
  355. package/skills/integration/integration-sveltekit/references/amplitude-quickstart.md +1845 -0
  356. package/skills/integration/integration-sveltekit/references/basic-integration-1.0-begin.md +43 -0
  357. package/skills/integration/integration-sveltekit/references/basic-integration-1.1-edit.md +35 -0
  358. package/skills/integration/integration-sveltekit/references/basic-integration-1.2-revise.md +23 -0
  359. package/skills/integration/integration-sveltekit/references/basic-integration-1.3-conclude.md +57 -0
  360. package/skills/integration/integration-sveltekit/references/browser-sdk-2.md +4680 -0
  361. package/skills/integration/integration-swift/SKILL.md +49 -0
  362. package/skills/integration/integration-swift/references/EXAMPLE.md +660 -0
  363. package/skills/integration/integration-swift/references/amplitude-quickstart.md +1845 -0
  364. package/skills/integration/integration-swift/references/analytics.md +1778 -0
  365. package/skills/integration/integration-swift/references/basic-integration-1.0-begin.md +43 -0
  366. package/skills/integration/integration-swift/references/basic-integration-1.1-edit.md +35 -0
  367. package/skills/integration/integration-swift/references/basic-integration-1.2-revise.md +23 -0
  368. package/skills/integration/integration-swift/references/basic-integration-1.3-conclude.md +57 -0
  369. package/skills/integration/integration-tanstack-start/SKILL.md +58 -0
  370. package/skills/integration/integration-tanstack-start/references/EXAMPLE.md +998 -0
  371. package/skills/integration/integration-tanstack-start/references/amplitude-quickstart.md +1845 -0
  372. package/skills/integration/integration-tanstack-start/references/basic-integration-1.0-begin.md +43 -0
  373. package/skills/integration/integration-tanstack-start/references/basic-integration-1.1-edit.md +35 -0
  374. package/skills/integration/integration-tanstack-start/references/basic-integration-1.2-revise.md +23 -0
  375. package/skills/integration/integration-tanstack-start/references/basic-integration-1.3-conclude.md +57 -0
  376. package/skills/integration/integration-tanstack-start/references/browser-sdk-2.md +4680 -0
  377. package/skills/integration/integration-vue-3/SKILL.md +46 -0
  378. package/skills/integration/integration-vue-3/references/EXAMPLE.md +846 -0
  379. package/skills/integration/integration-vue-3/references/amplitude-quickstart.md +1845 -0
  380. package/skills/integration/integration-vue-3/references/basic-integration-1.0-begin.md +43 -0
  381. package/skills/integration/integration-vue-3/references/basic-integration-1.1-edit.md +35 -0
  382. package/skills/integration/integration-vue-3/references/basic-integration-1.2-revise.md +23 -0
  383. package/skills/integration/integration-vue-3/references/basic-integration-1.3-conclude.md +57 -0
  384. package/skills/integration/integration-vue-3/references/browser-sdk-2.md +4680 -0
  385. package/skills/taxonomy/amplitude-quickstart-taxonomy-agent/SKILL.md +228 -0
  386. package/dist/src/ui/tui/components/TitleBar.d.ts +0 -8
  387. package/dist/src/ui/tui/components/TitleBar.js +0 -27
  388. package/dist/src/ui/tui/primitives/KagiSmallWebViewer.d.ts +0 -7
  389. package/dist/src/ui/tui/primitives/KagiSmallWebViewer.js +0 -101
  390. package/dist/src/utils/anthropic-status.d.ts +0 -17
  391. package/dist/src/utils/anthropic-status.js +0 -51
@@ -0,0 +1,1977 @@
1
+ # Amplitude Android Example Project
2
+
3
+ Repository: https://github.com/amplitude/context-hub
4
+ Path: basics/android
5
+
6
+ ---
7
+
8
+ ## README.md
9
+
10
+ # Amplitude Android example
11
+
12
+ This is an Android example demonstrating Amplitude integration with product analytics using Kotlin and Jetpack Compose.
13
+
14
+ This example uses the Amplitude Android SDK (`analytics-android`) to provide analytics integration with simplified configuration.
15
+
16
+ ## Features
17
+
18
+ - **Product Analytics**: Track user events and behaviors
19
+ - **User Authentication**: Demo login system with Amplitude user identification
20
+ - **Event Tracking**: Examples of custom event tracking throughout the app
21
+
22
+ ## Getting Started
23
+
24
+ ### 1. Prerequisites
25
+
26
+ - Android Studio (latest stable version)
27
+ - Android SDK (API level 24 or higher)
28
+ - JDK 11 or higher
29
+ - Gradle 8.0 or higher
30
+ - An [Amplitude account](https://amplitude.com/signup)
31
+
32
+ ### 2. Configure Environment Variables
33
+
34
+ The Amplitude configuration is stored in `local.properties` (this file is gitignored):
35
+
36
+ ```properties
37
+ # Amplitude configuration
38
+ amplitude.apiKey=your_amplitude_api_key
39
+ ```
40
+
41
+ Alternatively, you can configure Amplitude in your `build.gradle` file:
42
+
43
+ ```gradle
44
+ android {
45
+ defaultConfig {
46
+ buildConfigField "String", "AMPLITUDE_API_KEY", "\"your_amplitude_api_key\""
47
+ }
48
+ }
49
+ ```
50
+
51
+ Get your Amplitude API key from your [Amplitude project settings](https://app.amplitude.com/).
52
+
53
+ ### 3. Build and Run
54
+
55
+ 1. Open the project in Android Studio
56
+ 2. Sync Gradle files
57
+ 3. Run the app on an emulator or physical device
58
+
59
+ ## Project Structure
60
+
61
+ ```
62
+ ├── app/
63
+ │ ├── src/
64
+ │ │ ├── main/
65
+ │ │ │ ├── java/com/example/amplitude/
66
+ │ │ │ │ ├── BurritoApplication.kt # Application class with Amplitude initialization
67
+ │ │ │ │ ├── MainActivity.kt # Main activity
68
+ │ │ │ │ ├── ui/
69
+ │ │ │ │ │ ├── screens/
70
+ │ │ │ │ │ │ ├── HomeScreen.kt # Home screen with login
71
+ │ │ │ │ │ │ ├── BurritoScreen.kt # Demo feature screen with event tracking
72
+ │ │ │ │ │ │ └── ProfileScreen.kt # User profile screen
73
+ │ │ │ │ │ └── components/ # Reusable UI components
74
+ │ │ │ ├── res/ # Resources (layouts, strings, etc.)
75
+ │ │ │ └── AndroidManifest.xml # App manifest
76
+ │ │ └── test/ # Unit tests
77
+ │ └── build.gradle # App-level Gradle configuration
78
+ ├── build.gradle # Project-level Gradle configuration
79
+ ├── settings.gradle # Gradle settings
80
+ └── local.properties # Local configuration (gitignored)
81
+ ```
82
+
83
+ ## Key Integration Points
84
+
85
+ ### Application Initialization (BurritoApplication.kt)
86
+
87
+ Amplitude is initialized in the `Application` class to ensure it's available throughout the app lifecycle:
88
+
89
+ ```kotlin
90
+ class BurritoApplication : Application() {
91
+ override fun onCreate() {
92
+ super.onCreate()
93
+
94
+ // Initialize Amplitude early in Application lifecycle
95
+ Amplitude.getInstance().initialize(
96
+ this,
97
+ BuildConfig.AMPLITUDE_API_KEY
98
+ )
99
+ }
100
+ }
101
+ ```
102
+
103
+ **Key Points:**
104
+ - Amplitude is initialized in `onCreate()` to ensure it's initialized as early as possible
105
+ - Configuration is loaded from `BuildConfig` (set in `build.gradle`)
106
+ - The Application class must be registered in `AndroidManifest.xml`
107
+
108
+ ### User Identification (AuthViewModel.kt)
109
+
110
+ Users are identified when they log in:
111
+
112
+ ```kotlin
113
+ fun login(username: String) {
114
+ Amplitude.getInstance().setUserId(username)
115
+ Amplitude.getInstance().track("User Logged In")
116
+ }
117
+ ```
118
+
119
+ **Key Points:**
120
+ - `setUserId()` is called once when the user logs in or signs up
121
+ - Events are tracked using `track()` with event names and properties
122
+
123
+ ### Event Tracking (AuthViewModel.kt)
124
+
125
+ Custom events are tracked throughout the app:
126
+
127
+ ```kotlin
128
+ val eventProperties = mapOf(
129
+ "total_considerations" to updatedUser.burritoConsiderations,
130
+ "username" to updatedUser.username
131
+ )
132
+ Amplitude.getInstance().track("Burrito Considered", eventProperties)
133
+ ```
134
+
135
+ **Key Points:**
136
+ - Events are tracked with `track()` method
137
+ - Event properties provide context about the event
138
+ - Properties can be strings, numbers, booleans, or dates
139
+
140
+ ## Gradle Configuration
141
+
142
+ ### App-level build.gradle
143
+
144
+ ```gradle
145
+ android {
146
+ defaultConfig {
147
+ // Amplitude configuration
148
+ buildConfigField "String", "AMPLITUDE_API_KEY", "\"${project.findProperty("amplitude.apiKey") ?: ""}\""
149
+ }
150
+ }
151
+
152
+ dependencies {
153
+ // Amplitude Android SDK
154
+ implementation 'com.amplitude:analytics-android:1.+'
155
+
156
+ // Other dependencies...
157
+ }
158
+ ```
159
+
160
+ ## Best Practices
161
+
162
+ 1. **Initialize Early**: Initialize Amplitude in your `Application.onCreate()` method
163
+ 2. **Identify Once**: Call `setUserId()` once when the user logs in or signs up
164
+ 3. **Use Meaningful Event Names**: Use clear, descriptive event names (e.g., `User Logged In` instead of `login`)
165
+ 4. **Include Context**: Add relevant properties to events for better analysis
166
+ 5. **Test in Development**: Use a separate Amplitude project for development/testing
167
+ 6. **Respect Privacy**: Be mindful of PII (Personally Identifiable Information) in events and properties
168
+
169
+ ## Learn More
170
+
171
+ - [Amplitude Documentation](https://www.docs.developers.amplitude.com/)
172
+ - [Android Documentation](https://developer.android.com)
173
+ - [Amplitude Android SDK](https://github.com/amplitude/Amplitude-Kotlin)
174
+
175
+ ---
176
+
177
+ ## app/proguard-rules.pro
178
+
179
+ ```pro
180
+ # Add project specific ProGuard rules here.
181
+ # You can control the set of applied configuration files using the
182
+ # proguardFiles setting in build.gradle.
183
+ #
184
+ # For more details, see
185
+ # http://developer.android.com/guide/developing/tools/proguard.html
186
+
187
+ # If your project uses WebView with JS, uncomment the following
188
+ # and specify the fully qualified class name to the JavaScript interface
189
+ # class:
190
+ #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
191
+ # public *;
192
+ #}
193
+
194
+ # Uncomment this to preserve the line number information for
195
+ # debugging stack traces.
196
+ #-keepattributes SourceFile,LineNumberTable
197
+
198
+ # If you keep the line number information, uncomment this to
199
+ # hide the original source file name.
200
+ #-renamesourcefileattribute SourceFile
201
+ ```
202
+
203
+ ---
204
+
205
+ ## app/src/main/AndroidManifest.xml
206
+
207
+ ```xml
208
+ <?xml version="1.0" encoding="utf-8"?>
209
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
210
+ xmlns:tools="http://schemas.android.com/tools">
211
+
212
+ <uses-permission android:name="android.permission.INTERNET" />
213
+
214
+ <application
215
+ android:name=".BurritoApplication"
216
+ android:allowBackup="true"
217
+ android:dataExtractionRules="@xml/data_extraction_rules"
218
+ android:fullBackupContent="@xml/backup_rules"
219
+ android:icon="@mipmap/ic_launcher"
220
+ android:label="@string/app_name"
221
+ android:roundIcon="@mipmap/ic_launcher_round"
222
+ android:supportsRtl="true"
223
+ android:theme="@style/Theme.Amplitude">
224
+ <!-- We have to export the MainActivity to be able to start it from the system launcher.
225
+ Ignores added for semgrep. -->
226
+ <activity
227
+ android:name=".MainActivity"
228
+ android:exported="true"
229
+ android:label="@string/app_name"
230
+ android:theme="@style/Theme.Amplitude"
231
+ tools:ignore="ExportedActivity">
232
+ <intent-filter>
233
+ <action android:name="android.intent.action.MAIN" />
234
+
235
+ <category android:name="android.intent.category.LAUNCHER" />
236
+ </intent-filter>
237
+ </activity>
238
+ </application>
239
+
240
+ </manifest>
241
+ ```
242
+
243
+ ---
244
+
245
+ ## app/src/main/java/com/example/amplitude/BurritoApp.kt
246
+
247
+ ```kt
248
+ package com.example.amplitude
249
+
250
+ import android.app.Application
251
+ import com.amplitude.android.Amplitude
252
+ import com.amplitude.android.Configuration
253
+
254
+ class BurritoApplication : Application() {
255
+ lateinit var amplitude: Amplitude
256
+
257
+ override fun onCreate() {
258
+ super.onCreate()
259
+
260
+ // Initialize Amplitude early in Application lifecycle
261
+ amplitude = Amplitude(
262
+ Configuration(
263
+ apiKey = BuildConfig.AMPLITUDE_API_KEY,
264
+ context = applicationContext
265
+ )
266
+ )
267
+ }
268
+ }
269
+
270
+ ```
271
+
272
+ ---
273
+
274
+ ## app/src/main/java/com/example/amplitude/data/User.kt
275
+
276
+ ```kt
277
+ package com.example.amplitude.data
278
+
279
+ data class User(
280
+ val username: String,
281
+ val burritoConsiderations: Int = 0
282
+ )
283
+
284
+ ```
285
+
286
+ ---
287
+
288
+ ## app/src/main/java/com/example/amplitude/data/UserRepository.kt
289
+
290
+ ```kt
291
+ package com.example.amplitude.data
292
+
293
+ import android.content.Context
294
+ import android.content.SharedPreferences
295
+ import org.json.JSONObject
296
+
297
+ class UserRepository(context: Context) {
298
+
299
+ private val prefs: SharedPreferences = context.getSharedPreferences(
300
+ PREFS_NAME, Context.MODE_PRIVATE
301
+ )
302
+
303
+ companion object {
304
+ private const val PREFS_NAME = "burrito_app_prefs"
305
+ private const val KEY_CURRENT_USERNAME = "current_username"
306
+ private const val KEY_USER_DATA_PREFIX = "user_data_"
307
+ }
308
+
309
+ fun getCurrentUsername(): String? {
310
+ return prefs.getString(KEY_CURRENT_USERNAME, null)
311
+ }
312
+
313
+ fun getUser(username: String): User? {
314
+ val json = prefs.getString("$KEY_USER_DATA_PREFIX$username", null) ?: return null
315
+ return try {
316
+ val obj = JSONObject(json)
317
+ User(
318
+ username = obj.getString("username"),
319
+ burritoConsiderations = obj.getInt("burritoConsiderations")
320
+ )
321
+ } catch (e: Exception) {
322
+ null
323
+ }
324
+ }
325
+
326
+ fun saveUser(user: User) {
327
+ val json = JSONObject().apply {
328
+ put("username", user.username)
329
+ put("burritoConsiderations", user.burritoConsiderations)
330
+ }.toString()
331
+
332
+ prefs.edit()
333
+ .putString("$KEY_USER_DATA_PREFIX${user.username}", json)
334
+ .putString(KEY_CURRENT_USERNAME, user.username)
335
+ .apply()
336
+ }
337
+
338
+ fun clearCurrentUser() {
339
+ prefs.edit()
340
+ .remove(KEY_CURRENT_USERNAME)
341
+ .apply()
342
+ }
343
+
344
+ fun getCurrentUser(): User? {
345
+ val username = getCurrentUsername() ?: return null
346
+ return getUser(username)
347
+ }
348
+ }
349
+
350
+ ```
351
+
352
+ ---
353
+
354
+ ## app/src/main/java/com/example/amplitude/MainActivity.kt
355
+
356
+ ```kt
357
+ package com.example.amplitude
358
+
359
+ import android.os.Bundle
360
+ import androidx.activity.ComponentActivity
361
+ import androidx.activity.compose.setContent
362
+ import androidx.activity.enableEdgeToEdge
363
+ import androidx.compose.foundation.background
364
+ import androidx.compose.foundation.layout.Box
365
+ import androidx.compose.foundation.layout.fillMaxSize
366
+ import androidx.compose.foundation.layout.padding
367
+ import androidx.compose.material3.Scaffold
368
+ import androidx.compose.runtime.Composable
369
+ import androidx.compose.runtime.collectAsState
370
+ import androidx.compose.runtime.getValue
371
+ import androidx.compose.ui.Modifier
372
+ import androidx.lifecycle.viewmodel.compose.viewModel
373
+ import androidx.navigation.compose.currentBackStackEntryAsState
374
+ import androidx.navigation.compose.rememberNavController
375
+ import com.example.amplitude.navigation.NavGraph
376
+ import com.example.amplitude.navigation.Screen
377
+ import com.example.amplitude.ui.components.AppHeader
378
+ import com.example.amplitude.ui.components.BottomNavBar
379
+ import com.example.amplitude.ui.theme.BackgroundGray
380
+ import com.example.amplitude.ui.theme.AmplitudeTheme
381
+ import com.example.amplitude.viewmodel.AuthViewModel
382
+
383
+ class MainActivity : ComponentActivity() {
384
+ override fun onCreate(savedInstanceState: Bundle?) {
385
+ super.onCreate(savedInstanceState)
386
+ enableEdgeToEdge()
387
+ setContent {
388
+ AmplitudeTheme {
389
+ BurritoApp()
390
+ }
391
+ }
392
+ }
393
+ }
394
+
395
+ @Composable
396
+ fun BurritoApp() {
397
+ val navController = rememberNavController()
398
+ val viewModel: AuthViewModel = viewModel()
399
+
400
+ val isAuthenticated by viewModel.isAuthenticated.collectAsState()
401
+ val currentUser by viewModel.currentUser.collectAsState()
402
+
403
+ val navBackStackEntry by navController.currentBackStackEntryAsState()
404
+ val currentRoute = navBackStackEntry?.destination?.route
405
+
406
+ Scaffold(
407
+ modifier = Modifier.fillMaxSize(),
408
+ topBar = {
409
+ AppHeader(
410
+ isAuthenticated = isAuthenticated,
411
+ username = currentUser?.username,
412
+ currentRoute = currentRoute,
413
+ onNavigate = { route ->
414
+ navController.navigate(route) {
415
+ popUpTo(Screen.Home.route)
416
+ launchSingleTop = true
417
+ }
418
+ },
419
+ onLogout = {
420
+ viewModel.logout()
421
+ navController.navigate(Screen.Home.route) {
422
+ popUpTo(Screen.Home.route) { inclusive = true }
423
+ }
424
+ }
425
+ )
426
+ },
427
+ bottomBar = {
428
+ BottomNavBar(
429
+ isAuthenticated = isAuthenticated,
430
+ currentRoute = currentRoute,
431
+ onNavigate = { route ->
432
+ navController.navigate(route) {
433
+ popUpTo(Screen.Home.route)
434
+ launchSingleTop = true
435
+ }
436
+ }
437
+ )
438
+ },
439
+ containerColor = BackgroundGray
440
+ ) { innerPadding ->
441
+ Box(
442
+ modifier = Modifier
443
+ .fillMaxSize()
444
+ .background(BackgroundGray)
445
+ .padding(innerPadding)
446
+ ) {
447
+ NavGraph(
448
+ navController = navController,
449
+ viewModel = viewModel
450
+ )
451
+ }
452
+ }
453
+ }
454
+
455
+ ```
456
+
457
+ ---
458
+
459
+ ## app/src/main/java/com/example/amplitude/navigation/NavGraph.kt
460
+
461
+ ```kt
462
+ package com.example.amplitude.navigation
463
+
464
+ import androidx.compose.runtime.Composable
465
+ import androidx.compose.runtime.LaunchedEffect
466
+ import androidx.compose.runtime.collectAsState
467
+ import androidx.compose.runtime.getValue
468
+ import androidx.navigation.NavHostController
469
+ import androidx.navigation.compose.NavHost
470
+ import androidx.navigation.compose.composable
471
+ import com.example.amplitude.ui.screens.BurritoScreen
472
+ import com.example.amplitude.ui.screens.HomeScreen
473
+ import com.example.amplitude.ui.screens.ProfileScreen
474
+ import com.example.amplitude.viewmodel.AuthViewModel
475
+
476
+ sealed class Screen(val route: String) {
477
+ object Home : Screen("home")
478
+ object Burrito : Screen("burrito")
479
+ object Profile : Screen("profile")
480
+ }
481
+
482
+ @Composable
483
+ fun NavGraph(
484
+ navController: NavHostController,
485
+ viewModel: AuthViewModel
486
+ ) {
487
+ val isAuthenticated by viewModel.isAuthenticated.collectAsState()
488
+ val currentUser by viewModel.currentUser.collectAsState()
489
+
490
+ NavHost(
491
+ navController = navController,
492
+ startDestination = Screen.Home.route
493
+ ) {
494
+ composable(Screen.Home.route) {
495
+ HomeScreen(
496
+ isAuthenticated = isAuthenticated,
497
+ username = currentUser?.username,
498
+ onLogin = { username -> viewModel.login(username) }
499
+ )
500
+ }
501
+
502
+ composable(Screen.Burrito.route) {
503
+ if (!isAuthenticated) {
504
+ LaunchedEffect(Unit) {
505
+ navController.navigate(Screen.Home.route) {
506
+ popUpTo(Screen.Home.route) { inclusive = true }
507
+ }
508
+ }
509
+ } else {
510
+ BurritoScreen(
511
+ burritoCount = currentUser?.burritoConsiderations ?: 0,
512
+ onConsiderBurrito = { viewModel.incrementBurritoCount() }
513
+ )
514
+ }
515
+ }
516
+
517
+ composable(Screen.Profile.route) {
518
+ if (!isAuthenticated) {
519
+ LaunchedEffect(Unit) {
520
+ navController.navigate(Screen.Home.route) {
521
+ popUpTo(Screen.Home.route) { inclusive = true }
522
+ }
523
+ }
524
+ } else {
525
+ ProfileScreen(
526
+ username = currentUser?.username ?: "",
527
+ burritoCount = currentUser?.burritoConsiderations ?: 0
528
+ )
529
+ }
530
+ }
531
+ }
532
+ }
533
+
534
+ ```
535
+
536
+ ---
537
+
538
+ ## app/src/main/java/com/example/amplitude/ui/components/AppHeader.kt
539
+
540
+ ```kt
541
+ package com.example.amplitude.ui.components
542
+
543
+ import androidx.compose.foundation.background
544
+ import androidx.compose.foundation.layout.Arrangement
545
+ import androidx.compose.foundation.layout.Box
546
+ import androidx.compose.foundation.layout.PaddingValues
547
+ import androidx.compose.foundation.layout.Row
548
+ import androidx.compose.foundation.layout.fillMaxWidth
549
+ import androidx.compose.foundation.layout.padding
550
+ import androidx.compose.foundation.shape.RoundedCornerShape
551
+ import androidx.compose.material3.Button
552
+ import androidx.compose.material3.ButtonDefaults
553
+ import androidx.compose.material3.Text
554
+ import androidx.compose.runtime.Composable
555
+ import androidx.compose.ui.Alignment
556
+ import androidx.compose.ui.Modifier
557
+ import androidx.compose.ui.unit.dp
558
+ import androidx.compose.ui.unit.sp
559
+ import com.example.amplitude.ui.theme.DarkHeader
560
+ import com.example.amplitude.ui.theme.ErrorRed
561
+ import com.example.amplitude.ui.theme.White
562
+
563
+ @Composable
564
+ fun AppHeader(
565
+ isAuthenticated: Boolean,
566
+ username: String?,
567
+ currentRoute: String?,
568
+ onNavigate: (String) -> Unit,
569
+ onLogout: () -> Unit
570
+ ) {
571
+ Box(
572
+ modifier = Modifier
573
+ .fillMaxWidth()
574
+ .background(DarkHeader)
575
+ .padding(horizontal = 16.dp, vertical = 12.dp)
576
+ ) {
577
+ Row(
578
+ modifier = Modifier.fillMaxWidth(),
579
+ horizontalArrangement = Arrangement.SpaceBetween,
580
+ verticalAlignment = Alignment.CenterVertically
581
+ ) {
582
+ // App title
583
+ Text(
584
+ text = "Burrito App",
585
+ color = White,
586
+ fontSize = 18.sp
587
+ )
588
+
589
+ // User section (right side)
590
+ if (isAuthenticated && username != null) {
591
+ Row(
592
+ horizontalArrangement = Arrangement.spacedBy(12.dp),
593
+ verticalAlignment = Alignment.CenterVertically
594
+ ) {
595
+ Text(
596
+ text = username,
597
+ color = White,
598
+ fontSize = 14.sp
599
+ )
600
+
601
+ Button(
602
+ onClick = onLogout,
603
+ colors = ButtonDefaults.buttonColors(
604
+ containerColor = ErrorRed
605
+ ),
606
+ shape = RoundedCornerShape(4.dp),
607
+ contentPadding = PaddingValues(horizontal = 12.dp, vertical = 6.dp)
608
+ ) {
609
+ Text(
610
+ text = "Logout",
611
+ color = White,
612
+ fontSize = 14.sp
613
+ )
614
+ }
615
+ }
616
+ }
617
+ }
618
+ }
619
+ }
620
+
621
+ ```
622
+
623
+ ---
624
+
625
+ ## app/src/main/java/com/example/amplitude/ui/components/BottomNavBar.kt
626
+
627
+ ```kt
628
+ package com.example.amplitude.ui.components
629
+
630
+ import androidx.compose.foundation.layout.size
631
+ import androidx.compose.material.icons.Icons
632
+ import androidx.compose.material.icons.filled.Home
633
+ import androidx.compose.material.icons.filled.Person
634
+ import androidx.compose.material.icons.outlined.Home
635
+ import androidx.compose.material.icons.outlined.Person
636
+ import androidx.compose.material3.Icon
637
+ import androidx.compose.material3.NavigationBar
638
+ import androidx.compose.material3.NavigationBarItem
639
+ import androidx.compose.material3.NavigationBarItemDefaults
640
+ import androidx.compose.material3.Text
641
+ import androidx.compose.runtime.Composable
642
+ import androidx.compose.ui.Modifier
643
+ import androidx.compose.ui.graphics.vector.ImageVector
644
+ import androidx.compose.ui.unit.dp
645
+ import androidx.compose.ui.unit.sp
646
+ import com.example.amplitude.navigation.Screen
647
+ import com.example.amplitude.ui.theme.PrimaryBlue
648
+ import com.example.amplitude.ui.theme.TextGray
649
+ import com.example.amplitude.ui.theme.White
650
+
651
+ sealed class BottomNavItem(
652
+ val route: String,
653
+ val label: String,
654
+ val selectedIcon: ImageVector?,
655
+ val unselectedIcon: ImageVector?
656
+ ) {
657
+ object Home : BottomNavItem(
658
+ route = Screen.Home.route,
659
+ label = "Home",
660
+ selectedIcon = Icons.Filled.Home,
661
+ unselectedIcon = Icons.Outlined.Home
662
+ )
663
+
664
+ object Burrito : BottomNavItem(
665
+ route = Screen.Burrito.route,
666
+ label = "Burrito",
667
+ selectedIcon = null, // We'll use a custom icon or emoji
668
+ unselectedIcon = null
669
+ )
670
+
671
+ object Profile : BottomNavItem(
672
+ route = Screen.Profile.route,
673
+ label = "Profile",
674
+ selectedIcon = Icons.Filled.Person,
675
+ unselectedIcon = Icons.Outlined.Person
676
+ )
677
+ }
678
+
679
+ @Composable
680
+ fun BottomNavBar(
681
+ isAuthenticated: Boolean,
682
+ currentRoute: String?,
683
+ onNavigate: (String) -> Unit
684
+ ) {
685
+ val items = if (isAuthenticated) {
686
+ listOf(BottomNavItem.Home, BottomNavItem.Burrito, BottomNavItem.Profile)
687
+ } else {
688
+ listOf(BottomNavItem.Home)
689
+ }
690
+
691
+ NavigationBar(
692
+ containerColor = White
693
+ ) {
694
+ items.forEach { item ->
695
+ val selected = currentRoute == item.route
696
+
697
+ NavigationBarItem(
698
+ selected = selected,
699
+ onClick = { onNavigate(item.route) },
700
+ icon = {
701
+ if (item.selectedIcon != null && item.unselectedIcon != null) {
702
+ Icon(
703
+ imageVector = if (selected) item.selectedIcon else item.unselectedIcon,
704
+ contentDescription = item.label,
705
+ modifier = Modifier.size(24.dp)
706
+ )
707
+ } else {
708
+ // For Burrito, use text emoji as icon
709
+ Text(
710
+ text = "🌯",
711
+ fontSize = 24.sp
712
+ )
713
+ }
714
+ },
715
+ label = {
716
+ Text(
717
+ text = item.label,
718
+ fontSize = 12.sp
719
+ )
720
+ },
721
+ colors = NavigationBarItemDefaults.colors(
722
+ selectedIconColor = PrimaryBlue,
723
+ selectedTextColor = PrimaryBlue,
724
+ unselectedIconColor = TextGray,
725
+ unselectedTextColor = TextGray,
726
+ indicatorColor = PrimaryBlue.copy(alpha = 0.1f)
727
+ )
728
+ )
729
+ }
730
+ }
731
+ }
732
+
733
+ ```
734
+
735
+ ---
736
+
737
+ ## app/src/main/java/com/example/amplitude/ui/components/StatsCard.kt
738
+
739
+ ```kt
740
+ package com.example.amplitude.ui.components
741
+
742
+ import androidx.compose.foundation.background
743
+ import androidx.compose.foundation.layout.Column
744
+ import androidx.compose.foundation.layout.Spacer
745
+ import androidx.compose.foundation.layout.fillMaxWidth
746
+ import androidx.compose.foundation.layout.height
747
+ import androidx.compose.foundation.layout.padding
748
+ import androidx.compose.foundation.shape.RoundedCornerShape
749
+ import androidx.compose.material3.Text
750
+ import androidx.compose.runtime.Composable
751
+ import androidx.compose.ui.Modifier
752
+ import androidx.compose.ui.text.font.FontWeight
753
+ import androidx.compose.ui.unit.dp
754
+ import androidx.compose.ui.unit.sp
755
+ import com.example.amplitude.ui.theme.LightGray
756
+ import com.example.amplitude.ui.theme.TextDark
757
+ import com.example.amplitude.ui.theme.TextGray
758
+
759
+ @Composable
760
+ fun StatsCard(
761
+ title: String,
762
+ value: String,
763
+ modifier: Modifier = Modifier
764
+ ) {
765
+ Column(
766
+ modifier = modifier
767
+ .fillMaxWidth()
768
+ .background(
769
+ color = LightGray,
770
+ shape = RoundedCornerShape(4.dp)
771
+ )
772
+ .padding(16.dp)
773
+ ) {
774
+ Text(
775
+ text = title,
776
+ color = TextGray,
777
+ fontSize = 14.sp
778
+ )
779
+ Spacer(modifier = Modifier.height(4.dp))
780
+ Text(
781
+ text = value,
782
+ color = TextDark,
783
+ fontSize = 24.sp,
784
+ fontWeight = FontWeight.Bold
785
+ )
786
+ }
787
+ }
788
+
789
+ ```
790
+
791
+ ---
792
+
793
+ ## app/src/main/java/com/example/amplitude/ui/screens/BurritoScreen.kt
794
+
795
+ ```kt
796
+ package com.example.amplitude.ui.screens
797
+
798
+ import androidx.compose.foundation.background
799
+ import androidx.compose.foundation.layout.Box
800
+ import androidx.compose.foundation.layout.Column
801
+ import androidx.compose.foundation.layout.Spacer
802
+ import androidx.compose.foundation.layout.fillMaxSize
803
+ import androidx.compose.foundation.layout.fillMaxWidth
804
+ import androidx.compose.foundation.layout.height
805
+ import androidx.compose.foundation.layout.padding
806
+ import androidx.compose.foundation.layout.widthIn
807
+ import androidx.compose.foundation.rememberScrollState
808
+ import androidx.compose.foundation.shape.RoundedCornerShape
809
+ import androidx.compose.foundation.verticalScroll
810
+ import androidx.compose.material3.Button
811
+ import androidx.compose.material3.ButtonDefaults
812
+ import androidx.compose.material3.Text
813
+ import androidx.compose.runtime.Composable
814
+ import androidx.compose.runtime.LaunchedEffect
815
+ import androidx.compose.runtime.getValue
816
+ import androidx.compose.runtime.mutableStateOf
817
+ import androidx.compose.runtime.remember
818
+ import androidx.compose.runtime.setValue
819
+ import androidx.compose.ui.Alignment
820
+ import androidx.compose.ui.Modifier
821
+ import androidx.compose.ui.draw.shadow
822
+ import androidx.compose.ui.text.font.FontWeight
823
+ import androidx.compose.ui.text.style.TextAlign
824
+ import androidx.compose.ui.unit.dp
825
+ import androidx.compose.ui.unit.sp
826
+ import com.example.amplitude.ui.components.StatsCard
827
+ import com.example.amplitude.ui.theme.BackgroundGray
828
+ import com.example.amplitude.ui.theme.SuccessGreen
829
+ import com.example.amplitude.ui.theme.TextDark
830
+ import com.example.amplitude.ui.theme.TextGray
831
+ import com.example.amplitude.ui.theme.White
832
+ import kotlinx.coroutines.delay
833
+
834
+ @Composable
835
+ fun BurritoScreen(
836
+ burritoCount: Int,
837
+ onConsiderBurrito: () -> Unit
838
+ ) {
839
+ var showSuccess by remember { mutableStateOf(false) }
840
+
841
+ LaunchedEffect(showSuccess) {
842
+ if (showSuccess) {
843
+ delay(2000)
844
+ showSuccess = false
845
+ }
846
+ }
847
+
848
+ Box(
849
+ modifier = Modifier
850
+ .fillMaxSize()
851
+ .background(BackgroundGray)
852
+ .padding(horizontal = 16.dp)
853
+ .verticalScroll(rememberScrollState()),
854
+ contentAlignment = Alignment.TopCenter
855
+ ) {
856
+ Column(
857
+ modifier = Modifier
858
+ .widthIn(max = 600.dp)
859
+ .padding(vertical = 16.dp),
860
+ horizontalAlignment = Alignment.CenterHorizontally
861
+ ) {
862
+ // Main content card
863
+ Column(
864
+ modifier = Modifier
865
+ .fillMaxWidth()
866
+ .shadow(
867
+ elevation = 4.dp,
868
+ shape = RoundedCornerShape(8.dp),
869
+ ambientColor = TextDark.copy(alpha = 0.1f),
870
+ spotColor = TextDark.copy(alpha = 0.1f)
871
+ )
872
+ .background(
873
+ color = White,
874
+ shape = RoundedCornerShape(8.dp)
875
+ )
876
+ .padding(24.dp),
877
+ horizontalAlignment = Alignment.CenterHorizontally
878
+ ) {
879
+ Text(
880
+ text = "Burrito consideration zone",
881
+ fontSize = 24.sp,
882
+ fontWeight = FontWeight.SemiBold,
883
+ color = TextDark,
884
+ textAlign = TextAlign.Center
885
+ )
886
+
887
+ Spacer(modifier = Modifier.height(16.dp))
888
+
889
+ Text(
890
+ text = "Take a moment to truly consider the burrito.",
891
+ fontSize = 16.sp,
892
+ color = TextGray,
893
+ textAlign = TextAlign.Center,
894
+ lineHeight = 26.sp
895
+ )
896
+
897
+ Spacer(modifier = Modifier.height(24.dp))
898
+
899
+ Button(
900
+ onClick = {
901
+ onConsiderBurrito()
902
+ showSuccess = true
903
+ },
904
+ modifier = Modifier
905
+ .fillMaxWidth()
906
+ .height(56.dp),
907
+ colors = ButtonDefaults.buttonColors(
908
+ containerColor = SuccessGreen
909
+ ),
910
+ shape = RoundedCornerShape(4.dp)
911
+ ) {
912
+ Text(
913
+ text = "Consider the Burrito",
914
+ fontSize = 18.sp,
915
+ color = White
916
+ )
917
+ }
918
+
919
+ if (showSuccess) {
920
+ Spacer(modifier = Modifier.height(16.dp))
921
+
922
+ Text(
923
+ text = "You have considered the burrito. Well done!",
924
+ color = SuccessGreen,
925
+ fontSize = 16.sp,
926
+ textAlign = TextAlign.Center
927
+ )
928
+ }
929
+
930
+ Spacer(modifier = Modifier.height(24.dp))
931
+
932
+ Text(
933
+ text = "Consideration stats",
934
+ fontSize = 20.sp,
935
+ fontWeight = FontWeight.SemiBold,
936
+ color = TextDark,
937
+ modifier = Modifier.fillMaxWidth()
938
+ )
939
+
940
+ Spacer(modifier = Modifier.height(16.dp))
941
+
942
+ StatsCard(
943
+ title = "Total Burrito Considerations",
944
+ value = burritoCount.toString()
945
+ )
946
+ }
947
+ }
948
+ }
949
+ }
950
+
951
+ ```
952
+
953
+ ---
954
+
955
+ ## app/src/main/java/com/example/amplitude/ui/screens/HomeScreen.kt
956
+
957
+ ```kt
958
+ package com.example.amplitude.ui.screens
959
+
960
+ import androidx.compose.foundation.background
961
+ import androidx.compose.foundation.layout.Arrangement
962
+ import androidx.compose.foundation.layout.Box
963
+ import androidx.compose.foundation.layout.Column
964
+ import androidx.compose.foundation.layout.Spacer
965
+ import androidx.compose.foundation.layout.fillMaxSize
966
+ import androidx.compose.foundation.layout.fillMaxWidth
967
+ import androidx.compose.foundation.layout.height
968
+ import androidx.compose.foundation.layout.padding
969
+ import androidx.compose.foundation.layout.widthIn
970
+ import androidx.compose.foundation.rememberScrollState
971
+ import androidx.compose.foundation.shape.RoundedCornerShape
972
+ import androidx.compose.foundation.text.KeyboardOptions
973
+ import androidx.compose.foundation.verticalScroll
974
+ import androidx.compose.material3.Button
975
+ import androidx.compose.material3.ButtonDefaults
976
+ import androidx.compose.material3.OutlinedTextField
977
+ import androidx.compose.material3.OutlinedTextFieldDefaults
978
+ import androidx.compose.material3.Text
979
+ import androidx.compose.runtime.Composable
980
+ import androidx.compose.runtime.getValue
981
+ import androidx.compose.runtime.mutableStateOf
982
+ import androidx.compose.runtime.remember
983
+ import androidx.compose.runtime.setValue
984
+ import androidx.compose.ui.Alignment
985
+ import androidx.compose.ui.Modifier
986
+ import androidx.compose.ui.draw.shadow
987
+ import androidx.compose.ui.text.font.FontWeight
988
+ import androidx.compose.ui.text.input.KeyboardType
989
+ import androidx.compose.ui.text.input.PasswordVisualTransformation
990
+ import androidx.compose.ui.text.style.TextAlign
991
+ import androidx.compose.ui.unit.dp
992
+ import androidx.compose.ui.unit.sp
993
+ import com.example.amplitude.ui.theme.BackgroundGray
994
+ import com.example.amplitude.ui.theme.BorderGray
995
+ import com.example.amplitude.ui.theme.PrimaryBlue
996
+ import com.example.amplitude.ui.theme.TextDark
997
+ import com.example.amplitude.ui.theme.TextGray
998
+ import com.example.amplitude.ui.theme.White
999
+
1000
+ @Composable
1001
+ fun HomeScreen(
1002
+ isAuthenticated: Boolean,
1003
+ username: String?,
1004
+ onLogin: (String) -> Unit
1005
+ ) {
1006
+ Box(
1007
+ modifier = Modifier
1008
+ .fillMaxSize()
1009
+ .background(BackgroundGray)
1010
+ .padding(horizontal = 16.dp)
1011
+ .verticalScroll(rememberScrollState()),
1012
+ contentAlignment = if (isAuthenticated) Alignment.TopCenter else Alignment.Center
1013
+ ) {
1014
+ Column(
1015
+ modifier = Modifier
1016
+ .widthIn(max = 600.dp)
1017
+ .padding(vertical = 16.dp),
1018
+ horizontalAlignment = Alignment.CenterHorizontally
1019
+ ) {
1020
+ if (isAuthenticated && username != null) {
1021
+ LoggedInContent(username = username)
1022
+ } else {
1023
+ LoginForm(onLogin = onLogin)
1024
+ }
1025
+ }
1026
+ }
1027
+ }
1028
+
1029
+ @Composable
1030
+ private fun LoggedInContent(username: String) {
1031
+ ContentCard {
1032
+ Text(
1033
+ text = "Welcome back, $username!",
1034
+ fontSize = 24.sp,
1035
+ fontWeight = FontWeight.SemiBold,
1036
+ color = TextDark
1037
+ )
1038
+
1039
+ Spacer(modifier = Modifier.height(16.dp))
1040
+
1041
+ Text(
1042
+ text = "Ready to consider some burritos?",
1043
+ fontSize = 16.sp,
1044
+ color = TextGray,
1045
+ lineHeight = 26.sp
1046
+ )
1047
+ }
1048
+ }
1049
+
1050
+ @Composable
1051
+ private fun LoginForm(onLogin: (String) -> Unit) {
1052
+ var username by remember { mutableStateOf("") }
1053
+ var password by remember { mutableStateOf("") }
1054
+
1055
+ ContentCard {
1056
+ Text(
1057
+ text = "Welcome to Burrito Consideration App",
1058
+ fontSize = 24.sp,
1059
+ fontWeight = FontWeight.SemiBold,
1060
+ color = TextDark,
1061
+ textAlign = TextAlign.Center
1062
+ )
1063
+
1064
+ Spacer(modifier = Modifier.height(24.dp))
1065
+
1066
+ // Username field
1067
+ Column(modifier = Modifier.fillMaxWidth()) {
1068
+ Text(
1069
+ text = "Username",
1070
+ fontSize = 16.sp,
1071
+ fontWeight = FontWeight.Medium,
1072
+ color = TextDark,
1073
+ modifier = Modifier.padding(bottom = 8.dp)
1074
+ )
1075
+ OutlinedTextField(
1076
+ value = username,
1077
+ onValueChange = { username = it },
1078
+ modifier = Modifier.fillMaxWidth(),
1079
+ singleLine = true,
1080
+ shape = RoundedCornerShape(4.dp),
1081
+ colors = OutlinedTextFieldDefaults.colors(
1082
+ unfocusedBorderColor = BorderGray,
1083
+ focusedBorderColor = PrimaryBlue,
1084
+ unfocusedContainerColor = White,
1085
+ focusedContainerColor = White
1086
+ )
1087
+ )
1088
+ }
1089
+
1090
+ Spacer(modifier = Modifier.height(16.dp))
1091
+
1092
+ // Password field
1093
+ Column(modifier = Modifier.fillMaxWidth()) {
1094
+ Text(
1095
+ text = "Password",
1096
+ fontSize = 16.sp,
1097
+ fontWeight = FontWeight.Medium,
1098
+ color = TextDark,
1099
+ modifier = Modifier.padding(bottom = 8.dp)
1100
+ )
1101
+ OutlinedTextField(
1102
+ value = password,
1103
+ onValueChange = { password = it },
1104
+ modifier = Modifier.fillMaxWidth(),
1105
+ singleLine = true,
1106
+ visualTransformation = PasswordVisualTransformation(),
1107
+ keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
1108
+ shape = RoundedCornerShape(4.dp),
1109
+ colors = OutlinedTextFieldDefaults.colors(
1110
+ unfocusedBorderColor = BorderGray,
1111
+ focusedBorderColor = PrimaryBlue,
1112
+ unfocusedContainerColor = White,
1113
+ focusedContainerColor = White
1114
+ )
1115
+ )
1116
+ }
1117
+
1118
+ Spacer(modifier = Modifier.height(16.dp))
1119
+
1120
+ Button(
1121
+ onClick = {
1122
+ if (username.isNotBlank()) {
1123
+ onLogin(username)
1124
+ }
1125
+ },
1126
+ modifier = Modifier
1127
+ .fillMaxWidth()
1128
+ .height(48.dp),
1129
+ colors = ButtonDefaults.buttonColors(
1130
+ containerColor = PrimaryBlue
1131
+ ),
1132
+ shape = RoundedCornerShape(4.dp)
1133
+ ) {
1134
+ Text(
1135
+ text = "Sign In",
1136
+ fontSize = 16.sp,
1137
+ color = White
1138
+ )
1139
+ }
1140
+
1141
+ Spacer(modifier = Modifier.height(24.dp))
1142
+
1143
+ Text(
1144
+ text = "Note: This is a demo app. Enter any username to sign in.",
1145
+ fontSize = 14.sp,
1146
+ color = TextGray,
1147
+ textAlign = TextAlign.Center,
1148
+ lineHeight = 21.sp
1149
+ )
1150
+ }
1151
+ }
1152
+
1153
+ @Composable
1154
+ private fun ContentCard(
1155
+ content: @Composable () -> Unit
1156
+ ) {
1157
+ Column(
1158
+ modifier = Modifier
1159
+ .fillMaxWidth()
1160
+ .shadow(
1161
+ elevation = 4.dp,
1162
+ shape = RoundedCornerShape(8.dp),
1163
+ ambientColor = TextDark.copy(alpha = 0.1f),
1164
+ spotColor = TextDark.copy(alpha = 0.1f)
1165
+ )
1166
+ .background(
1167
+ color = White,
1168
+ shape = RoundedCornerShape(8.dp)
1169
+ )
1170
+ .padding(24.dp),
1171
+ horizontalAlignment = Alignment.CenterHorizontally
1172
+ ) {
1173
+ content()
1174
+ }
1175
+ }
1176
+
1177
+ ```
1178
+
1179
+ ---
1180
+
1181
+ ## app/src/main/java/com/example/amplitude/ui/screens/ProfileScreen.kt
1182
+
1183
+ ```kt
1184
+ package com.example.amplitude.ui.screens
1185
+
1186
+ import androidx.compose.foundation.background
1187
+ import androidx.compose.foundation.layout.Box
1188
+ import androidx.compose.foundation.layout.Column
1189
+ import androidx.compose.foundation.layout.Spacer
1190
+ import androidx.compose.foundation.layout.fillMaxSize
1191
+ import androidx.compose.foundation.layout.fillMaxWidth
1192
+ import androidx.compose.foundation.layout.height
1193
+ import androidx.compose.foundation.layout.padding
1194
+ import androidx.compose.foundation.layout.widthIn
1195
+ import androidx.compose.foundation.rememberScrollState
1196
+ import androidx.compose.foundation.shape.RoundedCornerShape
1197
+ import androidx.compose.foundation.verticalScroll
1198
+ import androidx.compose.material3.Text
1199
+ import androidx.compose.runtime.Composable
1200
+ import androidx.compose.ui.Alignment
1201
+ import androidx.compose.ui.Modifier
1202
+ import androidx.compose.ui.draw.shadow
1203
+ import androidx.compose.ui.text.font.FontWeight
1204
+ import androidx.compose.ui.text.style.TextAlign
1205
+ import androidx.compose.ui.unit.dp
1206
+ import androidx.compose.ui.unit.sp
1207
+ import com.example.amplitude.ui.components.StatsCard
1208
+ import com.example.amplitude.ui.theme.BackgroundGray
1209
+ import com.example.amplitude.ui.theme.TextDark
1210
+ import com.example.amplitude.ui.theme.TextGray
1211
+ import com.example.amplitude.ui.theme.White
1212
+
1213
+ @Composable
1214
+ fun ProfileScreen(
1215
+ username: String,
1216
+ burritoCount: Int
1217
+ ) {
1218
+ Box(
1219
+ modifier = Modifier
1220
+ .fillMaxSize()
1221
+ .background(BackgroundGray)
1222
+ .padding(horizontal = 16.dp)
1223
+ .verticalScroll(rememberScrollState()),
1224
+ contentAlignment = Alignment.TopCenter
1225
+ ) {
1226
+ Column(
1227
+ modifier = Modifier
1228
+ .widthIn(max = 600.dp)
1229
+ .padding(vertical = 16.dp),
1230
+ horizontalAlignment = Alignment.CenterHorizontally
1231
+ ) {
1232
+ // Main content card
1233
+ Column(
1234
+ modifier = Modifier
1235
+ .fillMaxWidth()
1236
+ .shadow(
1237
+ elevation = 4.dp,
1238
+ shape = RoundedCornerShape(8.dp),
1239
+ ambientColor = TextDark.copy(alpha = 0.1f),
1240
+ spotColor = TextDark.copy(alpha = 0.1f)
1241
+ )
1242
+ .background(
1243
+ color = White,
1244
+ shape = RoundedCornerShape(8.dp)
1245
+ )
1246
+ .padding(24.dp),
1247
+ horizontalAlignment = Alignment.CenterHorizontally
1248
+ ) {
1249
+ Text(
1250
+ text = "User Profile",
1251
+ fontSize = 24.sp,
1252
+ fontWeight = FontWeight.SemiBold,
1253
+ color = TextDark
1254
+ )
1255
+
1256
+ Spacer(modifier = Modifier.height(24.dp))
1257
+
1258
+ // Your Information section
1259
+ Text(
1260
+ text = "Your Information",
1261
+ fontSize = 24.sp,
1262
+ fontWeight = FontWeight.SemiBold,
1263
+ color = TextDark,
1264
+ modifier = Modifier.fillMaxWidth()
1265
+ )
1266
+
1267
+ Spacer(modifier = Modifier.height(16.dp))
1268
+
1269
+ // Username display
1270
+ Column(modifier = Modifier.fillMaxWidth()) {
1271
+ Text(
1272
+ text = "Username",
1273
+ fontSize = 14.sp,
1274
+ color = TextGray
1275
+ )
1276
+ Text(
1277
+ text = username,
1278
+ fontSize = 20.sp,
1279
+ fontWeight = FontWeight.SemiBold,
1280
+ color = TextDark
1281
+ )
1282
+ }
1283
+
1284
+ Spacer(modifier = Modifier.height(24.dp))
1285
+
1286
+ // Stats card
1287
+ StatsCard(
1288
+ title = "Total Burrito Considerations",
1289
+ value = burritoCount.toString()
1290
+ )
1291
+
1292
+ Spacer(modifier = Modifier.height(24.dp))
1293
+
1294
+ // Your Burrito Journey section
1295
+ Text(
1296
+ text = "Your Burrito Journey",
1297
+ fontSize = 20.sp,
1298
+ fontWeight = FontWeight.SemiBold,
1299
+ color = TextDark,
1300
+ modifier = Modifier.fillMaxWidth()
1301
+ )
1302
+
1303
+ Spacer(modifier = Modifier.height(8.dp))
1304
+
1305
+ Text(
1306
+ text = getJourneyMessage(burritoCount),
1307
+ fontSize = 16.sp,
1308
+ color = TextGray,
1309
+ textAlign = TextAlign.Start,
1310
+ lineHeight = 26.sp,
1311
+ modifier = Modifier.fillMaxWidth()
1312
+ )
1313
+ }
1314
+ }
1315
+ }
1316
+ }
1317
+
1318
+ private fun getJourneyMessage(count: Int): String = when {
1319
+ count == 0 -> "You haven't considered any burritos yet. Start your journey!"
1320
+ count == 1 -> "You've considered the burrito potential once. The journey begins!"
1321
+ count in 2..4 -> "You're getting the hang of burrito consideration!"
1322
+ count in 5..9 -> "You're becoming a burrito consideration expert!"
1323
+ else -> "You are a true burrito consideration master!"
1324
+ }
1325
+
1326
+ ```
1327
+
1328
+ ---
1329
+
1330
+ ## app/src/main/java/com/example/amplitude/ui/theme/Color.kt
1331
+
1332
+ ```kt
1333
+ package com.example.amplitude.ui.theme
1334
+
1335
+ import androidx.compose.ui.graphics.Color
1336
+
1337
+ val PrimaryBlue = Color(0xFF0070F3)
1338
+ val PrimaryBlueHover = Color(0xFF0051CC)
1339
+ val SuccessGreen = Color(0xFF28A745)
1340
+ val SuccessGreenHover = Color(0xFF218838)
1341
+ val ErrorRed = Color(0xFFDC3545)
1342
+ val ErrorRedHover = Color(0xFFC82333)
1343
+ val DarkHeader = Color(0xFF333333)
1344
+ val DarkHeaderHover = Color(0xFF555555)
1345
+ val LightGray = Color(0xFFF8F9FA)
1346
+ val BorderGray = Color(0xFFDDDDDD)
1347
+ val TextGray = Color(0xFF666666)
1348
+ val BackgroundGray = Color(0xFFF5F5F5)
1349
+ val TextDark = Color(0xFF333333)
1350
+ val White = Color(0xFFFFFFFF)
1351
+
1352
+ ```
1353
+
1354
+ ---
1355
+
1356
+ ## app/src/main/java/com/example/amplitude/ui/theme/Theme.kt
1357
+
1358
+ ```kt
1359
+ package com.example.amplitude.ui.theme
1360
+
1361
+ import androidx.compose.material3.MaterialTheme
1362
+ import androidx.compose.material3.lightColorScheme
1363
+ import androidx.compose.runtime.Composable
1364
+
1365
+ private val LightColorScheme = lightColorScheme(
1366
+ primary = PrimaryBlue,
1367
+ secondary = SuccessGreen,
1368
+ tertiary = DarkHeader,
1369
+ background = BackgroundGray,
1370
+ surface = White,
1371
+ onPrimary = White,
1372
+ onSecondary = White,
1373
+ onTertiary = White,
1374
+ onBackground = TextDark,
1375
+ onSurface = TextDark
1376
+ )
1377
+
1378
+ @Composable
1379
+ fun AmplitudeTheme(
1380
+ content: @Composable () -> Unit
1381
+ ) {
1382
+ MaterialTheme(
1383
+ colorScheme = LightColorScheme,
1384
+ typography = Typography,
1385
+ content = content
1386
+ )
1387
+ }
1388
+ ```
1389
+
1390
+ ---
1391
+
1392
+ ## app/src/main/java/com/example/amplitude/ui/theme/Type.kt
1393
+
1394
+ ```kt
1395
+ package com.example.amplitude.ui.theme
1396
+
1397
+ import androidx.compose.material3.Typography
1398
+ import androidx.compose.ui.text.TextStyle
1399
+ import androidx.compose.ui.text.font.FontFamily
1400
+ import androidx.compose.ui.text.font.FontWeight
1401
+ import androidx.compose.ui.unit.sp
1402
+
1403
+ // Typography based on design specification
1404
+ // Uses system font stack (FontFamily.Default maps to Roboto on Android)
1405
+ val Typography = Typography(
1406
+ // H1 - Page titles (32sp)
1407
+ displayLarge = TextStyle(
1408
+ fontFamily = FontFamily.Default,
1409
+ fontWeight = FontWeight.SemiBold,
1410
+ fontSize = 32.sp,
1411
+ lineHeight = 40.sp,
1412
+ letterSpacing = 0.sp
1413
+ ),
1414
+ // H2 - Section titles (24sp)
1415
+ displayMedium = TextStyle(
1416
+ fontFamily = FontFamily.Default,
1417
+ fontWeight = FontWeight.SemiBold,
1418
+ fontSize = 24.sp,
1419
+ lineHeight = 32.sp,
1420
+ letterSpacing = 0.sp
1421
+ ),
1422
+ // H3 - Subsection titles (20sp)
1423
+ displaySmall = TextStyle(
1424
+ fontFamily = FontFamily.Default,
1425
+ fontWeight = FontWeight.SemiBold,
1426
+ fontSize = 20.sp,
1427
+ lineHeight = 26.sp,
1428
+ letterSpacing = 0.sp
1429
+ ),
1430
+ // Body text (16sp with 1.6 line height = 25.6sp)
1431
+ bodyLarge = TextStyle(
1432
+ fontFamily = FontFamily.Default,
1433
+ fontWeight = FontWeight.Normal,
1434
+ fontSize = 16.sp,
1435
+ lineHeight = 26.sp,
1436
+ letterSpacing = 0.sp
1437
+ ),
1438
+ // Small/Note text (14sp)
1439
+ bodySmall = TextStyle(
1440
+ fontFamily = FontFamily.Default,
1441
+ fontWeight = FontWeight.Normal,
1442
+ fontSize = 14.sp,
1443
+ lineHeight = 21.sp,
1444
+ letterSpacing = 0.sp
1445
+ ),
1446
+ // Labels (16sp, medium weight)
1447
+ labelLarge = TextStyle(
1448
+ fontFamily = FontFamily.Default,
1449
+ fontWeight = FontWeight.Medium,
1450
+ fontSize = 16.sp,
1451
+ lineHeight = 24.sp,
1452
+ letterSpacing = 0.sp
1453
+ ),
1454
+ // Button text - Burrito button (18sp)
1455
+ titleLarge = TextStyle(
1456
+ fontFamily = FontFamily.Default,
1457
+ fontWeight = FontWeight.Normal,
1458
+ fontSize = 18.sp,
1459
+ lineHeight = 24.sp,
1460
+ letterSpacing = 0.sp
1461
+ ),
1462
+ // Button text - Primary/Logout (16sp/14sp)
1463
+ titleMedium = TextStyle(
1464
+ fontFamily = FontFamily.Default,
1465
+ fontWeight = FontWeight.Normal,
1466
+ fontSize = 16.sp,
1467
+ lineHeight = 24.sp,
1468
+ letterSpacing = 0.sp
1469
+ ),
1470
+ titleSmall = TextStyle(
1471
+ fontFamily = FontFamily.Default,
1472
+ fontWeight = FontWeight.Normal,
1473
+ fontSize = 14.sp,
1474
+ lineHeight = 20.sp,
1475
+ letterSpacing = 0.sp
1476
+ )
1477
+ )
1478
+ ```
1479
+
1480
+ ---
1481
+
1482
+ ## app/src/main/java/com/example/amplitude/viewmodel/AuthViewModel.kt
1483
+
1484
+ ```kt
1485
+ package com.example.amplitude.viewmodel
1486
+
1487
+ import android.app.Application
1488
+ import androidx.lifecycle.AndroidViewModel
1489
+ import androidx.lifecycle.viewModelScope
1490
+ import com.example.amplitude.BurritoApplication
1491
+ import com.example.amplitude.data.User
1492
+ import com.example.amplitude.data.UserRepository
1493
+ import kotlinx.coroutines.flow.MutableStateFlow
1494
+ import kotlinx.coroutines.flow.StateFlow
1495
+ import kotlinx.coroutines.flow.asStateFlow
1496
+ import kotlinx.coroutines.launch
1497
+
1498
+ class AuthViewModel(application: Application) : AndroidViewModel(application) {
1499
+
1500
+ private val repository = UserRepository(application)
1501
+ private val amplitude = (application as BurritoApplication).amplitude
1502
+
1503
+ private val _currentUser = MutableStateFlow<User?>(null)
1504
+ val currentUser: StateFlow<User?> = _currentUser.asStateFlow()
1505
+
1506
+ private val _isAuthenticated = MutableStateFlow(false)
1507
+ val isAuthenticated: StateFlow<Boolean> = _isAuthenticated.asStateFlow()
1508
+
1509
+ init {
1510
+ loadCurrentUser()
1511
+ }
1512
+
1513
+ private fun loadCurrentUser() {
1514
+ viewModelScope.launch {
1515
+ val user = repository.getCurrentUser()
1516
+ _currentUser.value = user
1517
+ _isAuthenticated.value = user != null
1518
+ }
1519
+ }
1520
+
1521
+ fun login(username: String) {
1522
+ viewModelScope.launch {
1523
+ val existingUser = repository.getUser(username)
1524
+ val user = existingUser ?: User(username = username, burritoConsiderations = 0)
1525
+ repository.saveUser(user)
1526
+ _currentUser.value = user
1527
+ _isAuthenticated.value = true
1528
+
1529
+ amplitude.setUserId(username)
1530
+ amplitude.track("User Logged In")
1531
+ }
1532
+ }
1533
+
1534
+ fun logout() {
1535
+ viewModelScope.launch {
1536
+ amplitude.track("User Logged Out")
1537
+ amplitude.reset()
1538
+ repository.clearCurrentUser()
1539
+ _currentUser.value = null
1540
+ _isAuthenticated.value = false
1541
+ }
1542
+ }
1543
+
1544
+ fun incrementBurritoCount() {
1545
+ viewModelScope.launch {
1546
+ val user = _currentUser.value ?: return@launch
1547
+ val updatedUser = user.copy(burritoConsiderations = user.burritoConsiderations + 1)
1548
+ repository.saveUser(updatedUser)
1549
+ _currentUser.value = updatedUser
1550
+
1551
+ val eventProperties = mapOf(
1552
+ "total_considerations" to updatedUser.burritoConsiderations,
1553
+ "username" to updatedUser.username
1554
+ )
1555
+ amplitude.track("Burrito Considered", eventProperties)
1556
+ }
1557
+ }
1558
+ }
1559
+
1560
+ ```
1561
+
1562
+ ---
1563
+
1564
+ ## app/src/main/res/drawable/ic_launcher_background.xml
1565
+
1566
+ ```xml
1567
+ <?xml version="1.0" encoding="utf-8"?>
1568
+ <vector xmlns:android="http://schemas.android.com/apk/res/android"
1569
+ android:width="108dp"
1570
+ android:height="108dp"
1571
+ android:viewportWidth="108"
1572
+ android:viewportHeight="108">
1573
+ <path
1574
+ android:fillColor="#3DDC84"
1575
+ android:pathData="M0,0h108v108h-108z" />
1576
+ <path
1577
+ android:fillColor="#00000000"
1578
+ android:pathData="M9,0L9,108"
1579
+ android:strokeWidth="0.8"
1580
+ android:strokeColor="#33FFFFFF" />
1581
+ <path
1582
+ android:fillColor="#00000000"
1583
+ android:pathData="M19,0L19,108"
1584
+ android:strokeWidth="0.8"
1585
+ android:strokeColor="#33FFFFFF" />
1586
+ <path
1587
+ android:fillColor="#00000000"
1588
+ android:pathData="M29,0L29,108"
1589
+ android:strokeWidth="0.8"
1590
+ android:strokeColor="#33FFFFFF" />
1591
+ <path
1592
+ android:fillColor="#00000000"
1593
+ android:pathData="M39,0L39,108"
1594
+ android:strokeWidth="0.8"
1595
+ android:strokeColor="#33FFFFFF" />
1596
+ <path
1597
+ android:fillColor="#00000000"
1598
+ android:pathData="M49,0L49,108"
1599
+ android:strokeWidth="0.8"
1600
+ android:strokeColor="#33FFFFFF" />
1601
+ <path
1602
+ android:fillColor="#00000000"
1603
+ android:pathData="M59,0L59,108"
1604
+ android:strokeWidth="0.8"
1605
+ android:strokeColor="#33FFFFFF" />
1606
+ <path
1607
+ android:fillColor="#00000000"
1608
+ android:pathData="M69,0L69,108"
1609
+ android:strokeWidth="0.8"
1610
+ android:strokeColor="#33FFFFFF" />
1611
+ <path
1612
+ android:fillColor="#00000000"
1613
+ android:pathData="M79,0L79,108"
1614
+ android:strokeWidth="0.8"
1615
+ android:strokeColor="#33FFFFFF" />
1616
+ <path
1617
+ android:fillColor="#00000000"
1618
+ android:pathData="M89,0L89,108"
1619
+ android:strokeWidth="0.8"
1620
+ android:strokeColor="#33FFFFFF" />
1621
+ <path
1622
+ android:fillColor="#00000000"
1623
+ android:pathData="M99,0L99,108"
1624
+ android:strokeWidth="0.8"
1625
+ android:strokeColor="#33FFFFFF" />
1626
+ <path
1627
+ android:fillColor="#00000000"
1628
+ android:pathData="M0,9L108,9"
1629
+ android:strokeWidth="0.8"
1630
+ android:strokeColor="#33FFFFFF" />
1631
+ <path
1632
+ android:fillColor="#00000000"
1633
+ android:pathData="M0,19L108,19"
1634
+ android:strokeWidth="0.8"
1635
+ android:strokeColor="#33FFFFFF" />
1636
+ <path
1637
+ android:fillColor="#00000000"
1638
+ android:pathData="M0,29L108,29"
1639
+ android:strokeWidth="0.8"
1640
+ android:strokeColor="#33FFFFFF" />
1641
+ <path
1642
+ android:fillColor="#00000000"
1643
+ android:pathData="M0,39L108,39"
1644
+ android:strokeWidth="0.8"
1645
+ android:strokeColor="#33FFFFFF" />
1646
+ <path
1647
+ android:fillColor="#00000000"
1648
+ android:pathData="M0,49L108,49"
1649
+ android:strokeWidth="0.8"
1650
+ android:strokeColor="#33FFFFFF" />
1651
+ <path
1652
+ android:fillColor="#00000000"
1653
+ android:pathData="M0,59L108,59"
1654
+ android:strokeWidth="0.8"
1655
+ android:strokeColor="#33FFFFFF" />
1656
+ <path
1657
+ android:fillColor="#00000000"
1658
+ android:pathData="M0,69L108,69"
1659
+ android:strokeWidth="0.8"
1660
+ android:strokeColor="#33FFFFFF" />
1661
+ <path
1662
+ android:fillColor="#00000000"
1663
+ android:pathData="M0,79L108,79"
1664
+ android:strokeWidth="0.8"
1665
+ android:strokeColor="#33FFFFFF" />
1666
+ <path
1667
+ android:fillColor="#00000000"
1668
+ android:pathData="M0,89L108,89"
1669
+ android:strokeWidth="0.8"
1670
+ android:strokeColor="#33FFFFFF" />
1671
+ <path
1672
+ android:fillColor="#00000000"
1673
+ android:pathData="M0,99L108,99"
1674
+ android:strokeWidth="0.8"
1675
+ android:strokeColor="#33FFFFFF" />
1676
+ <path
1677
+ android:fillColor="#00000000"
1678
+ android:pathData="M19,29L89,29"
1679
+ android:strokeWidth="0.8"
1680
+ android:strokeColor="#33FFFFFF" />
1681
+ <path
1682
+ android:fillColor="#00000000"
1683
+ android:pathData="M19,39L89,39"
1684
+ android:strokeWidth="0.8"
1685
+ android:strokeColor="#33FFFFFF" />
1686
+ <path
1687
+ android:fillColor="#00000000"
1688
+ android:pathData="M19,49L89,49"
1689
+ android:strokeWidth="0.8"
1690
+ android:strokeColor="#33FFFFFF" />
1691
+ <path
1692
+ android:fillColor="#00000000"
1693
+ android:pathData="M19,59L89,59"
1694
+ android:strokeWidth="0.8"
1695
+ android:strokeColor="#33FFFFFF" />
1696
+ <path
1697
+ android:fillColor="#00000000"
1698
+ android:pathData="M19,69L89,69"
1699
+ android:strokeWidth="0.8"
1700
+ android:strokeColor="#33FFFFFF" />
1701
+ <path
1702
+ android:fillColor="#00000000"
1703
+ android:pathData="M19,79L89,79"
1704
+ android:strokeWidth="0.8"
1705
+ android:strokeColor="#33FFFFFF" />
1706
+ <path
1707
+ android:fillColor="#00000000"
1708
+ android:pathData="M29,19L29,89"
1709
+ android:strokeWidth="0.8"
1710
+ android:strokeColor="#33FFFFFF" />
1711
+ <path
1712
+ android:fillColor="#00000000"
1713
+ android:pathData="M39,19L39,89"
1714
+ android:strokeWidth="0.8"
1715
+ android:strokeColor="#33FFFFFF" />
1716
+ <path
1717
+ android:fillColor="#00000000"
1718
+ android:pathData="M49,19L49,89"
1719
+ android:strokeWidth="0.8"
1720
+ android:strokeColor="#33FFFFFF" />
1721
+ <path
1722
+ android:fillColor="#00000000"
1723
+ android:pathData="M59,19L59,89"
1724
+ android:strokeWidth="0.8"
1725
+ android:strokeColor="#33FFFFFF" />
1726
+ <path
1727
+ android:fillColor="#00000000"
1728
+ android:pathData="M69,19L69,89"
1729
+ android:strokeWidth="0.8"
1730
+ android:strokeColor="#33FFFFFF" />
1731
+ <path
1732
+ android:fillColor="#00000000"
1733
+ android:pathData="M79,19L79,89"
1734
+ android:strokeWidth="0.8"
1735
+ android:strokeColor="#33FFFFFF" />
1736
+ </vector>
1737
+
1738
+ ```
1739
+
1740
+ ---
1741
+
1742
+ ## app/src/main/res/drawable/ic_launcher_foreground.xml
1743
+
1744
+ ```xml
1745
+ <vector xmlns:android="http://schemas.android.com/apk/res/android"
1746
+ xmlns:aapt="http://schemas.android.com/aapt"
1747
+ android:width="108dp"
1748
+ android:height="108dp"
1749
+ android:viewportWidth="108"
1750
+ android:viewportHeight="108">
1751
+ <path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
1752
+ <aapt:attr name="android:fillColor">
1753
+ <gradient
1754
+ android:endX="85.84757"
1755
+ android:endY="92.4963"
1756
+ android:startX="42.9492"
1757
+ android:startY="49.59793"
1758
+ android:type="linear">
1759
+ <item
1760
+ android:color="#44000000"
1761
+ android:offset="0.0" />
1762
+ <item
1763
+ android:color="#00000000"
1764
+ android:offset="1.0" />
1765
+ </gradient>
1766
+ </aapt:attr>
1767
+ </path>
1768
+ <path
1769
+ android:fillColor="#FFFFFF"
1770
+ android:fillType="nonZero"
1771
+ android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
1772
+ android:strokeWidth="1"
1773
+ android:strokeColor="#00000000" />
1774
+ </vector>
1775
+ ```
1776
+
1777
+ ---
1778
+
1779
+ ## app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
1780
+
1781
+ ```xml
1782
+ <?xml version="1.0" encoding="utf-8"?>
1783
+ <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
1784
+ <background android:drawable="@drawable/ic_launcher_background" />
1785
+ <foreground android:drawable="@drawable/ic_launcher_foreground" />
1786
+ <monochrome android:drawable="@drawable/ic_launcher_foreground" />
1787
+ </adaptive-icon>
1788
+ ```
1789
+
1790
+ ---
1791
+
1792
+ ## app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
1793
+
1794
+ ```xml
1795
+ <?xml version="1.0" encoding="utf-8"?>
1796
+ <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
1797
+ <background android:drawable="@drawable/ic_launcher_background" />
1798
+ <foreground android:drawable="@drawable/ic_launcher_foreground" />
1799
+ <monochrome android:drawable="@drawable/ic_launcher_foreground" />
1800
+ </adaptive-icon>
1801
+ ```
1802
+
1803
+ ---
1804
+
1805
+ ## app/src/main/res/values/colors.xml
1806
+
1807
+ ```xml
1808
+ <?xml version="1.0" encoding="utf-8"?>
1809
+ <resources>
1810
+ <color name="purple_200">#FFBB86FC</color>
1811
+ <color name="purple_500">#FF6200EE</color>
1812
+ <color name="purple_700">#FF3700B3</color>
1813
+ <color name="teal_200">#FF03DAC5</color>
1814
+ <color name="teal_700">#FF018786</color>
1815
+ <color name="black">#FF000000</color>
1816
+ <color name="white">#FFFFFFFF</color>
1817
+ </resources>
1818
+ ```
1819
+
1820
+ ---
1821
+
1822
+ ## app/src/main/res/values/strings.xml
1823
+
1824
+ ```xml
1825
+ <resources>
1826
+ <string name="app_name">Amplitude</string>
1827
+ </resources>
1828
+ ```
1829
+
1830
+ ---
1831
+
1832
+ ## app/src/main/res/values/themes.xml
1833
+
1834
+ ```xml
1835
+ <?xml version="1.0" encoding="utf-8"?>
1836
+ <resources>
1837
+
1838
+ <style name="Theme.Amplitude" parent="android:Theme.Material.Light.NoActionBar" />
1839
+ </resources>
1840
+ ```
1841
+
1842
+ ---
1843
+
1844
+ ## app/src/main/res/xml/backup_rules.xml
1845
+
1846
+ ```xml
1847
+ <?xml version="1.0" encoding="utf-8"?><!--
1848
+ Sample backup rules file; uncomment and customize as necessary.
1849
+ See https://developer.android.com/guide/topics/data/autobackup
1850
+ for details.
1851
+ Note: This file is ignored for devices older than API 31
1852
+ See https://developer.android.com/about/versions/12/backup-restore
1853
+ -->
1854
+ <full-backup-content>
1855
+ <!--
1856
+ <include domain="sharedpref" path="."/>
1857
+ <exclude domain="sharedpref" path="device.xml"/>
1858
+ -->
1859
+ </full-backup-content>
1860
+ ```
1861
+
1862
+ ---
1863
+
1864
+ ## app/src/main/res/xml/data_extraction_rules.xml
1865
+
1866
+ ```xml
1867
+ <?xml version="1.0" encoding="utf-8"?><!--
1868
+ Sample data extraction rules file; uncomment and customize as necessary.
1869
+ See https://developer.android.com/about/versions/12/backup-restore#xml-changes
1870
+ for details.
1871
+ -->
1872
+ <data-extraction-rules>
1873
+ <cloud-backup>
1874
+ <!-- TODO: Use <include> and <exclude> to control what is backed up.
1875
+ <include .../>
1876
+ <exclude .../>
1877
+ -->
1878
+ </cloud-backup>
1879
+ <!--
1880
+ <device-transfer>
1881
+ <include .../>
1882
+ <exclude .../>
1883
+ </device-transfer>
1884
+ -->
1885
+ </data-extraction-rules>
1886
+ ```
1887
+
1888
+ ---
1889
+
1890
+ ## gradle.properties
1891
+
1892
+ ```properties
1893
+ # Project-wide Gradle settings.
1894
+ # IDE (e.g. Android Studio) users:
1895
+ # Gradle settings configured through the IDE *will override*
1896
+ # any settings specified in this file.
1897
+ # For more details on how to configure your build environment visit
1898
+ # http://www.gradle.org/docs/current/userguide/build_environment.html
1899
+ # Specifies the JVM arguments used for the daemon process.
1900
+ # The setting is particularly useful for tweaking memory settings.
1901
+ org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
1902
+ # When configured, Gradle will run in incubating parallel mode.
1903
+ # This option should only be used with decoupled projects. For more details, visit
1904
+ # https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
1905
+ # org.gradle.parallel=true
1906
+ # AndroidX package structure to make it clearer which packages are bundled with the
1907
+ # Android operating system, and which are packaged with your app's APK
1908
+ # https://developer.android.com/topic/libraries/support-library/androidx-rn
1909
+ android.useAndroidX=true
1910
+ # Kotlin code style for this project: "official" or "obsolete":
1911
+ kotlin.code.style=official
1912
+ # Enables namespacing of each library's R class so that its R class includes only the
1913
+ # resources declared in the library itself and none from the library's dependencies,
1914
+ # thereby reducing the size of the R class for that library
1915
+ android.nonTransitiveRClass=true
1916
+ ```
1917
+
1918
+ ---
1919
+
1920
+ ## gradle/libs.versions.toml
1921
+
1922
+ ```toml
1923
+ [versions]
1924
+ agp = "9.0.0"
1925
+ coreKtx = "1.10.1"
1926
+ junit = "4.13.2"
1927
+ junitVersion = "1.1.5"
1928
+ espressoCore = "3.5.1"
1929
+ lifecycleRuntimeKtx = "2.6.1"
1930
+ activityCompose = "1.8.0"
1931
+ kotlin = "2.0.21"
1932
+ composeBom = "2024.09.00"
1933
+ navigationCompose = "2.7.5"
1934
+ amplitude = "1.+"
1935
+
1936
+ [libraries]
1937
+ androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
1938
+ junit = { group = "junit", name = "junit", version.ref = "junit" }
1939
+ androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
1940
+ androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
1941
+ androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" }
1942
+ androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" }
1943
+ androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" }
1944
+ androidx-compose-ui = { group = "androidx.compose.ui", name = "ui" }
1945
+ androidx-compose-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
1946
+ androidx-compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
1947
+ androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
1948
+ androidx-compose-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
1949
+ androidx-compose-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
1950
+ androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" }
1951
+ androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigationCompose" }
1952
+ amplitude-android = { group = "com.amplitude", name = "analytics-android", version.ref = "amplitude" }
1953
+
1954
+ [plugins]
1955
+ android-application = { id = "com.android.application", version.ref = "agp" }
1956
+ kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
1957
+
1958
+
1959
+ ```
1960
+
1961
+ ---
1962
+
1963
+ ## local.properties.example
1964
+
1965
+ ```example
1966
+ # Copy this file to local.properties and fill in your values
1967
+ # local.properties is gitignored and will not be committed
1968
+
1969
+ sdk.dir=/path/to/your/android/sdk
1970
+
1971
+ # Amplitude configuration
1972
+ amplitude.apiKey=your_amplitude_api_key_here
1973
+
1974
+ ```
1975
+
1976
+ ---
1977
+