Browse Source

app: add screen with cards, info about card, start developing chat with AI

Bobarik31p 4 days ago
parent
commit
f3e12ae494
58 changed files with 2486 additions and 580 deletions
  1. 2 2
      App/.idea/deploymentTargetSelector.xml
  2. 0 329
      App/.idea/other.xml
  3. 84 0
      App/.kotlin/errors/errors-1732397093537.log
  4. 3 0
      App/app/build.gradle.kts
  5. 128 2
      App/app/src/main/java/com/example/mystictale/MainActivity.kt
  6. 0 98
      App/app/src/main/java/com/example/mystictale/Screen/Cards.kt
  7. 152 0
      App/app/src/main/java/com/example/mystictale/Screen/CardsScreen.kt
  8. 70 0
      App/app/src/main/java/com/example/mystictale/Screen/ChatWithAI.kt
  9. 172 0
      App/app/src/main/java/com/example/mystictale/Screen/DialogWithAI.kt
  10. 168 0
      App/app/src/main/java/com/example/mystictale/Screen/InfoCard.kt
  11. 76 12
      App/app/src/main/java/com/example/mystictale/Screen/LoadingScreen.kt
  12. 54 18
      App/app/src/main/java/com/example/mystictale/Screen/Profile.kt
  13. 56 0
      App/app/src/main/java/com/example/mystictale/Screen/TypewriterText.kt
  14. 6 6
      App/app/src/main/java/com/example/mystictale/Screen/passwordRecovery/NewPassword.kt
  15. 10 11
      App/app/src/main/java/com/example/mystictale/Screen/registration/RegistrationGender.kt
  16. 8 9
      App/app/src/main/java/com/example/mystictale/Screen/signIn/SignIn.kt
  17. 70 0
      App/app/src/main/java/com/example/mystictale/ViewModels/AIViewModel.kt
  18. 76 26
      App/app/src/main/java/com/example/mystictale/ViewModels/AuthViewModel.kt
  19. 86 0
      App/app/src/main/java/com/example/mystictale/ViewModels/CardsViewModel.kt
  20. 23 0
      App/app/src/main/java/com/example/mystictale/aiConnect/Api.kt
  21. 13 0
      App/app/src/main/java/com/example/mystictale/aiConnect/Repository.kt
  22. 36 0
      App/app/src/main/java/com/example/mystictale/aiConnect/RepositoryImpl.kt
  23. 10 0
      App/app/src/main/java/com/example/mystictale/aiConnect/Result.kt
  24. 29 0
      App/app/src/main/java/com/example/mystictale/aiConnect/RetrofitInstance.kt
  25. 25 0
      App/app/src/main/java/com/example/mystictale/models/AnswerAI.kt
  26. 9 0
      App/app/src/main/java/com/example/mystictale/models/Aspects.kt
  27. 4 4
      App/app/src/main/java/com/example/mystictale/models/Cards.kt
  28. 8 0
      App/app/src/main/java/com/example/mystictale/models/CompletionOptions.kt
  29. 8 0
      App/app/src/main/java/com/example/mystictale/models/CompletionRequest.kt
  30. 7 0
      App/app/src/main/java/com/example/mystictale/models/DataState.kt
  31. 0 7
      App/app/src/main/java/com/example/mystictale/models/UserState.kt
  32. 14 0
      App/app/src/main/java/com/example/mystictale/models/Values.kt
  33. 31 14
      App/app/src/main/java/com/example/mystictale/navigation/Navigation.kt
  34. 5 0
      App/app/src/main/java/com/example/mystictale/navigation/Screens.kt
  35. 140 0
      App/app/src/main/java/com/example/mystictale/navigation/bottomNavigation/AppNavigation.kt
  36. 39 0
      App/app/src/main/java/com/example/mystictale/navigation/bottomNavigation/BottomGraph.kt
  37. 26 0
      App/app/src/main/java/com/example/mystictale/navigation/bottomNavigation/NavItem.kt
  38. 49 0
      App/app/src/main/java/com/example/mystictale/resources/components/AIMessage.kt
  39. 46 0
      App/app/src/main/java/com/example/mystictale/resources/components/ButtonAI.kt
  40. 19 8
      App/app/src/main/java/com/example/mystictale/resources/components/ChooseArcana.kt
  41. 3 3
      App/app/src/main/java/com/example/mystictale/resources/components/ChooseGenderForProfile.kt
  42. 115 0
      App/app/src/main/java/com/example/mystictale/resources/components/ChooseSuit.kt
  43. 159 0
      App/app/src/main/java/com/example/mystictale/resources/components/LayoutCard.kt
  44. 70 0
      App/app/src/main/java/com/example/mystictale/resources/components/TextFieldForAI.kt
  45. 25 0
      App/app/src/main/java/com/example/mystictale/resources/components/TriangleEdgeShape.kt
  46. 26 0
      App/app/src/main/java/com/example/mystictale/resources/components/TriangleEdgeShapeAI.kt
  47. 61 0
      App/app/src/main/java/com/example/mystictale/resources/components/UserMessage.kt
  48. 53 0
      App/app/src/main/java/com/example/mystictale/resources/components/ValuesDropMenu.kt
  49. 205 0
      App/app/src/main/java/com/example/mystictale/resources/components/ValuesElement.kt
  50. 0 31
      App/app/src/main/java/com/example/mystictale/resources/components/dateComponents/LayoutCard.kt
  51. 1 0
      App/app/src/main/java/com/example/mystictale/ui/theme/Color.kt
  52. BIN
      App/app/src/main/res/drawable/ai.png
  53. BIN
      App/app/src/main/res/drawable/cards.png
  54. BIN
      App/app/src/main/res/drawable/close_value.png
  55. BIN
      App/app/src/main/res/drawable/open_value.png
  56. BIN
      App/app/src/main/res/drawable/profile.png
  57. BIN
      App/app/src/main/res/drawable/send.png
  58. 6 0
      App/gradle/libs.versions.toml

+ 2 - 2
App/.idea/deploymentTargetSelector.xml

@@ -4,10 +4,10 @@
     <selectionStates>
       <SelectionState runConfigName="app">
         <option name="selectionMode" value="DROPDOWN" />
-        <DropdownSelection timestamp="2024-11-15T18:36:17.788996900Z">
+        <DropdownSelection timestamp="2024-11-24T01:14:47.576140900Z">
           <Target type="DEFAULT_BOOT">
             <handle>
-              <DeviceId pluginId="PhysicalDevice" identifier="serial=VKUK5TAU7D55R4ZH" />
+              <DeviceId pluginId="LocalEmulator" identifier="path=C:\Users\User\.android\avd\Pixel_7a_API_35.avd" />
             </handle>
           </Target>
         </DropdownSelection>

+ 0 - 329
App/.idea/other.xml

@@ -1,329 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="direct_access_persist.xml">
-    <option name="deviceSelectionList">
-      <list>
-        <PersistentDeviceSelectionData>
-          <option name="api" value="27" />
-          <option name="brand" value="DOCOMO" />
-          <option name="codename" value="F01L" />
-          <option name="id" value="F01L" />
-          <option name="manufacturer" value="FUJITSU" />
-          <option name="name" value="F-01L" />
-          <option name="screenDensity" value="360" />
-          <option name="screenX" value="720" />
-          <option name="screenY" value="1280" />
-        </PersistentDeviceSelectionData>
-        <PersistentDeviceSelectionData>
-          <option name="api" value="28" />
-          <option name="brand" value="DOCOMO" />
-          <option name="codename" value="SH-01L" />
-          <option name="id" value="SH-01L" />
-          <option name="manufacturer" value="SHARP" />
-          <option name="name" value="AQUOS sense2 SH-01L" />
-          <option name="screenDensity" value="480" />
-          <option name="screenX" value="1080" />
-          <option name="screenY" value="2160" />
-        </PersistentDeviceSelectionData>
-        <PersistentDeviceSelectionData>
-          <option name="api" value="34" />
-          <option name="brand" value="Lenovo" />
-          <option name="codename" value="TB370FU" />
-          <option name="id" value="TB370FU" />
-          <option name="manufacturer" value="Lenovo" />
-          <option name="name" value="Tab P12" />
-          <option name="screenDensity" value="340" />
-          <option name="screenX" value="1840" />
-          <option name="screenY" value="2944" />
-        </PersistentDeviceSelectionData>
-        <PersistentDeviceSelectionData>
-          <option name="api" value="31" />
-          <option name="brand" value="samsung" />
-          <option name="codename" value="a51" />
-          <option name="id" value="a51" />
-          <option name="manufacturer" value="Samsung" />
-          <option name="name" value="Galaxy A51" />
-          <option name="screenDensity" value="420" />
-          <option name="screenX" value="1080" />
-          <option name="screenY" value="2400" />
-        </PersistentDeviceSelectionData>
-        <PersistentDeviceSelectionData>
-          <option name="api" value="34" />
-          <option name="brand" value="google" />
-          <option name="codename" value="akita" />
-          <option name="id" value="akita" />
-          <option name="manufacturer" value="Google" />
-          <option name="name" value="Pixel 8a" />
-          <option name="screenDensity" value="420" />
-          <option name="screenX" value="1080" />
-          <option name="screenY" value="2400" />
-        </PersistentDeviceSelectionData>
-        <PersistentDeviceSelectionData>
-          <option name="api" value="33" />
-          <option name="brand" value="samsung" />
-          <option name="codename" value="b0q" />
-          <option name="id" value="b0q" />
-          <option name="manufacturer" value="Samsung" />
-          <option name="name" value="Galaxy S22 Ultra" />
-          <option name="screenDensity" value="600" />
-          <option name="screenX" value="1440" />
-          <option name="screenY" value="3088" />
-        </PersistentDeviceSelectionData>
-        <PersistentDeviceSelectionData>
-          <option name="api" value="32" />
-          <option name="brand" value="google" />
-          <option name="codename" value="bluejay" />
-          <option name="id" value="bluejay" />
-          <option name="manufacturer" value="Google" />
-          <option name="name" value="Pixel 6a" />
-          <option name="screenDensity" value="420" />
-          <option name="screenX" value="1080" />
-          <option name="screenY" value="2400" />
-        </PersistentDeviceSelectionData>
-        <PersistentDeviceSelectionData>
-          <option name="api" value="34" />
-          <option name="brand" value="google" />
-          <option name="codename" value="caiman" />
-          <option name="id" value="caiman" />
-          <option name="manufacturer" value="Google" />
-          <option name="name" value="Pixel 9 Pro" />
-          <option name="screenDensity" value="360" />
-          <option name="screenX" value="960" />
-          <option name="screenY" value="2142" />
-        </PersistentDeviceSelectionData>
-        <PersistentDeviceSelectionData>
-          <option name="api" value="34" />
-          <option name="brand" value="google" />
-          <option name="codename" value="comet" />
-          <option name="id" value="comet" />
-          <option name="manufacturer" value="Google" />
-          <option name="name" value="Pixel 9 Pro Fold" />
-          <option name="screenDensity" value="390" />
-          <option name="screenX" value="2076" />
-          <option name="screenY" value="2152" />
-        </PersistentDeviceSelectionData>
-        <PersistentDeviceSelectionData>
-          <option name="api" value="29" />
-          <option name="brand" value="samsung" />
-          <option name="codename" value="crownqlteue" />
-          <option name="id" value="crownqlteue" />
-          <option name="manufacturer" value="Samsung" />
-          <option name="name" value="Galaxy Note9" />
-          <option name="screenDensity" value="420" />
-          <option name="screenX" value="2220" />
-          <option name="screenY" value="1080" />
-        </PersistentDeviceSelectionData>
-        <PersistentDeviceSelectionData>
-          <option name="api" value="34" />
-          <option name="brand" value="samsung" />
-          <option name="codename" value="dm3q" />
-          <option name="id" value="dm3q" />
-          <option name="manufacturer" value="Samsung" />
-          <option name="name" value="Galaxy S23 Ultra" />
-          <option name="screenDensity" value="600" />
-          <option name="screenX" value="1440" />
-          <option name="screenY" value="3088" />
-        </PersistentDeviceSelectionData>
-        <PersistentDeviceSelectionData>
-          <option name="api" value="34" />
-          <option name="brand" value="samsung" />
-          <option name="codename" value="e1q" />
-          <option name="id" value="e1q" />
-          <option name="manufacturer" value="Samsung" />
-          <option name="name" value="Galaxy S24" />
-          <option name="screenDensity" value="480" />
-          <option name="screenX" value="1080" />
-          <option name="screenY" value="2340" />
-        </PersistentDeviceSelectionData>
-        <PersistentDeviceSelectionData>
-          <option name="api" value="33" />
-          <option name="brand" value="google" />
-          <option name="codename" value="felix" />
-          <option name="id" value="felix" />
-          <option name="manufacturer" value="Google" />
-          <option name="name" value="Pixel Fold" />
-          <option name="screenDensity" value="420" />
-          <option name="screenX" value="2208" />
-          <option name="screenY" value="1840" />
-        </PersistentDeviceSelectionData>
-        <PersistentDeviceSelectionData>
-          <option name="api" value="34" />
-          <option name="brand" value="google" />
-          <option name="codename" value="felix" />
-          <option name="id" value="felix" />
-          <option name="manufacturer" value="Google" />
-          <option name="name" value="Pixel Fold" />
-          <option name="screenDensity" value="420" />
-          <option name="screenX" value="2208" />
-          <option name="screenY" value="1840" />
-        </PersistentDeviceSelectionData>
-        <PersistentDeviceSelectionData>
-          <option name="api" value="33" />
-          <option name="brand" value="google" />
-          <option name="codename" value="felix_camera" />
-          <option name="id" value="felix_camera" />
-          <option name="manufacturer" value="Google" />
-          <option name="name" value="Pixel Fold (Camera-enabled)" />
-          <option name="screenDensity" value="420" />
-          <option name="screenX" value="2208" />
-          <option name="screenY" value="1840" />
-        </PersistentDeviceSelectionData>
-        <PersistentDeviceSelectionData>
-          <option name="api" value="33" />
-          <option name="brand" value="samsung" />
-          <option name="codename" value="gts8uwifi" />
-          <option name="id" value="gts8uwifi" />
-          <option name="manufacturer" value="Samsung" />
-          <option name="name" value="Galaxy Tab S8 Ultra" />
-          <option name="screenDensity" value="320" />
-          <option name="screenX" value="1848" />
-          <option name="screenY" value="2960" />
-        </PersistentDeviceSelectionData>
-        <PersistentDeviceSelectionData>
-          <option name="api" value="34" />
-          <option name="brand" value="google" />
-          <option name="codename" value="husky" />
-          <option name="id" value="husky" />
-          <option name="manufacturer" value="Google" />
-          <option name="name" value="Pixel 8 Pro" />
-          <option name="screenDensity" value="390" />
-          <option name="screenX" value="1008" />
-          <option name="screenY" value="2244" />
-        </PersistentDeviceSelectionData>
-        <PersistentDeviceSelectionData>
-          <option name="api" value="30" />
-          <option name="brand" value="motorola" />
-          <option name="codename" value="java" />
-          <option name="id" value="java" />
-          <option name="manufacturer" value="Motorola" />
-          <option name="name" value="G20" />
-          <option name="screenDensity" value="280" />
-          <option name="screenX" value="720" />
-          <option name="screenY" value="1600" />
-        </PersistentDeviceSelectionData>
-        <PersistentDeviceSelectionData>
-          <option name="api" value="34" />
-          <option name="brand" value="google" />
-          <option name="codename" value="komodo" />
-          <option name="id" value="komodo" />
-          <option name="manufacturer" value="Google" />
-          <option name="name" value="Pixel 9 Pro XL" />
-          <option name="screenDensity" value="360" />
-          <option name="screenX" value="1008" />
-          <option name="screenY" value="2244" />
-        </PersistentDeviceSelectionData>
-        <PersistentDeviceSelectionData>
-          <option name="api" value="33" />
-          <option name="brand" value="google" />
-          <option name="codename" value="lynx" />
-          <option name="id" value="lynx" />
-          <option name="manufacturer" value="Google" />
-          <option name="name" value="Pixel 7a" />
-          <option name="screenDensity" value="420" />
-          <option name="screenX" value="1080" />
-          <option name="screenY" value="2400" />
-        </PersistentDeviceSelectionData>
-        <PersistentDeviceSelectionData>
-          <option name="api" value="31" />
-          <option name="brand" value="google" />
-          <option name="codename" value="oriole" />
-          <option name="id" value="oriole" />
-          <option name="manufacturer" value="Google" />
-          <option name="name" value="Pixel 6" />
-          <option name="screenDensity" value="420" />
-          <option name="screenX" value="1080" />
-          <option name="screenY" value="2400" />
-        </PersistentDeviceSelectionData>
-        <PersistentDeviceSelectionData>
-          <option name="api" value="33" />
-          <option name="brand" value="google" />
-          <option name="codename" value="panther" />
-          <option name="id" value="panther" />
-          <option name="manufacturer" value="Google" />
-          <option name="name" value="Pixel 7" />
-          <option name="screenDensity" value="420" />
-          <option name="screenX" value="1080" />
-          <option name="screenY" value="2400" />
-        </PersistentDeviceSelectionData>
-        <PersistentDeviceSelectionData>
-          <option name="api" value="34" />
-          <option name="brand" value="samsung" />
-          <option name="codename" value="q5q" />
-          <option name="id" value="q5q" />
-          <option name="manufacturer" value="Samsung" />
-          <option name="name" value="Galaxy Z Fold5" />
-          <option name="screenDensity" value="420" />
-          <option name="screenX" value="1812" />
-          <option name="screenY" value="2176" />
-        </PersistentDeviceSelectionData>
-        <PersistentDeviceSelectionData>
-          <option name="api" value="34" />
-          <option name="brand" value="samsung" />
-          <option name="codename" value="q6q" />
-          <option name="id" value="q6q" />
-          <option name="manufacturer" value="Samsung" />
-          <option name="name" value="Galaxy Z Fold6" />
-          <option name="screenDensity" value="420" />
-          <option name="screenX" value="1856" />
-          <option name="screenY" value="2160" />
-        </PersistentDeviceSelectionData>
-        <PersistentDeviceSelectionData>
-          <option name="api" value="30" />
-          <option name="brand" value="google" />
-          <option name="codename" value="r11" />
-          <option name="id" value="r11" />
-          <option name="manufacturer" value="Google" />
-          <option name="name" value="Pixel Watch" />
-          <option name="screenDensity" value="320" />
-          <option name="screenX" value="384" />
-          <option name="screenY" value="384" />
-          <option name="type" value="WEAR_OS" />
-        </PersistentDeviceSelectionData>
-        <PersistentDeviceSelectionData>
-          <option name="api" value="30" />
-          <option name="brand" value="google" />
-          <option name="codename" value="redfin" />
-          <option name="id" value="redfin" />
-          <option name="manufacturer" value="Google" />
-          <option name="name" value="Pixel 5" />
-          <option name="screenDensity" value="440" />
-          <option name="screenX" value="1080" />
-          <option name="screenY" value="2340" />
-        </PersistentDeviceSelectionData>
-        <PersistentDeviceSelectionData>
-          <option name="api" value="34" />
-          <option name="brand" value="google" />
-          <option name="codename" value="shiba" />
-          <option name="id" value="shiba" />
-          <option name="manufacturer" value="Google" />
-          <option name="name" value="Pixel 8" />
-          <option name="screenDensity" value="420" />
-          <option name="screenX" value="1080" />
-          <option name="screenY" value="2400" />
-        </PersistentDeviceSelectionData>
-        <PersistentDeviceSelectionData>
-          <option name="api" value="33" />
-          <option name="brand" value="google" />
-          <option name="codename" value="tangorpro" />
-          <option name="id" value="tangorpro" />
-          <option name="manufacturer" value="Google" />
-          <option name="name" value="Pixel Tablet" />
-          <option name="screenDensity" value="320" />
-          <option name="screenX" value="1600" />
-          <option name="screenY" value="2560" />
-        </PersistentDeviceSelectionData>
-        <PersistentDeviceSelectionData>
-          <option name="api" value="34" />
-          <option name="brand" value="google" />
-          <option name="codename" value="tokay" />
-          <option name="id" value="tokay" />
-          <option name="manufacturer" value="Google" />
-          <option name="name" value="Pixel 9" />
-          <option name="screenDensity" value="420" />
-          <option name="screenX" value="1080" />
-          <option name="screenY" value="2424" />
-        </PersistentDeviceSelectionData>
-      </list>
-    </option>
-  </component>
-</project>

+ 84 - 0
App/.kotlin/errors/errors-1732397093537.log

@@ -0,0 +1,84 @@
+kotlin version: 2.0.0
+error message: Daemon compilation failed: null
+java.lang.Exception
+	at org.jetbrains.kotlin.daemon.common.CompileService$CallResult$Error.get(CompileService.kt:69)
+	at org.jetbrains.kotlin.daemon.common.CompileService$CallResult$Error.get(CompileService.kt:65)
+	at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemon(GradleKotlinCompilerWork.kt:240)
+	at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemonOrFallbackImpl(GradleKotlinCompilerWork.kt:159)
+	at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.run(GradleKotlinCompilerWork.kt:111)
+	at org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers$GradleKotlinCompilerWorkAction.execute(GradleCompilerRunnerWithWorkers.kt:76)
+	at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:63)
+	at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:66)
+	at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:62)
+	at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:100)
+	at org.gradle.workers.internal.NoIsolationWorkerFactory$1.lambda$execute$0(NoIsolationWorkerFactory.java:62)
+	at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:44)
+	at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:41)
+	at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:200)
+	at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:195)
+	at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
+	at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
+	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
+	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
+	at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
+	at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73)
+	at org.gradle.workers.internal.AbstractWorker.executeWrappedInBuildOperation(AbstractWorker.java:41)
+	at org.gradle.workers.internal.NoIsolationWorkerFactory$1.execute(NoIsolationWorkerFactory.java:59)
+	at org.gradle.workers.internal.DefaultWorkerExecutor.lambda$submitWork$0(DefaultWorkerExecutor.java:174)
+	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
+	at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runExecution(DefaultConditionalExecutionQueue.java:187)
+	at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.access$700(DefaultConditionalExecutionQueue.java:120)
+	at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner$1.run(DefaultConditionalExecutionQueue.java:162)
+	at org.gradle.internal.Factories$1.create(Factories.java:31)
+	at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:264)
+	at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:128)
+	at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:133)
+	at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runBatch(DefaultConditionalExecutionQueue.java:157)
+	at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.run(DefaultConditionalExecutionQueue.java:126)
+	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)
+	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
+	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
+	at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47)
+	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
+	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
+	at java.base/java.lang.Thread.run(Thread.java:840)
+Caused by: java.nio.file.DirectoryNotEmptyException: C:\Users\User\AppData\Local\Temp\kotlin-backups11117319605272527924
+	at java.base/sun.nio.fs.WindowsFileSystemProvider.implDelete(WindowsFileSystemProvider.java:272)
+	at java.base/sun.nio.fs.AbstractFileSystemProvider.delete(AbstractFileSystemProvider.java:105)
+	at java.base/java.nio.file.Files.delete(Files.java:1152)
+	at org.jetbrains.kotlin.incremental.RecoverableCompilationTransaction$cleanupStash$2$1$1.invoke(CompilationTransaction.kt:244)
+	at org.jetbrains.kotlin.incremental.RecoverableCompilationTransaction$cleanupStash$2$1$1.invoke(CompilationTransaction.kt:244)
+	at org.jetbrains.kotlin.incremental.RecoverableCompilationTransaction.cleanupStash$lambda$11$lambda$10$lambda$9(CompilationTransaction.kt:244)
+	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
+	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
+	at java.base/java.util.stream.SortedOps$RefSortingSink.end(SortedOps.java:395)
+	at java.base/java.util.stream.Sink$ChainedReference.end(Sink.java:258)
+	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:510)
+	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
+	at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
+	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
+	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
+	at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596)
+	at org.jetbrains.kotlin.incremental.RecoverableCompilationTransaction.cleanupStash(CompilationTransaction.kt:244)
+	at org.jetbrains.kotlin.incremental.RecoverableCompilationTransaction.close(CompilationTransaction.kt:254)
+	at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.tryCompileIncrementally(IncrementalCompilerRunner.kt:747)
+	at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:120)
+	at org.jetbrains.kotlin.daemon.CompileServiceImplBase.execIncrementalCompiler(CompileServiceImpl.kt:676)
+	at org.jetbrains.kotlin.daemon.CompileServiceImplBase.access$execIncrementalCompiler(CompileServiceImpl.kt:92)
+	at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1661)
+	at jdk.internal.reflect.GeneratedMethodAccessor14.invoke(Unknown Source)
+	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
+	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
+	at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:360)
+	at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:200)
+	at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:197)
+	at java.base/java.security.AccessController.doPrivileged(AccessController.java:712)
+	at java.rmi/sun.rmi.transport.Transport.serviceCall(Transport.java:196)
+	at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:587)
+	at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:828)
+	at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:705)
+	at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
+	at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:704)
+	... 3 more
+
+

+ 3 - 0
App/app/build.gradle.kts

@@ -88,6 +88,9 @@ dependencies {
     implementation (libs.gson)
     implementation (libs.jackson.module.kotlin)
     implementation(libs.coil.compose)
+    implementation(libs.retrofit)
+    implementation(libs.converter.gson)
+    implementation(libs.logging.interceptor)
 
 
 }

+ 128 - 2
App/app/src/main/java/com/example/mystictale/MainActivity.kt

@@ -5,13 +5,66 @@ import android.os.Bundle
 import androidx.activity.ComponentActivity
 import androidx.activity.compose.setContent
 import androidx.activity.enableEdgeToEdge
+import androidx.activity.viewModels
 import androidx.annotation.RequiresApi
-import com.example.mystictale.Screen.Cards
+import androidx.annotation.RequiresExtension
+import androidx.compose.foundation.background
+import androidx.compose.foundation.border
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.foundation.text.BasicText
+import androidx.compose.material3.DropdownMenuItem
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.ExposedDropdownMenuBox
+import androidx.compose.material3.ExposedDropdownMenuDefaults
+import androidx.compose.material3.OutlinedTextField
+import androidx.compose.material3.Text
+import androidx.compose.material3.TextField
+import androidx.compose.material3.TextFieldDefaults
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.text.AnnotatedString
+import androidx.compose.ui.text.SpanStyle
+import androidx.compose.ui.text.buildAnnotatedString
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.withStyle
+import androidx.compose.ui.unit.dp
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.example.mystictale.Screen.DialogWithAI
+import com.example.mystictale.ViewModels.AIViewModel
+import com.example.mystictale.aiConnect.RepositoryImpl
+import com.example.mystictale.aiConnect.RetrofitInstance
 import com.example.mystictale.navigation.Navigation
+import com.example.mystictale.ui.theme.Grey
 import com.example.mystictale.ui.theme.MysticTaleTheme
 
 
 class MainActivity : ComponentActivity() {
+    private val viewModel by viewModels<AIViewModel>(factoryProducer = {
+        object : ViewModelProvider.Factory {
+            @RequiresExtension(extension = Build.VERSION_CODES.S, version = 7)
+            override fun <T : ViewModel> create(modelClass: Class<T>): T {
+                return AIViewModel(RepositoryImpl(RetrofitInstance.api))
+                        as T
+            }
+        }
+    })
+
+    @OptIn(ExperimentalMaterial3Api::class)
+    @RequiresExtension(extension = Build.VERSION_CODES.S, version = 7)
     @RequiresApi(Build.VERSION_CODES.O)
     override fun onCreate(savedInstanceState: Bundle?) {
 
@@ -19,13 +72,86 @@ class MainActivity : ComponentActivity() {
         enableEdgeToEdge()
         setContent {
             MysticTaleTheme {
+
                 //Navigation()
-                Cards()
+                DialogWithAI(viewModel)
+
+                val characterList = viewModel.answer.collectAsState().value
+                val context = LocalContext.current
+//                LaunchedEffect(Unit) {
+//                    withContext(Dispatchers.IO) {
+//                        viewModel.sendARequest(
+//                            listOf(
+//                                Message(
+//                                    "system",
+//                                    "Ты таролог с многолетним стажем. Помоги новичку, ответь на все его вопросы сам, не перенапрвляя его к другим"
+//                                ),
+//                                Message("user", "Привет! Что значит карта шут в раскладе на любовь")
+//                            )
+//                        )
+//                    }
+//                }
+//
+//                if (characterList == null) {
+//                    Box(
+//                        modifier = Modifier.fillMaxSize(),
+//                        contentAlignment = Alignment.Center
+//                    ) {
+//                        CircularProgressIndicator()
+//                    }
+//                } else {
+//                    DisplayFormattedText(characterList.result.alternatives.last().message.text)
+//                }
+
+
+
             }
         }
     }
 }
 
+@Composable
+fun DisplayFormattedText(input: String) {
+    val formattedText = parseMarkdownToAnnotatedString(input)
+
+    BasicText(
+        text = formattedText
+    )
+}
+
+// Функция для обработки строки с **форматированием**
+fun parseMarkdownToAnnotatedString(input: String): AnnotatedString {
+    val regex = "\\*\\*(.*?)\\*\\*".toRegex() // Находит текст, обрамленный **
+
+    return buildAnnotatedString {
+        var currentIndex = 0
+
+        regex.findAll(input).forEach { matchResult ->
+            val start = matchResult.range.first
+            val end = matchResult.range.last
+            val boldText = matchResult.groupValues[1] // Текст между **
+
+            // Добавляем обычный текст до выделенного
+            if (start > currentIndex) {
+                append(input.substring(currentIndex, start))
+            }
+
+            // Добавляем жирный текст
+            withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) {
+                append(boldText)
+            }
+
+            currentIndex = end + 1
+        }
+
+        // Добавляем остаток текста после последнего выделения
+        if (currentIndex < input.length) {
+            append(input.substring(currentIndex))
+        }
+    }
+}
+
+
 
 
 

+ 0 - 98
App/app/src/main/java/com/example/mystictale/Screen/Cards.kt

@@ -1,98 +0,0 @@
-package com.example.mystictale.Screen
-
-import androidx.compose.foundation.gestures.detectTapGestures
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.padding
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.paint
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.input.pointer.pointerInput
-import androidx.compose.ui.layout.ContentScale
-import androidx.compose.ui.platform.LocalContext
-import androidx.compose.ui.platform.LocalFocusManager
-import androidx.compose.ui.platform.LocalSoftwareKeyboardController
-import androidx.compose.ui.res.painterResource
-import androidx.compose.ui.text.font.FontWeight
-import androidx.compose.ui.tooling.preview.Preview
-import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.sp
-import com.example.mystictale.R
-import com.example.mystictale.resources.components.SearchTextField
-import com.example.mystictale.resources.components.dateComponents.ChooseArcana
-import com.example.mystictale.ui.theme.OpenSans
-@Preview
-@Composable
-fun Cards() {
-    val focusManager = LocalFocusManager.current
-    val context = LocalContext.current
-    val keyboardController = LocalSoftwareKeyboardController.current
-    val search = remember {
-        mutableStateOf("")
-    }
-    Column(
-        Modifier
-            .fillMaxSize()
-            .paint(
-                painterResource(id = R.drawable.background),
-                contentScale = ContentScale.FillBounds
-            )
-            .pointerInput(Unit) {
-                detectTapGestures(onTap = {
-                    keyboardController?.hide()
-                    focusManager.clearFocus()
-                })
-            }
-            .padding(35.dp)
-            .padding(top = 15.dp),
-        verticalArrangement = Arrangement.Top,
-        horizontalAlignment = Alignment.CenterHorizontally
-    ) {
-        Row(
-            modifier = Modifier.fillMaxWidth(),
-            horizontalArrangement = Arrangement.Center,
-            verticalAlignment = Alignment.CenterVertically
-        ) {
-            Text(
-                text = "Значения карт Таро",
-                fontFamily = OpenSans,
-                fontWeight = FontWeight.Bold,
-                fontSize = 30.sp,
-                color = Color.White
-            )
-        }
-        Spacer(modifier = Modifier.height(5.dp))
-
-        Row(
-            modifier = Modifier.fillMaxWidth(),
-            horizontalArrangement = Arrangement.Center,
-            verticalAlignment = Alignment.CenterVertically
-        ) {
-
-            SearchTextField(search.value) { search.value = it }
-        }
-        Spacer(modifier = Modifier.height(5.dp))
-
-        Row(
-            modifier = Modifier.fillMaxWidth(),
-            horizontalArrangement = Arrangement.Center,
-            verticalAlignment = Alignment.CenterVertically
-        ) {
-
-            ChooseArcana()
-        }
-
-
-    }
-
-}

+ 152 - 0
App/app/src/main/java/com/example/mystictale/Screen/CardsScreen.kt

@@ -0,0 +1,152 @@
+package com.example.mystictale.Screen
+
+import androidx.compose.foundation.gestures.detectTapGestures
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.lazy.grid.GridCells
+import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
+import androidx.compose.foundation.lazy.grid.items
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.paint
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.input.pointer.pointerInput
+import androidx.compose.ui.layout.ContentScale
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.LocalFocusManager
+import androidx.compose.ui.platform.LocalSoftwareKeyboardController
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import androidx.navigation.NavController
+import com.example.mystictale.R
+import com.example.mystictale.ViewModels.CardsViewModel
+import com.example.mystictale.resources.components.Loading
+import com.example.mystictale.resources.components.SearchTextField
+import com.example.mystictale.resources.components.ChooseArcana
+import com.example.mystictale.resources.components.ChooseSuit
+import com.example.mystictale.resources.components.LayoutCard
+import com.example.mystictale.ui.theme.OpenSans
+
+@Composable
+fun CardsScreen(navController: NavController,viewModel: CardsViewModel) {
+    val focusManager = LocalFocusManager.current
+    val context = LocalContext.current
+    val keyboardController = LocalSoftwareKeyboardController.current
+    val search = remember {
+        mutableStateOf("")
+    }
+    val cards by viewModel.cards
+
+
+    val flag = remember { mutableStateOf(true) }
+
+    if (flag.value) {
+        viewModel.selectCards()
+        flag.value = false
+    }
+    if (cards.isNotEmpty()) {
+        val filteredCards by viewModel.filteredCards
+        Column(
+
+            Modifier
+                .fillMaxSize()
+                .paint(
+                    painterResource(id = R.drawable.background),
+                    contentScale = ContentScale.FillBounds
+                )
+                .pointerInput(Unit) {
+                    detectTapGestures(onTap = {
+                        keyboardController?.hide()
+                        focusManager.clearFocus()
+                    })
+                }
+                .padding(10.dp)
+                .padding(top = 40.dp),
+            verticalArrangement = Arrangement.Top,
+            horizontalAlignment = Alignment.CenterHorizontally
+        ) {
+            Row(
+                modifier = Modifier.fillMaxWidth(),
+                horizontalArrangement = Arrangement.Center,
+                verticalAlignment = Alignment.CenterVertically
+            ) {
+                Text(
+                    text = "Значения карт Таро",
+                    fontFamily = OpenSans,
+                    fontWeight = FontWeight.Bold,
+                    fontSize = 25.sp,
+                    color = Color.White
+                )
+            }
+            Spacer(modifier = Modifier.height(15.dp))
+
+            Row(
+                modifier = Modifier.fillMaxWidth(),
+                horizontalArrangement = Arrangement.Center,
+                verticalAlignment = Alignment.CenterVertically
+            ) {
+
+                SearchTextField(search.value) {
+                    search.value = it
+                    viewModel.searchQuery.value = search.value
+                    viewModel.filteredCards()
+                }
+            }
+            Spacer(modifier = Modifier.height(15.dp))
+
+            Row(
+                modifier = Modifier.fillMaxWidth(),
+                horizontalArrangement = Arrangement.Center,
+                verticalAlignment = Alignment.CenterVertically
+            ) {
+
+                ChooseArcana(viewModel)
+            }
+            Spacer(modifier = Modifier.height(10.dp))
+            if(viewModel.arcana == 2){
+                Row(
+                    modifier = Modifier.fillMaxWidth().padding(bottom = 10.dp),
+                    horizontalArrangement = Arrangement.Center,
+                    verticalAlignment = Alignment.CenterVertically
+                ) {
+
+                    ChooseSuit(viewModel)
+                }
+            }
+            LazyVerticalGrid(columns = GridCells.Fixed(3), Modifier.fillMaxWidth()) {
+                items(filteredCards) { card ->
+                    LayoutCard(card,viewModel,navController)
+                }
+            }
+
+
+        }
+
+    } else {
+        Box(
+            Modifier
+                .fillMaxSize()
+                .paint(
+                    painterResource(id = R.drawable.background),
+                    contentScale = ContentScale.FillBounds
+                )
+        ) {
+            Loading()
+        }
+    }
+
+}

+ 70 - 0
App/app/src/main/java/com/example/mystictale/Screen/ChatWithAI.kt

@@ -0,0 +1,70 @@
+package com.example.mystictale.Screen
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.paint
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.layout.ContentScale
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import com.example.mystictale.R
+import com.example.mystictale.resources.components.ButtonAI
+import com.example.mystictale.ui.theme.OpenSans
+
+
+@Composable
+fun ChatWithAI() {
+    Box(
+        Modifier
+            .fillMaxSize()
+            .paint(
+                painterResource(id = R.drawable.background),
+                contentScale = ContentScale.FillBounds
+            )
+            .padding(top = 40.dp)
+            .padding(10.dp)
+    ) {
+        Row(
+            modifier = Modifier
+                .fillMaxSize()
+                .padding(horizontal = 30.dp),
+            horizontalArrangement = Arrangement.Center,
+            verticalAlignment = Alignment.Top
+        ) {
+            Text(
+                text = "Расшифровка расклада с помощью ИИ",
+                fontFamily = OpenSans,
+                fontWeight = FontWeight.Bold,
+                fontSize = 26.sp,
+                color = Color.White,
+                textAlign = TextAlign.Center
+            )
+        }
+
+        Column(
+            modifier = Modifier
+                .fillMaxSize()
+                .padding(horizontal = 30.dp),
+            verticalArrangement = Arrangement.Center,
+            horizontalAlignment = Alignment.CenterHorizontally
+        ) {
+            ButtonAI("Текстовый запрос") {}
+            ButtonAI("Линейный расклад") {}
+            ButtonAI("Кельтский крест") {}
+        }
+
+
+    }
+}

+ 172 - 0
App/app/src/main/java/com/example/mystictale/Screen/DialogWithAI.kt

@@ -0,0 +1,172 @@
+package com.example.mystictale.Screen
+
+import android.os.Build
+import android.widget.Toast
+import androidx.annotation.RequiresExtension
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.items
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonColors
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.paint
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.layout.ContentScale
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import com.example.mystictale.R
+import com.example.mystictale.ViewModels.AIViewModel
+import com.example.mystictale.models.DataState
+import com.example.mystictale.models.Message
+import com.example.mystictale.resources.components.AIMessage
+import com.example.mystictale.resources.components.Loading
+import com.example.mystictale.resources.components.TextFieldForAI
+import com.example.mystictale.resources.components.UserMessage
+import com.example.mystictale.ui.theme.OpenSans
+
+@RequiresExtension(extension = Build.VERSION_CODES.S, version = 7)
+@Composable
+fun DialogWithAI(viewModel: AIViewModel) {
+    val dataState by viewModel.dataState
+    val context = LocalContext.current
+    val query = remember { mutableStateOf("") }
+    val enabled = remember { mutableStateOf(true) }
+    val dialog = remember { mutableStateOf(listOf<Message>()) }
+    val answer = remember { mutableStateOf(false) }
+    Column(
+        Modifier
+            .fillMaxSize()
+            .paint(
+                painterResource(id = R.drawable.background),
+                contentScale = ContentScale.FillBounds
+            )
+            .padding(top = 10.dp)
+            .padding(10.dp),
+        verticalArrangement = Arrangement.SpaceBetween,
+        horizontalAlignment = Alignment.CenterHorizontally
+    ) {
+        Box(Modifier.fillMaxWidth()) {
+            Row(
+                modifier = Modifier
+                    .fillMaxWidth()
+                    .padding(horizontal = 30.dp)
+                    .padding(top = 30.dp),
+                horizontalArrangement = Arrangement.Center,
+                verticalAlignment = Alignment.Top
+            ) {
+                Text(
+                    text = "Диалог с ИИ",
+                    fontFamily = OpenSans,
+                    fontWeight = FontWeight.Bold,
+                    fontSize = 26.sp,
+                    color = Color.White,
+                    textAlign = TextAlign.Center
+                )
+            }
+            Row(
+                modifier = Modifier
+                    .fillMaxWidth()
+                    .padding(),
+                horizontalArrangement = Arrangement.Start,
+                verticalAlignment = Alignment.Top
+            ) {
+                Button(
+                    onClick = { },
+                    colors = ButtonColors(
+                        disabledContentColor = Color.White,
+                        disabledContainerColor = Color.Transparent,
+                        contentColor = Color.White,
+                        containerColor = Color.Transparent
+                    )
+                ) {
+                    Image(
+                        painter = painterResource(id = R.drawable.back),
+                        contentDescription = "back",
+                        modifier = Modifier
+                            .width(11.dp)
+                            .height(14.dp)
+                    )
+                }
+            }
+        }
+
+
+        Column(
+            modifier = Modifier
+                .fillMaxWidth()
+                .padding(bottom = 10.dp)
+                .padding(horizontal = 20.dp),
+            verticalArrangement = Arrangement.Bottom,
+            horizontalAlignment = Alignment.CenterHorizontally
+        ) {
+
+            LazyColumn {
+                items(dialog.value) {
+                    if (it.role == "user") {
+                        UserMessage(it.text)
+                    }
+                    Spacer(Modifier.height(20.dp))
+                    if (it.role == "assistant") {
+                        AIMessage(
+                            it.text
+                        )
+                    }
+
+
+                }
+            }
+
+            Spacer(Modifier.height(10.dp))
+            TextFieldForAI(query.value, enabled.value, onValue = { query.value = it }, onClick = {
+                viewModel.sendARequest(
+                    listOf(Message("user", query.value))
+                )
+                answer.value = true
+                query.value = ""
+            })
+
+        }
+    }
+    if (answer.value) {
+        when (dataState) {
+            is DataState.Loading -> {
+                Loading()
+            }
+
+            is DataState.Success -> {
+                val AIanswer = viewModel.answer.collectAsState().value
+                dialog.value += AIanswer!!.result.alternatives.last().message
+                answer.value = false
+            }
+
+            is DataState.Error -> {
+                Toast.makeText(context, "Error", Toast.LENGTH_SHORT).show()
+                answer.value = false
+            }
+        }
+    }
+
+}

+ 168 - 0
App/app/src/main/java/com/example/mystictale/Screen/InfoCard.kt

@@ -0,0 +1,168 @@
+package com.example.mystictale.Screen
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonColors
+import androidx.compose.material3.CircularProgressIndicator
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.paint
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.layout.ContentScale
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import androidx.navigation.NavController
+import coil.compose.AsyncImagePainter
+import coil.compose.rememberAsyncImagePainter
+import coil.request.ImageRequest
+import com.example.mystictale.R
+import com.example.mystictale.ViewModels.CardsViewModel
+import com.example.mystictale.navigation.Screens
+import com.example.mystictale.resources.components.Loading
+import com.example.mystictale.resources.components.ValuesDropMenu
+import com.example.mystictale.ui.theme.OpenSans
+
+@Composable
+fun InfoCard(viewModel: CardsViewModel, navController: NavController) {
+    val card = viewModel.card!!
+    val values by viewModel.values
+    if (values.isNotEmpty()) {
+        Column(
+            Modifier
+                .fillMaxSize()
+                .paint(
+                    painterResource(id = R.drawable.background),
+                    contentScale = ContentScale.FillBounds
+                )
+                .verticalScroll(rememberScrollState())
+                .padding(10.dp),
+            verticalArrangement = Arrangement.SpaceBetween,
+            horizontalAlignment = Alignment.CenterHorizontally
+        ) {
+
+            Column {
+                Box(
+                    modifier = Modifier
+                        .padding(top = 30.dp)
+                        .height(40.dp)
+                        .fillMaxWidth(),
+                    contentAlignment = Alignment.TopStart
+                ) {
+                    Button(
+                        onClick = { navController.navigate(Screens.AppNavigation.route) },
+                        colors = ButtonColors(
+                            disabledContentColor = Color.White,
+                            disabledContainerColor = Color.Transparent,
+                            contentColor = Color.White,
+                            containerColor = Color.Transparent
+                        )
+                    ) {
+                        Image(
+                            painter = painterResource(id = R.drawable.back),
+                            contentDescription = "back",
+                            modifier = Modifier
+                                .width(11.dp)
+                                .height(14.dp)
+                        )
+                    }
+                }
+                Column(
+                    modifier = Modifier
+                        .fillMaxWidth()
+                        .padding(vertical = 10.dp),
+                    verticalArrangement = Arrangement.Top,
+                    horizontalAlignment = Alignment.CenterHorizontally
+                ) {
+
+                    Text(
+                        text = card.title,
+                        fontWeight = FontWeight.Bold,
+                        fontFamily = OpenSans,
+                        fontSize = 24.sp,
+                        color = Color.White,
+                        style = MaterialTheme.typography.headlineMedium
+                    )
+                    Spacer(modifier = Modifier.height(30.dp))
+                    val imageCard = rememberAsyncImagePainter(
+                        model = ImageRequest.Builder(LocalContext.current).data(card.image)
+                            .size(142, 242).build()
+                    ).state
+
+
+                    if (imageCard is AsyncImagePainter.State.Success) {
+                        Image(
+                            painter = imageCard.painter,
+                            contentDescription = "",
+                            modifier = Modifier
+                                .height(242.dp)
+                                .width(142.dp)
+                        )
+                    }
+                    if (imageCard is AsyncImagePainter.State.Loading) {
+                        Box(
+                            modifier = Modifier
+                                .fillMaxWidth()
+                                .height(200.dp),
+                            contentAlignment = Alignment.Center
+                        ) {
+                            CircularProgressIndicator()
+                        }
+                    }
+                    if (imageCard is AsyncImagePainter.State.Error) {
+                        Box(
+                            modifier = Modifier
+                                .fillMaxWidth(),
+                            contentAlignment = Alignment.Center
+                        ) {
+                            CircularProgressIndicator()
+                        }
+
+                    }
+                    Spacer(modifier = Modifier.height(30.dp))
+
+                    Box(
+                        Modifier
+                            .fillMaxWidth()
+                            .padding(horizontal = 10.dp)) {
+                        ValuesDropMenu(values)
+                    }
+
+
+                }
+
+
+            }
+        }
+    } else {
+        Box(
+            Modifier
+                .fillMaxSize()
+                .paint(
+                    painterResource(id = R.drawable.background),
+                    contentScale = ContentScale.FillBounds
+                )
+        ) {
+            Loading()
+        }
+    }
+
+
+}

+ 76 - 12
App/app/src/main/java/com/example/mystictale/Screen/LoadingScreen.kt

@@ -1,27 +1,91 @@
 package drawable.Screen
 
 import androidx.compose.foundation.Image
-import androidx.compose.foundation.background
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.layout.ContentScale
+import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.res.painterResource
-import androidx.compose.ui.tooling.preview.Preview
+import androidx.navigation.NavController
 import com.example.mystictale.R
-@Preview
+import com.example.mystictale.ViewModels.AuthViewModel
+import com.example.mystictale.models.DataState
+import com.example.mystictale.navigation.Screens
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+
 @Composable
-fun LoadingScreen() {
-    Column(Modifier.fillMaxSize()) {
+fun LoadingScreen(navController: NavController, viewModel: AuthViewModel) {
+
+    val context = LocalContext.current
+    val dataState by viewModel.dataState
+    val flag = remember { mutableStateOf(true) }
+    val flag2 = remember { mutableStateOf(false) }
+    val flag3 = remember { mutableStateOf(false) }
+    if(flag.value){
+        viewModel.isUserLoggedIn(context)
+        flag.value = false
+        flag2.value = true
+    }
+    if (flag2.value) {
+        when (dataState) {
+            is DataState.Loading -> {
+                Column(Modifier.fillMaxSize()) {
+                    Image(
+                        painter = painterResource(id = R.drawable.loading),
+                        contentDescription = "",
+                        contentScale = ContentScale.FillHeight,
+                        modifier = Modifier.fillMaxSize()
+                    )
+
+                }
+            }
+            is DataState.Success -> {
+                viewModel.checkForRegistration()
+                flag2.value = false
+                flag3.value = true
+            }
 
-        Image(
-            painter = painterResource(id = R.drawable.loading),
-            contentDescription = "",
-            contentScale = ContentScale.FillHeight,
-            modifier = Modifier.fillMaxSize()
-        )
+            is DataState.Error -> {
+                navController.navigate(Screens.Start.route)
+                flag2.value = false
+            }
+        }
+    }
+    if (flag3.value) {
+        when (dataState) {
+            is DataState.Loading -> {
+                Column(Modifier.fillMaxSize()) {
+                    Image(
+                        painter = painterResource(id = R.drawable.loading),
+                        contentDescription = "",
+                        contentScale = ContentScale.FillHeight,
+                        modifier = Modifier.fillMaxSize()
+                    )
+
+                }
+            }
+            is DataState.Success -> {
+                if(viewModel.user.value.isEmpty()){
+                    navController.navigate(Screens.Start.route)
+                }else{
+                    navController.navigate(Screens.AppNavigation.route)
+                }
+                flag3.value = false
 
+            }
+
+            is DataState.Error -> {
+                navController.navigate(Screens.Start.route)
+                flag3.value = false
+            }
+        }
     }
+
 }

+ 54 - 18
App/app/src/main/java/com/example/mystictale/Screen/Profile.kt

@@ -55,7 +55,8 @@ import coil.compose.rememberAsyncImagePainter
 import coil.request.ImageRequest
 import com.example.mystictale.R
 import com.example.mystictale.ViewModels.AuthViewModel
-import com.example.mystictale.models.UserState
+import com.example.mystictale.models.DataState
+import com.example.mystictale.navigation.Screens
 import com.example.mystictale.resources.components.ChooseGenderForProfile
 import com.example.mystictale.resources.components.ImageForBitmap
 import com.example.mystictale.resources.components.ImagePainter
@@ -67,6 +68,7 @@ import com.example.mystictale.resources.components.dateComponents.FormattingDate
 import com.example.mystictale.resources.components.dateComponents.ValidationDate
 import com.example.mystictale.resources.components.dateComponents.isDateValid
 import com.example.mystictale.ui.theme.DarkPurple
+import com.example.mystictale.ui.theme.DarkRed
 import com.example.mystictale.ui.theme.Grey
 import com.example.mystictale.ui.theme.OpenSans
 import com.vanpra.composematerialdialogs.MaterialDialog
@@ -84,7 +86,7 @@ import java.util.Locale
 fun Profile(navController: NavController, viewModel: AuthViewModel) {
 
     val user by viewModel.user
-    val userState by viewModel.userState
+    val userState by viewModel.dataState
     val focusManager = LocalFocusManager.current
     val context = LocalContext.current
     val keyboardController = LocalSoftwareKeyboardController.current
@@ -93,6 +95,7 @@ fun Profile(navController: NavController, viewModel: AuthViewModel) {
     val flag = remember { mutableStateOf(true) }
     val flag1 = remember { mutableStateOf(false) }
     val flag2 = remember { mutableStateOf(false) }
+    val flagLogout = remember { mutableStateOf(false) }
     val nameFlag = remember { mutableStateOf(false) }
     val dateOfBirthFlag = remember { mutableStateOf(false) }
 
@@ -371,7 +374,7 @@ fun Profile(navController: NavController, viewModel: AuthViewModel) {
 
             }
 
-            AnimatedVisibility(visible = isEnabled.value, Modifier.padding(40.dp)) {
+            AnimatedVisibility(visible = isEnabled.value, Modifier.padding( vertical = 10.dp)) {
                 Button(
                     onClick = {
                         if (ValidationDate(
@@ -389,11 +392,6 @@ fun Profile(navController: NavController, viewModel: AuthViewModel) {
                         } else {
                             viewModel.name = name.value
                             viewModel.dateOfBirth = dateForBase
-                            viewModel.gender = if (gender.value == "Женский") {
-                                1
-                            } else {
-                                2
-                            }
                             viewModel.addAvatar(newAvatar.value)
                             flag1.value = true
                         }
@@ -402,7 +400,7 @@ fun Profile(navController: NavController, viewModel: AuthViewModel) {
                     modifier = Modifier
                         .fillMaxWidth()
                         .height(48.dp)
-                        .padding(horizontal = 30.dp),
+                        .padding(horizontal = 20.dp,),
                     shape = RoundedCornerShape(12.dp),
                     colors = ButtonColors(
                         containerColor = DarkPurple,
@@ -415,7 +413,25 @@ fun Profile(navController: NavController, viewModel: AuthViewModel) {
 
                 }
             }
+            Spacer(Modifier.height(10.dp))
+            Button(
+                onClick = {viewModel.logout(context)
+                          flagLogout.value = true},
+                modifier = Modifier
+                    .fillMaxWidth()
+                    .height(48.dp)
+                    .padding(horizontal = 20.dp),
+                shape = RoundedCornerShape(12.dp),
+                colors = ButtonColors(
+                    containerColor = DarkRed,
+                    contentColor = Color.White,
+                    disabledContentColor = Color.White,
+                    disabledContainerColor = DarkRed
+                )
+            ) {
+                Text("Выйти", fontSize = 14.sp, fontWeight = FontWeight.Normal)
 
+            }
 
         }
         MaterialDialog(
@@ -438,6 +454,8 @@ fun Profile(navController: NavController, viewModel: AuthViewModel) {
 
             }
         }
+
+
     } else {
         Box(
             Modifier
@@ -452,19 +470,19 @@ fun Profile(navController: NavController, viewModel: AuthViewModel) {
     }
     if (flag1.value) {
         when (userState) {
-            is UserState.Loading -> {
+            is DataState.Loading -> {
                 Loading()
             }
 
-            is UserState.Success -> {
-                val message = (userState as UserState.Success).message
+            is DataState.Success -> {
+                val message = (userState as DataState.Success).message
                 viewModel.updateProfile()
                 flag1.value = false
                 flag2.value = true
             }
 
-            is UserState.Error -> {
-                val message = (userState as UserState.Error).message
+            is DataState.Error -> {
+                val message = (userState as DataState.Error).message
                 Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
                 flag1.value = false
             }
@@ -472,23 +490,41 @@ fun Profile(navController: NavController, viewModel: AuthViewModel) {
     }
     if (flag2.value) {
         when (userState) {
-            is UserState.Loading -> {
+            is DataState.Loading -> {
                 Loading()
             }
 
-            is UserState.Success -> {
+            is DataState.Success -> {
                 Toast.makeText(context, "Изменения сохранены", Toast.LENGTH_SHORT).show()
                 isEnabled.value = false
                 flag2.value = false
             }
 
-            is UserState.Error -> {
-                val message = (userState as UserState.Error).message
+            is DataState.Error -> {
+                val message = (userState as DataState.Error).message
                 Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
                 flag2.value = false
             }
         }
     }
+    if (flagLogout.value) {
+        when (userState) {
+            is DataState.Loading -> {
+                Loading()
+            }
+
+            is DataState.Success -> {
+                navController.navigate(Screens.Start.route)
+                flagLogout.value = false
+            }
+
+            is DataState.Error -> {
+                val message = (userState as DataState.Error).message
+                Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
+                flagLogout.value = false
+            }
+        }
+    }
 
 
 }

+ 56 - 0
App/app/src/main/java/com/example/mystictale/Screen/TypewriterText.kt

@@ -0,0 +1,56 @@
+package com.example.mystictale.Screen
+
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import com.example.mystictale.ui.theme.OpenSans
+import kotlinx.coroutines.delay
+
+
+@Composable
+fun TypewriterText(
+    texts: List<String>,
+) {
+    var textIndex by remember {
+        mutableStateOf(0)
+    }
+    var textToDisplay by remember {
+        mutableStateOf("")
+    }
+
+    LaunchedEffect(
+        key1 = texts,
+    ) {
+        while (textIndex < texts.size) {
+            texts[textIndex].forEachIndexed { charIndex, _ ->
+                textToDisplay = texts[textIndex]
+                    .substring(
+                        startIndex = 0,
+                        endIndex = charIndex + 1,
+                    )
+                delay(50)
+            }
+            textIndex = (textIndex + 1) % texts.size
+            delay(1000)
+        }
+    }
+
+    Text(
+        text = textToDisplay,
+        fontWeight = FontWeight.Normal,
+        fontFamily = OpenSans,
+        fontSize = 13.sp,
+        color = Color.White,
+        modifier = Modifier.padding(7.dp)
+    )
+}

+ 6 - 6
App/app/src/main/java/com/example/mystictale/Screen/passwordRecovery/NewPassword.kt

@@ -38,7 +38,7 @@ import androidx.core.text.isDigitsOnly
 import androidx.navigation.NavController
 import com.example.mystictale.R
 import com.example.mystictale.ViewModels.AuthViewModel
-import com.example.mystictale.models.UserState
+import com.example.mystictale.models.DataState
 import com.example.mystictale.navigation.Screens
 import com.example.mystictale.resources.components.Loading
 import com.example.mystictale.resources.components.PasswordTextField
@@ -48,7 +48,7 @@ import com.example.mystictale.ui.theme.OpenSans
 
 @Composable
 fun NewPassword(navController: NavController, viewModel: AuthViewModel) {
-    val userState by viewModel.userState
+    val userState by viewModel.dataState
     val focusManager = LocalFocusManager.current
     val context = LocalContext.current
     val keyboardController = LocalSoftwareKeyboardController.current
@@ -223,17 +223,17 @@ fun NewPassword(navController: NavController, viewModel: AuthViewModel) {
     }
     if (flag.value) {
         when (userState) {
-            is UserState.Loading -> {
+            is DataState.Loading -> {
                 Loading()
             }
 
-            is UserState.Success -> {
+            is DataState.Success -> {
                 navController.navigate(Screens.Start.route)
                 flag.value = false
             }
 
-            is UserState.Error -> {
-                val message = (userState as UserState.Error).message
+            is DataState.Error -> {
+                val message = (userState as DataState.Error).message
                 Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
                 flag.value = false
             }

+ 10 - 11
App/app/src/main/java/com/example/mystictale/Screen/registration/RegistrationGender.kt

@@ -15,7 +15,6 @@ import androidx.compose.foundation.layout.width
 import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.material3.Button
 import androidx.compose.material3.ButtonColors
-import androidx.compose.material3.CircularProgressIndicator
 import androidx.compose.material3.LinearProgressIndicator
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Text
@@ -37,7 +36,7 @@ import androidx.compose.ui.unit.sp
 import androidx.navigation.NavController
 import com.example.mystictale.R
 import com.example.mystictale.ViewModels.AuthViewModel
-import com.example.mystictale.models.UserState
+import com.example.mystictale.models.DataState
 import com.example.mystictale.navigation.Screens
 import com.example.mystictale.resources.components.ChooseGender
 import com.example.mystictale.resources.components.Loading
@@ -46,7 +45,7 @@ import com.example.mystictale.ui.theme.OpenSans
 
 @Composable
 fun RegistrationGender(navController: NavController, viewModel: AuthViewModel) {
-    val userState by viewModel.userState
+    val userState by viewModel.dataState
     val flag = remember { mutableStateOf(false) }
     val flag2 = remember { mutableStateOf(false) }
     val genderFlag = remember { mutableStateOf(false) }
@@ -170,18 +169,18 @@ fun RegistrationGender(navController: NavController, viewModel: AuthViewModel) {
     }
     if (flag.value) {
         when (userState) {
-            is UserState.Loading -> {
+            is DataState.Loading -> {
                 Loading()
             }
 
-            is UserState.Success -> {
+            is DataState.Success -> {
                 viewModel.addProfile()
                 flag2.value = true
                 flag.value = false
             }
 
-            is UserState.Error -> {
-                val message = (userState as UserState.Error).message
+            is DataState.Error -> {
+                val message = (userState as DataState.Error).message
                 Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
                 flag.value = false
             }
@@ -189,17 +188,17 @@ fun RegistrationGender(navController: NavController, viewModel: AuthViewModel) {
     }
     if (flag2.value) {
         when (userState) {
-            is UserState.Loading -> {
+            is DataState.Loading -> {
                 Loading()
             }
 
-            is UserState.Success -> {
+            is DataState.Success -> {
                 navController.navigate(Screens.Start.route)
                 flag2.value = false
             }
 
-            is UserState.Error -> {
-                val message = (userState as UserState.Error).message
+            is DataState.Error -> {
+                val message = (userState as DataState.Error).message
                 Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
                 flag2.value = false
             }

+ 8 - 9
App/app/src/main/java/com/example/mystictale/Screen/signIn/SignIn.kt

@@ -2,7 +2,6 @@ package com.example.mystictale.Screen.signIn
 
 import android.util.Patterns
 import android.widget.Toast
-import androidx.activity.compose.BackHandler
 import androidx.compose.foundation.Image
 import androidx.compose.foundation.clickable
 import androidx.compose.foundation.gestures.detectTapGestures
@@ -41,7 +40,7 @@ import androidx.compose.ui.unit.sp
 import androidx.navigation.NavController
 import com.example.mystictale.R
 import com.example.mystictale.ViewModels.AuthViewModel
-import com.example.mystictale.models.UserState
+import com.example.mystictale.models.DataState
 import com.example.mystictale.navigation.Screens
 import com.example.mystictale.resources.components.GenericTextField
 import com.example.mystictale.resources.components.Loading
@@ -67,7 +66,7 @@ fun SignIn(navController: NavController, viewModel: AuthViewModel) {
     val flagPassword = remember {
         mutableStateOf(false)
     }
-    val userState by viewModel.userState
+    val userState by viewModel.dataState
     val flag = remember {
         mutableStateOf(false)
     }
@@ -228,7 +227,7 @@ fun SignIn(navController: NavController, viewModel: AuthViewModel) {
                     disabledContainerColor = DarkPurple
                 )
             ) {
-                Text("Далее", fontSize = 20.sp, fontWeight = FontWeight.Bold)
+                Text("Войти", fontSize = 20.sp, fontWeight = FontWeight.Bold)
 
             }
 
@@ -238,17 +237,17 @@ fun SignIn(navController: NavController, viewModel: AuthViewModel) {
     }
     if (flag.value) {
         when (userState) {
-            is UserState.Loading -> {
+            is DataState.Loading -> {
                 Loading()
             }
 
-            is UserState.Success -> {
-                navController.navigate(Screens.Profile.route)
+            is DataState.Success -> {
+                navController.navigate(Screens.AppNavigation.route)
                 flag.value = false
             }
 
-            is UserState.Error -> {
-                val message = (userState as UserState.Error).message
+            is DataState.Error -> {
+                val message = (userState as DataState.Error).message
                 Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
                 flag.value = false
             }

+ 70 - 0
App/app/src/main/java/com/example/mystictale/ViewModels/AIViewModel.kt

@@ -0,0 +1,70 @@
+package com.example.mystictale.ViewModels
+
+import android.os.Build
+import androidx.annotation.RequiresExtension
+import androidx.compose.runtime.State
+import androidx.compose.runtime.mutableStateOf
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.example.mystictale.aiConnect.Repository
+import com.example.mystictale.aiConnect.RepositoryImpl
+import com.example.mystictale.aiConnect.Result
+import com.example.mystictale.aiConnect.RetrofitInstance
+import com.example.mystictale.models.ApiResponse
+import com.example.mystictale.models.CompletionOptions
+import com.example.mystictale.models.CompletionRequest
+import com.example.mystictale.models.DataState
+import com.example.mystictale.models.Message
+import com.google.gson.Gson
+import kotlinx.coroutines.channels.Channel
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.collectLatest
+import kotlinx.coroutines.flow.receiveAsFlow
+import kotlinx.coroutines.flow.update
+import kotlinx.coroutines.launch
+import java.nio.charset.Charset
+
+
+class AIViewModel(private val repository: Repository): ViewModel() {
+    private val _dataState = mutableStateOf<DataState>(DataState.Loading)
+    val dataState: State<DataState> = _dataState
+    private val _showErrorToastChannel = Channel<Boolean>()
+    val showErrorToastChannel = _showErrorToastChannel.receiveAsFlow()
+    private val _answer = MutableStateFlow<ApiResponse?>(null)
+    val answer = _answer.asStateFlow()
+
+    @RequiresExtension(extension = Build.VERSION_CODES.S, version = 7)
+    fun sendARequest(messages: List<Message>) {
+        val request = CompletionRequest(
+            modelUri = "gpt://b1g2t3n39087a6vamssj/yandexgpt-lite",
+            completionOptions = CompletionOptions(
+                stream = false,
+                temperature = 0.6,
+                maxTokens = "2000"
+            ),
+            messages = messages
+        )
+        viewModelScope.launch {
+            _dataState.value = DataState.Loading
+            repository.sendARequest(request,"Api-Key AQVNzhwkrRq6kkKpFsNekN2hbDSbV98GKz7hMzPZ").collect { result ->
+                when (result) {
+                    is Result.Error -> {
+                        _dataState.value = DataState.Error("")
+                        _showErrorToastChannel.send(true)
+                    }
+                    is Result.Success -> {
+                        _dataState.value = DataState.Success("")
+                       result.data?.let { answer->
+                           _answer.update { answer}
+
+                       }
+                    }
+
+                }
+            }
+        }
+    }
+
+
+}

+ 76 - 26
App/app/src/main/java/com/example/mystictale/ViewModels/AuthViewModel.kt

@@ -9,19 +9,18 @@ import androidx.compose.runtime.setValue
 import androidx.lifecycle.ViewModel
 import androidx.lifecycle.viewModelScope
 import com.example.mystictale.Constants.SupabaseConnect
-import com.example.mystictale.models.UserState
+import com.example.mystictale.models.DataState
 import com.example.mystictale.models.Users
 import com.example.mystictale.resources.SharedPreferenceHelper
 import io.github.jan.supabase.auth.auth
 import io.github.jan.supabase.auth.providers.builtin.Email
 import io.github.jan.supabase.postgrest.from
 import io.github.jan.supabase.storage.storage
-import io.github.jan.supabase.storage.update
 import kotlinx.coroutines.launch
 
 class AuthViewModel : ViewModel() {
-    private val _userState = mutableStateOf<UserState>(UserState.Loading)
-    val userState: State<UserState> = _userState
+    private val _dataState = mutableStateOf<DataState>(DataState.Loading)
+    val dataState: State<DataState> = _dataState
     var uid by mutableStateOf<String?>(null)
     var avatar by mutableStateOf<String?>(null)
     var emailUser by mutableStateOf<String?>(null)
@@ -34,18 +33,18 @@ class AuthViewModel : ViewModel() {
     fun onSignUpEmailPassword(context: Context) {
         viewModelScope.launch {
             try {
-                _userState.value = UserState.Loading
+                _dataState.value = DataState.Loading
                 SupabaseConnect.supabase.auth.signUpWith(Email) {
                     email = emailUser!!
                     password = passwordUser!!
                 }
                 saveToken(context)
-                _userState.value = UserState.Success("Success sing up")
+                _dataState.value = DataState.Success("Success sing up")
                 Log.d("my_tag", "Success sing up")
 
 
             } catch (e: Exception) {
-                _userState.value = UserState.Error("Error: ${e.message}")
+                _dataState.value = DataState.Error("Error: ${e.message}")
                 Log.d("my_tag", e.message!!)
 
             }
@@ -56,18 +55,18 @@ class AuthViewModel : ViewModel() {
     fun onSignInEmailPassword(context: Context, emailUser: String, passwordUser: String) {
         viewModelScope.launch {
             try {
-                _userState.value = UserState.Loading
+                _dataState.value = DataState.Loading
                 SupabaseConnect.supabase.auth.signInWith(Email) {
                     email = emailUser
                     password = passwordUser
                 }
 
                 saveToken(context)
-                _userState.value = UserState.Success("Success sing in")
+                _dataState.value = DataState.Success("Success sing in")
                 Log.d("my_tag", "Success sing in")
 
             } catch (e: Exception) {
-                _userState.value = UserState.Error("Error: ${e.message}")
+                _dataState.value = DataState.Error("Error: ${e.message}")
                 Log.d("my_tag", e.message!!)
             }
         }
@@ -76,7 +75,7 @@ class AuthViewModel : ViewModel() {
     fun addProfile() {
         viewModelScope.launch {
             try {
-                _userState.value = UserState.Loading
+                _dataState.value = DataState.Loading
                 SupabaseConnect.supabase.from("Users").insert(
                     Users(
                         name = name!!,
@@ -86,11 +85,11 @@ class AuthViewModel : ViewModel() {
                     )
                 )
 
-                _userState.value = UserState.Success("Success create profile")
+                _dataState.value = DataState.Success("Success create profile")
                 Log.d("my_tag", "Success create profile")
 
             } catch (e: Exception) {
-                _userState.value = UserState.Error("Error: ${e.message}")
+                _dataState.value = DataState.Error("Error: ${e.message}")
                 Log.d("my_tag", e.message!!)
             }
         }
@@ -99,18 +98,18 @@ class AuthViewModel : ViewModel() {
     fun selectProfile() {
         viewModelScope.launch {
             try {
-                _userState.value = UserState.Loading
+                _dataState.value = DataState.Loading
                 _user.value = SupabaseConnect.supabase.from("Users").select {
                     filter {
                         Users::UID eq SupabaseConnect.supabase.auth.currentUserOrNull()!!.id
                     }
                 }.decodeList<Users>()
-
-                _userState.value = UserState.Success("Success create profile")
+                gender = _user.value.last().id_gender
+                _dataState.value = DataState.Success("Success create profile")
                 Log.d("my_tag", "Success create profile")
 
             } catch (e: Exception) {
-                _userState.value = UserState.Error("Error: ${e.message}")
+                _dataState.value = DataState.Error("Error: ${e.message}")
                 Log.d("my_tag", e.message!!)
             }
         }
@@ -120,7 +119,7 @@ class AuthViewModel : ViewModel() {
         viewModelScope.launch {
             try {
 
-                _userState.value = UserState.Loading
+                _dataState.value = DataState.Loading
                 SupabaseConnect.supabase.from("Users").update(
                     {
                         Users::name setTo name
@@ -133,11 +132,11 @@ class AuthViewModel : ViewModel() {
                     }
                 }
 
-                _userState.value = UserState.Success("Success update profile")
+                _dataState.value = DataState.Success("Success update profile")
                 Log.d("my_tag", "Success update profile")
 
             } catch (e: Exception) {
-                _userState.value = UserState.Error("Error: ${e.message}")
+                _dataState.value = DataState.Error("Error: ${e.message}")
                 Log.d("my_tag", e.message!!)
             }
         }
@@ -147,7 +146,7 @@ class AuthViewModel : ViewModel() {
         viewModelScope.launch {
             try {
 
-                _userState.value = UserState.Loading
+                _dataState.value = DataState.Loading
                 val basket = SupabaseConnect.supabase.storage["Avatars"]
                if(byteArray.isNotEmpty()){
                    try {
@@ -184,9 +183,9 @@ class AuthViewModel : ViewModel() {
                        }
                    }
                }
-                _userState.value = UserState.Success("The avatar has been successfully added")
+                _dataState.value = DataState.Success("The avatar has been successfully added")
             } catch (e: Exception) {
-                _userState.value = UserState.Error("Error: ${e.message}")
+                _dataState.value = DataState.Error("Error: ${e.message}")
                 Log.d("my_tag", e.message!!)
             }
         }
@@ -196,15 +195,15 @@ class AuthViewModel : ViewModel() {
         viewModelScope.launch {
             try {
                 Log.d("my_tag", uid!!)
-                _userState.value = UserState.Loading
+                _dataState.value = DataState.Loading
                 SupabaseConnect.supabaseAdmin.auth.admin.updateUserById(uid = uid!!) {
                     password = passwordUser
                 }
-                _userState.value = UserState.Success("Success changed password")
+                _dataState.value = DataState.Success("Success changed password")
                 Log.d("my_tag", "Success changed password")
 
             } catch (e: Exception) {
-                _userState.value = UserState.Error("Error: ${e.message}")
+                _dataState.value = DataState.Error("Error: ${e.message}")
                 Log.d("my_tag", e.message!!)
             }
         }
@@ -225,4 +224,55 @@ class AuthViewModel : ViewModel() {
 
     }
 
+    fun logout(context: Context) {
+        val sharedPref = SharedPreferenceHelper(context)
+        viewModelScope.launch {
+            try {
+                _dataState.value = DataState.Loading
+                SupabaseConnect.supabase.auth.signOut()
+                sharedPref.clearPreferences()
+                _dataState.value = DataState.Success("Logged out successfully!")
+            } catch (e: Exception) {
+                _dataState.value = DataState.Error(e.message ?: "")
+                Log.d("my_tag",e.message!!)
+            }
+        }
+    }
+    fun isUserLoggedIn(context: Context) {
+        viewModelScope.launch {
+            try {
+                val token = getToken(context)
+                if (token.isNullOrEmpty()) {
+                    _dataState.value = DataState.Error("User is not logged in")
+                } else {
+                    SupabaseConnect.supabase.auth.retrieveUser(token)
+                    SupabaseConnect.supabase.auth.refreshCurrentSession()
+                    saveToken(context)
+                    _dataState.value = DataState.Success("User is logged in")
+                }
+
+            } catch (e: Exception) {
+                _dataState.value = DataState.Error("Error: ${e.message}")
+            }
+        }
+    }
+    fun checkForRegistration() {
+        viewModelScope.launch {
+            try {
+                _dataState.value = DataState.Loading
+                _user.value = SupabaseConnect.supabase.from("Users")
+                    .select() {
+                        filter {
+                            Users::UID eq SupabaseConnect.supabase.auth.currentUserOrNull()!!.id
+                        }
+                    }
+                    .decodeList<Users>()
+
+                _dataState.value = DataState.Success("")
+            } catch (e: Exception) {
+                _dataState.value = DataState.Error("Error: ${e.message}")
+            }
+        }
+    }
+
 }

+ 86 - 0
App/app/src/main/java/com/example/mystictale/ViewModels/CardsViewModel.kt

@@ -0,0 +1,86 @@
+package com.example.mystictale.ViewModels
+
+import android.util.Log
+import androidx.compose.runtime.State
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.example.mystictale.Constants.SupabaseConnect
+import com.example.mystictale.models.Cards
+import com.example.mystictale.models.DataState
+import com.example.mystictale.models.Values
+import io.github.jan.supabase.postgrest.from
+import io.github.jan.supabase.postgrest.query.Columns
+import kotlinx.coroutines.launch
+import java.util.Locale
+
+
+class CardsViewModel : ViewModel() {
+    private val _dataState = mutableStateOf<DataState>(DataState.Loading)
+    val dataState: State<DataState> = _dataState
+    private val _cards = mutableStateOf(listOf<Cards>())
+    val cards: State<List<Cards>> = _cards
+    var arcana by mutableStateOf<Int?>(null)
+    var suit by mutableStateOf<Int?>(null)
+    private val _filteredCards = mutableStateOf(listOf<Cards>())
+    val filteredCards: State<List<Cards>> = _filteredCards
+    var searchQuery = mutableStateOf("")
+    var card by mutableStateOf<Cards?>(null)
+    private val _values = mutableStateOf(listOf<Values>())
+    val values: State<List<Values>> = _values
+
+
+    fun selectCards() {
+        viewModelScope.launch {
+            try {
+                _dataState.value = DataState.Loading
+                _cards.value = SupabaseConnect.supabase.from("Cards").select().decodeList<Cards>()
+                _filteredCards.value = _cards.value
+                _dataState.value = DataState.Success("Success select cards")
+                Log.d("my_tag", "Success select cards")
+
+            } catch (e: Exception) {
+                _dataState.value = DataState.Error("Error: ${e.message}")
+                Log.d("my_tag", e.message!!)
+            }
+        }
+    }
+    fun selectInfoCard(){
+        viewModelScope.launch {
+            try {
+                _dataState.value = DataState.Loading
+               _values.value = SupabaseConnect.supabase.from("Values").select(
+                    Columns.raw("*, Aspects(id,Title)")){
+                    filter {
+                        Values::Id_card eq card!!.id
+                    }
+                }.decodeList<Values>()
+
+                _dataState.value = DataState.Success("Success select info about card")
+                Log.d("my_tag", "Success select info about card")
+
+            } catch (e: Exception) {
+                _dataState.value = DataState.Error("Error: ${e.message}")
+                Log.d("my_tag", e.message!!)
+            }
+        }
+    }
+
+    fun filteredCards() {
+        _filteredCards.value = _cards.value
+        if(arcana!=null){
+            _filteredCards.value =_filteredCards.value.filter { card-> card.id_arcana == arcana }
+        }
+        if(suit!=null){
+            _filteredCards.value =_filteredCards.value.filter { card-> card.id_suit == suit }
+        }
+        if(searchQuery.value.isNotEmpty()){
+            _filteredCards.value = _filteredCards.value.filter { card ->
+                card.title.lowercase(Locale.getDefault())
+                    .contains(searchQuery.value.lowercase(Locale.getDefault()))
+            }
+        }
+    }
+}

+ 23 - 0
App/app/src/main/java/com/example/mystictale/aiConnect/Api.kt

@@ -0,0 +1,23 @@
+package com.example.mystictale.aiConnect
+
+import com.example.mystictale.models.ApiResponse
+import com.example.mystictale.models.CompletionRequest
+import retrofit2.http.Body
+import retrofit2.http.Header
+import retrofit2.http.Headers
+import retrofit2.http.POST
+
+
+interface Api {
+    @Headers("Content-Type: application/json")
+    @POST("foundationModels/v1/completion")
+    suspend fun sendARequest(
+        @Body request: CompletionRequest,
+        @Header("Authorization") apiKey: String
+    ): ApiResponse
+
+    companion object {
+        const val BASE_URL = "https://llm.api.cloud.yandex.net/"
+        const val API_KEY = "AQVNzhwkrRq6kkKpFsNekN2hbDSbV98GKz7hMzPZ"
+    }
+}

+ 13 - 0
App/app/src/main/java/com/example/mystictale/aiConnect/Repository.kt

@@ -0,0 +1,13 @@
+package com.example.mystictale.aiConnect
+
+import com.example.mystictale.models.ApiResponse
+import com.example.mystictale.models.CompletionRequest
+import kotlinx.coroutines.flow.Flow
+
+
+interface Repository {
+    suspend fun sendARequest(
+        request: CompletionRequest,
+        apiKey: String
+    ): Flow<Result<ApiResponse>>
+}

+ 36 - 0
App/app/src/main/java/com/example/mystictale/aiConnect/RepositoryImpl.kt

@@ -0,0 +1,36 @@
+package com.example.mystictale.aiConnect
+
+import android.net.http.HttpException
+import android.os.Build
+import androidx.annotation.RequiresExtension
+import com.example.mystictale.models.ApiResponse
+import com.example.mystictale.models.CompletionRequest
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flow
+import kotlinx.io.IOException
+
+@RequiresExtension(extension = Build.VERSION_CODES.S, version = 7)
+class RepositoryImpl (private val api: Api) : Repository {
+    override suspend fun sendARequest(
+        request: CompletionRequest, apiKey:String
+    ): Flow<Result<ApiResponse>> {
+        return flow {
+            val response = try {
+                api.sendARequest(request, apiKey)
+            } catch (e: IOException) {
+                e.printStackTrace()
+                emit(Result.Error(message = "IOException: ${e.message}"))
+                return@flow
+            } catch (e: HttpException) {
+                e.printStackTrace()
+                emit(Result.Error(message = "HttpException: ${e.message}"))
+                return@flow
+            } catch (e: Exception) {
+                e.printStackTrace()
+                emit(Result.Error(message = "Exception: ${e.message}"))
+                return@flow
+            }
+            emit(Result.Success(response))
+        }
+    }
+}

+ 10 - 0
App/app/src/main/java/com/example/mystictale/aiConnect/Result.kt

@@ -0,0 +1,10 @@
+package com.example.mystictale.aiConnect
+
+
+sealed class Result<T>(
+    val data: T? = null,
+    val message: String? = null
+) {
+    class Success<T>(data: T?) : Result<T>(data)
+    class Error<T>(data: T? = null,message: String?) : Result<T>(data,message)
+}

+ 29 - 0
App/app/src/main/java/com/example/mystictale/aiConnect/RetrofitInstance.kt

@@ -0,0 +1,29 @@
+package com.example.mystictale.aiConnect
+
+import com.google.gson.GsonBuilder
+import okhttp3.OkHttpClient
+import okhttp3.logging.HttpLoggingInterceptor
+import retrofit2.Retrofit
+import retrofit2.converter.gson.GsonConverterFactory
+
+
+object RetrofitInstance {
+    private val gson = GsonBuilder()
+        .setLenient()
+        .create()
+
+    private val interceptor: HttpLoggingInterceptor = HttpLoggingInterceptor().apply {
+        level = HttpLoggingInterceptor.Level.BODY
+    }
+
+    private val client: OkHttpClient = OkHttpClient.Builder()
+        .addInterceptor(interceptor)
+        .build()
+
+    val api: Api = Retrofit.Builder()
+        .baseUrl(Api.BASE_URL)
+        .addConverterFactory(GsonConverterFactory.create(gson))
+        .client(client)
+        .build()
+        .create(Api::class.java)
+}

+ 25 - 0
App/app/src/main/java/com/example/mystictale/models/AnswerAI.kt

@@ -0,0 +1,25 @@
+package com.example.mystictale.models
+
+
+data class ApiResponse(
+    val result: Result
+)
+data class Result(
+    val alternatives: List<Alternative>,
+    val usage: Usage,
+    val modelVersion: String
+)
+data class Message(
+    val role: String,
+    val text: String
+)
+
+data class Alternative(
+    val message: Message,
+    val status: String
+)
+data class Usage(
+    val inputTextTokens: Int,
+    val completionTokens: Int,
+    val totalTokens: Int
+)

+ 9 - 0
App/app/src/main/java/com/example/mystictale/models/Aspects.kt

@@ -0,0 +1,9 @@
+package com.example.mystictale.models
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class Aspects(
+    val id:Int?,
+    val Title:String
+)

+ 4 - 4
App/app/src/main/java/com/example/mystictale/models/Cards.kt

@@ -9,10 +9,10 @@ data class Cards (
     val id:Int? = null,
     @SerialName("Title")
     val title:String = "",
-    @SerialName("Id_arcana")
-    val id_arcana:Int,
+    @SerialName("Id_arcan")
+    val id_arcana:Int = 0,
     @SerialName("Id_suit")
-    val id_suit:Int,
+    val id_suit:Int? = null,
     @SerialName("Image")
-    val image:String
+    val image:String = ""
 )

+ 8 - 0
App/app/src/main/java/com/example/mystictale/models/CompletionOptions.kt

@@ -0,0 +1,8 @@
+package com.example.mystictale.models
+
+
+data class CompletionOptions(
+    val stream: Boolean,
+    val temperature: Double,
+    val maxTokens: String
+)

+ 8 - 0
App/app/src/main/java/com/example/mystictale/models/CompletionRequest.kt

@@ -0,0 +1,8 @@
+package com.example.mystictale.models
+
+
+data class CompletionRequest(
+    val modelUri: String,
+    val completionOptions: CompletionOptions,
+    val messages: List<Message>
+)

+ 7 - 0
App/app/src/main/java/com/example/mystictale/models/DataState.kt

@@ -0,0 +1,7 @@
+package com.example.mystictale.models
+
+sealed class DataState {
+    object Loading: DataState()
+    data class Success(val message:String):DataState()
+    data class Error(val message:String):DataState()
+}

+ 0 - 7
App/app/src/main/java/com/example/mystictale/models/UserState.kt

@@ -1,7 +0,0 @@
-package com.example.mystictale.models
-
-sealed class UserState {
-    object Loading: UserState()
-    data class Success(val message:String):UserState()
-    data class Error(val message:String):UserState()
-}

+ 14 - 0
App/app/src/main/java/com/example/mystictale/models/Values.kt

@@ -0,0 +1,14 @@
+package com.example.mystictale.models
+
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class Values(
+    val id: Int,
+    val Id_card: Int,
+    val Content: String,
+    val Negative_of_positive: Boolean?,
+    @SerialName("Aspects")
+    val TileAspect: Aspects
+)

+ 31 - 14
App/app/src/main/java/com/example/mystictale/navigation/Navigation.kt

@@ -1,7 +1,6 @@
 package com.example.mystictale.navigation
 
 import android.os.Build
-import android.util.Log
 import androidx.activity.compose.BackHandler
 import androidx.annotation.RequiresApi
 import androidx.compose.runtime.Composable
@@ -9,67 +8,85 @@ import androidx.lifecycle.viewmodel.compose.viewModel
 import androidx.navigation.compose.NavHost
 import androidx.navigation.compose.composable
 import androidx.navigation.compose.rememberNavController
+import com.example.mystictale.Screen.InfoCard
 import com.example.mystictale.Screen.Profile
+import com.example.mystictale.Screen.Start
+import com.example.mystictale.Screen.passwordRecovery.NewPassword
+import com.example.mystictale.Screen.passwordRecovery.PasswordRecovery
 import com.example.mystictale.Screen.registration.RegistrationDateOfBirth
 import com.example.mystictale.Screen.registration.RegistrationEmail
 import com.example.mystictale.Screen.registration.RegistrationGender
 import com.example.mystictale.Screen.registration.RegistrationName
 import com.example.mystictale.Screen.registration.RegistrationPassword
-import com.example.mystictale.Screen.Start
-import com.example.mystictale.Screen.passwordRecovery.NewPassword
-import com.example.mystictale.Screen.passwordRecovery.PasswordRecovery
 import com.example.mystictale.Screen.signIn.SignIn
 import com.example.mystictale.ViewModels.AuthViewModel
+import com.example.mystictale.ViewModels.CardsViewModel
+import com.example.mystictale.navigation.bottomNavigation.AppNavigation
+import drawable.Screen.LoadingScreen
 
 @RequiresApi(Build.VERSION_CODES.O)
 @Composable
 fun Navigation() {
     val viewModel: AuthViewModel = viewModel()
+    val cardsViewModel: CardsViewModel = viewModel()
     val navController = rememberNavController()
-    NavHost(navController = navController, startDestination = Screens.Start.route)
+    NavHost(navController = navController, startDestination = Screens.Loading.route)
     {
         composable(Screens.Start.route)
         {
             Start(navController)
         }
+        composable(Screens.Loading.route)
+        {
+            LoadingScreen(navController, viewModel)
+        }
         composable(Screens.RegistrationEmail.route)
         {
-            RegistrationEmail(navController,viewModel)
+            RegistrationEmail(navController, viewModel)
         }
         composable(Screens.RegistrationName.route)
         {
-            RegistrationName(navController,viewModel)
+            RegistrationName(navController, viewModel)
         }
         composable(Screens.RegistrationPassword.route)
         {
-            RegistrationPassword(navController,viewModel)
+            RegistrationPassword(navController, viewModel)
         }
         composable(Screens.RegistrationDateOfBirth.route)
         {
-            RegistrationDateOfBirth(navController,viewModel)
+            RegistrationDateOfBirth(navController, viewModel)
         }
         composable(Screens.RegistrationGender.route)
         {
-            RegistrationGender(navController,viewModel)
+            RegistrationGender(navController, viewModel)
         }
         composable(Screens.SingIn.route)
         {
-            SignIn(navController,viewModel)
+            SignIn(navController, viewModel)
         }
         composable(Screens.PasswordRecovery.route)
         {
-            PasswordRecovery(navController,viewModel)
+            PasswordRecovery(navController, viewModel)
         }
         composable(Screens.NewPassword.route)
         {
-            NewPassword(navController,viewModel)
+            NewPassword(navController, viewModel)
         }
         composable(Screens.Profile.route)
         {
             BackHandler(true) {
             }
-            Profile(navController,viewModel)
+            Profile(navController, viewModel)
+        }
+        composable(Screens.InfoCard.route)
+        {
+            InfoCard(cardsViewModel, navController)
         }
+        composable(Screens.AppNavigation.route)
+        {
+            AppNavigation(viewModel, cardsViewModel, navController)
+        }
+
 
     }
 }

+ 5 - 0
App/app/src/main/java/com/example/mystictale/navigation/Screens.kt

@@ -1,6 +1,7 @@
 package com.example.mystictale.navigation
 
 sealed class Screens (val route:String){
+    object Loading:Screens("loading")
     object Start:Screens("start")
     object RegistrationEmail:Screens("email")
     object RegistrationPassword:Screens("password")
@@ -11,5 +12,9 @@ sealed class Screens (val route:String){
     object PasswordRecovery: Screens("password_recovery")
     object NewPassword: Screens("new_password")
     object Profile: Screens("profile")
+    object InfoCard: Screens("info_card")
+    object CardsScreen: Screens("cards_screen")
+    object ChatWithAI:Screens("chat_with_ai")
+    object AppNavigation:Screens("app_navigation")
 
 }

+ 140 - 0
App/app/src/main/java/com/example/mystictale/navigation/bottomNavigation/AppNavigation.kt

@@ -0,0 +1,140 @@
+package com.example.mystictale.navigation.bottomNavigation
+
+import android.os.Build
+import androidx.annotation.RequiresApi
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Icon
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import androidx.navigation.NavController
+import androidx.navigation.NavDestination
+import androidx.navigation.NavDestination.Companion.hierarchy
+import androidx.navigation.NavGraph.Companion.findStartDestination
+import androidx.navigation.NavHostController
+import androidx.navigation.compose.currentBackStackEntryAsState
+import androidx.navigation.compose.rememberNavController
+import com.example.mystictale.ViewModels.AuthViewModel
+import com.example.mystictale.ViewModels.CardsViewModel
+
+@RequiresApi(Build.VERSION_CODES.O)
+@Composable
+fun AppNavigation(
+    authViewModel: AuthViewModel,
+    cardsViewModel: CardsViewModel,
+    mainNavController: NavController
+) {
+    val navController = rememberNavController()
+    Scaffold(
+        modifier = Modifier
+            .fillMaxSize()
+            .background(Color.Transparent),
+        bottomBar = { BottomBarCustomer(navController = navController) }
+    ) {paddingValues ->
+        Column(
+            modifier = Modifier
+                .fillMaxSize()
+                .padding(if (true) PaddingValues(0.dp) else paddingValues)
+        ) {
+            BottomGraph(
+                navController,
+                cardsViewModel,
+                authViewModel,
+                mainNavController
+            )
+        }
+    }
+}
+
+@Composable
+fun BottomBarCustomer(navController: NavHostController) {
+    val screens = listOf(
+        NavItem.AI,
+        NavItem.Cards,
+        NavItem.Profile
+        )
+
+    val navStackBackEntry by navController.currentBackStackEntryAsState()
+    val currentDestination = navStackBackEntry?.destination
+
+    Row(
+        modifier = Modifier
+            .fillMaxWidth()
+            .height(50.dp)
+            .background(Color.White),
+        horizontalArrangement = Arrangement.SpaceEvenly,
+        verticalAlignment = Alignment.CenterVertically
+    ) {
+        screens.forEach { screen ->
+            AddItemCustomer(
+                screen = screen,
+                currentDestination = currentDestination,
+                navController = navController
+            )
+        }
+    }
+
+}
+
+@Composable
+fun AddItemCustomer(
+    screen: NavItem,
+    currentDestination: NavDestination?,
+    navController: NavHostController
+) {
+    val selected = currentDestination?.hierarchy?.any { it.route == screen.rote } == true
+
+    val background =
+        if (selected) Color.White else Color.Transparent
+
+    val contentColor = Color(0xFF0B0328)
+
+    Box(
+        modifier = Modifier
+            .width(85.dp)
+            .clip(RoundedCornerShape(10.dp))
+            .background(background)
+            .clickable(onClick = {
+                navController.navigate(screen.rote) {
+                    popUpTo(navController.graph.findStartDestination().id)
+                    launchSingleTop = true
+                }
+            })
+    ) {
+        Column(
+            modifier = Modifier
+                .height(60.dp)
+                .align(Alignment.Center),
+            verticalArrangement = Arrangement.Center,
+            horizontalAlignment = Alignment.CenterHorizontally
+        ) {
+            Icon(
+                painter = painterResource(id = if (selected) screen.icon else screen.icon),
+                contentDescription = "icon",
+                tint = contentColor,
+                modifier = Modifier.height(26.dp).width(26.dp)
+            )
+        }
+    }
+}

+ 39 - 0
App/app/src/main/java/com/example/mystictale/navigation/bottomNavigation/BottomGraph.kt

@@ -0,0 +1,39 @@
+package com.example.mystictale.navigation.bottomNavigation
+
+import android.os.Build
+import androidx.annotation.RequiresApi
+import androidx.compose.runtime.Composable
+import androidx.navigation.NavController
+import androidx.navigation.NavHostController
+import androidx.navigation.compose.NavHost
+import androidx.navigation.compose.composable
+import com.example.mystictale.Screen.CardsScreen
+import com.example.mystictale.Screen.ChatWithAI
+import com.example.mystictale.Screen.Profile
+import com.example.mystictale.ViewModels.AuthViewModel
+import com.example.mystictale.ViewModels.CardsViewModel
+import com.example.mystictale.navigation.Screens
+
+@RequiresApi(Build.VERSION_CODES.O)
+@Composable
+fun BottomGraph(
+    navController: NavHostController,
+    cardsViewModel: CardsViewModel,
+    authViewModel: AuthViewModel,
+    mainNavController: NavController
+) {
+    NavHost(
+        navController = navController,
+        startDestination = Screens.CardsScreen.route,
+    ) {
+        composable(Screens.Profile.route) {
+            Profile(mainNavController, authViewModel)
+        }
+        composable(Screens.CardsScreen.route) {
+            CardsScreen(mainNavController, cardsViewModel)
+        }
+        composable(Screens.ChatWithAI.route) {
+            ChatWithAI()
+        }
+    }
+}

+ 26 - 0
App/app/src/main/java/com/example/mystictale/navigation/bottomNavigation/NavItem.kt

@@ -0,0 +1,26 @@
+package com.example.mystictale.navigation.bottomNavigation
+
+import com.example.mystictale.R
+import com.example.mystictale.navigation.Screens
+
+
+sealed class NavItem (
+    val icon: Int,
+    val rote: String
+) {
+    object Profile: NavItem(
+        icon = R.drawable.profile ,
+        rote = Screens.Profile.route
+
+    )
+    object Cards: NavItem(
+        icon = R.drawable.cards,
+        rote = Screens.CardsScreen.route
+
+    )
+    object AI: NavItem(
+        icon = R.drawable.ai,
+        rote = Screens.ChatWithAI.route
+
+    )
+}

+ 49 - 0
App/app/src/main/java/com/example/mystictale/resources/components/AIMessage.kt

@@ -0,0 +1,49 @@
+package com.example.mystictale.resources.components
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.IntrinsicSize
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+import com.example.mystictale.Screen.TypewriterText
+import com.example.mystictale.ui.theme.DarkPurple
+
+@Composable
+fun AIMessage(message: String) {
+    Row(
+        Modifier
+            .height(IntrinsicSize.Max)
+            .fillMaxWidth(),
+        horizontalArrangement = Arrangement.Start
+    ) {
+        Column(
+            modifier = Modifier
+                .background(
+                    color = DarkPurple,
+                    shape = TriangleEdgeShapeAI(40) // Используем обновленную форму
+                )
+                .width(8.dp)
+                .fillMaxHeight()
+        ) {
+        }
+        Column(
+            modifier = Modifier
+                .background(
+                    color = DarkPurple,
+                    shape = RoundedCornerShape(0.dp, 4.dp, 4.dp, 4.dp)
+                )
+                .fillMaxWidth()
+        ) {
+            TypewriterText(listOf(message))
+        }
+    }
+
+}

+ 46 - 0
App/app/src/main/java/com/example/mystictale/resources/components/ButtonAI.kt

@@ -0,0 +1,46 @@
+package com.example.mystictale.resources.components
+
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import com.example.mystictale.ui.theme.DarkPurple
+import com.example.mystictale.ui.theme.OpenSans
+import com.example.mystictale.ui.theme.Purple
+
+@Composable
+fun ButtonAI(title: String, onClick: () -> Unit) {
+    Button(
+        onClick = onClick,
+        modifier = Modifier
+            .fillMaxWidth()
+            .padding(vertical = 10.dp)
+            .height(33.dp),
+        shape = RoundedCornerShape(10.dp),
+        colors = ButtonDefaults.buttonColors(
+            containerColor = DarkPurple,
+            contentColor = Color.White,
+            disabledContainerColor = DarkPurple,
+            disabledContentColor = Color.White,
+        ),
+        contentPadding = PaddingValues(start = 16.dp, end = 16.dp)
+    ) {
+        Text(
+            text = title,
+            fontFamily = OpenSans,
+            fontSize = 15.sp,
+            fontWeight = FontWeight.Normal
+        )
+
+    }
+}

+ 19 - 8
App/app/src/main/java/com/example/mystictale/resources/components/dateComponents/ChooseArcana.kt → App/app/src/main/java/com/example/mystictale/resources/components/ChooseArcana.kt

@@ -1,10 +1,8 @@
-package com.example.mystictale.resources.components.dateComponents
+package com.example.mystictale.resources.components
 
 import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.width
@@ -26,19 +24,17 @@ import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.layout.onGloballyPositioned
 import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.text.font.FontWeight
-import androidx.compose.ui.tooling.preview.Preview
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
 import androidx.compose.ui.unit.toSize
+import com.example.mystictale.ViewModels.CardsViewModel
 import com.example.mystictale.ui.theme.DarkPurple
-import com.example.mystictale.ui.theme.Grey
 import com.example.mystictale.ui.theme.OpenSans
 
-@Preview
 @Composable
-fun ChooseArcana() {
+fun ChooseArcana(viewModel: CardsViewModel) {
     var expanded by remember { mutableStateOf(false) }
-    val list = listOf("Старшие арканы", "Младшие арканы")
+    val list = listOf("Выберите тип аркана","Старшие арканы", "Младшие арканы")
     var selectedItem by remember { mutableStateOf("") }
     var buttonSize by remember { mutableStateOf(Size.Zero) }
 
@@ -56,6 +52,7 @@ fun ChooseArcana() {
                 .onGloballyPositioned { coordinates ->
                     buttonSize = coordinates.size.toSize()
                 },
+
             shape = RoundedCornerShape(12.dp),
             colors = ButtonDefaults.buttonColors(
                 containerColor = DarkPurple,
@@ -91,6 +88,20 @@ fun ChooseArcana() {
                     },
                     onClick = {
                         selectedItem = label
+                        when (selectedItem) {
+                            "Выберите тип аркана" -> {
+                                viewModel.arcana = null
+                                viewModel.suit = null
+                            }
+                            "Старшие арканы" -> {
+                                viewModel.arcana = 1
+                                viewModel.suit = null
+                            }
+                            "Младшие арканы" -> {
+                                viewModel.arcana = 2
+                            }
+                        }
+                        viewModel.filteredCards()
                         expanded = false
                     }
                 )

+ 3 - 3
App/app/src/main/java/com/example/mystictale/resources/components/ChooseGenderForProfile.kt

@@ -31,12 +31,11 @@ import androidx.compose.ui.unit.sp
 import androidx.compose.ui.unit.toSize
 import com.example.mystictale.ViewModels.AuthViewModel
 import com.example.mystictale.ui.theme.DarkPurple
-import com.example.mystictale.ui.theme.Grey
 import com.example.mystictale.ui.theme.OpenSans
 import com.example.mystictale.ui.theme.Purple
 
 @Composable
-fun ChooseGenderForProfile(viewModel: AuthViewModel, gender:String, isEnabled:Boolean) {
+fun ChooseGenderForProfile(viewModel: AuthViewModel, gender: String, isEnabled: Boolean) {
     var expanded by remember { mutableStateOf(false) }
     val list = listOf("Мужской", "Женский")
     var selectedItem by remember { mutableStateOf(gender) }
@@ -95,7 +94,8 @@ fun ChooseGenderForProfile(viewModel: AuthViewModel, gender:String, isEnabled:Bo
                     onClick = {
                         selectedItem = label
                         expanded = false
-                        viewModel.gender = if (selectedItem == "Женский") 1 else 2
+                        viewModel.gender =
+                            if (selectedItem == "Женский") 1 else if (selectedItem == "Мужской") 2 else 1
 
                     }
                 )

+ 115 - 0
App/app/src/main/java/com/example/mystictale/resources/components/ChooseSuit.kt

@@ -0,0 +1,115 @@
+package com.example.mystictale.resources.components
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.DropdownMenu
+import androidx.compose.material3.DropdownMenuItem
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Size
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.layout.onGloballyPositioned
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import androidx.compose.ui.unit.toSize
+import com.example.mystictale.ViewModels.CardsViewModel
+import com.example.mystictale.ui.theme.DarkPurple
+import com.example.mystictale.ui.theme.OpenSans
+
+@Composable
+fun ChooseSuit(viewModel: CardsViewModel) {
+    var expanded by remember { mutableStateOf(false) }
+    val list = listOf("Выберите масть","Жезлы", "Мечи", "Кубки", "Пентакли")
+    var selectedItem by remember { mutableStateOf("") }
+    var buttonSize by remember { mutableStateOf(Size.Zero) }
+
+    Column(
+        modifier = Modifier
+            .fillMaxWidth(),
+        horizontalAlignment = Alignment.CenterHorizontally,
+        verticalArrangement = Arrangement.Center
+    ) {
+        Button(
+            onClick = { expanded = !expanded },
+            modifier = Modifier
+                .fillMaxWidth()
+                .height(33.dp)
+                .onGloballyPositioned { coordinates ->
+                    buttonSize = coordinates.size.toSize()
+                },
+
+            shape = RoundedCornerShape(12.dp),
+            colors = ButtonDefaults.buttonColors(
+                containerColor = DarkPurple,
+                contentColor = Color.White
+            ),
+            contentPadding = PaddingValues(0.dp)
+        ) {
+
+            Text(
+                text = selectedItem.ifEmpty { "Выберите масть" },
+                fontSize = 15.sp,
+                fontFamily = OpenSans,
+                fontWeight = FontWeight.Light,
+                color = Color.White
+            )
+
+        }
+
+        DropdownMenu(
+            expanded = expanded,
+            onDismissRequest = { expanded = false },
+            modifier = Modifier
+                .width(with(LocalDensity.current) { buttonSize.width.toDp() })
+        ) {
+            list.forEach { label ->
+                DropdownMenuItem(
+                    text = {
+                        Text(
+                            text = label,
+                            fontSize = 15.sp,
+                            fontWeight = FontWeight.Normal
+                        )
+                    },
+                    onClick = {
+                        selectedItem = label
+                        when (selectedItem) {
+                            "Выберите масть" -> {
+                                viewModel.suit = null
+                            }
+                            "Жезлы" -> {
+                                viewModel.suit = 1
+                            }
+                            "Мечи" -> {
+                                viewModel.suit = 2
+                            }
+                            "Кубки" -> {
+                                viewModel.suit = 3
+                            }
+                            "Пентакли" -> {
+                                viewModel.suit = 4
+                            }
+                        }
+                        viewModel.filteredCards()
+                        expanded = false
+                    }
+                )
+            }
+        }
+    }
+}

+ 159 - 0
App/app/src/main/java/com/example/mystictale/resources/components/LayoutCard.kt

@@ -0,0 +1,159 @@
+package com.example.mystictale.resources.components
+
+import android.widget.Toast
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.CircularProgressIndicator
+import androidx.compose.material3.LocalTextStyle
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.text.PlatformTextStyle
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.style.LineHeightStyle
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.em
+import androidx.compose.ui.unit.sp
+import androidx.navigation.NavController
+import coil.compose.AsyncImagePainter
+import coil.compose.rememberAsyncImagePainter
+import coil.request.ImageRequest
+import com.example.mystictale.ViewModels.CardsViewModel
+import com.example.mystictale.models.Cards
+import com.example.mystictale.models.DataState
+import com.example.mystictale.navigation.Screens
+import com.example.mystictale.ui.theme.DarkPurple
+import com.example.mystictale.ui.theme.OpenSans
+
+@Composable
+fun LayoutCard(card: Cards, viewModel: CardsViewModel, navController: NavController) {
+    val dataState by viewModel.dataState
+    val flag = remember { mutableStateOf(false) }
+    val context = LocalContext.current
+    Column(
+        modifier = Modifier
+            .height(200.dp)
+            .padding(vertical = 5.dp, horizontal = 5.dp)
+            .clip(RoundedCornerShape(10.dp))
+            .background(DarkPurple)
+            .padding(3.dp)
+            .clickable {
+                viewModel.card = card
+                viewModel.selectInfoCard()
+                flag.value = true
+            },
+        verticalArrangement = Arrangement.Center,
+        horizontalAlignment = Alignment.CenterHorizontally
+    ) {
+        val imageCard = rememberAsyncImagePainter(
+            model = ImageRequest.Builder(LocalContext.current).data(card.image)
+                .size(60, 103).build()
+        ).state
+
+
+        if (imageCard is AsyncImagePainter.State.Success) {
+            Image(
+                painter = imageCard.painter,
+                contentDescription = "",
+                modifier = Modifier
+                    .height(103.dp)
+                    .width(60.dp)
+            )
+        }
+        if (imageCard is AsyncImagePainter.State.Loading) {
+            Box(
+                modifier = Modifier
+                    .fillMaxWidth()
+                    .height(200.dp),
+                contentAlignment = Alignment.Center
+            ) {
+                CircularProgressIndicator()
+            }
+        }
+        if (imageCard is AsyncImagePainter.State.Error) {
+            Box(
+                modifier = Modifier
+                    .fillMaxWidth(),
+                contentAlignment = Alignment.Center
+            ) {
+                CircularProgressIndicator()
+            }
+
+        }
+
+        Text(
+            card.title,
+            fontSize = 10.sp,
+            fontWeight = FontWeight.Bold,
+            fontFamily = OpenSans,
+            color = Color.White,
+            textAlign = TextAlign.Center,
+            style = LocalTextStyle.current.merge(
+                TextStyle(
+                    lineHeight = 1.5.em,
+                    platformStyle = PlatformTextStyle(
+                        includeFontPadding = false
+                    ),
+                    lineHeightStyle = LineHeightStyle(
+                        alignment = LineHeightStyle.Alignment.Center,
+                        trim = LineHeightStyle.Trim.None
+                    )
+                )
+            )
+        )
+        if (card.id_arcana == 1) {
+            Text(
+                "Старший аркан",
+                fontSize = 10.sp,
+                fontWeight = FontWeight.Light,
+                fontFamily = OpenSans,
+                color = Color.White
+            )
+        } else {
+            Text(
+                "Младший аркан",
+                fontSize = 10.sp,
+                fontWeight = FontWeight.Light,
+                fontFamily = OpenSans,
+                color = Color.White
+            )
+        }
+
+
+    }
+    if (flag.value) {
+        when (dataState) {
+            is DataState.Loading -> {
+                Loading()
+            }
+
+            is DataState.Success -> {
+                navController.navigate(Screens.InfoCard.route)
+                flag.value = false
+            }
+
+            is DataState.Error -> {
+                Toast.makeText(context, "Упс! Ошибка", Toast.LENGTH_SHORT).show()
+                flag.value = false
+            }
+        }
+    }
+}

+ 70 - 0
App/app/src/main/java/com/example/mystictale/resources/components/TextFieldForAI.kt

@@ -0,0 +1,70 @@
+package com.example.mystictale.resources.components
+
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.material3.Icon
+import androidx.compose.material3.OutlinedTextField
+import androidx.compose.material3.TextFieldDefaults
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.input.ImeAction
+import androidx.compose.ui.text.input.KeyboardType
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import com.example.mystictale.R
+import com.example.mystictale.ui.theme.Grey
+import com.example.mystictale.ui.theme.OpenSans
+
+
+@Composable
+fun TextFieldForAI(value: String,enabled:Boolean, onValue: (String) -> Unit,onClick:()->Unit) {
+    OutlinedTextField(
+        value = value,
+        onValueChange = onValue,
+        singleLine = true,
+        keyboardOptions = KeyboardOptions(
+            keyboardType = KeyboardType.Text,
+            imeAction = ImeAction.Done
+        ),
+        shape = RoundedCornerShape(10.dp),
+        colors = TextFieldDefaults.colors(
+            unfocusedTextColor = Color.Black,
+            unfocusedContainerColor = Grey,
+            focusedTextColor = Color.Black,
+            focusedContainerColor = Grey,
+            focusedIndicatorColor = Color.Transparent,
+            unfocusedIndicatorColor = Color.Transparent,
+        ),
+        enabled = enabled,
+        maxLines = 1,
+        textStyle = TextStyle(
+            fontFamily = OpenSans,
+            fontWeight = FontWeight.Normal,
+            fontSize = 14.sp,
+        ),
+        modifier = Modifier
+            .fillMaxWidth()
+            .height(52.dp),
+        trailingIcon = {
+            Icon(
+                painter = painterResource(id = R.drawable.send),
+                contentDescription = "",
+                tint = if(enabled) Color(0xff3C3C3C) else Grey,
+                modifier = Modifier
+                    .height(20.dp)
+                    .width(20.dp)
+                    .clickable { onClick() }
+            )
+        }
+
+
+    )
+}

+ 25 - 0
App/app/src/main/java/com/example/mystictale/resources/components/TriangleEdgeShape.kt

@@ -0,0 +1,25 @@
+package com.example.mystictale.resources.components
+
+import androidx.compose.ui.geometry.Size
+import androidx.compose.ui.graphics.Outline
+import androidx.compose.ui.graphics.Path
+import androidx.compose.ui.graphics.Shape
+import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.LayoutDirection
+
+
+class TriangleEdgeShape(val offset: Int) : Shape {
+
+    override fun createOutline(
+        size: Size,
+        layoutDirection: LayoutDirection,
+        density: Density
+    ): Outline {
+        val trianglePath = Path().apply {
+            moveTo(x = 0f, y = size.height-offset)
+            lineTo(x = 0f, y = size.height)
+            lineTo(x = 0f + offset, y = size.height)
+        }
+        return Outline.Generic(path = trianglePath)
+    }
+}

+ 26 - 0
App/app/src/main/java/com/example/mystictale/resources/components/TriangleEdgeShapeAI.kt

@@ -0,0 +1,26 @@
+package com.example.mystictale.resources.components
+
+import androidx.compose.ui.geometry.Size
+import androidx.compose.ui.graphics.Outline
+import androidx.compose.ui.graphics.Path
+import androidx.compose.ui.graphics.Shape
+import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.LayoutDirection
+
+
+class TriangleEdgeShapeAI(val offset: Int) : Shape {
+
+    override fun createOutline(
+        size: Size,
+        layoutDirection: LayoutDirection,
+        density: Density
+    ): Outline {
+        val trianglePath = Path().apply {
+            moveTo(x = size.width / 2 - offset + 30f, y = size.height) // Левая вершина треугольника
+            lineTo(x = size.width / 2 + offset + 30f, y = size.height) // Правая вершина треугольника
+            lineTo(x = size.width / 2 + 30f, y = size.height - offset) // Верхняя центральная вершина
+            close()
+        }
+        return Outline.Generic(path = trianglePath)
+    }
+}

+ 61 - 0
App/app/src/main/java/com/example/mystictale/resources/components/UserMessage.kt

@@ -0,0 +1,61 @@
+package com.example.mystictale.resources.components
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.IntrinsicSize
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import com.example.mystictale.ui.theme.DarkPurple
+import com.example.mystictale.ui.theme.OpenSans
+import com.example.mystictale.ui.theme.Purple
+
+@Composable
+fun UserMessage(message: String) {
+    Row(
+        Modifier
+            .height(IntrinsicSize.Max)
+            .fillMaxWidth(),
+        horizontalArrangement = Arrangement.End
+    ) {
+        Column(
+            modifier = Modifier
+                .background(
+                    color = Purple,
+                    shape = RoundedCornerShape(4.dp, 4.dp, 0.dp, 4.dp)
+                )
+                .fillMaxWidth(0.7f)
+        ) {
+            Text(
+                message,
+                fontWeight = FontWeight.Normal,
+                fontFamily = OpenSans,
+                fontSize = 13.sp,
+                color = Color.White,
+                modifier = Modifier.padding(7.dp)
+            )
+        }
+        Column(
+            modifier = Modifier
+                .background(
+                    color = Purple,
+                    shape = TriangleEdgeShape(20)
+                )
+                .width(8.dp)
+                .fillMaxHeight()
+        ) {
+        }
+    }
+}

+ 53 - 0
App/app/src/main/java/com/example/mystictale/resources/components/ValuesDropMenu.kt

@@ -0,0 +1,53 @@
+package com.example.mystictale.resources.components
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonColors
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.DropdownMenu
+import androidx.compose.material3.DropdownMenuItem
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Size
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.layout.onGloballyPositioned
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import androidx.compose.ui.unit.toSize
+import com.example.mystictale.ViewModels.CardsViewModel
+import com.example.mystictale.models.Values
+import com.example.mystictale.resources.components.dateComponents.ValidationDate
+import com.example.mystictale.ui.theme.DarkPurple
+import com.example.mystictale.ui.theme.OpenSans
+
+@Composable
+fun ValuesDropMenu(values: List<Values>) {
+    values.sortedBy { value -> value.id }
+    val numberOfAspects =  values.sortedByDescending  { value-> value.TileAspect.id }.first().TileAspect.id
+   Column(Modifier.fillMaxWidth()) {
+
+       for (i in 1..numberOfAspects!!) {
+           val valueList = values.filter { value -> value.TileAspect.id == i }
+           ValuesElement(valueList)
+           Spacer(Modifier.height(10.dp))
+       }
+   }
+
+}

+ 205 - 0
App/app/src/main/java/com/example/mystictale/resources/components/ValuesElement.kt

@@ -0,0 +1,205 @@
+package com.example.mystictale.resources.components
+
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonColors
+import androidx.compose.material3.Icon
+import androidx.compose.material3.LocalTextStyle
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.text.PlatformTextStyle
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.style.LineHeightStyle
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.em
+import androidx.compose.ui.unit.sp
+import com.example.mystictale.R
+import com.example.mystictale.models.Values
+import com.example.mystictale.ui.theme.DarkPurple
+import com.example.mystictale.ui.theme.OpenSans
+
+@Composable
+fun ValuesElement(values: List<Values>) {
+    val valuesPositive = values.filter { value -> value.Negative_of_positive == true }
+    val valuesNegative = values.filter { value -> value.Negative_of_positive == false }
+    val valueGeneral = values.filter { value -> value.Negative_of_positive == null }
+    val open = remember { mutableStateOf(false) }
+    Column(
+        modifier = Modifier.fillMaxSize(),
+        verticalArrangement = Arrangement.Center,
+        horizontalAlignment = Alignment.CenterHorizontally
+    ) {
+        Button(
+            onClick = { open.value = !open.value },
+            modifier = Modifier
+                .fillMaxWidth()
+                .height(33.dp),
+            shape = RoundedCornerShape(10.dp),
+            colors = ButtonColors(
+                containerColor = DarkPurple,
+                contentColor = Color.White,
+                disabledContentColor = Color.White,
+                disabledContainerColor = DarkPurple
+            ),
+
+            ) {
+            Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
+                Text(
+                    values.last().TileAspect.Title,
+                    fontSize = 14.sp,
+                    fontWeight = FontWeight.Normal,
+                    color = Color.White
+                )
+                Icon(
+                    painter = painterResource(if (open.value) R.drawable.open_value else R.drawable.close_value),
+                    contentDescription = "",
+                    modifier = Modifier
+                        .height(15.dp)
+                        .width(15.dp),
+                    tint = Color(0xFF0B0328)
+                )
+            }
+
+
+        }
+        AnimatedVisibility(visible = open.value) {
+            if (valuesNegative.isNotEmpty() && valuesPositive.isNotEmpty()) {
+                Row(
+                    modifier = Modifier
+                        .fillMaxSize()
+                        .clip(RoundedCornerShape(10.dp))
+                        .background(Color.White)
+                        .padding(15.dp),
+                    horizontalArrangement = Arrangement.SpaceEvenly
+                ) {
+                    Column(
+                        modifier = Modifier
+                            .fillMaxWidth()
+                            .padding(5.dp)
+                            .background(Color.Transparent)
+                            .weight(1f),
+                        verticalArrangement = Arrangement.Center,
+                        horizontalAlignment = Alignment.CenterHorizontally
+                    ) {
+                        Text(
+                            "Прямое\nположение",
+                            fontSize = 13.sp,
+                            fontFamily = OpenSans,
+                            fontWeight = FontWeight.Bold,
+                            textAlign = TextAlign.Center
+                        )
+                        Spacer(Modifier.height(5.dp))
+                        Text(
+                            valuesPositive.last().Content,
+                            fontSize = 11.sp,
+                            fontWeight = FontWeight.Light,
+                            fontFamily = OpenSans,
+                            style = LocalTextStyle.current.merge(
+                                TextStyle(
+                                    lineHeight = 1.5.em,
+                                    platformStyle = PlatformTextStyle(
+                                        includeFontPadding = false
+                                    ),
+                                    lineHeightStyle = LineHeightStyle(
+                                        alignment = LineHeightStyle.Alignment.Center,
+                                        trim = LineHeightStyle.Trim.None
+                                    )
+                                )
+                            )
+                        )
+                    }
+
+                    Column(
+                        modifier = Modifier
+                            .fillMaxWidth()
+                            .padding(5.dp)
+                            .background(Color.Transparent)
+                            .fillMaxWidth()
+                            .weight(1f),
+                        verticalArrangement = Arrangement.Center,
+                        horizontalAlignment = Alignment.CenterHorizontally
+                    ) {
+                        Text(
+                            "Перевернутой\nположение",
+                            fontSize = 13.sp,
+                            fontFamily = OpenSans,
+                            fontWeight = FontWeight.Bold,
+                            textAlign = TextAlign.Center
+                        )
+                        Text(
+                            valuesNegative.last().Content,
+                            fontSize = 11.sp,
+                            fontWeight = FontWeight.Light,
+                            fontFamily = OpenSans,
+                            style = LocalTextStyle.current.merge(
+                                TextStyle(
+                                    lineHeight = 1.5.em,
+                                    platformStyle = PlatformTextStyle(
+                                        includeFontPadding = false
+                                    ),
+                                    lineHeightStyle = LineHeightStyle(
+                                        alignment = LineHeightStyle.Alignment.Center,
+                                        trim = LineHeightStyle.Trim.None
+                                    )
+                                )
+                            )
+                        )
+                    }
+
+                }
+
+            }
+            if (valueGeneral.isNotEmpty()) {
+                Column(
+                    modifier = Modifier
+                        .fillMaxWidth()
+                        .clip(RoundedCornerShape(10.dp))
+                        .background(Color.White)
+                        .padding(15.dp),
+                    verticalArrangement = Arrangement.Top,
+                    horizontalAlignment = Alignment.CenterHorizontally
+                ) {
+                    Text(
+                        valueGeneral.last().Content, fontSize = 11.sp,
+                        fontWeight = FontWeight.Light,
+                        fontFamily = OpenSans,
+                        style = LocalTextStyle.current.merge(
+                            TextStyle(
+                                lineHeight = 1.5.em,
+                                platformStyle = PlatformTextStyle(
+                                    includeFontPadding = false
+                                ),
+                                lineHeightStyle = LineHeightStyle(
+                                    alignment = LineHeightStyle.Alignment.Center,
+                                    trim = LineHeightStyle.Trim.None
+                                )
+                            )
+                        )
+                    )
+                }
+            }
+
+
+        }
+    }
+}

+ 0 - 31
App/app/src/main/java/com/example/mystictale/resources/components/dateComponents/LayoutCard.kt

@@ -1,31 +0,0 @@
-package com.example.mystictale.resources.components.dateComponents
-
-import androidx.compose.foundation.Image
-import androidx.compose.foundation.background
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.width
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.unit.dp
-import com.example.mystictale.models.Cards
-import com.example.mystictale.ui.theme.DarkPurple
-
-@Composable
-fun LayoutCard(card: Cards) {
-
-    Column(modifier = Modifier
-        .height(171.dp)
-        .width(100.dp)
-        .background(DarkPurple)
-        .padding(10.dp),
-        verticalArrangement = Arrangement.Top,
-        horizontalAlignment = Alignment.CenterHorizontally) {
-       
-
-
-    }
-}

+ 1 - 0
App/app/src/main/java/com/example/mystictale/ui/theme/Color.kt

@@ -12,4 +12,5 @@ val Pink40 = Color(0xFF7D5260)
 val DarkPurple = Color(0xFF28176B)
 val Grey = Color(0xFFA1A0A3)
 val Purple = Color(0xFF493795)
+val DarkRed = Color(0Xff421212)
 

BIN
App/app/src/main/res/drawable/ai.png


BIN
App/app/src/main/res/drawable/cards.png


BIN
App/app/src/main/res/drawable/close_value.png


BIN
App/app/src/main/res/drawable/open_value.png


BIN
App/app/src/main/res/drawable/profile.png


BIN
App/app/src/main/res/drawable/send.png


+ 6 - 0
App/gradle/libs.versions.toml

@@ -2,6 +2,7 @@
 agp = "8.5.1"
 bom = "3.0.2"
 coilCompose = "2.4.0"
+converterGson = "2.9.0"
 fragmentKtx = "1.8.5"
 gson = "2.10.1"
 jacksonModuleKotlin = "2.12.1"
@@ -17,9 +18,11 @@ lifecycleRuntimeKtx = "2.8.5"
 activityCompose = "1.9.2"
 composeBom = "2024.04.01"
 lifecycleViewmodelKtx = "2.8.7"
+loggingInterceptor = "4.10.0"
 material3 = "1.4.0-alpha03"
 navigationCompose = "2.8.0"
 okhttp = "4.12.0"
+retrofit = "2.9.0"
 
 [libraries]
 androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
@@ -29,6 +32,7 @@ androidx-lifecycle-viewmodel-ktx = { module = "androidx.lifecycle:lifecycle-view
 auth-kt = { module = "io.github.jan-tennert.supabase:auth-kt" }
 bom = { module = "io.github.jan-tennert.supabase:bom", version.ref = "bom" }
 coil-compose = { module = "io.coil-kt:coil-compose", version.ref = "coilCompose" }
+converter-gson = { module = "com.squareup.retrofit2:converter-gson", version.ref = "converterGson" }
 gson = { module = "com.google.code.gson:gson", version.ref = "gson" }
 jackson-module-kotlin = { module = "com.fasterxml.jackson.module:jackson-module-kotlin", version.ref = "jacksonModuleKotlin" }
 junit = { group = "junit", name = "junit", version.ref = "junit" }
@@ -47,8 +51,10 @@ androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit
 androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
 kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlinxCoroutinesAndroid" }
 ktor-client-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktorClientOkhttp" }
+logging-interceptor = { module = "com.squareup.okhttp3:logging-interceptor", version.ref = "loggingInterceptor" }
 material3 = { module = "androidx.compose.material3:material3", version.ref = "material3" }
 okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
+retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }
 storage-kt = { module = "io.github.jan-tennert.supabase:storage-kt", version.ref = "bom" }
 
 androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "navigationCompose" }