Compare commits

...

No commits in common. "main" and "Course_Work" have entirely different histories.

144 changed files with 5535 additions and 32 deletions

46
.gitignore vendored
View File

@ -1,33 +1,15 @@
# Gradle files
.gradle/
build/
# Local configuration file (sdk path, etc)
local.properties
# Log/OS Files
*.log
# Android Studio generated files and folders
captures/
.externalNativeBuild/
.cxx/
*.apk
output.json
# IntelliJ
*.iml
.idea/
misc.xml
deploymentTargetDropDown.xml
render.experimental.xml
# Keystore files
*.jks
*.keystore
# Google Services (e.g. APIs or Firebase)
google-services.json
# Android Profiling
*.hprof
.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

3
.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

1
.idea/.name Normal file
View File

@ -0,0 +1 @@
Android-Programming

6
.idea/compiler.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="19" />
</component>
</project>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetDropDown">
<targetSelectedWithDropDown>
<Target>
<type value="QUICK_BOOT_TARGET" />
<deviceKey>
<Key>
<type value="VIRTUAL_DEVICE_PATH" />
<value value="C:\Users\Admin\.android\avd\Pixel_7_Pro_API_30.avd" />
</Key>
</deviceKey>
</Target>
</targetSelectedWithDropDown>
<timeTargetWasSelectedWithDropDown value="2023-11-10T15:46:58.753378100Z" />
</component>
</project>

21
.idea/gradle.xml Normal file
View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="GRADLE" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleHome" value="$PROJECT_DIR$/../../../../Gradle/gradle-8.3" />
<option name="gradleJvm" value="19" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>

View File

@ -0,0 +1,41 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="PreviewAnnotationInFunctionWithParameters" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewApiLevelMustBeValid" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewDimensionRespectsLimit" enabled="true" level="WARNING" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewFontScaleMustBeGreaterThanZero" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewMultipleParameterProviders" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewMustBeTopLevelFunction" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewNeedsComposableAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewNotSupportedInUnitTestFiles" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewPickerAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
</profile>
</component>

6
.idea/kotlinc.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KotlinJpsPluginSettings">
<option name="version" value="1.8.10" />
</component>
</project>

9
.idea/misc.xml Normal file
View File

@ -0,0 +1,9 @@
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_19" default="true" project-jdk-name="19" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

1
app/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

99
app/build.gradle.kts Normal file
View File

@ -0,0 +1,99 @@
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id ("kotlin-kapt")
kotlin("plugin.serialization") version "1.4.21"
}
android {
namespace = "com.example.android_programming"
compileSdk = 34
defaultConfig {
applicationId = "com.example.android_programming"
minSdk = 24
targetSdk = 34
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary = true
}
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_19
targetCompatibility = JavaVersion.VERSION_19
}
kotlinOptions {
jvmTarget = "19"
}
buildFeatures {
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = "1.4.3"
}
packaging {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
}
}
}
apply(plugin = "kotlin-kapt")
dependencies {
implementation("androidx.core:core-ktx:1.12.0")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2")
implementation("androidx.activity:activity-compose:1.8.0")
implementation(platform("androidx.compose:compose-bom:2023.03.00"))
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.ui:ui-graphics")
implementation("androidx.compose.ui:ui-tooling-preview")
implementation("androidx.compose.material:material")
implementation("androidx.navigation:navigation-runtime-ktx:2.7.4")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
androidTestImplementation(platform("androidx.compose:compose-bom:2023.03.00"))
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
debugImplementation("androidx.compose.ui:ui-tooling")
debugImplementation("androidx.compose.ui:ui-test-manifest")
implementation ("androidx.activity:activity-ktx:1.8.0")
implementation ("androidx.fragment:fragment-ktx:1.6.1")
implementation ("io.coil-kt:coil-compose:1.4.0")
implementation ("com.google.code.gson:gson:2.8.8")
implementation("androidx.navigation:navigation-compose:2.7.4")
implementation ("androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0-alpha02")
//ROOM
val room_version = "2.5.2"
implementation("androidx.room:room-runtime:$room_version")
annotationProcessor("androidx.room:room-compiler:$room_version")
kapt("androidx.room:room-compiler:$room_version")
implementation("androidx.room:room-ktx:$room_version")
implementation("androidx.room:room-paging:$room_version")
//Paging
implementation ("androidx.paging:paging-compose:3.2.1")
implementation ("androidx.paging:paging-runtime:3.2.1")
// retrofit
val retrofitVersion = "2.9.0"
implementation("com.squareup.retrofit2:retrofit:$retrofitVersion")
implementation("com.squareup.okhttp3:logging-interceptor:4.11.0")
implementation("androidx.paging:paging-compose:3.2.1")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1")
implementation("com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:1.0.0")
}

21
app/proguard-rules.pro vendored Normal file
View File

@ -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

View File

@ -0,0 +1,24 @@
package com.example.android_programming
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.android_programming", appContext.packageName)
}
}

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:name=".App"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.AndroidProgramming"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.AndroidProgramming">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@ -0,0 +1,14 @@
package com.example.android_programming
import android.app.Application
import com.example.android_programming.di.AppContainer
import com.example.android_programming.di.AppDataContainer
class App : Application() {
lateinit var container: AppContainer
override fun onCreate() {
super.onCreate()
container = AppDataContainer(this)
}
}

View File

@ -0,0 +1,25 @@
package com.example.android_programming
import com.example.android_programming.model.User
class GlobalUser private constructor() {
private var user: User? = null
fun setUser(user: User?) {
this.user = user
}
fun getUser(): User? {
return user
}
companion object {
private var instance: GlobalUser? = null
fun getInstance(): GlobalUser {
return instance ?: synchronized(this) {
instance ?: GlobalUser().also { instance = it }
}
}
}
}

View File

@ -0,0 +1,33 @@
package com.example.android_programming
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.example.android_programming.composeui.Header.Header
import com.example.android_programming.composeui.Navigation.Navigate
import com.example.android_programming.model.User
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// this.deleteDatabase("my-db")
setContent {
MainContent()
}
}
}
@Composable
fun MainContent() {
Column(
modifier = Modifier.fillMaxSize()
) {
Header()
Navigate()
}
}

View File

@ -0,0 +1,176 @@
package com.example.android_programming.api
import com.example.android_programming.api.model.BasketSneakerRemote
import com.example.android_programming.api.model.OrderRemote
import com.example.android_programming.api.model.OrderSneakerRemote
import com.example.android_programming.api.model.SneakerRemote
import com.example.android_programming.api.model.UserRemote
import com.example.android_programming.api.model.UserRemoteSignIn
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
import kotlinx.serialization.json.Json
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
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 retrofit2.http.Query
interface BackendService {
//SNEAKER
@GET("sneaker/get/{id}")
suspend fun getSneaker(
@Path("id") id: Int,
): SneakerRemote
@GET("sneaker/getAll")
suspend fun getSneakers(
@Query("page") page: Int,
@Query("size") size: Int,
): List<SneakerRemote>
@POST("sneaker/create")
suspend fun createSneaker(
@Body sneaker: SneakerRemote,
): SneakerRemote
@PUT("sneaker/update/{id}")
suspend fun updateSneaker(
@Path("id") id: Int,
@Body sneaker: SneakerRemote
): SneakerRemote
@DELETE("sneaker/delete/{id}")
suspend fun deleteSneaker(
@Path("id") id: Int
)
@GET("sneaker/findSneakersByString/{string}")
suspend fun findSneakersByString(
@Path("string") str: String,
nextPageNumber: Int,
loadSize: Int
): List<SneakerRemote>
//USER
@POST("user/signup")
suspend fun SignUp(
@Body user: UserRemote,
): UserRemote
@POST("user/signin")
suspend fun SignIn(
@Body user: UserRemoteSignIn
): UserRemote
//BASKET
@POST("basket/createBasketSneaker")
suspend fun createBasketSneaker(
@Body basketSneaker: BasketSneakerRemote
)
@GET("basket/getUserBasketSneakers/{id}")
suspend fun getUserBasketSneakers(
@Path("id") id: Int
): List<SneakerRemote>
@GET("basket/getUserBasket/{id}")
suspend fun getUserBasket(
@Path("id") id: Int
): Int
@GET("basket/getQuantity/{basketId}/{sneakerId}")
suspend fun getQuantity(
@Path("basketId") basketId: Int,
@Path("sneakerId") sneakerId: Int,
): Int
@PUT("basket/incrementQuantity/{basketId}/{sneakerId}")
suspend fun increment(
@Path("basketId") basketId: Int,
@Path("sneakerId") sneakerId: Int,
)
@PUT("basket/decrementQuantity/{basketId}/{sneakerId}")
suspend fun decrement(
@Path("basketId") basketId: Int,
@Path("sneakerId") sneakerId: Int,
)
@GET("basket/getSneaker/{basketId}/{sneakerId}")
suspend fun getSneaker(
@Path("basketId") basketId: Int,
@Path("sneakerId") sneakerId: Int,
): Boolean
@GET("basket/removeSneaker/{basketId}/{sneakerId}")
suspend fun deleteSneakerFromBasket(
@Path("basketId") basketId: Int,
@Path("sneakerId") sneakerId: Int,
)
@GET("basket/getUserPrice/{userId}")
suspend fun getTotalPriceForUserBasket(
@Path("userId") userId: Int
): Double
@GET("basket/deleteAllSneakerFromBasket/{basketId}")
suspend fun deleteAllSneakerFromBasket(
@Path("basketId") basketId: Int
)
//ORDER
@POST("order/createOrderSneaker")
suspend fun createOrderSneaker(
@Body orderSneaker: OrderSneakerRemote
)
@POST("order/create")
suspend fun createOrder(
@Body order: OrderRemote
): Long
@GET("order/getUserOrders/{userId}")
suspend fun getUserOrders(
@Path("userId") userId: Int
) : List<OrderRemote>
@GET("order/getSneakerFromOrder/{orderId}")
suspend fun getSneakerFromOrder(
@Path("orderId") orderId: Int
) : List<SneakerRemote>
@GET("order/deleteOrder/{orderId}")
suspend fun deleteOrder(
@Path("orderId") orderId: Int
)
companion object {
private const val BASE_URL = "https://59k4pfj3-8080.euw.devtunnels.ms/api/"
@Volatile
private var INSTANCE: BackendService? = null
fun getInstance(): BackendService {
return INSTANCE ?: synchronized(this) {
val logger = HttpLoggingInterceptor()
logger.level = HttpLoggingInterceptor.Level.BASIC
val client = OkHttpClient.Builder()
.addInterceptor(logger)
.build()
return Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(Json.asConverterFactory("application/json".toMediaType()))
.build()
.create(BackendService::class.java)
.also { INSTANCE = it }
}
}
}
}

View File

@ -0,0 +1,103 @@
package com.example.android_programming.api
import androidx.paging.ExperimentalPagingApi
import androidx.paging.LoadType
import androidx.paging.PagingState
import androidx.paging.RemoteMediator
import androidx.room.withTransaction
import com.example.android_programming.api.model.toSneaker
import com.example.android_programming.database.AppDatabase
import com.example.android_programming.model.RemoteKeyType
import com.example.android_programming.model.RemoteKeys
import com.example.android_programming.database.repository.RemoteKeysRepositoryImpl
import com.example.android_programming.model.Sneaker
import com.example.android_programming.database.repository.SneakerRepoImpl
import retrofit2.HttpException
import java.io.IOException
@OptIn(ExperimentalPagingApi::class)
class SneakerRemoteMediator(
private val service: BackendService,
private val sneakerRepository: SneakerRepoImpl,
private val database: AppDatabase,
private val dbRemoteKeyRepository: RemoteKeysRepositoryImpl
) : RemoteMediator<Int, Sneaker>() {
override suspend fun initialize(): InitializeAction {
return InitializeAction.LAUNCH_INITIAL_REFRESH
}
override suspend fun load(
loadType: LoadType,
state: PagingState<Int, Sneaker>
): MediatorResult {
val page = when (loadType) {
LoadType.REFRESH -> {
val remoteKeys = getRemoteKeyClosestToCurrentPosition(state)
remoteKeys?.nextKey?.minus(1) ?: 1
}
LoadType.PREPEND -> {
val remoteKeys = getRemoteKeyForFirstItem(state)
remoteKeys?.prevKey
?: return MediatorResult.Success(endOfPaginationReached = remoteKeys != null)
}
LoadType.APPEND -> {
val remoteKeys = getRemoteKeyForLastItem(state)
remoteKeys?.nextKey
?: return MediatorResult.Success(endOfPaginationReached = remoteKeys != null)
}
}
try {
val sneakers = service.getSneakers(page, state.config.pageSize).map { it.toSneaker() }
val endOfPaginationReached = sneakers.isEmpty()
database.withTransaction {
if (loadType == LoadType.REFRESH) {
dbRemoteKeyRepository.deleteRemoteKey(RemoteKeyType.SNEAKER)
sneakerRepository.clearSneakers()
}
val prevKey = if (page == 1) null else page - 1
val nextKey = if (endOfPaginationReached) null else page + 1
val keys = sneakers.map {
RemoteKeys(
entityId = it.sneakerId!!,
type = RemoteKeyType.SNEAKER,
prevKey = prevKey,
nextKey = nextKey
)
}
dbRemoteKeyRepository.createRemoteKeys(keys)
sneakerRepository.insertSneakers(sneakers)
}
return MediatorResult.Success(endOfPaginationReached = endOfPaginationReached)
} catch (exception: IOException) {
return MediatorResult.Error(exception)
} catch (exception: HttpException) {
return MediatorResult.Error(exception)
}
}
private suspend fun getRemoteKeyForLastItem(state: PagingState<Int, Sneaker>): RemoteKeys? {
return state.pages.lastOrNull { it.data.isNotEmpty() }?.data?.lastOrNull()
?.let { sneaker ->
sneaker.sneakerId?.let { dbRemoteKeyRepository.getAllRemoteKeys(it, RemoteKeyType.SNEAKER) }
}
}
private suspend fun getRemoteKeyForFirstItem(state: PagingState<Int, Sneaker>): RemoteKeys? {
return state.pages.firstOrNull { it.data.isNotEmpty() }?.data?.firstOrNull()
?.let { sneaker ->
sneaker.sneakerId?.let { dbRemoteKeyRepository.getAllRemoteKeys(it, RemoteKeyType.SNEAKER) }
}
}
private suspend fun getRemoteKeyClosestToCurrentPosition(
state: PagingState<Int, Sneaker>
): RemoteKeys? {
return state.anchorPosition?.let { position ->
state.closestItemToPosition(position)?.sneakerId?.let { sneakerUid ->
dbRemoteKeyRepository.getAllRemoteKeys(sneakerUid, RemoteKeyType.SNEAKER)
}
}
}
}

View File

@ -0,0 +1,9 @@
package com.example.android_programming.api.model
import kotlinx.serialization.Serializable
@Serializable
data class BasketRemote (
val id: Int? = 0,
val userId: Int = 0,
)

View File

@ -0,0 +1,24 @@
package com.example.android_programming.api.model
import com.example.android_programming.model.BasketSneakers
import com.example.android_programming.model.Sneaker
import kotlinx.serialization.Serializable
@Serializable
data class BasketSneakerRemote (
val basketId: Int = 0,
val sneakerId: Int = 0,
val quantity: Int = 0
)
fun BasketSneakerRemote.toBasketSneaker(): BasketSneakers = BasketSneakers(
basketId,
sneakerId,
quantity
)
fun BasketSneakers.toBasketSneakerRemote():BasketSneakerRemote = BasketSneakerRemote(
basketId,
sneakerId,
quantity
)

View File

@ -0,0 +1,44 @@
package com.example.android_programming.api.model
import androidx.room.ColumnInfo
import androidx.room.PrimaryKey
import com.example.android_programming.model.Order
import com.example.android_programming.model.Sneaker
import kotlinx.serialization.Serializable
@Serializable
data class OrderRemote(
val id: Int? = 0,
val date: Long = 0L,
val city: String = "",
val street: String = "",
val house: String = "",
val subtotal: Double = 0.0,
val taxes: Double = 0.0,
val total: Double = 0.0,
val userId: Int = 0
)
fun OrderRemote.toOrder(): Order = Order(
id,
date,
city,
street,
house,
subtotal,
taxes,
total,
userId
)
fun Order.toOrderRemote():OrderRemote = OrderRemote(
orderId,
date,
city,
street,
house,
subtotal,
taxes,
total,
creatorUserId
)

View File

@ -0,0 +1,24 @@
package com.example.android_programming.api.model
import com.example.android_programming.model.BasketSneakers
import com.example.android_programming.model.OrderSneaker
import kotlinx.serialization.Serializable
@Serializable
data class OrderSneakerRemote (
val orderId: Int = 0,
val sneakerId: Int = 0,
val quantity: Int = 0
)
fun OrderSneakerRemote.toOrderSneaker(): OrderSneaker = OrderSneaker(
orderId,
sneakerId,
quantity
)
fun OrderSneaker.toOrderSneakerRemote():OrderSneakerRemote = OrderSneakerRemote(
orderId,
sneakerId,
quantity
)

View File

@ -0,0 +1,32 @@
package com.example.android_programming.api.model
import com.example.android_programming.model.Sneaker
import kotlinx.serialization.Serializable
@Serializable
data class SneakerRemote (
val id: Int? = 0,
val brand: String = "",
val model: String = "",
val description: String = "",
val price: Double = 0.0,
val photo: Int = 0
)
fun SneakerRemote.toSneaker():Sneaker = Sneaker(
id,
brand,
model,
description,
price,
photo
)
fun Sneaker.toSneakerRemote():SneakerRemote = SneakerRemote(
sneakerId,
brand,
model,
description,
price,
photo
)

View File

@ -0,0 +1,40 @@
package com.example.android_programming.api.model
import androidx.room.ColumnInfo
import androidx.room.PrimaryKey
import com.example.android_programming.model.RoleEnum
import com.example.android_programming.model.Sneaker
import com.example.android_programming.model.User
import kotlinx.serialization.Serializable
@Serializable
data class UserRemote (
val id: Int? = 0,
val name: String = "",
val surname: String = "",
val email: String = "",
val password: String = "",
val role: String = "",
val photo: Int? = 0,
)
fun UserRemote.toUser(): User = User(
id,
name,
surname,
email,
password,
role,
photo
)
fun User.toUserRemote():UserRemote = UserRemote(
userId,
name,
surname,
email,
password,
role,
photo
)

View File

@ -0,0 +1,9 @@
package com.example.android_programming.api.model
import kotlinx.serialization.Serializable
@Serializable
data class UserRemoteSignIn(
val email: String = "",
val password: String = "",
)

View File

@ -0,0 +1,81 @@
package com.example.android_programming.api.repository
import com.example.android_programming.api.BackendService
import com.example.android_programming.api.model.SneakerRemote
import com.example.android_programming.api.model.toBasketSneaker
import com.example.android_programming.api.model.toBasketSneakerRemote
import com.example.android_programming.api.model.toSneaker
import com.example.android_programming.businessLogic.repo.BasketRepository
import com.example.android_programming.model.Basket
import com.example.android_programming.model.BasketSneakers
import com.example.android_programming.model.BasketWithSneakers
import com.example.android_programming.model.Sneaker
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.runBlocking
class RestBasketRepository(
private var service: BackendService
): BasketRepository {
override suspend fun insertBasketSneaker(basketSneaker: BasketSneakers) {
service.createBasketSneaker(basketSneaker.toBasketSneakerRemote())
}
override suspend fun getBasketWithSneakers(id: Int): Flow<List<Sneaker>> {
val sneakersRemoteList = service.getUserBasketSneakers(id)
val sneakersList = sneakersRemoteList.map { it.toSneaker() }
return flowOf(sneakersList.toList())
}
override suspend fun getUserBasketId(id: Int): Flow<Int> {
return flowOf(service.getUserBasket(id))
}
override suspend fun getQuantity(basketId: Int, sneakerId: Int): Int? {
return service.getQuantity(basketId, sneakerId)
}
//
// override fun getAllBasket(): Flow<List<Basket>> {
// TODO("Not yet implemented")
// }
//
// override suspend fun delete(basket: Basket) {
// TODO("Not yet implemented")
// }
//
// override suspend fun createBasket(basket: Basket): Long {
// TODO("Not yet implemented")
// }
//
override suspend fun removeSneakerFromBasket(basketId: Int, sneakerId: Int) {
service.deleteSneakerFromBasket(basketId, sneakerId)
}
//
// override suspend fun updateSneakerQuantity(basketId: Int, sneakerId: Int, quantity: Int) {
// TODO("Not yet implemented")
// }
//
override suspend fun incrementSneakerQuantity(basketId: Int, sneakerId: Int) {
service.increment(basketId, sneakerId)
}
override suspend fun decrementSneakerQuantity(basketId: Int, sneakerId: Int) {
service.decrement(basketId, sneakerId)
}
//
// override suspend fun getQuantity(basketId: Int, sneakerId: Int): Int? {
// TODO("Not yet implemented")
// }
//
override suspend fun existSneaker(basketId: Int, sneakerId: Int): Boolean {
return service.getSneaker(basketId, sneakerId)
}
override suspend fun getTotalPriceForUser(userId: Int): Double? {
return service.getTotalPriceForUserBasket(userId)
}
override suspend fun deleteAllSneakerFromBasket(basketId: Int) {
service.deleteAllSneakerFromBasket(basketId)
}
}

View File

@ -0,0 +1,39 @@
package com.example.android_programming.api.repository
import com.example.android_programming.api.BackendService
import com.example.android_programming.api.model.toOrder
import com.example.android_programming.api.model.toOrderRemote
import com.example.android_programming.api.model.toOrderSneakerRemote
import com.example.android_programming.api.model.toSneaker
import com.example.android_programming.businessLogic.repo.OrderRepository
import com.example.android_programming.model.Order
import com.example.android_programming.model.OrderSneaker
import com.example.android_programming.model.Sneaker
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
class RestOrderRepository(private val service: BackendService): OrderRepository {
override suspend fun createOrder(order: Order): Long {
return service.createOrder(order.toOrderRemote())
}
override suspend fun insertOrderSneaker(orderSneaker: OrderSneaker) {
service.createOrderSneaker(orderSneaker.toOrderSneakerRemote())
}
override suspend fun delete(orderId: Int) {
service.deleteOrder(orderId)
}
override suspend fun getSneakerFromOrder(id: Int): Flow<List<Sneaker>> {
val sneakersRemoteList = service.getSneakerFromOrder(id)
val sneakersList = sneakersRemoteList.map { it.toSneaker() }
return flowOf(sneakersList.toList())
}
override suspend fun getUserOrders(id: Int): Flow<List<Order>> {
val ordersRemoteList = service.getUserOrders(id)
val ordersList = ordersRemoteList.map { it.toOrder() }
return flowOf(ordersList.toList())
}
}

View File

@ -0,0 +1,62 @@
package com.example.android_programming.api.repository
import androidx.paging.ExperimentalPagingApi
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import androidx.paging.PagingSource
import androidx.paging.PagingState
import androidx.paging.compose.collectAsLazyPagingItems
import com.example.android_programming.di.AppContainer
import com.example.android_programming.api.BackendService
import com.example.android_programming.api.SneakerRemoteMediator
import com.example.android_programming.api.model.toSneaker
import com.example.android_programming.api.model.toSneakerRemote
import com.example.android_programming.database.AppDatabase
import com.example.android_programming.database.repository.RemoteKeysRepositoryImpl
import com.example.android_programming.model.Sneaker
import com.example.android_programming.database.repository.SneakerRepoImpl
import com.example.android_programming.businessLogic.repo.SneakerRepository
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.flowOf
class RestSneakerRepository(
private val service: BackendService,
private val dbSneakerRepository: SneakerRepoImpl,
private val database: AppDatabase,
private val dbRemoteKeyRepository: RemoteKeysRepositoryImpl
) : SneakerRepository {
override fun getAllSneakers(): Flow<PagingData<Sneaker>> {
val pagingSourceFactory = { dbSneakerRepository.getAllSneakersPagingSource() }
@OptIn(ExperimentalPagingApi::class)
return Pager(
config = PagingConfig(
pageSize = AppContainer.LIMIT,
enablePlaceholders = false
),
remoteMediator = SneakerRemoteMediator(
service,
dbSneakerRepository,
database,
dbRemoteKeyRepository,
),
pagingSourceFactory = pagingSourceFactory
).flow
}
override suspend fun getSneakerById(id: Int): Sneaker = service.getSneaker(id).toSneaker()
override suspend fun insertSneaker(sneaker: Sneaker) {
service.createSneaker(sneaker.toSneakerRemote())
}
override suspend fun updateSneaker(sneaker: Sneaker) {
sneaker.sneakerId?.let { service.updateSneaker(it, sneaker.toSneakerRemote()) }
}
override suspend fun deleteSneaker(sneaker: Sneaker) {
sneaker.sneakerId?.let { service.deleteSneaker(it) }
}
}

View File

@ -0,0 +1,27 @@
package com.example.android_programming.api.repository
import com.example.android_programming.api.BackendService
import com.example.android_programming.api.model.UserRemoteSignIn
import com.example.android_programming.api.model.toUser
import com.example.android_programming.api.model.toUserRemote
import com.example.android_programming.model.User
import com.example.android_programming.businessLogic.repo.UserRepository
class RestUserRepository(
private var service: BackendService
): UserRepository {
override suspend fun createUser(user: User) {
service.SignUp(user.toUserRemote())
}
override suspend fun updateUser(user: User) {
println()
}
override suspend fun deleteUser(user: User) {
println()
}
override suspend fun authUser(user: UserRemoteSignIn): User {
return service.SignIn(user).toUser()
}
}

View File

@ -0,0 +1,27 @@
package com.example.android_programming.businessLogic.repo
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
import com.example.android_programming.model.Basket
import com.example.android_programming.model.BasketSneakers
import com.example.android_programming.model.BasketWithSneakers
import com.example.android_programming.model.Sneaker
import kotlinx.coroutines.flow.Flow
interface BasketRepository {
suspend fun insertBasketSneaker(basketSneaker: BasketSneakers)
suspend fun getBasketWithSneakers(id: Int): Flow<List<Sneaker>>
suspend fun getUserBasketId(id: Int): Flow<Int>
// fun getAllBasket(): Flow<List<Basket>>
// suspend fun delete(basket: Basket)
// suspend fun createBasket(basket: Basket):Long
suspend fun removeSneakerFromBasket(basketId: Int, sneakerId: Int)
// suspend fun updateSneakerQuantity(basketId: Int, sneakerId: Int, quantity: Int)
suspend fun incrementSneakerQuantity(basketId: Int, sneakerId: Int)
suspend fun decrementSneakerQuantity(basketId: Int, sneakerId: Int)
suspend fun getQuantity(basketId: Int, sneakerId: Int): Int?
suspend fun existSneaker(basketId: Int, sneakerId: Int): Boolean
suspend fun getTotalPriceForUser(userId: Int): Double?
suspend fun deleteAllSneakerFromBasket(basketId: Int)
}

View File

@ -0,0 +1,17 @@
package com.example.android_programming.businessLogic.repo
import com.example.android_programming.model.Order
import com.example.android_programming.model.OrderSneaker
import com.example.android_programming.model.OrderWithSneakers
import com.example.android_programming.model.Sneaker
import com.example.android_programming.model.UserWithOrder
import kotlinx.coroutines.flow.Flow
interface OrderRepository {
suspend fun createOrder(order: Order): Long
suspend fun insertOrderSneaker(orderSneaker: OrderSneaker)
suspend fun delete(orderId: Int)
suspend fun getSneakerFromOrder(id: Int): Flow<List<Sneaker>>
// fun getAllOrder(): Flow<List<Order>>
suspend fun getUserOrders(id: Int) : Flow<List<Order>>
}

View File

@ -0,0 +1,10 @@
package com.example.android_programming.businessLogic.repo
import com.example.android_programming.model.RemoteKeyType
import com.example.android_programming.model.RemoteKeys
interface RemoteKeyRepository {
suspend fun getAllRemoteKeys(id: Int, type: RemoteKeyType): RemoteKeys?
suspend fun createRemoteKeys(remoteKeys: List<RemoteKeys>)
suspend fun deleteRemoteKey(type: RemoteKeyType)
}

View File

@ -0,0 +1,14 @@
package com.example.android_programming.businessLogic.repo
import androidx.paging.PagingData
import androidx.paging.PagingSource
import com.example.android_programming.model.Sneaker
import kotlinx.coroutines.flow.Flow
interface SneakerRepository {
suspend fun insertSneaker(sneaker: Sneaker)
suspend fun updateSneaker(sneaker: Sneaker)
suspend fun deleteSneaker(sneaker: Sneaker)
suspend fun getSneakerById(id: Int): Sneaker
fun getAllSneakers(): Flow<PagingData<Sneaker>>
}

View File

@ -0,0 +1,14 @@
package com.example.android_programming.businessLogic.repo
import com.example.android_programming.api.model.UserRemoteSignIn
import com.example.android_programming.model.Basket
import com.example.android_programming.model.User
import com.example.android_programming.model.UserWithOrder
import kotlinx.coroutines.flow.Flow
interface UserRepository {
suspend fun createUser(user: User)
suspend fun updateUser(user: User)
suspend fun deleteUser(user: User)
suspend fun authUser(user: UserRemoteSignIn): User
}

View File

@ -0,0 +1,27 @@
package com.example.android_programming.businessLogic.vmodel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewmodel.CreationExtras
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
import com.example.android_programming.App
object AppViewModelProvider {
val Factory = viewModelFactory {
initializer {
SneakerViewModel(app().container.sneakerRepo)
}
initializer {
UserViewModel(app().container.userRepo)
}
initializer {
OrderViewModel(app().container.orderRepo, app().container.basketRepo)
}
initializer {
BasketViewModel(app().container.basketRepo)
}
}
}
fun CreationExtras.app(): App =
(this[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY] as App)

View File

@ -0,0 +1,100 @@
package com.example.android_programming.businessLogic.vmodel
import androidx.compose.runtime.State
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.android_programming.GlobalUser
import com.example.android_programming.model.BasketSneakers
import com.example.android_programming.model.BasketWithSneakers
import com.example.android_programming.businessLogic.repo.BasketRepository
import com.example.android_programming.model.Sneaker
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.async
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
class BasketViewModel(private val basketRepository: BasketRepository): ViewModel() {
private val _quantityStateMap = mutableMapOf<Int, MutableStateFlow<Int>>()
private val _sneakerList = MutableStateFlow<List<Sneaker>>(emptyList())
val sneakerList: StateFlow<List<Sneaker>> = _sneakerList
fun getQuantityState(basketId: Int, sneakerId: Int): StateFlow<Int> {
val quantityStateFlow = _quantityStateMap.getOrPut(sneakerId) {
MutableStateFlow(0)
}
viewModelScope.launch {
val quantityFromDb = basketRepository.getQuantity(basketId, sneakerId)
quantityFromDb?.let { quantityStateFlow.value = it }
}
return quantityStateFlow
}
suspend fun isSneakerInBasket(basketId: Int, sneakerId: Int): Boolean {
return basketRepository.existSneaker(basketId, sneakerId)
}
fun addToBasket(basketSneakers: BasketSneakers) = viewModelScope.launch {
val isSneakerInBasket = isSneakerInBasket(basketSneakers.basketId, basketSneakers.sneakerId)
if (isSneakerInBasket) {
incrementQuantity(basketSneakers.basketId, basketSneakers.sneakerId)
} else {
basketRepository.insertBasketSneaker(basketSneakers)
}
}
fun fetchBasketSneakers(userId: Int) {
viewModelScope.launch {
basketRepository.getBasketWithSneakers(userId).collect {
_sneakerList.value = it
}
}
}
suspend fun getUserBasketId(userId: Int) : Flow<Int>{
return basketRepository.getUserBasketId(userId)
}
fun deleteSneakerFromBasket(basketId: Int, sneakerId: Int) = viewModelScope.launch {
basketRepository.removeSneakerFromBasket(basketId, sneakerId)
fetchBasketSneakers(GlobalUser.getInstance().getUser()?.userId!!)
}
fun incrementQuantity(basketId: Int, sneakerId: Int) {
val currentQuantity = _quantityStateMap[sneakerId]?.value ?: 1
_quantityStateMap[sneakerId]?.value = currentQuantity + 1
viewModelScope.launch {
basketRepository.incrementSneakerQuantity(basketId, sneakerId)
}
}
fun decrementQuantity(basketId: Int, sneakerId: Int) {
val currentQuantity = _quantityStateMap[sneakerId]?.value ?: 1
if (currentQuantity > 1) {
_quantityStateMap[sneakerId]?.value = currentQuantity - 1
viewModelScope.launch {
basketRepository.decrementSneakerQuantity(basketId, sneakerId)
}
}
}
fun deleteAllSneakerFromBasket(basketId: Int) = viewModelScope.launch {
basketRepository.deleteAllSneakerFromBasket(basketId)
}
}

View File

@ -0,0 +1,84 @@
package com.example.android_programming.businessLogic.vmodel
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.android_programming.GlobalUser
import com.example.android_programming.model.Order
import com.example.android_programming.model.OrderSneaker
import com.example.android_programming.model.OrderWithSneakers
import com.example.android_programming.model.Sneaker
import com.example.android_programming.model.UserWithOrder
import com.example.android_programming.businessLogic.repo.BasketRepository
import com.example.android_programming.businessLogic.repo.OrderRepository
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch
import java.util.Date
class OrderViewModel(private val orderRepository: OrderRepository, private val basketRepository: BasketRepository) : ViewModel() {
var city = mutableStateOf("")
val street = mutableStateOf("")
val house = mutableStateOf("")
private val _selectedItems = MutableLiveData<List<Sneaker>>()
private val _subTotal = mutableStateOf(0.0)
val subTotal: State<Double> get() = _subTotal
val selectedItems: LiveData<List<Sneaker>> get() = _selectedItems
fun updateSelectedItems(items: List<Sneaker>) {
_selectedItems.value = items
}
fun deleteOrder(orderId: Int) = viewModelScope.launch {
orderRepository.delete(orderId)
}
suspend fun getOrderList(id: Int) : Flow<List<Order>> {
return orderRepository.getUserOrders(id)
}
suspend fun getOrderWithSneakers(id: Int) : Flow<List<Sneaker>> {
return orderRepository.getSneakerFromOrder(id)
}
fun createOrder() = viewModelScope.launch {
val userId = GlobalUser.getInstance().getUser()?.userId!!
val subTotal = getSubTotal(userId)
val order = Order(
date = Date().time,
city = city.value,
street = street.value,
house = house.value,
subtotal = subTotal,
taxes = "%.2f".format(subTotal * 0.05).toDouble(),
total = "%.2f".format(subTotal * 0.05 + subTotal).toDouble(),
creatorUserId = GlobalUser.getInstance().getUser()?.userId!!
)
val orderId = orderRepository.createOrder(order)
for (sneaker in selectedItems.value.orEmpty()) {
val userId = GlobalUser.getInstance().getUser()?.userId!!
val orderSneaker = OrderSneaker( orderId.toInt(), sneaker.sneakerId!!, 1)
if (orderSneaker != null) {
orderRepository.insertOrderSneaker(orderSneaker)
}
}
city.value = ""
street.value = ""
house.value = ""
}
fun updateSubTotal(userId: Int) {
viewModelScope.launch {
_subTotal.value = getSubTotal(userId)
}
}
suspend fun getSubTotal(userId: Int): Double {
return basketRepository.getTotalPriceForUser(userId) ?: 0.0
}
}

View File

@ -0,0 +1,44 @@
package com.example.android_programming.businessLogic.vmodel
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.PagingData
import com.example.android_programming.R
import com.example.android_programming.api.repository.RestSneakerRepository
import com.example.android_programming.businessLogic.repo.SneakerRepository
import com.example.android_programming.model.Sneaker
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.launch
class SneakerViewModel(private val sneakerRepository: SneakerRepository): ViewModel() {
val sneakerList = sneakerRepository.getAllSneakers()
var brand = mutableStateOf("")
val model = mutableStateOf("")
val description = mutableStateOf("")
val price = mutableStateOf("")
val photo = mutableIntStateOf(R.drawable.img)
fun insertSneaker() = viewModelScope.launch {
val sneaker = Sneaker(
brand = brand.value,
model = model.value,
description = description.value,
price = price.value.toDouble(),
photo = photo.value
)
sneakerRepository.insertSneaker(sneaker)
}
fun deleteSneaker(sneaker : Sneaker) = viewModelScope.launch {
sneakerRepository.deleteSneaker(sneaker)
}
fun UpdateSneaker(sneaker: Sneaker) = viewModelScope.launch {
sneakerRepository.updateSneaker(sneaker)
}
}

View File

@ -0,0 +1,38 @@
package com.example.android_programming.businessLogic.vmodel
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.android_programming.GlobalUser
import com.example.android_programming.R
import com.example.android_programming.api.model.UserRemoteSignIn
import com.example.android_programming.model.User
import com.example.android_programming.businessLogic.repo.UserRepository
import kotlinx.coroutines.launch
class UserViewModel(private val userRepository: UserRepository): ViewModel() {
var name = mutableStateOf("")
val surname = mutableStateOf("")
val email = mutableStateOf("")
val password = mutableStateOf("")
fun createUser() = viewModelScope.launch {
val user = User(
name = name.value,
surname = surname.value,
email = email.value,
password = password.value,
role = "USER",
photo = R.drawable.shailushai
)
userRepository.createUser(user)
}
fun authUser() = viewModelScope.launch {
val user = userRepository.authUser(UserRemoteSignIn(email.value, password.value))
GlobalUser.getInstance().setUser(user)
}
fun isValidEmail(email: String): Boolean {
return android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches()
}
}

View File

@ -0,0 +1,40 @@
package com.example.android_programming.composeui.Header
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.example.android_programming.R
@Composable
fun Header() {
Box(
modifier = Modifier
.fillMaxWidth()
.background(Color.White)
) {
Image(
painter = painterResource(id = R.drawable.logo),
contentDescription = "image",
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.padding(0.dp, 10.dp, 0.dp, 0.dp)
)
}
}
@Composable
@Preview
fun NavigatePreview(){
Header()
}

View File

@ -0,0 +1,76 @@
package com.example.android_programming.composeui.Navigation
import androidx.compose.runtime.Composable
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import com.example.android_programming.composeui.Screens.AdminPanel.AddPanel
import com.example.android_programming.composeui.Screens.AdminPanel.AdminPanel
import com.example.android_programming.composeui.Screens.AdminPanel.ChangePanel
import com.example.android_programming.composeui.Screens.AdminPanel.ChangeSneaker
import com.example.android_programming.composeui.Screens.HomeScreen.AboutSneaker
import com.example.android_programming.composeui.Screens.HomeScreen.HomeScreen
import com.example.android_programming.composeui.Screens.MyOrderScreen.MyOrderScreen
import com.example.android_programming.composeui.Screens.OrderScreen.OrderScreen
import com.example.android_programming.composeui.Screens.ProfileScreen.Profile.Person
import com.example.android_programming.composeui.Screens.ProfileScreen.Profile.ProfileScreen
import com.example.android_programming.composeui.Screens.ProfileScreen.SignIn.LoginScreen
import com.example.android_programming.composeui.Screens.ProfileScreen.SignUp.SignUpScreen
import com.example.android_programming.model.Sneaker
import com.example.android_programming.businessLogic.vmodel.AppViewModelProvider
import com.example.android_programming.businessLogic.vmodel.OrderViewModel
import com.google.gson.Gson
@Composable
fun NavController(navController: NavHostController){
NavHost(
navController = navController,
startDestination = NavItem.Home.route
){
composable(NavItem.Home.route){
HomeScreen(navController)
}
composable(NavItem.MyOrder.route){
MyOrderScreen()
}
composable(NavItem.Order.route){
OrderScreen(navController)
}
composable(NavItem.Profile.route){
ProfileScreen(navController)
}
composable(NavItem.SignIn.route){
LoginScreen(navController)
}
composable(NavItem.SignUp.route){
SignUpScreen(navController)
}
composable(NavItem.Person.route){
Person(navController)
}
composable(NavItem.AdminPanel.route){
AdminPanel(navController)
}
composable(NavItem.AddPanel.route){
AddPanel()
}
composable(NavItem.ChangePanel.route){
ChangePanel(navController)
}
composable(NavItem.AboutSneaker.route) { backStackEntry ->
val sneakerItemString = backStackEntry.arguments?.getString("sneakerItem")
val sneakerItem = Gson().fromJson(sneakerItemString, Sneaker::class.java)
sneakerItem?.let { AboutSneaker(it, onBackClick = {
navController.navigateUp() })
}
}
composable(NavItem.ChangeSneaker.route) { backStackEntry ->
val sneakerItemString = backStackEntry.arguments?.getString("sneakerItem")
val sneakerItem = Gson().fromJson(sneakerItemString, Sneaker::class.java)
sneakerItem?.let { ChangeSneaker(it, onBackClick = {
navController.navigateUp() })
}
}
}
}

View File

@ -0,0 +1,23 @@
package com.example.android_programming.composeui.Navigation
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Build
import androidx.compose.material.icons.filled.Home
import androidx.compose.material.icons.filled.Person
import androidx.compose.material.icons.filled.ShoppingCart
import androidx.compose.ui.graphics.vector.ImageVector
sealed class NavItem(val route: String, val icon: ImageVector?){
object Home : NavItem("home", Icons.Default.Home)
object MyOrder : NavItem("myorder", null)
object Order : NavItem("order", Icons.Default.ShoppingCart)
object Profile : NavItem("profile", Icons.Default.Person)
object SignIn : NavItem("login", null)
object SignUp : NavItem("signup", null)
object Person : NavItem("person", null)
object AdminPanel : NavItem("admin", Icons.Default.Build)
object AddPanel : NavItem("add", null)
object ChangePanel : NavItem("change", null)
object AboutSneaker : NavItem("aboutSneaker/{sneakerItem}", null)
object ChangeSneaker : NavItem("changeSneaker/{sneakerItem}", null)
}

View File

@ -0,0 +1,81 @@
package com.example.android_programming.composeui.Navigation
import android.annotation.SuppressLint
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.BottomNavigation
import androidx.compose.material.BottomNavigationItem
import androidx.compose.material.Icon
import androidx.compose.material.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.unit.dp
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import com.example.android_programming.R
@SuppressLint("UnusedMaterialScaffoldPaddingParameter")
@Composable
fun Navigate() {
val navController = rememberNavController()
val Items = listOf(
NavItem.Home,
NavItem.Order,
NavItem.Profile,
NavItem.AdminPanel,
)
Scaffold(bottomBar = {
// Оставьте код навигационного бара без изменений
BottomNavigation(
backgroundColor = Color.White
) {
val navBackStackEntry = navController.currentBackStackEntryAsState()
val currentState = navBackStackEntry.value
Items.forEach { it ->
val isSelected = currentState?.destination?.route == it.route
BottomNavigationItem(
selected = isSelected,
onClick = {
if (!isSelected) {
navController.graph.startDestinationRoute?.let {
navController.popBackStack(it, inclusive = true)
}
navController.navigate(it.route) {
launchSingleTop
}
}
navController.navigate(it.route)
},
icon = {
val iconModifier = if (isSelected) {
Modifier
.background(color = colorResource(id = R.color.figma_blue), shape = CircleShape)
.padding(8.dp)
} else {
Modifier
}
it.icon?.let { it1 ->
Icon(
imageVector = it1,
contentDescription = null,
tint = if (isSelected) Color.White else Color.Unspecified,
modifier = iconModifier.then(Modifier.size(24.dp))
)
}
}
)
}
}
}) {
NavController(navController = navController)
}
}

View File

@ -0,0 +1,206 @@
package com.example.android_programming.composeui.Screens.AdminPanel
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.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.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Text
import androidx.compose.material.TextField
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.example.android_programming.R
import com.example.android_programming.model.PhotoManager
import com.example.android_programming.businessLogic.vmodel.AppViewModelProvider
import com.example.android_programming.businessLogic.vmodel.SneakerViewModel
@Composable
fun AddPanel(sneakerViewModel: SneakerViewModel = viewModel(factory = AppViewModelProvider.Factory)){
val photoManager = PhotoManager()
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
.clip(RoundedCornerShape(16.dp))
.background(colorResource(id = R.color.figma))
.verticalScroll(rememberScrollState())
) {
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Image(
painter = painterResource(id = sneakerViewModel.photo.value),
contentDescription = "image",
contentScale = ContentScale.FillHeight,
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
.height(200.dp)
)
Button(
colors = ButtonDefaults.buttonColors(
backgroundColor = colorResource(id = R.color.figma_blue),
contentColor = Color.White
),
onClick = {
sneakerViewModel.photo.value = photoManager.changePhoto(sneakerViewModel.photo.value)
},
modifier = Modifier
.fillMaxWidth()
.padding(16.dp, 0.dp, 16.dp, 16.dp)
) {
Text("Add image")
}
TextField(
value = sneakerViewModel.brand.value,
onValueChange = { sneakerViewModel.brand.value = it },
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.padding(16.dp, 0.dp)
.border(1.dp, Color.Gray, RoundedCornerShape(4.dp)),
singleLine = true,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Next
),
keyboardActions = KeyboardActions(
onNext = {
}
),
placeholder = {
Text(
text = "Brand",
style = TextStyle(fontSize = 12.sp)
)
}
)
Spacer(modifier = Modifier.height(16.dp))
TextField(
value = sneakerViewModel.model.value,
onValueChange = { sneakerViewModel.model.value = it },
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.padding(16.dp, 0.dp)
.border(1.dp, Color.Gray, RoundedCornerShape(4.dp)),
singleLine = true,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Next
),
keyboardActions = KeyboardActions(
onNext = {
}
),
placeholder = {
Text(
text = "Model",
style = TextStyle(fontSize = 12.sp)
)
}
)
Spacer(modifier = Modifier.height(16.dp))
TextField(
value = sneakerViewModel.description.value,
onValueChange = { sneakerViewModel.description.value = it },
modifier = Modifier
.fillMaxWidth()
.height(150.dp)
.padding(16.dp, 0.dp)
.border(1.dp, Color.Gray, RoundedCornerShape(4.dp)),
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Next
),
keyboardActions = KeyboardActions(
onNext = {
}
),
placeholder = {
Text(
text = "Description",
style = TextStyle(fontSize = 12.sp)
)
}
)
Spacer(modifier = Modifier.height(16.dp))
TextField(
value = sneakerViewModel.price.value,
onValueChange = { sneakerViewModel.price.value = it },
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.padding(16.dp, 0.dp)
.border(1.dp, Color.Gray, RoundedCornerShape(4.dp)),
singleLine = true,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Next
),
keyboardActions = KeyboardActions(
onNext = {
}
),
placeholder = {
Text(
text = "Price",
style = TextStyle(fontSize = 12.sp)
)
}
)
Button(
colors = ButtonDefaults.buttonColors(
backgroundColor = colorResource(id = R.color.figma_blue),
contentColor = Color.White
),
onClick = {
sneakerViewModel.insertSneaker()
},
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
) {
Text("Add sneaker")
}
}
}
}

View File

@ -0,0 +1,72 @@
package com.example.android_programming.composeui.Screens.AdminPanel
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material.AlertDialog
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController
import com.example.android_programming.GlobalUser
import com.example.android_programming.model.RoleEnum
@Composable
fun AdminPanel(navHostController: NavHostController) {
var isAddPanelVisible by remember { mutableStateOf(false) }
var isChangePanelVisible by remember { mutableStateOf(false) }
var showDialog by remember { mutableStateOf(GlobalUser.getInstance().getUser()?.role == "USER" || GlobalUser.getInstance().getUser()?.role == null) }
if (!showDialog) {
Column(
modifier = Modifier
.fillMaxSize()
.background(Color.White)
.padding(bottom = 50.dp)
) {
ButtonAdmin(
onAddClick = {
isAddPanelVisible = true
isChangePanelVisible = false
},
onChangeClick = {
isChangePanelVisible = true
isAddPanelVisible = false
}
)
}
if (isAddPanelVisible) {
AddPanel()
}
if (isChangePanelVisible) {
ChangePanel(navHostController)
}
}
if (showDialog) {
AlertDialog(
onDismissRequest = { showDialog = false },
title = {
Text("Access denied")
},
text = {
Text("You are not admin")
},
confirmButton = {
Button(
onClick = { navHostController.navigate("home") }
) {
Text("OK")
}
}
)
}
}

View File

@ -0,0 +1,60 @@
package com.example.android_programming.composeui.Screens.AdminPanel
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.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.res.colorResource
import androidx.compose.ui.unit.dp
import com.example.android_programming.R
@Composable
fun ButtonAdmin(onAddClick: () -> Unit, onChangeClick: () -> Unit) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp, 16.dp, 16.dp, 0.dp)
.clip(RoundedCornerShape(16.dp))
.background(colorResource(id = R.color.figma))
){
Button(
colors = ButtonDefaults.buttonColors(
backgroundColor = colorResource(id = R.color.figma_blue),
contentColor = Color.White
),
onClick = {
onAddClick()
},
modifier = Modifier
.clip(RoundedCornerShape(20.dp))
.fillMaxWidth(0.5f)
.padding(16.dp)
) {
Text("Add")
}
Button(
colors = ButtonDefaults.buttonColors(
backgroundColor = colorResource(id = R.color.figma_blue),
contentColor = Color.White
),
onClick = {
onChangeClick()
},
modifier = Modifier
.clip(RoundedCornerShape(20.dp))
.fillMaxWidth()
.padding(16.dp)
) {
Text("Change/Del")
}
}
}

View File

@ -0,0 +1,99 @@
package com.example.android_programming.composeui.Screens.AdminPanel
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Icon
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Create
import androidx.compose.material.icons.filled.Delete
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
import com.example.android_programming.R
import com.example.android_programming.model.Sneaker
import com.example.android_programming.businessLogic.vmodel.AppViewModelProvider
import com.example.android_programming.businessLogic.vmodel.SneakerViewModel
import com.google.gson.Gson
@Composable
fun CardSneakerForChange(item: Sneaker, navController: NavHostController, sneakerViewModel: SneakerViewModel = viewModel(factory = AppViewModelProvider.Factory)) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(0.dp, 0.dp, 0.dp, 16.dp)
.clip(RoundedCornerShape(10.dp))
.background(colorResource(id = R.color.figma)),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
Image(
painter = painterResource(id = item.photo),
contentDescription = "image",
contentScale = ContentScale.FillWidth,
modifier = Modifier
.size(70.dp)
.padding(10.dp)
.clip(RoundedCornerShape(10.dp))
)
Column(
modifier = Modifier
.weight(1f)
.padding(start = 16.dp)
) {
item.brand?.let { Text(text = it, fontSize = 20.sp) }
Text(text = "${item.price} $", color = Color.Red, fontSize = 16.sp)
}
Button(
colors = ButtonDefaults.buttonColors(
backgroundColor = colorResource(id = R.color.figma_blue),
contentColor = Color.White
),
onClick = {
sneakerViewModel.brand.value = item.brand ?: ""
sneakerViewModel.model.value = item.model ?: ""
sneakerViewModel.description.value = item.description ?: ""
sneakerViewModel.price.value = item.price.toString()
val sneakerItemString = Gson().toJson(item)
navController.navigate("changeSneaker/${sneakerItemString}") },
modifier = Modifier
.padding(end = 16.dp)
) {
Icon(imageVector = Icons.Default.Create, contentDescription = "change")
}
Button(
colors = ButtonDefaults.buttonColors(
backgroundColor = colorResource(id = R.color.figma_blue),
contentColor = Color.White
),
onClick = {
sneakerViewModel.deleteSneaker(item)
},
modifier = Modifier
.padding(end = 16.dp)
) {
Icon(imageVector = Icons.Default.Delete, contentDescription = "delete")
}
}
}

View File

@ -0,0 +1,62 @@
package com.example.android_programming.composeui.Screens.AdminPanel
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.material.CircularProgressIndicator
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
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.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
import androidx.paging.LoadState
import androidx.paging.compose.collectAsLazyPagingItems
import androidx.paging.compose.itemKey
import com.example.android_programming.model.Sneaker
import com.example.android_programming.businessLogic.vmodel.AppViewModelProvider
import com.example.android_programming.businessLogic.vmodel.SneakerViewModel
import kotlinx.coroutines.delay
@Composable
fun ChangePanel(navHostController: NavHostController, sneakerViewModel: SneakerViewModel = viewModel(factory = AppViewModelProvider.Factory)) {
val list = sneakerViewModel.sneakerList.collectAsLazyPagingItems()
Column(
modifier = Modifier
.fillMaxSize()
.background(Color.White)
.padding(16.dp, 80.dp)
) {
Row {
LazyColumn(
modifier = Modifier
.fillMaxSize()
) {
items(list.itemCount) { index ->
list[index]?.let { sneaker ->
CardSneakerForChange(item = sneaker, navController = navHostController)
}
}
}
}
}
}

View File

@ -0,0 +1,242 @@
package com.example.android_programming.composeui.Screens.AdminPanel
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.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.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Icon
import androidx.compose.material.Text
import androidx.compose.material.TextField
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.example.android_programming.R
import com.example.android_programming.model.PhotoManager
import com.example.android_programming.model.Sneaker
import com.example.android_programming.businessLogic.vmodel.AppViewModelProvider
import com.example.android_programming.businessLogic.vmodel.SneakerViewModel
@Composable
fun ChangeSneaker(sneaker: Sneaker, onBackClick: () -> Unit, sneakerViewModel: SneakerViewModel = viewModel(factory = AppViewModelProvider.Factory)) {
val brand = remember {mutableStateOf(sneaker.brand)}
val model = remember{mutableStateOf(sneaker.model)}
val description = remember{mutableStateOf(sneaker.description)}
val price = remember{mutableStateOf(sneaker.price.toString())}
var photo by remember { mutableStateOf(sneaker.photo) }
val photoManager = PhotoManager()
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp, 16.dp, 16.dp, 50.dp)
.clip(RoundedCornerShape(16.dp))
.background(colorResource(id = R.color.figma))
.verticalScroll(rememberScrollState())
) {
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Button(
onClick = onBackClick,
colors = ButtonDefaults.buttonColors(
backgroundColor = colorResource(id = R.color.white),
contentColor = Color.Black
),
) {
Icon(
imageVector = Icons.Default.ArrowBack,
contentDescription = "Back",
)
}
Image(
painter = painterResource(id = photo),
contentDescription = "image",
contentScale = ContentScale.FillHeight,
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
.height(200.dp)
)
Button(
colors = ButtonDefaults.buttonColors(
backgroundColor = colorResource(id = R.color.figma_blue),
contentColor = Color.White
),
onClick = {
photo = photoManager.changePhoto(photo)
},
modifier = Modifier
.fillMaxWidth()
.padding(16.dp, 0.dp, 16.dp, 16.dp)
) {
Text("Change image")
}
TextField(
value = brand.value,
onValueChange = { newValue -> brand.value = newValue },
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.padding(16.dp, 0.dp)
.border(1.dp, Color.Gray, RoundedCornerShape(4.dp)),
singleLine = true,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Next
),
keyboardActions = KeyboardActions(
onNext = {
}
),
placeholder = {
Text(
text = "Brand",
style = TextStyle(fontSize = 12.sp)
)
}
)
Spacer(modifier = Modifier.height(16.dp))
TextField(
value = model.value,
onValueChange = { model.value = it },
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.padding(16.dp, 0.dp)
.border(1.dp, Color.Gray, RoundedCornerShape(4.dp)),
singleLine = true,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Next
),
keyboardActions = KeyboardActions(
onNext = {
}
),
placeholder = {
Text(
text = "Model",
style = TextStyle(fontSize = 12.sp)
)
}
)
Spacer(modifier = Modifier.height(16.dp))
TextField(
value = description.value,
onValueChange = { description.value = it },
modifier = Modifier
.fillMaxWidth()
.height(150.dp)
.padding(16.dp, 0.dp)
.border(1.dp, Color.Gray, RoundedCornerShape(4.dp)),
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Next
),
keyboardActions = KeyboardActions(
onNext = {
}
),
placeholder = {
Text(
text = "Description",
style = TextStyle(fontSize = 12.sp)
)
}
)
Spacer(modifier = Modifier.height(16.dp))
TextField(
value = price.value,
onValueChange = { price.value = it },
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.padding(16.dp, 0.dp)
.border(1.dp, Color.Gray, RoundedCornerShape(4.dp)),
singleLine = true,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Next
),
keyboardActions = KeyboardActions(
onNext = {
}
),
placeholder = {
Text(
text = "Price",
style = TextStyle(fontSize = 12.sp)
)
}
)
Button(
colors = ButtonDefaults.buttonColors(
backgroundColor = colorResource(id = R.color.figma_blue),
contentColor = Color.White
),
onClick = {
sneakerViewModel.UpdateSneaker(
Sneaker(
sneakerId = sneaker.sneakerId,
brand = brand.value,
model = model.value,
description = description.value,
photo = photo,
price = price.value.toDouble()
)
)
onBackClick()
},
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
) {
Text("Save")
}
}
}
}

View File

@ -0,0 +1,34 @@
package com.example.android_programming.composeui.Screens
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.Snackbar
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.Delete
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
@Composable
fun ErrorSnackbar(
) {
Text(text = "случилось говно")
}

View File

@ -0,0 +1,90 @@
package com.example.android_programming.composeui.Screens.HomeScreen
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Icon
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
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.layout.ContentScale
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.example.android_programming.R
import com.example.android_programming.model.Sneaker
@Composable
fun AboutSneaker(sneaker: Sneaker, onBackClick: () -> Unit) {
Column(
modifier = Modifier
.fillMaxSize()
.background(Color.White)
.padding(20.dp)
) {
Button(
onClick = onBackClick,
colors = ButtonDefaults.buttonColors(
backgroundColor = colorResource(id = R.color.white),
contentColor = Color.Black
),
) {
Icon(
imageVector = Icons.Default.ArrowBack,
contentDescription = "Back",
)
}
Image(
painter = painterResource(id = sneaker.photo),
contentDescription = "image",
contentScale = ContentScale.FillWidth,
modifier = Modifier
.fillMaxWidth()
.height(300.dp)
)
Column(
modifier = Modifier.padding(16.dp)
) {
Text(
text = "${sneaker.brand}",
fontSize = 25.sp,
fontWeight = FontWeight.Bold
)
Text(
text = "${sneaker.model}",
fontSize = 25.sp,
fontWeight = FontWeight.Bold
)
Text(text = "Price: $${sneaker.price}", fontSize = 16.sp)
Text(text = "Description: ${sneaker.description}", fontSize = 16.sp)
Button(
colors = ButtonDefaults.buttonColors(
backgroundColor = colorResource(id = R.color.figma_blue),
contentColor = Color.White
),
onClick = {
},
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(20.dp))
) {
Text("Add to cart")
}
}
}
}

View File

@ -0,0 +1,38 @@
package com.example.android_programming.composeui.Screens.HomeScreen.FilterByBrand
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.example.android_programming.R
@Preview
@Composable
fun FilterByBrand() {
Row {
LazyRow(
modifier = Modifier
.fillMaxWidth()
.padding(0.dp, 10.dp, 0.dp, 5.dp),
horizontalArrangement = Arrangement.SpaceEvenly
){
itemsIndexed(
listOf(
ItemFilterByBrand(R.drawable.jordan),
ItemFilterByBrand(R.drawable.jordan),
ItemFilterByBrand(R.drawable.jordan),
ItemFilterByBrand(R.drawable.jordan)
)
){ _, item->
ItemRow(item = item)
}
}
}
}

View File

@ -0,0 +1,5 @@
package com.example.android_programming.composeui.Screens.HomeScreen.FilterByBrand
data class ItemFilterByBrand(
val imageId: Int,
)

View File

@ -0,0 +1,45 @@
package com.example.android_programming.composeui.Screens.HomeScreen.FilterByBrand
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.example.android_programming.R
@Composable
fun ItemRow(item: ItemFilterByBrand) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.clip(RoundedCornerShape(10.dp))
.background(colorResource(id = R.color.figma))
) {
Image(
painter = painterResource(id = item.imageId),
contentDescription = "image",
contentScale = ContentScale.Crop,
modifier = Modifier
.padding(13.dp, 3.dp, 13.dp, 3.dp)
.size(30.dp)
)
}
}
@Composable
@Preview
fun PreviewItemRow(){
ItemRow(item = ItemFilterByBrand(R.drawable.jordan))
}

View File

@ -0,0 +1,39 @@
package com.example.android_programming.composeui.Screens.HomeScreen
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
import com.example.android_programming.composeui.Screens.HomeScreen.FilterByBrand.FilterByBrand
import com.example.android_programming.composeui.Screens.HomeScreen.SearchField.SearchField
import com.example.android_programming.composeui.Screens.HomeScreen.SneakerRecyclerView.RecyclerView
import com.example.android_programming.model.Sneaker
import com.example.android_programming.businessLogic.vmodel.AppViewModelProvider
import com.example.android_programming.businessLogic.vmodel.OrderViewModel
@Composable
fun HomeScreen(navHostController: NavHostController) {
Column(
modifier = Modifier
.fillMaxSize()
.background(Color.White)
) {
RecyclerView(navHostController = navHostController)
}
}

View File

@ -0,0 +1,30 @@
package com.example.android_programming.composeui.Screens.HomeScreen
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.example.android_programming.R
@Composable
@Preview
fun Sales() {
Row(
modifier = Modifier
.padding(16.dp, 0.dp)
){
Image(
painter = painterResource(id = R.drawable.sales),
contentDescription = "image",
contentScale = ContentScale.FillWidth,
modifier = Modifier
.fillMaxWidth()
)
}
}

View File

@ -0,0 +1,79 @@
package com.example.android_programming.composeui.Screens.HomeScreen.SearchField;
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.material.Icon
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Search
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.dp
import com.example.android_programming.R
@Composable
fun SearchField(
modifier: Modifier = Modifier,
onSearch: (String) -> Unit
) {
var searchText by remember { mutableStateOf("") }
Box(
modifier = modifier
.fillMaxWidth()
.background(colorResource(id = R.color.figma))
.padding(horizontal = 16.dp, vertical = 8.dp)
) {
Row(
modifier = Modifier
.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
content = {
BasicTextField(
value = searchText,
onValueChange = {
searchText = it
onSearch(it)
},
textStyle = TextStyle(color = Color.Black),
modifier = Modifier
.weight(1f)
)
SearchIcon(
imageVector = Icons.Default.Search,
contentDescription = "Search Icon",
modifier = Modifier.size(24.dp)
)
}
)
}
}
@Composable
fun SearchIcon(
imageVector: ImageVector,
contentDescription: String,
modifier: Modifier = Modifier
) {
Icon(
imageVector = imageVector,
contentDescription = contentDescription,
modifier = modifier
.size(24.dp)
.padding(4.dp)
)
}

View File

@ -0,0 +1,129 @@
package com.example.android_programming.composeui.Screens.HomeScreen.SneakerRecyclerView
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Icon
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ShoppingCart
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
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.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
import com.example.android_programming.GlobalUser
import com.example.android_programming.R
import com.example.android_programming.model.BasketSneakers
import com.example.android_programming.model.Sneaker
import com.example.android_programming.businessLogic.vmodel.AppViewModelProvider
import com.example.android_programming.businessLogic.vmodel.BasketViewModel
import com.google.gson.Gson
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
@Composable
fun CardSneaker(item: Sneaker, navController: NavHostController, basketViewModel: BasketViewModel = viewModel(factory = AppViewModelProvider.Factory)) {
val maxWidth = (LocalConfiguration.current.screenWidthDp / 2).dp
val coroutineScope = rememberCoroutineScope()
Box(
modifier = Modifier
.padding(4.dp)
.widthIn(maxWidth)
.clickable {
val sneakerItemString = Gson().toJson(item)
navController.navigate("aboutSneaker/${sneakerItemString}")
}
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.clip(RoundedCornerShape(10.dp))
.background(colorResource(id = R.color.figma))
.widthIn(maxWidth)
) {
Image(
painter = painterResource(id = item.photo),
contentDescription = "image",
contentScale = ContentScale.FillWidth,
modifier = Modifier
.size(100.dp)
)
Column {
Row(
modifier = Modifier
.widthIn(maxWidth),
horizontalArrangement = Arrangement.SpaceBetween,
) {
Column(
horizontalAlignment = Alignment.Start,
modifier = Modifier
.padding(10.dp, 0.dp)
) {
Row {
item.brand?.let { Text(text = "$it ") }
item.model?.let { Text(text = it) }
}
Text(text = item.price.toString(), color = Color.Red)
}
Column(
modifier = Modifier
.padding(10.dp)
) {
Button(
colors = ButtonDefaults.buttonColors(
backgroundColor = colorResource(id = R.color.figma_blue),
contentColor = Color.White
),
onClick = {
val user = GlobalUser.getInstance().getUser()
if(user == null){
navController.navigate("login")
}else{
coroutineScope.launch {
val userBasketId: Int = basketViewModel.getUserBasketId(user.userId!!).first()
basketViewModel.addToBasket(BasketSneakers(userBasketId, item.sneakerId!!, 1))
}
}
},
modifier = Modifier
.size(50.dp, 30.dp)
.clip(RoundedCornerShape(10.dp))
) {
Icon(
imageVector = Icons.Default.ShoppingCart,
contentDescription = null
)
}
}
}
}
}
}
}

View File

@ -0,0 +1,81 @@
package com.example.android_programming.composeui.Screens.HomeScreen.SneakerRecyclerView
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
import androidx.paging.compose.collectAsLazyPagingItems
import androidx.paging.compose.itemKey
import com.example.android_programming.R
import com.example.android_programming.model.Sneaker
import com.example.android_programming.businessLogic.vmodel.AppViewModelProvider
import com.example.android_programming.businessLogic.vmodel.OrderViewModel
import com.example.android_programming.businessLogic.vmodel.SneakerViewModel
import com.example.android_programming.composeui.Screens.HomeScreen.FilterByBrand.FilterByBrand
import com.example.android_programming.composeui.Screens.HomeScreen.Sales
import com.example.android_programming.composeui.Screens.HomeScreen.SearchField.SearchField
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.serialization.builtins.serializer
@Composable
fun RecyclerView(navHostController: NavHostController, sneakerViewModel: SneakerViewModel = viewModel(factory = AppViewModelProvider.Factory)) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(bottom = 60.dp)
) {
Row {
// Поле для поиска
SearchField(
modifier = Modifier
.fillMaxWidth()
.padding(20.dp, 20.dp, 20.dp, 10.dp)
.clip(RoundedCornerShape(10.dp))
) { searchText ->
// Обработка введенного текста поиска
}
}
Sales()
FilterByBrand()
val sneakerLazyPagingItems = sneakerViewModel.sneakerList.collectAsLazyPagingItems()
LazyVerticalGrid(
modifier = Modifier
.fillMaxSize(),
columns = GridCells.Fixed(2)
) {
items(
count = sneakerLazyPagingItems.itemCount,
key = sneakerLazyPagingItems.itemKey { sneaker -> sneaker.sneakerId!! }
) { index: Int ->
val sneaker: Sneaker? = sneakerLazyPagingItems[index]
if (sneaker != null) {
CardSneaker(sneaker, navHostController)
}
}
}
}
}

View File

@ -0,0 +1,70 @@
package com.example.android_programming.composeui.Screens.MyOrderScreen
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.example.android_programming.GlobalUser
import com.example.android_programming.model.Order
import com.example.android_programming.businessLogic.vmodel.AppViewModelProvider
import com.example.android_programming.businessLogic.vmodel.OrderViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
@Composable
fun MyOrderScreen(orderViewModel: OrderViewModel = viewModel(factory = AppViewModelProvider.Factory)) {
val userId = GlobalUser.getInstance().getUser()?.userId
var usersOrder by remember { mutableStateOf<List<Order>>(emptyList()) }
LaunchedEffect(userId) {
usersOrder = orderViewModel.getOrderList(userId!!).first()
}
Column(
modifier = Modifier
.padding(bottom = 50.dp)
.fillMaxSize()
.background(Color.White)
.verticalScroll(rememberScrollState())
){
Text(
text = "My order",
style = MaterialTheme.typography.h5,
fontWeight = FontWeight.Bold,
modifier = Modifier
.padding(10.dp, 10.dp)
)
Row {
Column(
modifier = Modifier
.fillMaxSize()
) {
if (usersOrder != null) {
for (item in usersOrder) {
OrderCard(item)
}
}
}
}
}
}

View File

@ -0,0 +1,97 @@
package com.example.android_programming.composeui.Screens.MyOrderScreen
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.KeyboardArrowDown
import androidx.compose.material.icons.filled.KeyboardArrowLeft
import androidx.compose.material.icons.filled.KeyboardArrowRight
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.example.android_programming.R
import com.example.android_programming.model.Order
import com.example.android_programming.model.Sneaker
import com.example.android_programming.businessLogic.vmodel.AppViewModelProvider
import com.example.android_programming.businessLogic.vmodel.OrderViewModel
import kotlinx.coroutines.flow.first
import java.util.Date
@Composable
fun OrderCard(order: Order, orderViewModel: OrderViewModel = viewModel(factory = AppViewModelProvider.Factory)){
var sneakers by remember { mutableStateOf<List<Sneaker>>(emptyList()) }
LaunchedEffect(order.orderId) {
sneakers = orderViewModel.getOrderWithSneakers(order.orderId!!).first()
}
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp, 16.dp, 16.dp, 0.dp)
.clip(RoundedCornerShape(16.dp))
.background(colorResource(id = R.color.figma))
){
Column(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
verticalArrangement = Arrangement.Center
){
Text("${order.orderId}")
Text("${Date(order.date)}")
Row(){
if (sneakers != null) {
for(sneaker in sneakers){
Image(
contentScale = ContentScale.FillBounds,
painter = painterResource(id = sneaker.photo),
contentDescription = null,
modifier = Modifier
.size(70.dp)
.padding(0.dp, 10.dp, 10.dp, 10.dp)
)
}
}
}
Button(
colors = ButtonDefaults.buttonColors(
backgroundColor = colorResource(id = R.color.figma_blue),
contentColor = Color.White
),
onClick = {
orderViewModel.deleteOrder(order.orderId!!)
},
modifier = Modifier
.fillMaxWidth()
.padding(16.dp, 16.dp, 16.dp, 0.dp)
) {
Text("Cancel")
}
}
}
}

View File

@ -0,0 +1,119 @@
package com.example.android_programming.composeui.Screens.OrderScreen
import android.annotation.SuppressLint
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.KeyboardArrowLeft
import androidx.compose.material.icons.filled.KeyboardArrowRight
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
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.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.example.android_programming.GlobalUser
import com.example.android_programming.R
import com.example.android_programming.model.Sneaker
import com.example.android_programming.businessLogic.vmodel.AppViewModelProvider
import com.example.android_programming.businessLogic.vmodel.BasketViewModel
import com.example.android_programming.businessLogic.vmodel.OrderViewModel
import com.example.android_programming.model.BasketSneakers
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
@SuppressLint("UnrememberedMutableState")
@Composable
fun CardSneakerLike(item: Sneaker, basketViewModel: BasketViewModel = viewModel(factory = AppViewModelProvider.Factory)) {
val userId = GlobalUser.getInstance().getUser()?.userId!!
val quantityState by basketViewModel.getQuantityState(userId, item.sneakerId!!).collectAsState()
val scope = rememberCoroutineScope()
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp, 5.dp)
.clip(RoundedCornerShape(10.dp))
.background(colorResource(id = R.color.figma)),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
Image(
painter = painterResource(id = item.photo),
contentDescription = "image",
contentScale = ContentScale.FillWidth,
modifier = Modifier
.size(70.dp)
.padding(10.dp)
.clip(RoundedCornerShape(10.dp))
)
Column(
modifier = Modifier
.weight(1f)
.padding(start = 16.dp)
) {
item.brand?.let { Text(text = it, fontSize = 20.sp) }
Text(text = "${item.price} USD", color = Color.Red, fontSize = 16.sp)
}
Column {
Button(
colors = ButtonDefaults.buttonColors(
backgroundColor = colorResource(id = R.color.figma_blue),
contentColor = Color.White
),
onClick = {
scope.launch {
basketViewModel.deleteSneakerFromBasket(basketViewModel.getUserBasketId(GlobalUser.getInstance().getUser()?.userId!!).first(), item.sneakerId!!)
}
// runBlocking {
// launch(Dispatchers.Default) {
// basketViewModel.deleteSneakerFromBasket(basketViewModel.getUserBasketId(GlobalUser.getInstance().getUser()?.userId!!), item.sneakerId!!)
// }
// }
},
modifier = Modifier
.padding(end = 16.dp)
) {
Icon(imageVector = Icons.Default.Delete, contentDescription = "delete")
}
}
Column {
Row {
IconButton(onClick = { basketViewModel.decrementQuantity(userId ,item.sneakerId!!) }) {
Icon(Icons.Default.KeyboardArrowLeft, contentDescription = "Decrease Quantity")
}
Text("$quantityState")
IconButton(onClick = { basketViewModel.incrementQuantity(userId, item.sneakerId!!) }) {
Icon(Icons.Default.KeyboardArrowRight, contentDescription = "Increase Quantity")
}
}
}
}
}

View File

@ -0,0 +1,132 @@
package com.example.android_programming.composeui.Screens.OrderScreen
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.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.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.Text
import androidx.compose.material.TextField
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.example.android_programming.R
import com.example.android_programming.businessLogic.vmodel.OrderViewModel
@Composable
fun DeliveryAddress(orderViewModel: OrderViewModel) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
.clip(RoundedCornerShape(16.dp))
.background(colorResource(id = R.color.figma)),
horizontalArrangement = Arrangement.Center
) {
Column(
modifier = Modifier
.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(text = "Delivery Address", fontSize = 24.sp, fontWeight = FontWeight.Bold)
Spacer(modifier = Modifier.height(16.dp))
TextField(
value = orderViewModel.city.value,
onValueChange = { orderViewModel.city.value = it },
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.border(1.dp, Color.Gray, RoundedCornerShape(4.dp)),
singleLine = true,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Next
),
keyboardActions = KeyboardActions(
onNext = {
}
),
placeholder = {
Text(
text = "City",
style = TextStyle(fontSize = 12.sp)
)
}
)
Spacer(modifier = Modifier.height(16.dp))
TextField(
value = orderViewModel.street.value,
onValueChange = { orderViewModel.street.value = it },
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.border(1.dp, Color.Gray, RoundedCornerShape(4.dp)),
singleLine = true,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Next
),
keyboardActions = KeyboardActions(
onNext = {
}
),
placeholder = {
Text(
text = "Street",
style = TextStyle(fontSize = 12.sp)
)
}
)
Spacer(modifier = Modifier.height(16.dp))
TextField(
value = orderViewModel.house.value,
onValueChange = { orderViewModel.house.value = it },
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.border(1.dp, Color.Gray, RoundedCornerShape(4.dp)),
singleLine = true,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Next
),
keyboardActions = KeyboardActions(
onNext = {
}
),
placeholder = {
Text(
text = "House",
style = TextStyle(fontSize = 12.sp)
)
}
)
}
}
}

View File

@ -0,0 +1,84 @@
package com.example.android_programming.composeui.Screens.OrderScreen
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
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.res.colorResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
import com.example.android_programming.GlobalUser
import com.example.android_programming.R
import com.example.android_programming.model.Sneaker
import com.example.android_programming.businessLogic.vmodel.AppViewModelProvider
import com.example.android_programming.businessLogic.vmodel.BasketViewModel
import com.example.android_programming.businessLogic.vmodel.OrderViewModel
import com.example.android_programming.model.BasketSneakers
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
@Composable
fun OrderScreen(navHostController: NavHostController, basketViewModel: BasketViewModel = viewModel(factory = AppViewModelProvider.Factory), orderViewModel: OrderViewModel = viewModel(factory = AppViewModelProvider.Factory)) {
val scope = rememberCoroutineScope()
Column(
modifier = Modifier
.fillMaxSize()
.background(Color.White)
.padding(bottom = 60.dp)
.verticalScroll(rememberScrollState())
){
DeliveryAddress(orderViewModel)
val userId = GlobalUser.getInstance().getUser()?.userId
if (userId != null) {
basketViewModel.fetchBasketSneakers(userId!!)
val sneakerList: List<Sneaker>? = basketViewModel.sneakerList.collectAsState(null).value
if (sneakerList != null) {
orderViewModel.updateSelectedItems(sneakerList)
ShoppingList(sneakerList)
SubTotal(orderViewModel)
}
}
Button(
colors = ButtonDefaults.buttonColors(
backgroundColor = colorResource(id = R.color.figma_blue),
contentColor = Color.White
),
onClick = {
if(GlobalUser.getInstance().getUser() != null){
orderViewModel.createOrder()
scope.launch {
basketViewModel.deleteAllSneakerFromBasket(basketViewModel.getUserBasketId(userId!!).first())
}
navHostController.navigate("home")
}else{
navHostController.navigate("login")
}
},
modifier = Modifier
.fillMaxWidth()
.padding(16.dp, 0.dp, 16.dp, 16.dp)
) {
Text("Confirm order")
}
}
}

View File

@ -0,0 +1,18 @@
package com.example.android_programming.composeui.Screens.OrderScreen
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.runtime.Composable
import com.example.android_programming.model.Sneaker
import com.example.android_programming.businessLogic.vmodel.OrderViewModel
@Composable
fun ShoppingList(list : List<Sneaker>) {
Row {
Column {
for(item in list){
CardSneakerLike(item = item)
}
}
}
}

View File

@ -0,0 +1,91 @@
package com.example.android_programming.composeui.Screens.OrderScreen
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.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.example.android_programming.GlobalUser
import com.example.android_programming.R
import com.example.android_programming.businessLogic.vmodel.OrderViewModel
@Composable
fun SubTotal(orderViewModel: OrderViewModel) {
val userId = GlobalUser.getInstance().getUser()?.userId!!
orderViewModel.updateSubTotal(userId)
val subTotal = orderViewModel.subTotal.value
Column(
modifier = Modifier
.padding(16.dp)
.clip(RoundedCornerShape(16.dp))
.background(colorResource(id = R.color.figma))
){
Row(
modifier = Modifier
.padding(10.dp, 5.dp)
.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
){
Row(
modifier = Modifier.weight(1f),
horizontalArrangement = Arrangement.Start
){
Text(text = "Sub total", fontSize = 15.sp)
}
Row(
modifier = Modifier.weight(1f),
horizontalArrangement = Arrangement.End
){
Text(text = "$subTotal $", fontSize = 15.sp)
}
}
Row(
modifier = Modifier
.padding(10.dp, 5.dp)
.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
){
Row(
modifier = Modifier.weight(1f),
horizontalArrangement = Arrangement.Start
){
Text(text = "Taxes", fontSize = 15.sp)
}
Row(
modifier = Modifier.weight(1f),
horizontalArrangement = Arrangement.End
){
Text(text = "${"%.2f".format(subTotal * 0.05)} $", fontSize = 15.sp)
}
}
Row(
modifier = Modifier
.padding(10.dp, 5.dp)
.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
){
Row(
modifier = Modifier.weight(1f),
horizontalArrangement = Arrangement.Start
){
Text(text = "Total", fontSize = 15.sp)
}
Row(
modifier = Modifier.weight(1f),
horizontalArrangement = Arrangement.End
){
Text(text = "${"%.2f".format(subTotal + subTotal * 0.05)} $", fontSize = 15.sp)
}
}
}
}

View File

@ -0,0 +1,44 @@
package com.example.android_programming.composeui.Screens.ProfileScreen.Profile
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.padding
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController
import com.example.android_programming.GlobalUser
import com.example.android_programming.R
@Composable
fun Person(navHostController: NavHostController) {
Column(
modifier = Modifier
.background(Color.White)
.fillMaxSize(),
verticalArrangement = Arrangement.Center
) {
Button(
onClick = {
GlobalUser.getInstance().setUser(null)
navHostController.navigate("profile")
},
colors = ButtonDefaults.buttonColors(
backgroundColor = colorResource(id = R.color.white),
contentColor = Color.Black
),
modifier = Modifier
.padding(16.dp, 0.dp)
) {
Text("Exit")
}
ProfileCard(navHostController)
}
}

View File

@ -0,0 +1,86 @@
package com.example.android_programming.composeui.Screens.ProfileScreen.Profile
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavHostController
import com.example.android_programming.GlobalUser
import com.example.android_programming.R
@Composable
fun ProfileCard(navHostController: NavHostController) {
val globalUser = GlobalUser.getInstance().getUser()
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
.clip(RoundedCornerShape(16.dp))
.background(colorResource(id = R.color.figma))
){
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
){
Image(
contentScale = ContentScale.Crop,
painter = painterResource(id = R.drawable.shailushai),
contentDescription = null,
modifier = Modifier
.size(150.dp)
.border(2.dp, Color.White, CircleShape)
.padding(16.dp)
.clip(CircleShape)
)
if (globalUser != null) {
Text(
text = "${globalUser.name} ${globalUser.surname}",
fontSize = 18.sp,
fontWeight = FontWeight.Bold
)
Text(
text = globalUser.email,
fontSize = 16.sp,
color = Color.Gray
)
}
Button(
colors = ButtonDefaults.buttonColors(
backgroundColor = colorResource(id = R.color.figma_blue),
contentColor = Color.White
),
onClick = {
navHostController.navigate("myorder")
},
modifier = Modifier
.fillMaxWidth()
.padding(16.dp, 16.dp, 16.dp, 0.dp)
) {
Text("My order")
}
}
}
}

View File

@ -0,0 +1,29 @@
package com.example.android_programming.composeui.Screens.ProfileScreen.Profile;
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
import com.example.android_programming.GlobalUser
import com.example.android_programming.composeui.Screens.ProfileScreen.SignIn.LoginScreen
import com.example.android_programming.model.Basket
import com.example.android_programming.businessLogic.vmodel.AppViewModelProvider
import com.example.android_programming.businessLogic.vmodel.BasketViewModel
@Composable
fun ProfileScreen(navController: NavHostController) {
val globalUser: GlobalUser = GlobalUser.getInstance()
if(globalUser.getUser() != null){
Person(navController)
}else{
LoginScreen(navController = navController)
}
}
@Composable
@Preview
fun ProfileScreenPreview(){
val navController = rememberNavController()
ProfileScreen(navController = navController)
}

View File

@ -0,0 +1,175 @@
package com.example.android_programming.composeui.Screens.ProfileScreen.SignIn
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.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.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.ClickableText
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Text
import androidx.compose.material.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
import com.example.android_programming.GlobalUser
import com.example.android_programming.R
import com.example.android_programming.model.Basket
import com.example.android_programming.businessLogic.vmodel.AppViewModelProvider
import com.example.android_programming.businessLogic.vmodel.BasketViewModel
import com.example.android_programming.businessLogic.vmodel.UserViewModel
import com.example.android_programming.composeui.Screens.ErrorSnackbar
@Composable
fun SignInCard(navController: NavHostController, userViewModel: UserViewModel = viewModel(factory = AppViewModelProvider.Factory), basketViewModel: BasketViewModel = viewModel(factory = AppViewModelProvider.Factory)) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
.clip(RoundedCornerShape(16.dp))
.background(colorResource(id = R.color.figma))
){
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
){
var isEmailValid by remember { mutableStateOf(true) }
var isPasswordValid by remember { mutableStateOf(true) }
Text(
text = "Sign In",
fontSize = 24.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier
.padding(16.dp)
)
TextField(
value = userViewModel.email.value,
onValueChange = {
userViewModel.email.value = it
isEmailValid = userViewModel.isValidEmail(it)},
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.padding(16.dp, 0.dp)
.border(1.dp, Color.Gray, RoundedCornerShape(4.dp)),
singleLine = true,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Next
),
keyboardActions = KeyboardActions(
onNext = {
}
),
placeholder = {
Text(
text = "Email",
style = TextStyle(fontSize = 12.sp)
)
}
)
if (!isEmailValid) {
Text(
text = "Invalid email format",
color = Color.Red,
style = TextStyle(fontSize = 12.sp)
)
}
Spacer(modifier = Modifier.height(16.dp))
TextField(
value = userViewModel.password.value,
onValueChange = {
userViewModel.password.value = it
isPasswordValid = it.isNotEmpty()
},
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.padding(16.dp, 0.dp)
.border(1.dp, Color.Gray, RoundedCornerShape(4.dp)),
singleLine = true,
visualTransformation = PasswordVisualTransformation(),
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Next
),
keyboardActions = KeyboardActions(
onNext = {
}
),
placeholder = {
Text(
text = "Password",
style = TextStyle(fontSize = 12.sp)
)
}
)
if (!isPasswordValid) {
Text(
text = "Password is required",
color = Color.Red,
style = TextStyle(fontSize = 12.sp)
)
}
Button(
colors = ButtonDefaults.buttonColors(
backgroundColor = colorResource(id = R.color.figma_blue),
contentColor = Color.White
),
onClick = {
userViewModel.authUser()
navController.navigate("profile")
},
modifier = Modifier
.fillMaxWidth()
.padding(16.dp, 16.dp, 16.dp, 0.dp)
) {
Text("Sign In")
}
ClickableText(
text = AnnotatedString("You do not have an account? Register!"),
modifier = Modifier
.padding(0.dp, 0.dp, 0.dp, 16.dp),
onClick = {
navController.navigate("signup")
}
)
}
}
}

View File

@ -0,0 +1,21 @@
package com.example.android_programming.composeui.Screens.ProfileScreen.SignIn
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.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.navigation.NavHostController
@Composable
fun LoginScreen(navController: NavHostController) {
Column(modifier = Modifier
.fillMaxSize()
.background(Color.White),
verticalArrangement = Arrangement.Center
) {
SignInCard(navController)
}
}

View File

@ -0,0 +1,191 @@
package com.example.android_programming.composeui.Screens.ProfileScreen.SignUp
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.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.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Text
import androidx.compose.material.TextField
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
import com.example.android_programming.R
import com.example.android_programming.businessLogic.vmodel.AppViewModelProvider
import com.example.android_programming.businessLogic.vmodel.UserViewModel
@Composable
fun SignUpCard(navHostController: NavHostController, userViewModel: UserViewModel = viewModel(factory = AppViewModelProvider.Factory)) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
.clip(RoundedCornerShape(16.dp))
.background(colorResource(id = R.color.figma))
){
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
){
Text(
text = "Sign Up",
fontSize = 24.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier
.padding(16.dp)
)
Spacer(modifier = Modifier.height(16.dp))
TextField(
value = userViewModel.name.value,
onValueChange = { userViewModel.name.value = it },
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.padding(16.dp, 0.dp)
.border(1.dp, Color.Gray, RoundedCornerShape(4.dp)),
singleLine = true,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Next
),
keyboardActions = KeyboardActions(
onNext = {
}
),
placeholder = {
Text(
text = "Name",
style = TextStyle(fontSize = 12.sp)
)
}
)
Spacer(modifier = Modifier.height(16.dp))
TextField(
value = userViewModel.surname.value,
onValueChange = { userViewModel.surname.value = it },
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.padding(16.dp, 0.dp)
.border(1.dp, Color.Gray, RoundedCornerShape(4.dp)),
singleLine = true,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Next
),
keyboardActions = KeyboardActions(
onNext = {
}
),
placeholder = {
Text(
text = "Surname",
style = TextStyle(fontSize = 12.sp)
)
}
)
Spacer(modifier = Modifier.height(16.dp))
TextField(
value = userViewModel.email.value,
onValueChange = { userViewModel.email.value = it },
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.padding(16.dp, 0.dp)
.border(1.dp, Color.Gray, RoundedCornerShape(4.dp)),
singleLine = true,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Next
),
keyboardActions = KeyboardActions(
onNext = {
}
),
placeholder = {
Text(
text = "Email",
style = TextStyle(fontSize = 12.sp)
)
}
)
Spacer(modifier = Modifier.height(16.dp))
TextField(
value = userViewModel.password.value,
onValueChange = { userViewModel.password.value = it },
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.padding(16.dp, 0.dp)
.border(1.dp, Color.Gray, RoundedCornerShape(4.dp)),
singleLine = true,
visualTransformation = PasswordVisualTransformation(),
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Next
),
keyboardActions = KeyboardActions(
onNext = {
}
),
placeholder = {
Text(
text = "Password",
style = TextStyle(fontSize = 12.sp)
)
}
)
Button(
colors = ButtonDefaults.buttonColors(
backgroundColor = colorResource(id = R.color.figma_blue),
contentColor = Color.White
),
onClick = {
userViewModel.createUser()
navHostController.navigate("login")
},
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
) {
Text("Sign Up")
}
}
}
}

View File

@ -0,0 +1,21 @@
package com.example.android_programming.composeui.Screens.ProfileScreen.SignUp
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.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.navigation.NavHostController
@Composable
fun SignUpScreen(navHostController: NavHostController) {
Column(modifier = Modifier
.fillMaxSize()
.background(Color.White),
verticalArrangement = Arrangement.Center
) {
SignUpCard(navHostController)
}
}

View File

@ -0,0 +1,91 @@
package com.example.android_programming.database
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.sqlite.db.SupportSQLiteDatabase
import com.example.android_programming.R
import com.example.android_programming.database.dao.BasketDao
import com.example.android_programming.database.dao.OrderDao
import com.example.android_programming.database.dao.SneakerDao
import com.example.android_programming.database.dao.UserDao
import com.example.android_programming.database.dao.RemoteKeysDao
import com.example.android_programming.model.RemoteKeys
import com.example.android_programming.model.Basket
import com.example.android_programming.model.BasketSneakers
import com.example.android_programming.model.Order
import com.example.android_programming.model.OrderSneaker
import com.example.android_programming.model.Sneaker
import com.example.android_programming.model.User
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@Database(entities = [Sneaker::class, User::class, Order::class, OrderSneaker::class, Basket::class, BasketSneakers::class, RemoteKeys::class], version = 7)
abstract class AppDatabase : RoomDatabase() {
abstract fun sneakerDao(): SneakerDao
abstract fun userDao(): UserDao
abstract fun orderDao(): OrderDao
abstract fun basketDao(): BasketDao
abstract fun remoteKeysDao(): RemoteKeysDao
companion object {
private const val DB_NAME: String = "my-db"
@Volatile
private var INSTANCE: AppDatabase? = null
suspend fun populateDatabase() {
INSTANCE?.let { database ->
// User
val userDao = database.userDao()
val user1 = User(null, "Artem", "Emelyanov", "artem@mail.ru", "123", "ADMIN")
val user2 = User(null, "Danil", "Markov", "danil@mail.ru", "123", "USER")
val user3 = User(null, "Viktoria", "Presnyakova", "vika@mail.ru", "123", "USER")
userDao.createUser(user1)
userDao.createUser(user2)
userDao.createUser(user3)
// Sneaker
val sneakerDao = database.sneakerDao()
val sneaker1 = Sneaker(null, "Nike", "Air Force 1", "nice", 159.99, R.drawable.img_1)
val sneaker2 = Sneaker(null, "Adidas", "ZX 750", "beautiful", 169.99, R.drawable.img_2)
val sneaker3 = Sneaker(null, "Reebok", "Classic", "amazing", 179.99, R.drawable.img_3)
val sneaker4 = Sneaker(null, "Puma", "Classic", "normal", 189.99, R.drawable.img_4)
sneakerDao.insert(sneaker1)
sneakerDao.insert(sneaker2)
sneakerDao.insert(sneaker3)
sneakerDao.insert(sneaker4)
// Order
val basketDao = database.basketDao()
val basket1 = Basket(1,1)
val basket2 = Basket(2,2)
val basket3 = Basket(3,3)
basketDao.createBasket(basket1)
basketDao.createBasket(basket2)
basketDao.createBasket(basket3)
}
}
fun getInstance(appContext: Context): AppDatabase {
return INSTANCE ?: synchronized(this) {
Room.databaseBuilder(
appContext,
AppDatabase::class.java,
DB_NAME
)
.addCallback(object : Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
// CoroutineScope(Dispatchers.IO).launch {
// populateDatabase()
// }
}
})
.fallbackToDestructiveMigration()
.build()
.also { INSTANCE = it }
}
}
}
}

View File

@ -0,0 +1,47 @@
package com.example.android_programming.database.dao
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
import com.example.android_programming.model.Basket
import com.example.android_programming.model.BasketSneakers
import com.example.android_programming.model.BasketWithSneakers
import kotlinx.coroutines.flow.Flow
@Dao
interface BasketDao {
@Insert
suspend fun createBasket(basket: Basket):Long
@Insert
suspend fun insertBasketSneaker(basketSneaker: BasketSneakers)
@Query("SELECT * FROM 'Basket' WHERE creatorUserId = :id")
fun getBasketWithSneakers(id: Int): Flow<BasketWithSneakers>
@Query("SELECT * FROM 'Basket'")
fun getAllBasket(): Flow<List<Basket>>
@Delete
suspend fun delete(basket: Basket)
@Query("DELETE FROM 'BasketSneakers' WHERE basketId = :basketId AND sneakerId = :sneakerId")
suspend fun removeSneakerFromBasket(basketId: Int, sneakerId: Int)
@Query("UPDATE 'BasketSneakers' SET quantity = :quantity WHERE basketId = :basketId AND sneakerId = :sneakerId")
suspend fun updateSneakerQuantity(basketId: Int, sneakerId: Int, quantity: Int)
@Query("UPDATE 'BasketSneakers' SET quantity = quantity + 1 WHERE basketId = :basketId AND sneakerId = :sneakerId")
suspend fun incrementSneakerQuantity(basketId: Int, sneakerId: Int)
@Query("UPDATE 'BasketSneakers' SET quantity = quantity - 1 WHERE basketId = :basketId AND sneakerId = :sneakerId")
suspend fun decrementSneakerQuantity(basketId: Int, sneakerId: Int)
@Query("SELECT quantity FROM 'BasketSneakers' WHERE basketId = :basketId AND sneakerId = :sneakerId")
suspend fun getQuantity(basketId: Int, sneakerId: Int): Int?
@Query("SELECT * FROM 'BasketSneakers' WHERE basketId = :basketId AND sneakerId = :sneakerId")
suspend fun getSneaker(basketId: Int, sneakerId: Int): BasketSneakers?
@Query("SELECT SUM(price * quantity) FROM 'BasketSneakers' bs JOIN 'Sneaker' s ON bs.sneakerId = s.sneakerId WHERE bs.basketId = :userId")
suspend fun getTotalPriceForUser(userId: Int): Double?
}

View File

@ -0,0 +1,33 @@
package com.example.android_programming.database.dao
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
import com.example.android_programming.model.Order
import com.example.android_programming.model.OrderSneaker
import com.example.android_programming.model.OrderWithSneakers
import com.example.android_programming.model.UserWithOrder
import kotlinx.coroutines.flow.Flow
@Dao
interface OrderDao {
@Insert
suspend fun createOrder(order: Order): Long
@Insert
suspend fun insertOrderSneaker(orderSneaker: OrderSneaker)
@Query("SELECT * FROM 'Order' WHERE orderId = :id")
fun getOrderWithSneakers(id: Int): Flow<OrderWithSneakers>
@Query("SELECT * FROM `Order`")
fun getAllOrder(): Flow<List<Order>>
@Delete
suspend fun delete(order: Order)
@Query("SELECT * FROM users WHERE userId =:id")
fun getUserOrders(id: Int) : Flow<UserWithOrder>
}

View File

@ -0,0 +1,18 @@
package com.example.android_programming.database.dao
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.example.android_programming.model.RemoteKeyType
import com.example.android_programming.model.RemoteKeys
@Dao
interface RemoteKeysDao {
@Query("SELECT * FROM remote_keys WHERE entityId = :entityId AND type = :type")
suspend fun getRemoteKeys(entityId: Int, type: RemoteKeyType): RemoteKeys?
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertAll(remoteKey: List<RemoteKeys>)
@Query("DELETE FROM remote_keys WHERE type = :type")
suspend fun clearRemoteKeys(type: RemoteKeyType)
}

View File

@ -0,0 +1,31 @@
package com.example.android_programming.database.dao
import androidx.paging.PagingSource
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Update
import com.example.android_programming.model.Sneaker
import kotlinx.coroutines.flow.Flow
@Dao
interface SneakerDao {
@Insert
suspend fun insert(vararg sneaker: Sneaker)
@Update
suspend fun update(sneaker: Sneaker)
@Delete
suspend fun delete(sneaker: Sneaker)
@Query("SELECT*FROM Sneaker")
fun getAllSneakersPaged(): PagingSource<Int, Sneaker>
@Query("select * from Sneaker")
fun getAll(): PagingSource<Int, Sneaker>
@Query("SELECT * FROM Sneaker WHERE sneakerId = :id")
suspend fun getSneakerById(id: Int): Sneaker
@Query("DELETE FROM Sneaker")
suspend fun deleteAll()
}

View File

@ -0,0 +1,28 @@
package com.example.android_programming.database.dao
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Update
import com.example.android_programming.model.User
import com.example.android_programming.model.UserWithOrder
import kotlinx.coroutines.flow.Flow
@Dao
interface UserDao {
@Insert
suspend fun createUser(user: User)
@Update
suspend fun updateUser(user: User)
@Delete
suspend fun deleteUser(user: User)
@Query("SELECT * FROM users WHERE userId = :id")
suspend fun getUserById(id: Int): User
@Query("SELECT * FROM users WHERE email = :email")
suspend fun getUserByEmail(email: String): User
}

View File

@ -0,0 +1,27 @@
package com.example.android_programming.database.repository
import com.example.android_programming.businessLogic.repo.BasketRepository
import com.example.android_programming.database.dao.BasketDao
import com.example.android_programming.model.Basket
import com.example.android_programming.model.BasketSneakers
import com.example.android_programming.model.BasketWithSneakers
import com.example.android_programming.model.Sneaker
import kotlinx.coroutines.flow.Flow
//class BasketRepoImpl(private val basketDao: BasketDao): BasketRepository {
//// override suspend fun createBasket(basket: Basket): Long = basketDao.createBasket(basket)
//// override suspend fun removeSneakerFromBasket(basketId: Int, sneakerId: Int) = basketDao.removeSneakerFromBasket(basketId, sneakerId)
//// override suspend fun updateSneakerQuantity(basketId: Int, sneakerId: Int, quantity: Int) = basketDao.updateSneakerQuantity(basketId, sneakerId, quantity)
//// override suspend fun incrementSneakerQuantity(basketId: Int, sneakerId: Int) = basketDao.incrementSneakerQuantity(basketId, sneakerId)
//// override suspend fun decrementSneakerQuantity(basketId: Int, sneakerId: Int) = basketDao.decrementSneakerQuantity(basketId, sneakerId)
// override suspend fun insertBasketSneaker(basketSneaker: BasketSneakers) = basketDao.insertBasketSneaker(basketSneaker)
// override suspend fun getBasketWithSneakers(id: Int): Flow<List<Sneaker>> {
// return basketDao
// }
//// override fun getBasketWithSneakers(id: Int): Flow<BasketWithSneakers> = basketDao.getBasketWithSneakers(id)
//// override fun getAllBasket(): Flow<List<Basket>> = basketDao.getAllBasket()
//// override suspend fun delete(basket: Basket) = basketDao.delete(basket)
//// override suspend fun getQuantity(basketId: Int, sneakerId: Int): Int? = basketDao.getQuantity(basketId, sneakerId)
//// override suspend fun getSneaker(basketId: Int, sneakerId: Int): BasketSneakers? = basketDao.getSneaker(basketId, sneakerId)
//// override suspend fun getTotalPriceForUser(userId: Int): Double? = basketDao.getTotalPriceForUser(userId)
//}

View File

@ -0,0 +1,32 @@
//package com.example.android_programming.database.repository
//
//import com.example.android_programming.businessLogic.repo.OrderRepository
//import com.example.android_programming.database.dao.OrderDao
//import com.example.android_programming.model.Order
//import com.example.android_programming.model.OrderSneaker
//import com.example.android_programming.model.OrderWithSneakers
//import com.example.android_programming.model.Sneaker
//import com.example.android_programming.model.UserWithOrder
//import kotlinx.coroutines.flow.Flow
//
//class OrderRepoImpl(private val orderDao: OrderDao) : OrderRepository {
//
// override suspend fun createOrder(order: Order): Long = orderDao.createOrder(order)
//
// override suspend fun insertOrderSneaker(orderSneaker: OrderSneaker) = orderDao.insertOrderSneaker(orderSneaker)
// override suspend fun getSneakerFromOrder(id: Int): Flow<List<Sneaker>> {
// TODO("Not yet implemented")
// }
//
// override suspend fun getUserOrders(id: Int): Flow<List<Order>> {
// TODO("Not yet implemented")
// }
//
//// override suspend fun delete(order: Order) = orderDao.delete(order)
////
//// override fun getOrderWithSneakers(id: Int): Flow<OrderWithSneakers> = orderDao.getOrderWithSneakers(id)
////
//// override fun getAllOrder(): Flow<List<Order>> = orderDao.getAllOrder()
////
//// override fun getUserOrders(id: Int): Flow<UserWithOrder> = orderDao.getUserOrders(id)
//}

View File

@ -0,0 +1,17 @@
package com.example.android_programming.database.repository
import com.example.android_programming.businessLogic.repo.RemoteKeyRepository
import com.example.android_programming.database.dao.RemoteKeysDao
import com.example.android_programming.model.RemoteKeyType
import com.example.android_programming.model.RemoteKeys
class RemoteKeysRepositoryImpl(private val remoteKeysDao: RemoteKeysDao) : RemoteKeyRepository {
override suspend fun getAllRemoteKeys(id: Int, type: RemoteKeyType) =
remoteKeysDao.getRemoteKeys(id, type)
override suspend fun createRemoteKeys(remoteKeys: List<RemoteKeys>) =
remoteKeysDao.insertAll(remoteKeys)
override suspend fun deleteRemoteKey(type: RemoteKeyType) =
remoteKeysDao.clearRemoteKeys(type)
}

View File

@ -0,0 +1,43 @@
package com.example.android_programming.database.repository
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import androidx.paging.PagingSource
import com.example.android_programming.di.AppContainer
import com.example.android_programming.businessLogic.repo.SneakerRepository
import com.example.android_programming.database.dao.SneakerDao
import com.example.android_programming.model.Sneaker
import kotlinx.coroutines.flow.Flow
class SneakerRepoImpl(private val sneakerDao: SneakerDao) : SneakerRepository {
override suspend fun insertSneaker(sneaker: Sneaker) = sneakerDao.insert(sneaker)
override suspend fun updateSneaker(sneaker: Sneaker) = sneakerDao.update(sneaker)
override suspend fun deleteSneaker(sneaker: Sneaker) = sneakerDao.delete(sneaker)
override suspend fun getSneakerById(id: Int): Sneaker = sneakerDao.getSneakerById(id)
override fun getAllSneakers(): Flow<PagingData<Sneaker>> = Pager(
config = PagingConfig(
pageSize = AppContainer.LIMIT,
enablePlaceholders = false
),
pagingSourceFactory = sneakerDao::getAll
).flow
suspend fun clearSneakers() = sneakerDao.deleteAll()
suspend fun insertSneakers(sneakers: List<Sneaker>) =
sneakerDao.insert(*sneakers.toTypedArray())
fun getAllSneakersPagingSource(): PagingSource<Int, Sneaker> = sneakerDao.getAll()
// override fun getAllSneakersPaged(): PagingSource<Int, Sneaker> = sneakerDao.getAllSneakersPaged()
// override fun call(): Flow<PagingData<Sneaker>> {
// return Pager(
// PagingConfig(pageSize = 5)
// ) {
// sneakerDao.getAllSneakersPaged()
// }.flow
// }
}

View File

@ -0,0 +1,17 @@
package com.example.android_programming.database.repository
//class UserRepoImpl(private val userDao: UserDao) : UserRepository {
//
// override suspend fun createUser(user: User) = userDao.createUser(user)
//
// override suspend fun updateUser(user: User) = userDao.updateUser(user)
//
// override suspend fun deleteUser(user: User) = userDao.deleteUser(user)
//// override suspend fun authUser(user: UserRemoteSignIn): User {
//// println()
//// }
//
//// override suspend fun getUserById(id: Int): User = userDao.getUserById(id)
////
//// override suspend fun getUserByEmail(email: String): User = userDao.getUserByEmail(email)
//}

View File

@ -0,0 +1,21 @@
package com.example.android_programming.di
import com.example.android_programming.api.repository.RestBasketRepository
import com.example.android_programming.api.repository.RestSneakerRepository
import com.example.android_programming.api.repository.RestUserRepository
import com.example.android_programming.businessLogic.repo.BasketRepository
import com.example.android_programming.businessLogic.repo.OrderRepository
import com.example.android_programming.businessLogic.repo.SneakerRepository
import com.example.android_programming.businessLogic.repo.UserRepository
interface AppContainer {
val sneakerRepo: SneakerRepository
val userRepo: UserRepository
val orderRepo: OrderRepository
val basketRepo: BasketRepository
companion object {
const val TIMEOUT = 500L
const val LIMIT = 10
}
}

View File

@ -0,0 +1,42 @@
package com.example.android_programming.di
import android.content.Context
import com.example.android_programming.api.BackendService
import com.example.android_programming.api.repository.RestBasketRepository
import com.example.android_programming.api.repository.RestOrderRepository
import com.example.android_programming.api.repository.RestSneakerRepository
import com.example.android_programming.api.repository.RestUserRepository
import com.example.android_programming.database.AppDatabase
import com.example.android_programming.database.repository.RemoteKeysRepositoryImpl
import com.example.android_programming.businessLogic.repo.BasketRepository
import com.example.android_programming.businessLogic.repo.OrderRepository
import com.example.android_programming.businessLogic.repo.SneakerRepository
import com.example.android_programming.businessLogic.repo.UserRepository
import com.example.android_programming.database.repository.SneakerRepoImpl
class AppDataContainer(private val context: Context) : AppContainer {
override val sneakerRepo: SneakerRepository by lazy {
RestSneakerRepository(
BackendService.getInstance(),
sneakerRepository,
AppDatabase.getInstance(context),
remoteKeyRepository
)
}
override val userRepo: UserRepository by lazy {
RestUserRepository(BackendService.getInstance())
}
override val basketRepo: BasketRepository by lazy {
RestBasketRepository(BackendService.getInstance())
}
override val orderRepo: OrderRepository by lazy {
RestOrderRepository(BackendService.getInstance())
}
private val sneakerRepository: SneakerRepoImpl by lazy {
SneakerRepoImpl(AppDatabase.getInstance(context).sneakerDao())
}
private val remoteKeyRepository: RemoteKeysRepositoryImpl by lazy {
RemoteKeysRepositoryImpl(AppDatabase.getInstance(context).remoteKeysDao())
}
}

View File

@ -0,0 +1,13 @@
package com.example.android_programming.model
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity
class Basket (
@PrimaryKey
val basketId: Int? = null,
@ColumnInfo(name = "CreatorUserId")
val creatorUserId: Int
)

View File

@ -0,0 +1,11 @@
package com.example.android_programming.model
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(primaryKeys = ["basketId", "sneakerId"])
class BasketSneakers(
val basketId: Int,
val sneakerId: Int,
val quantity: Int
)

View File

@ -0,0 +1,15 @@
package com.example.android_programming.model
import androidx.room.Embedded
import androidx.room.Junction
import androidx.room.Relation
class BasketWithSneakers (
@Embedded val basket: Basket,
@Relation(
parentColumn = "basketId",
entityColumn = "sneakerId",
associateBy = Junction(BasketSneakers::class)
)
val sneakers: List<Sneaker>
)

View File

@ -0,0 +1,27 @@
package com.example.android_programming.model
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity
data class Order(
@PrimaryKey(autoGenerate = true)
val orderId: Int? = null,
@ColumnInfo(name = "Date")
val date: Long,
@ColumnInfo(name = "City")
val city: String,
@ColumnInfo(name = "Street")
val street: String,
@ColumnInfo(name = "House")
val house: String,
@ColumnInfo(name = "Sub Total")
val subtotal: Double,
@ColumnInfo(name = "Taxes")
val taxes: Double,
@ColumnInfo(name = "Total")
val total: Double,
@ColumnInfo(name = "CreatorUserId")
val creatorUserId: Int
)

View File

@ -0,0 +1,10 @@
package com.example.android_programming.model
import androidx.room.Entity
@Entity(primaryKeys = ["orderId", "sneakerId"])
data class OrderSneaker(
val orderId: Int,
val sneakerId: Int,
val quantity: Int
)

View File

@ -0,0 +1,17 @@
package com.example.android_programming.model
import androidx.room.Embedded
import androidx.room.Junction
import androidx.room.Relation
data class OrderWithSneakers(
@Embedded val order: Order,
@Relation(
parentColumn = "orderId",
entityColumn = "sneakerId",
associateBy = Junction(OrderSneaker::class)
)
val sneakers: List<Sneaker>
)

View File

@ -0,0 +1,35 @@
package com.example.android_programming.model
import com.example.android_programming.R
class PhotoManager {
private val photos = listOf(
R.drawable.img,
R.drawable.img_1,
R.drawable.img_2,
R.drawable.img_3,
R.drawable.img_4,
R.drawable.img_5,
)
private var currentIndex = 0
fun changePhoto(int: Int): Int {
currentIndex = photos.indexOf(int)
if (photos.isNotEmpty()) {
if(currentIndex + 1 >= photos.size){
currentIndex = 0
}else{
currentIndex += 1
}
return photos[currentIndex]
} else {
return -1
}
}
}

View File

@ -0,0 +1,22 @@
package com.example.android_programming.model
import androidx.room.Entity
import androidx.room.PrimaryKey
import androidx.room.TypeConverter
import androidx.room.TypeConverters
enum class RemoteKeyType(private val type: String) {
SNEAKER(Sneaker::class.simpleName ?: "Sneaker");
@TypeConverter
fun toRemoteKeyType(value: String) = RemoteKeyType.values().first { it.type == value }
@TypeConverter
fun fromRemoteKeyType(value: RemoteKeyType) = value.type
}
@Entity(tableName = "remote_keys")
data class RemoteKeys(
@PrimaryKey val entityId: Int,
@TypeConverters(RemoteKeyType::class)
val type: RemoteKeyType,
val prevKey: Int?,
val nextKey: Int?
)

View File

@ -0,0 +1,6 @@
package com.example.android_programming.model
enum class RoleEnum {
Admin,
User
}

View File

@ -0,0 +1,21 @@
package com.example.android_programming.model
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity
data class Sneaker(
@PrimaryKey(autoGenerate = true)
val sneakerId: Int? = null,
@ColumnInfo(name = "Brand")
val brand: String,
@ColumnInfo(name = "Model")
val model: String,
@ColumnInfo(name = "Description")
val description: String,
@ColumnInfo(name = "Price")
val price: Double,
@ColumnInfo(name = "Photo")
val photo: Int
)

View File

@ -0,0 +1,23 @@
package com.example.android_programming.model
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "users")
data class User(
@PrimaryKey(autoGenerate = true)
val userId: Int? = null,
@ColumnInfo(name = "Name")
val name: String,
@ColumnInfo(name = "Surname")
val surname: String,
@ColumnInfo(name = "Email")
val email: String,
@ColumnInfo(name = "Password")
val password: String,
@ColumnInfo(name = "Role")
val role: String,
@ColumnInfo(name = "Photo")
val photo: Int? = null,
)

View File

@ -0,0 +1,13 @@
package com.example.android_programming.model
import androidx.room.Embedded
import androidx.room.Relation
data class UserWithOrder(
@Embedded val user: User,
@Relation(
parentColumn = "userId",
entityColumn = "CreatorUserId"
)
val orders: List<Order>
)

Some files were not shown because too many files have changed in this diff Show More