many done

This commit is contained in:
Zyzf 2023-12-14 22:14:12 +04:00
parent d2db976f34
commit 8c7ed46049
47 changed files with 346 additions and 281 deletions

3
.idea/.gitignore vendored
View File

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

View File

@ -1 +0,0 @@
Coffee Preorder

View File

@ -5,7 +5,7 @@
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="jbr-17" />
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />

View File

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

View File

@ -1,3 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<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">

View File

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

View File

@ -2,6 +2,7 @@ plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("com.google.devtools.ksp")
id("org.jetbrains.kotlin.plugin.serialization")
}
android {
@ -41,7 +42,7 @@ android {
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = "1.5.5"
kotlinCompilerExtensionVersion = "1.5.3"
}
packaging {
resources {
@ -56,12 +57,9 @@ kotlin {
dependencies {
// Retrofit
implementation("com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:1.0.0")
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("io.coil-kt:coil-compose:2.5.0")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.2")
implementation("com.squareup.okhttp3:logging-interceptor:4.11.0")
implementation("androidx.paging:paging-compose:3.2.1")
implementation("com.squareup.okhttp3:logging-interceptor:4.12.0")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.2")
implementation("com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:1.0.0")
@ -72,30 +70,30 @@ dependencies {
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2")
// UI
implementation("androidx.activity:activity-compose:1.8.1")
implementation("androidx.activity:activity-compose:1.8.2")
implementation(platform("androidx.compose:compose-bom:2023.10.01"))
implementation("androidx.navigation:navigation-compose:2.7.5")
implementation("androidx.compose.ui:ui:1.6.0-beta02")
implementation("androidx.compose.ui:ui-graphics:1.6.0-beta02")
implementation("androidx.compose.ui:ui-tooling-preview:1.6.0-beta02")
implementation("androidx.navigation:navigation-compose:2.7.6")
implementation("androidx.compose.ui:ui:1.6.0-beta03")
implementation("androidx.compose.ui:ui-graphics:1.6.0-beta03")
implementation("androidx.compose.ui:ui-tooling-preview:1.6.0-beta03")
implementation("androidx.compose.material3:material3:1.1.2")
implementation("androidx.compose.material:material:1.5.4")
implementation("androidx.paging:paging-compose:3.2.1")
implementation("eu.bambooapps:compose-material3-pullrefresh:1.0.1")
// Room
val roomVersion = "2.6.1"
implementation("androidx.room:room-runtime:$roomVersion")
annotationProcessor("androidx.room:room-compiler:$roomVersion")
ksp("androidx.room:room-compiler:$roomVersion")
implementation("androidx.room:room-ktx:$roomVersion")
implementation("androidx.room:room-paging:$roomVersion")
implementation("androidx.room:room-runtime:2.6.1")
annotationProcessor("androidx.room:room-compiler:2.6.1")
ksp("androidx.room:room-compiler:2.6.1")
implementation("androidx.room:room-ktx:2.6.1")
implementation("androidx.room:room-paging:2.6.1")
// Tests
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.10.01"))
androidTestImplementation("androidx.compose.ui:ui-test-junit4:1.6.0-beta02")
debugImplementation("androidx.compose.ui:ui-tooling:1.6.0-beta02")
debugImplementation("androidx.compose.ui:ui-test-manifest:1.6.0-beta02")
androidTestImplementation("androidx.compose.ui:ui-test-junit4:1.6.0-beta03")
debugImplementation("androidx.compose.ui:ui-tooling:1.6.0-beta03")
debugImplementation("androidx.compose.ui:ui-test-manifest:1.6.0-beta03")
}

View File

@ -1,21 +1,48 @@
# 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
# Retrofit does reflection on generic parameters. InnerClasses is required to use Signature and
# EnclosingMethod is required to use InnerClasses.
-keepattributes Signature, InnerClasses, EnclosingMethod
# 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 *;
#}
# Retrofit does reflection on method and parameter annotations.
-keepattributes RuntimeVisibleAnnotations, RuntimeVisibleParameterAnnotations
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# Keep annotation default values (e.g., retrofit2.http.Field.encoded).
-keepattributes AnnotationDefault
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
# Retain service method parameters when optimizing.
-keepclassmembers,allowshrinking,allowobfuscation interface * {
@retrofit2.http.* <methods>;
}
# Ignore annotation used for build tooling.
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
# Ignore JSR 305 annotations for embedding nullability information.
-dontwarn javax.annotation.**
# Guarded by a NoClassDefFoundError try/catch and only used when on the classpath.
-dontwarn kotlin.Unit
# Top-level functions that can only be used by Kotlin.
-dontwarn retrofit2.KotlinExtensions
-dontwarn retrofit2.KotlinExtensions$*
# With R8 full mode, it sees no subtypes of Retrofit interfaces since they are created with a Proxy
# and replaces all potential values with null. Explicitly keeping the interfaces prevents this.
-if interface * { @retrofit2.http.* <methods>; }
-keep,allowobfuscation interface <1>
# Keep inherited services.
-if interface * { @retrofit2.http.* <methods>; }
-keep,allowobfuscation interface * extends <1>
# With R8 full mode generic signatures are stripped for classes that are not
# kept. Suspend functions are wrapped in continuations where the type argument
# is used.
-keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation
# R8 full mode strips generic signatures from return types if not kept.
-if interface * { @retrofit2.http.* public *** *(...); }
-keep,allowoptimization,allowshrinking,allowobfuscation class <3>
# With R8 full mode generic signatures are stripped for classes that are not kept.
-keep,allowobfuscation,allowshrinking class retrofit2.Response

View File

@ -8,7 +8,7 @@
<uses-permission android:name="com.google.android.gms.persmission.AD_ID" />
<application
android:name=".CoffeeApplication"
android:allowBackup="false"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
@ -16,7 +16,8 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.CoffeePreorder"
tools:targetApi="31">
tools:targetApi="31"
android:networkSecurityConfig="@xml/network_security_config">
<activity
android:name=".MainComposeActivity"
android:exported="true"

View File

@ -3,6 +3,7 @@ package com.zyzf.coffeepreorder
import android.app.Application
import com.zyzf.coffeepreorder.database.AppContainer
import com.zyzf.coffeepreorder.database.AppDataContainer
import com.zyzf.coffeepreorder.database.model.Coffee
import com.zyzf.coffeepreorder.database.model.User
class CoffeeApplication : Application() {

View File

@ -17,68 +17,68 @@ import retrofit2.http.Path
import retrofit2.http.Query
interface MyServerService {
@GET("user")
@GET("user/")
suspend fun getUsers(
@Query("pageNo") page: Int,
@Query("pageSize") limit: Int,
): List<UserRemote>
@GET("user/{id}")
@GET("user/{id}/")
suspend fun getUser(
@Path("id") id: Int,
): UserRemote
@GET("user")
suspend fun tryLogin(
@Body login: String,
@Body password: String,
): UserRemote
@GET("user/tryLogin")
fun tryLogin(
@Query("login") login: String,
@Query("password") password: String,
): UserRemote?
@POST("user")
suspend fun createUser(
@POST("user/")
fun createUser(
@Body user: UserRemote,
): UserRemote
@PUT("user/{id}")
suspend fun updateUser(
@PUT("user/{id}/")
fun updateUser(
@Path("id") id: Int,
@Body user: UserRemote,
): UserRemote
@DELETE("user/{id}")
@DELETE("user/{id}/")
suspend fun deleteUser(
@Path("id") id: Int,
): UserRemote
@GET("coffee")
@GET("coffee/")
suspend fun getCoffees(
@Query("pageNo") page: Int,
@Query("pageSize") limit: Int,
): List<CoffeeRemote>
@GET("coffee/{id}")
@GET("coffee/{id}/")
suspend fun getCoffee(
@Path("id") id: Int,
): CoffeeRemote
@POST("coffee")
suspend fun createCoffee(
@POST("coffee/")
fun createCoffee(
@Body coffee: CoffeeRemote,
): CoffeeRemote
@PUT("coffee/{id}")
suspend fun updateCoffee(
@PUT("coffee/{id}/")
fun updateCoffee(
@Path("id") id: Int,
@Body coffee: CoffeeRemote,
): CoffeeRemote
@DELETE("coffee/{id}")
@DELETE("coffee/{id}/")
suspend fun deleteCoffee(
@Path("id") id: Int,
): CoffeeRemote
companion object {
private const val BASE_URL = "http://192.168.42.94:8080/api/"
private const val BASE_URL = "http://192.168.0.100:8080/api/"
@Volatile
private var INSTANCE: MyServerService? = null

View File

@ -56,7 +56,7 @@ class CoffeeRemoteMediator(
val endOfPaginationReached = coffees.isEmpty()
database.withTransaction {
if (loadType == LoadType.REFRESH) {
dbRemoteKeyRepository.deleteRemoteKey(RemoteKeyType.Coffee)
dbRemoteKeyRepository.deleteRemoteKey(RemoteKeyType.COFFEE)
dbCoffeeRepository.clearCoffees()
}
val prevKey = if (page == 1) null else page - 1
@ -64,15 +64,13 @@ class CoffeeRemoteMediator(
val keys = coffees.map {
RemoteKeys(
entityId = it.uid,
type = RemoteKeyType.Coffee,
type = RemoteKeyType.COFFEE,
prevKey = prevKey,
nextKey = nextKey
)
}
dbRemoteKeyRepository.createRemoteKeys(keys)
for (coffee in coffees) {
dbCoffeeRepository.insert(coffee.name, coffee.cost, coffee.ingredients)
}
dbCoffeeRepository.insertCoffees(coffees)
}
return MediatorResult.Success(endOfPaginationReached = endOfPaginationReached)
} catch (exception: IOException) {
@ -85,14 +83,14 @@ class CoffeeRemoteMediator(
private suspend fun getRemoteKeyForLastItem(state: PagingState<Int, Coffee>): RemoteKeys? {
return state.pages.lastOrNull { it.data.isNotEmpty() }?.data?.lastOrNull()
?.let { coffee ->
dbRemoteKeyRepository.getAllRemoteKeys(coffee.uid, RemoteKeyType.Coffee)
dbRemoteKeyRepository.getAllRemoteKeys(coffee.uid, RemoteKeyType.COFFEE)
}
}
private suspend fun getRemoteKeyForFirstItem(state: PagingState<Int, Coffee>): RemoteKeys? {
return state.pages.firstOrNull { it.data.isNotEmpty() }?.data?.firstOrNull()
?.let { coffee ->
dbRemoteKeyRepository.getAllRemoteKeys(coffee.uid, RemoteKeyType.Coffee)
dbRemoteKeyRepository.getAllRemoteKeys(coffee.uid, RemoteKeyType.COFFEE)
}
}
@ -101,7 +99,7 @@ class CoffeeRemoteMediator(
): RemoteKeys? {
return state.anchorPosition?.let { position ->
state.closestItemToPosition(position)?.uid?.let { coffeeUid ->
dbRemoteKeyRepository.getAllRemoteKeys(coffeeUid, RemoteKeyType.Coffee)
dbRemoteKeyRepository.getAllRemoteKeys(coffeeUid, RemoteKeyType.COFFEE)
}
}
}

View File

@ -22,7 +22,7 @@ class RestCoffeeRepository(
private val dbRemoteKeyRepository: OfflineRemoteKeyRepository,
private val database: AppDatabase
) : CoffeeRepository {
override fun getAll(): Flow<PagingData<Coffee>> {
override fun getAllCoffees(): Flow<PagingData<Coffee>> {
Log.d(RestCoffeeRepository::class.simpleName, "Get coffees")
val pagingSourceFactory = { dbCoffeeRepository.getAllCoffeesPagingSource() }
@ -43,15 +43,15 @@ class RestCoffeeRepository(
).flow
}
override suspend fun getByUid(uid: Int): Coffee? =
override suspend fun getByUid(uid: Int): Coffee =
service.getCoffee(uid).toCoffee()
override suspend fun insert(name: String, cost: Double, ingredients: String): Long {
return service.createCoffee(Coffee(name, cost, ingredients).toCoffeeRemote()).toCoffee().uid.toLong()
override fun insert(coffee: Coffee): Long {
return service.createCoffee(coffee.toCoffeeRemote()).toCoffee().uid.toLong()
}
override suspend fun update(uid: Int, name: String, cost: Double, ingredients: String): Int? {
return service.updateCoffee(uid, Coffee(uid, name, cost, ingredients).toCoffeeRemote()).toCoffee().uid
override fun update(coffee: Coffee): Int {
return service.updateCoffee(coffee.uid, coffee.toCoffeeRemote()).toCoffee().uid
}
override suspend fun delete(coffee: Coffee) {

View File

@ -52,19 +52,19 @@ class RestUserRepository(
override suspend fun getByUid(uid: Int): User? =
service.getUser(uid).toUser()
override suspend fun tryLogin(login: String, password: String): User? =
service.tryLogin(login, password).toUser()
override fun tryLogin(login: String, password: String): User? =
service.tryLogin(login, password)?.toUser()
override suspend fun insert(login: String, fio: String, phone: String, password: String, role: String): Long {
return service.createUser(User(login, fio, phone, password, role).toUserRemote()).toUser().uid.toLong()
override fun insert(user: User): Long {
return service.createUser(user.toUserRemote()).toUser().uid.toLong()
}
override suspend fun update(uid: Int, login: String, fio: String, phone: String, password: String, role: String): Int? {
return service.updateUser(uid, User(uid, login, fio, phone, password, role).toUserRemote()).toUser().uid
override fun update(user: User): Int? {
return service.updateUser(user.uid, user.toUserRemote()).toUser().uid
}
override suspend fun delete(userId: Int) {
service.deleteUser(userId).toUser()
override suspend fun delete(user: User) {
service.deleteUser(user.uid).toUser()
}
}

View File

@ -59,22 +59,21 @@ class UserRemoteMediator(
val endOfPaginationReached = users.isEmpty()
database.withTransaction {
if (loadType == LoadType.REFRESH) {
dbRemoteKeyRepository.deleteRemoteKey(RemoteKeyType.User)
dbRemoteKeyRepository.deleteRemoteKey(RemoteKeyType.USER)
dbUserRepository.clearUsers()
}
val prevKey = if (page == 1) null else page - 1
val nextKey = if (endOfPaginationReached) null else page + 1
val keys = users.map {
RemoteKeys(
entityId = it.uid,
type = RemoteKeyType.User,
type = RemoteKeyType.USER,
prevKey = prevKey,
nextKey = nextKey
)
}
dbRemoteKeyRepository.createRemoteKeys(keys)
for (user in users) {
dbUserRepository.insert(user.login, user.fio, user.phone, user.password, user.role)
}
dbUserRepository.insertUsers(users)
}
return MediatorResult.Success(endOfPaginationReached = endOfPaginationReached)
} catch (exception: IOException) {
@ -87,14 +86,14 @@ class UserRemoteMediator(
private suspend fun getRemoteKeyForLastItem(state: PagingState<Int, User>): RemoteKeys? {
return state.pages.lastOrNull { it.data.isNotEmpty() }?.data?.lastOrNull()
?.let { user ->
dbRemoteKeyRepository.getAllRemoteKeys(user.uid, RemoteKeyType.User)
dbRemoteKeyRepository.getAllRemoteKeys(user.uid, RemoteKeyType.USER)
}
}
private suspend fun getRemoteKeyForFirstItem(state: PagingState<Int, User>): RemoteKeys? {
return state.pages.firstOrNull { it.data.isNotEmpty() }?.data?.firstOrNull()
?.let { user ->
dbRemoteKeyRepository.getAllRemoteKeys(user.uid, RemoteKeyType.User)
dbRemoteKeyRepository.getAllRemoteKeys(user.uid, RemoteKeyType.USER)
}
}
@ -103,7 +102,7 @@ class UserRemoteMediator(
): RemoteKeys? {
return state.anchorPosition?.let { position ->
state.closestItemToPosition(position)?.uid?.let { userUid ->
dbRemoteKeyRepository.getAllRemoteKeys(userUid, RemoteKeyType.User)
dbRemoteKeyRepository.getAllRemoteKeys(userUid, RemoteKeyType.USER)
}
}
}

View File

@ -1,17 +1,19 @@
package com.zyzf.coffeepreorder.database
import android.content.Context
import com.zyzf.coffeepreorder.api.MyServerService
import com.zyzf.coffeepreorder.api.coffee.RestCoffeeRepository
import com.zyzf.coffeepreorder.api.user.RestUserRepository
import com.zyzf.coffeepreorder.database.repository.CartRepository
import com.zyzf.coffeepreorder.database.repository.CoffeeRepository
import com.zyzf.coffeepreorder.database.repository.OfflineCartRepository
import com.zyzf.coffeepreorder.database.repository.OfflineCoffeeRepository
import com.zyzf.coffeepreorder.database.repository.OfflineRemoteKeyRepository
import com.zyzf.coffeepreorder.database.repository.OfflineUserRepository
import com.zyzf.coffeepreorder.database.repository.UserRepository
interface AppContainer {
val coffeeRepository: CoffeeRepository
val userRepository: UserRepository
val cartRepository: CartRepository
val coffeeRestRepository: RestCoffeeRepository
val userRestRepository: RestUserRepository
companion object {
const val TIMEOUT = 5000L
@ -20,13 +22,32 @@ interface AppContainer {
}
class AppDataContainer(private val context: Context) : AppContainer {
override val coffeeRepository: CoffeeRepository by lazy {
private val coffeeRepository: OfflineCoffeeRepository by lazy {
OfflineCoffeeRepository(AppDatabase.getInstance(context).coffeeDao())
}
override val userRepository: UserRepository by lazy {
private val userRepository: OfflineUserRepository by lazy {
OfflineUserRepository(AppDatabase.getInstance(context).userDao())
}
override val cartRepository: CartRepository by lazy {
OfflineCartRepository(AppDatabase.getInstance(context).cartDao())
}
private val remoteKeyRepository: OfflineRemoteKeyRepository by lazy {
OfflineRemoteKeyRepository(AppDatabase.getInstance(context).remoteKeysDao())
}
override val coffeeRestRepository: RestCoffeeRepository by lazy {
RestCoffeeRepository(
MyServerService.getInstance(),
coffeeRepository,
remoteKeyRepository,
AppDatabase.getInstance(context)
)
}
override val userRestRepository: RestUserRepository by lazy {
RestUserRepository(
MyServerService.getInstance(),
userRepository,
remoteKeyRepository,
AppDatabase.getInstance(context)
)
}
}

View File

@ -4,22 +4,21 @@ import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.sqlite.db.SupportSQLiteDatabase
import com.zyzf.coffeepreorder.database.dao.CartDao
import com.zyzf.coffeepreorder.database.dao.CoffeeDao
import com.zyzf.coffeepreorder.database.dao.RemoteKeysDao
import com.zyzf.coffeepreorder.database.dao.UserDao
import com.zyzf.coffeepreorder.database.model.Cart
import com.zyzf.coffeepreorder.database.model.Coffee
import com.zyzf.coffeepreorder.database.model.RemoteKeys
import com.zyzf.coffeepreorder.database.model.User
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@Database(entities = [User::class, Coffee::class, Cart::class], version = 1, exportSchema = false)
@Database(entities = [User::class, Coffee::class, Cart::class, RemoteKeys::class], version = 1, exportSchema = false)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
abstract fun coffeeDao(): CoffeeDao
abstract fun cartDao(): CartDao
abstract fun remoteKeysDao(): RemoteKeysDao
companion object {
private const val DB_NAME: String = "coffee-preorder"
@ -32,7 +31,7 @@ abstract class AppDatabase : RoomDatabase() {
// Users
val userDao = database.userDao()
val user1 = User("zyzf", "Ян К.", "+79911152503", "250303zyzf", "admin")
userDao.insert(user1.login, user1.fio, user1.phone, user1.password, user1.role)
userDao.insert(user1)
// Coffees
val coffeeDao = database.coffeeDao()
val coffee1 = Coffee("Coffee1", 200.0, "Ing1")
@ -46,17 +45,17 @@ abstract class AppDatabase : RoomDatabase() {
val coffee9 = Coffee("Coffee9", 200.0, "Ing1")
val coffee10 = Coffee("Coffee10", 900.0, "Ing1")
val coffee11 = Coffee("Coffee11", 200.0, "Ing1")
coffeeDao.insert(coffee1.name, coffee1.cost, coffee1.ingredients)
coffeeDao.insert(coffee2.name, coffee2.cost, coffee2.ingredients)
coffeeDao.insert(coffee3.name, coffee3.cost, coffee3.ingredients)
coffeeDao.insert(coffee4.name, coffee4.cost, coffee4.ingredients)
coffeeDao.insert(coffee5.name, coffee5.cost, coffee5.ingredients)
coffeeDao.insert(coffee6.name, coffee6.cost, coffee6.ingredients)
coffeeDao.insert(coffee7.name, coffee7.cost, coffee7.ingredients)
coffeeDao.insert(coffee8.name, coffee8.cost, coffee8.ingredients)
coffeeDao.insert(coffee9.name, coffee9.cost, coffee9.ingredients)
coffeeDao.insert(coffee10.name, coffee10.cost, coffee10.ingredients)
coffeeDao.insert(coffee11.name, coffee11.cost, coffee11.ingredients)
coffeeDao.insert(coffee1)
coffeeDao.insert(coffee2)
coffeeDao.insert(coffee3)
coffeeDao.insert(coffee4)
coffeeDao.insert(coffee5)
coffeeDao.insert(coffee6)
coffeeDao.insert(coffee7)
coffeeDao.insert(coffee8)
coffeeDao.insert(coffee9)
coffeeDao.insert(coffee10)
coffeeDao.insert(coffee11)
// Cart
val cartDao = database.cartDao()
val cart = Cart(2, 1)
@ -71,14 +70,15 @@ abstract class AppDatabase : RoomDatabase() {
AppDatabase::class.java,
DB_NAME
)
.addCallback(object : Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
CoroutineScope(Dispatchers.IO).launch {
populateDatabase()
}
}
})
// .addCallback(object : Callback() {
// override fun onCreate(db: SupportSQLiteDatabase) {
// super.onCreate(db)
// CoroutineScope(Dispatchers.IO).launch {
// populateDatabase()
// }
// }
// })
.allowMainThreadQueries()
.build()
.also { INSTANCE = it }
}

View File

@ -3,22 +3,27 @@ package com.zyzf.coffeepreorder.database.dao
import androidx.paging.PagingSource
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Update
import com.zyzf.coffeepreorder.database.model.Coffee
@Dao
interface CoffeeDao {
@Query("select * from coffee order by name collate nocase asc")
fun getAll(): PagingSource<Int, Coffee>
fun getAllCoffees(): PagingSource<Int, Coffee>
@Query("select coffee.uid, name, cost, ingredients from coffee where coffee.uid = :uid")
suspend fun getByUid(uid: Int): Coffee?
@Query("insert into coffee (name, cost, ingredients) values (:name, :cost, :ingredients)")
suspend fun insert(name: String, cost: Double, ingredients: String): Long
@Insert
fun insert(coffee: Coffee): Long
@Query("update coffee set name = :name, cost = :cost, ingredients = :ingredients where uid = :uid")
suspend fun update(uid: Int, name: String, cost: Double, ingredients: String): Int?
@Insert
suspend fun insert(vararg coffee: Coffee)
@Update
fun update(coffee: Coffee): Int
@Delete
suspend fun delete(coffee: Coffee)

View File

@ -2,8 +2,11 @@ package com.zyzf.coffeepreorder.database.dao
import androidx.paging.PagingSource
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Update
import com.zyzf.coffeepreorder.api.user.RestUserRepository
import com.zyzf.coffeepreorder.database.model.Coffee
import com.zyzf.coffeepreorder.database.model.User
import kotlinx.coroutines.flow.Flow
@ -14,17 +17,23 @@ interface UserDao {
fun getAll(): PagingSource<Int, User>
@Query("select * from user where login = :login and password = :password")
suspend fun tryLogin(login: String, password: String): User?
fun tryLogin(login: String, password: String): User?
@Query("select * from user where uid = :uid")
suspend fun getByUid(uid: Int): User?
@Query("insert into user (login, fio, phone, password, role) values (:login, :fio, :phone, :password, :role)")
suspend fun insert(login: String, fio: String, phone: String, password: String, role: String): Long
@Insert
fun insert(user: User): Long
@Query("update user set login = :login, fio = :fio, phone = :phone, password = :password, role = :role where uid = :uid")
suspend fun update(uid: Int, login: String, fio: String, phone: String, password: String, role: String): Int?
@Insert
fun insert(vararg user: User)
@Query("delete from user where uid = :uid")
suspend fun delete(uid: Int)
@Update
fun update(user: User): Int?
@Delete
suspend fun delete(user: User)
@Query("delete from user")
suspend fun deleteAll()
}

View File

@ -17,7 +17,7 @@ import androidx.room.PrimaryKey
])
data class Cart(
@PrimaryKey(autoGenerate = true)
val uid: Int?,
val uid: Int = 0,
@ColumnInfo(name = "coffee_id", index = true)
val coffeeId: Int,
@ColumnInfo(name = "count", index = true)
@ -27,16 +27,22 @@ data class Cart(
constructor(
coffeeId: Int,
count: Int
) : this(null, coffeeId, 0)
) : this(0, coffeeId, count)
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as Cart
return uid == other.uid
if (uid != other.uid) return false
if (coffeeId != other.coffeeId) return false
if (count != other.count) return false
return true
}
override fun hashCode(): Int {
return uid ?: -1
var result = uid
result = 31 * result + coffeeId.hashCode()
result = 31 * result + count.hashCode()
return result
}
}
}

View File

@ -2,7 +2,6 @@ package com.zyzf.coffeepreorder.database.model
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.Ignore
import androidx.room.PrimaryKey
@ -39,10 +38,18 @@ data class Coffee(
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as Coffee
return uid == other.uid
if (uid != other.uid) return false
if (name != other.name) return false
if (cost != other.cost) return false
if (ingredients != other.ingredients) return false
return true
}
override fun hashCode(): Int {
return uid
var result = uid
result = 31 * result + name.hashCode()
result = 31 * result + cost.hashCode()
result = 31 * result + ingredients.hashCode()
return result
}
}
}

View File

@ -6,8 +6,8 @@ import androidx.room.TypeConverter
import androidx.room.TypeConverters
enum class RemoteKeyType(private val type: String) {
Coffee(Coffee::class.simpleName ?: "Coffee"),
User(User::class.simpleName ?: "User");
COFFEE(Coffee::class.simpleName ?: "Coffee"),
USER(User::class.simpleName ?: "User");
@TypeConverter
fun toRemoteKeyType(value: String) = RemoteKeyType.values().first { it.type == value }
@ -24,3 +24,4 @@ data class RemoteKeys(
val prevKey: Int?,
val nextKey: Int?
)

View File

@ -46,10 +46,22 @@ data class User(
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as User
return uid == other.uid
if (uid != other.uid) return false
if (login != other.login) return false
if (fio != other.fio) return false
if (phone != other.phone) return false
if (password != other.password) return false
if (role != other.role) return false
return true
}
override fun hashCode(): Int {
return uid ?: -1
var result = uid
result = 31 * result + login.hashCode()
result = 31 * result + fio.hashCode()
result = 31 * result + phone.hashCode()
result = 31 * result + password.hashCode()
result = 31 * result + role.hashCode()
return result
}
}
}

View File

@ -15,4 +15,4 @@ interface CartRepository {
fun getCountForCoffee(coffeeId: Int): Double
suspend fun update(cart: Cart)
suspend fun deleteAll()
}
}

View File

@ -5,9 +5,9 @@ import com.zyzf.coffeepreorder.database.model.Coffee
import kotlinx.coroutines.flow.Flow
interface CoffeeRepository {
fun getAll(): Flow<PagingData<Coffee>>
fun getAllCoffees(): Flow<PagingData<Coffee>>
suspend fun getByUid(uid: Int): Coffee?
suspend fun insert(name: String, cost: Double, ingredients: String): Long
suspend fun update(uid: Int, name: String, cost: Double, ingredients: String): Int?
fun insert(coffee: Coffee): Long
fun update(coffee: Coffee): Int
suspend fun delete(coffee: Coffee)
}

View File

@ -25,4 +25,4 @@ class OfflineCartRepository(private val cartDao: CartDao) : CartRepository {
override fun getCountForCoffee(coffeeId: Int): Double = cartDao.getCountForCoffee(coffeeId)
override suspend fun update(cart: Cart) = cartDao.update(cart)
override suspend fun deleteAll() = cartDao.deleteAll()
}
}

View File

@ -10,18 +10,20 @@ import com.zyzf.coffeepreorder.database.model.Coffee
import kotlinx.coroutines.flow.Flow
class OfflineCoffeeRepository(private val coffeeDao: CoffeeDao) : CoffeeRepository {
override fun getAll(): Flow<PagingData<Coffee>> = Pager(
override fun getAllCoffees(): Flow<PagingData<Coffee>> = Pager(
config = PagingConfig(
pageSize = AppContainer.LIMIT,
enablePlaceholders = false
),
pagingSourceFactory = coffeeDao::getAll
pagingSourceFactory = coffeeDao::getAllCoffees
).flow
fun getAllCoffeesPagingSource(): PagingSource<Int, Coffee> = coffeeDao.getAll()
fun getAllCoffeesPagingSource(): PagingSource<Int, Coffee> = coffeeDao.getAllCoffees()
suspend fun clearCoffees() = coffeeDao.deleteAll()
override suspend fun getByUid(uid: Int): Coffee? = coffeeDao.getByUid(uid)
override suspend fun insert(name: String, cost: Double, ingredients: String): Long = coffeeDao.insert(name, cost, ingredients)
override suspend fun update(uid: Int, name: String, cost: Double, ingredients: String): Int? = coffeeDao.update(uid, name, cost, ingredients)
override fun insert(coffee: Coffee): Long = coffeeDao.insert(coffee)
suspend fun insertCoffees(coffees: List<Coffee>) =
coffeeDao.insert(*coffees.toTypedArray())
override fun update(coffee: Coffee): Int = coffeeDao.update(coffee)
override suspend fun delete(coffee: Coffee) = coffeeDao.delete(coffee)
}

View File

@ -20,8 +20,11 @@ class OfflineUserRepository(private val userDao: UserDao) : UserRepository {
).flow
fun getAllUserPagingSource(): PagingSource<Int, User> = userDao.getAll()
override suspend fun getByUid(uid: Int): User? = userDao.getByUid(uid)
override suspend fun tryLogin(login: String, password: String): User? = userDao.tryLogin(login, password)
override suspend fun insert(login: String, fio: String, phone: String, password: String, role: String): Long = userDao.insert(login, fio, phone, password, role)
override suspend fun update(uid: Int, login: String, fio: String, phone: String, password: String, role: String): Int? = userDao.update(uid, login, fio, phone, password, role)
override suspend fun delete(uid: Int) = userDao.delete(uid)
override fun tryLogin(login: String, password: String): User? = userDao.tryLogin(login, password)
override fun insert(user: User): Long = userDao.insert(user)
fun insertUsers(users: List<User>) =
userDao.insert(*users.toTypedArray())
override fun update(user: User): Int? = userDao.update(user)
override suspend fun delete(user: User) = userDao.delete(user)
suspend fun clearUsers() = userDao.deleteAll()
}

View File

@ -7,8 +7,8 @@ import kotlinx.coroutines.flow.Flow
interface UserRepository {
fun getAll(): Flow<PagingData<User>>
suspend fun getByUid(uid: Int): User?
suspend fun tryLogin(login: String, password: String): User?
suspend fun insert(login: String, fio: String, phone: String, password: String, role: String): Long
suspend fun update(uid: Int, login: String, fio: String, phone: String, password: String, role: String) : Int?
suspend fun delete(uid: Int)
fun tryLogin(login: String, password: String): User?
fun insert(user: User): Long
fun update(user: User) : Int?
suspend fun delete(user: User)
}

View File

@ -7,15 +7,23 @@ import androidx.lifecycle.viewmodel.viewModelFactory
import com.zyzf.coffeepreorder.CoffeeApplication
import com.zyzf.coffeepreorder.ui.cart.CartViewModel
import com.zyzf.coffeepreorder.ui.coffee.CoffeeListViewModel
import com.zyzf.coffeepreorder.ui.login.LoginViewModel
import com.zyzf.coffeepreorder.ui.register.RegisterViewModel
object AppViewModelProvider {
val Factory = viewModelFactory {
initializer {
CoffeeListViewModel(coffeeApplication().container.coffeeRepository, coffeeApplication().container.cartRepository)
CoffeeListViewModel(coffeeApplication().container.coffeeRestRepository, coffeeApplication().container.cartRepository)
}
initializer {
CartViewModel(coffeeApplication().container.cartRepository)
}
initializer {
LoginViewModel(coffeeApplication().container.userRestRepository)
}
initializer {
RegisterViewModel(coffeeApplication().container.userRestRepository)
}
}
}

View File

@ -4,7 +4,6 @@ import androidx.lifecycle.ViewModel
import androidx.paging.PagingData
import com.zyzf.coffeepreorder.database.model.Coffee
import com.zyzf.coffeepreorder.database.repository.CartRepository
import com.zyzf.coffeepreorder.database.repository.CoffeeRepository
import kotlinx.coroutines.flow.Flow
class CartViewModel(

View File

@ -13,7 +13,6 @@ import com.jcraft.jsch.JSch
import com.jcraft.jsch.JSchException
import com.jcraft.jsch.Session
import com.jcraft.jsch.SftpException
import com.zyzf.coffeepreorder.database.model.Cart
import com.zyzf.coffeepreorder.database.model.Coffee
import com.zyzf.coffeepreorder.database.repository.CartRepository
import com.zyzf.coffeepreorder.database.repository.CoffeeRepository
@ -29,13 +28,13 @@ class CoffeeListViewModel(
private val coffeeRepository: CoffeeRepository,
private val cartRepository: CartRepository
) : ViewModel() {
val coffeeListUiState: Flow<PagingData<Coffee>> = coffeeRepository.getAll()
val coffeeListUiState: Flow<PagingData<Coffee>> = coffeeRepository.getAllCoffees()
suspend fun addCoffeeToCart(coffeeUid: Int) {
cartRepository.insertCoffee(coffeeUid, 1)
}
suspend fun createCoffee(coffee: Coffee, imageUri: Uri, context: Context) {
val newCoffee: Long = coffeeRepository.insert(coffee.name, coffee.cost, coffee.ingredients)
val newCoffee: Long = coffeeRepository.insert(coffee)
val inputStream = context.contentResolver.openInputStream(imageUri)
val bitmap = BitmapFactory.decodeStream(inputStream)
@ -54,7 +53,7 @@ class CoffeeListViewModel(
copyFileToSftp(f, "/mnt/nextcloud/data/Zyzf/files/Images")
}
suspend fun editCoffee(coffee: Coffee, imageUri: Uri, context: Context) {
val editedCoffee: Int = coffeeRepository.update(coffee.uid, coffee.name, coffee.cost, coffee.ingredients)!!
val editedCoffee: Int = coffeeRepository.update(coffee)
val inputStream = context.contentResolver.openInputStream(imageUri)
val bitmap = BitmapFactory.decodeStream(inputStream)

View File

@ -23,6 +23,7 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@ -34,6 +35,7 @@ import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController
import coil.compose.AsyncImage
import coil.request.ImageRequest
@ -41,18 +43,25 @@ import com.zyzf.coffeepreorder.CoffeeApplication
import com.zyzf.coffeepreorder.R
import com.zyzf.coffeepreorder.database.AppDatabase
import com.zyzf.coffeepreorder.database.model.User
import com.zyzf.coffeepreorder.ui.AppViewModelProvider
import com.zyzf.coffeepreorder.ui.coffee.CoffeeListViewModel
import com.zyzf.coffeepreorder.ui.navigation.Screen
import com.zyzf.coffeepreorder.ui.theme.CoffeePreorderTheme
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@OptIn(DelicateCoroutinesApi::class)
@Composable
fun Login(navController: NavController?) {
fun Login(
navController: NavController?,
viewModel: LoginViewModel = viewModel(factory = AppViewModelProvider.Factory)
) {
val context = LocalContext.current
val coroutineScope = rememberCoroutineScope()
var login by remember { mutableStateOf("") }
var password by remember { mutableStateOf("") }
LaunchedEffect(Unit) {
@ -91,8 +100,8 @@ fun Login(navController: NavController?) {
Button(
onClick = {
var user: User?
GlobalScope.launch (Dispatchers.Main) {
user = AppDatabase.getInstance(context).userDao().tryLogin(login, password)
coroutineScope.launch {
user = viewModel.tryLogin(login, password)
if (user != null) {
CoffeeApplication.currentUser = null
CoffeeApplication.currentUser = user

View File

@ -0,0 +1,14 @@
package com.zyzf.coffeepreorder.ui.login
import androidx.lifecycle.ViewModel
import com.zyzf.coffeepreorder.api.user.RestUserRepository
import com.zyzf.coffeepreorder.database.model.User
import com.zyzf.coffeepreorder.database.repository.UserRepository
class LoginViewModel(
private val userRepository: UserRepository
) : ViewModel() {
fun tryLogin(login: String, password: String): User? {
return userRepository.tryLogin(login, password)
}
}

View File

@ -43,7 +43,7 @@ enum class Screen(
fun getItem(route: String): Screen? {
val findRoute = route.split("/").first()
return entries.find { value -> value.route.startsWith(findRoute) }
return values().find { value -> value.route.startsWith(findRoute) }
}
}
}

View File

@ -195,7 +195,7 @@ fun Profile(navController: NavController?) {
onClick = {
GlobalScope.launch (Dispatchers.Main) {
if (userOldPsswd.value == user.password && userNewPsswd.value == userNewPsswdConf.value) {
val userUid: Int? = AppDatabase.getInstance(context).userDao().update(user.uid!!, userLogin, userFIO, userPhone, userNewPsswd.value, user.role)
val userUid: Int? = AppDatabase.getInstance(context).userDao().update(User(user.uid!!, userLogin, userFIO, userPhone, userNewPsswd.value, user.role))
user = AppDatabase.getInstance(context).userDao().getByUid(userUid!!)!!
CoffeeApplication.currentUser = user
}
@ -274,7 +274,7 @@ fun Profile(navController: NavController?) {
onClick = {
GlobalScope.launch (Dispatchers.Main) {
CoffeeApplication.currentUser = null
AppDatabase.getInstance(context).userDao().delete(user.uid!!)
AppDatabase.getInstance(context).userDao().delete(user)
}
openDialogDelete.value = false
navController?.navigate(Screen.Login.route)

View File

@ -22,6 +22,7 @@ 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
@ -33,6 +34,7 @@ import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController
import coil.compose.AsyncImage
import coil.request.ImageRequest
@ -40,17 +42,24 @@ import com.zyzf.coffeepreorder.CoffeeApplication
import com.zyzf.coffeepreorder.R
import com.zyzf.coffeepreorder.database.AppDatabase
import com.zyzf.coffeepreorder.database.model.User
import com.zyzf.coffeepreorder.ui.AppViewModelProvider
import com.zyzf.coffeepreorder.ui.login.LoginViewModel
import com.zyzf.coffeepreorder.ui.navigation.Screen
import com.zyzf.coffeepreorder.ui.theme.CoffeePreorderTheme
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
@OptIn(DelicateCoroutinesApi::class)
@Composable
fun Register(navController: NavController?) {
fun Register(
navController: NavController?,
viewModel: RegisterViewModel = viewModel(factory = AppViewModelProvider.Factory)
) {
val context = LocalContext.current
val coroutineScope = rememberCoroutineScope()
var login: String by remember { mutableStateOf("") }
var fio: String by remember { mutableStateOf("") }
var phone: String by remember { mutableStateOf("") }
@ -105,10 +114,9 @@ fun Register(navController: NavController?) {
Button(
onClick = {
var user: User?
GlobalScope.launch (Dispatchers.Main) {
coroutineScope.launch (Dispatchers.Main) {
if (password == confPassword) {
AppDatabase.getInstance(context).userDao().insert(login, fio, phone, password, "user")
user = AppDatabase.getInstance(context).userDao().tryLogin(login, password)
user = viewModel.register(User(login, fio, phone, password, "user"))
if (user != null) {
CoffeeApplication.currentUser = null
CoffeeApplication.currentUser = user!!

View File

@ -0,0 +1,15 @@
package com.zyzf.coffeepreorder.ui.register
import androidx.lifecycle.ViewModel
import com.zyzf.coffeepreorder.database.AppDatabase
import com.zyzf.coffeepreorder.database.model.User
import com.zyzf.coffeepreorder.database.repository.UserRepository
class RegisterViewModel(
private val userRepository: UserRepository
) : ViewModel() {
fun register(user: User): User? {
userRepository.insert(user)
return userRepository.tryLogin(user.login, user.password)
}
}

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">192.168.42.94</domain>
<domain includeSubdomains="true">192.168.0.100</domain>
</domain-config>
</network-security-config>

View File

@ -2,9 +2,12 @@ package com.kalyshev.yan.coffee.controller;
import com.kalyshev.yan.WebConfiguration;
import com.kalyshev.yan.coffee.service.CoffeeService;
import com.kalyshev.yan.user.model.User;
import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping(WebConfiguration.REST_API + "/coffee")
public class CoffeeController {
@ -17,13 +20,13 @@ public class CoffeeController {
return new CoffeeDto(coffeeService.findCoffee(id));
}
@GetMapping("/")
public CoffeeResponse getAllCoffees(
@RequestParam(value = "pageNo", defaultValue = "0", required = false) int pageNo,
public List<CoffeeDto> getAllCoffees(
@RequestParam(value = "pageNo", defaultValue = "1", required = false) int pageNo,
@RequestParam(value = "pageSize", defaultValue = "10", required = false) int pageSize,
@RequestParam(value = "sortBy", defaultValue = "id", required = false) String sortBy,
@RequestParam(value = "sortDir", defaultValue = "asc", required = false) String sortDir
){
return coffeeService.findAllCoffees(pageNo, pageSize, sortBy, sortDir);
return coffeeService.findAllCoffees(pageNo-1, pageSize, sortBy, sortDir);
}
@PostMapping("/")
public CoffeeDto createCoffee(@RequestBody @Valid CoffeeDto coffeeDto) {

View File

@ -1,32 +0,0 @@
package com.kalyshev.yan.coffee.controller;
import com.kalyshev.yan.user.controller.UserDto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CoffeeResponse {
private List<CoffeeDto> content;
private int pageNo;
private int pageSize;
private long totalElements;
private int totalPages;
private boolean last;
public List<CoffeeDto> getContent() {return content;}
public int getPageNo() {return pageNo;}
public int getPageSize() {return pageSize;}
public long getTotalElements() {return totalElements;}
public int getTotalPages() {return totalPages;}
public boolean getLast() {return last;}
public void setContent (List<CoffeeDto> content) { this.content = content; }
public void setPageNo (int pageNo) { this.pageNo = pageNo; }
public void setPageSize (int pageSize) { this.pageSize = pageSize; }
public void setTotalElements (long totalElements) { this.totalElements = totalElements; }
public void setTotalPages (int totalPages) { this.totalPages = totalPages; }
public void setLast (boolean last) { this.last = last; }
}

View File

@ -1,9 +1,9 @@
package com.kalyshev.yan.coffee.service;
import com.kalyshev.yan.coffee.controller.CoffeeDto;
import com.kalyshev.yan.coffee.controller.CoffeeResponse;
import com.kalyshev.yan.coffee.model.Coffee;
import com.kalyshev.yan.coffee.repository.CoffeeRepository;
import com.kalyshev.yan.user.model.User;
import com.kalyshev.yan.user.repository.UserNotFoundException;
import com.kalyshev.yan.util.validation.ValidatorUtil;
import org.springframework.data.domain.Page;
@ -44,7 +44,7 @@ public class CoffeeService {
return coffee.orElseThrow(() -> new UserNotFoundException(id));
}
@Transactional(readOnly = true)
public CoffeeResponse findAllCoffees(int pageNo, int pageSize, String sortBy, String sortDir) {
public List<CoffeeDto> findAllCoffees(int pageNo, int pageSize, String sortBy, String sortDir) {
Sort sort = sortDir.equalsIgnoreCase(Sort.Direction.ASC.name()) ? Sort.by(sortBy).ascending()
: Sort.by(sortBy).descending();
@ -60,15 +60,7 @@ public class CoffeeService {
.map(CoffeeDto::new)
.toList();
CoffeeResponse coffeeResponse = new CoffeeResponse();
coffeeResponse.setContent(content);
coffeeResponse.setPageNo(coffees.getNumber());
coffeeResponse.setPageSize(coffees.getSize());
coffeeResponse.setTotalElements(coffees.getTotalElements());
coffeeResponse.setTotalPages(coffees.getTotalPages());
coffeeResponse.setLast(coffees.isLast());
return coffeeResponse;
return content;
}
@Transactional
public Coffee updateCoffee(Long id, String name, Double cost, String ingredients) {

View File

@ -6,6 +6,8 @@ import com.kalyshev.yan.user.service.UserService;
import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping(WebConfiguration.REST_API + "/user")
public class UserController {
@ -18,7 +20,7 @@ public class UserController {
return new UserDto(userService.findUser(id));
}
@GetMapping("/")
public UserResponse getAllUsers(
public List<UserDto> getAllUsers(
@RequestParam(value = "pageNo", defaultValue = "0", required = false) int pageNo,
@RequestParam(value = "pageSize", defaultValue = "10", required = false) int pageSize,
@RequestParam(value = "sortBy", defaultValue = "id", required = false) String sortBy,

View File

@ -1,31 +0,0 @@
package com.kalyshev.yan.user.controller;
import com.kalyshev.yan.coffee.controller.CoffeeDto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserResponse {
private List<UserDto> content;
private int pageNo;
private int pageSize;
private long totalElements;
private int totalPages;
private boolean last;
public List<UserDto> getContent() {return content;}
public int getPageNo() {return pageNo;}
public int getPageSize() {return pageSize;}
public long getTotalElements() {return totalElements;}
public int getTotalPages() {return totalPages;}
public void setContent (List<UserDto> content) { this.content = content; }
public void setPageNo (int pageNo) { this.pageNo = pageNo; }
public void setPageSize (int pageSize) { this.pageSize = pageSize; }
public void setTotalElements (long totalElements) { this.totalElements = totalElements; }
public void setTotalPages (int totalPages) { this.totalPages = totalPages; }
public void setLast (boolean last) { this.last = last; }
}

View File

@ -1,7 +1,6 @@
package com.kalyshev.yan.user.service;
import com.kalyshev.yan.user.controller.UserDto;
import com.kalyshev.yan.user.controller.UserResponse;
import com.kalyshev.yan.user.model.User;
import com.kalyshev.yan.user.repository.UserNotFoundException;
import com.kalyshev.yan.user.repository.UserRepository;
@ -58,7 +57,7 @@ public class UserService {
return user.orElseThrow(() -> new UserNotFoundException((long)0));
}
@Transactional(readOnly = true)
public UserResponse findAllUsers(int pageNo, int pageSize, String sortBy, String sortDir) {
public List<UserDto> findAllUsers(int pageNo, int pageSize, String sortBy, String sortDir) {
Sort sort = sortDir.equalsIgnoreCase(Sort.Direction.ASC.name()) ? Sort.by(sortBy).ascending()
: Sort.by(sortBy).descending();
@ -74,15 +73,7 @@ public class UserService {
.map(UserDto::new)
.toList();
UserResponse userResponse = new UserResponse();
userResponse.setContent(content);
userResponse.setPageNo(users.getNumber());
userResponse.setPageSize(users.getSize());
userResponse.setTotalElements(users.getTotalElements());
userResponse.setTotalPages(users.getTotalPages());
userResponse.setLast(users.isLast());
return userResponse;
return content;
}
@Transactional
public User updateUser(Long id, String login, String fio, String phone, String password, String role) {

View File

@ -1,6 +1,7 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id("com.android.application") version "8.2.0" apply false
id("org.jetbrains.kotlin.android") version "1.9.20" apply false
id("com.google.devtools.ksp") version "1.9.20-1.0.14" apply false
id("org.jetbrains.kotlin.android") version "1.9.10" apply false
id("com.google.devtools.ksp") version "1.9.10-1.0.13" apply false
id("org.jetbrains.kotlin.plugin.serialization") version "1.9.10" apply false
}

View File

@ -1,6 +1,6 @@
#Sun Oct 15 15:51:04 GMT+04:00 2023
#Thu Dec 14 21:41:14 GMT+04:00 2023
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists