Чё-то делается

This commit is contained in:
ElEgEv 2023-12-12 01:06:48 +04:00
parent 178d0953d3
commit 9fea8e3bc4
48 changed files with 921 additions and 99 deletions

Binary file not shown.

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module version="4">
<component name="ModuleClassLoaderOverlays">
<paths>
<option value="C:\Users\egore\AppData\Local\Temp\overlay16197097467506260191" />
</paths>
</component>
</module>

View File

@ -0,0 +1,11 @@
package ru.ulstu.`is`.pmu.tank.api
object ApiRoutes {
const val BASE = "http://10.0.2.2:8079/"
const val USER = "users"
const val LEVEL = "level"
const val NATION = "nation"
const val TANK = "TANK"
const val USER_TANK = "userTanks"
const val NOT_USER_TANK = "notUserTanks"
}

View File

@ -0,0 +1,184 @@
package ru.ulstu.`is`.pmu.tank.api
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
import kotlinx.serialization.json.Json
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.http.Body
import retrofit2.http.DELETE
import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.PUT
import retrofit2.http.Path
import retrofit2.http.Query
import ru.ulstu.`is`.pmu.tank.api.model.LevelRemote
import ru.ulstu.`is`.pmu.tank.api.model.NationRemote
import ru.ulstu.`is`.pmu.tank.api.model.TankRemote
import ru.ulstu.`is`.pmu.tank.api.model.TankWithNationAndLevelRemote
import ru.ulstu.`is`.pmu.tank.api.model.UserRemote
import ru.ulstu.`is`.pmu.tank.api.model.UserTankCrossRefRemote
interface ServerService {
// :[USER]
@GET(ApiRoutes.USER)
suspend fun getUserByEmail(
@Query("email") email: String
): UserRemote
@POST(ApiRoutes.USER)
suspend fun insertUser(
@Body user: UserRemote
): UserRemote
@PUT("${ApiRoutes.USER}/{id}")
suspend fun updateUser(
@Path("id") id: Long,
@Body user: UserRemote
): UserRemote
// ![USER]
// :[LEVEL]
@GET(ApiRoutes.LEVEL)
suspend fun getLevels(): List<LevelRemote>
@GET("${ApiRoutes.LEVEL}/{id}")
suspend fun getLevel(
@Path("id") id: Long
): LevelRemote
@POST(ApiRoutes.LEVEL)
suspend fun insertLevel(
@Body level: LevelRemote
): LevelRemote
@PUT("${ApiRoutes.LEVEL}/{id}")
suspend fun updateLevel(
@Path("id") id: Long,
@Body level: LevelRemote
): LevelRemote
@DELETE("${ApiRoutes.LEVEL}/{id}")
suspend fun deleteLevel(
@Path("id") id: Long
): LevelRemote
// ![LEVEL]
// :[NATION]
@GET(ApiRoutes.NATION)
suspend fun getNations(
@Query("_page") page: Int,
@Query("_limit") limit: Int
): List<NationRemote>
@GET("${ApiRoutes.NATION}/{id}")
suspend fun getNation(
@Path("id") id: Long
): NationRemote
@POST(ApiRoutes.NATION)
suspend fun insertNation(
@Body product: NationRemote
): NationRemote
@PUT("${ApiRoutes.NATION}/{id}")
suspend fun updateNation(
@Path("id") id: Long,
@Body product: NationRemote
): NationRemote
@DELETE("${ApiRoutes.NATION}/{id}")
suspend fun deleteNation(
@Path("id") id: Long
): NationRemote
// ![NATION]
// :[TANK]
@GET(ApiRoutes.TANK)
suspend fun getTanks(): List<TankRemote>
@GET("${ApiRoutes.TANK}/{id}")
suspend fun getTank(
@Path("id") id: Long
): TankRemote
@GET("${ApiRoutes.TANK}/forPurchase")
suspend fun getTanksForPurchase(
@Path("id") userId: Long
): List<TankRemote>
@GET("${ApiRoutes.TANK}/myHangar")
suspend fun getTanksFromHangar(
@Path("id") userId: Long
): List<TankWithNationAndLevelRemote>
@POST(ApiRoutes.TANK)
suspend fun insertTank(
@Body tank: TankRemote
): TankRemote
@PUT("${ApiRoutes.TANK}/{id}")
suspend fun updateTank(
@Path("id") id: Long,
@Body tank: TankRemote
): TankRemote
@DELETE("${ApiRoutes.TANK}/{id}")
suspend fun deleteTank(
@Path("id") id: Long
): TankRemote
// ![TANK]
// :[USER_TANK_CROSS_REF]
@GET("${ApiRoutes.USER_TANK}?_hangar={userId}")
suspend fun getUserTankCrossRef(
@Path("userId") userId: Long,
): List<UserTankCrossRefRemote>
@POST(ApiRoutes.USER_TANK)
suspend fun insertUserTankCrossRef(
@Body tank: UserTankCrossRefRemote
) : UserTankCrossRefRemote
@DELETE("${ApiRoutes.USER_TANK}/deleteMyTank")
suspend fun deleteUserTankCrossRef(
@Body tank: UserTankCrossRefRemote
): UserTankCrossRefRemote
// ![USER_TANK_CROSS_REF]
companion object {
private const val BASE_URL = ApiRoutes.BASE
@Volatile
private var INSTANCE: ServerService? = null
fun getInstance(): ServerService {
return INSTANCE ?: synchronized(this) {
val logger = HttpLoggingInterceptor()
logger.level = HttpLoggingInterceptor.Level.BASIC
val client = OkHttpClient.Builder()
.addInterceptor(logger)
.build()
return Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(Json.asConverterFactory("application/json".toMediaType()))
.build()
.create(ServerService::class.java)
.also { INSTANCE = it }
}
}
}
}

View File

@ -0,0 +1,111 @@
package ru.ulstu.`is`.pmu.tank.api.mediator
import androidx.paging.ExperimentalPagingApi
import androidx.paging.LoadType
import androidx.paging.PagingState
import androidx.paging.RemoteMediator
import androidx.room.withTransaction
import retrofit2.HttpException
import ru.ulstu.`is`.pmu.tank.api.ServerService
import ru.ulstu.`is`.pmu.tank.api.model.toLevel
import ru.ulstu.`is`.pmu.tank.api.model.toNation
import ru.ulstu.`is`.pmu.tank.database.AppDatabase
import ru.ulstu.`is`.pmu.tank.model.Nation
import ru.ulstu.`is`.pmu.tank.model.RemoteKeyType
import ru.ulstu.`is`.pmu.tank.model.RemoteKeys
import ru.ulstu.`is`.pmu.tank.repository.OfflineNationRepository
import ru.ulstu.`is`.pmu.tank.repository.OfflineRemoteKeyRepository
import java.io.IOException
@OptIn(ExperimentalPagingApi::class)
class NationRemoteMediator(
private val service: ServerService,
private val dbNationRepository: OfflineNationRepository,
private val dbRemoteKeyRepository: OfflineRemoteKeyRepository,
private val database: AppDatabase
) : RemoteMediator<Int, Nation>() {
override suspend fun initialize(): InitializeAction {
return InitializeAction.LAUNCH_INITIAL_REFRESH
}
override suspend fun load(
loadType: LoadType,
state: PagingState<Int, Nation>
): MediatorResult {
val page = when (loadType) {
LoadType.REFRESH -> {
val remoteKeys = getRemoteKeyClosestToCurrentPosition(state)
remoteKeys?.nextKey?.minus(1) ?: 1
}
LoadType.PREPEND -> {
val remoteKeys = getRemoteKeyForFirstItem(state)
remoteKeys?.prevKey
?: return MediatorResult.Success(endOfPaginationReached = remoteKeys != null)
}
LoadType.APPEND -> {
val remoteKeys = getRemoteKeyForLastItem(state)
remoteKeys?.nextKey
?: return MediatorResult.Success(endOfPaginationReached = remoteKeys != null)
}
}
try {
val nations = service.getNations(page, state.config.pageSize).map { it.toNation() }
val endOfPaginationReached = nations.isEmpty()
database.withTransaction {
if (loadType == LoadType.REFRESH) {
dbRemoteKeyRepository.deleteRemoteKey(RemoteKeyType.NATION)
dbNationRepository.deleteNations()
}
val prevKey = if (page == 1) null else page - 1
val nextKey = if (endOfPaginationReached) null else page + 1
val keys = nations.map {
RemoteKeys(
entityId = it.uid!!.toInt(),
type = RemoteKeyType.NATION,
prevKey = prevKey,
nextKey = nextKey
)
}
dbRemoteKeyRepository.createRemoteKeys(keys)
dbNationRepository.insertNations(nations)
}
return MediatorResult.Success(endOfPaginationReached = endOfPaginationReached)
} catch (exception: IOException) {
return MediatorResult.Error(exception)
} catch (exception: HttpException) {
return MediatorResult.Error(exception)
}
}
private suspend fun getRemoteKeyForLastItem(state: PagingState<Int, Nation>): RemoteKeys? {
return state.pages.lastOrNull { it.data.isNotEmpty() }?.data?.lastOrNull()
?.let { nation ->
dbRemoteKeyRepository.getAllRemoteKeys(nation.uid!!.toInt(), RemoteKeyType.NATION)
}
}
private suspend fun getRemoteKeyForFirstItem(state: PagingState<Int, Nation>): RemoteKeys? {
return state.pages.firstOrNull { it.data.isNotEmpty() }?.data?.firstOrNull()
?.let { nation ->
dbRemoteKeyRepository.getAllRemoteKeys(nation.uid!!.toInt(), RemoteKeyType.NATION)
}
}
private suspend fun getRemoteKeyClosestToCurrentPosition(
state: PagingState<Int, Nation>
): RemoteKeys? {
return state.anchorPosition?.let { position ->
state.closestItemToPosition(position)?.uid?.let { nationUid ->
dbRemoteKeyRepository.getAllRemoteKeys(nationUid.toInt(), RemoteKeyType.NATION)
}
}
}
}

View File

@ -0,0 +1,22 @@
package ru.ulstu.`is`.pmu.tank.api.model
import androidx.room.ColumnInfo
import kotlinx.serialization.Serializable
import ru.ulstu.`is`.pmu.tank.model.Level
import ru.ulstu.`is`.pmu.tank.model.Nation
@Serializable
data class LevelRemote (
val uid: Long = 0,
val level: Int = 0
)
fun LevelRemote.toLevel(): Level = Level(
uid,
level
)
fun Level.toRemote(): LevelRemote = LevelRemote(
uid!!,
level
)

View File

@ -0,0 +1,20 @@
package ru.ulstu.`is`.pmu.tank.api.model
import kotlinx.serialization.Serializable
import ru.ulstu.`is`.pmu.tank.model.Nation
@Serializable
data class NationRemote(
val uid: Long = 0,
val nationName: String = ""
)
fun NationRemote.toNation(): Nation = Nation(
uid,
nationName
)
fun Nation.toRemote(): NationRemote = NationRemote(
uid!!,
nationName
)

View File

@ -0,0 +1,38 @@
package ru.ulstu.`is`.pmu.tank.api.model
import android.graphics.Bitmap
import com.application.ui.toBase64
import com.application.ui.toBitmap
import kotlinx.serialization.Serializable
import ru.ulstu.`is`.pmu.tank.model.Tank
@Serializable
data class TankRemote(
val tankId: Long = 0,
val name: String = "",
val price: Int = 0,
val miniature: String = "",
val imageId: Long = 0,
val levelId: Long = 0,
val nationId: Long = 0,
)
fun TankRemote.toTank(): Tank = Tank(
tankId = tankId,
name = name,
price = price,
miniature = miniature.toBitmap(),
imageId = imageId,
levelId = levelId,
nationId = nationId
)
fun Tank.toRemote(): TankRemote = TankRemote(
tankId = tankId!!,
name = name,
price = price,
miniature = miniature.toBase64(),
imageId = imageId,
levelId = levelId!!,
nationId = nationId!!
)

View File

@ -0,0 +1,34 @@
package ru.ulstu.`is`.pmu.tank.api.model
import com.application.ui.toBase64
import com.application.ui.toBitmap
import kotlinx.serialization.Serializable
import ru.ulstu.`is`.pmu.tank.model.TankWithNationAndLevel
@Serializable
data class TankWithNationAndLevelRemote(
val tankId: Long,
val name: String,
val price: Int,
val image: String,
val level: Int,
val nationName: String
)
fun TankWithNationAndLevelRemote.toTankWithNationAndLevel(): TankWithNationAndLevel = TankWithNationAndLevel(
tankId = tankId,
name = name,
price = price,
image = image.toBitmap(),
level = level,
nationName = nationName
)
fun TankWithNationAndLevel.toRemote(): TankWithNationAndLevelRemote = TankWithNationAndLevelRemote(
tankId = tankId!!,
name = name,
price = price,
image = image.toBase64(),
level = level,
nationName = nationName
)

View File

@ -0,0 +1,33 @@
package ru.ulstu.`is`.pmu.tank.api.model
import kotlinx.serialization.Serializable
import ru.ulstu.`is`.pmu.tank.model.User
import ru.ulstu.`is`.pmu.tank.model.UserRole
@Serializable
data class UserRemote (
val id: Long = 0,
val nickname: String = "",
val email: String = " ",
val role: Int = -1,
val password: String = "",
val balance: Int = 0
)
fun UserRemote.toUser(): User = User(
userId = id,
nickname = nickname,
email = email,
password = password,
role = enumValues<UserRole>()[role],
balance = balance
)
fun User.toRemote(): UserRemote = UserRemote(
id = userId,
nickname = nickname,
email = email,
password = password,
role = role.ordinal,
balance = balance
)

View File

@ -0,0 +1,9 @@
package ru.ulstu.`is`.pmu.tank.api.model
import kotlinx.serialization.Serializable
@Serializable
data class UserTankCrossRefRemote (
val userId: Long = 0,
val tankId: Long = 0
)

View File

@ -0,0 +1,51 @@
package ru.ulstu.`is`.pmu.tank.api.repository
import kotlinx.coroutines.flow.Flow
import ru.ulstu.`is`.pmu.tank.api.ServerService
import ru.ulstu.`is`.pmu.tank.api.model.toLevel
import ru.ulstu.`is`.pmu.tank.api.model.toRemote
import ru.ulstu.`is`.pmu.tank.model.Level
import ru.ulstu.`is`.pmu.tank.model.LevelWithTanks
import ru.ulstu.`is`.pmu.tank.repository.LevelRepository
import ru.ulstu.`is`.pmu.tank.repository.OfflineLevelRepository
class RestLevelRepository(
private val service: ServerService,
private val dbLevelRepository: OfflineLevelRepository,
) : LevelRepository {
override suspend fun getAllLevels(): List<Level> {
dbLevelRepository.deleteAll()
val levels = service.getLevels().map { it.toLevel() }
dbLevelRepository.insertMany(levels)
return levels
}
override suspend fun getSimpleLevel(uid: Long): Level {
TODO("Not yet implemented")
}
override fun getFullLevel(uid: Long): Flow<LevelWithTanks?> {
TODO("Not yet implemented")
}
override suspend fun insertLevel(level: Level) {
service.insertLevel(level.toRemote())
}
override suspend fun insertMany(levels: List<Level>) {
TODO("Not yet implemented")
}
override suspend fun updateLevel(level: Level) {
service.updateLevel(level.uid!!, level.toRemote())
}
override suspend fun deleteLevel(level: Level) {
service.deleteLevel(level.uid!!)
dbLevelRepository.deleteLevel(level)
}
override suspend fun deleteAll() {
TODO("Not yet implemented")
}
}

View File

@ -0,0 +1,84 @@
package ru.ulstu.`is`.pmu.tank.api.repository
import android.util.Log
import androidx.paging.ExperimentalPagingApi
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import androidx.paging.PagingSource
import androidx.paging.map
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import ru.ulstu.`is`.pmu.tank.api.ServerService
import ru.ulstu.`is`.pmu.tank.api.mediator.NationRemoteMediator
import ru.ulstu.`is`.pmu.tank.api.model.NationRemote
import ru.ulstu.`is`.pmu.tank.api.model.toNation
import ru.ulstu.`is`.pmu.tank.api.model.toRemote
import ru.ulstu.`is`.pmu.tank.database.AppContainer
import ru.ulstu.`is`.pmu.tank.database.AppDatabase
import ru.ulstu.`is`.pmu.tank.model.Nation
import ru.ulstu.`is`.pmu.tank.model.NationWithTanks
import ru.ulstu.`is`.pmu.tank.repository.NationRepository
import ru.ulstu.`is`.pmu.tank.repository.OfflineNationRepository
import ru.ulstu.`is`.pmu.tank.repository.OfflineRemoteKeyRepository
class RestNationRepository(
private val service: ServerService,
private val dbNationRepository: OfflineNationRepository,
private val dbRemoteKeyRepository: OfflineRemoteKeyRepository,
private val database: AppDatabase
) : NationRepository {
override suspend fun getAllNations(): List<Nation> {
TODO("Not yet implemented")
}
override suspend fun getAll(): Flow<PagingData<Nation>> {
@OptIn(ExperimentalPagingApi::class)
return Pager(
config = PagingConfig(
pageSize = 10,
enablePlaceholders = false
),
remoteMediator = NationRemoteMediator(
service = service,
dbNationRepository = dbNationRepository,
dbRemoteKeyRepository = dbRemoteKeyRepository,
database = database,
),
) {
dbNationRepository.pagingSource()
}.flow
}
override fun getSimpleNation(uid: Long): Flow<Nation?> {
TODO("Not yet implemented")
}
override fun getFullNation(uid: Long): Flow<NationWithTanks?> {
TODO("Not yet implemented")
}
override fun pagingSource(): PagingSource<Int, Nation> {
TODO("Not yet implemented")
}
override suspend fun insertNation(nation: Nation) {
service.insertNation(nation.toRemote()).toNation()
}
override suspend fun insertNations(nations: List<Nation>) {
TODO("Not yet implemented")
}
override suspend fun updateNation(nation: Nation) {
service.updateNation(nation.uid!!, nation.toRemote())
}
override suspend fun deleteNation(nation: Nation) {
service.deleteNation(nation.uid!!)
}
override suspend fun deleteNations() {
TODO("Not yet implemented")
}
}

View File

@ -0,0 +1,66 @@
package ru.ulstu.`is`.pmu.tank.api.repository
import android.graphics.Bitmap
import kotlinx.coroutines.flow.Flow
import ru.ulstu.`is`.pmu.tank.api.ServerService
import ru.ulstu.`is`.pmu.tank.api.model.toLevel
import ru.ulstu.`is`.pmu.tank.api.model.toRemote
import ru.ulstu.`is`.pmu.tank.api.model.toTank
import ru.ulstu.`is`.pmu.tank.api.model.toTankWithNationAndLevel
import ru.ulstu.`is`.pmu.tank.api.model.toUser
import ru.ulstu.`is`.pmu.tank.model.Tank
import ru.ulstu.`is`.pmu.tank.model.TankWithNationAndLevel
import ru.ulstu.`is`.pmu.tank.model.User
import ru.ulstu.`is`.pmu.tank.repository.OfflineTankRepository
import ru.ulstu.`is`.pmu.tank.repository.OfflineUserRepository
import ru.ulstu.`is`.pmu.tank.repository.TankRepository
import ru.ulstu.`is`.pmu.tank.repository.UserRepository
class RestTankReppository (
private val service: ServerService,
private val dbTankRepository: OfflineTankRepository,
) : TankRepository {
override suspend fun getAll(): List<Tank> {
dbTankRepository.deleteAll()
val tanks = service.getTanks().map { it.toTank() }
dbTankRepository.insertMany(tanks)
return tanks
}
override suspend fun getForUserAll(userId: Long): List<Tank> {
return service.getTanksForPurchase(userId).map { it.toTank() }
}
override suspend fun getTank(uid: Long): Tank {
return service.getTank(uid).toTank()
}
override suspend fun getUserTanks(uid: Long): List<TankWithNationAndLevel> {
return service.getTanksFromHangar(uid).map { it.toTankWithNationAndLevel() }
}
override suspend fun insertTank(tank: Tank, image: Bitmap) {
service.insertTank(tank.toRemote())
}
override suspend fun insertMany(tankList: List<Tank>) {
TODO("Not yet implemented")
}
override suspend fun updateTank(tank: Tank, image: Bitmap) {
service.updateTank(tank.tankId!!, tank.toRemote())
}
override suspend fun deleteTank(tank: Tank) {
TODO("Not yet implemented")
}
override suspend fun delete(tankId: Long) {
service.deleteTank(tankId)
dbTankRepository.delete(tankId)
}
override suspend fun deleteAll() {
TODO("Not yet implemented")
}
}

View File

@ -0,0 +1,44 @@
package ru.ulstu.`is`.pmu.tank.api.repository
import kotlinx.coroutines.flow.Flow
import ru.ulstu.`is`.pmu.tank.api.ServerService
import ru.ulstu.`is`.pmu.tank.api.model.toLevel
import ru.ulstu.`is`.pmu.tank.api.model.toRemote
import ru.ulstu.`is`.pmu.tank.api.model.toUser
import ru.ulstu.`is`.pmu.tank.model.Level
import ru.ulstu.`is`.pmu.tank.model.LevelWithTanks
import ru.ulstu.`is`.pmu.tank.model.TankWithNationAndLevel
import ru.ulstu.`is`.pmu.tank.model.User
import ru.ulstu.`is`.pmu.tank.repository.LevelRepository
import ru.ulstu.`is`.pmu.tank.repository.OfflineLevelRepository
import ru.ulstu.`is`.pmu.tank.repository.OfflineUserRepository
import ru.ulstu.`is`.pmu.tank.repository.UserRepository
class RestUserRepository(
private val service: ServerService,
private val dbUserRepository: OfflineUserRepository,
) : UserRepository {
override fun getAllUsers(): Flow<List<User>> {
TODO("Not yet implemented")
}
override suspend fun getSimpleUser(email: String): User {
return service.getUserByEmail(email).toUser()
}
override fun getFullUser(uid: Long): Flow<Map<User, List<TankWithNationAndLevel>>> {
TODO("Not yet implemented")
}
override suspend fun insertUser(user: User) {
service.insertUser(user.toRemote())
}
override suspend fun updateUser(user: User) {
service.updateUser(user.userId, user.toRemote())
}
override suspend fun deleteUser(user: User) {
TODO("Not yet implemented")
}
}

View File

@ -73,13 +73,11 @@ fun TankList(
viewModel: TankListViewModel = viewModel(factory = AppViewModelProvider.Factory),
listNations: NationDropDownViewModel = viewModel(factory = AppViewModelProvider.Factory)
) {
val tankListUiState by viewModel.tankListUiState.collectAsState()
// Lazy Column, Pass the numbers array
if (navController != null) {
TankList(
nations = listNations.nationsListUiState,
listTanks = tankListUiState.tankList
listTanks = viewModel.tankListUiState.tankList
) { uid: Long ->
val route = Screen.Constructor.route.replace("{id}", uid.toString())
navController.navigate(route)

View File

@ -33,8 +33,6 @@ class TankEditViewModel(
viewModelScope.launch {
if (tankUid > 0) {
tankUiState = tankRepository.getTank(tankUid)
.filterNotNull()
.first()
.toUiState(true)
}
}

View File

@ -10,6 +10,7 @@ import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import ru.ulstu.`is`.pmu.tank.model.User
import ru.ulstu.`is`.pmu.tank.model.UserRole
import ru.ulstu.`is`.pmu.tank.repository.UserRepository
class UserEditViewModel(
@ -22,14 +23,12 @@ class UserEditViewModel(
//private val userUid: Long = checkNotNull(savedStateHandle["id"])
private val userUid: Long = 100L
private val userEmail: String = "egor@mail.ru"
init {
viewModelScope.launch {
if (userUid > 0) {
userUiState = userRepository.getSimpleUser(userUid)
.filterNotNull()
.first()
if (userEmail.length > 0) {
userUiState = userRepository.getSimpleUser(userEmail)
.toUiState(true)
}
}
@ -44,8 +43,8 @@ class UserEditViewModel(
suspend fun saveUser() {
if (validateInput()) {
if (userUid > 0) {
userRepository.updateUser(userUiState.userDetails.toUser(userUid))
if (userEmail.length > 0) {
userRepository.updateUser(userUiState.userDetails.toUser(100L))
} else {
userRepository.insertUser(userUiState.userDetails.toUser())
}
@ -57,6 +56,7 @@ class UserEditViewModel(
nickname.isNotBlank()
&& email.isNotBlank()
&& password.isNotBlank()
&& role.value > -1
&& balance > 0
}
}
@ -71,6 +71,7 @@ data class UserDetails(
val nickname: String = "",
val email: String = "",
val password: String = "",
val role: UserRole = UserRole.USER,
val balance: Int = 0,
)
@ -79,6 +80,7 @@ fun UserDetails.toUser(uid: Long = 0): User = User(
nickname = nickname,
email = email,
password = password,
role = role,
balance = balance
)
@ -86,6 +88,7 @@ fun User.toDetails(): UserDetails = UserDetails(
nickname = nickname,
email = email,
password = password,
role = role,
balance = balance
)

View File

@ -1,5 +1,8 @@
package ru.ulstu.`is`.pmu.tank.composeui.list
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.SharingStarted
@ -15,21 +18,11 @@ class TankListViewModel(
private val tankRepository: TankRepository,
private var userId: Long = 100L
) : ViewModel() {
val tankListUiState: StateFlow<TankListUiState> = tankRepository.getForUserAll(userId).map {
TankListUiState(it)
}.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(stopTimeoutMillis = AppDataContainer.TIMEOUT),
initialValue = TankListUiState()
)
var tankListUiState by mutableStateOf(TankListUiState())
private set
val usersTanksUiState: StateFlow<UserTankListUiState> = tankRepository.getUserTanks(userId).map {
UserTankListUiState(it)
}.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(stopTimeoutMillis = AppDataContainer.TIMEOUT),
initialValue = UserTankListUiState()
)
var usersTanksUiState by mutableStateOf(UserTankListUiState())
private set
suspend fun deleteTank(tank: Tank) {
tankRepository.deleteTank(tank)

View File

@ -30,14 +30,21 @@ interface LevelDao {
@Query(
"SELECT level FROM levels where levels.uid = :uid"
)
open fun getSimpleLevelUid(uid: Long): Flow<Level?>
open fun getSimpleLevelUid(uid: Long): Level
@Insert
suspend fun insert(level: Level)
@Insert
suspend fun insertMany(level: List<Level>)
@Update
suspend fun update(level: Level)
@Delete
suspend fun delete(level: Level)
@Query("DELETE FROM levels")
suspend fun deleteAll()
}

View File

@ -23,24 +23,33 @@ interface NationDao {
suspend fun getNationsWithTanks(): List<NationWithTanks>
//получить конкретную нацию
@Transaction
@Query("select * from nations where nations.uid = :uid")
fun getNationUid(uid: Long): Flow<NationWithTanks?>
//получить нацию без списка танков
@Transaction
@Query(
"SELECT nationName FROM nations where nations.uid = :uid"
)
open fun getSimpleNationUid(uid: Long): Flow<Nation?>
@Transaction
@Query("SELECT * FROM nations")
fun pagingSource(): PagingSource<Int, Nation>
@Insert
suspend fun insert(nation: Nation)
@Insert
suspend fun insertMany(nations: List<Nation>)
@Update
suspend fun update(nation: Nation)
@Delete
suspend fun delete(nation: Nation)
@Query("DELETE FROM nations")
suspend fun deleteAll()
}

View File

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

View File

@ -16,33 +16,36 @@ import ru.ulstu.`is`.pmu.tank.model.TankWithNationAndLevel
@Dao
interface TankDao {
@Query("select * from tanks GROUP BY nationId, levelId ORDER BY nationId")
fun getAll(): Flow<List<Tank>>
fun getAll(): List<Tank>
//получить конкретный танк
@Query("select t.*, ti.data from tanks AS t " +
"LEFT JOIN tank_images as ti on t.image_id = ti.image_id " +
"where t.tankId = :uid")
fun getTankUid(uid: Long): Flow<Tank?>
fun getTankUid(uid: Long): Tank
//получаем все танки пользователя по его Id
@Query(
"SELECT t.tankId, t.name, t.price, t.image_id, l.level, n.nationName, ti.data AS image FROM UserTankCrossRef AS ut " +
"SELECT t.tankId, t.name, t.price, t.image_id, l.level, n.nationName, ti.data AS image FROM users_tanks AS ut " +
"LEFT JOIN tanks as t on ut.tankId = t.tankId " +
"LEFT JOIN tank_images as ti on t.image_id = ti.image_id " +
"LEFT JOIN levels as l on t.levelId = l.uid " +
"LEFT JOIN nations as n on t.nationId = n.uid " +
"WHERE ut.userId = :uid GROUP BY t.nationId, t.levelId ORDER BY t.nationId"
)
fun getUserTanks(uid: Long): Flow<List<TankWithNationAndLevel>>
fun getUserTanks(uid: Long): List<TankWithNationAndLevel>
@Query(
"SELECT t.* FROM tanks AS t WHERE t.tankId NOT IN (SELECT ut.tankId FROM UserTankCrossRef AS ut WHERE ut.userId = :uid)"
"SELECT t.* FROM tanks AS t WHERE t.tankId NOT IN (SELECT ut.tankId FROM users_tanks AS ut WHERE ut.userId = :uid)"
)
fun getNotUserTank(uid: Long): Flow<List<Tank>>
fun getNotUserTank(uid: Long): List<Tank>
@Insert
suspend fun insert(tank: Tank)
@Insert
suspend fun insertMany(tankList: List<Tank>)
@Update
suspend fun update(tank: Tank)
@ -51,4 +54,7 @@ interface TankDao {
@Query("DELETE FROM tanks WHERE tankId = :id")
suspend fun delete(id: Long)
@Query("DELETE FROM tanks")
suspend fun deleteAll()
}

View File

@ -11,7 +11,6 @@ import ru.ulstu.`is`.pmu.tank.model.Tank
import ru.ulstu.`is`.pmu.tank.model.TankWithNationAndLevel
import ru.ulstu.`is`.pmu.tank.model.User
import ru.ulstu.`is`.pmu.tank.model.UserTankCrossRef
import ru.ulstu.`is`.pmu.tank.model.UserWithTanks
@Dao
interface UserDao {
@ -21,7 +20,7 @@ interface UserDao {
//получить конкретного пользователя
@Query(
"SELECT u.*, t.*, l.level, n.nationName, ti.data AS image FROM users AS u " +
"LEFT JOIN UserTankCrossRef as ut on u.userId = ut.userId " +
"LEFT JOIN users_tanks as ut on u.userId = ut.userId " +
"LEFT JOIN tanks as t on ut.tankId = t.tankId " +
"LEFT JOIN tank_images as ti on ut.tankId = ti.image_id " +
"LEFT JOIN levels as l on t.levelId = l.uid " +
@ -30,8 +29,8 @@ interface UserDao {
)
fun getUserUid(uid: Long): Flow<Map<User, List<TankWithNationAndLevel>>>
@Query("select * from users where users.userId = :uid")
fun getSimpleUserUid(uid: Long): Flow<User?>
@Query("select * from users where users.email = :email")
fun getSimpleUserUid(email: String): User
//добавить танк в ангар пользователя
@Insert

View File

@ -20,8 +20,8 @@ import ru.ulstu.`is`.pmu.tank.model.Nation
import ru.ulstu.`is`.pmu.tank.model.Tank
import ru.ulstu.`is`.pmu.tank.model.TankImage
import ru.ulstu.`is`.pmu.tank.model.User
import ru.ulstu.`is`.pmu.tank.model.UserRole
import ru.ulstu.`is`.pmu.tank.model.UserTankCrossRef
import ru.ulstu.`is`.pmu.tank.model.UserWithTanks
//тут, собственно говоря, всё и мутится с БД :)))
@Database(entities = [Nation::class, Level::class, Tank::class, User::class, UserTankCrossRef::class, TankImage::class], version = 1, exportSchema = false)
@ -34,7 +34,7 @@ abstract class AppDatabase : RoomDatabase() {
abstract fun tankImageDao() : TankImageDao
companion object {
private const val DB_NAME: String = "19-db"
private const val DB_NAME: String = "20-db"
@Volatile
private var INSTANCE: AppDatabase? = null
@ -129,7 +129,7 @@ abstract class AppDatabase : RoomDatabase() {
//Users
val userDao = database.userDao()
val user = User(100L,"3tankista73", "egor@mail.ru", "12032003", 10000000)
val user = User(100L,"3tankista73", "egor@mail.ru", "12032003", UserRole.ADMIN, 10000000)
userDao.insert(user)
@ -148,14 +148,14 @@ 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(appContext)
}
}
})
// .addCallback(object : Callback() {
// override fun onCreate(db: SupportSQLiteDatabase) {
// super.onCreate(db)
// CoroutineScope(Dispatchers.IO).launch {
// populateDatabase(appContext)
// }
// }
// })
.build()
.also { INSTANCE = it }
}

View File

@ -0,0 +1,25 @@
package ru.ulstu.`is`.pmu.tank.model
import androidx.room.Entity
import androidx.room.PrimaryKey
import androidx.room.TypeConverter
import androidx.room.TypeConverters
enum class RemoteKeyType(private val type: String) {
NATION(Nation::class.simpleName ?: "Nation");
@TypeConverter
fun toRemoteKeyType(value: String) = RemoteKeyType.values().first { it.type == value }
@TypeConverter
fun fromRemoteKeyType(value: RemoteKeyType) = value.type
}
@Entity(tableName = "remote_keys")
data class RemoteKeys(
@PrimaryKey val entityId: Int,
@TypeConverters(RemoteKeyType::class)
val type: RemoteKeyType,
val prevKey: Int?,
val nextKey: Int?
)

View File

@ -17,6 +17,8 @@ data class User (
val email: String,
@ColumnInfo(name = "password")
val password: String,
@ColumnInfo(name = "role")
val role: UserRole,
@ColumnInfo(name = "balance")
val balance: Int
){
@ -25,8 +27,9 @@ data class User (
nickname: String,
email: String,
password: String,
role: UserRole,
balance: Int
) : this(0L, nickname, email, password, balance)
) : this(0L, nickname, email, password, UserRole.ADMIN, balance)
companion object {
fun getUser(index: Long = 0L): User {
@ -35,6 +38,7 @@ data class User (
"3tankista73",
"egor@mail.ru",
"1234567890!",
UserRole.USER,
10000000
)
}
@ -50,6 +54,7 @@ data class User (
if (nickname != other.nickname) return false
if (email != other.email) return false
if (password != other.password) return false
if (role != other.role) return false
if (balance != other.balance) return false
return true
@ -60,6 +65,7 @@ data class User (
result = 31 * result + nickname.hashCode()
result = 31 * result + email.hashCode()
result = 31 * result + password.hashCode()
result = 31 * result + role.hashCode()
result = 31 * result + balance
return result
}

View File

@ -0,0 +1,6 @@
package ru.ulstu.`is`.pmu.tank.model
enum class UserRole(val value: Int) {
USER(0),
ADMIN(1)
}

View File

@ -8,7 +8,10 @@ import androidx.room.PrimaryKey
import org.jetbrains.annotations.NotNull
//many to many for user and tank
@Entity(primaryKeys = ["userId", "tankId"])
@Entity(
tableName = "users_tanks",
primaryKeys = ["userId", "tankId"]
)
data class UserTankCrossRef(
val userId: Long,
val tankId: Long

View File

@ -6,9 +6,11 @@ import ru.ulstu.`is`.pmu.tank.model.LevelWithTanks
interface LevelRepository {
suspend fun getAllLevels(): List<Level>
fun getSimpleLevel(uid: Long): Flow<Level?>
suspend fun getSimpleLevel(uid: Long): Level
fun getFullLevel(uid: Long): Flow<LevelWithTanks?>
suspend fun insertLevel(level: Level)
suspend fun insertMany(levels: List<Level>)
suspend fun updateLevel(level: Level)
suspend fun deleteLevel(level: Level)
suspend fun deleteAll()
}

View File

@ -1,16 +1,21 @@
package ru.ulstu.`is`.pmu.tank.repository
import androidx.paging.PagingData
import androidx.paging.PagingSource
import kotlinx.coroutines.flow.Flow
import ru.ulstu.`is`.pmu.tank.api.model.NationRemote
import ru.ulstu.`is`.pmu.tank.model.Nation
import ru.ulstu.`is`.pmu.tank.model.NationWithTanks
interface NationRepository {
suspend fun getAllNations(): List<Nation>
suspend fun getAll(): Flow<PagingData<Nation>>
fun getSimpleNation(uid: Long): Flow<Nation?>
fun getFullNation(uid: Long): Flow<NationWithTanks?>
fun pagingSource(): PagingSource<Int, Nation>
suspend fun insertNation(nation: Nation)
suspend fun insertNations(nations: List<Nation>)
suspend fun updateNation(nation: Nation)
suspend fun deleteNation(nation: Nation)
suspend fun deleteNations()
}

View File

@ -8,13 +8,16 @@ import ru.ulstu.`is`.pmu.tank.model.LevelWithTanks
class OfflineLevelRepository(private val levelDao: LevelDao) : LevelRepository {
override suspend fun getAllLevels(): List<Level> = levelDao.getAll()
override fun getSimpleLevel(uid: Long): Flow<Level?> = levelDao.getSimpleLevelUid(uid)
override suspend fun getSimpleLevel(uid: Long): Level = levelDao.getSimpleLevelUid(uid)
override fun getFullLevel(uid: Long): Flow<LevelWithTanks?> = levelDao.getLevelUid(uid)
override suspend fun insertLevel(level: Level) = levelDao.insert(level)
override suspend fun insertMany(levels: List<Level>) = levelDao.insertMany(levels)
override suspend fun updateLevel(level: Level) = levelDao.update(level)
override suspend fun deleteLevel(level: Level) = levelDao.delete(level)
override suspend fun deleteAll() = levelDao.deleteAll()
}

View File

@ -1,5 +1,6 @@
package ru.ulstu.`is`.pmu.tank.repository
import androidx.paging.PagingData
import androidx.paging.PagingSource
import kotlinx.coroutines.flow.Flow
import ru.ulstu.`is`.pmu.tank.dao.NationDao
@ -8,16 +9,25 @@ import ru.ulstu.`is`.pmu.tank.model.NationWithTanks
class OfflineNationRepository(private val nationDao: NationDao) : NationRepository {
override suspend fun getAllNations(): List<Nation> = nationDao.getAll()
override suspend fun getAll(): Flow<PagingData<Nation>> {
TODO("Not yet implemented")
}
override fun getSimpleNation(uid: Long): Flow<Nation?> = nationDao.getSimpleNationUid(uid)
override fun getFullNation(uid: Long): Flow<NationWithTanks?> = nationDao.getNationUid(uid)
override fun pagingSource(): PagingSource<Int, Nation> = nationDao.pagingSource()
override fun pagingSource(): PagingSource<Int, Nation> {
return nationDao.pagingSource()
}
override suspend fun insertNation(nation: Nation) = nationDao.insert(nation)
override suspend fun updateNation(nation: Nation) = nationDao.update(nation)
override suspend fun deleteNation(nation: Nation) = nationDao.delete(nation)
override suspend fun insertNations(nations: List<Nation>) = nationDao.insertMany(nations)
override suspend fun deleteNations() = nationDao.deleteAll()
}

View File

@ -0,0 +1,16 @@
package ru.ulstu.`is`.pmu.tank.repository
import ru.ulstu.`is`.pmu.tank.dao.RemoteKeysDao
import ru.ulstu.`is`.pmu.tank.model.RemoteKeyType
import ru.ulstu.`is`.pmu.tank.model.RemoteKeys
class OfflineRemoteKeyRepository(private val remoteKeysDao: RemoteKeysDao) : RemoteKeyRepository {
override suspend fun getAllRemoteKeys(id: Int, type: RemoteKeyType) =
remoteKeysDao.getRemoteKeys(id, type)
override suspend fun createRemoteKeys(remoteKeys: List<RemoteKeys>) =
remoteKeysDao.insertAll(remoteKeys)
override suspend fun deleteRemoteKey(type: RemoteKeyType) =
remoteKeysDao.clearRemoteKeys(type)
}

View File

@ -13,13 +13,13 @@ class OfflineTankRepository(
private val tankDao: TankDao,
private val tankImageDao: TankImageDao
) : TankRepository {
override fun getAll(): Flow<List<Tank>> = tankDao.getAll()
override suspend fun getAll(): List<Tank> = tankDao.getAll()
override fun getForUserAll(userId: Long): Flow<List<Tank>> = tankDao.getNotUserTank(userId)
override suspend fun getForUserAll(userId: Long): List<Tank> = tankDao.getNotUserTank(userId)
override fun getTank(uid: Long): Flow<Tank?> = tankDao.getTankUid(uid)
override suspend fun getTank(uid: Long): Tank = tankDao.getTankUid(uid)
override fun getUserTanks(uid: Long): Flow<List<TankWithNationAndLevel>> = tankDao.getUserTanks(uid)
override suspend fun getUserTanks(uid: Long): List<TankWithNationAndLevel> = tankDao.getUserTanks(uid)
override suspend fun insertTank(tank: Tank, image: Bitmap) {
val imageId = tankImageDao.insert(
@ -32,6 +32,10 @@ class OfflineTankRepository(
tankDao.insert(tank.copy(imageId = imageId))
}
override suspend fun insertMany(tankList: List<Tank>) {
tankDao.insertMany(tankList)
}
override suspend fun updateTank(tank: Tank, image: Bitmap) {
val imageId = tankImageDao.insert(
TankImage(
@ -49,4 +53,8 @@ class OfflineTankRepository(
override suspend fun delete(tankId: Long) {
tankDao.delete(tankId)
}
override suspend fun deleteAll() {
tankDao.deleteAll()
}
}

View File

@ -8,7 +8,7 @@ import ru.ulstu.`is`.pmu.tank.model.User
class OfflineUserRepository(private val userDao: UserDao) : UserRepository {
override fun getAllUsers(): Flow<List<User>> = userDao.getAll()
override fun getSimpleUser(uid: Long): Flow<User?> = userDao.getSimpleUserUid(uid)
override suspend fun getSimpleUser(email: String): User = userDao.getSimpleUserUid(email)
override fun getFullUser(uid: Long): Flow<Map<User, List<TankWithNationAndLevel>>> = userDao.getUserUid(uid)

View File

@ -0,0 +1,10 @@
package ru.ulstu.`is`.pmu.tank.repository
import ru.ulstu.`is`.pmu.tank.model.RemoteKeyType
import ru.ulstu.`is`.pmu.tank.model.RemoteKeys
interface RemoteKeyRepository {
suspend fun getAllRemoteKeys(id: Int, type: RemoteKeyType): RemoteKeys?
suspend fun createRemoteKeys(remoteKeys: List<RemoteKeys>)
suspend fun deleteRemoteKey(type: RemoteKeyType)
}

View File

@ -7,12 +7,14 @@ import ru.ulstu.`is`.pmu.tank.model.TankExtra
import ru.ulstu.`is`.pmu.tank.model.TankWithNationAndLevel
interface TankRepository {
fun getAll(): Flow<List<Tank>>
fun getForUserAll(userId: Long): Flow<List<Tank>>
fun getTank(uid: Long): Flow<Tank?>
fun getUserTanks(uid: Long): Flow<List<TankWithNationAndLevel>>
suspend fun getAll(): List<Tank>
suspend fun getForUserAll(userId: Long): List<Tank>
suspend fun getTank(uid: Long): Tank
suspend fun getUserTanks(uid: Long): List<TankWithNationAndLevel>
suspend fun insertTank(tank: Tank, image: Bitmap)
suspend fun insertMany(tankList: List<Tank>)
suspend fun updateTank(tank: Tank, image: Bitmap)
suspend fun deleteTank(tank: Tank)
suspend fun delete(tankId: Long)
suspend fun deleteAll()
}

View File

@ -6,7 +6,7 @@ import ru.ulstu.`is`.pmu.tank.model.User
interface UserRepository {
fun getAllUsers(): Flow<List<User>>
fun getSimpleUser(uid: Long): Flow<User?>
suspend fun getSimpleUser(email: String): User
fun getFullUser(uid: Long): Flow<Map<User, List<TankWithNationAndLevel>>>
suspend fun insertUser(user: User)
suspend fun updateUser(user: User)

View File

@ -1,14 +1,11 @@
package ru.ulstu.`is`.pmu.tanks.composeui
import android.content.res.Configuration
import android.util.Log
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
@ -20,20 +17,12 @@ import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.key
import androidx.compose.runtime.mutableStateListOf
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.graphics.asImageBitmap
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
@ -41,23 +30,8 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.FlowCollector
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.withContext
import ru.ulstu.`is`.pmu.R
import ru.ulstu.`is`.pmu.composeui.navigation.Screen
import ru.ulstu.`is`.pmu.tank.composeui.list.TankListViewModel
import ru.ulstu.`is`.pmu.tank.database.AppDatabase
import ru.ulstu.`is`.pmu.tank.model.Level
import ru.ulstu.`is`.pmu.tank.model.Nation
import ru.ulstu.`is`.pmu.tank.model.Tank
import ru.ulstu.`is`.pmu.tank.model.TankWithNationAndLevel
import ru.ulstu.`is`.pmu.tank.model.UserWithTanks
import ru.ulstu.`is`.pmu.tanks.composeui.image.CuteImage
import ru.ulstu.`is`.pmu.tanks.composeui.image.Dimensions
import ru.ulstu.`is`.pmu.tanks.composeui.image.RoundedCorderImage
import ru.ulstu.`is`.pmu.ui.AppViewModelProvider
@ -71,10 +45,9 @@ fun Hangar(
viewModel: TankListViewModel = viewModel(factory = AppViewModelProvider.Factory)
){
viewModel.setUserId(100L)
val userTankListUiState by viewModel.usersTanksUiState.collectAsState()
//новый вызов основного списка
Hangar(tankList = userTankListUiState.userTankList )
Hangar(tankList = viewModel.usersTanksUiState.userTankList )
}
@OptIn(ExperimentalMaterial3Api::class)

View File

@ -1,6 +1,9 @@
package com.application.ui
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.util.Base64
import java.io.ByteArrayOutputStream
import kotlin.math.sqrt
const val miniatureBound: Int = 250
@ -24,3 +27,21 @@ fun Bitmap.resize(bound: Int): Bitmap {
val newHeight: Int = (height / factor).toInt()
return Bitmap.createScaledBitmap(this, newWidth, newHeight, false)
}
fun Bitmap.toByteArray(): ByteArray {
val outputStream = ByteArrayOutputStream()
this.compress(Bitmap.CompressFormat.PNG, 1, outputStream)
return outputStream.toByteArray()
}
fun Bitmap.toBase64(): String {
return Base64.encodeToString(this.toByteArray(), Base64.DEFAULT)
}
fun ByteArray.toBitmap(): Bitmap {
return BitmapFactory.decodeByteArray(this, 0, this.size)
}
fun String.toBitmap(): Bitmap {
return Base64.decode(this, Base64.DEFAULT).toBitmap()
}