Compare commits

..

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

127 changed files with 36 additions and 5780 deletions

48
.gitignore vendored
View File

@ -1,15 +1,35 @@
*.iml # ---> Android
.gradle # Gradle files
/local.properties .gradle/
/.idea/caches build/
/.idea/libraries
/.idea/modules.xml # Local configuration file (sdk path, etc)
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties 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

3
.idea/.gitignore vendored
View File

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

View File

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

View File

@ -1,20 +0,0 @@
<?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="gradleJvm" value="jbr-17" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>

View File

@ -1,41 +0,0 @@
<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>

View File

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

View File

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

View File

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

2
README.md Normal file
View File

@ -0,0 +1,2 @@
# Minhasapov_PMD

1
app/.gitignore vendored
View File

@ -1 +0,0 @@
/build

View File

@ -1,98 +0,0 @@
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id ("kotlin-kapt")
id("com.google.dagger.hilt.android")
id("org.jetbrains.kotlin.plugin.serialization")
}
android {
namespace = "com.example.mobileapp"
compileSdk = 34
defaultConfig {
applicationId = "com.example.mobileapp"
minSdk = 24
targetSdk = 34
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary = true
}
kapt {
arguments {arg("room.schemaLocation", "$projectDir/schemas")}
}
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = "17"
}
buildFeatures {
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = "1.4.3"
}
packaging {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
}
}
}
dependencies {
implementation("androidx.core:core-ktx:1.9.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.material3:material3")
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.navigation:navigation-compose:2.7.3")
implementation ("androidx.room:room-runtime:2.5.0") // Библиотека "Room"
kapt ("androidx.room:room-compiler:2.5.0") // Кодогенератор
implementation ("androidx.room:room-ktx:2.5.0")
// lab4
implementation ("com.google.dagger:hilt-android:2.44")
kapt ("com.google.dagger:hilt-android-compiler:2.44")
implementation("androidx.hilt:hilt-navigation-compose:1.0.0")
implementation ("androidx.compose.runtime:runtime-livedata:1.0.0-beta01")
implementation ("androidx.datastore:datastore-preferences:1.0.0")
implementation ("androidx.paging:paging-runtime-ktx:3.2.1")
implementation ("androidx.paging:paging-compose:3.2.1")
implementation("androidx.room:room-paging:2.5.0")
// lab5
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("com.squareup.okhttp3:logging-interceptor:4.11.0")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1")
implementation("com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:1.0.0")
}

View File

@ -1,21 +0,0 @@
# 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

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

View File

@ -1,32 +0,0 @@
<?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" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:name=".MobileApp"
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.MobileApp"
android:usesCleartextTraffic="true"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.MobileApp">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@ -1,95 +0,0 @@
package com.example.mobileapp
import android.app.Application
import androidx.room.*
import com.example.mobileapp.data.api.MyServerService
import com.example.mobileapp.data.api.repositories.RestCategoryRepository
import com.example.mobileapp.data.api.repositories.RestOrderProductRepository
import com.example.mobileapp.data.api.repositories.RestOrderRepository
import com.example.mobileapp.data.api.repositories.RestProductRepository
import com.example.mobileapp.data.api.repositories.RestRoleRepository
import com.example.mobileapp.data.api.repositories.RestStatusRepository
import com.example.mobileapp.data.api.repositories.RestUserRepository
import com.example.mobileapp.data.db.AppDatabase
import com.example.mobileapp.data.repositories.CategoryRepository
import com.example.mobileapp.data.repositories.OrderProductRepository
import com.example.mobileapp.data.repositories.OrderRepository
import com.example.mobileapp.data.repositories.ProductRepository
import com.example.mobileapp.data.repositories.RoleRepository
import com.example.mobileapp.data.repositories.StatusRepository
import com.example.mobileapp.data.repositories.UserRepository
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
@Provides
@Singleton
fun provideDatabase(app: Application) : AppDatabase {
return Room.databaseBuilder(
app,
AppDatabase::class.java,
AppDatabase.DB_NAME
)
.fallbackToDestructiveMigration()
.build()
}
@Provides
@Singleton
fun provideServerService() : MyServerService {
return MyServerService.getInstance()
}
@Provides
@Singleton
fun provideRestUserRepository(service: MyServerService) : RestUserRepository {
return RestUserRepository(service)
}
@Provides
@Singleton
fun provideCategoryRepository(db: AppDatabase, restCategoryRepository: RestCategoryRepository) : CategoryRepository {
return CategoryRepository(db.categoryDao(), db, restCategoryRepository)
}
@Provides
@Singleton
fun provideOrderProductRepository(db: AppDatabase, restOrderProductRepository: RestOrderProductRepository) : OrderProductRepository {
return OrderProductRepository(db.orderProductDao(), restOrderProductRepository)
}
@Provides
@Singleton
fun provideOrderRepository(db: AppDatabase, restOrderRepository: RestOrderRepository) : OrderRepository {
return OrderRepository(db, db.orderDao(), db.orderProductDao(), restOrderRepository)
}
@Provides
@Singleton
fun provideProductRepository(db: AppDatabase, restProductRepository: RestProductRepository) : ProductRepository {
return ProductRepository(db.productDao(), db.orderProductDao(), restProductRepository)
}
@Provides
@Singleton
fun provideRoleRepository(db: AppDatabase, restRoleRepository: RestRoleRepository) : RoleRepository {
return RoleRepository(db.roleDao(), restRoleRepository)
}
@Provides
@Singleton
fun provideStatusRepository(db: AppDatabase, restStatusRepository: RestStatusRepository) : StatusRepository {
return StatusRepository(db.statusDao(), restStatusRepository)
}
@Provides
@Singleton
fun provideUserRepository(db: AppDatabase, restUserRepository: RestUserRepository) : UserRepository {
return UserRepository(db.userDao(), db, restUserRepository)
}
}

View File

@ -1,18 +0,0 @@
package com.example.mobileapp
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import com.example.mobileapp.ui.navigation.AppNavigation
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
AppNavigation()
}
}
}

View File

@ -1,11 +0,0 @@
package com.example.mobileapp
import android.app.Application
import dagger.hilt.android.HiltAndroidApp
@HiltAndroidApp
class MobileApp : Application() {
override fun onCreate() {
super.onCreate()
}
}

View File

@ -1,199 +0,0 @@
package com.example.mobileapp.data.api
import com.example.mobileapp.data.api.models.CategoryListResponse
import com.example.mobileapp.data.api.models.CategoryRemote
import com.example.mobileapp.data.api.models.OrderListResponse
import com.example.mobileapp.data.api.models.OrderProductRemote
import com.example.mobileapp.data.api.models.OrderRemote
import com.example.mobileapp.data.api.models.ProductRemote
import com.example.mobileapp.data.api.models.RoleRemote
import com.example.mobileapp.data.api.models.StatusRemote
import com.example.mobileapp.data.api.models.TokenRemote
import com.example.mobileapp.data.api.models.UserListResponse
import com.example.mobileapp.data.api.models.UserRemote
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
import kotlinx.serialization.json.Json
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.http.Body
import retrofit2.http.DELETE
import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.POST
import retrofit2.http.PUT
import retrofit2.http.Path
interface MyServerService {
// User
@POST("register")
suspend fun createUser(
@Body user: UserRemote,
): UserRemote
@POST("auth")
suspend fun getToken(
@Body user: UserRemote
) : TokenRemote
@POST("check/login")
suspend fun checkLogin(
@Body user: UserRemote
) : UserRemote?
@GET("users/{after}")
suspend fun getUsersList(
@Path("after") after: Int,
@Header("Authorization") token: String
) : UserListResponse
@PUT("user/update")
suspend fun updateUser(
@Body user: UserRemote,
@Header("Authorization") token: String
): UserRemote
@DELETE("user/delete/{id}")
suspend fun deleteUser(
@Path("id") id: Int,
@Header("Authorization") token: String
)
// Product
@POST("product")
suspend fun insertProduct(
@Body product: ProductRemote,
@Header("Authorization") token: String
) : ProductRemote
@PUT("product")
suspend fun updateProduct(
@Body product: ProductRemote,
@Header("Authorization") token: String
): ProductRemote
@DELETE("product/{id}")
suspend fun deleteProduct(
@Path("id") id: Int,
@Header("Authorization") token: String
)
@GET("product/{id}")
suspend fun getProductById(
@Path("id") id: Int,
@Header("Authorization") token: String
): ProductRemote
@GET("products/{category_id}")
suspend fun getProductsByCategoryId(
@Path("category_id") category_id: Int,
@Header("Authorization") token: String
): List<ProductRemote>
// Role
@POST("role")
suspend fun getRole(
@Body role: RoleRemote,
) : RoleRemote?
@GET("roles")
suspend fun getRoles() : List<RoleRemote>
// Category
@POST("category")
suspend fun getCategory(
@Body category: CategoryRemote,
) : CategoryRemote?
@GET("categories")
suspend fun getCategories() : List<CategoryRemote>
@GET("categories/{after}")
suspend fun getCategoriesList(
@Path("after") after: Int,
@Header("Authorization") token: String
) : CategoryListResponse
// Status
@POST("status")
suspend fun getStatus(
@Body status: StatusRemote,
) : StatusRemote?
// Order
@GET("order/cart")
suspend fun getCartByUser(
@Header("Authorization") token: String
) : OrderRemote
@GET("order/to_worker/{after}")
suspend fun getOrdersToWorkList(
@Path("after") after: Int,
@Header("Authorization") token: String
) : OrderListResponse
@GET("order/to_user/{after}")
suspend fun getOrdersByUserList(
@Path("after") after: Int,
@Header("Authorization") token: String
) : OrderListResponse
@POST("order")
suspend fun insertOrder(
@Body order: OrderRemote,
@Header("Authorization") token: String
) : OrderRemote?
@PUT("order")
suspend fun updateOrder(
@Body order: OrderRemote,
@Header("Authorization") token: String
) : OrderRemote?
@DELETE("order/{id}")
suspend fun deleteOrder(
@Path("id") id: Int,
@Header("Authorization") token: String
)
// Order_Product
@POST("order/product")
suspend fun insertOrderProduct(
@Body orderProduct: OrderProductRemote,
@Header("Authorization") token: String
)
@PUT("order/product")
suspend fun updateOrderProduct(
@Body orderProduct: OrderProductRemote,
@Header("Authorization") token: String
)
@POST("order/product/delete")
suspend fun deleteOrderProduct(
@Body orderProduct: OrderProductRemote,
@Header("Authorization") token: String
)
companion object {
private const val BASE_URL ="http://10.0.2.2:8000/api/"
@Volatile
private var INSTANCE: MyServerService? = null
fun getInstance(): MyServerService {
return INSTANCE ?: synchronized(this) {
val logger = HttpLoggingInterceptor()
logger.level = HttpLoggingInterceptor.Level.BASIC
val client = UnsafeOkHttpClient.getUnsafeOkHttpClient()
return Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(Json.asConverterFactory("application/json".toMediaType()))
.build()
.create(MyServerService::class.java)
.also { INSTANCE = it }
}
}
}
}

View File

@ -1,55 +0,0 @@
package com.example.mobileapp.data.api;
import java.security.cert.CertificateException;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import okhttp3.OkHttpClient;
public class UnsafeOkHttpClient {
public static OkHttpClient getUnsafeOkHttpClient() {
try {
// Create a trust manager that does not validate certificate chains
final TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[]{};
}
}
};
// Install the all-trusting trust manager
final SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
// Create an ssl socket factory with our all-trusting manager
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.sslSocketFactory(sslSocketFactory, (X509TrustManager)trustAllCerts[0]);
builder.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
OkHttpClient okHttpClient = builder.build();
return okHttpClient;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

View File

@ -1,60 +0,0 @@
package com.example.mobileapp.data.api.mediators
import androidx.paging.ExperimentalPagingApi
import androidx.paging.LoadType
import androidx.paging.PagingState
import androidx.paging.RemoteMediator
import androidx.room.withTransaction
import com.example.mobileapp.data.api.MyServerService
import com.example.mobileapp.data.api.models.CategoryListResponse
import com.example.mobileapp.data.api.models.toCategory
import com.example.mobileapp.data.db.AppDatabase
import com.example.mobileapp.data.db.models.Category
import java.io.IOException
@OptIn(ExperimentalPagingApi::class)
class CategoryRemoteMediator (
private val database: AppDatabase,
private val serverService: MyServerService,
private val token: String
) : RemoteMediator<Int, Category>(){
private val categoryDao = database.categoryDao()
override suspend fun load(
loadType: LoadType,
state: PagingState<Int, Category>
): MediatorResult {
return try {
var loadKey = when (loadType) {
LoadType.REFRESH -> null
LoadType.PREPEND -> return MediatorResult.Success(endOfPaginationReached = true)
LoadType.APPEND -> {
val lastItem = state.lastItemOrNull()
?: return MediatorResult.Success(endOfPaginationReached = true)
lastItem.id
}
}
if (loadKey == null) {
loadKey = 0
}
val response: CategoryListResponse = serverService.getCategoriesList(after = loadKey, token = token)
database.withTransaction {
if (loadType == LoadType.REFRESH) {
categoryDao.deleteAll()
}
for (category in response.categories) {
categoryDao.insert(category.toCategory())
}
}
MediatorResult.Success(endOfPaginationReached = response.nextKey == -1)
} catch (e: IOException) {
MediatorResult.Error(e)
}
}
}

View File

@ -1,63 +0,0 @@
package com.example.mobileapp.data.api.mediators
import androidx.paging.ExperimentalPagingApi
import androidx.paging.LoadType
import androidx.paging.PagingState
import androidx.paging.RemoteMediator
import androidx.room.withTransaction
import com.example.mobileapp.data.api.MyServerService
import com.example.mobileapp.data.api.models.OrderListResponse
import com.example.mobileapp.data.api.models.toOrder
import com.example.mobileapp.data.db.AppDatabase
import com.example.mobileapp.data.db.models.OrderWithProducts
import java.io.IOException
@OptIn(ExperimentalPagingApi::class)
class OrderRemoteMediator (
private val database: AppDatabase,
private val serverService: MyServerService,
private val query: String,
private val token: String
) : RemoteMediator<Int, OrderWithProducts>(){
private val orderDao = database.orderDao()
override suspend fun load(
loadType: LoadType,
state: PagingState<Int, OrderWithProducts>
): MediatorResult {
return try {
var loadKey = when (loadType) {
LoadType.REFRESH -> null
LoadType.PREPEND -> return MediatorResult.Success(endOfPaginationReached = true)
LoadType.APPEND -> {
val lastItem = state.lastItemOrNull()
?: return MediatorResult.Success(endOfPaginationReached = true)
lastItem.order.id
}
}
if (loadKey == null) {
loadKey = 0
}
val response: OrderListResponse = if (query.isEmpty()) {
serverService.getOrdersToWorkList (after = loadKey, token = token)
} else {serverService.getOrdersByUserList(after = loadKey, token = token)}
database.withTransaction {
if (loadType == LoadType.REFRESH) {
orderDao.deleteByQuery(query)
}
for (order in response.orders) {
orderDao.insert(order.toOrder())
}
}
MediatorResult.Success(endOfPaginationReached = response.nextKey == -1)
} catch (e: IOException) {
MediatorResult.Error(e)
}
}
}

View File

@ -1,60 +0,0 @@
package com.example.mobileapp.data.api.mediators
import androidx.paging.ExperimentalPagingApi
import androidx.paging.LoadType
import androidx.paging.PagingState
import androidx.paging.RemoteMediator
import androidx.room.withTransaction
import com.example.mobileapp.data.api.MyServerService
import com.example.mobileapp.data.api.models.UserListResponse
import com.example.mobileapp.data.api.models.toUser
import com.example.mobileapp.data.db.AppDatabase
import com.example.mobileapp.data.db.models.User
import java.io.IOException
@OptIn(ExperimentalPagingApi::class)
class UserRemoteMediator (
private val database: AppDatabase,
private val serverService: MyServerService,
private val token: String
) : RemoteMediator<Int, User>(){
private val userDao = database.userDao()
override suspend fun load(
loadType: LoadType,
state: PagingState<Int, User>
): MediatorResult {
return try {
var loadKey = when (loadType) {
LoadType.REFRESH -> null
LoadType.PREPEND -> return MediatorResult.Success(endOfPaginationReached = true)
LoadType.APPEND -> {
val lastItem = state.lastItemOrNull()
?: return MediatorResult.Success(endOfPaginationReached = true)
lastItem.id
}
}
if (loadKey == null) {
loadKey = 0
}
val response: UserListResponse = serverService.getUsersList(after = loadKey, token = token)
database.withTransaction {
if (loadType == LoadType.REFRESH) {
userDao.deleteAll()
}
for (user in response.users) {
userDao.insert(user.toUser())
}
}
MediatorResult.Success(endOfPaginationReached = response.nextKey == -1)
} catch (e: IOException) {
MediatorResult.Error(e)
}
}
}

View File

@ -1,24 +0,0 @@
package com.example.mobileapp.data.api.models
import com.example.mobileapp.data.db.models.Category
import kotlinx.serialization.Serializable
@Serializable
data class CategoryRemote(
val id: Int? = 0,
val name: String = ""
)
@Serializable
data class CategoryListResponse(
val categories: List<CategoryRemote> = listOf(),
val nextKey: Int? = null
)
fun CategoryRemote.toCategory(): Category = Category(
id, name
)
fun Category.toCategoryRemote(): CategoryRemote = CategoryRemote(
id = id, name = name
)

View File

@ -1,48 +0,0 @@
package com.example.mobileapp.data.api.models
import com.example.mobileapp.data.db.models.Order
import com.example.mobileapp.data.db.models.OrderProduct
import kotlinx.serialization.Serializable
@Serializable
data class OrderRemote(
val id: Int? = null,
val user_id: Int? = -1,
val price: Int = -1,
val status_id: Int? = -1,
val order_products: List<OrderProductRemote> = listOf()
)
@Serializable
data class OrderListResponse(
val orders: List<OrderRemote> = listOf(),
val nextKey: Int? = null
)
fun OrderRemote.toOrder() : Order = Order(
id= id, userId = user_id, price= price, statusId = status_id
)
fun Order.toOrderRemote() : OrderRemote = OrderRemote(
id= id, user_id= userId, price= price, status_id = statusId
)
@Serializable
data class OrderProductRemote(
val id: Int? = null,
val order_id: Int = -1,
val product_id: Int = -1,
val amount: Int = 0,
val order: OrderRemote? = null,
val product: ProductRemote? = null
)
fun OrderProductRemote.toOrderProduct() : OrderProduct = OrderProduct(
order_id, product_id, amount
)
fun OrderProduct.toOrderProductRemote() : OrderProductRemote = OrderProductRemote(
order_id = orderId, product_id = productId, amount = amount
)

View File

@ -1,20 +0,0 @@
package com.example.mobileapp.data.api.models
import com.example.mobileapp.data.db.models.Product
import kotlinx.serialization.Serializable
@Serializable
data class ProductRemote(
val id: Int? = null,
val name: String = "",
val category_id: Int = 0,
val price: Int = 0,
)
fun ProductRemote.toProduct(): Product = Product(
id, name, category_id, price
)
fun Product.toProductRemote(): ProductRemote = ProductRemote(
id = id, name = name, category_id = categoryId, price = price
)

View File

@ -1,18 +0,0 @@
package com.example.mobileapp.data.api.models
import com.example.mobileapp.data.db.models.Role
import kotlinx.serialization.Serializable
@Serializable
data class RoleRemote(
val id: Int? = 0,
val name: String = ""
)
fun RoleRemote.toRole(): Role = Role(
id, name
)
fun Role.toRoleRemote(): RoleRemote = RoleRemote(
id = id, name = name
)

View File

@ -1,18 +0,0 @@
package com.example.mobileapp.data.api.models
import com.example.mobileapp.data.db.models.Status
import kotlinx.serialization.Serializable
@Serializable
data class StatusRemote(
val id: Int? = 0,
val name: String = ""
)
fun StatusRemote.toStatus(): Status = Status(
id, name
)
fun Status.toStatusRemote(): StatusRemote = StatusRemote(
id = id, name = name
)

View File

@ -1,31 +0,0 @@
package com.example.mobileapp.data.api.models
import com.example.mobileapp.data.db.models.User
import kotlinx.serialization.Serializable
@Serializable
data class TokenRemote(
val access_token: String = ""
)
@Serializable
data class UserRemote(
val id: Int? = 0,
val login: String = "",
val password:String = "",
val role_id:Int = -1
)
@Serializable
data class UserListResponse(
val users: List<UserRemote> = listOf(),
val nextKey: Int? = null
)
fun UserRemote.toUser(): User = User(
id, login, password, role_id
)
fun User.toUserRemote(): UserRemote = UserRemote(
id = id, login = login, password = password, role_id = roleId
)

View File

@ -1,13 +0,0 @@
package com.example.mobileapp.data.api.repositories
import com.example.mobileapp.data.api.MyServerService
import com.example.mobileapp.data.api.models.CategoryRemote
import javax.inject.Inject
class RestCategoryRepository @Inject constructor(
private val service: MyServerService
) {
suspend fun getCategories() : List<CategoryRemote> {
return service.getCategories()
}
}

View File

@ -1,21 +0,0 @@
package com.example.mobileapp.data.api.repositories
import com.example.mobileapp.data.api.MyServerService
import com.example.mobileapp.data.api.models.OrderProductRemote
import javax.inject.Inject
class RestOrderProductRepository @Inject constructor(
private val service: MyServerService
) {
suspend fun insertOrderProduct(token: String, orderProduct: OrderProductRemote) {
service.insertOrderProduct(orderProduct, token)
}
suspend fun updateOrderProduct(token: String, orderProduct: OrderProductRemote) {
service.updateOrderProduct(orderProduct, token)
}
suspend fun deleteOrderProduct(token: String, orderProduct: OrderProductRemote) {
service.deleteOrderProduct(orderProduct, token)
}
}

View File

@ -1,25 +0,0 @@
package com.example.mobileapp.data.api.repositories
import com.example.mobileapp.data.api.MyServerService
import com.example.mobileapp.data.api.models.OrderRemote
import javax.inject.Inject
class RestOrderRepository @Inject constructor(
private val service: MyServerService
) {
suspend fun getCartByUser(token:String) : OrderRemote {
return service.getCartByUser(token)
}
suspend fun insertOrder(token: String, order: OrderRemote): OrderRemote? {
return service.insertOrder(order, token)
}
suspend fun updateOrder(token: String, order: OrderRemote): OrderRemote? {
return service.updateOrder(order, token)
}
suspend fun deleteOrder(token: String, orderId: Int) {
service.deleteOrder(orderId, token)
}
}

View File

@ -1,32 +0,0 @@
package com.example.mobileapp.data.api.repositories
import com.example.mobileapp.data.api.MyServerService
import com.example.mobileapp.data.api.models.ProductRemote
import com.example.mobileapp.data.api.models.toProduct
import com.example.mobileapp.data.api.models.toProductRemote
import com.example.mobileapp.data.db.models.Product
import javax.inject.Inject
class RestProductRepository @Inject constructor(
private val service: MyServerService
) {
suspend fun insert(product: Product, token: String) {
service.insertProduct(product.toProductRemote(), token)
}
suspend fun update(product: Product, token: String) {
service.updateProduct((product.toProductRemote()), token)
}
suspend fun delete(id: Int, token: String) {
service.deleteProduct(id, token)
}
suspend fun getProductById(id: Int, token: String) : Product {
return service.getProductById(id, token).toProduct()
}
suspend fun getProductsByCategoryId(categoryId: Int, token: String) : List<ProductRemote> {
return service.getProductsByCategoryId(categoryId, token)
}
}

View File

@ -1,19 +0,0 @@
package com.example.mobileapp.data.api.repositories
import com.example.mobileapp.data.api.MyServerService
import com.example.mobileapp.data.api.models.RoleRemote
import com.example.mobileapp.data.api.models.toRoleRemote
import com.example.mobileapp.data.db.models.Role
import javax.inject.Inject
class RestRoleRepository @Inject constructor(
private val service: MyServerService
) {
suspend fun getRole(role: Role): RoleRemote? {
return service.getRole(role.toRoleRemote())
}
suspend fun getRoles() : List<RoleRemote> {
return service.getRoles()
}
}

View File

@ -1,15 +0,0 @@
package com.example.mobileapp.data.api.repositories
import com.example.mobileapp.data.api.MyServerService
import com.example.mobileapp.data.api.models.StatusRemote
import com.example.mobileapp.data.api.models.toStatusRemote
import com.example.mobileapp.data.db.models.Status
import javax.inject.Inject
class RestStatusRepository @Inject constructor(
private val service: MyServerService
) {
suspend fun getStatus(status: Status): StatusRemote? {
return service.getStatus(status.toStatusRemote())
}
}

View File

@ -1,32 +0,0 @@
package com.example.mobileapp.data.api.repositories
import com.example.mobileapp.data.api.MyServerService
import com.example.mobileapp.data.api.models.TokenRemote
import com.example.mobileapp.data.api.models.UserRemote
import com.example.mobileapp.data.api.models.toUserRemote
import com.example.mobileapp.data.db.models.User
import javax.inject.Inject
class RestUserRepository @Inject constructor(
private val service: MyServerService
) {
suspend fun insert(user: User) {
service.createUser(user.toUserRemote())
}
suspend fun update(user: User, token: String) {
service.updateUser((user.toUserRemote()), token)
}
suspend fun delete(id: Int, token: String) {
service.deleteUser(id, token)
}
suspend fun getToken(user: User): TokenRemote {
return service.getToken(user.toUserRemote())
}
suspend fun checkLogin(user: User): UserRemote? {
return service.checkLogin(user.toUserRemote())
}
}

View File

@ -1,32 +0,0 @@
package com.example.mobileapp.data.db
import androidx.room.*
import com.example.mobileapp.data.db.dao.*
import com.example.mobileapp.data.db.models.*
@Database(
entities =
[
Role::class,
Status::class,
Category::class,
User::class,
Order::class,
Product::class,
OrderProduct::class,
],
version = 5,
exportSchema = false
)
abstract class AppDatabase : RoomDatabase() {
abstract fun roleDao() : RoleDao
abstract fun statusDao() : StatusDao
abstract fun categoryDao() : CategoryDao
abstract fun userDao() : UserDao
abstract fun productDao() : ProductDao
abstract fun orderDao() : OrderDao
abstract fun orderProductDao() : OrderProductDao
companion object {
const val DB_NAME: String = "mobileapp-db"
}
}

View File

@ -1,19 +0,0 @@
package com.example.mobileapp.data.db.dao
import androidx.room.*
import com.example.mobileapp.data.db.models.*
import androidx.paging.PagingSource
import com.example.mobileapp.data.db.models.Category
@Dao
interface CategoryDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(category: Category)
@Update
suspend fun update(category: Category)
@Delete
suspend fun delete(category: Category)
@Query("delete from category")
fun deleteAll()
@Query("select * from category")
fun getPaged() : PagingSource<Int, Category>
}

View File

@ -1,41 +0,0 @@
package com.example.mobileapp.data.db.dao
import androidx.paging.PagingSource
import androidx.room.*
import com.example.mobileapp.data.db.models.Order
import com.example.mobileapp.data.db.models.OrderWithProducts
import kotlinx.coroutines.flow.Flow
@Dao
interface OrderDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(order: Order)
@Update
suspend fun update(order: Order)
@Delete
suspend fun delete(order: Order)
@Query("select * from `order` where `order`.`id` =:id")
fun getById(id: Int): Flow<OrderWithProducts>
@Query("select * from `order` where `order`.`user_id` =:userId and `order`.`status_id` = 1")
fun getCartByUser(userId: Int): Flow<OrderWithProducts?>
@Query("select * from `order` where `order`.`status_id` != 1 and `order`.`status_id` != 4")
fun getOrdersToWork(): PagingSource<Int, OrderWithProducts>
@Query("select * from `order` where (`order`.`user_id` =:userId and `order`.`status_id` != 1 and `order`.`status_id` != 4)")
fun getOrdersByUser(userId: Int): PagingSource<Int, OrderWithProducts>
@Query("delete from `order` where `order`.`status_id` != 1 and `order`.`status_id` != 4")
fun deleteOrdersToWork()
@Query("delete from `order` where (`order`.`user_id` =:userId and `order`.`status_id` != 1 and `order`.`status_id` != 4)")
fun deleteOrdersByUser(userId: Int)
fun deleteByQuery(query: String) {
if (query.isEmpty()) {
deleteOrdersToWork()
}
else {
deleteOrdersByUser(query.toInt())
}
}
}

View File

@ -1,17 +0,0 @@
package com.example.mobileapp.data.db.dao
import androidx.room.*
import com.example.mobileapp.data.db.models.OrderProduct
@Dao
interface OrderProductDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(orderProduct: OrderProduct)
@Update
suspend fun update(orderProduct: OrderProduct)
@Delete
suspend fun delete(orderProduct: OrderProduct)
@Query("delete from order_product WHERE order_id = :orderId")
suspend fun deleteByOrderId(orderId: Int)
@Query("delete from order_product WHERE product_id = :productId")
suspend fun deleteByProductId(productId: Int)
}

View File

@ -1,13 +0,0 @@
package com.example.mobileapp.data.db.dao
import androidx.room.*
import com.example.mobileapp.data.db.models.Product
@Dao
interface ProductDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(product: Product)
@Update
suspend fun update(product: Product)
@Delete
suspend fun delete(product: Product)
}

View File

@ -1,17 +0,0 @@
package com.example.mobileapp.data.db.dao
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Update
import com.example.mobileapp.data.db.models.Role
@Dao
interface RoleDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(role: Role)
@Update
suspend fun update(role: Role)
@Delete
suspend fun delete(role: Role)
}

View File

@ -1,17 +0,0 @@
package com.example.mobileapp.data.db.dao
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Update
import com.example.mobileapp.data.db.models.Status
@Dao
interface StatusDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(status: Status)
@Update
suspend fun update(status: Status)
@Delete
suspend fun delete(status: Status)
}

View File

@ -1,18 +0,0 @@
package com.example.mobileapp.data.db.dao
import androidx.paging.PagingSource
import androidx.room.*
import com.example.mobileapp.data.db.models.User
@Dao
interface UserDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(user: User)
@Update
suspend fun update(user: User)
@Delete
suspend fun delete(user: User)
@Query("delete from user")
fun deleteAll()
@Query("select * from user")
fun getPaged() : PagingSource<Int, User>
}

View File

@ -1,23 +0,0 @@
package com.example.mobileapp.data.db.models
import androidx.room.*
@Entity(tableName = "category")
data class Category(
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
val id: Int?,
@ColumnInfo(name = "name")
val name: String
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as Category
return id == other.id
}
override fun hashCode(): Int {
return id ?: -1
}
}

View File

@ -1,28 +0,0 @@
package com.example.mobileapp.data.db.models
import androidx.room.*
@Entity(
tableName = "order"
)
data class Order(
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
val id: Int?,
@ColumnInfo(name = "user_id")
val userId: Int?,
@ColumnInfo(name = "price")
var price: Int,
@ColumnInfo(name = "status_id")
var statusId: Int?,
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as Order
return id == other.id
}
override fun hashCode(): Int {
return id ?: -1
}
}

View File

@ -1,12 +0,0 @@
package com.example.mobileapp.data.db.models
import androidx.room.*
@Entity(tableName = "order_product", primaryKeys = ["order_id", "product_id"])
data class OrderProduct(
@ColumnInfo(name = "order_id", index = true)
var orderId: Int,
@ColumnInfo(name = "product_id", index = true)
var productId: Int,
@ColumnInfo(name = "amount")
var amount: Int
)

View File

@ -1,9 +0,0 @@
package com.example.mobileapp.data.db.models
import androidx.room.*
data class OrderProductWithProduct(
@Embedded
val orderProduct: OrderProduct,
@Relation(entity = Product::class, parentColumn = "product_id", entityColumn = "id")
val product: Product
)

View File

@ -1,9 +0,0 @@
package com.example.mobileapp.data.db.models
import androidx.room.*
data class OrderWithProducts(
@Embedded
val order: Order,
@Relation(entity = OrderProduct::class, parentColumn = "id", entityColumn = "order_id")
val orderWithProducts: List<OrderProductWithProduct>
)

View File

@ -1,26 +0,0 @@
package com.example.mobileapp.data.db.models
import androidx.room.*
@Entity(tableName = "product")
data class Product(
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
val id: Int?,
@ColumnInfo(name = "name")
val name: String,
@ColumnInfo(name = "category_id")
val categoryId: Int,
@ColumnInfo(name = "price")
val price: Int
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as Product
return id == other.id
}
override fun hashCode(): Int {
return id ?: -1
}
}

View File

@ -1,22 +0,0 @@
package com.example.mobileapp.data.db.models
import androidx.room.*
@Entity(tableName = "role")
data class Role(
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
val id: Int?,
@ColumnInfo(name = "name")
val name: String
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as Role
return id == other.id
}
override fun hashCode(): Int {
return id ?: -1
}
}

View File

@ -1,22 +0,0 @@
package com.example.mobileapp.data.db.models
import androidx.room.*
@Entity(tableName = "status")
data class Status(
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
val id: Int?,
@ColumnInfo(name = "name")
val name: String
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as Status
return id == other.id
}
override fun hashCode(): Int {
return id ?: -1
}
}

View File

@ -1,26 +0,0 @@
package com.example.mobileapp.data.db.models
import androidx.room.*
@Entity(tableName = "user")
data class User(
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
val id: Int?,
@ColumnInfo(name = "login")
val login: String,
@ColumnInfo(name = "password")
val password: String,
@ColumnInfo(name = "role_id")
var roleId: Int
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as User
return id == other.id
}
override fun hashCode(): Int {
return id ?: -1
}
}

View File

@ -1,35 +0,0 @@
package com.example.mobileapp.data.repositories
import androidx.paging.ExperimentalPagingApi
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import com.example.mobileapp.data.api.MyServerService
import com.example.mobileapp.data.api.mediators.CategoryRemoteMediator
import com.example.mobileapp.data.api.models.CategoryRemote
import com.example.mobileapp.data.api.repositories.RestCategoryRepository
import com.example.mobileapp.data.db.dao.CategoryDao
import com.example.mobileapp.data.db.AppDatabase
import com.example.mobileapp.data.db.models.Category
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject
class CategoryRepository @Inject constructor(
private val categoryDao: CategoryDao,
private val database: AppDatabase,
private val restRepository: RestCategoryRepository
){
@OptIn(ExperimentalPagingApi::class)
fun getAllPaged(token: String): Flow<PagingData<Category>> = Pager(
config = PagingConfig(
pageSize = 20,
enablePlaceholders = false
),
pagingSourceFactory = categoryDao::getPaged,
remoteMediator = CategoryRemoteMediator(database = database, serverService = MyServerService.getInstance(), token = token)
).flow
suspend fun getCategories() : List<CategoryRemote> {
return restRepository.getCategories()
}
}

View File

@ -1,25 +0,0 @@
package com.example.mobileapp.data.repositories
import com.example.mobileapp.data.api.models.toOrderProductRemote
import com.example.mobileapp.data.api.repositories.RestOrderProductRepository
import com.example.mobileapp.data.db.dao.OrderProductDao
import com.example.mobileapp.data.db.models.OrderProduct
import javax.inject.Inject
class OrderProductRepository @Inject constructor(
private val orderProductDao: OrderProductDao,
private val restOrderProductRepository: RestOrderProductRepository
){
suspend fun insert(token: String, orderProduct: OrderProduct) {
orderProductDao.insert(orderProduct)
return restOrderProductRepository.insertOrderProduct(token, orderProduct.toOrderProductRemote())
}
suspend fun update(token: String, orderProduct: OrderProduct) {
orderProductDao.update(orderProduct)
return restOrderProductRepository.updateOrderProduct(token, orderProduct.toOrderProductRemote())
}
suspend fun delete(token: String, orderProduct: OrderProduct) {
orderProductDao.delete(orderProduct)
restOrderProductRepository.deleteOrderProduct(token, orderProduct.toOrderProductRemote())
}
}

View File

@ -1,75 +0,0 @@
package com.example.mobileapp.data.repositories
import com.example.mobileapp.data.db.dao.OrderDao
import androidx.paging.*
import com.example.mobileapp.data.api.MyServerService
import com.example.mobileapp.data.api.models.toOrder
import com.example.mobileapp.data.api.models.toOrderProduct
import com.example.mobileapp.data.api.models.toOrderRemote
import com.example.mobileapp.data.api.repositories.RestOrderRepository
import com.example.mobileapp.data.db.dao.OrderProductDao
import com.example.mobileapp.data.db.AppDatabase
import com.example.mobileapp.data.db.models.Order
import com.example.mobileapp.data.api.mediators.OrderRemoteMediator
import com.example.mobileapp.data.db.models.OrderWithProducts
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import javax.inject.Inject
class OrderRepository @Inject constructor(
private val database: AppDatabase,
private val orderDao: OrderDao,
private val orderProductDao: OrderProductDao,
private val restRepository: RestOrderRepository
){
suspend fun insert(token: String, order: Order): Order? {
orderDao.insert(order)
val result = restRepository.insertOrder(token, order.toOrderRemote())
if (result == null) {
return result
}
return result.toOrder()
}
suspend fun update(token: String, order: Order) {
orderDao.update(order)
restRepository.updateOrder(token, order.toOrderRemote())
}
suspend fun delete(token: String, order: Order) {
orderProductDao.deleteByOrderId(order.id!!)
orderDao.delete(order)
restRepository.deleteOrder(token, order.id)
}
fun getById(id: Int) = orderDao.getById(id)
suspend fun getCartByUser(token: String) : OrderWithProducts? {
val order = restRepository.getCartByUser(token)
if (order.id != null) {
orderDao.insert(order.toOrder())
for (product in order.order_products) {
orderProductDao.insert(product.toOrderProduct())
}
return orderDao.getCartByUser(order.user_id!!).first()
}
return null
}
@OptIn(ExperimentalPagingApi::class)
fun getOrdersToWorkPaged(token: String): Flow<PagingData<OrderWithProducts>> = Pager(
config = PagingConfig(
pageSize = 6,
enablePlaceholders = false
),
pagingSourceFactory = orderDao::getOrdersToWork,
remoteMediator = OrderRemoteMediator(database = database, serverService = MyServerService.getInstance(), query = "", token = token)
).flow
@OptIn(ExperimentalPagingApi::class)
fun getOrdersByUserPaged(token: String, userId: Int): Flow<PagingData<OrderWithProducts>> = Pager(
config = PagingConfig(
pageSize = 6,
enablePlaceholders = false
),
pagingSourceFactory = {orderDao.getOrdersByUser(userId)},
remoteMediator = OrderRemoteMediator(database = database, serverService = MyServerService.getInstance(), query = userId.toString(), token = token)
).flow
}

View File

@ -1,43 +0,0 @@
package com.example.mobileapp.data.repositories
import com.example.mobileapp.data.api.models.ProductRemote
import com.example.mobileapp.data.api.models.toProduct
import com.example.mobileapp.data.api.repositories.RestProductRepository
import com.example.mobileapp.data.db.dao.OrderProductDao
import com.example.mobileapp.data.db.dao.ProductDao
import com.example.mobileapp.data.db.models.Product
import javax.inject.Inject
class ProductRepository @Inject constructor(
private val productDao: ProductDao,
private val orderProductDao: OrderProductDao,
private val restRepository: RestProductRepository
){
suspend fun insert(product: Product, token: String) {
productDao.insert(product)
return restRepository.insert(product, token)
}
suspend fun update(product: Product, token: String) {
productDao.update(product)
return restRepository.update(product, token)
}
suspend fun delete(product: Product, token: String) {
productDao.delete(product)
product.id?.let { orderProductDao.deleteByProductId(it) }
return restRepository.delete(product.id!!, token)
}
suspend fun getProductById(id: Int, token: String) : Product {
val product = restRepository.getProductById(id, token)
productDao.insert(product)
return product
}
suspend fun getProductsByCategoryId(categoryId: Int, token: String) : List<ProductRemote> {
val products = restRepository.getProductsByCategoryId(categoryId, token)
products.forEach{ productRemote ->
productDao.insert(productRemote.toProduct())
}
return products
}
}

View File

@ -1,24 +0,0 @@
package com.example.mobileapp.data.repositories
import com.example.mobileapp.data.api.models.RoleRemote
import com.example.mobileapp.data.api.repositories.RestRoleRepository
import com.example.mobileapp.data.db.dao.RoleDao
import com.example.mobileapp.data.db.models.Role
import javax.inject.Inject
class RoleRepository @Inject constructor(
private val roleDao: RoleDao,
private val restRepository: RestRoleRepository
){
suspend fun insert(role: Role) = roleDao.insert(role)
suspend fun update(role: Role) = roleDao.update(role)
suspend fun delete(role: Role) = roleDao.delete(role)
suspend fun getRole(role: Role): RoleRemote? {
return restRepository.getRole(role)
}
suspend fun getRoles() : List<RoleRemote> {
return restRepository.getRoles()
}
}

View File

@ -1,24 +0,0 @@
package com.example.mobileapp.data.repositories
import com.example.mobileapp.data.api.models.StatusRemote
import com.example.mobileapp.data.api.models.toStatus
import com.example.mobileapp.data.api.repositories.RestStatusRepository
import com.example.mobileapp.data.db.dao.StatusDao
import com.example.mobileapp.data.db.models.Status
import javax.inject.Inject
class StatusRepository @Inject constructor(
private val statusDao: StatusDao,
private val restRepository: RestStatusRepository
){
suspend fun insert(status: Status) = statusDao.insert(status)
suspend fun update(status: Status) = statusDao.update(status)
suspend fun delete(status: Status) = statusDao.delete(status)
suspend fun getStatus(status: Status): StatusRemote? {
val statusModel = restRepository.getStatus(status)
if (statusModel != null){
statusDao.insert(statusModel.toStatus())
}
return statusModel
}
}

View File

@ -1,51 +0,0 @@
package com.example.mobileapp.data.repositories
import androidx.paging.ExperimentalPagingApi
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import com.example.mobileapp.data.api.MyServerService
import com.example.mobileapp.data.api.mediators.UserRemoteMediator
import com.example.mobileapp.data.api.models.TokenRemote
import com.example.mobileapp.data.api.models.UserRemote
import com.example.mobileapp.data.api.repositories.RestUserRepository
import com.example.mobileapp.data.db.dao.UserDao
import com.example.mobileapp.data.db.AppDatabase
import com.example.mobileapp.data.db.models.User
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject
class UserRepository @Inject constructor(
private val userDao: UserDao,
private val database: AppDatabase,
private val restRepository: RestUserRepository
){
suspend fun insert(user: User){
userDao.insert(user)
restRepository.insert(user)
}
suspend fun update(user: User, token: String) {
return restRepository.update(user, token)
}
suspend fun delete(user: User, token: String) {
userDao.delete(user)
return restRepository.delete(user.id!!, token)
}
@OptIn(ExperimentalPagingApi::class)
fun getAllPaged(token: String): Flow<PagingData<User>> = Pager(
config = PagingConfig(
pageSize = 6,
enablePlaceholders = false
),
pagingSourceFactory = userDao::getPaged,
remoteMediator = UserRemoteMediator(database = database, serverService = MyServerService.getInstance(), token = token)
).flow
suspend fun getToken(user: User): TokenRemote {
return restRepository.getToken(user)
}
suspend fun checkLogin(user: User): UserRemote? {
return restRepository.checkLogin(user)
}
}

View File

@ -1,23 +0,0 @@
package com.example.mobileapp.data.sharedpref
import android.content.Context
import android.content.SharedPreferences
class PreferencesManager(context: Context) {
private val sharedPreferences: SharedPreferences =
context.getSharedPreferences("MyPrefs", Context.MODE_PRIVATE)
fun saveData(key: String, value: String) {
val editor = sharedPreferences.edit()
editor.putString(key, value)
editor.apply()
}
fun getData(key: String, defaultValue: String): String {
return sharedPreferences.getString(key, defaultValue) ?: defaultValue
}
fun deleteData(key: String) {
sharedPreferences.edit().remove(key).apply()
}
}

View File

@ -1,135 +0,0 @@
package com.example.mobileapp.ui.navigation
import android.annotation.SuppressLint
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import com.example.mobileapp.data.sharedpref.PreferencesManager
import com.example.mobileapp.ui.screens.AuthorizationScreen
import com.example.mobileapp.ui.screens.CartScreen
import com.example.mobileapp.ui.screens.CreateProductScreen
import com.example.mobileapp.ui.screens.EditMenuScreen
import com.example.mobileapp.ui.screens.EditProductScreen
import com.example.mobileapp.ui.screens.ManagmentScreen
import com.example.mobileapp.ui.screens.MenuScreen
import com.example.mobileapp.ui.screens.OrderScreen
import com.example.mobileapp.ui.screens.ProfileScreen
import com.example.mobileapp.ui.screens.RegistrationScreen
import com.example.mobileapp.ui.screens.UsersScreen
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AppNavigation(){
val navController = rememberNavController()
Scaffold(
bottomBar = {
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry?.destination?.route
if (currentRoute != Screens.AuthorizationScreen.name && currentRoute != Screens.RegistrationScreen.name) {
CustomNavigationBar(navController)
}
}
){
paddingValues ->
NavHost(
navController = navController,
startDestination = Screens.AuthorizationScreen.name,
modifier = Modifier.padding(paddingValues)
){
composable(route = Screens.MenuScreen.name){ MenuScreen() }
composable(route = Screens.ProfileScreen.name){ ProfileScreen(navController) }
composable(route = Screens.CartScreen.name){ CartScreen() }
composable(route = Screens.ManagmentScreen.name){ ManagmentScreen(navController) }
composable(route = Screens.OrderScreen.name){ OrderScreen() }
composable(route = Screens.AuthorizationScreen.name){ AuthorizationScreen(navController) }
composable(route = Screens.CreateProductScreen.name){ CreateProductScreen(navController) }
composable(route = Screens.EditMenuScreen.name){ EditMenuScreen(navController) }
composable(route = Screens.RegistrationScreen.name){ RegistrationScreen(navController) }
composable(route = Screens.UsersScreen.name){ UsersScreen() }
composable(route = Screens.EditProductScreen.name + "/{productId}"){ backStackEntry ->
val productId = backStackEntry.arguments?.getString("productId")
EditProductScreen(navController, productId.toString().toInt())
}
}
}
}
@SuppressLint("CoroutineCreationDuringComposition")
@Composable
fun CustomNavigationBar(navController: NavController) {
val sharedPref = PreferencesManager(LocalContext.current)
val user_role = sharedPref.getData("userRole", "user")
val listOfNavItems = remember { mutableStateListOf<NavItem>() }
when (user_role) {
"admin" -> {
listOfNavItems.clear()
listOfNavItems.addAll(listOfAdminNavItems)
}
"worker" -> {
listOfNavItems.clear()
listOfNavItems.addAll(listOfWorkerNavItems)
}
"user" -> {
listOfNavItems.clear()
listOfNavItems.addAll(listOfUserNavItems)
}
}
Row(
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight(0.1f)
.background(Color(212, 206, 203))
) {
listOfNavItems.forEachIndexed { index, navItem ->
OutlinedButton(
modifier = Modifier
.fillMaxHeight()
.weight(1f),
onClick = {
navController.navigate(navItem.route) {
popUpTo(navController.graph.startDestinationId)
launchSingleTop = true
}
},
border = BorderStroke(4.dp, Color(222,161,69)),
shape = RoundedCornerShape(
topStart = if (index == 0) 30.dp else 0.dp,
topEnd = if (index == listOfNavItems.size - 1) 30.dp else 0.dp
),
colors = ButtonDefaults.outlinedButtonColors(Color(255,186,83)),
){
Icon(
painterResource(id = navItem.icon),
contentDescription = null,
tint = Color.Black
)
}
}
}
}

View File

@ -1,78 +0,0 @@
package com.example.mobileapp.ui.navigation
import com.example.mobileapp.R
data class NavItem(
val label: String,
val icon: Int,
val route: String
)
val listOfAdminNavItems = listOf(
NavItem(
label = "Order",
icon = R.drawable.icon_order,
route = Screens.OrderScreen.name
),
NavItem(
label = "Profile",
icon = R.drawable.icon_profile,
route = Screens.ProfileScreen.name
),
NavItem(
label = "Menu",
icon = R.drawable.icon_menu,
route = Screens.MenuScreen.name
),
NavItem(
label = "Cart",
icon = R.drawable.icon_cart,
route = Screens.CartScreen.name
),
NavItem(
label = "Managment",
icon = R.drawable.icon_managment,
route = Screens.ManagmentScreen.name
),
)
val listOfUserNavItems = listOf(
NavItem(
label = "Profile",
icon = R.drawable.icon_profile,
route = Screens.ProfileScreen.name
),
NavItem(
label = "Menu",
icon = R.drawable.icon_menu,
route = Screens.MenuScreen.name
),
NavItem(
label = "Cart",
icon = R.drawable.icon_cart,
route = Screens.CartScreen.name
),
)
val listOfWorkerNavItems = listOf(
NavItem(
label = "Order",
icon = R.drawable.icon_order,
route = Screens.OrderScreen.name
),
NavItem(
label = "Profile",
icon = R.drawable.icon_profile,
route = Screens.ProfileScreen.name
),
NavItem(
label = "Menu",
icon = R.drawable.icon_menu,
route = Screens.MenuScreen.name
),
NavItem(
label = "Cart",
icon = R.drawable.icon_cart,
route = Screens.CartScreen.name
),
)

View File

@ -1,15 +0,0 @@
package com.example.mobileapp.ui.navigation
enum class Screens {
CartScreen,
ManagmentScreen,
MenuScreen,
OrderScreen,
ProfileScreen,
AuthorizationScreen,
CreateProductScreen,
EditMenuScreen,
EditProductScreen,
RegistrationScreen,
UsersScreen,
}

View File

@ -1,211 +0,0 @@
package com.example.mobileapp.ui.screens
import androidx.compose.foundation.BorderStroke
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.shape.RoundedCornerShape
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.livedata.observeAsState
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.platform.LocalContext
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavController
import com.example.mobileapp.data.sharedpref.PreferencesManager
import com.example.mobileapp.R
import com.example.mobileapp.ui.navigation.Screens
import com.example.mobileapp.viewmodels.AuthorizationViewModel
import com.example.mobileapp.ui.widgets.Header
@Composable
fun AuthorizationScreen(navController: NavController) {
Column (
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Header(Color.White)
AuthorizationCard(navController)
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AuthorizationCard(navController: NavController){
val sharedPref = PreferencesManager(LocalContext.current)
val login = remember { mutableStateOf(TextFieldValue("")) }
val password = remember { mutableStateOf(TextFieldValue("")) }
val viewModel = hiltViewModel<AuthorizationViewModel>()
val success = viewModel.successState.observeAsState().value
if (success == true) {
navController.navigate(Screens.MenuScreen.name)
}
if (success == false) {
AlertDialog(
title = {
Text(
text = "Ошибка авторизации",
fontWeight = FontWeight.Bold,
fontSize = 20.sp
)
},
text = {
Text(
text = "Неверный логин или пароль",
fontWeight = FontWeight.Normal,
fontSize = 16.sp
)
},
onDismissRequest = {
viewModel.calmSuccessState()
},
confirmButton = {
TextButton(
onClick = {
viewModel.calmSuccessState()
}
) {
Text("ОК")
}
}
)
}
Column(
horizontalAlignment = Alignment.CenterHorizontally,
) {
Card(
shape = RoundedCornerShape(30.dp),
modifier = Modifier.padding(top = 30.dp)
) {
Column (
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.background(Color(212, 206, 203))
.fillMaxWidth(0.9f)
) {
Card(
shape = RoundedCornerShape(90.dp, 90.dp, 30.dp, 30.dp),
border = BorderStroke(4.dp, Color(222,161,69)),
modifier = Modifier
.fillMaxWidth()
.padding(top = 30.dp, start = 20.dp, end = 20.dp)
){
Text(
text = "Авторизация",
color = Color.White,
fontFamily = FontFamily(Font(R.font.nunito_bold)),
fontSize = 30.sp,
modifier = Modifier
.fillMaxWidth()
.background(Color(255, 186, 83))
.padding(top = 20.dp, bottom = 20.dp),
textAlign = TextAlign.Center,
)
}
OutlinedTextField(
value = login.value,
onValueChange = {login.value = it},
placeholder = { Text(text = "Логин", fontSize = 20.sp, color = Color.LightGray) },
singleLine = true,
shape = RoundedCornerShape(30.dp, 30.dp, 30.dp, 30.dp),
textStyle = TextStyle(fontSize = 20.sp),
colors = TextFieldDefaults.outlinedTextFieldColors(
textColor = Color.Black,
disabledTextColor = Color.Transparent,
containerColor = Color.White,
focusedBorderColor = Color.Yellow,
unfocusedBorderColor = Color.Yellow,
),
modifier = Modifier
.fillMaxWidth()
.padding(top = 20.dp, start = 20.dp, end = 20.dp),
)
OutlinedTextField(
value = password.value,
onValueChange = {password.value = it},
placeholder = { Text(text = "Пароль", fontSize = 20.sp, color = Color.LightGray) },
singleLine = true,
shape = RoundedCornerShape(30.dp, 30.dp, 30.dp, 30.dp),
textStyle = TextStyle(fontSize = 20.sp),
colors = TextFieldDefaults.outlinedTextFieldColors(
textColor = Color.Black,
disabledTextColor = Color.Transparent,
containerColor = Color.White,
focusedBorderColor = Color(183,97,48),
unfocusedBorderColor = Color(183,97,48),
),
modifier = Modifier
.fillMaxWidth()
.padding(top = 20.dp, start = 20.dp, end = 20.dp),
)
Button(
onClick = {
viewModel.login(sharedPref, login.value.text, password.value.text)
},
colors = ButtonDefaults.buttonColors(Color(255,186,83), Color.White),
shape = RoundedCornerShape(30.dp, 30.dp, 30.dp, 30.dp),
border = BorderStroke(4.dp, Color(222,161,69)),
modifier = Modifier
.fillMaxWidth()
.padding(top = 20.dp, start = 20.dp, end = 20.dp)
) {
Text(
text = "Войти",
color = Color.White,
fontFamily = FontFamily(Font(R.font.nunito_bold)),
fontSize = 30.sp,
textAlign = TextAlign.Center,
)
}
Button(
onClick = {
navController.navigate(Screens.RegistrationScreen.name)
},
colors = ButtonDefaults.buttonColors(Color(212,206,203)),
modifier = Modifier
.fillMaxWidth()
.padding(top = 10.dp, start = 20.dp, end = 20.dp)
) {
Text(
text = "Создать аккаунт",
color = Color.White,
fontFamily = FontFamily(Font(R.font.nunito_bold)),
fontSize = 20.sp,
textAlign = TextAlign.Center,
)
}
}
}
}
}

View File

@ -1,279 +0,0 @@
package com.example.mobileapp.ui.screens
import android.annotation.SuppressLint
import androidx.compose.foundation.BorderStroke
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.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
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.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.hilt.navigation.compose.hiltViewModel
import com.example.mobileapp.data.sharedpref.PreferencesManager
import com.example.mobileapp.R
import com.example.mobileapp.data.db.models.OrderProductWithProduct
import com.example.mobileapp.data.db.models.OrderWithProducts
import com.example.mobileapp.viewmodels.CartViewModel
import com.example.mobileapp.ui.widgets.Header
@Composable
fun CartScreen(){
Column (
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Header(Color(212, 206, 203))
CartCard()
}
}
@SuppressLint("CoroutineCreationDuringComposition")
@Composable
fun CartCard(){
val sharedPref = PreferencesManager(LocalContext.current)
val searchToken = sharedPref.getData("token", "")
val cartViewModel: CartViewModel = hiltViewModel<CartViewModel>()
cartViewModel.getCart(searchToken)
val cart: OrderWithProducts? = cartViewModel.cart.observeAsState().value
Column(
modifier = Modifier
.fillMaxSize()
.background(Color(212, 206, 203)),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Column(
modifier = Modifier
.fillMaxHeight()
.fillMaxWidth(0.9f)
.background(Color.White),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
text = "Корзина",
color = Color.Black,
fontFamily = FontFamily(Font(R.font.nunito_extrabold_italic)),
fontSize = 34.sp,
modifier = Modifier
.fillMaxWidth()
.padding(top = 10.dp),
textAlign = TextAlign.Center,
)
if (cart != null && cart.orderWithProducts.size != 0) {
LazyColumn(
modifier = Modifier
.fillMaxWidth()
){
items(cart.orderWithProducts.size) { index ->
CartProductCard(cartViewModel, cart.orderWithProducts[index])
}
}
Card(
shape = RoundedCornerShape(20.dp),
border = BorderStroke(3.dp, Color(222,161,69)),
modifier = Modifier
.padding(top = 15.dp, start = 5.dp, end = 5.dp)
){
Row(
modifier = Modifier
.fillMaxWidth()
.background(Color.White),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
){
Text(
text = "Итого: " + cart.order.price.toString() + " р.",
color = Color.Black,
fontFamily = FontFamily(Font(R.font.nunito_extrabold_italic)),
fontSize = 20.sp,
textAlign = TextAlign.Center,
modifier = Modifier.padding(start = 5.dp),
)
OutlinedButton(
onClick = {
cartViewModel.makeOrder(searchToken)
},
border = BorderStroke(4.dp, Color(222,161,69)),
shape = RoundedCornerShape(20.dp),
colors = ButtonDefaults.outlinedButtonColors(Color(255,186,83)),
modifier = Modifier.padding(5.dp)
) {
Text(text = "Заказать", fontSize = 20.sp, color = Color.White)
}
}
}
}
}
}
}
@Composable
fun CartProductCard(
cartViewModel: CartViewModel,
product: OrderProductWithProduct
){
val sharedPref = PreferencesManager(LocalContext.current)
val searchToken = sharedPref.getData("token", "")
var amountProduct by remember { mutableStateOf(product.orderProduct.amount)}
Card(
shape = RoundedCornerShape(20.dp),
border = BorderStroke(3.dp, Color(222,161,69)),
modifier = Modifier
.fillMaxSize()
.padding(top = 15.dp, start = 5.dp, end = 5.dp)
){
Row(
modifier = Modifier
.fillMaxSize()
.background(Color.White),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceEvenly,
){
CartProductImageCard(product.product.categoryId)
Column (
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.SpaceAround
) {
Text(
text = product.product.name,
color = Color.Black,
fontFamily = FontFamily(Font(R.font.nunito_extrabold_italic)),
fontSize = 17.sp,
textAlign = TextAlign.Center,
)
Text(
text = product.product.price.toString() + " р.",
color = Color.Black,
fontFamily = FontFamily(Font(R.font.nunito_extrabold_italic)),
fontSize = 17.sp,
textAlign = TextAlign.Center,
)
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center,
modifier = Modifier
.fillMaxWidth(0.8f)
){
OutlinedButton(
modifier = Modifier
.fillMaxHeight(),
onClick = {
cartViewModel.removeProductFromOrder(searchToken, product.product.id!!)
amountProduct -= 1
},
border = BorderStroke(4.dp, Color(222,161,69)),
shape = RoundedCornerShape(topStart = 30.dp, bottomStart = 30.dp),
colors = ButtonDefaults.outlinedButtonColors(Color(255,186,83)),
) {
Text(text = "-", fontSize = 20.sp, color = Color.Black)
}
Card(
modifier = Modifier
.fillMaxHeight(),
border = BorderStroke(3.dp, Color(222,161,69)),
shape = RoundedCornerShape(0.dp),
){
Text(
modifier = Modifier
.background(Color.White)
.fillMaxHeight()
.padding(
start = 20.dp,
end = 20.dp,
top = 7.dp,
bottom = 7.dp
),
text = amountProduct.toString(),
color = Color.Black,
fontFamily = FontFamily(Font(R.font.nunito_bold)),
fontSize = 20.sp,
textAlign = TextAlign.Center,
)
}
OutlinedButton(
modifier = Modifier
.fillMaxHeight(),
onClick = {
cartViewModel.addProductToOrder(searchToken, product.product.id!!)
amountProduct += 1
},
border = BorderStroke(4.dp, Color(222,161,69)),
shape = RoundedCornerShape(topEnd = 30.dp, bottomEnd = 30.dp),
colors = ButtonDefaults.outlinedButtonColors(Color(255,186,83)),
) {
Text(text = "+", fontSize = 20.sp, color = Color.Black)
}
}
}
}
}
}
@Composable
fun CartProductImageCard(categoryId : Int){
if (categoryId == 1){
Image(
painterResource(
id = R.drawable.burger
),
contentDescription = null,
modifier = Modifier
.size(100.dp, 100.dp)
.padding(5.dp),
)
}
if (categoryId == 2){
Image(
painterResource(
id = R.drawable.potato
),
contentDescription = null,
modifier = Modifier
.size(100.dp, 100.dp)
.padding(5.dp),
)
}
if (categoryId == 3){
Image(
painterResource(
id = R.drawable.pepsi
),
contentDescription = null,
modifier = Modifier
.size(100.dp, 100.dp)
.padding(5.dp),
)
}
}

View File

@ -1,218 +0,0 @@
package com.example.mobileapp.ui.screens
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.ExposedDropdownMenuDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableStateListOf
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.platform.LocalContext
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavController
import com.example.mobileapp.data.sharedpref.PreferencesManager
import com.example.mobileapp.R
import com.example.mobileapp.ui.navigation.Screens
import com.example.mobileapp.viewmodels.ProductViewModel
import com.example.mobileapp.ui.widgets.Header
@Composable
fun CreateProductScreen(navController: NavController){
Column (
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Header(Color(212, 206, 203))
CreateProductCard(navController)
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CreateProductCard(navController: NavController){
val sharedPref = PreferencesManager(LocalContext.current)
val searchToken = sharedPref.getData("token", "")
val productViewModel: ProductViewModel = hiltViewModel<ProductViewModel>()
val title = remember { mutableStateOf(TextFieldValue("")) }
val price = remember { mutableStateOf(TextFieldValue("")) }
val categoryList = remember { mutableStateListOf(productViewModel.categories) }
var selectedCategory by remember { mutableStateOf("") }
var expanded by remember { mutableStateOf(false) }
val success = productViewModel.successState.observeAsState().value
if (success == true) {
navController.navigate(Screens.ManagmentScreen.name)
}
Column(
modifier = Modifier
.fillMaxSize()
.background(Color(212, 206, 203)),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Column(
modifier = Modifier
.fillMaxHeight()
.fillMaxWidth(0.9f)
.background(Color.White),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
text = "Создание блюда",
color = Color.Black,
fontFamily = FontFamily(Font(R.font.nunito_extrabold_italic)),
fontSize = 34.sp,
modifier = Modifier
.fillMaxWidth()
.padding(top = 10.dp),
textAlign = TextAlign.Center,
)
Card(
shape = RoundedCornerShape(20.dp),
border = BorderStroke(3.dp, Color(222,161,69)),
modifier = Modifier
.padding(top = 15.dp, start = 5.dp, end = 5.dp)
){
Column (
modifier = Modifier.background(Color.White)
) {
OutlinedTextField(
value = title.value,
onValueChange = {title.value = it},
placeholder = { Text(text = "Название", fontSize = 20.sp, color = Color.LightGray) },
singleLine = true,
shape = RoundedCornerShape(20.dp),
textStyle = TextStyle(fontSize = 20.sp),
colors = TextFieldDefaults.outlinedTextFieldColors(
textColor = Color.Black,
disabledTextColor = Color.Transparent,
containerColor = Color.White,
focusedBorderColor = Color(222,161,69),
unfocusedBorderColor = Color(222,161,69),
),
modifier = Modifier
.fillMaxWidth()
.padding(top = 20.dp, start = 20.dp, end = 20.dp),
)
Card(
shape = RoundedCornerShape(20.dp),
border = BorderStroke(1.dp, Color(222,161,69)),
modifier = Modifier.fillMaxWidth().padding(top = 20.dp, start = 20.dp, end = 20.dp),
){
MaterialTheme(
colorScheme = lightColorScheme(
surfaceVariant= Color.White,
surface = Color.White,
onSurface = Color.Gray
)
){
ExposedDropdownMenuBox(
expanded = expanded,
onExpandedChange = {
expanded = !expanded
},
) {
TextField(
modifier = Modifier
.menuAnchor().fillMaxWidth(),
readOnly = true,
value = selectedCategory,
onValueChange = {},
label = { Text("Категория") },
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) },
)
ExposedDropdownMenu(
expanded = expanded,
onDismissRequest = {
expanded = false
},
) {
categoryList.first().forEach { selectionOption ->
DropdownMenuItem(
text = { Text(selectionOption.name) },
onClick = {
selectedCategory = selectionOption.name
expanded = false
},
contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding,
)
}
}
}
}
}
OutlinedTextField(
value = price.value,
onValueChange = {price.value = it},
placeholder = { Text(text = "Цена", fontSize = 20.sp, color = Color.LightGray) },
singleLine = true,
shape = RoundedCornerShape(20.dp),
textStyle = TextStyle(fontSize = 20.sp),
colors = TextFieldDefaults.outlinedTextFieldColors(
textColor = Color.Black,
disabledTextColor = Color.Transparent,
containerColor = Color.White,
focusedBorderColor = Color(222,161,69),
unfocusedBorderColor = Color(222,161,69),
),
modifier = Modifier
.fillMaxWidth()
.padding(top = 20.dp, start = 20.dp, end = 20.dp),
)
OutlinedButton(
onClick = {
productViewModel.addProduct(title.value.text, selectedCategory, price.value.text, searchToken)
},
border = BorderStroke(4.dp, Color(222,161,69)),
shape = RoundedCornerShape(20.dp),
colors = ButtonDefaults.outlinedButtonColors(Color(255,186,83)),
modifier = Modifier
.fillMaxWidth()
.padding(20.dp),
) {
Text(
text = "Сохранить",
fontFamily = FontFamily(Font(R.font.nunito_extrabold_italic)),
fontSize = 30.sp,
color = Color.White
)
}
}
}
}
}
}

View File

@ -1,240 +0,0 @@
package com.example.mobileapp.ui.screens
import androidx.compose.foundation.BorderStroke
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.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card
import androidx.compose.material3.Icon
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavController
import androidx.paging.compose.collectAsLazyPagingItems
import androidx.paging.compose.itemKey
import com.example.mobileapp.data.sharedpref.PreferencesManager
import com.example.mobileapp.R
import com.example.mobileapp.data.db.models.Category
import com.example.mobileapp.data.db.models.Product
import com.example.mobileapp.ui.navigation.Screens
import com.example.mobileapp.viewmodels.MenuViewModel
import com.example.mobileapp.ui.widgets.Header
@Composable
fun EditMenuScreen(navController: NavController){
Column (
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Header(Color(212, 206, 203))
EditMenuCard(navController)
}
}
@Composable
fun EditMenuCard(navController: NavController){
val sharedPref = PreferencesManager(LocalContext.current)
val searchToken = sharedPref.getData("token", "")
val menuViewModel: MenuViewModel = hiltViewModel<MenuViewModel>()
val categoryListUi = menuViewModel.getCategoriesList(searchToken).collectAsLazyPagingItems()
Column(
modifier = Modifier
.fillMaxSize()
.background(Color(212, 206, 203)),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Column(
modifier = Modifier
.fillMaxHeight()
.fillMaxWidth(0.9f)
.background(Color.White),
horizontalAlignment = Alignment.CenterHorizontally,
) {
LazyColumn() {
items(
count = categoryListUi.itemCount,
key = categoryListUi.itemKey()
){ index ->
EditMenuCategoryProductsCard(navController, menuViewModel, categoryListUi[index]!!, searchToken)
}
}
}
}
}
@Composable
fun EditMenuCategoryProductsCard(
navController: NavController,
menuViewModel: MenuViewModel,
category: Category,
searchToken: String
){
val productListUiState = menuViewModel.getProductsByCategoryId(category.id!!, searchToken).collectAsState(initial = listOf())
if (productListUiState.value!= null){
Text(
text = category.name,
color = Color.Black,
fontFamily = FontFamily(Font(R.font.nunito_extrabold_italic)),
fontSize = 34.sp,
modifier = Modifier
.fillMaxWidth()
.padding(top = 10.dp),
textAlign = TextAlign.Center,
)
Column {
productListUiState.value!!.forEach{product ->
EditMenuProductsCard(navController, menuViewModel, product, category, searchToken)
}
}
}
}
@Composable
fun EditMenuProductsCard(
navController: NavController,
menuViewModel: MenuViewModel,
product: Product,
category: Category,
searchToken: String
){
Card(
shape = RoundedCornerShape(20.dp),
border = BorderStroke(3.dp, Color(222,161,69)),
modifier = Modifier
.fillMaxSize()
.padding(top = 15.dp, start = 5.dp, end = 5.dp)
){
Row(
modifier = Modifier
.fillMaxSize()
.background(Color.White),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceEvenly,
){
EditMenuProductImageCard(category.name)
Column (
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.SpaceAround
) {
Text(
text = product.name,
color = Color.Black,
fontFamily = FontFamily(Font(R.font.nunito_extrabold_italic)),
fontSize = 17.sp,
textAlign = TextAlign.Center,
)
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(10.dp),
){
Text(
text = product.price.toString() + " р.",
color = Color.Black,
fontFamily = FontFamily(Font(R.font.nunito_extrabold_italic)),
fontSize = 17.sp,
textAlign = TextAlign.Center,
)
OutlinedButton(
onClick = {
navController.navigate(Screens.EditProductScreen.name + "/${product.id}")
},
border = BorderStroke(4.dp, Color(222,161,69)),
shape = RoundedCornerShape(10.dp),
colors = ButtonDefaults.outlinedButtonColors(Color(255,186,83)),
){
Icon(
painterResource(id = R.drawable.icon_settings),
contentDescription = null,
Modifier.size(30.dp),
tint = Color.Black
)
}
OutlinedButton(
onClick = {
menuViewModel.deleteProduct(product, searchToken)
navController.navigate(Screens.EditMenuScreen.name)
},
border = BorderStroke(4.dp, Color(222,161,69)),
shape = RoundedCornerShape(10.dp),
colors = ButtonDefaults.outlinedButtonColors(Color(255,186,83)),
){
Icon(
painterResource(id = R.drawable.icon_trash),
contentDescription = null,
Modifier.size(30.dp),
tint = Color.Black
)
}
}
}
}
}
}
@Composable
fun EditMenuProductImageCard(categoryName : String){
if (categoryName == "Бургеры"){
Image(
painterResource(
id = R.drawable.burger
),
contentDescription = null,
modifier = Modifier
.size(100.dp, 100.dp)
.padding(5.dp),
)
}
if (categoryName == "Картошка"){
Image(
painterResource(
id = R.drawable.potato
),
contentDescription = null,
modifier = Modifier
.size(100.dp, 100.dp)
.padding(5.dp),
)
}
if (categoryName == "Напитки"){
Image(
painterResource(
id = R.drawable.pepsi
),
contentDescription = null,
modifier = Modifier
.size(100.dp, 100.dp)
.padding(5.dp),
)
}
}

View File

@ -1,240 +0,0 @@
package com.example.mobileapp.ui.screens
import android.annotation.SuppressLint
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.ExposedDropdownMenuDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableStateListOf
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.platform.LocalContext
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavController
import com.example.mobileapp.data.sharedpref.PreferencesManager
import com.example.mobileapp.R
import com.example.mobileapp.data.db.models.Product
import com.example.mobileapp.ui.navigation.Screens
import com.example.mobileapp.viewmodels.ProductViewModel
import com.example.mobileapp.ui.widgets.Header
@Composable
fun EditProductScreen(navController: NavController, id: Int){
Column (
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Header(Color(212, 206, 203))
EditProductCard(navController, id)
}
}
@SuppressLint("CoroutineCreationDuringComposition")
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun EditProductCard(navController: NavController, productId : Int){
val sharedPref = PreferencesManager(LocalContext.current)
val searchToken = sharedPref.getData("token", "")
val productViewModel: ProductViewModel = hiltViewModel<ProductViewModel>()
productViewModel.getProduct(productId, searchToken)
val currentProduct = remember { mutableStateOf<Product?>(null) }
val title = remember { mutableStateOf(TextFieldValue("")) }
val price = remember { mutableStateOf(TextFieldValue("")) }
val categoryList = remember { mutableStateListOf(productViewModel.categories) }
var selectedCategory by remember { mutableStateOf("") }
var expanded by remember { mutableStateOf(false) }
val success = productViewModel.successState.observeAsState().value
if (productViewModel.product.value != null){
currentProduct.value = productViewModel.product.value!!
title.value = TextFieldValue(productViewModel.product.value!!.name)
price.value = TextFieldValue(productViewModel.product.value!!.price.toString())
selectedCategory = productViewModel.getProductCategory(productViewModel.product.value!!.categoryId)
}
if (success == true) {
navController.navigate(Screens.EditMenuScreen.name)
}
Column(
modifier = Modifier
.fillMaxSize()
.background(Color(212, 206, 203)),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Column(
modifier = Modifier
.fillMaxHeight()
.fillMaxWidth(0.9f)
.background(Color.White),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
text = "Редактирование блюда",
color = Color.Black,
fontFamily = FontFamily(Font(R.font.nunito_extrabold_italic)),
fontSize = 34.sp,
modifier = Modifier
.fillMaxWidth()
.padding(top = 10.dp),
textAlign = TextAlign.Center,
)
Card(
shape = RoundedCornerShape(20.dp),
border = BorderStroke(3.dp, Color(222,161,69)),
modifier = Modifier
.padding(top = 15.dp, start = 5.dp, end = 5.dp)
){
Column (
modifier = Modifier.background(Color.White)
) {
OutlinedTextField(
value = title.value,
onValueChange = {title.value = it},
placeholder = { Text(text = "Название", fontSize = 20.sp, color = Color.LightGray) },
singleLine = true,
shape = RoundedCornerShape(20.dp),
textStyle = TextStyle(fontSize = 20.sp),
colors = TextFieldDefaults.outlinedTextFieldColors(
textColor = Color.Black,
disabledTextColor = Color.Transparent,
containerColor = Color.White,
focusedBorderColor = Color(222,161,69),
unfocusedBorderColor = Color(222,161,69),
),
modifier = Modifier
.fillMaxWidth()
.padding(top = 20.dp, start = 20.dp, end = 20.dp),
)
Card(
shape = RoundedCornerShape(20.dp),
border = BorderStroke(1.dp, Color(222,161,69)),
modifier = Modifier
.fillMaxWidth()
.padding(top = 20.dp, start = 20.dp, end = 20.dp),
){
MaterialTheme(
colorScheme = lightColorScheme(
surfaceVariant= Color.White,
surface = Color.White,
onSurface = Color.Gray
)
){
ExposedDropdownMenuBox(
expanded = expanded,
onExpandedChange = {
expanded = !expanded
},
) {
TextField(
modifier = Modifier
.menuAnchor()
.fillMaxWidth(),
readOnly = true,
value = selectedCategory,
onValueChange = {},
label = { Text("Категория") },
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) },
)
ExposedDropdownMenu(
expanded = expanded,
onDismissRequest = {
expanded = false
},
) {
categoryList.first().forEach { selectionOption ->
DropdownMenuItem(
text = { Text(selectionOption.name) },
onClick = {
selectedCategory = selectionOption.name
expanded = false
},
contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding,
)
}
}
}
}
}
OutlinedTextField(
value = price.value,
onValueChange = {price.value = it},
placeholder = { Text(text = "Цена", fontSize = 20.sp, color = Color.LightGray) },
singleLine = true,
shape = RoundedCornerShape(20.dp),
textStyle = TextStyle(fontSize = 20.sp),
colors = TextFieldDefaults.outlinedTextFieldColors(
textColor = Color.Black,
disabledTextColor = Color.Transparent,
containerColor = Color.White,
focusedBorderColor = Color(222,161,69),
unfocusedBorderColor = Color(222,161,69),
),
modifier = Modifier
.fillMaxWidth()
.padding(top = 20.dp, start = 20.dp, end = 20.dp),
)
OutlinedButton(
onClick = {
productViewModel.updateProduct(
currentProduct.value?.id!!,
title.value.text,
selectedCategory,
price.value.text,
searchToken)
},
border = BorderStroke(4.dp, Color(222,161,69)),
shape = RoundedCornerShape(20.dp),
colors = ButtonDefaults.outlinedButtonColors(Color(255,186,83)),
modifier = Modifier
.fillMaxWidth()
.padding(20.dp),
) {
Text(
text = "Сохранить",
fontFamily = FontFamily(Font(R.font.nunito_extrabold_italic)),
fontSize = 30.sp,
color = Color.White
)
}
}
}
}
}
}

View File

@ -1,148 +0,0 @@
package com.example.mobileapp.ui.screens
import androidx.compose.foundation.BorderStroke
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.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
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.material3.ButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavController
import com.example.mobileapp.R
import com.example.mobileapp.ui.navigation.Screens
import com.example.mobileapp.ui.widgets.Header
@Composable
fun ManagmentScreen(navController: NavController){
Column (
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Header(Color(212, 206, 203))
ManagmentCard(navController)
}
}
@Composable
fun ManagmentCard(navController: NavController){
Column(
modifier = Modifier
.fillMaxSize()
.background(Color(212, 206, 203)),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Column(
modifier = Modifier
.fillMaxHeight()
.fillMaxWidth(0.9f)
.background(Color.White),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
text = "Блюда",
color = Color.Black,
fontFamily = FontFamily(Font(R.font.nunito_extrabold_italic)),
fontSize = 34.sp,
modifier = Modifier
.fillMaxWidth()
.padding(top = 10.dp),
textAlign = TextAlign.Center,
)
Row(
horizontalArrangement = Arrangement.spacedBy(5.dp),
modifier = Modifier.padding(top = 10.dp),
){
OutlinedButton(
onClick = {
navController.navigate(Screens.CreateProductScreen.name)
},
border = BorderStroke(4.dp, Color(222,161,69)),
shape = RoundedCornerShape(20.dp),
colors = ButtonDefaults.outlinedButtonColors(Color(255,186,83)),
){
Icon(
painterResource(id = R.drawable.icon_add),
contentDescription = null,
Modifier.size(50.dp),
tint = Color.Black
)
}
OutlinedButton(
onClick = {
navController.navigate(Screens.EditMenuScreen.name)
},
border = BorderStroke(4.dp, Color(222,161,69)),
shape = RoundedCornerShape(20.dp),
colors = ButtonDefaults.outlinedButtonColors(Color(255,186,83)),
){
Icon(
painterResource(id = R.drawable.icon_settings),
contentDescription = null,
Modifier.size(50.dp),
tint = Color.Black
)
}
}
Text(
text = "Пользователи",
color = Color.Black,
fontFamily = FontFamily(Font(R.font.nunito_extrabold_italic)),
fontSize = 34.sp,
modifier = Modifier
.fillMaxWidth()
.padding(top = 10.dp),
textAlign = TextAlign.Center,
)
OutlinedButton(
onClick = {
navController.navigate(Screens.UsersScreen.name)
},
border = BorderStroke(4.dp, Color(222,161,69)),
shape = RoundedCornerShape(20.dp),
colors = ButtonDefaults.outlinedButtonColors(Color(255,186,83)),
modifier = Modifier.padding(top = 10.dp)
){
Icon(
painterResource(id = R.drawable.icon_profile),
contentDescription = null,
Modifier.size(50.dp),
tint = Color.Black
)
Icon(
painterResource(id = R.drawable.icon_order),
contentDescription = null,
Modifier.size(50.dp),
tint = Color.Black
)
Icon(
painterResource(id = R.drawable.icon_managment),
contentDescription = null,
Modifier.size(50.dp),
tint = Color.Black
)
}
}
}
}

View File

@ -1,213 +0,0 @@
package com.example.mobileapp.ui.screens
import androidx.compose.foundation.BorderStroke
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.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.paging.compose.collectAsLazyPagingItems
import androidx.paging.compose.itemKey
import com.example.mobileapp.data.sharedpref.PreferencesManager
import com.example.mobileapp.R
import com.example.mobileapp.data.db.models.Category
import com.example.mobileapp.data.db.models.Product
import com.example.mobileapp.viewmodels.MenuViewModel
import com.example.mobileapp.ui.widgets.Header
@Composable
fun MenuScreen(){
Column (
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Header(Color(212, 206, 203))
MenuCard()
}
}
@Composable
fun MenuCard(){
val sharedPref = PreferencesManager(LocalContext.current)
val searchToken = sharedPref.getData("token", "")
val menuViewModel: MenuViewModel = hiltViewModel<MenuViewModel>()
val categoryListUi = menuViewModel.getCategoriesList(searchToken).collectAsLazyPagingItems()
Column(
modifier = Modifier
.fillMaxSize()
.background(Color(212, 206, 203)),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Column(
modifier = Modifier
.fillMaxHeight()
.fillMaxWidth(0.9f)
.background(Color.White),
horizontalAlignment = Alignment.CenterHorizontally,
) {
LazyColumn() {
items(
count = categoryListUi.itemCount,
key = categoryListUi.itemKey()
){ index ->
MenuCategoryProductsCard(menuViewModel, categoryListUi[index]!!, searchToken)
}
}
}
}
}
@Composable
fun MenuCategoryProductsCard(
menuViewModel: MenuViewModel,
category: Category,
searchToken: String
){
val productListUiState = menuViewModel.getProductsByCategoryId(category.id!!, searchToken).collectAsState(initial = listOf())
if (productListUiState.value != null){
Text(
text = category.name,
color = Color.Black,
fontFamily = FontFamily(Font(R.font.nunito_extrabold_italic)),
fontSize = 34.sp,
modifier = Modifier
.fillMaxWidth()
.padding(top = 10.dp),
textAlign = TextAlign.Center,
)
Column {
productListUiState.value!!.forEach{product ->
MenuProductsCard(menuViewModel, product, category, searchToken)
}
}
}
}
@Composable
fun MenuProductsCard(
menuViewModel: MenuViewModel,
product: Product,
category: Category,
searchToken: String
){
val sharedPref = PreferencesManager(LocalContext.current)
val userId = sharedPref.getData("userId", "").toInt()
Card(
shape = RoundedCornerShape(20.dp),
border = BorderStroke(3.dp, Color(222,161,69)),
modifier = Modifier
.fillMaxSize()
.padding(top = 15.dp, start = 5.dp, end = 5.dp)
){
Row(
modifier = Modifier
.fillMaxSize()
.background(Color.White),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceEvenly,
){
MenuProductImageCard(category.name)
Column (
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.SpaceAround
) {
Text(
text = product.name,
color = Color.Black,
fontFamily = FontFamily(Font(R.font.nunito_extrabold_italic)),
fontSize = 17.sp,
textAlign = TextAlign.Center,
)
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(10.dp),
){
Text(
text = product.price.toString() + " р.",
color = Color.Black,
fontFamily = FontFamily(Font(R.font.nunito_extrabold_italic)),
fontSize = 17.sp,
textAlign = TextAlign.Center,
)
OutlinedButton(
onClick = {
menuViewModel.addProductToCart(product.id!!, userId, searchToken)
},
border = BorderStroke(4.dp, Color(222,161,69)),
shape = RoundedCornerShape(30.dp),
colors = ButtonDefaults.outlinedButtonColors(Color(255,186,83)),
) {
Text(text = "+", fontSize = 20.sp, color = Color.Black)
}
}
}
}
}
}
@Composable
fun MenuProductImageCard(categoryName : String){
if (categoryName == "Бургеры"){
Image(
painterResource(
id = R.drawable.burger
),
contentDescription = null,
modifier = Modifier
.size(100.dp, 100.dp)
.padding(5.dp),
)
}
if (categoryName == "Картошка"){
Image(
painterResource(
id = R.drawable.potato
),
contentDescription = null,
modifier = Modifier
.size(100.dp, 100.dp)
.padding(5.dp),
)
}
if (categoryName == "Напитки"){
Image(
painterResource(
id = R.drawable.pepsi
),
contentDescription = null,
modifier = Modifier
.size(100.dp, 100.dp)
.padding(5.dp),
)
}
}

View File

@ -1,204 +0,0 @@
package com.example.mobileapp.ui.screens
import android.annotation.SuppressLint
import androidx.compose.foundation.BorderStroke
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.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
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.platform.LocalContext
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.paging.compose.collectAsLazyPagingItems
import androidx.paging.compose.itemKey
import com.example.mobileapp.data.sharedpref.PreferencesManager
import com.example.mobileapp.R
import com.example.mobileapp.data.db.models.OrderWithProducts
import com.example.mobileapp.viewmodels.OrderViewModel
import com.example.mobileapp.ui.widgets.Header
import kotlinx.coroutines.launch
@Composable
fun OrderScreen(){
Column (
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Header(Color(212, 206, 203))
OrdersCard()
}
}
@SuppressLint("CoroutineCreationDuringComposition")
@Composable
fun OrdersCard(){
val sharedPref = PreferencesManager(LocalContext.current)
val searchToken = sharedPref.getData("token", "")
val orderViewModel: OrderViewModel = hiltViewModel<OrderViewModel>()
val orderListUiState = orderViewModel.getOrdersList(searchToken).collectAsLazyPagingItems()
Column(
modifier = Modifier
.fillMaxSize()
.background(Color(212, 206, 203)),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Column(
modifier = Modifier
.fillMaxHeight()
.fillMaxWidth(0.9f)
.background(Color.White),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
text = "Заказы",
color = Color.Black,
fontFamily = FontFamily(Font(R.font.nunito_extrabold_italic)),
fontSize = 34.sp,
modifier = Modifier
.fillMaxWidth()
.padding(top = 10.dp),
textAlign = TextAlign.Center,
)
if (orderListUiState != null){
LazyColumn(
modifier = Modifier
.fillMaxWidth()
) {
items(
count = orderListUiState.itemCount,
key = orderListUiState.itemKey()
){ index ->
if (orderListUiState[index] != null){
OrderCard(orderListUiState[index]!!, orderViewModel)
}
}
}
}
}
}
}
@SuppressLint("CoroutineCreationDuringComposition")
@Composable
fun OrderCard(
order: OrderWithProducts,
orderViewModel: OrderViewModel
){
val sharedPref = PreferencesManager(LocalContext.current)
val searchToken = sharedPref.getData("token", "")
val scope = rememberCoroutineScope()
var status by remember { mutableStateOf("")}
scope.launch {
status = orderViewModel.getOrderStatus(order.order.statusId!!)
}
Card(
shape = RoundedCornerShape(20.dp),
border = BorderStroke(3.dp, Color(222,161,69)),
modifier = Modifier
.padding(top = 15.dp, start = 5.dp, end = 5.dp)
){
Row(
modifier = Modifier
.fillMaxWidth()
.background(Color.White),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceEvenly,
){
Text(
text = "" + order.order.id,
color = Color.Black,
fontFamily = FontFamily(Font(R.font.nunito_extrabold_italic)),
fontSize = 34.sp,
textAlign = TextAlign.Center,
)
Text(
text = "Статус: " + status,
color = Color.Black,
fontFamily = FontFamily(Font(R.font.nunito_extrabold_italic)),
fontSize = 20.sp,
textAlign = TextAlign.Center,
)
}
Row(
modifier = Modifier
.fillMaxWidth()
.background(Color.White),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceAround,
){
Column {
if (order.orderWithProducts.size != 0){
order.orderWithProducts.forEach{ orderProduct ->
Row(
modifier = Modifier
.background(Color.White),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center,
){
Text(
text = orderProduct.product.name + " x" + orderProduct.orderProduct.amount.toString(),
color = Color.Gray,
fontFamily = FontFamily(Font(R.font.nunito_bold)),
fontSize = 20.sp,
textAlign = TextAlign.Center,
)
}
}
}
}
OutlinedButton(
onClick = {
orderViewModel.changeOrderStatus(searchToken, order.order.id!!)
when(status){
"Принят" -> {status = "Готов"}
"Готов" -> {status = "Выдан"}
"Выдан" -> {status = "..."}
}
},
border = BorderStroke(4.dp, Color(222,161,69)),
shape = RoundedCornerShape(20.dp),
colors = ButtonDefaults.outlinedButtonColors(Color(255,186,83)),
modifier = Modifier.padding(bottom = 10.dp)
) {
Text(
text = when(status){
"Принят" -> {"Готов"}
"Готов" -> {"Выдать"}
"Выдан" -> {"..."}
else -> {""}
},
fontFamily = FontFamily(Font(R.font.nunito_extrabold_italic)),
fontSize = 30.sp,
color = Color.White
)
}
}
}
}

View File

@ -1,195 +0,0 @@
package com.example.mobileapp.ui.screens
import android.annotation.SuppressLint
import androidx.compose.foundation.BorderStroke
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.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavController
import androidx.paging.compose.collectAsLazyPagingItems
import androidx.paging.compose.itemKey
import com.example.mobileapp.data.sharedpref.PreferencesManager
import com.example.mobileapp.R
import com.example.mobileapp.data.db.models.OrderWithProducts
import com.example.mobileapp.ui.navigation.Screens
import com.example.mobileapp.viewmodels.ProfileViewModel
import com.example.mobileapp.ui.widgets.Header
import kotlinx.coroutines.launch
@Composable
fun ProfileScreen(navController: NavController){
Column (
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Header(Color(212, 206, 203))
ProfileCard(navController)
}
}
@SuppressLint("CoroutineCreationDuringComposition")
@Composable
fun ProfileCard(navController: NavController){
val sharedPref = PreferencesManager(LocalContext.current)
val searchToken = sharedPref.getData("token", "")
val profileViewModel: ProfileViewModel = hiltViewModel<ProfileViewModel>()
val activeOrdersListUiState = profileViewModel.getActiveOrders(searchToken, sharedPref.getData("userId", "-1").toInt())?.collectAsLazyPagingItems()
Column(
modifier = Modifier
.fillMaxSize()
.background(Color(212, 206, 203)),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Column(
modifier = Modifier
.fillMaxHeight()
.fillMaxWidth(0.9f)
.background(Color.White),
horizontalAlignment = Alignment.CenterHorizontally,
) {
OutlinedButton(
modifier = Modifier
.fillMaxWidth()
.padding(top = 15.dp, start = 5.dp, end = 5.dp),
onClick = {
navController.navigate(Screens.AuthorizationScreen.name)
profileViewModel.logout(sharedPref)
},
border = BorderStroke(4.dp, Color(255,86,86)),
shape = RoundedCornerShape(20.dp),
colors = ButtonDefaults.outlinedButtonColors(Color(255,86,86)),
) {
Text(
text = "Выйти из аккаунта",
fontFamily = FontFamily(Font(R.font.nunito_extrabold_italic)),
fontSize = 30.sp,
color = Color.White
)
}
Text(
text = "Активные заказы",
color = Color.Black,
fontFamily = FontFamily(Font(R.font.nunito_extrabold_italic)),
fontSize = 34.sp,
modifier = Modifier
.fillMaxWidth()
.padding(top = 10.dp),
textAlign = TextAlign.Center,
)
if (activeOrdersListUiState != null){
LazyColumn(
modifier = Modifier
.fillMaxWidth()
) {
items(
count = activeOrdersListUiState.itemCount,
key = activeOrdersListUiState.itemKey()
){ index ->
ActiveOrderCard(activeOrdersListUiState[index]!!, profileViewModel)
}
}
}
}
}
}
@SuppressLint("CoroutineCreationDuringComposition")
@Composable
fun ActiveOrderCard(order: OrderWithProducts, profileViewModel: ProfileViewModel) {
val scope = rememberCoroutineScope()
val status = remember { mutableStateOf("")}
scope.launch {
status.value = profileViewModel.getOrderStatus(order.order.statusId!!)
}
Card(
shape = RoundedCornerShape(20.dp),
border = BorderStroke(3.dp, Color(222,161,69)),
modifier = Modifier
.padding(top = 15.dp, start = 5.dp, end = 5.dp)
) {
Row(
modifier = Modifier
.fillMaxWidth()
.background(Color.White),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceEvenly,
) {
Text(
text = "" + order.order.id.toString(),
color = Color.Black,
fontFamily = FontFamily(Font(R.font.nunito_extrabold_italic)),
fontSize = 34.sp,
textAlign = TextAlign.Center,
)
Text(
text = "Статус: " + status.value,
color = Color.Black,
fontFamily = FontFamily(Font(R.font.nunito_extrabold_italic)),
fontSize = 20.sp,
textAlign = TextAlign.Center,
)
}
order.orderWithProducts.forEach { orderProduct ->
Row(
modifier = Modifier
.fillMaxWidth()
.background(Color.White),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center,
) {
Text(
text = orderProduct.product.name + " " + orderProduct.product.price.toString() + "р. x" + orderProduct.orderProduct.amount.toString(),
color = Color.Gray,
fontFamily = FontFamily(Font(R.font.nunito_bold)),
fontSize = 20.sp,
textAlign = TextAlign.Center,
)
}
}
Row(
modifier = Modifier
.fillMaxWidth()
.background(Color.White),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Start,
) {
Text(
text = "К оплате: " + order.order.price.toString() + " р.",
modifier = Modifier.padding(start = 20.dp),
color = Color.Black,
fontFamily = FontFamily(Font(R.font.nunito_extrabold_italic)),
fontSize = 20.sp,
textAlign = TextAlign.Center,
)
}
}
}

View File

@ -1,230 +0,0 @@
package com.example.mobileapp.ui.screens
import androidx.compose.foundation.BorderStroke
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.shape.RoundedCornerShape
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.livedata.observeAsState
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.text.TextStyle
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavController
import com.example.mobileapp.R
import com.example.mobileapp.ui.navigation.Screens
import com.example.mobileapp.viewmodels.RegistrationViewModel
import com.example.mobileapp.ui.widgets.Header
@Composable
fun RegistrationScreen(navController: NavController) {
Column (
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Header(Color.White)
RegistrationCard(navController)
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun RegistrationCard(navController: NavController){
val login = remember { mutableStateOf(TextFieldValue("")) }
val password = remember { mutableStateOf(TextFieldValue("")) }
val passwordRepeat = remember { mutableStateOf(TextFieldValue("")) }
val viewModel = hiltViewModel<RegistrationViewModel>()
val success = viewModel.successState.observeAsState().value
if (success == true) {
navController.navigate(Screens.AuthorizationScreen.name)
}
if (success == false) {
AlertDialog(
title = {
Text(
text = "Ошибка регистрации",
fontWeight = FontWeight.Bold,
fontSize = 20.sp
)
},
text = {
Text(
text = "Проверьте корректность введенных данных",
fontWeight = FontWeight.Normal,
fontSize = 16.sp
)
},
onDismissRequest = {
viewModel.calmSuccessState()
},
confirmButton = {
TextButton(
onClick = {
viewModel.calmSuccessState()
}
) {
Text("ОК")
}
}
)
}
Column(
horizontalAlignment = Alignment.CenterHorizontally,
) {
Card(
shape = RoundedCornerShape(30.dp),
modifier = Modifier.padding(top = 30.dp)
) {
Column (
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.background(Color(212, 206, 203))
.fillMaxWidth(0.9f)
) {
Card(
shape = RoundedCornerShape(90.dp, 90.dp, 30.dp, 30.dp),
border = BorderStroke(4.dp, Color(222,161,69)),
modifier = Modifier
.fillMaxWidth()
.padding(top = 30.dp, start = 20.dp, end = 20.dp)
){
Text(
text = "Регистрация",
color = Color.White,
fontFamily = FontFamily(Font(R.font.nunito_bold)),
fontSize = 30.sp,
modifier = Modifier
.fillMaxWidth()
.background(Color(255, 186, 83))
.padding(top = 20.dp, bottom = 20.dp),
textAlign = TextAlign.Center,
)
}
OutlinedTextField(
value = login.value,
onValueChange = {login.value = it},
placeholder = { Text(text = "Логин", fontSize = 20.sp, color = Color.LightGray) },
singleLine = true,
shape = RoundedCornerShape(30.dp, 30.dp, 30.dp, 30.dp),
textStyle = TextStyle(fontSize = 20.sp),
colors = TextFieldDefaults.outlinedTextFieldColors(
textColor = Color.Black,
disabledTextColor = Color.Transparent,
containerColor = Color.White,
focusedBorderColor = Color.Yellow,
unfocusedBorderColor = Color.Yellow,
),
modifier = Modifier
.fillMaxWidth()
.padding(top = 20.dp, start = 20.dp, end = 20.dp),
)
OutlinedTextField(
value = password.value,
onValueChange = {password.value = it},
placeholder = { Text(text = "Пароль", fontSize = 20.sp, color = Color.LightGray) },
singleLine = true,
shape = RoundedCornerShape(30.dp, 30.dp, 30.dp, 30.dp),
textStyle = TextStyle(fontSize = 20.sp),
colors = TextFieldDefaults.outlinedTextFieldColors(
textColor = Color.Black,
disabledTextColor = Color.Transparent,
containerColor = Color.White,
focusedBorderColor = Color(183,97,48),
unfocusedBorderColor = Color(183,97,48),
),
modifier = Modifier
.fillMaxWidth()
.padding(top = 20.dp, start = 20.dp, end = 20.dp),
)
OutlinedTextField(
value = passwordRepeat.value,
onValueChange = {passwordRepeat.value = it},
placeholder = { Text(text = "Логин повторно", fontSize = 20.sp, color = Color.LightGray) },
singleLine = true,
shape = RoundedCornerShape(30.dp, 30.dp, 30.dp, 30.dp),
textStyle = TextStyle(fontSize = 20.sp),
colors = TextFieldDefaults.outlinedTextFieldColors(
textColor = Color.Black,
disabledTextColor = Color.Transparent,
containerColor = Color.White,
focusedBorderColor = Color.Red,
unfocusedBorderColor = Color.Red,
),
modifier = Modifier
.fillMaxWidth()
.padding(top = 20.dp, start = 20.dp, end = 20.dp),
)
Button(
onClick = {
viewModel.registration(login.value.text, password.value.text, passwordRepeat.value.text)
},
colors = ButtonDefaults.buttonColors(Color(255,186,83), Color.White),
shape = RoundedCornerShape(30.dp, 30.dp, 30.dp, 30.dp),
border = BorderStroke(4.dp, Color(222,161,69)),
modifier = Modifier
.fillMaxWidth()
.padding(top = 20.dp, start = 20.dp, end = 20.dp)
) {
Text(
text = "Продолжить",
color = Color.White,
fontFamily = FontFamily(Font(R.font.nunito_bold)),
fontSize = 30.sp,
textAlign = TextAlign.Center,
)
}
Button(
onClick = {
navController.navigate(Screens.AuthorizationScreen.name)
},
colors = ButtonDefaults.buttonColors(Color(212,206,203)),
modifier = Modifier
.fillMaxWidth()
.padding(top = 10.dp, start = 20.dp, end = 20.dp)
) {
Text(
text = "Есть аккаунт",
color = Color.White,
fontFamily = FontFamily(Font(R.font.nunito_bold)),
fontSize = 20.sp,
textAlign = TextAlign.Center,
)
}
}
}
}
}

View File

@ -1,239 +0,0 @@
package com.example.mobileapp.ui.screens
import android.annotation.SuppressLint
import androidx.compose.foundation.BorderStroke
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.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.ExposedDropdownMenuDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf
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.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.paging.compose.collectAsLazyPagingItems
import androidx.paging.compose.itemKey
import com.example.mobileapp.data.sharedpref.PreferencesManager
import com.example.mobileapp.R
import com.example.mobileapp.data.db.models.User
import com.example.mobileapp.viewmodels.UsersViewModel
import com.example.mobileapp.ui.widgets.Header
@Composable
fun UsersScreen() {
Column (
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Header(Color(212, 206, 203))
UsersCard()
}
}
@SuppressLint("CoroutineCreationDuringComposition")
@Composable
fun UsersCard(){
val sharedPref = PreferencesManager(LocalContext.current)
val usersViewModel: UsersViewModel = hiltViewModel<UsersViewModel>()
val searchToken = sharedPref.getData("token", "")
val userListUiState = usersViewModel.getUsersList(searchToken).collectAsLazyPagingItems()
Column(
modifier = Modifier
.fillMaxSize()
.background(Color(212, 206, 203)),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Column(
modifier = Modifier
.fillMaxHeight()
.fillMaxWidth(0.9f)
.background(Color.White),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
text = "Редактирование пользователей",
color = Color.Black,
fontFamily = FontFamily(Font(R.font.nunito_extrabold_italic)),
fontSize = 34.sp,
modifier = Modifier
.fillMaxWidth()
.padding(top = 10.dp),
textAlign = TextAlign.Center,
)
if (userListUiState != null && usersViewModel.allRoles.size != 0){
LazyColumn(
modifier = Modifier
.fillMaxSize()
) {
items(
count = userListUiState.itemCount,
key = userListUiState.itemKey()
){ index ->
if (userListUiState[index]!!.id != sharedPref.getData("userId", "-1").toInt()){
UserCard(userListUiState[index]!!, usersViewModel)
}
}
}
}
}
}
}
@SuppressLint("CoroutineCreationDuringComposition")
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun UserCard (user: User, usersViewModel: UsersViewModel){
val sharedPref = PreferencesManager(LocalContext.current)
val searchToken = sharedPref.getData("token", "")
val roleList = remember { mutableStateListOf(usersViewModel.allRoles)}
var selectedRole by remember { mutableStateOf(usersViewModel.getUserRole(user.roleId))}
var expanded by remember { mutableStateOf(false) }
Card(
shape = RoundedCornerShape(20.dp),
border = BorderStroke(3.dp, Color(222,161,69)),
modifier = Modifier
.fillMaxSize()
.padding(top = 15.dp, start = 5.dp, end = 5.dp)
){
Row(
modifier = Modifier
.fillMaxSize()
.background(Color.White),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceEvenly,
){
Column (
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.SpaceAround,
modifier = Modifier.fillMaxWidth(0.4f)
) {
Text(
text = "Логин: " + user.login,
color = Color.Black,
fontFamily = FontFamily(Font(R.font.nunito_extrabold_italic)),
fontSize = 17.sp,
textAlign = TextAlign.Center,
modifier = Modifier.padding(top = 5.dp)
)
Card(
shape = RoundedCornerShape(20.dp),
border = BorderStroke(1.dp, Color(222,161,69)),
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 10.dp),
){
MaterialTheme(
colorScheme = lightColorScheme(
surfaceVariant= Color.White,
surface = Color.White,
onSurface = Color.Gray
)
){
ExposedDropdownMenuBox(
expanded = expanded,
onExpandedChange = {
expanded = !expanded
},
) {
TextField(
modifier = Modifier
.menuAnchor()
.fillMaxWidth(),
readOnly = true,
value = selectedRole,
onValueChange = {},
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) },
)
ExposedDropdownMenu(
expanded = expanded,
onDismissRequest = {
expanded = false
},
) {
roleList.first().forEach {selectionOption ->
DropdownMenuItem(
text = { Text(selectionOption.name) },
onClick = {
selectedRole = selectionOption.name
expanded = false
},
contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding,
)
}
}
}
}
}
}
OutlinedButton(
onClick = {
usersViewModel.changeUserRole(user.id!!, selectedRole, searchToken)
},
border = BorderStroke(4.dp, Color(222,161,69)),
shape = RoundedCornerShape(10.dp),
colors = ButtonDefaults.outlinedButtonColors(Color(255,186,83)),
){
Icon(
painterResource(id = R.drawable.icon_settings),
contentDescription = null,
Modifier.size(30.dp),
tint = Color.Black
)
}
OutlinedButton(
onClick = {
usersViewModel.deleteUser(user.id!!, searchToken)
},
border = BorderStroke(4.dp, Color(222,161,69)),
shape = RoundedCornerShape(10.dp),
colors = ButtonDefaults.outlinedButtonColors(Color(255,186,83)),
){
Icon(
painterResource(id = R.drawable.icon_trash),
contentDescription = null,
Modifier.size(30.dp),
tint = Color.Black
)
}
}
}
}

View File

@ -1,11 +0,0 @@
package com.example.mobileapp.ui.theme
import androidx.compose.ui.graphics.Color
val Purple80 = Color(0xFFD0BCFF)
val PurpleGrey80 = Color(0xFFCCC2DC)
val Pink80 = Color(0xFFEFB8C8)
val Purple40 = Color(0xFF6650a4)
val PurpleGrey40 = Color(0xFF625b71)
val Pink40 = Color(0xFF7D5260)

View File

@ -1,70 +0,0 @@
package com.example.mobileapp.ui.theme
import android.app.Activity
import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView
import androidx.core.view.WindowCompat
private val DarkColorScheme = darkColorScheme(
primary = Purple80,
secondary = PurpleGrey80,
tertiary = Pink80
)
private val LightColorScheme = lightColorScheme(
primary = Purple40,
secondary = PurpleGrey40,
tertiary = Pink40
/* Other default colors to override
background = Color(0xFFFFFBFE),
surface = Color(0xFFFFFBFE),
onPrimary = Color.White,
onSecondary = Color.White,
onTertiary = Color.White,
onBackground = Color(0xFF1C1B1F),
onSurface = Color(0xFF1C1B1F),
*/
)
@Composable
fun MobileAppTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
// Dynamic color is available on Android 12+
dynamicColor: Boolean = true,
content: @Composable () -> Unit
) {
val colorScheme = when {
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
val context = LocalContext.current
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
}
darkTheme -> DarkColorScheme
else -> LightColorScheme
}
val view = LocalView.current
if (!view.isInEditMode) {
SideEffect {
val window = (view.context as Activity).window
window.statusBarColor = colorScheme.primary.toArgb()
WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme
}
}
MaterialTheme(
colorScheme = colorScheme,
typography = Typography,
content = content
)
}

View File

@ -1,34 +0,0 @@
package com.example.mobileapp.ui.theme
import androidx.compose.material3.Typography
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
// Set of Material typography styles to start with
val Typography = Typography(
bodyLarge = TextStyle(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Normal,
fontSize = 16.sp,
lineHeight = 24.sp,
letterSpacing = 0.5.sp
)
/* Other default text styles to override
titleLarge = TextStyle(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Normal,
fontSize = 22.sp,
lineHeight = 28.sp,
letterSpacing = 0.sp
),
labelSmall = TextStyle(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Medium,
fontSize = 11.sp,
lineHeight = 16.sp,
letterSpacing = 0.5.sp
)
*/
)

View File

@ -1,76 +0,0 @@
package com.example.mobileapp.ui.widgets
import androidx.compose.foundation.BorderStroke
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.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.example.mobileapp.R
@Composable
fun Header(backColor: Color){
Column {
Card(
shape = RoundedCornerShape(bottomStart = 30.dp, bottomEnd = 30.dp),
border = BorderStroke(4.dp, Color(222,161,69)),
modifier = Modifier
.fillMaxWidth()
.background(backColor),
colors = CardDefaults.cardColors(
containerColor = Color(255, 186, 83)
)
) {
Row (
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth(),
horizontalArrangement = Arrangement.Center,
) {
Text(
text = "Вкусно",
color = Color.Black,
fontFamily = FontFamily(Font(R.font.nunito_extrabold_italic)),
fontSize = 34.sp,
modifier = Modifier
.padding(top = 20.dp, bottom = 20.dp),
textAlign = TextAlign.Center,
)
Image(
painterResource(
id = R.drawable.icon
),
contentDescription = "Logo",
modifier = Modifier
.size(60.dp, 60.dp),
)
Text(
text = "ладно",
color = Color.Black,
fontFamily = FontFamily(Font(R.font.nunito_extrabold_italic)),
fontSize = 34.sp,
modifier = Modifier
.padding(top = 20.dp, bottom = 20.dp),
textAlign = TextAlign.Center,
)
}
}
}
}

View File

@ -1,50 +0,0 @@
package com.example.mobileapp.viewmodels
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.mobileapp.data.sharedpref.PreferencesManager
import com.example.mobileapp.data.db.models.Role
import com.example.mobileapp.data.db.models.User
import com.example.mobileapp.data.repositories.RoleRepository
import com.example.mobileapp.data.repositories.UserRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class AuthorizationViewModel @Inject constructor(
private val userRepository: UserRepository,
private val roleRepository: RoleRepository
) : ViewModel() {
private val _successState = MutableLiveData<Boolean?>()
val successState: LiveData<Boolean?>
get() = _successState
fun calmSuccessState() {
_successState.postValue(null)
}
fun login(sharedPref: PreferencesManager, login: String, password: String) {
viewModelScope.launch {
val token_response = userRepository.getToken(User(null, login, password,-1))
if (token_response.access_token.isNotEmpty()) {
val user = userRepository.checkLogin(User(null, login, password, -1))
if (user != null){
val role = roleRepository.getRole(Role(user.role_id, ""))
if (role != null){
sharedPref.saveData("userId", user.id.toString())
sharedPref.saveData("userRole", role.name)
sharedPref.saveData("token", token_response.access_token)
_successState.postValue(true)
println(token_response.access_token)
}
}
}
else {
_successState.postValue(false)
}
}
}
}

View File

@ -1,89 +0,0 @@
package com.example.mobileapp.viewmodels
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.mobileapp.data.db.models.OrderProduct
import com.example.mobileapp.data.db.models.OrderWithProducts
import com.example.mobileapp.data.repositories.OrderProductRepository
import com.example.mobileapp.data.repositories.OrderRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class CartViewModel @Inject constructor(
private val orderRepository: OrderRepository,
private val orderProductRepository: OrderProductRepository
) : ViewModel() {
private val _cart = MutableLiveData<OrderWithProducts?>()
val cart: LiveData<OrderWithProducts?>
get() = _cart
fun getCart(token: String) {
viewModelScope.launch {
_cart.postValue(orderRepository.getCartByUser(token))
}
}
fun makeOrder(token: String) {
if (cart.value == null){
return
}
val model = cart.value!!.order
model.statusId = 2
viewModelScope.launch {
orderRepository.update(token, model)
}
_cart.postValue(null)
}
fun removeProductFromOrder(token: String, productId: Int) {
val orderModel = cart.value!!.order
var productModel : OrderProduct? = null
cart.value!!.orderWithProducts.map {
if (it.orderProduct.productId == productId){
productModel = it.orderProduct
orderModel.price -= it.product.price
}
}
if(productModel!!.amount == 1) {
// delete
viewModelScope.launch {
orderRepository.update(token, orderModel)
orderProductRepository.delete(token, productModel!!)
getCart(token)
}
}
else{
// update
productModel!!.amount -= 1
viewModelScope.launch {
orderRepository.update(token, orderModel)
orderProductRepository.update(token, productModel!!)
getCart(token)
}
}
}
fun addProductToOrder(token: String, productId: Int) {
val orderModel = cart.value!!.order
var productModel : OrderProduct? = null
cart.value!!.orderWithProducts.map {
if (it.orderProduct.productId == productId){
productModel = it.orderProduct
orderModel.price += it.product.price
}
}
// update
productModel!!.amount += 1
viewModelScope.launch {
orderRepository.update(token, orderModel)
orderProductRepository.update(token, productModel!!)
getCart(token)
}
}
}

View File

@ -1,80 +0,0 @@
package com.example.mobileapp.viewmodels
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.PagingData
import com.example.mobileapp.data.api.models.ProductRemote
import com.example.mobileapp.data.api.models.toProduct
import com.example.mobileapp.data.db.models.Category
import com.example.mobileapp.data.db.models.Order
import com.example.mobileapp.data.db.models.OrderProduct
import com.example.mobileapp.data.db.models.Product
import com.example.mobileapp.data.repositories.CategoryRepository
import com.example.mobileapp.data.repositories.OrderProductRepository
import com.example.mobileapp.data.repositories.OrderRepository
import com.example.mobileapp.data.repositories.ProductRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import java.util.stream.Collectors
import javax.inject.Inject
@HiltViewModel
class MenuViewModel @Inject constructor(
private val categoryRepository: CategoryRepository,
private val orderRepository: OrderRepository,
private val orderProductRepository: OrderProductRepository,
private val productRepository: ProductRepository
) : ViewModel() {
fun getCategoriesList(token: String) : Flow<PagingData<Category>> {
return categoryRepository.getAllPaged(token)
}
fun getProductsByCategoryId(categoryId: Int, token: String): Flow<MutableList<Product>?> {
return flow{ emit(productRepository.getProductsByCategoryId(categoryId, token).stream().map(
ProductRemote::toProduct).collect(Collectors.toList())) }
}
fun deleteProduct(product : Product, token: String) {
viewModelScope.launch {
productRepository.delete(product, token)
}
}
fun addProductToCart(productId: Int, userId: Int, token: String) {
viewModelScope.launch {
val product = productRepository.getProductById(productId, token)
val order = orderRepository.getCartByUser(token)
if (order == null) {
val newOrder = orderRepository.insert(token, Order(null, userId, product.price, 1 ))
if (newOrder != null) {
orderProductRepository.insert(token, OrderProduct(newOrder.id!!, productId, 1))
}
}
else {
var isAlreadyAdded = false
for (prod in order.orderWithProducts) {
if (prod.product != null) {
if (prod.product.id == productId) {
val newOrderProduct = prod.orderProduct
newOrderProduct.amount += 1
val newOrder = order.order
newOrder.price += prod.product.price
orderProductRepository.update(token, newOrderProduct)
orderRepository.update(token, newOrder)
isAlreadyAdded = true
}
}
}
if (!isAlreadyAdded) {
orderProductRepository.insert(token, OrderProduct(order.order.id!!, productId, 1))
val newOrder = order.order
newOrder.price += product.price
orderRepository.update(token, newOrder)
}
}
}
}
}

View File

@ -1,48 +0,0 @@
package com.example.mobileapp.viewmodels
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.PagingData
import com.example.mobileapp.data.db.models.OrderWithProducts
import com.example.mobileapp.data.db.models.Status
import com.example.mobileapp.data.repositories.OrderRepository
import com.example.mobileapp.data.repositories.StatusRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class OrderViewModel @Inject constructor(
private val statusRepository: StatusRepository,
private val orderRepository: OrderRepository
) : ViewModel() {
fun getOrdersList(token: String) : Flow<PagingData<OrderWithProducts>> {
return orderRepository.getOrdersToWorkPaged(token)
}
suspend fun getOrderStatus(statusId: Int) : String{
return statusRepository.getStatus(Status(statusId, ""))!!.name
}
fun changeOrderStatus(token: String, orderId: Int) {
viewModelScope.launch {
val order = orderRepository.getById(orderId).first()
when(statusRepository.getStatus(Status(order.order.statusId, ""))!!.name){
"Принят" -> {
val newOrder = order.order
newOrder.statusId = statusRepository.getStatus(Status(null, "Готов"))!!.id!!
orderRepository.update(token, newOrder)
}
"Готов" -> {
val newOrder = order.order
newOrder.statusId = statusRepository.getStatus(Status(null, "Выдан"))!!.id!!
orderRepository.update(token, newOrder)
}
}
}
}
}

View File

@ -1,108 +0,0 @@
package com.example.mobileapp.viewmodels
import androidx.compose.runtime.mutableStateListOf
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.mobileapp.data.api.models.CategoryRemote
import com.example.mobileapp.data.api.models.toCategory
import com.example.mobileapp.data.db.models.Category
import com.example.mobileapp.data.db.models.Product
import com.example.mobileapp.data.repositories.CategoryRepository
import com.example.mobileapp.data.repositories.ProductRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import java.util.stream.Collectors
import javax.inject.Inject
@HiltViewModel
class ProductViewModel @Inject constructor(
private val productRepository: ProductRepository,
private val categoryRepository: CategoryRepository,
) : ViewModel() {
private val _successState = MutableLiveData<Boolean?>()
private val _categories = mutableStateListOf<Category>()
val categories: List<Category>
get() = _categories
val successState: LiveData<Boolean?>
get() = _successState
private val _product = MutableLiveData<Product?>()
val product: LiveData<Product?>
get() = _product
fun getProduct(productId: Int, token: String) {
viewModelScope.launch {
_product.postValue(productRepository.getProductById(productId, token))
}
}
init {
if (categories.size == 0){
viewModelScope.launch {
_categories.addAll(categoryRepository.getCategories().stream().map(CategoryRemote::toCategory).collect(Collectors.toList()))
}
}
}
fun getProductCategory(categoryId : Int) : String{
return categories.find { it.id == categoryId }?.name ?: ""
}
fun addProduct(name: String, categoryName: String, price: String, token: String) {
if (name.isEmpty() || name.length > 10 || name.length < 3){
_successState.postValue(false)
return
}
if (categoryName.isEmpty()){
_successState.postValue(false)
return
}
if (price.isEmpty() || price.toIntOrNull() == null || price.toInt() <= 0){
_successState.postValue(false)
return
}
viewModelScope.launch {
productRepository.insert(
Product(
null,
name,
categories.find { it.name == categoryName }!!.id!!,
price.toInt()
),
token
)
_successState.postValue(true)
}
}
fun updateProduct(id: Int, name: String, categoryName: String, price: String, token: String) {
if (name.isEmpty() || name.length > 10 || name.length < 3){
_successState.postValue(false)
return
}
if (categoryName.isEmpty()){
_successState.postValue(false)
return
}
if (price.isEmpty() || price.toIntOrNull() == null || price.toInt() <= 0){
_successState.postValue(false)
return
}
viewModelScope.launch {
productRepository.update(
Product(
id,
name,
categories.find {it.name == categoryName}!!.id!!,
price.toInt()
),
token
)
_successState.postValue(true)
}
}
}

View File

@ -1,35 +0,0 @@
package com.example.mobileapp.viewmodels
import androidx.lifecycle.ViewModel
import androidx.paging.PagingData
import com.example.mobileapp.data.sharedpref.PreferencesManager
import com.example.mobileapp.data.db.models.OrderWithProducts
import com.example.mobileapp.data.db.models.Status
import com.example.mobileapp.data.repositories.OrderRepository
import com.example.mobileapp.data.repositories.StatusRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject
@HiltViewModel
class ProfileViewModel @Inject constructor(
private val orderRepository: OrderRepository,
private val statusRepository: StatusRepository
) : ViewModel() {
fun getActiveOrders(token: String, userId: Int) : Flow<PagingData<OrderWithProducts>>? {
if (token.isNotEmpty() && userId.toString().isNotEmpty()){
return orderRepository.getOrdersByUserPaged(token, userId)
}
return null
}
suspend fun getOrderStatus(statusId: Int) : String{
return statusRepository.getStatus(Status(statusId, ""))!!.name
}
fun logout(sharedPref: PreferencesManager) {
sharedPref.deleteData("userId")
sharedPref.deleteData("userRole")
sharedPref.deleteData("token")
}
}

View File

@ -1,60 +0,0 @@
package com.example.mobileapp.viewmodels
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.mobileapp.data.db.models.User
import com.example.mobileapp.data.repositories.UserRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class RegistrationViewModel @Inject constructor(
private val userRepository: UserRepository
) : ViewModel() {
private val _successState = MutableLiveData<Boolean?>()
val successState: LiveData<Boolean?>
get() = _successState
fun calmSuccessState() {
_successState.postValue(null)
}
fun registration(login: String, password: String, confirmPassword: String) {
if (login.length < 3 || login.length > 20) {
_successState.postValue(false)
return
}
if (password.length < 3 || password.length > 20) {
_successState.postValue(false)
return
}
if (password != confirmPassword) {
_successState.postValue(false)
return
}
viewModelScope.launch {
val user_response = userRepository.checkLogin(User(null, login, password, -1))
if (user_response != null) {
if (user_response.login.isNullOrEmpty()) {
if (login == "admin" && password == "admin") {
userRepository.insert(User(null, login, password, 1))
_successState.postValue(true)
}
else {
userRepository.insert(User(null, login, password, 3))
_successState.postValue(true)
}
}
else {
_successState.postValue(false)
}
}
}
}
}

View File

@ -1,58 +0,0 @@
package com.example.mobileapp.viewmodels
import androidx.compose.runtime.mutableStateListOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.PagingData
import com.example.mobileapp.data.api.models.RoleRemote
import com.example.mobileapp.data.api.models.toRole
import com.example.mobileapp.data.db.models.Role
import com.example.mobileapp.data.db.models.User
import com.example.mobileapp.data.repositories.RoleRepository
import com.example.mobileapp.data.repositories.UserRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch
import java.util.stream.Collectors
import javax.inject.Inject
@HiltViewModel
class UsersViewModel @Inject constructor(
private val userRepository: UserRepository,
private val roleRepository: RoleRepository
) : ViewModel() {
private val _allRoles = mutableStateListOf<Role>()
val allRoles: List<Role>
get() = _allRoles
init {
viewModelScope.launch {
_allRoles.addAll(roleRepository.getRoles().stream().map(RoleRemote::toRole).collect(Collectors.toList()))
}
}
fun getUsersList(token: String) : Flow<PagingData<User>> {
return userRepository.getAllPaged(token)
}
fun getUserRole(roleId: Int) : String {
return allRoles.find { it.id == roleId }?.name ?: ""
}
fun changeUserRole(userId: Int, roleName: String, token: String) {
viewModelScope.launch {
userRepository.update(
User(
userId, "","",
allRoles.find { it.name == roleName }!!.id!!),
token
)
}
}
fun deleteUser(userId: Int, token: String){
viewModelScope.launch{
userRepository.delete(User(userId, "","",-1),token)
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 164 KiB

View File

@ -1,170 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>

View File

@ -1,30 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 250 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

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