pre final for mobile app

This commit is contained in:
zyzf 2023-12-12 14:28:13 +04:00
parent 7c3af23e3b
commit 176147f583
20 changed files with 102 additions and 101 deletions

View File

@ -60,6 +60,10 @@ dependencies {
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("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.2")
implementation("com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:1.0.0")
implementation("com.jcraft:jsch:0.1.55")

View File

@ -3,10 +3,15 @@ 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.User
class CoffeeApplication : Application() {
lateinit var container: AppContainer
companion object {
var currentUser: User? = null
}
override fun onCreate() {
super.onCreate()
container = AppDataContainer(this)

View File

@ -1,6 +1,13 @@
package com.zyzf.coffeepreorder.api
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
import com.zyzf.coffeepreorder.api.model.CoffeeRemote
import com.zyzf.coffeepreorder.api.model.UserRemote
import kotlinx.serialization.json.Json
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.http.Body
import retrofit2.http.DELETE
import retrofit2.http.GET
@ -10,8 +17,38 @@ import retrofit2.http.Path
import retrofit2.http.Query
interface MyServerService {
@GET("groups")
suspend fun getGroups(): List<GroupRemote>
@GET("user")
suspend fun getUsers(
@Query("_page") page: Int,
@Query("_limit") limit: Int,
): List<UserRemote>
@GET("user/{id}")
suspend fun getUser(
@Path("id") id: Int,
): UserRemote
@GET("user")
suspend fun tryLogin(
@Body login: String,
@Body password: String,
): UserRemote
@POST("user")
suspend fun createUser(
@Body user: UserRemote,
): UserRemote
@PUT("user/{id}")
suspend fun updateUser(
@Path("id") id: Int,
@Body user: UserRemote,
): UserRemote
@DELETE("user/{id}")
suspend fun deleteUser(
@Path("id") id: Int,
): UserRemote
@GET("coffee")
suspend fun getCoffees(
@ -26,13 +63,13 @@ interface MyServerService {
@POST("coffee")
suspend fun createCoffee(
@Body student: CoffeeRemote,
@Body coffee: CoffeeRemote,
): CoffeeRemote
@PUT("coffee/{id}")
suspend fun updateCoffee(
@Path("id") id: Int,
@Body student: CoffeeRemote,
@Body coffee: CoffeeRemote,
): CoffeeRemote
@DELETE("coffee/{id}")

View File

@ -46,8 +46,8 @@ class RestCoffeeRepository(
override suspend fun getByUid(uid: Int): Coffee? =
service.getCoffee(uid).toCoffee()
override suspend fun insert(name: String, cost: Double, ingredients: String): Int {
return service.createCoffee(Coffee(name, cost, ingredients, null, 0).toCoffeeRemote()).toCoffee().uid
override suspend fun insert(name: String, cost: Double, ingredients: String): Long {
return service.createCoffee(Coffee(name, cost, ingredients, null, 0).toCoffeeRemote()).toCoffee().uid.toLong()
}
override suspend fun update(uid: Int, name: String, cost: Double, ingredients: String, cartId: Int?, count: Int): Int? {

View File

@ -9,6 +9,8 @@ import com.zyzf.coffeepreorder.api.MyServerService
import com.zyzf.coffeepreorder.api.coffee.CoffeeRemoteMediator
import com.zyzf.coffeepreorder.api.model.toCoffee
import com.zyzf.coffeepreorder.api.model.toCoffeeRemote
import com.zyzf.coffeepreorder.api.model.toUser
import com.zyzf.coffeepreorder.api.model.toUserRemote
import com.zyzf.coffeepreorder.database.AppContainer
import com.zyzf.coffeepreorder.database.AppDatabase
import com.zyzf.coffeepreorder.database.model.Coffee
@ -50,15 +52,19 @@ class RestUserRepository(
override suspend fun getByUid(uid: Int): User? =
service.getUser(uid).toUser()
override suspend fun insert(name: String, cost: Double, ingredients: String): Int {
return service.createCoffee(Coffee(name, cost, ingredients, null, 0).toCoffeeRemote()).toCoffee().uid
override suspend 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 suspend fun update(uid: Int, name: String, cost: Double, ingredients: String, cartId: Int?, count: Int): Int? {
return service.updateCoffee(uid, Coffee(uid, name, cost, ingredients, cartId, count).toCoffeeRemote()).toCoffee().uid
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 suspend fun delete(coffee: Coffee) {
service.deleteCoffee(coffee.uid).toCoffee()
override suspend fun delete(userId: Int) {
service.deleteUser(userId).toUser()
}
}

View File

@ -7,6 +7,7 @@ import androidx.paging.RemoteMediator
import androidx.room.withTransaction
import com.zyzf.coffeepreorder.api.MyServerService
import com.zyzf.coffeepreorder.api.model.toCoffee
import com.zyzf.coffeepreorder.api.model.toUser
import com.zyzf.coffeepreorder.database.AppDatabase
import com.zyzf.coffeepreorder.database.model.Coffee
import com.zyzf.coffeepreorder.database.model.RemoteKeyType
@ -54,16 +55,15 @@ class UserRemoteMediator(
}
try {
val coffees = service.getUsers(page, state.config.pageSize).map { it.toCoffee() }
val endOfPaginationReached = coffees.isEmpty()
val users = service.getUsers(page, state.config.pageSize).map { it.toUser() }
val endOfPaginationReached = users.isEmpty()
database.withTransaction {
if (loadType == LoadType.REFRESH) {
dbRemoteKeyRepository.deleteRemoteKey(RemoteKeyType.User)
dbUserRepository.clearCoffees()
}
val prevKey = if (page == 1) null else page - 1
val nextKey = if (endOfPaginationReached) null else page + 1
val keys = coffees.map {
val keys = users.map {
RemoteKeys(
entityId = it.uid,
type = RemoteKeyType.User,
@ -72,8 +72,8 @@ class UserRemoteMediator(
)
}
dbRemoteKeyRepository.createRemoteKeys(keys)
for (user in coffees) {
dbUserRepository.insert()
for (user in users) {
dbUserRepository.insert(user.login, user.fio, user.phone, user.password, user.role)
}
}
return MediatorResult.Success(endOfPaginationReached = endOfPaginationReached)

View File

@ -11,12 +11,11 @@ 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.User
import com.zyzf.coffeepreorder.database.model.UserLogined
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@Database(entities = [User::class, Coffee::class, Cart::class, UserLogined::class], version = 1, exportSchema = false)
@Database(entities = [User::class, Coffee::class, Cart::class], version = 1, exportSchema = false)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
abstract fun coffeeDao(): CoffeeDao
@ -33,7 +32,7 @@ abstract class AppDatabase : RoomDatabase() {
// Users
val userDao = database.userDao()
val user1 = User("zyzf", "Ян К.", "+79911152503", "250303zyzf", "admin")
userDao.insert(user1)
userDao.insert(user1.login, user1.fio, user1.phone, user1.password, user1.role)
// Coffees
val coffeeDao = database.coffeeDao()
val coffee1 = Coffee("Coffee1", 200.0, "Ing1", null, 0)

View File

@ -15,7 +15,7 @@ interface CoffeeDao {
suspend fun getByUid(uid: Int): Coffee?
@Query("insert into coffee (name, cost, ingredients, count) values (:name, :cost, :ingredients, 0)")
suspend fun insert(name: String, cost: Double, ingredients: String): Int
suspend fun insert(name: String, cost: Double, ingredients: String): Long
@Query("update coffee set name = :name, cost = :cost, ingredients = :ingredients, cart_id = :cartId, count = :count where uid = :uid")
suspend fun update(uid: Int, name: String, cost: Double, ingredients: String, cartId: Int?, count: Int): Int?

View File

@ -19,20 +19,11 @@ interface UserDao {
@Query("select * from user where uid = :uid")
suspend fun getByUid(uid: Int): User?
@Query("select user.uid, login, fio, phone, password, role from user join user_logined on user_logined.user_id = user.uid limit 1")
suspend fun getLogined(): 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
@Query("insert into user_logined (user_id) values (:userId)")
suspend fun setLogined(userId: Int)
@Query("delete from user_logined")
suspend fun logout()
@Insert
suspend fun insert(user: User)
@Query("update user set login = :login, fio = :fio, phone = :phone, password = :password where uid = :uid")
suspend fun update(uid: Int, login: String, fio: String, phone: String, password: String) : Int?
@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?
@Query("delete from user where uid = :uid")
suspend fun delete(uid: Int)

View File

@ -1,39 +0,0 @@
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
@Entity(tableName = "user_logined", foreignKeys = [
ForeignKey(
entity = User::class,
parentColumns = ["uid"],
childColumns = ["user_id"],
onDelete = ForeignKey.RESTRICT,
onUpdate = ForeignKey.RESTRICT
)]
)
data class UserLogined(
@PrimaryKey(autoGenerate = true)
val uid: Int?,
@ColumnInfo(name = "user_id", index = true)
val userId: Int?
) {
@Ignore
constructor(
userId: Int?
) : this(null, userId)
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as UserLogined
return uid == other.uid
}
override fun hashCode(): Int {
return uid ?: -1
}
}

View File

@ -7,7 +7,7 @@ import kotlinx.coroutines.flow.Flow
interface CoffeeRepository {
fun getAll(): Flow<PagingData<Coffee>>
suspend fun getByUid(uid: Int): Coffee?
suspend fun insert(name: String, cost: Double, ingredients: String): Int
suspend fun insert(name: String, cost: Double, ingredients: String): Long
suspend fun update(uid: Int, name: String, cost: Double, ingredients: String, cartId: Int?, count: Int): Int?
suspend fun delete(coffee: Coffee)
}

View File

@ -21,7 +21,7 @@ class OfflineCoffeeRepository(private val coffeeDao: CoffeeDao) : CoffeeReposito
fun getAllCoffeesPagingSource(): PagingSource<Int, Coffee> = coffeeDao.getAll()
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): Int = coffeeDao.insert(name, cost, ingredients)
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, cartId: Int?, count: Int): Int? = coffeeDao.update(uid, name, cost, ingredients, cartId, count)
override suspend fun delete(coffee: Coffee) = coffeeDao.delete(coffee)
}

View File

@ -19,12 +19,9 @@ class OfflineUserRepository(private val userDao: UserDao) : UserRepository {
pagingSourceFactory = userDao::getAll
).flow
fun getAllUserPagingSource(): PagingSource<Int, User> = userDao.getAll()
override suspend fun tryLogin(login: String, password: String): User? = userDao.tryLogin(login, password)
override suspend fun getByUid(uid: Int): User? = userDao.getByUid(uid)
override suspend fun getLogined(): User? = userDao.getLogined()
override suspend fun setLogined(userId: Int) = userDao.setLogined(userId)
override suspend fun logout() = userDao.logout()
override suspend fun insert(user: User) = userDao.insert(user)
override suspend fun update(uid: Int, login: String, fio: String, phone: String, password: String) : Int? = userDao.update(uid, login, fio, phone, password)
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)
}

View File

@ -6,12 +6,9 @@ import kotlinx.coroutines.flow.Flow
interface UserRepository {
fun getAll(): Flow<PagingData<User>>
suspend fun tryLogin(login: String, password: String): User?
suspend fun getByUid(uid: Int): User?
suspend fun getLogined(): User?
suspend fun setLogined(userId: Int)
suspend fun logout()
suspend fun insert(user: User)
suspend fun update(uid: Int, login: String, fio: String, phone: String, password: String) : Int?
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)
}

View File

@ -14,7 +14,7 @@ object AppViewModelProvider {
CoffeeListViewModel(coffeeApplication().container.coffeeRepository, coffeeApplication().container.cartRepository)
}
initializer {
CartViewModel(coffeeApplication().container.coffeeRepository, coffeeApplication().container.cartRepository)
CartViewModel(coffeeApplication().container.cartRepository)
}
}
}

View File

@ -36,7 +36,7 @@ class CoffeeListViewModel(
cart.uid?.let { cartRepository.insertCoffee(it, coffeeUid, 1) }
}
suspend fun createCoffee(coffee: Coffee, imageUri: Uri, context: Context) {
val newCoffee: Int = coffeeRepository.insert(coffee.name, coffee.cost, coffee.ingredients)
val newCoffee: Long = coffeeRepository.insert(coffee.name, coffee.cost, coffee.ingredients)
val inputStream = context.contentResolver.openInputStream(imageUri)
val bitmap = BitmapFactory.decodeStream(inputStream)

View File

@ -37,6 +37,7 @@ import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import coil.compose.AsyncImage
import coil.request.ImageRequest
import com.zyzf.coffeepreorder.CoffeeApplication
import com.zyzf.coffeepreorder.R
import com.zyzf.coffeepreorder.database.AppDatabase
import com.zyzf.coffeepreorder.database.model.User
@ -93,8 +94,8 @@ fun Login(navController: NavController?) {
GlobalScope.launch (Dispatchers.Main) {
user = AppDatabase.getInstance(context).userDao().tryLogin(login, password)
if (user != null) {
AppDatabase.getInstance(context).userDao().logout()
AppDatabase.getInstance(context).userDao().setLogined(user!!.uid!!)
CoffeeApplication.currentUser = null
CoffeeApplication.currentUser = user
navController?.navigate(Screen.CoffeeList.route)
} else {
password = ""

View File

@ -64,7 +64,7 @@ fun Order(navController: NavController?) {
val sum = remember { mutableStateOf(0.0) }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
sum.value = AppDatabase.getInstance(context).coffeeDao().getSumInCart()
sum.value = AppDatabase.getInstance(context).cartDao().getSumInCart()
}
}
Column(Modifier.padding(all = 10.dp), horizontalAlignment = Alignment.CenterHorizontally) {

View File

@ -40,6 +40,7 @@ import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import com.zyzf.coffeepreorder.CoffeeApplication
import com.zyzf.coffeepreorder.R
import com.zyzf.coffeepreorder.database.AppDatabase
import com.zyzf.coffeepreorder.database.model.User
@ -67,7 +68,7 @@ fun Profile(navController: NavController?) {
val userNewPsswdConf = remember { mutableStateOf("") }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
user = AppDatabase.getInstance(context).userDao().getLogined()!!
user = CoffeeApplication.currentUser!!
userLogin = user.login
userFIO = user.fio
userPhone = user.phone
@ -194,8 +195,9 @@ fun Profile(navController: NavController?) {
onClick = {
GlobalScope.launch (Dispatchers.Main) {
if (userOldPsswd.value == user.password && userNewPsswd.value == userNewPsswdConf.value) {
AppDatabase.getInstance(context).userDao().update(user.uid!!, userLogin, userFIO, userPhone, userNewPsswd.value)
user = AppDatabase.getInstance(context).userDao().getLogined()!!
val userUid: Int? = AppDatabase.getInstance(context).userDao().update(user.uid!!, userLogin, userFIO, userPhone, userNewPsswd.value, user.role)
user = AppDatabase.getInstance(context).userDao().getByUid(userUid!!)!!
CoffeeApplication.currentUser = user
}
}
openDialogEdit.value = false
@ -233,7 +235,7 @@ fun Profile(navController: NavController?) {
TextButton(
onClick = {
GlobalScope.launch (Dispatchers.Main) {
AppDatabase.getInstance(context).userDao().logout()
CoffeeApplication.currentUser = null
}
openDialogExit.value = false
navController?.navigate(Screen.Login.route)
@ -271,7 +273,7 @@ fun Profile(navController: NavController?) {
TextButton(
onClick = {
GlobalScope.launch (Dispatchers.Main) {
AppDatabase.getInstance(context).userDao().logout()
CoffeeApplication.currentUser = null
AppDatabase.getInstance(context).userDao().delete(user.uid!!)
}
openDialogDelete.value = false

View File

@ -36,6 +36,7 @@ import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import coil.compose.AsyncImage
import coil.request.ImageRequest
import com.zyzf.coffeepreorder.CoffeeApplication
import com.zyzf.coffeepreorder.R
import com.zyzf.coffeepreorder.database.AppDatabase
import com.zyzf.coffeepreorder.database.model.User
@ -106,11 +107,11 @@ fun Register(navController: NavController?) {
var user: User?
GlobalScope.launch (Dispatchers.Main) {
if (password == confPassword) {
AppDatabase.getInstance(context).userDao().insert(User(login, fio, phone, password, "user"))
AppDatabase.getInstance(context).userDao().insert(login, fio, phone, password, "user")
user = AppDatabase.getInstance(context).userDao().tryLogin(login, password)
if (user != null) {
AppDatabase.getInstance(context).userDao().logout()
AppDatabase.getInstance(context).userDao().setLogined(user!!.uid!!)
CoffeeApplication.currentUser = null
CoffeeApplication.currentUser = user!!
navController?.navigate(Screen.CoffeeList.route)
} else {
password = ""