From 18de6efe6aad327e1b814ae95a383f4e7c079f5d Mon Sep 17 00:00:00 2001 From: KP9lK Date: Wed, 11 Jun 2025 14:30:16 +0300 Subject: [PATCH] init --- .gitignore | 15 + .idea/.gitignore | 3 + .idea/compiler.xml | 6 + .idea/deploymentTargetSelector.xml | 25 + .idea/gradle.xml | 19 + .idea/inspectionProfiles/Project_Default.xml | 57 ++ .idea/kotlinc.xml | 6 + .idea/migrations.xml | 10 + .idea/misc.xml | 794 ++++++++++++++++++ .idea/runConfigurations.xml | 17 + .idea/vcs.xml | 4 + app/.gitignore | 1 + app/build.gradle.kts | 80 ++ app/proguard-rules.pro | 21 + .../furintiture/ExampleInstrumentedTest.kt | 24 + app/src/main/AndroidManifest.xml | 29 + .../com/example/furintiture/MainActivity.kt | 89 ++ .../furintiture/configure/Serializers.kt | 34 + .../com/example/furintiture/data/DataStore.kt | 25 + .../furintiture/data/RetrofitClient.kt | 21 + .../furintiture/data/api/FurnitureApi.kt | 88 ++ .../model/request/AddAddressRequest.kt | 12 + .../model/request/AddToCartRequest.kt | 12 + .../model/request/AddToWishlistRequest.kt | 11 + .../request/ChangeCountFromCartRequest.kt | 12 + .../model/request/CreateOrderItemRequest.kt | 12 + .../model/request/CreateOrderRequest.kt | 18 + .../furintiture/model/request/LoginRequest.kt | 6 + .../model/request/RegisterRequest.kt | 11 + .../model/request/RemoveFromCartRequest.kt | 11 + .../request/RemoveFromWishlistRequest.kt | 11 + .../model/response/AddressResponse.kt | 13 + .../model/response/AllShopCategoryResponse.kt | 10 + .../model/response/CartResponse.kt | 9 + .../response/FurnitureCategoryResponse.kt | 9 + .../model/response/FurnitureResponse.kt | 19 + .../model/response/OrderItemResponse.kt | 14 + .../model/response/OrderResponse.kt | 21 + .../model/response/OrderStatusResponse.kt | 9 + .../model/response/SaleResponse.kt | 10 + .../model/response/ShopCategoryResponse.kt | 9 + .../model/response/UserResponse.kt | 15 + .../ui/common/FurnitrueTextField.kt | 173 ++++ .../ui/common/FurnitureBottomNavigation.kt | 81 ++ .../furintiture/ui/common/FurnitureButton.kt | 65 ++ .../furintiture/ui/common/FurnitureCard.kt | 142 ++++ .../ui/common/FurnitureCartCard.kt | 114 +++ .../ui/common/FurnitureHorizontalList.kt | 79 ++ .../ui/common/FurnitureOrderCard.kt | 100 +++ .../ui/screen/FurnitureGlobalNavigation.kt | 132 +++ .../FurnitureAddressBottomSheet.kt | 135 +++ .../FurnitureAddressBottomSheetViewModel.kt | 33 + .../furintiture/ui/screen/cart/CartScreen.kt | 118 +++ .../ui/screen/cart/CartScreenState.kt | 8 + .../ui/screen/cart/CartScreenViewModel.kt | 80 ++ .../ui/screen/detail/DetailScreen.kt | 216 +++++ .../ui/screen/detail/DetailScreenState.kt | 22 + .../ui/screen/detail/DetailScreenViewModel.kt | 56 ++ .../ui/screen/furniture/FurnitureScreen.kt | 109 +++ .../screen/furniture/FurnitureScreenState.kt | 8 + .../furniture/FurnitureScreenViewModel.kt | 34 + .../ui/screen/login/LoginScreen.kt | 146 ++++ .../ui/screen/login/LoginScreenState.kt | 10 + .../ui/screen/login/LoginScreenViewModel.kt | 55 ++ .../furintiture/ui/screen/main/MainScreen.kt | 246 ++++++ .../ui/screen/main/MainScreenState.kt | 16 + .../ui/screen/main/MainScreenViewModel.kt | 85 ++ .../ui/screen/order/OrderScreen.kt | 84 ++ .../ui/screen/order/OrderScreenState.kt | 8 + .../ui/screen/order/OrderScreenViewModel.kt | 30 + .../screen/registration/RegistrationScreen.kt | 160 ++++ .../registration/RegistrationScreenState.kt | 13 + .../RegistrationScreenViewModel.kt | 79 ++ .../ui/screen/splashscreen/SplashScreen.kt | 54 ++ .../com/example/furintiture/ui/theme/Color.kt | 19 + .../com/example/furintiture/ui/theme/Theme.kt | 58 ++ .../com/example/furintiture/ui/theme/Type.kt | 34 + app/src/main/res/drawable/fi_sr_eye_1.xml | 16 + .../res/drawable/ic_launcher_background.xml | 170 ++++ .../res/drawable/ic_launcher_foreground.xml | 30 + app/src/main/res/drawable/images.png | Bin 0 -> 144 bytes app/src/main/res/drawable/lock_icon.xml | 10 + app/src/main/res/drawable/mail_icon.xml | 10 + app/src/main/res/drawable/user_icon.xml | 13 + app/src/main/res/font/manrope.ttf | Bin 0 -> 94948 bytes app/src/main/res/font/manrope_extrabold.ttf | Bin 0 -> 95664 bytes .../res/mipmap-anydpi-v26/ic_launcher.xml | 6 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 6 + app/src/main/res/mipmap-hdpi/ic_launcher.webp | Bin 0 -> 1404 bytes .../res/mipmap-hdpi/ic_launcher_round.webp | Bin 0 -> 2898 bytes app/src/main/res/mipmap-mdpi/ic_launcher.webp | Bin 0 -> 982 bytes .../res/mipmap-mdpi/ic_launcher_round.webp | Bin 0 -> 1772 bytes .../main/res/mipmap-xhdpi/ic_launcher.webp | Bin 0 -> 1900 bytes .../res/mipmap-xhdpi/ic_launcher_round.webp | Bin 0 -> 3918 bytes .../main/res/mipmap-xxhdpi/ic_launcher.webp | Bin 0 -> 2884 bytes .../res/mipmap-xxhdpi/ic_launcher_round.webp | Bin 0 -> 5914 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.webp | Bin 0 -> 3844 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.webp | Bin 0 -> 7778 bytes app/src/main/res/values/colors.xml | 10 + app/src/main/res/values/strings.xml | 3 + app/src/main/res/values/themes.xml | 5 + app/src/main/res/xml/backup_rules.xml | 13 + .../main/res/xml/data_extraction_rules.xml | 19 + .../example/furintiture/ExampleUnitTest.kt | 17 + build.gradle.kts | 6 + gradle.properties | 23 + gradle/libs.versions.toml | 50 ++ gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59203 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 185 ++++ gradlew.bat | 89 ++ settings.gradle.kts | 24 + 112 files changed, 5135 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/.gitignore create mode 100644 .idea/compiler.xml create mode 100644 .idea/deploymentTargetSelector.xml create mode 100644 .idea/gradle.xml create mode 100644 .idea/inspectionProfiles/Project_Default.xml create mode 100644 .idea/kotlinc.xml create mode 100644 .idea/migrations.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/runConfigurations.xml create mode 100644 .idea/vcs.xml create mode 100644 app/.gitignore create mode 100644 app/build.gradle.kts create mode 100644 app/proguard-rules.pro create mode 100644 app/src/androidTest/java/com/example/furintiture/ExampleInstrumentedTest.kt create mode 100644 app/src/main/AndroidManifest.xml create mode 100644 app/src/main/java/com/example/furintiture/MainActivity.kt create mode 100644 app/src/main/java/com/example/furintiture/configure/Serializers.kt create mode 100644 app/src/main/java/com/example/furintiture/data/DataStore.kt create mode 100644 app/src/main/java/com/example/furintiture/data/RetrofitClient.kt create mode 100644 app/src/main/java/com/example/furintiture/data/api/FurnitureApi.kt create mode 100644 app/src/main/java/com/example/furintiture/model/request/AddAddressRequest.kt create mode 100644 app/src/main/java/com/example/furintiture/model/request/AddToCartRequest.kt create mode 100644 app/src/main/java/com/example/furintiture/model/request/AddToWishlistRequest.kt create mode 100644 app/src/main/java/com/example/furintiture/model/request/ChangeCountFromCartRequest.kt create mode 100644 app/src/main/java/com/example/furintiture/model/request/CreateOrderItemRequest.kt create mode 100644 app/src/main/java/com/example/furintiture/model/request/CreateOrderRequest.kt create mode 100644 app/src/main/java/com/example/furintiture/model/request/LoginRequest.kt create mode 100644 app/src/main/java/com/example/furintiture/model/request/RegisterRequest.kt create mode 100644 app/src/main/java/com/example/furintiture/model/request/RemoveFromCartRequest.kt create mode 100644 app/src/main/java/com/example/furintiture/model/request/RemoveFromWishlistRequest.kt create mode 100644 app/src/main/java/com/example/furintiture/model/response/AddressResponse.kt create mode 100644 app/src/main/java/com/example/furintiture/model/response/AllShopCategoryResponse.kt create mode 100644 app/src/main/java/com/example/furintiture/model/response/CartResponse.kt create mode 100644 app/src/main/java/com/example/furintiture/model/response/FurnitureCategoryResponse.kt create mode 100644 app/src/main/java/com/example/furintiture/model/response/FurnitureResponse.kt create mode 100644 app/src/main/java/com/example/furintiture/model/response/OrderItemResponse.kt create mode 100644 app/src/main/java/com/example/furintiture/model/response/OrderResponse.kt create mode 100644 app/src/main/java/com/example/furintiture/model/response/OrderStatusResponse.kt create mode 100644 app/src/main/java/com/example/furintiture/model/response/SaleResponse.kt create mode 100644 app/src/main/java/com/example/furintiture/model/response/ShopCategoryResponse.kt create mode 100644 app/src/main/java/com/example/furintiture/model/response/UserResponse.kt create mode 100644 app/src/main/java/com/example/furintiture/ui/common/FurnitrueTextField.kt create mode 100644 app/src/main/java/com/example/furintiture/ui/common/FurnitureBottomNavigation.kt create mode 100644 app/src/main/java/com/example/furintiture/ui/common/FurnitureButton.kt create mode 100644 app/src/main/java/com/example/furintiture/ui/common/FurnitureCard.kt create mode 100644 app/src/main/java/com/example/furintiture/ui/common/FurnitureCartCard.kt create mode 100644 app/src/main/java/com/example/furintiture/ui/common/FurnitureHorizontalList.kt create mode 100644 app/src/main/java/com/example/furintiture/ui/common/FurnitureOrderCard.kt create mode 100644 app/src/main/java/com/example/furintiture/ui/screen/FurnitureGlobalNavigation.kt create mode 100644 app/src/main/java/com/example/furintiture/ui/screen/bottomsheet/FurnitureAddressBottomSheet.kt create mode 100644 app/src/main/java/com/example/furintiture/ui/screen/bottomsheet/FurnitureAddressBottomSheetViewModel.kt create mode 100644 app/src/main/java/com/example/furintiture/ui/screen/cart/CartScreen.kt create mode 100644 app/src/main/java/com/example/furintiture/ui/screen/cart/CartScreenState.kt create mode 100644 app/src/main/java/com/example/furintiture/ui/screen/cart/CartScreenViewModel.kt create mode 100644 app/src/main/java/com/example/furintiture/ui/screen/detail/DetailScreen.kt create mode 100644 app/src/main/java/com/example/furintiture/ui/screen/detail/DetailScreenState.kt create mode 100644 app/src/main/java/com/example/furintiture/ui/screen/detail/DetailScreenViewModel.kt create mode 100644 app/src/main/java/com/example/furintiture/ui/screen/furniture/FurnitureScreen.kt create mode 100644 app/src/main/java/com/example/furintiture/ui/screen/furniture/FurnitureScreenState.kt create mode 100644 app/src/main/java/com/example/furintiture/ui/screen/furniture/FurnitureScreenViewModel.kt create mode 100644 app/src/main/java/com/example/furintiture/ui/screen/login/LoginScreen.kt create mode 100644 app/src/main/java/com/example/furintiture/ui/screen/login/LoginScreenState.kt create mode 100644 app/src/main/java/com/example/furintiture/ui/screen/login/LoginScreenViewModel.kt create mode 100644 app/src/main/java/com/example/furintiture/ui/screen/main/MainScreen.kt create mode 100644 app/src/main/java/com/example/furintiture/ui/screen/main/MainScreenState.kt create mode 100644 app/src/main/java/com/example/furintiture/ui/screen/main/MainScreenViewModel.kt create mode 100644 app/src/main/java/com/example/furintiture/ui/screen/order/OrderScreen.kt create mode 100644 app/src/main/java/com/example/furintiture/ui/screen/order/OrderScreenState.kt create mode 100644 app/src/main/java/com/example/furintiture/ui/screen/order/OrderScreenViewModel.kt create mode 100644 app/src/main/java/com/example/furintiture/ui/screen/registration/RegistrationScreen.kt create mode 100644 app/src/main/java/com/example/furintiture/ui/screen/registration/RegistrationScreenState.kt create mode 100644 app/src/main/java/com/example/furintiture/ui/screen/registration/RegistrationScreenViewModel.kt create mode 100644 app/src/main/java/com/example/furintiture/ui/screen/splashscreen/SplashScreen.kt create mode 100644 app/src/main/java/com/example/furintiture/ui/theme/Color.kt create mode 100644 app/src/main/java/com/example/furintiture/ui/theme/Theme.kt create mode 100644 app/src/main/java/com/example/furintiture/ui/theme/Type.kt create mode 100644 app/src/main/res/drawable/fi_sr_eye_1.xml create mode 100644 app/src/main/res/drawable/ic_launcher_background.xml create mode 100644 app/src/main/res/drawable/ic_launcher_foreground.xml create mode 100644 app/src/main/res/drawable/images.png create mode 100644 app/src/main/res/drawable/lock_icon.xml create mode 100644 app/src/main/res/drawable/mail_icon.xml create mode 100644 app/src/main/res/drawable/user_icon.xml create mode 100644 app/src/main/res/font/manrope.ttf create mode 100644 app/src/main/res/font/manrope_extrabold.ttf create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/values/colors.xml create mode 100644 app/src/main/res/values/strings.xml create mode 100644 app/src/main/res/values/themes.xml create mode 100644 app/src/main/res/xml/backup_rules.xml create mode 100644 app/src/main/res/xml/data_extraction_rules.xml create mode 100644 app/src/test/java/com/example/furintiture/ExampleUnitTest.kt create mode 100644 build.gradle.kts create mode 100644 gradle.properties create mode 100644 gradle/libs.versions.toml create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat create mode 100644 settings.gradle.kts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aa724b7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..b86273d --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml new file mode 100644 index 0000000..b687156 --- /dev/null +++ b/.idea/deploymentTargetSelector.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..ae733f1 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,19 @@ + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..cde3e19 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,57 @@ + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..6d0ee1c --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/migrations.xml b/.idea/migrations.xml new file mode 100644 index 0000000..f8051a6 --- /dev/null +++ b/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..76c7d9e --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,794 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..16660f1 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..d843f34 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 0000000..62ab0de --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,80 @@ +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.kotlin.compose) + kotlin("plugin.serialization") version "2.1.20" +} + +android { + namespace = "com.example.furintiture" + compileSdk = 35 + + defaultConfig { + applicationId = "com.example.furintiture" + minSdk = 24 + targetSdk = 35 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + kotlinOptions { + jvmTarget = "11" + } + buildFeatures { + compose = true + } +} + +dependencies { + + implementation(libs.retrofit) + implementation(libs.converter.kotlinx.serialization) + implementation(libs.okhttp) + + implementation(libs.kotlinx.serialization.json) + implementation(libs.kotlinx.datetime) + + implementation (libs.androidx.datastore.preferences) + + + + implementation(libs.androidx.lifecycle.viewmodel.compose) + + + implementation(libs.coil.compose) + implementation(libs.coil.network.okhttp) + + implementation (libs.androidx.navigation.compose) + + + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.lifecycle.runtime.ktx) + implementation(libs.androidx.activity.compose) + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.ui) + implementation(libs.androidx.ui.graphics) + implementation(libs.androidx.ui.tooling.preview) + implementation(libs.androidx.material3) + testImplementation(libs.junit) + androidTestImplementation(libs.androidx.junit) + androidTestImplementation(libs.androidx.espresso.core) + androidTestImplementation(platform(libs.androidx.compose.bom)) + androidTestImplementation(libs.androidx.ui.test.junit4) + debugImplementation(libs.androidx.ui.tooling) + debugImplementation(libs.androidx.ui.test.manifest) +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/app/src/androidTest/java/com/example/furintiture/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/example/furintiture/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..cb115e1 --- /dev/null +++ b/app/src/androidTest/java/com/example/furintiture/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.example.furintiture + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.example.furintiture", appContext.packageName) + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..c88f1ac --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/MainActivity.kt b/app/src/main/java/com/example/furintiture/MainActivity.kt new file mode 100644 index 0000000..c9268bc --- /dev/null +++ b/app/src/main/java/com/example/furintiture/MainActivity.kt @@ -0,0 +1,89 @@ +package com.example.furintiture + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.activity.enableEdgeToEdge +import androidx.compose.material3.Scaffold +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.lifecycle.lifecycleScope +import androidx.navigation.compose.rememberNavController +import com.example.furintiture.data.DataStoreSettings +import com.example.furintiture.ui.common.BottomNavigation +import com.example.furintiture.ui.common.Destination +import com.example.furintiture.ui.common.FurnitureBottomNavigation +import com.example.furintiture.ui.screen.Cart +import com.example.furintiture.ui.screen.FurnitureGlobalNavigation +import com.example.furintiture.ui.screen.Login +import com.example.furintiture.ui.screen.Main +import com.example.furintiture.ui.screen.Order +import com.example.furintiture.ui.screen.Registration +import com.example.furintiture.ui.screen.Splash +import com.example.furintiture.ui.theme.FurintitureTheme +import kotlinx.coroutines.launch + +class MainActivity : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdge() + val dataStoreSettings = DataStoreSettings(applicationContext) + setContent { + FurintitureTheme { + val navController = rememberNavController() + val bottomBarIsVisible = remember { mutableStateOf(false) } + val userUuid = remember { mutableStateOf("") } + + Scaffold( + bottomBar = { + if(bottomBarIsVisible.value) FurnitureBottomNavigation(){ destination -> + when(destination.route){ + BottomNavigation.Home -> navController.navigate(Main(userUuid.value)) + BottomNavigation.Cart -> navController.navigate(Cart(userUuid.value)) + BottomNavigation.Order -> { + navController.navigate(Order(userUuid.value)) + } + } + } + } + ) { paddingValues -> + paddingValues + FurnitureGlobalNavigation(dataStoreSettings, navController){ + bottomBarIsVisible.value = it + } + } + LaunchedEffect(Unit) { + lifecycleScope.launch { + navController.clearBackStack(Splash) + dataStoreSettings.userUuidFlow.collect{ + if(it.isEmpty()){ + navController.navigate(Login){ + popUpTo(Splash){ + inclusive = true + } + } + }else{ + userUuid.value = it + navController.navigate(Main(it)){ + popUpTo(Splash){ + inclusive = true + } + popUpTo(Registration){ + inclusive = true + } + popUpTo(Login){ + inclusive = true + } + } + } + } + } + + } + } + } + + } +} + diff --git a/app/src/main/java/com/example/furintiture/configure/Serializers.kt b/app/src/main/java/com/example/furintiture/configure/Serializers.kt new file mode 100644 index 0000000..a0d324e --- /dev/null +++ b/app/src/main/java/com/example/furintiture/configure/Serializers.kt @@ -0,0 +1,34 @@ +package com.example.furintiture.configure + +import androidx.navigation.NavType +import kotlinx.serialization.KSerializer +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import java.math.BigDecimal +import java.util.UUID + +object BigDecimalSerializer: KSerializer { + override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("BigDecimal", PrimitiveKind.STRING) + + override fun deserialize(decoder: Decoder): BigDecimal { + return BigDecimal(decoder.decodeString()) + } + + override fun serialize(encoder: Encoder, value: BigDecimal) { + encoder.encodeString(value.toString()) + } +} +object UuidSerializer: KSerializer { + override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("UUID", PrimitiveKind.STRING) + + override fun deserialize(decoder: Decoder): UUID { + return UUID.fromString(decoder.decodeString()) + } + + override fun serialize(encoder: Encoder, value: UUID) { + encoder.encodeString(value.toString()) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/data/DataStore.kt b/app/src/main/java/com/example/furintiture/data/DataStore.kt new file mode 100644 index 0000000..6eb87c5 --- /dev/null +++ b/app/src/main/java/com/example/furintiture/data/DataStore.kt @@ -0,0 +1,25 @@ +package com.example.furintiture.data + +import android.content.Context +import androidx.datastore.core.DataStore +import androidx.datastore.preferences.core.Preferences +import androidx.datastore.preferences.core.edit +import androidx.datastore.preferences.core.stringPreferencesKey +import androidx.datastore.preferences.preferencesDataStore +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import java.util.UUID + +val Context.dataStore: DataStore by preferencesDataStore(name = "settings") + +class DataStoreSettings(private val context: Context){ + private val UUID_KEY = stringPreferencesKey("user_uuid") + val userUuidFlow: Flow = context.dataStore.data.map { preferences -> + preferences[UUID_KEY] ?: "" + } + suspend fun setUuid(uuid: UUID){ + context.dataStore.edit { preferences -> + preferences[UUID_KEY] = uuid.toString() + } + } +} diff --git a/app/src/main/java/com/example/furintiture/data/RetrofitClient.kt b/app/src/main/java/com/example/furintiture/data/RetrofitClient.kt new file mode 100644 index 0000000..0b15b88 --- /dev/null +++ b/app/src/main/java/com/example/furintiture/data/RetrofitClient.kt @@ -0,0 +1,21 @@ +package com.example.furintiture.data + +import com.example.furintiture.data.api.FurnitureApi +import kotlinx.serialization.json.Json +import okhttp3.MediaType.Companion.toMediaType +import retrofit2.Retrofit +import retrofit2.converter.kotlinx.serialization.asConverterFactory + +private const val BASE_URL = "http://185.207.0.137:8090" +object RetrofitClient { + private val mediaType = "application/json".toMediaType() + private val client by lazy { + Retrofit.Builder() + .baseUrl(BASE_URL) + .addConverterFactory(Json.asConverterFactory(mediaType)) + .build() + } + val api by lazy { + client.create(FurnitureApi::class.java) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/data/api/FurnitureApi.kt b/app/src/main/java/com/example/furintiture/data/api/FurnitureApi.kt new file mode 100644 index 0000000..dccef3a --- /dev/null +++ b/app/src/main/java/com/example/furintiture/data/api/FurnitureApi.kt @@ -0,0 +1,88 @@ +package com.example.furintiture.data.api + +import com.example.furintiture.model.request.AddAddressRequest +import com.example.furintiture.model.request.AddToCartRequest +import com.example.furintiture.model.request.AddToWishlistRequest +import com.example.furintiture.model.request.ChangeCountFromCartRequest +import com.example.furintiture.model.request.CreateOrderRequest +import com.example.furintiture.model.request.LoginRequest +import com.example.furintiture.model.request.RegisterRequest +import com.example.furintiture.model.request.RemoveFromCartRequest +import com.example.furintiture.model.request.RemoveFromWishlistRequest +import com.example.furintiture.model.response.AllShopCategoryResponse +import com.example.furintiture.model.response.CartResponse +import com.example.furintiture.model.response.FurnitureCategoryResponse +import com.example.furintiture.model.response.FurnitureResponse +import com.example.furintiture.model.response.OrderResponse +import com.example.furintiture.model.response.SaleResponse +import com.example.furintiture.model.response.UserResponse +import retrofit2.http.Body +import retrofit2.http.DELETE +import retrofit2.http.GET +import retrofit2.http.POST +import retrofit2.http.PUT +import retrofit2.http.Path +import java.util.UUID +import kotlin.uuid.Uuid + +interface FurnitureApi { + @POST("/auth/login") + suspend fun auth(@Body loginRequest: LoginRequest): UserResponse + + @POST("/auth/register") + suspend fun register(@Body registerRequest: RegisterRequest): UserResponse + + @GET("/user/{uuid}/wishlist") + suspend fun getWithListByUuid(@Path("uuid") uuid: UUID): List + + @GET("/user/{uuid}/cart") + suspend fun getCartByUuid(@Path("uuid") uuid: UUID): List + + @GET("/user/{uuid}/order") + suspend fun getOrdersByUuid(@Path("uuid") uuid: UUID): List + + @GET("/user/{uuid}/profile") + suspend fun getProfileByUuid(@Path("uuid") uuid: UUID): UserResponse + + @POST("/user/{uuid}/address") + suspend fun addAddressByUuid(@Path("uuid") uuid: UUID, @Body addAddressRequest: AddAddressRequest) + + @POST("/wishlist") + suspend fun addToWishlist(addToWishlistRequest: AddToWishlistRequest) + + @DELETE("/wishlist") + suspend fun addToWishlist(removeFromWishlistRequest: RemoveFromWishlistRequest) + + @GET("/shop_category") + suspend fun getAllShopCategory(): List + + @GET("/shop_category/{shopCategoryId}/furniture") + suspend fun getFurnitureByShopCategory(@Path("shopCategoryId") shopCategoryId: Long): List + + @GET("/sale") + suspend fun getAllSales(): List + + @POST("/order") + suspend fun createOrder(@Body createOrderRequest: CreateOrderRequest) + + @GET("/furniture") + suspend fun getAllFurniture(): List + + @GET("/furniture/{furnitureId}") + suspend fun getFurnitureById(@Path("furnitureId") furnitureId: Long): FurnitureResponse + + @GET("/category") + suspend fun getAllFurnitureCategory(): List + + @GET("/category/{id}/furniture") + suspend fun getFurnitureByCategory(@Path("id") categoryId: Long): List + + @POST("/cart") + suspend fun addToCartByUuid(@Body addToCartRequest: AddToCartRequest) + + @PUT("/cart") + suspend fun changeCountFromCartByUuid(@Body changeCountFromCartRequest: ChangeCountFromCartRequest) + + @DELETE("/cart") + suspend fun removeFromCartByUuid(@Body removeFromCartRequest: RemoveFromCartRequest) +} \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/model/request/AddAddressRequest.kt b/app/src/main/java/com/example/furintiture/model/request/AddAddressRequest.kt new file mode 100644 index 0000000..9f8d883 --- /dev/null +++ b/app/src/main/java/com/example/furintiture/model/request/AddAddressRequest.kt @@ -0,0 +1,12 @@ +package com.example.furintiture.model.request + +import kotlinx.serialization.Serializable + +@Serializable +data class AddAddressRequest( + var address: String = "", + var entrance: Int? = null, + var floor: Int? = null, + var apartment: Int? = null, + var comment: String? = null +) \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/model/request/AddToCartRequest.kt b/app/src/main/java/com/example/furintiture/model/request/AddToCartRequest.kt new file mode 100644 index 0000000..52811bd --- /dev/null +++ b/app/src/main/java/com/example/furintiture/model/request/AddToCartRequest.kt @@ -0,0 +1,12 @@ +package com.example.furintiture.model.request + +import com.example.furintiture.configure.UuidSerializer +import kotlinx.serialization.Serializable +import java.util.UUID +@Serializable +data class AddToCartRequest( + @Serializable(with = UuidSerializer::class) + val uuid: UUID, + val furnitureId: Long, + val count: Int, +) \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/model/request/AddToWishlistRequest.kt b/app/src/main/java/com/example/furintiture/model/request/AddToWishlistRequest.kt new file mode 100644 index 0000000..ef2ea97 --- /dev/null +++ b/app/src/main/java/com/example/furintiture/model/request/AddToWishlistRequest.kt @@ -0,0 +1,11 @@ +package com.example.furintiture.model.request + +import com.example.furintiture.configure.UuidSerializer +import kotlinx.serialization.Serializable +import java.util.UUID +@Serializable +data class AddToWishlistRequest( + @Serializable(with = UuidSerializer::class) + val uuid: UUID, + val furnitureId: Long +) \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/model/request/ChangeCountFromCartRequest.kt b/app/src/main/java/com/example/furintiture/model/request/ChangeCountFromCartRequest.kt new file mode 100644 index 0000000..faac649 --- /dev/null +++ b/app/src/main/java/com/example/furintiture/model/request/ChangeCountFromCartRequest.kt @@ -0,0 +1,12 @@ +package com.example.furintiture.model.request + +import com.example.furintiture.configure.UuidSerializer +import kotlinx.serialization.Serializable +import java.util.UUID +@Serializable +data class ChangeCountFromCartRequest( + @Serializable(with = UuidSerializer::class) + val uuid: UUID, + val furnitureId: Long, + val count: Int, +) \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/model/request/CreateOrderItemRequest.kt b/app/src/main/java/com/example/furintiture/model/request/CreateOrderItemRequest.kt new file mode 100644 index 0000000..580d632 --- /dev/null +++ b/app/src/main/java/com/example/furintiture/model/request/CreateOrderItemRequest.kt @@ -0,0 +1,12 @@ +package com.example.furintiture.model.request + +import com.example.furintiture.configure.BigDecimalSerializer +import kotlinx.serialization.Serializable +import java.math.BigDecimal +@Serializable +data class CreateOrderItemRequest( + val furnitureId : Long, + @Serializable(with = BigDecimalSerializer::class) + val furniturePrice: BigDecimal, + val count: Int +) diff --git a/app/src/main/java/com/example/furintiture/model/request/CreateOrderRequest.kt b/app/src/main/java/com/example/furintiture/model/request/CreateOrderRequest.kt new file mode 100644 index 0000000..4502308 --- /dev/null +++ b/app/src/main/java/com/example/furintiture/model/request/CreateOrderRequest.kt @@ -0,0 +1,18 @@ +package com.example.furintiture.model.request + +import com.example.furintiture.configure.BigDecimalSerializer +import com.example.furintiture.configure.UuidSerializer +import kotlinx.serialization.Serializable +import java.math.BigDecimal +import java.util.UUID + +@Serializable +data class CreateOrderRequest( + @Serializable(with = UuidSerializer::class) + val userUuid : UUID, + val addressId: Long, + val orderStatus : Int, + @Serializable(with = BigDecimalSerializer::class) + val orderTotalSum : BigDecimal, + val orderSet: List +) diff --git a/app/src/main/java/com/example/furintiture/model/request/LoginRequest.kt b/app/src/main/java/com/example/furintiture/model/request/LoginRequest.kt new file mode 100644 index 0000000..97eebfa --- /dev/null +++ b/app/src/main/java/com/example/furintiture/model/request/LoginRequest.kt @@ -0,0 +1,6 @@ +package com.example.furintiture.model.request + +import kotlinx.serialization.Serializable + +@Serializable +data class LoginRequest(val email: String, val password: String) \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/model/request/RegisterRequest.kt b/app/src/main/java/com/example/furintiture/model/request/RegisterRequest.kt new file mode 100644 index 0000000..86a08e9 --- /dev/null +++ b/app/src/main/java/com/example/furintiture/model/request/RegisterRequest.kt @@ -0,0 +1,11 @@ +package com.example.furintiture.model.request + +import kotlinx.serialization.Serializable + +@Serializable +data class RegisterRequest( + val firstName: String, + val lastName: String, + val email: String, + val password: String +) \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/model/request/RemoveFromCartRequest.kt b/app/src/main/java/com/example/furintiture/model/request/RemoveFromCartRequest.kt new file mode 100644 index 0000000..b7eab9c --- /dev/null +++ b/app/src/main/java/com/example/furintiture/model/request/RemoveFromCartRequest.kt @@ -0,0 +1,11 @@ +package com.example.furintiture.model.request + +import com.example.furintiture.configure.UuidSerializer +import kotlinx.serialization.Serializable +import java.util.UUID +@Serializable +data class RemoveFromCartRequest( + @Serializable(with = UuidSerializer::class) + val uuid: UUID, + val furnitureId: Long, +) \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/model/request/RemoveFromWishlistRequest.kt b/app/src/main/java/com/example/furintiture/model/request/RemoveFromWishlistRequest.kt new file mode 100644 index 0000000..f86d4e7 --- /dev/null +++ b/app/src/main/java/com/example/furintiture/model/request/RemoveFromWishlistRequest.kt @@ -0,0 +1,11 @@ +package com.example.furintiture.model.request + +import com.example.furintiture.configure.UuidSerializer +import kotlinx.serialization.Serializable +import java.util.UUID +@Serializable +data class RemoveFromWishlistRequest( + @Serializable(with = UuidSerializer::class) + val uuid: UUID, + val furnitureId: Long +) \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/model/response/AddressResponse.kt b/app/src/main/java/com/example/furintiture/model/response/AddressResponse.kt new file mode 100644 index 0000000..106be4e --- /dev/null +++ b/app/src/main/java/com/example/furintiture/model/response/AddressResponse.kt @@ -0,0 +1,13 @@ +package com.example.furintiture.model.response + +import kotlinx.serialization.Serializable + +@Serializable +data class AddressResponse( + val addressId: Int, + val entrance: Int, + val floor: Int, + val apartment: Int, + val comment: String?, + val address: String +) \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/model/response/AllShopCategoryResponse.kt b/app/src/main/java/com/example/furintiture/model/response/AllShopCategoryResponse.kt new file mode 100644 index 0000000..a1bc57c --- /dev/null +++ b/app/src/main/java/com/example/furintiture/model/response/AllShopCategoryResponse.kt @@ -0,0 +1,10 @@ +package com.example.furintiture.model.response + +import kotlinx.serialization.Serializable + +@Serializable +data class AllShopCategoryResponse( + val id: Long, + val name: String, + var furnitureList: List +) \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/model/response/CartResponse.kt b/app/src/main/java/com/example/furintiture/model/response/CartResponse.kt new file mode 100644 index 0000000..dcce1ff --- /dev/null +++ b/app/src/main/java/com/example/furintiture/model/response/CartResponse.kt @@ -0,0 +1,9 @@ +package com.example.furintiture.model.response + +import kotlinx.serialization.Serializable + +@Serializable +data class CartResponse( + val count: Int, + val furnitureResponse: FurnitureResponse +) \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/model/response/FurnitureCategoryResponse.kt b/app/src/main/java/com/example/furintiture/model/response/FurnitureCategoryResponse.kt new file mode 100644 index 0000000..39196e0 --- /dev/null +++ b/app/src/main/java/com/example/furintiture/model/response/FurnitureCategoryResponse.kt @@ -0,0 +1,9 @@ +package com.example.furintiture.model.response + +import kotlinx.serialization.Serializable + +@Serializable +data class FurnitureCategoryResponse( + val id: Int, + val name: String, +) \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/model/response/FurnitureResponse.kt b/app/src/main/java/com/example/furintiture/model/response/FurnitureResponse.kt new file mode 100644 index 0000000..f752849 --- /dev/null +++ b/app/src/main/java/com/example/furintiture/model/response/FurnitureResponse.kt @@ -0,0 +1,19 @@ +package com.example.furintiture.model.response + +import com.example.furintiture.configure.BigDecimalSerializer +import kotlinx.serialization.Serializable +import java.math.BigDecimal + +@Serializable +data class FurnitureResponse( + val id: Long, + val name: String, + val description: String, + val url: String, + val category: FurnitureCategoryResponse, + @Serializable(with = BigDecimalSerializer::class) + val price: BigDecimal, + @Serializable(with = BigDecimalSerializer::class) + val sale: BigDecimal, + var shopCategories: List, +) \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/model/response/OrderItemResponse.kt b/app/src/main/java/com/example/furintiture/model/response/OrderItemResponse.kt new file mode 100644 index 0000000..1eca45f --- /dev/null +++ b/app/src/main/java/com/example/furintiture/model/response/OrderItemResponse.kt @@ -0,0 +1,14 @@ +package com.example.furintiture.model.response + +import com.example.furintiture.configure.BigDecimalSerializer +import kotlinx.serialization.Serializable +import java.math.BigDecimal +@Serializable +data class OrderItemResponse( + val furnitureId : Long, + val orderId : Long, + @Serializable(with = BigDecimalSerializer::class) + val furniturePrice: BigDecimal, + val count: Int, + val furnitureResponse: FurnitureResponse +) diff --git a/app/src/main/java/com/example/furintiture/model/response/OrderResponse.kt b/app/src/main/java/com/example/furintiture/model/response/OrderResponse.kt new file mode 100644 index 0000000..4329ba2 --- /dev/null +++ b/app/src/main/java/com/example/furintiture/model/response/OrderResponse.kt @@ -0,0 +1,21 @@ +package com.example.furintiture.model.response + +import com.example.furintiture.configure.BigDecimalSerializer +import com.example.furintiture.configure.UuidSerializer +import kotlinx.datetime.LocalDateTime +import kotlinx.serialization.Serializable +import java.math.BigDecimal +import java.util.* +@Serializable +data class OrderResponse( + val id : Long, + @Serializable(with = UuidSerializer::class) + val userUuid : UUID, + val addressId: Long, + val addressResponse: AddressResponse, + val dateTime: LocalDateTime, + val orderStatus : OrderStatusResponse, + @Serializable(with = BigDecimalSerializer::class) + val orderTotalSum : BigDecimal, + var orderSet: List +) \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/model/response/OrderStatusResponse.kt b/app/src/main/java/com/example/furintiture/model/response/OrderStatusResponse.kt new file mode 100644 index 0000000..e10406a --- /dev/null +++ b/app/src/main/java/com/example/furintiture/model/response/OrderStatusResponse.kt @@ -0,0 +1,9 @@ +package com.example.furintiture.model.response + +import kotlinx.serialization.Serializable + +@Serializable +data class OrderStatusResponse( + val id: Int, + val name: String, +) \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/model/response/SaleResponse.kt b/app/src/main/java/com/example/furintiture/model/response/SaleResponse.kt new file mode 100644 index 0000000..6beecb9 --- /dev/null +++ b/app/src/main/java/com/example/furintiture/model/response/SaleResponse.kt @@ -0,0 +1,10 @@ +package com.example.furintiture.model.response + +import kotlinx.serialization.Serializable + +@Serializable +data class SaleResponse( + val id: Int, + val name: String, + val url: String, +) \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/model/response/ShopCategoryResponse.kt b/app/src/main/java/com/example/furintiture/model/response/ShopCategoryResponse.kt new file mode 100644 index 0000000..8a39eab --- /dev/null +++ b/app/src/main/java/com/example/furintiture/model/response/ShopCategoryResponse.kt @@ -0,0 +1,9 @@ +package com.example.furintiture.model.response + +import kotlinx.serialization.Serializable + +@Serializable +data class ShopCategoryResponse( + val id: Long, + val name: String, +) \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/model/response/UserResponse.kt b/app/src/main/java/com/example/furintiture/model/response/UserResponse.kt new file mode 100644 index 0000000..eccdee6 --- /dev/null +++ b/app/src/main/java/com/example/furintiture/model/response/UserResponse.kt @@ -0,0 +1,15 @@ +package com.example.furintiture.model.response + +import com.example.furintiture.configure.UuidSerializer +import kotlinx.serialization.Serializable +import java.util.* +@Serializable +data class UserResponse( + @Serializable(with = UuidSerializer::class) + val userUuid: UUID, + val email: String, + val firstName: String, + val lastName: String, + val imageUrl: String? = null, + val address: AddressResponse? = null, + ) \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/ui/common/FurnitrueTextField.kt b/app/src/main/java/com/example/furintiture/ui/common/FurnitrueTextField.kt new file mode 100644 index 0000000..eae34fc --- /dev/null +++ b/app/src/main/java/com/example/furintiture/ui/common/FurnitrueTextField.kt @@ -0,0 +1,173 @@ +package com.example.furintiture.ui.common + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +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.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.BasicTextField +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +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.Font +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.input.PasswordVisualTransformation +import androidx.compose.ui.text.input.VisualTransformation +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.example.furintiture.R +import com.example.furintiture.ui.theme.Neutral_40 +import com.example.furintiture.ui.theme.Neutral_70 +import com.example.furintiture.ui.theme.Neutral_90 + +@Composable +fun BasieFurnitureTextField( + value: String, + onValueChange: (String) -> Unit, + textColor: Color, + label: @Composable () -> Unit, + modifier: Modifier = Modifier, + leadingIcon: @Composable (() -> Unit)? = null, + visualTransformation: VisualTransformation = VisualTransformation.None, + trailingIcon: @Composable (() -> Unit)? = null, +){ + BasicTextField( + value = value, + onValueChange = onValueChange, + modifier = modifier + .fillMaxWidth() + .background( + color = Color.White, + shape = RoundedCornerShape(18.dp)) + .border( + width = 1.dp, color = Neutral_40, + shape = RoundedCornerShape(18.dp) + ), + singleLine = true, + textStyle = TextStyle( + color = Neutral_90, + fontSize = 20.sp, + fontFamily = FontFamily(Font(R.font.manrope)) + ), + visualTransformation = visualTransformation, + ){ innerTextField -> + Row( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 8.dp, horizontal = 18.dp), + verticalAlignment = Alignment.CenterVertically + ) { + if (leadingIcon != null) { + leadingIcon() + } + Spacer(modifier = Modifier.width(10.dp)) + Column { + label() + Spacer(modifier = Modifier.height(4.dp)) + innerTextField() + } + Spacer(modifier = Modifier.weight(1f)) + trailingIcon?.let { + it() + } + } + } +} + + + + + + +@Composable +fun FurnitureTextField( + value: String, + onValueChange: (String) -> Unit, + textLabel: String, + leadingResourceId: Int, + tintColor: Color = Neutral_70, + textColor: Color = Neutral_90, +){ + BasieFurnitureTextField( + value = value, + textColor = textColor, + onValueChange = onValueChange, + label = { + Text( + textLabel, + color = textColor, + style = TextStyle( + color = Neutral_90, + fontSize = 15.sp, + fontFamily = FontFamily(Font(R.font.manrope)) + ) + ) + }, + leadingIcon = { Icon( + modifier = Modifier.size(24.dp), + painter = painterResource(leadingResourceId), + tint = tintColor, + contentDescription = null) + } + ) +} + + +@Composable +fun FurniturePasswordTextField( + value: String, + onValueChange: (String) -> Unit, + tintColor: Color = Neutral_70, + textColor: Color = Neutral_90, +){ + val passwordIsVisible = remember { mutableStateOf(false) } + BasieFurnitureTextField( + value = value, + textColor = textColor, + onValueChange = onValueChange, + label = { + Text("Password", + color = textColor, + style = TextStyle( + color = Neutral_90, + fontSize = 15.sp, + fontFamily = FontFamily(Font(R.font.manrope)) + )) + }, + visualTransformation = if(passwordIsVisible.value) VisualTransformation.None else PasswordVisualTransformation('*'), + leadingIcon = { Icon( + modifier = Modifier.size(24.dp), + painter = painterResource(R.drawable.lock_icon), + tint = tintColor, + contentDescription = null) + }, + trailingIcon = { Icon( + modifier = + Modifier.size(20.dp).clickable { + passwordIsVisible.value = !passwordIsVisible.value + }, + tint = tintColor, + painter = painterResource(R.drawable.fi_sr_eye_1), + contentDescription = null) + } + ) + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/ui/common/FurnitureBottomNavigation.kt b/app/src/main/java/com/example/furintiture/ui/common/FurnitureBottomNavigation.kt new file mode 100644 index 0000000..505ae9a --- /dev/null +++ b/app/src/main/java/com/example/furintiture/ui/common/FurnitureBottomNavigation.kt @@ -0,0 +1,81 @@ +package com.example.furintiture.ui.common + +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Home +import androidx.compose.material.icons.filled.Menu +import androidx.compose.material.icons.filled.ShoppingCart +import androidx.compose.material3.Icon +import androidx.compose.material3.NavigationBar +import androidx.compose.material3.NavigationBarItem +import androidx.compose.material3.NavigationBarItemColors +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector +import com.example.furintiture.ui.theme.Neutral_40 +import com.example.furintiture.ui.theme.Primary + +public enum class Destination( + val route: BottomNavigation, + val label: String, + val icon: ImageVector, + val contentDescription: String +) { + HOME(BottomNavigation.Home, "Основная", Icons.Default.Home, "Songs"), + CART(BottomNavigation.Cart, "Корзина", Icons.Default.ShoppingCart, "Album"), + ORDER(BottomNavigation.Order, "Заказы", Icons.Default.Menu, "Playlist") +} + +sealed class BottomNavigation{ + data object Home: BottomNavigation() + data object Cart: BottomNavigation() + data object Order: BottomNavigation() +} + +@Composable +fun FurnitureBottomNavigation( + onChangeBottomItem: (Destination) -> Unit +) { + + val startDestination = Destination.HOME + var selectedDestination by rememberSaveable { mutableIntStateOf(startDestination.ordinal) } + NavigationBar( + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight(), + containerColor = Color.White + ) { + Destination.entries.forEachIndexed { index, destination -> + NavigationBarItem( + selected = selectedDestination == index, + onClick = { + selectedDestination = index + onChangeBottomItem(destination) + }, + icon = { + Icon( + destination.icon, + contentDescription = destination.contentDescription + ) + }, + label = { Text(destination.label) }, + colors = NavigationBarItemColors( + selectedIconColor = Primary, + selectedTextColor = Primary, + selectedIndicatorColor = Color.Transparent, + unselectedIconColor = Neutral_40, + unselectedTextColor = Neutral_40, + disabledIconColor = Neutral_40, + disabledTextColor = Neutral_40 + ) + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/ui/common/FurnitureButton.kt b/app/src/main/java/com/example/furintiture/ui/common/FurnitureButton.kt new file mode 100644 index 0000000..3cdc294 --- /dev/null +++ b/app/src/main/java/com/example/furintiture/ui/common/FurnitureButton.kt @@ -0,0 +1,65 @@ +package com.example.furintiture.ui.common + +import android.content.res.Resources.Theme +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.Font +import androidx.compose.ui.text.font.FontFamily +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.furintiture.R +import com.example.furintiture.ui.theme.FurintitureTheme +import com.example.furintiture.ui.theme.Primary + +@Composable +fun FurnitureButton( + text: String, + modifier: Modifier = Modifier, + onClick : () -> Unit, + ){ + Button( + modifier = modifier + .fillMaxWidth() + .height(43.dp) + .clip(shape = RoundedCornerShape(8.dp)) + , + colors = ButtonDefaults.buttonColors().copy( + containerColor = Primary, + contentColor = Color.White, + disabledContainerColor = Primary, + disabledContentColor = Color.White + ), + onClick = onClick + ) { + Text( + text = text, + style = TextStyle( + fontFamily = FontFamily(Font(R.font.manrope)), + fontWeight = FontWeight.Bold, + fontSize = 16.sp + ) + ) + } +} + +@Preview +@Composable +fun FurniturePreview(){ + FurnitureButton( + "Войти" + ){ + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/ui/common/FurnitureCard.kt b/app/src/main/java/com/example/furintiture/ui/common/FurnitureCard.kt new file mode 100644 index 0000000..de3b0b2 --- /dev/null +++ b/app/src/main/java/com/example/furintiture/ui/common/FurnitureCard.kt @@ -0,0 +1,142 @@ +package com.example.furintiture.ui.common + +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.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +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.text.TextStyle +import androidx.compose.ui.text.font.Font +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import coil3.compose.AsyncImage +import coil3.request.ImageRequest +import coil3.request.crossfade +import com.example.furintiture.R +import com.example.furintiture.model.response.FurnitureCategoryResponse +import com.example.furintiture.model.response.FurnitureResponse +import com.example.furintiture.ui.theme.Neutral_10 +import com.example.furintiture.ui.theme.Neutral_20 +import java.math.BigDecimal + +@Composable +fun FurnitureCard( + furnitureResponse: FurnitureResponse, + onFurnitureClick: (FurnitureResponse) -> Unit +){ + Column( + modifier = Modifier + .wrapContentHeight() + .width(150.dp) + .background(color = Neutral_10, shape = RoundedCornerShape(14.dp)) + .padding(16.dp) + .clickable { + onFurnitureClick(furnitureResponse) + }, + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ) { + Box( + modifier = Modifier.wrapContentSize() + ) { + AsyncImage( + modifier = Modifier + .size(120.dp, 120.dp) + , + model = ImageRequest + .Builder(LocalContext.current) + .data(furnitureResponse.url) + .crossfade(true) + .build(), + placeholder = painterResource(R.drawable.images), + contentScale = ContentScale.FillWidth, + contentDescription = null + ) + Text( + text = "${furnitureResponse.sale.multiply(BigDecimal(100)).toInt()}% OFF", + modifier = Modifier + .align(Alignment.BottomStart) + .background( + color = Color.Red, + shape = RoundedCornerShape(10.dp) + ) + .padding( + vertical = 4.dp, + horizontal = 6.dp + ), + style = TextStyle( + color = Color.White, + fontWeight = FontWeight.SemiBold, + fontFamily = FontFamily(Font(R.font.manrope)), + fontSize = 10.sp + ) + ) + } + Spacer(modifier = Modifier.height(4.dp)) + Column( + modifier = Modifier.wrapContentHeight() + ) { + Text( + text = furnitureResponse.name, + style = TextStyle( + color = com.example.furintiture.ui.theme.Text, + fontFamily = FontFamily(Font(R.font.manrope)), + fontSize = 14.sp + ), + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + Text( + text = "${furnitureResponse.price} ₽", + style = TextStyle( + color = com.example.furintiture.ui.theme.Text, + fontFamily = FontFamily(Font(R.font.manrope)), + fontSize = 20.sp, + fontWeight = FontWeight.Bold + ) + ) + } + } +} + +@Composable +@Preview +fun FurnitureCardPreview(){ + val furnitureResponse = FurnitureResponse( + id = 1, + name = "Стул", + price = BigDecimal("1000.5"), + description = "!@3", + sale = BigDecimal("0.40"), + url = "https://laurendanger.com/wp-content/uploads/sites/33/2024/10/IMG_3826.jpeg", + category = FurnitureCategoryResponse( + id = 1, + name = "!@3" + ), + shopCategories = emptyList() + ) + FurnitureCard(furnitureResponse){ + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/ui/common/FurnitureCartCard.kt b/app/src/main/java/com/example/furintiture/ui/common/FurnitureCartCard.kt new file mode 100644 index 0000000..bcebb07 --- /dev/null +++ b/app/src/main/java/com/example/furintiture/ui/common/FurnitureCartCard.kt @@ -0,0 +1,114 @@ +package com.example.furintiture.ui.common + +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.fillMaxHeight +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.size +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.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.shadow +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.TextStyle +import androidx.compose.ui.text.font.Font +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import coil3.compose.AsyncImage +import coil3.request.ImageRequest +import coil3.request.crossfade +import com.example.furintiture.R +import com.example.furintiture.model.response.CartResponse +import com.example.furintiture.ui.theme.Neutral_10 +import java.math.BigDecimal + +@Composable +fun FurnitureCartCard(cartResponse: CartResponse) { + Row( + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .fillMaxWidth() + .background(color = Neutral_10, shape = RoundedCornerShape(16.dp)) + .padding(16.dp) + ) { + AsyncImage( + modifier = Modifier + .size(100.dp, 100.dp) + , + model = ImageRequest + .Builder(LocalContext.current) + .data(cartResponse.furnitureResponse.url) + .crossfade(true) + .build(), + placeholder = painterResource(R.drawable.images), + contentScale = ContentScale.FillWidth, + contentDescription = null + ) + Spacer(Modifier.width(16.dp)) + Column( + modifier = Modifier + .fillMaxSize() + .fillMaxHeight() + ) { + Text( + text = cartResponse.furnitureResponse.name, + style = TextStyle( + color = com.example.furintiture.ui.theme.Text, + fontFamily = FontFamily(Font(R.font.manrope)), + fontSize = 24.sp + ) + ) + Text( + text = "${cartResponse.furnitureResponse.price} ₽", + style = TextStyle( + color = com.example.furintiture.ui.theme.Text, + fontFamily = FontFamily(Font(R.font.manrope)), + fontSize = 36.sp, + fontWeight = FontWeight.Bold + ) + ) + Spacer(modifier = Modifier.width(8.dp)) + Text( + text = "${cartResponse.furnitureResponse.sale.multiply(BigDecimal(100)).toInt()}% OFF", + modifier = Modifier + .background( + color = Color.Red, + shape = RoundedCornerShape(10.dp) + ) + .padding( + vertical = 4.dp, + horizontal = 6.dp + ), + style = TextStyle( + color = Color.White, + fontWeight = FontWeight.SemiBold, + fontFamily = FontFamily(Font(R.font.manrope)), + fontSize = 16.sp + ) + ) + Text( + text = "Количество: ${cartResponse.count}", + style = TextStyle( + color = com.example.furintiture.ui.theme.Text, + fontFamily = FontFamily(Font(R.font.manrope)), + fontSize = 24.sp + ) + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/ui/common/FurnitureHorizontalList.kt b/app/src/main/java/com/example/furintiture/ui/common/FurnitureHorizontalList.kt new file mode 100644 index 0000000..8950ded --- /dev/null +++ b/app/src/main/java/com/example/furintiture/ui/common/FurnitureHorizontalList.kt @@ -0,0 +1,79 @@ +package com.example.furintiture.ui.common + +import androidx.compose.foundation.clickable +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.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.lazy.items +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.capitalize +import androidx.compose.ui.text.font.Font +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.intl.Locale +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.example.furintiture.R +import com.example.furintiture.model.response.FurnitureResponse +import com.example.furintiture.model.response.ShopCategoryResponse +import com.example.furintiture.ui.theme.Primary + +@Composable +fun FurnitureHorizontalList( + categoryName: String, categoryFurnitureList: List, + onAllFurnitureClick: () -> Unit, + onFurnitureClick: (FurnitureResponse) -> Unit, +) { + Column( + modifier = Modifier.height(300.dp).fillMaxWidth() + ) { + Row( + modifier = + Modifier.height(30.dp) + .fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + modifier = Modifier.weight(1f), + text = categoryName.replaceFirstChar { it.titlecaseChar() }, + style = TextStyle( + color = com.example.furintiture.ui.theme.Text, + fontFamily = FontFamily(Font(R.font.manrope)), + fontSize = 20.sp, + fontWeight = FontWeight.Bold) + ) + Text( + modifier = Modifier.clickable { + onAllFurnitureClick() + }, + text = "Больше товаров", + style = TextStyle( + color = Primary, + fontFamily = FontFamily(Font(R.font.manrope)), + fontSize = 14.sp, + fontWeight = FontWeight.Bold + ) + ) + } + Spacer(modifier = Modifier.height(16.dp)) + LazyRow( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(16.dp) + ) { + items(categoryFurnitureList.size){ item -> + FurnitureCard(categoryFurnitureList[item]){ furniture -> + onFurnitureClick(furniture) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/ui/common/FurnitureOrderCard.kt b/app/src/main/java/com/example/furintiture/ui/common/FurnitureOrderCard.kt new file mode 100644 index 0000000..9022b37 --- /dev/null +++ b/app/src/main/java/com/example/furintiture/ui/common/FurnitureOrderCard.kt @@ -0,0 +1,100 @@ +package com.example.furintiture.ui.common + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.lazy.items +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.Font +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.example.furintiture.R +import com.example.furintiture.model.response.OrderResponse +import com.example.furintiture.ui.theme.Primary +import kotlinx.datetime.LocalDateTime +import kotlinx.datetime.format +import kotlinx.datetime.format.DateTimeComponents +import kotlinx.datetime.format.DateTimeFormat +import kotlinx.datetime.format.DateTimeFormatBuilder +import kotlinx.datetime.format.byUnicodePattern + +@Composable +fun FurnitureOrderCard(orderResponse: OrderResponse) { + + Column( + modifier = Modifier + .fillMaxWidth() + ) { + Row( + modifier = + Modifier.height(30.dp) + .fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + modifier = Modifier.weight(1f), + text = "Номер заказа: ${orderResponse.id}", + style = TextStyle( + color = com.example.furintiture.ui.theme.Text, + fontFamily = FontFamily(Font(R.font.manrope)), + fontSize = 20.sp, + fontWeight = FontWeight.Bold) + ) + Text( + text = "Статус заказа: ${orderResponse.orderStatus.name}", + style = TextStyle( + color = Primary, + fontFamily = FontFamily(Font(R.font.manrope)), + fontSize = 14.sp, + fontWeight = FontWeight.Bold + ) + ) + } + val format = LocalDateTime.Format { + byUnicodePattern("uuuu-MM-dd HH:mm") + } + Text( + text = "Дата заказа: ${format.format(orderResponse.dateTime)}", + style = TextStyle( + color = com.example.furintiture.ui.theme.Text, + fontFamily = FontFamily(Font(R.font.manrope)), + fontSize = 14.sp + ) + ) + Text( + text = "Итого: ${orderResponse.orderTotalSum}", + style = TextStyle( + color = com.example.furintiture.ui.theme.Text, + fontFamily = FontFamily(Font(R.font.manrope)), + fontSize = 14.sp + ) + ) + Text( + text = "По адресу: ${orderResponse.addressResponse.address}", + style = TextStyle( + color = com.example.furintiture.ui.theme.Text, + fontFamily = FontFamily(Font(R.font.manrope)), + fontSize = 14.sp + ) + ) + LazyRow( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(16.dp) + ) { + items(orderResponse.orderSet){ orderSet -> + FurnitureCard(orderSet.furnitureResponse) { + + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/ui/screen/FurnitureGlobalNavigation.kt b/app/src/main/java/com/example/furintiture/ui/screen/FurnitureGlobalNavigation.kt new file mode 100644 index 0000000..392ff7e --- /dev/null +++ b/app/src/main/java/com/example/furintiture/ui/screen/FurnitureGlobalNavigation.kt @@ -0,0 +1,132 @@ +package com.example.furintiture.ui.screen + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.navigation.NavHostController +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.toRoute +import com.example.furintiture.configure.UuidSerializer +import com.example.furintiture.data.DataStoreSettings +import com.example.furintiture.ui.screen.cart.CartScreen +import com.example.furintiture.ui.screen.detail.DetailScreen +import com.example.furintiture.ui.screen.furniture.FurnitureScreen +import com.example.furintiture.ui.screen.login.LoginScreen +import com.example.furintiture.ui.screen.main.MainScreen +import com.example.furintiture.ui.screen.order.OrderScreen +import com.example.furintiture.ui.screen.registration.RegistrationScreen +import com.example.furintiture.ui.screen.splashscreen.SplashScreen +import kotlinx.serialization.Serializable +import java.util.UUID + +@Composable +fun FurnitureGlobalNavigation( + dataStoreSettings: DataStoreSettings, + navHostController: NavHostController, + onBottomBarVisibleEvent: (Boolean) -> Unit +) { + NavHost( + modifier = Modifier, + navController = navHostController, + startDestination = Splash + ){ + composable { + SplashScreen() + onBottomBarVisibleEvent(false) + } + composable { + RegistrationScreen(dataStoreSettings){ + navHostController.navigate(Login) + } + onBottomBarVisibleEvent(false) + + } + composable { + LoginScreen(dataStoreSettings){ + navHostController.navigate(Registration) + } + onBottomBarVisibleEvent(false) + + } + + composable{ navBackStackEntry -> + val detail: Detail = navBackStackEntry.toRoute() + DetailScreen(detail){ + navHostController.navigateUp() + } + onBottomBarVisibleEvent(false) + + } + composable{navBackStackEntry -> + val furniture: Furniture = navBackStackEntry.toRoute() + + FurnitureScreen(uuid = furniture.uuid, onClosePressed = { + navHostController.navigateUp() + }) { + navHostController.navigate(it) + } + onBottomBarVisibleEvent(false) + } + composable{ navBackStackEntry -> + val cart: Cart = navBackStackEntry.toRoute() + CartScreen(cart.uuid) + } + composable{ navBackStackEntry -> + val order: Order = navBackStackEntry.toRoute() + OrderScreen(order.uuid) + } + composable
{ navBackStackEntry -> + val main: Main = navBackStackEntry.toRoute() + MainScreen( + main.uuid, + onNavigateToFurniture = { furniture -> + navHostController.navigate(furniture) + } + ){ detail -> + navHostController.navigate(detail) + } + onBottomBarVisibleEvent(true) + } + + } +} + + +@Serializable +data class Main( + val uuid: String +) + + + +@Serializable +data class Detail( + val furnitureId: Long, + val uuid: String +) + +@Serializable +data class Cart( + val uuid: String +) + +@Serializable +data class Order( + val uuid: String +) + +@Serializable +object Login + + +@Serializable +data class Furniture( + val uuid: String +) + + +@Serializable +object Registration + +@Serializable +object Splash \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/ui/screen/bottomsheet/FurnitureAddressBottomSheet.kt b/app/src/main/java/com/example/furintiture/ui/screen/bottomsheet/FurnitureAddressBottomSheet.kt new file mode 100644 index 0000000..6975355 --- /dev/null +++ b/app/src/main/java/com/example/furintiture/ui/screen/bottomsheet/FurnitureAddressBottomSheet.kt @@ -0,0 +1,135 @@ +package com.example.furintiture.ui.screen.bottomsheet + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +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.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ModalBottomSheet +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.Font +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.example.furintiture.R +import com.example.furintiture.model.request.AddAddressRequest +import com.example.furintiture.model.response.AddressResponse +import com.example.furintiture.ui.common.BasieFurnitureTextField +import com.example.furintiture.ui.common.FurnitureButton +import com.example.furintiture.ui.theme.Neutral_90 +import kotlinx.coroutines.flow.MutableStateFlow + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun FurnitureAddressBottomSheet( + addressResponse: AddressResponse?, + viewModel: FurnitureAddressBottomSheetViewModel, + createAddressCallback: (AddAddressRequest) -> Unit, +) { + val state = viewModel.furnitureAddressState.collectAsState() + LaunchedEffect(addressResponse) { + if (addressResponse != null){ + viewModel.setAddress(address = addressResponse.address) + viewModel.setFloor(floor = addressResponse.floor.toString()) + viewModel.setApartment(apartment = addressResponse.apartment.toString()) + viewModel.setComment(comment = addressResponse.comment ?: "") + } + } + ModalBottomSheet( + onDismissRequest = { + createAddressCallback(state.value) + } + ){ + Column( + modifier = Modifier + .padding(horizontal = 16.dp, vertical = 8.dp) + ) { + BasieFurnitureTextField( + value = state.value.address, + onValueChange = {viewModel.setAddress(it)}, + textColor = Neutral_90, + label = { + Text( + "Адрес", + color = Neutral_90, + style = TextStyle( + color = Neutral_90, + fontSize = 15.sp, + fontFamily = FontFamily(Font(R.font.manrope)) + ) + ) + } + ) + Spacer(Modifier.height(16.dp)) + Row( + modifier = Modifier.fillMaxWidth() + ){ + BasieFurnitureTextField( + modifier = Modifier.weight(0.5f), + value = if(state.value.floor == null) "" else state.value.floor.toString(), + onValueChange = {viewModel.setFloor(it)}, + textColor = Neutral_90, + label = { + Text( + "Этаж", + color = Neutral_90, + style = TextStyle( + color = Neutral_90, + fontSize = 15.sp, + fontFamily = FontFamily(Font(R.font.manrope)) + ) + ) + } + ) + BasieFurnitureTextField( + modifier = Modifier.weight(0.5f), + value = if(state.value.apartment == null) "" else state.value.apartment.toString(), + onValueChange = {viewModel.setApartment(it)}, + textColor = Neutral_90, + label = { + Text( + "Квартира", + color = Neutral_90, + style = TextStyle( + color = Neutral_90, + fontSize = 15.sp, + fontFamily = FontFamily(Font(R.font.manrope)) + ) + ) + } + ) + } + Spacer(Modifier.height(16.dp)) + BasieFurnitureTextField( + value = state.value.comment ?: "", + onValueChange = {viewModel.setComment(it)}, + textColor = Neutral_90, + label = { + Text( + "Комментарий курьеру", + color = Neutral_90, + style = TextStyle( + color = Neutral_90, + fontSize = 15.sp, + fontFamily = FontFamily(Font(R.font.manrope)) + ) + ) + } + ) + Spacer(Modifier.height(16.dp)) + val text = if(addressResponse != null) "Изменить" else "Добавить" + FurnitureButton( + text = text + ) { + createAddressCallback(state.value) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/ui/screen/bottomsheet/FurnitureAddressBottomSheetViewModel.kt b/app/src/main/java/com/example/furintiture/ui/screen/bottomsheet/FurnitureAddressBottomSheetViewModel.kt new file mode 100644 index 0000000..16e279e --- /dev/null +++ b/app/src/main/java/com/example/furintiture/ui/screen/bottomsheet/FurnitureAddressBottomSheetViewModel.kt @@ -0,0 +1,33 @@ +package com.example.furintiture.ui.screen.bottomsheet + +import androidx.lifecycle.ViewModel +import com.example.furintiture.model.request.AddAddressRequest +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update + +class FurnitureAddressBottomSheetViewModel: ViewModel() { + private val _furnitureAddressState = MutableStateFlow(AddAddressRequest()) + val furnitureAddressState = _furnitureAddressState.asStateFlow() + + fun setAddress(address: String){ + _furnitureAddressState.update { + it.copy(address = address) + } + } + fun setFloor(floor: String){ + _furnitureAddressState.update { + it.copy(floor = floor.toIntOrNull()) + } + } + fun setApartment(apartment: String){ + _furnitureAddressState.update { + it.copy(apartment = apartment.toIntOrNull()) + } + } + fun setComment(comment: String){ + _furnitureAddressState.update { + it.copy(comment = comment) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/ui/screen/cart/CartScreen.kt b/app/src/main/java/com/example/furintiture/ui/screen/cart/CartScreen.kt new file mode 100644 index 0000000..6a2c615 --- /dev/null +++ b/app/src/main/java/com/example/furintiture/ui/screen/cart/CartScreen.kt @@ -0,0 +1,118 @@ +package com.example.furintiture.ui.screen.cart + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.material3.Scaffold +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.Font +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.lifecycle.viewmodel.compose.viewModel +import com.example.furintiture.R +import com.example.furintiture.ui.common.FurnitureButton +import com.example.furintiture.ui.common.FurnitureCartCard +import com.example.furintiture.ui.theme.Neutral_20 +import kotlinx.coroutines.launch +import java.math.BigDecimal + +@Composable +fun CartScreen( + uuid: String +) { + val snackbarHostState = remember { SnackbarHostState() } + val coroutineScope = rememberCoroutineScope() + val viewModel: CartScreenViewModel = viewModel { CartScreenViewModel(uuid) } + Scaffold( + snackbarHost = { + SnackbarHost(hostState = snackbarHostState) + }, + contentColor = Neutral_20 + ) { paddingValues -> + CartScreenContent(viewModel, paddingValues){ + coroutineScope.launch { + snackbarHostState.showSnackbar(it) + } + } + } +} + +@Composable +fun CartScreenContent( + viewModel: CartScreenViewModel, + paddingValues: PaddingValues, + onErrorCallback : (String) -> Unit +){ + val state = viewModel.cartScreenState.collectAsState() + val totalSum = remember { derivedStateOf { + state.value.cartResponse.sumOf { cart -> + BigDecimal(cart.count) * cart.furnitureResponse.price + } + }} + + LaunchedEffect(state.value.error) { + state.value.error?.let(onErrorCallback) + state.value.error = null + } + Column( + modifier = Modifier + .padding(paddingValues) + .fillMaxSize() + .padding(horizontal = 16.dp) + .padding(bottom = 100.dp) + + + ) { + LazyColumn( + modifier = Modifier.fillMaxSize(), + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + items(state.value.cartResponse.size){ item -> + FurnitureCartCard(state.value.cartResponse[item]) + } + if(totalSum.value > BigDecimal(0)){ + item { + Spacer(Modifier.height(16.dp)) + Text( + "Итого: ${totalSum.value}", + style = TextStyle( + color = com.example.furintiture.ui.theme.Text, + fontFamily = FontFamily(Font(R.font.manrope)), + fontSize = 36.sp, + fontWeight = FontWeight.Bold + ) + ) + } + item { + Spacer(Modifier.height(16.dp)) + FurnitureButton( + modifier = Modifier.height(60.dp), + text = "Оформить заказ" + ) { + viewModel.createOrder() + } + } + } + } + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/ui/screen/cart/CartScreenState.kt b/app/src/main/java/com/example/furintiture/ui/screen/cart/CartScreenState.kt new file mode 100644 index 0000000..d0b02ee --- /dev/null +++ b/app/src/main/java/com/example/furintiture/ui/screen/cart/CartScreenState.kt @@ -0,0 +1,8 @@ +package com.example.furintiture.ui.screen.cart + +import com.example.furintiture.model.response.CartResponse + +data class CartScreenState( + var cartResponse: List = emptyList(), + var error: String? = null +) \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/ui/screen/cart/CartScreenViewModel.kt b/app/src/main/java/com/example/furintiture/ui/screen/cart/CartScreenViewModel.kt new file mode 100644 index 0000000..747edc5 --- /dev/null +++ b/app/src/main/java/com/example/furintiture/ui/screen/cart/CartScreenViewModel.kt @@ -0,0 +1,80 @@ +package com.example.furintiture.ui.screen.cart + +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.example.furintiture.data.RetrofitClient +import com.example.furintiture.model.request.CreateOrderItemRequest +import com.example.furintiture.model.request.CreateOrderRequest +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import java.math.BigDecimal +import java.util.UUID + +class CartScreenViewModel(private val uuid: String): ViewModel() { + private val _cartScreenState = MutableStateFlow(CartScreenState()) + val cartScreenState = _cartScreenState.asStateFlow() + val totalSum = derivedStateOf { cartScreenState.value.cartResponse.sumOf { cart -> + BigDecimal(cart.count) * cart.furnitureResponse.price } + } + init { + try { + init() + } + catch (e: Exception){ + _cartScreenState.update { + it.copy(error = e.message) + } + } + } + fun createOrder(){ + viewModelScope.launch { + try { + val addresId = RetrofitClient.api.getProfileByUuid(UUID.fromString(uuid)).address?.addressId + if (addresId == null){ + _cartScreenState.update { + it.copy(error = "Нельзя сделать заказ без адрес") + } + return@launch + } + val createOrderRequest = CreateOrderRequest( + userUuid = UUID.fromString(uuid), + addressId = addresId.toLong(), + orderStatus = 1, + orderTotalSum = cartScreenState.value.cartResponse.sumOf { cart -> + BigDecimal(cart.count) * cart.furnitureResponse.price + }, + orderSet = cartScreenState.value.cartResponse.map { + CreateOrderItemRequest( + furnitureId = it.furnitureResponse.id, + furniturePrice = it.furnitureResponse.price, + count = it.count + ) + } + ) + RetrofitClient.api.createOrder(createOrderRequest) + _cartScreenState.update { + it.copy(cartResponse = emptyList()) + } + } + catch (e: Exception){ + _cartScreenState.update { + it.copy(error = e.message) + } + } + + } + } + private fun init(){ + + viewModelScope.launch { + val cart = RetrofitClient.api.getCartByUuid(UUID.fromString(uuid)) + _cartScreenState.update { + it.copy(cartResponse = cart) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/ui/screen/detail/DetailScreen.kt b/app/src/main/java/com/example/furintiture/ui/screen/detail/DetailScreen.kt new file mode 100644 index 0000000..956ba9c --- /dev/null +++ b/app/src/main/java/com/example/furintiture/ui/screen/detail/DetailScreen.kt @@ -0,0 +1,216 @@ +package com.example.furintiture.ui.screen.detail + +import androidx.compose.foundation.background +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.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.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material.icons.filled.Close +import androidx.compose.material3.Button +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.Scaffold +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.Font +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.lifecycle.viewmodel.compose.viewModel +import coil3.compose.AsyncImage +import coil3.request.ImageRequest +import coil3.request.crossfade +import com.example.furintiture.R +import com.example.furintiture.ui.common.FurnitureButton +import com.example.furintiture.ui.screen.Detail +import com.example.furintiture.ui.theme.Neutral_10 +import com.example.furintiture.ui.theme.Neutral_20 +import com.example.furintiture.ui.theme.Neutral_40 +import kotlinx.coroutines.launch +import java.math.BigDecimal + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun DetailScreen( + detail: Detail, + onClosePressed: () -> Unit +) { + val snackbarHostState = remember { SnackbarHostState() } + val coroutineScope = rememberCoroutineScope() + val viewModel = viewModel { + DetailScreenViewModel(detail.furnitureId, detail.uuid) + } + Scaffold( + snackbarHost = { + SnackbarHost(hostState = snackbarHostState) + }, + topBar = { + TopAppBar( + title = {}, + navigationIcon = { + IconButton ( + onClick = { + onClosePressed() + } + ){ + Icon( + imageVector = Icons.Default.Close, + contentDescription = null + ) + } + } + ) + }, + bottomBar = { + Column( + modifier = Modifier + .fillMaxWidth() + .background(color = Neutral_20, shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp)) + .padding(20.dp) + ) { + FurnitureButton( + modifier = Modifier.height(60.dp), + text = "Добавить в корзину", + ) { + viewModel.addToCart() + } + } + }, + contentColor = Neutral_20 + ) { paddingValues -> + DetailScreenContent(viewModel, paddingValues){ + coroutineScope.launch { + snackbarHostState.showSnackbar(message = it) + } + } + } +} + +@Composable +fun DetailScreenContent( + detailScreenViewModel: DetailScreenViewModel, + paddingValues: PaddingValues, + errorCallback: (String) -> Unit + +){ + val state = detailScreenViewModel.detailScreenState.collectAsState() + LaunchedEffect(state.value.error) { + state.value.error?.let(errorCallback) + } + Column( + modifier = Modifier + .padding(paddingValues) + .fillMaxSize() + .background(color = Neutral_20) + , + verticalArrangement = Arrangement.Center + ) { + Spacer(modifier = Modifier.height(16.dp)) + AsyncImage( + modifier = Modifier + .size(350.dp, 350.dp) + .align(Alignment.CenterHorizontally) + , + model = ImageRequest + .Builder(LocalContext.current) + .data(state.value.furnitureResponse.url) + .crossfade(true) + .build(), + placeholder = painterResource(R.drawable.images), + contentScale = ContentScale.FillWidth, + contentDescription = null + ) + Spacer(modifier = Modifier.height(16.dp)) + Column( + modifier = Modifier + .fillMaxWidth() + .background(Color.White, shape = RoundedCornerShape( + topStart = 16.dp, + topEnd = 16.dp) + ) + .weight(1f) + .padding(horizontal = 20.dp, vertical = 10.dp) + ) { + Text( + text = state.value.furnitureResponse.name, + style = TextStyle( + color = com.example.furintiture.ui.theme.Text, + fontFamily = FontFamily(Font(R.font.manrope)), + fontSize = 28.sp + ) + ) + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.Start, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "${state.value.furnitureResponse.price} ₽", + style = TextStyle( + color = com.example.furintiture.ui.theme.Text, + fontFamily = FontFamily(Font(R.font.manrope)), + fontSize = 40.sp, + fontWeight = FontWeight.Bold + ) + ) + Spacer(modifier = Modifier.width(8.dp)) + Text( + text = "${state.value.furnitureResponse.sale.multiply(BigDecimal(100)).toInt()}% OFF", + modifier = Modifier + .background( + color = Color.Red, + shape = RoundedCornerShape(10.dp) + ) + .padding( + vertical = 4.dp, + horizontal = 6.dp + ), + style = TextStyle( + color = Color.White, + fontWeight = FontWeight.SemiBold, + fontFamily = FontFamily(Font(R.font.manrope)), + fontSize = 20.sp + ) + ) + } + Text( + text = state.value.furnitureResponse.description, + style = TextStyle( + color = com.example.furintiture.ui.theme.Text, + fontWeight = FontWeight.Normal, + fontFamily = FontFamily(Font(R.font.manrope)), + fontSize = 18.sp + ) + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/ui/screen/detail/DetailScreenState.kt b/app/src/main/java/com/example/furintiture/ui/screen/detail/DetailScreenState.kt new file mode 100644 index 0000000..caca45a --- /dev/null +++ b/app/src/main/java/com/example/furintiture/ui/screen/detail/DetailScreenState.kt @@ -0,0 +1,22 @@ +package com.example.furintiture.ui.screen.detail + +import com.example.furintiture.model.response.FurnitureCategoryResponse +import com.example.furintiture.model.response.FurnitureResponse +import java.math.BigDecimal + +data class DetailScreenState( + val furnitureResponse: FurnitureResponse = FurnitureResponse( + id = 1, + name = "Стул", + price = BigDecimal("1000.5"), + description = "Этот стул выполнен из натурального дуба, что придает ему прочность и долговечность. Спинка украшена резными узорами, напоминающими старинные европейские интерьеры. Сиденье обито мягкой тканью с антикварным орнаментом, обеспечивая комфорт во время сидения. Ножки слегка изогнуты, что добавляет изделию элегантности. Такой стул идеально впишется в гостиную или столовую в классическом стиле, создавая атмосферу уюта и респектабельности.", + sale = BigDecimal("0.40"), + url = "https://laurendanger.com/wp-content/uploads/sites/33/2024/10/IMG_3826.jpeg", + category = FurnitureCategoryResponse( + id = 1, + name = "!@3" + ), + shopCategories = emptyList() + ), + var error: String? = null +) diff --git a/app/src/main/java/com/example/furintiture/ui/screen/detail/DetailScreenViewModel.kt b/app/src/main/java/com/example/furintiture/ui/screen/detail/DetailScreenViewModel.kt new file mode 100644 index 0000000..ced33a5 --- /dev/null +++ b/app/src/main/java/com/example/furintiture/ui/screen/detail/DetailScreenViewModel.kt @@ -0,0 +1,56 @@ +package com.example.furintiture.ui.screen.detail + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.example.furintiture.data.RetrofitClient +import com.example.furintiture.model.request.AddToCartRequest +import com.example.furintiture.model.request.ChangeCountFromCartRequest +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import java.util.UUID + +class DetailScreenViewModel(private val furnitureId: Long, private val uuidUser: String): ViewModel() { + private val _detailScreenState = MutableStateFlow(DetailScreenState()) + val detailScreenState = _detailScreenState.asStateFlow() + init { + init() + } + + fun addToCart(){ + viewModelScope.launch { + try { + RetrofitClient.api.addToCartByUuid( + AddToCartRequest( + uuid = UUID.fromString(uuidUser), + furnitureId = furnitureId, + count = 1 + ) + ) + _detailScreenState.update { + it.copy(error = "Успешно добавлено") + } + } + catch (e: Exception){ + _detailScreenState.update { + it.copy(error = e.message) + } + } + } + } + + private fun init(){ + viewModelScope.launch { + try { + val result = RetrofitClient.api.getFurnitureById(furnitureId) + _detailScreenState.update { + it.copy(furnitureResponse = result) + } + } + catch (e: Exception){ + println(e.message) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/ui/screen/furniture/FurnitureScreen.kt b/app/src/main/java/com/example/furintiture/ui/screen/furniture/FurnitureScreen.kt new file mode 100644 index 0000000..2b7b83d --- /dev/null +++ b/app/src/main/java/com/example/furintiture/ui/screen/furniture/FurnitureScreen.kt @@ -0,0 +1,109 @@ +package com.example.furintiture.ui.screen.furniture + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.fillMaxSize +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.material.icons.Icons +import androidx.compose.material.icons.filled.Close +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.Scaffold +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.TopAppBar +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.lifecycle.viewmodel.compose.viewModel +import com.example.furintiture.ui.common.FurnitureCard +import com.example.furintiture.ui.screen.Detail +import kotlinx.coroutines.launch + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun FurnitureScreen( + uuid: String, + onClosePressed: () -> Unit, + onNavigateToDetail: (Detail) -> Unit +) { + val snackbarHostState = remember { SnackbarHostState() } + val coroutineScope = rememberCoroutineScope() + val viewModel = viewModel { + FurnitureScreenViewModel() + } + Scaffold( + snackbarHost = { + SnackbarHost(hostState = snackbarHostState) + }, + topBar = { + TopAppBar( + title = {}, + navigationIcon = { + IconButton ( + onClick = { + onClosePressed() + } + ){ + Icon( + imageVector = Icons.Default.Close, + contentDescription = null + ) + } + } + ) + }, + ) { paddingValues -> + FurnitureContent(uuid, viewModel, paddingValues, onNavigateToDetail){ + coroutineScope.launch { + snackbarHostState.showSnackbar(message = it) + } + } + } +} + +@Composable +fun FurnitureContent( + uuid: String, + furnitureScreenViewModel: FurnitureScreenViewModel, + paddingValues: PaddingValues, + onNavigateToDetail: (Detail) -> Unit, + onErrorCallback: (String) -> Unit +){ + val state = furnitureScreenViewModel.furnitureScreenState.collectAsState() + + LaunchedEffect(state.value.error) { + state.value.error?.let(onErrorCallback) + state.value.error = null + } + + Column( + modifier = Modifier + .padding(paddingValues) + .fillMaxSize() + .padding(horizontal = 16.dp) + ) { + LazyVerticalGrid ( + modifier = Modifier + .fillMaxSize(), + horizontalArrangement = Arrangement.spacedBy(8.dp), + verticalArrangement = Arrangement.spacedBy(8.dp), + columns = GridCells.Adaptive(minSize = 130.dp) + ){ + items(state.value.furnitureList){ it -> + FurnitureCard(it) { + onNavigateToDetail(Detail(uuid = uuid, furnitureId = it.id)) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/ui/screen/furniture/FurnitureScreenState.kt b/app/src/main/java/com/example/furintiture/ui/screen/furniture/FurnitureScreenState.kt new file mode 100644 index 0000000..3625d35 --- /dev/null +++ b/app/src/main/java/com/example/furintiture/ui/screen/furniture/FurnitureScreenState.kt @@ -0,0 +1,8 @@ +package com.example.furintiture.ui.screen.furniture + +import com.example.furintiture.model.response.FurnitureResponse + +data class FurnitureScreenState( + var furnitureList: List = emptyList(), + var error: String? = null +) \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/ui/screen/furniture/FurnitureScreenViewModel.kt b/app/src/main/java/com/example/furintiture/ui/screen/furniture/FurnitureScreenViewModel.kt new file mode 100644 index 0000000..fde52b3 --- /dev/null +++ b/app/src/main/java/com/example/furintiture/ui/screen/furniture/FurnitureScreenViewModel.kt @@ -0,0 +1,34 @@ +package com.example.furintiture.ui.screen.furniture + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.example.furintiture.data.RetrofitClient +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch + +class FurnitureScreenViewModel: ViewModel(){ + private val _furnitureScreenState = MutableStateFlow(FurnitureScreenState()) + val furnitureScreenState = _furnitureScreenState.asStateFlow() + + init { + try { + init() + } + catch (e: Exception){ + _furnitureScreenState.update { + it.copy(error = e.message) + } + } + } + private fun init(){ + viewModelScope.launch { + val result = RetrofitClient.api.getAllFurniture() + _furnitureScreenState.update { + it.copy(furnitureList = result) + } + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/ui/screen/login/LoginScreen.kt b/app/src/main/java/com/example/furintiture/ui/screen/login/LoginScreen.kt new file mode 100644 index 0000000..4210034 --- /dev/null +++ b/app/src/main/java/com/example/furintiture/ui/screen/login/LoginScreen.kt @@ -0,0 +1,146 @@ +package com.example.furintiture.ui.screen.login + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Scaffold +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.Font +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.lifecycle.viewmodel.compose.viewModel +import com.example.furintiture.R +import com.example.furintiture.data.DataStoreSettings +import com.example.furintiture.ui.common.FurnitureButton +import com.example.furintiture.ui.common.FurniturePasswordTextField +import com.example.furintiture.ui.common.FurnitureTextField +import com.example.furintiture.ui.theme.Neutral_20 +import com.example.furintiture.ui.theme.Neutral_70 +import com.example.furintiture.ui.theme.Primary +import kotlinx.coroutines.launch + +@Composable +fun LoginScreen( + dataStoreSettings: DataStoreSettings, + onNavigateToRegistration: () -> Unit +) { + val snackbarHostState = remember { SnackbarHostState() } + val coroutineScope = rememberCoroutineScope() + val viewModel = viewModel { LoginScreenViewModel(dataStoreSettings) } + Scaffold( + snackbarHost = { + SnackbarHost(hostState = snackbarHostState) + }, + contentColor = Neutral_20 + ) { paddingValues -> + LoginScreenContent(viewModel, paddingValues, onNavigateToRegistration){ + coroutineScope.launch { + snackbarHostState.showSnackbar(message = it) + } + } + } +} + +@Composable +fun LoginScreenContent( + loginScreenViewModel: LoginScreenViewModel, + paddingValues: PaddingValues, + onNavigateToRegistration: () -> Unit, + errorCallback: (String) -> Unit +){ + val state = loginScreenViewModel.loginScreenState.collectAsState() + + LaunchedEffect(state.value.error) { + state.value.error?.let { + errorCallback(it) + } + state.value.error = null + } + + Column( + modifier = Modifier + .padding(paddingValues) + .fillMaxSize() + .padding(horizontal = 16.dp) + ) { + + Spacer(modifier = Modifier.height(24.dp)) + Text( + text = "C возвращением!", + style = TextStyle( + fontSize = 32.sp, + lineHeight = 20.sp, + fontFamily = FontFamily(Font(R.font.manrope_extrabold)) + ), + color = Color.Black + ) + Spacer(modifier = Modifier.height(8.dp)) + Text( + text = "Введите свой email, чтобы начать делать покупки и получать выгодные предложения уже сегодня!", + style = TextStyle( + fontSize = 16.sp, + lineHeight = 20.sp, + fontFamily = FontFamily(Font(R.font.manrope)) + ), + color = Neutral_70 + ) + Spacer(modifier = Modifier.height(32.dp)) + FurnitureTextField( + value = state.value.request.email, + onValueChange = { loginScreenViewModel.setEmail(it) }, + textLabel = "Email", + leadingResourceId = R.drawable.mail_icon + ) + Spacer(modifier = Modifier.height(16.dp)) + FurniturePasswordTextField( + value = state.value.request.password, + onValueChange = { loginScreenViewModel.setPassword(it) } + ) + Spacer(modifier = Modifier.height(16.dp)) + Text( + text = "Забыли пароль?", + style = TextStyle( + fontSize = 16.sp, + lineHeight = 20.sp, + fontFamily = FontFamily(Font(R.font.manrope)) + ), + color = Primary + ) + Spacer(modifier = Modifier.height(16.dp)) + FurnitureButton( + text = "Войти" + ) { + loginScreenViewModel.login() + } + Spacer(modifier = Modifier.height(16.dp)) + Text( + modifier = Modifier.clickable { + onNavigateToRegistration() + }, + text = "У вас нет учетной записи? Зарегистрируйтесь", + style = TextStyle( + fontSize = 16.sp, + lineHeight = 20.sp, + fontFamily = FontFamily(Font(R.font.manrope)) + ), + color = Neutral_70 + ) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/ui/screen/login/LoginScreenState.kt b/app/src/main/java/com/example/furintiture/ui/screen/login/LoginScreenState.kt new file mode 100644 index 0000000..4cd59d2 --- /dev/null +++ b/app/src/main/java/com/example/furintiture/ui/screen/login/LoginScreenState.kt @@ -0,0 +1,10 @@ +package com.example.furintiture.ui.screen.login + +import android.util.Log +import androidx.compose.runtime.Composable +import com.example.furintiture.model.request.LoginRequest + +data class LoginScreenState( + var request: LoginRequest = LoginRequest(email = "", password = ""), + var error: String? = null +) diff --git a/app/src/main/java/com/example/furintiture/ui/screen/login/LoginScreenViewModel.kt b/app/src/main/java/com/example/furintiture/ui/screen/login/LoginScreenViewModel.kt new file mode 100644 index 0000000..b6608ae --- /dev/null +++ b/app/src/main/java/com/example/furintiture/ui/screen/login/LoginScreenViewModel.kt @@ -0,0 +1,55 @@ +package com.example.furintiture.ui.screen.login + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.example.furintiture.data.DataStoreSettings +import com.example.furintiture.data.RetrofitClient +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch + +class LoginScreenViewModel(private val dataStoreSettings: DataStoreSettings): ViewModel() { + private val _loginScreenState = MutableStateFlow(LoginScreenState()) + val loginScreenState = _loginScreenState.asStateFlow() + + fun setPassword(password: String){ + _loginScreenState.update { + it.copy(request = it.request.copy(password = password)) + } + } + fun setEmail(email: String){ + _loginScreenState.update { + it.copy(request = it.request.copy(email = email)) + } + } + fun login(){ + if(!validate()) return + viewModelScope.launch { + try { + val result = RetrofitClient.api.auth(loginScreenState.value.request) + dataStoreSettings.setUuid(result.userUuid) + } + catch (e: Exception){ + _loginScreenState.update { + it.copy(error = e.message) + } + } + } + } + private fun validate(): Boolean{ + if (_loginScreenState.value.request.email.isEmpty()){ + _loginScreenState.update { + it.copy(error = "Введите email") + } + return false + } + if (_loginScreenState.value.request.password.isEmpty()){ + _loginScreenState.update { + it.copy(error = "Введите password") + } + return false + } + return true + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/ui/screen/main/MainScreen.kt b/app/src/main/java/com/example/furintiture/ui/screen/main/MainScreen.kt new file mode 100644 index 0000000..b8203c0 --- /dev/null +++ b/app/src/main/java/com/example/furintiture/ui/screen/main/MainScreen.kt @@ -0,0 +1,246 @@ +package com.example.furintiture.ui.screen.main + +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.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.size +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.pager.HorizontalPager +import androidx.compose.foundation.pager.rememberPagerState +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.Scaffold +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.input.pointer.motionEventSpy +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.Font +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.lifecycle.viewmodel.compose.viewModel +import coil3.compose.AsyncImage +import coil3.request.ImageRequest +import coil3.request.crossfade +import com.example.furintiture.R +import com.example.furintiture.ui.screen.bottomsheet.FurnitureAddressBottomSheet +import com.example.furintiture.ui.common.FurnitureHorizontalList +import com.example.furintiture.ui.screen.Detail +import com.example.furintiture.ui.screen.Furniture +import com.example.furintiture.ui.screen.bottomsheet.FurnitureAddressBottomSheetViewModel +import com.example.furintiture.ui.theme.Neutral_20 +import com.example.furintiture.ui.theme.Neutral_40 +import com.example.furintiture.ui.theme.Primary +import com.example.furintiture.ui.theme.gradientColors +import kotlinx.coroutines.launch + +@Composable +fun MainScreen( + uuid: String, + onNavigateToFurniture: (Furniture) -> Unit, + onNavigateToDetail: (Detail) -> Unit, +) { + val snackbarHostState = remember { SnackbarHostState() } + val coroutineScope = rememberCoroutineScope() + val viewModel: MainScreenViewModel = viewModel { + MainScreenViewModel(uuid) + } + Scaffold( + snackbarHost = { + SnackbarHost(hostState = snackbarHostState) + }, + contentColor = Neutral_20 + ) { paddingValues -> + MainScreenContent(uuid, viewModel, paddingValues, onNavigateToFurniture, onNavigateToDetail ){ + coroutineScope.launch { + snackbarHostState.showSnackbar(message = it) + } + } + } +} + +@Composable +fun MainScreenContent( + userUuid: String, + mainScreenViewModel: MainScreenViewModel, + paddingValues: PaddingValues, + onNavigateToFurniture: (Furniture) -> Unit, + onNavigateToDetail: (Detail) -> Unit, + errorCallback: (String) -> Unit, +) { + val state = mainScreenViewModel.mainScreenState.collectAsState() + val pagerState = rememberPagerState(pageCount = {state.value.sales.size}) + val showBottomSheet = remember { mutableStateOf(false) } + val viewModel: FurnitureAddressBottomSheetViewModel = viewModel() + LaunchedEffect(state.value.error) { + state.value.error?.let { + errorCallback(it) + } + state.value.error = null + } + + Column( + modifier = Modifier + .padding(paddingValues) + .fillMaxSize() + .padding(bottom = 100.dp,) + ) { + Spacer(modifier = Modifier.height(16.dp)) + state.value.profile?.let { + val text = if(it.address != null) "Доставим по адресу: ${it.address.address}" else "Выберите адрес доставки" + Text( + modifier = + Modifier.padding(horizontal = 16.dp) + .clickable { + showBottomSheet.value = true + } + , + text = text, + overflow = TextOverflow.Ellipsis, + maxLines = 1, + style = TextStyle( + fontSize = 16.sp, + lineHeight = 20.sp, + fontFamily = FontFamily(Font(R.font.manrope_extrabold)), + color = com.example.furintiture.ui.theme.Text + ) + ) + Spacer(modifier = Modifier.height(16.dp)) + } + if(showBottomSheet.value){ + FurnitureAddressBottomSheet( + state.value.profile?.address, viewModel + ) { requestAddress -> + mainScreenViewModel.addAddress(requestAddress) + showBottomSheet.value = false + } + } + HorizontalPager(state = pagerState) { page -> + Box( + modifier = Modifier + .fillMaxWidth() + .height(200.dp) + .padding(top = 20.dp) + , + ) { + AsyncImage( + modifier = Modifier + .fillMaxSize() + , + model = ImageRequest + .Builder(LocalContext.current) + .data(state.value.sales[page].url) + .crossfade(true) + .build(), + placeholder = painterResource(R.drawable.images), + contentScale = ContentScale.FillWidth, + contentDescription = null + ) + Box( + modifier = Modifier + .fillMaxSize() + .background(Brush.horizontalGradient(colorStops = gradientColors))) + Column( + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.Start, + modifier = Modifier + .padding(10.dp) + ) { + Text( + text = state.value.sales[page].name, + style = TextStyle( + fontSize = 16.sp, + lineHeight = 20.sp, + fontFamily = FontFamily(Font(R.font.manrope_extrabold)) + ), + color = Neutral_20 + ) + Button( + onClick = {}, + colors = ButtonDefaults.buttonColors().copy( + contentColor = Color.White, + disabledContentColor = Color.White, + containerColor = Color.White, + disabledContainerColor = Color.White + ) + ) { + Text( + "Купить сейчас", + style = TextStyle( + fontSize = 16.sp, + lineHeight = 20.sp, + fontFamily = FontFamily(Font(R.font.manrope)), + fontWeight = FontWeight.Bold + ), + color = Primary + ) + } + } + + } + + } + Spacer(modifier = Modifier.height(16.dp)) + Row( + modifier = Modifier + .wrapContentHeight() + .fillMaxWidth() + .padding(8.dp), + horizontalArrangement = Arrangement.Center + ) { + repeat(pagerState.pageCount) { iteration -> + val color = if (pagerState.currentPage == iteration) Primary else Neutral_40 + Box( + modifier = Modifier + .padding(2.dp) + .clip(CircleShape) + .background(color) + .size(12.dp) + ) + } + } + Spacer(modifier = Modifier.height(16.dp)) + LazyColumn( + modifier = Modifier.fillMaxWidth(), + contentPadding = PaddingValues(16.dp) + ) { + items(state.value.shopCategories.size){ item -> + FurnitureHorizontalList( + categoryName = state.value.shopCategories[item].name, + categoryFurnitureList = state.value.shopCategories[item].furnitureList, + onAllFurnitureClick = { onNavigateToFurniture(Furniture(uuid = userUuid)) } + ){ + onNavigateToDetail(Detail(furnitureId = it.id, uuid = userUuid)) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/ui/screen/main/MainScreenState.kt b/app/src/main/java/com/example/furintiture/ui/screen/main/MainScreenState.kt new file mode 100644 index 0000000..3d7fdc3 --- /dev/null +++ b/app/src/main/java/com/example/furintiture/ui/screen/main/MainScreenState.kt @@ -0,0 +1,16 @@ +package com.example.furintiture.ui.screen.main + +import com.example.furintiture.model.response.AllShopCategoryResponse +import com.example.furintiture.model.response.FurnitureResponse +import com.example.furintiture.model.response.SaleResponse +import com.example.furintiture.model.response.ShopCategoryResponse +import com.example.furintiture.model.response.UserResponse + +data class MainScreenState( + var sales: List = emptyList(), + var shopCategories: List = emptyList(), + var addresses: List = emptyList(), + var cartItems: List = emptyList(), + var error: String? = null, + val profile: UserResponse? = null +) \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/ui/screen/main/MainScreenViewModel.kt b/app/src/main/java/com/example/furintiture/ui/screen/main/MainScreenViewModel.kt new file mode 100644 index 0000000..89b006f --- /dev/null +++ b/app/src/main/java/com/example/furintiture/ui/screen/main/MainScreenViewModel.kt @@ -0,0 +1,85 @@ +package com.example.furintiture.ui.screen.main + +import androidx.compose.runtime.saveable.autoSaver +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.example.furintiture.data.RetrofitClient +import com.example.furintiture.model.request.AddAddressRequest +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import java.util.UUID + +class MainScreenViewModel(private val uuid: String): ViewModel() { + private val _mainScreenState = MutableStateFlow(MainScreenState()) + val mainScreenState = _mainScreenState.asStateFlow() + + init { + try { + init() + } + catch (e: Exception){ + _mainScreenState.update { + it.copy(error = e.message) + } + } + } + + private fun init(){ + viewModelScope.launch { + val sales = RetrofitClient.api.getAllSales() + _mainScreenState.update { + it.copy(sales = sales) + } + val allCategory = RetrofitClient.api.getAllShopCategory() + _mainScreenState.update { + it.copy(shopCategories = allCategory) + } + val profile = RetrofitClient.api.getProfileByUuid(UUID.fromString(uuid)) + _mainScreenState.update { + it.copy(profile = profile) + } + } + } + + fun addAddress(addressRequest: AddAddressRequest){ + viewModelScope.launch { + if (!validate(addressRequest)) return@launch + addressRequest.entrance = 10 + try { + RetrofitClient.api.addAddressByUuid(uuid = UUID.fromString(uuid), addressRequest) + val profile = RetrofitClient.api.getProfileByUuid(UUID.fromString(uuid)) + _mainScreenState.update { + it.copy(profile = profile) + } + } + catch (e: Exception){ + _mainScreenState.update { + it.copy(error = e.message) + } + } + } + } + private fun validate(addressRequest: AddAddressRequest): Boolean{ + if (addressRequest.address.isEmpty()){ + _mainScreenState.update { + it.copy(error = "Адрес не может быть пустым") + } + return false + } + if(addressRequest.apartment == null){ + _mainScreenState.update { + it.copy(error = "Укажите квартиру") + } + return false + } + if(addressRequest.floor == null){ + _mainScreenState.update { + it.copy(error = "Укажите этаж") + } + return false + } + return true + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/ui/screen/order/OrderScreen.kt b/app/src/main/java/com/example/furintiture/ui/screen/order/OrderScreen.kt new file mode 100644 index 0000000..ec1f1d4 --- /dev/null +++ b/app/src/main/java/com/example/furintiture/ui/screen/order/OrderScreen.kt @@ -0,0 +1,84 @@ +package com.example.furintiture.ui.screen.order + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material3.Scaffold +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.lifecycle.viewmodel.compose.viewModel +import com.example.furintiture.ui.common.FurnitureOrderCard +import com.example.furintiture.ui.screen.cart.CartScreenContent +import com.example.furintiture.ui.screen.cart.CartScreenViewModel +import com.example.furintiture.ui.theme.Neutral_20 +import kotlinx.coroutines.launch +import java.math.BigDecimal + +@Composable +fun OrderScreen( + uuid: String +) { + val snackbarHostState = remember { SnackbarHostState() } + val coroutineScope = rememberCoroutineScope() + val viewModel: OrderScreenViewModel = viewModel { OrderScreenViewModel(uuid) } + Scaffold( + snackbarHost = { + SnackbarHost(hostState = snackbarHostState) + }, + contentColor = Neutral_20 + ) { paddingValues -> + OrderScreenContent(viewModel, paddingValues){ + coroutineScope.launch { + snackbarHostState.showSnackbar(it) + } + } + } +} + +@Composable +fun OrderScreenContent( + viewModel: OrderScreenViewModel, + paddingValues: PaddingValues, + onErrorCallback : (String) -> Unit +) { + val state = viewModel.orderScreenState.collectAsState() + + + LaunchedEffect(state.value.error) { + state.value.error?.let(onErrorCallback) + state.value.error = null + } + Column( + modifier = Modifier + .padding(paddingValues) + .fillMaxSize() + .padding(horizontal = 16.dp) + .padding(bottom = 100.dp) + + + ) { + Spacer(modifier = Modifier.height(16.dp)) + LazyColumn( + modifier = Modifier.fillMaxSize(), + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + items(state.value.orders){ + FurnitureOrderCard(it) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/ui/screen/order/OrderScreenState.kt b/app/src/main/java/com/example/furintiture/ui/screen/order/OrderScreenState.kt new file mode 100644 index 0000000..be73ba4 --- /dev/null +++ b/app/src/main/java/com/example/furintiture/ui/screen/order/OrderScreenState.kt @@ -0,0 +1,8 @@ +package com.example.furintiture.ui.screen.order + +import com.example.furintiture.model.response.OrderResponse + +data class OrderScreenState( + var orders: List = emptyList(), + var error: String? = null +) \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/ui/screen/order/OrderScreenViewModel.kt b/app/src/main/java/com/example/furintiture/ui/screen/order/OrderScreenViewModel.kt new file mode 100644 index 0000000..230f2c6 --- /dev/null +++ b/app/src/main/java/com/example/furintiture/ui/screen/order/OrderScreenViewModel.kt @@ -0,0 +1,30 @@ +package com.example.furintiture.ui.screen.order + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.example.furintiture.data.RetrofitClient +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import java.util.UUID + +class OrderScreenViewModel(private val uuid: String): ViewModel() { + private val _orderScreenState = MutableStateFlow(OrderScreenState()) + val orderScreenState = _orderScreenState.asStateFlow() + + init { + try{ + viewModelScope.launch { + _orderScreenState.update { + it.copy(orders = RetrofitClient.api.getOrdersByUuid(UUID.fromString(uuid))) + } + } + } + catch (e: Exception){ + _orderScreenState.update { + it.copy(error = e.message) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/ui/screen/registration/RegistrationScreen.kt b/app/src/main/java/com/example/furintiture/ui/screen/registration/RegistrationScreen.kt new file mode 100644 index 0000000..e89c68e --- /dev/null +++ b/app/src/main/java/com/example/furintiture/ui/screen/registration/RegistrationScreen.kt @@ -0,0 +1,160 @@ +package com.example.furintiture.ui.screen.registration + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Scaffold +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.Font +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.lifecycle.viewmodel.compose.viewModel +import com.example.furintiture.R +import com.example.furintiture.data.DataStoreSettings +import com.example.furintiture.ui.common.FurnitureButton +import com.example.furintiture.ui.common.FurniturePasswordTextField +import com.example.furintiture.ui.common.FurnitureTextField +import com.example.furintiture.ui.screen.login.LoginScreenContent +import com.example.furintiture.ui.screen.login.LoginScreenViewModel +import com.example.furintiture.ui.theme.Neutral_20 +import com.example.furintiture.ui.theme.Neutral_70 +import com.example.furintiture.ui.theme.Primary +import kotlinx.coroutines.launch + +@Composable +fun RegistrationScreen( + dataStoreSettings: DataStoreSettings, + onNavigateToLogin: () -> Unit +) { + val snackbarHostState = remember { SnackbarHostState() } + val coroutineScope = rememberCoroutineScope() + val viewModel: RegistrationScreenViewModel = viewModel { RegistrationScreenViewModel(dataStoreSettings) } + Scaffold( + snackbarHost = { + SnackbarHost(hostState = snackbarHostState) + }, + contentColor = Neutral_20 + ) { paddingValues -> + RegisterScreenContent(viewModel, paddingValues, onNavigateToLogin){ + coroutineScope.launch { + snackbarHostState.showSnackbar(message = it) + } + } + } +} + +@Composable +fun RegisterScreenContent( + registrationScreenViewModel: RegistrationScreenViewModel, + paddingValues: PaddingValues, + onNavigateToLogin: () -> Unit, + errorCallback: (String) -> Unit +){ + val state = registrationScreenViewModel.registrationScreenState.collectAsState() + + LaunchedEffect(state.value.error) { + state.value.error?.let { + errorCallback(it) + } + state.value.error = null + } + + Column( + modifier = Modifier + .padding(paddingValues) + .fillMaxSize() + .padding(horizontal = 16.dp) + ) { + + Spacer(modifier = Modifier.height(24.dp)) + Text( + text = "Создать аккаунт", + style = TextStyle( + fontSize = 32.sp, + lineHeight = 20.sp, + fontFamily = FontFamily(Font(R.font.manrope_extrabold)) + ), + color = Color.Black + ) + Spacer(modifier = Modifier.height(8.dp)) + Text( + text = "Введите свои данные ниже, чтобы начать совершать покупки.", + style = TextStyle( + fontSize = 16.sp, + lineHeight = 20.sp, + fontFamily = FontFamily(Font(R.font.manrope)) + ), + color = Neutral_70 + ) + Spacer(modifier = Modifier.height(32.dp)) + FurnitureTextField( + value = state.value.request.firstName, + onValueChange = { registrationScreenViewModel.setFirstName(it) }, + textLabel = "Имя", + leadingResourceId = R.drawable.user_icon + ) + Spacer(modifier = Modifier.height(16.dp)) + FurnitureTextField( + value = state.value.request.lastName, + onValueChange = { registrationScreenViewModel.setLastName(it) }, + textLabel = "Фамиля", + leadingResourceId = R.drawable.user_icon + ) + Spacer(modifier = Modifier.height(16.dp)) + FurnitureTextField( + value = state.value.request.email, + onValueChange = { registrationScreenViewModel.setEmail(it) }, + textLabel = "Email", + leadingResourceId = R.drawable.mail_icon + ) + Spacer(modifier = Modifier.height(16.dp)) + FurniturePasswordTextField( + value = state.value.request.password, + onValueChange = { registrationScreenViewModel.setPassword(it) } + ) + Spacer(modifier = Modifier.height(16.dp)) + Text( + text = "Нажимая кнопку Зарегистрироваться, вы подтверждаете, что ознакомились и согласились с нашими Условиями использования и Политикой конфиденциальности.", + style = TextStyle( + fontSize = 16.sp, + lineHeight = 20.sp, + fontFamily = FontFamily(Font(R.font.manrope)) + ), + color = Primary + ) + Spacer(modifier = Modifier.height(16.dp)) + FurnitureButton( + text = "Зарегистрироваться" + ) { + registrationScreenViewModel.register() + } + Spacer(modifier = Modifier.height(16.dp)) + Text( + modifier = Modifier.clickable { + onNavigateToLogin() + }, + text = "Войти", + style = TextStyle( + fontSize = 16.sp, + lineHeight = 20.sp, + fontFamily = FontFamily(Font(R.font.manrope)) + ), + color = Neutral_70 + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/ui/screen/registration/RegistrationScreenState.kt b/app/src/main/java/com/example/furintiture/ui/screen/registration/RegistrationScreenState.kt new file mode 100644 index 0000000..442bcbc --- /dev/null +++ b/app/src/main/java/com/example/furintiture/ui/screen/registration/RegistrationScreenState.kt @@ -0,0 +1,13 @@ +package com.example.furintiture.ui.screen.registration + +import com.example.furintiture.model.request.RegisterRequest + +data class RegistrationScreenState( + var error: String? = null, + var request: RegisterRequest = RegisterRequest( + firstName = "", + lastName = "", + email = "", + password = "" + ) +) \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/ui/screen/registration/RegistrationScreenViewModel.kt b/app/src/main/java/com/example/furintiture/ui/screen/registration/RegistrationScreenViewModel.kt new file mode 100644 index 0000000..7b5c562 --- /dev/null +++ b/app/src/main/java/com/example/furintiture/ui/screen/registration/RegistrationScreenViewModel.kt @@ -0,0 +1,79 @@ +package com.example.furintiture.ui.screen.registration + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.example.furintiture.data.DataStoreSettings +import com.example.furintiture.data.RetrofitClient +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch + +class RegistrationScreenViewModel(private val dataStoreSettings: DataStoreSettings): ViewModel() { + private val _registrationScreenState = MutableStateFlow(RegistrationScreenState()) + val registrationScreenState = _registrationScreenState.asStateFlow() + + fun setPassword(password: String){ + _registrationScreenState.update { + it.copy(request = it.request.copy(password = password)) + } + } + fun setEmail(email: String){ + _registrationScreenState.update { + it.copy(request = it.request.copy(email = email)) + } + } + fun setLastName(lastName: String){ + _registrationScreenState.update { + it.copy(request = it.request.copy(lastName = lastName)) + } + } + fun setFirstName(firstName: String){ + _registrationScreenState.update { + it.copy(request = it.request.copy(firstName = firstName)) + } + } + + fun register(){ + if(!validate()) return + viewModelScope.launch { + try { + val result = RetrofitClient.api.register(_registrationScreenState.value.request) + dataStoreSettings.setUuid(result.userUuid) + } + catch (e: Exception){ + _registrationScreenState.update { + it.copy(error = e.message) + } + } + } + } + + private fun validate(): Boolean{ + if (_registrationScreenState.value.request.email.isEmpty()){ + _registrationScreenState.update { + it.copy(error = "Введите email") + } + return false + } + if (_registrationScreenState.value.request.password.isEmpty()){ + _registrationScreenState.update { + it.copy(error = "Введите password") + } + return false + } + if (_registrationScreenState.value.request.lastName.isEmpty()){ + _registrationScreenState.update { + it.copy(error = "Введите фамилию") + } + return false + } + if (_registrationScreenState.value.request.firstName.isEmpty()){ + _registrationScreenState.update { + it.copy(error = "Введите имя") + } + return false + } + return true + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/ui/screen/splashscreen/SplashScreen.kt b/app/src/main/java/com/example/furintiture/ui/screen/splashscreen/SplashScreen.kt new file mode 100644 index 0000000..31736ac --- /dev/null +++ b/app/src/main/java/com/example/furintiture/ui/screen/splashscreen/SplashScreen.kt @@ -0,0 +1,54 @@ +package com.example.furintiture.ui.screen.splashscreen + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Home +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.Font +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.example.furintiture.R +import com.example.furintiture.ui.theme.gradientColors + +@Composable +fun SplashScreen() { + Column( + modifier = Modifier + .fillMaxSize() + .background(Brush.verticalGradient(colorStops = gradientColors)) + , + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ) { + Icon( + modifier = Modifier.size(87.dp), + imageVector = Icons.Default.Home, + contentDescription = null, + tint = Color.White + ) + Text( + text = "Дом мечты", + style = TextStyle( + fontSize = 36.sp, + fontWeight = FontWeight.ExtraBold, + fontFamily = FontFamily(Font(R.font.manrope_extrabold)), + color = Color.White + ) + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/ui/theme/Color.kt b/app/src/main/java/com/example/furintiture/ui/theme/Color.kt new file mode 100644 index 0000000..9bc0dd7 --- /dev/null +++ b/app/src/main/java/com/example/furintiture/ui/theme/Color.kt @@ -0,0 +1,19 @@ +package com.example.furintiture.ui.theme + +import androidx.compose.ui.graphics.Color + +val Primary = Color(0xFF5C6B67) +val Secondary = Color(0xFFEBB65B) +val Text = Color(0xFF404040) +val Neutral_40 = Color(0xFFE0E0E0) +val Green_Linear= Color(0xFF156651) +val Neutral_70 = Color(0xFF757575) +val Neutral_90 = Color(0xFF404040) +val Neutral_20 = Color(0xFFF5F5F5) +val Neutral_10 = Color(0xFFFFFFFF) + +val gradientColors = arrayOf( + 0.0f to Color(0xFF156651).copy(alpha = 0.94f), + 0.47f to Color(0xFF156651).copy(alpha = 0.67f), + 1f to Color(0xFF156651).copy(alpha = 0f) +) diff --git a/app/src/main/java/com/example/furintiture/ui/theme/Theme.kt b/app/src/main/java/com/example/furintiture/ui/theme/Theme.kt new file mode 100644 index 0000000..428cb14 --- /dev/null +++ b/app/src/main/java/com/example/furintiture/ui/theme/Theme.kt @@ -0,0 +1,58 @@ +package com.example.furintiture.ui.theme + +import android.app.Activity +import android.os.Build +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext + +private val DarkColorScheme = darkColorScheme( + primary = Primary, + secondary = Secondary, + tertiary = Text +) + +private val LightColorScheme = lightColorScheme( + primary = Primary, + secondary = Secondary, + tertiary = Text + + /* Other default colors to override + background = Color(0xFFFFFBFE), + surface = Color(0xFFFFFBFE), + onPrimary = Color.White, + onSecondary = Color.White, + onTertiary = Color.White, + onBackground = Color(0xFF1C1B1F), + onSurface = Color(0xFF1C1B1F), + */ +) + +@Composable +fun FurintitureTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + // Dynamic color is available on Android 12+ + dynamicColor: Boolean = true, + content: @Composable () -> Unit +) { + val colorScheme = when { + dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { + val context = LocalContext.current + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + } + + darkTheme -> DarkColorScheme + else -> LightColorScheme + } + + MaterialTheme( + colorScheme = colorScheme, + typography = Typography, + content = content + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/example/furintiture/ui/theme/Type.kt b/app/src/main/java/com/example/furintiture/ui/theme/Type.kt new file mode 100644 index 0000000..57a8b73 --- /dev/null +++ b/app/src/main/java/com/example/furintiture/ui/theme/Type.kt @@ -0,0 +1,34 @@ +package com.example.furintiture.ui.theme + +import androidx.compose.material3.Typography +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp + +// Set of Material typography styles to start with +val Typography = Typography( + bodyLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.5.sp + ) + /* Other default text styles to override + titleLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 22.sp, + lineHeight = 28.sp, + letterSpacing = 0.sp + ), + labelSmall = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 11.sp, + lineHeight = 16.sp, + letterSpacing = 0.5.sp + ) + */ +) \ No newline at end of file diff --git a/app/src/main/res/drawable/fi_sr_eye_1.xml b/app/src/main/res/drawable/fi_sr_eye_1.xml new file mode 100644 index 0000000..ea4b396 --- /dev/null +++ b/app/src/main/res/drawable/fi_sr_eye_1.xml @@ -0,0 +1,16 @@ + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/images.png b/app/src/main/res/drawable/images.png new file mode 100644 index 0000000000000000000000000000000000000000..85ab7e29d53cc2ca4db34bf355c16894c09b98ac GIT binary patch literal 144 zcmeAS@N?(olHy`uVBq!ia0vp^4?&oN8Ax*GDtQ1Y<^Z1%*N%>kh}68zK(2?Ui(^Q| toVN!XfgFaz3w{R2Ki~*u1aU|KA9#-~VqgsCk6sMY<>~6@vd$@?2>{k_8SVf8 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/lock_icon.xml b/app/src/main/res/drawable/lock_icon.xml new file mode 100644 index 0000000..63af700 --- /dev/null +++ b/app/src/main/res/drawable/lock_icon.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/mail_icon.xml b/app/src/main/res/drawable/mail_icon.xml new file mode 100644 index 0000000..84c9598 --- /dev/null +++ b/app/src/main/res/drawable/mail_icon.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/user_icon.xml b/app/src/main/res/drawable/user_icon.xml new file mode 100644 index 0000000..0bd41e6 --- /dev/null +++ b/app/src/main/res/drawable/user_icon.xml @@ -0,0 +1,13 @@ + + + diff --git a/app/src/main/res/font/manrope.ttf b/app/src/main/res/font/manrope.ttf new file mode 100644 index 0000000000000000000000000000000000000000..f1795e015ffbf0c8d5a095ad5b1a4a1fb0243e46 GIT binary patch literal 94948 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

i-*ds9SUQ0#ue>s%x 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`K* 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 0000000000000000000000000000000000000000..c209e78ecd372343283f4157dcfd918ec5165bb3 GIT binary patch literal 1404 zcmV-?1%vuhNk&F=1pok7MM6+kP&il$0000G0000-002h-06|PpNX!5L00Dqw+t%{r zzW2vH!KF=w&cMnnN@{whkTw+#mAh0SV?YL=)3MimFYCWp#fpdtz~8$hD5VPuQgtcN zXl<@<#Cme5f5yr2h%@8TWh?)bSK`O z^Z@d={gn7J{iyxL_y_%J|L>ep{dUxUP8a{byupH&!UNR*OutO~0{*T4q5R6@ApLF! z5{w?Z150gC7#>(VHFJZ-^6O@PYp{t!jH(_Z*nzTK4 zkc{fLE4Q3|mA2`CWQ3{8;gxGizgM!zccbdQoOLZc8hThi-IhN90RFT|zlxh3Ty&VG z?Fe{#9RrRnxzsu|Lg2ddugg7k%>0JeD+{XZ7>Z~{=|M+sh1MF7~ zz>To~`~LVQe1nNoR-gEzkpe{Ak^7{{ZBk2i_<+`Bq<^GB!RYG+z)h;Y3+<{zlMUYd zrd*W4w&jZ0%kBuDZ1EW&KLpyR7r2=}fF2%0VwHM4pUs}ZI2egi#DRMYZPek*^H9YK zay4Iy3WXFG(F14xYsoDA|KXgGc5%2DhmQ1gFCkrgHBm!lXG8I5h*uf{rn48Z!_@ z4Bk6TJAB2CKYqPjiX&mWoW>OPFGd$wqroa($ne7EUK;#3VYkXaew%Kh^3OrMhtjYN?XEoY`tRPQsAkH-DSL^QqyN0>^ zmC>{#F14jz4GeW{pJoRpLFa_*GI{?T93^rX7SPQgT@LbLqpNA}<@2wH;q493)G=1Y z#-sCiRNX~qf3KgiFzB3I>4Z%AfS(3$`-aMIBU+6?gbgDb!)L~A)je+;fR0jWLL-Fu z4)P{c7{B4Hp91&%??2$v9iRSFnuckHUm}or9seH6 z>%NbT+5*@L5(I9j@06@(!{ZI?U0=pKn8uwIg&L{JV14+8s2hnvbRrU|hZCd}IJu7*;;ECgO%8_*W Kmw_-CKmY()leWbG literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 0000000000000000000000000000000000000000..b2dfe3d1ba5cf3ee31b3ecc1ced89044a1f3b7a9 GIT binary patch literal 2898 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 0000000000000000000000000000000000000000..4f0f1d64e58ba64d180ce43ee13bf9a17835fbca GIT binary patch literal 982 zcmV;{11bDcNk&G_0{{S5MM6+kP&il$0000G0000l001ul06|PpNU8t;00Dqo+t#w^ z^1csucXz7-Qrhzl9HuHB%l>&>1tG2^vb*E&k^T3$FG1eQZ51g$uv4V+kI`0<^1Z@N zk?Jjh$olyC%l>)Xq;7!>{iBj&BjJ`P&$fsCfpve_epJOBkTF?nu-B7D!hO=2ZR}

C%4 zc_9eOXvPbC4kzU8YowIA8cW~Uv|eB&yYwAObSwL2vY~UYI7NXPvf3b+c^?wcs~_t{ ze_m66-0)^{JdOMKPwjpQ@Sna!*?$wTZ~su*tNv7o!gXT!GRgivP}ec?5>l1!7<(rT zds|8x(qGc673zrvYIz;J23FG{9nHMnAuP}NpAED^laz3mAN1sy+NXK)!6v1FxQ;lh zOBLA>$~P3r4b*NcqR;y6pwyhZ3_PiDb|%n1gGjl3ZU}ujInlP{eks-#oA6>rh&g+!f`hv#_%JrgYPu z(U^&XLW^QX7F9Z*SRPpQl{B%x)_AMp^}_v~?j7 zapvHMKxSf*Mtyx8I}-<*UGn3)oHd(nn=)BZ`d$lDBwq_GL($_TPaS{UeevT(AJ`p0 z9%+hQb6z)U9qjbuXjg|dExCLjpS8$VKQ55VsIC%@{N5t{NsW)=hNGI`J=x97_kbz@ E0Of=7!TQj4N+cqN`nQhxvX7dAV-`K|Ub$-q+H-5I?Tx0g9jWxd@A|?POE8`3b8fO$T))xP* z(X?&brZw({`)WU&rdAs1iTa0x6F@PIxJ&&L|dpySV!ID|iUhjCcKz(@mE z!x@~W#3H<)4Ae(4eQJRk`Iz3<1)6^m)0b_4_TRZ+cz#eD3f8V;2r-1fE!F}W zEi0MEkTTx}8i1{`l_6vo0(Vuh0HD$I4SjZ=?^?k82R51bC)2D_{y8mi_?X^=U?2|F{Vr7s!k(AZC$O#ZMyavHhlQ7 zUR~QXuH~#o#>(b$u4?s~HLF*3IcF7023AlwAYudn0FV~|odGH^05AYPEfR)8p`i{n zwg3zPVp{+wOsxKc>)(pMupKF!Y2HoUqQ3|Yu|8lwR=?5zZuhG6J?H`bSNk_wPoM{u zSL{c@pY7+c2kck>`^q1^^gR0QB7Y?KUD{vz-uVX~;V-rW)PDcI)$_UjgVV?S?=oLR zf4}zz{#*R_{LkiJ#0RdQLNC^2Vp%JPEUvG9ra2BVZ92(p9h7Ka@!yf9(lj#}>+|u* z;^_?KWdzkM`6gqPo9;;r6&JEa)}R3X{(CWv?NvgLeOTq$cZXqf7|sPImi-7cS8DCN zGf;DVt3Am`>hH3{4-WzH43Ftx)SofNe^-#|0HdCo<+8Qs!}TZP{HH8~z5n`ExcHuT zDL1m&|DVpIy=xsLO>8k92HcmfSKhflQ0H~9=^-{#!I1g(;+44xw~=* zxvNz35vfsQE)@)Zsp*6_GjYD};Squ83<_?^SbALb{a`j<0Gn%6JY!zhp=Fg}Ga2|8 z52e1WU%^L1}15Ex0fF$e@eCT(()_P zvV?CA%#Sy08_U6VPt4EtmVQraWJX` zh=N|WQ>LgrvF~R&qOfB$!%D3cGv?;Xh_z$z7k&s4N)$WYf*k=|*jCEkO19{h_(%W4 zPuOqbCw`SeAX*R}UUsbVsgtuG?xs(#Ikx9`JZoQFz0n*7ZG@Fv@kZk`gzO$HoA9kN z8U5{-yY zvV{`&WKU2$mZeoBmiJrEdzUZAv1sRxpePdg1)F*X^Y)zp^Y*R;;z~vOv-z&)&G)JQ{m!C9cmziu1^nHA z`#`0c>@PnQ9CJKgC5NjJD8HM3|KC(g5nnCq$n0Gsu_DXk36@ql%npEye|?%RmG)

FJ$wK}0tWNB{uH;AM~i literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 0000000000000000000000000000000000000000..948a3070fe34c611c42c0d3ad3013a0dce358be0 GIT binary patch literal 1900 zcmV-y2b1_xNk&Fw2LJ$9MM6+kP&il$0000G0001A003VA06|PpNH75a00DqwTbm-~ zullQTcXxO9ki!OCRx^i?oR|n!<8G0=kI^!JSjFi-LL*`V;ET0H2IXfU0*i>o6o6Gy zRq6Ap5(_{XLdXcL-MzlN`ugSdZY_`jXhcENAu)N_0?GhF))9R;E`!bo9p?g?SRgw_ zEXHhFG$0{qYOqhdX<(wE4N@es3VIo$%il%6xP9gjiBri+2pI6aY4 zJbgh-Ud|V%3O!IcHKQx1FQH(_*TK;1>FQWbt^$K1zNn^cczkBs=QHCYZ8b&l!UV{K z{L0$KCf_&KR^}&2Fe|L&?1I7~pBENnCtCuH3sjcx6$c zwqkNkru);ie``q+_QI;IYLD9OV0ZxkuyBz|5<$1BH|vtey$> z5oto4=l-R-Aaq`Dk0}o9N0VrkqW_#;!u{!bJLDq%0092{Ghe=F;(kn} z+sQ@1=UlX30+2nWjkL$B^b!H2^QYO@iFc0{(-~yXj2TWz?VG{v`Jg zg}WyYnwGgn>{HFaG7E~pt=)sOO}*yd(UU-D(E&x{xKEl6OcU?pl)K%#U$dn1mDF19 zSw@l8G!GNFB3c3VVK0?uyqN&utT-D5%NM4g-3@Sii9tSXKtwce~uF zS&Jn746EW^wV~8zdQ1XC28~kXu8+Yo9p!<8h&(Q({J*4DBglPdpe4M_mD8AguZFn~ ztiuO~{6Bx?SfO~_ZV(GIboeR9~hAym{{fV|VM=77MxDrbW6`ujX z<3HF(>Zr;#*uCvC*bpoSr~C$h?_%nXps@A)=l_;({Fo#6Y1+Zv`!T5HB+)#^-Ud_; zBwftPN=d8Vx)*O1Mj+0oO=mZ+NVH*ptNDC-&zZ7Hwho6UQ#l-yNvc0Cm+2$$6YUk2D2t#vdZX-u3>-Be1u9gtTBiMB^xwWQ_rgvGpZ6(C@e23c!^K=>ai-Rqu zhqT`ZQof;9Bu!AD(i^PCbYV%yha9zuoKMp`U^z;3!+&d@Hud&_iy!O-$b9ZLcSRh? z)R|826w}TU!J#X6P%@Zh=La$I6zXa#h!B;{qfug}O%z@K{EZECu6zl)7CiNi%xti0 zB{OKfAj83~iJvmpTU|&q1^?^cIMn2RQ?jeSB95l}{DrEPTW{_gmU_pqTc)h@4T>~& zluq3)GM=xa(#^VU5}@FNqpc$?#SbVsX!~RH*5p0p@w z;~v{QMX0^bFT1!cXGM8K9FP+=9~-d~#TK#ZE{4umGT=;dfvWi?rYj;^l_Zxywze`W z^Cr{55U@*BalS}K%Czii_80e0#0#Zkhlij4-~I@}`-JFJ7$5{>LnoJSs??J8kWVl6|8A}RCGAu9^rAsfCE=2}tHwl93t0C?#+jMpvr7O3`2=tr{Hg$=HlnjVG^ewm|Js0J*kfPa6*GhtB>`fN!m#9J(sU!?(OSfzY*zS(FJ<-Vb zfAIg+`U)YaXv#sY(c--|X zEB+TVyZ%Ie4L$gi#Fc++`h6%vzsS$pjz9aLt+ZL(g;n$Dzy5=m=_TV(3H8^C{r0xd zp#a%}ht55dOq?yhwYPrtp-m1xXp;4X;)NhxxUpgP%XTLmO zcjaFva^}dP3$&sfFTIR_jC=2pHh9kpI@2(6V*GQo7Ws)`j)hd+tr@P~gR*2gO@+1? zG<`_tB+LJuF|SZ9tIec;h%}}6WClT`L>HSW?E{Hp1h^+mlbf_$9zA>!ug>NALJsO{ mU%z=YwVD?}XMya)Bp;vlyE5&E_6!fzx9pwrdz474!~g(M6R?N? literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 0000000000000000000000000000000000000000..1b9a6956b3acdc11f40ce2bb3f6efbd845cc243f GIT binary patch literal 3918 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�(p-{x$&=IACIfoAR!za)F-^da-t3#0Dycnp zwO~NVXwXCl;jE<}>%@xz|=8fIJAB?>+E{7)|4l${4ngA3G|=r z2Dyv;VVWSgZx9Wj>qUjleGl3Ei9K4>h!(lPS%8VOG>Xu0%6VDz^O=bjJmuP7>DeUv zrbI}MlHB^^d?{zv6d=@_ZD2lg1&G7UjnVN{1}9WkaM3H~btX0GtSzB+tZ^qRgWo4m z!GmimlG$=wgXCnr6j@m<1gAL46#T~5Bnm=2{^@>|t&`9mkEPddj zAvG~@Tv~TAm2i%VW}R-g(Z0)z-Y|szHr@rk>4MAyG*Ma*7Yh#H7(!-5>DZ@8r;_dx z{prSe<>~099F8vsYd2xff7uAS%7{S)f(|@me3t2$iy&NEc7OUEchp@9A|X;;IA>8!oX+y(BKJ$EzV* znR$z;!L$s7uy@{OT~nG#B!NRraT8(X##Ho!0r_o@gg0CA-9H^;-uE&?$2$nHv_00o z%cbuUc-tCx$Uh&EZ4Nf4Zgqv)Y6>usG3>GeQnxx_Z6+PcbX-+ysbt1hQ`K1LDpOE? zrAhIZhSN9yVIAOa22gn577tbc&i3|3V8NWy&!tw##`}9*x}gtI^h1DzZRA>UuaJG) zaZ7j)dq!O}{?#8Y7~7i6fHh4{`pL?>-18|p!S75Y#^DM>-S3)vuZG+Q7l@ek zQP~#cBpWgg#mApc_sPYjpw8odQuRokmTkzcNl`^CcKB7e&;zViV;{Y{o^Y$%7i0m# z62%#1Lq!RC?}lK>%mp}T!3Xv;L*0v*>USLm``N%>w>@fwC+#T&Tx2bN4w(20JB}oU zuSa6v^kXi0xPs?pbaOHnyiqq6By1EZY9OZ^^QA>{q-Hsd&m`pbQ%8121aWG-F5xf zlZ%;B{;C>X19|`^_?dVyCq>n+41w7|!tUS!{9rHlbhX=SZO5CQ^;!Du_E7*`GiR^Q w)2!4MKjfSAeNo!9>IaV6aUZ*?W>} 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

UmY2RIYtNPVDpE$%vda+HD#3m z&VuXJ{BK&Qe+rBa7eq}Q(bq|tn(RrJAk|ztj2(i{d>nmQnM?;HF2k&9sA6up5tmjl z7lySlzMbifH17-m-Lwa_F&e7nOH?ESi3#ckR3tsM+jsck3`oG!uMS}|eAwVXv>}qxwq?QY%QJ0}r@^;fhuUA9W z*BVl>TGo&N004@xSiwDUXUvp51sVmqO3m)=B55aPwf@0=e}cN+$-BdKxY`YrT_4)0 z_d10#i44Q*rFr8MC>*)v$EJvz``(pb{e&*6k+b zsMz%($|1+8hn8c2?P(l@;Rb&CsZeYoCI3?2!LqjbwPXW3z4G$Qfj=cT5Yb%vY0(AX oeb?AaKtwrnc|$|zzw9vfvn^aJJ!zd)XFXqqy0000001=f@-~a#s literal 0 HcmV?d00001 diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..f8c6127 --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,10 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..2655f4c --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + furintiture + \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..d3cf159 --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,5 @@ + + + +