Сделал на 2 листа пагинацию, хохо

This commit is contained in:
Кашин Максим 2023-12-27 01:15:26 +04:00
parent c7f73c4d5a
commit 68d533c81b
19 changed files with 211 additions and 28 deletions

View File

@ -0,0 +1,5 @@
package com.example.myapplication.api
enum class ApiStatus {
LOADING, ERROR, DONE
}

View File

@ -29,6 +29,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@ -55,11 +56,15 @@ fun BikeList(
currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)
) {
var getUser by remember { mutableStateOf(currentUserViewModel.user) }
val bikePagingItems = viewModel.bikePagingFlowState.flow.collectAsLazyPagingItems()
LaunchedEffect(getUser?.uid) {
viewModel.refresh()
}
// Проверяем, есть ли у пользователя uid
if (getUser?.uid != null) {
val coroutineScope = rememberCoroutineScope()
val bikePagingItems = viewModel.bikeListUiState.collectAsLazyPagingItems()
Scaffold(
topBar = {},

View File

@ -1,17 +1,37 @@
package com.example.myapplication.database.entities.composeui
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.PagingData
import androidx.paging.cachedIn
import com.example.myapplication.database.entities.model.Bike
import com.example.myapplication.database.entities.repository.BikeRepository
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.emptyFlow
class BikeListViewModel(
private val bikeRepository: BikeRepository
) : ViewModel() {
val bikeListUiState: Flow<PagingData<Bike>> = bikeRepository.getAllBikes()
) : LoadingViewModel() {
var bikePagingFlowState by mutableStateOf(BikePagingFlowState())
private set
fun refresh() {
runInScope(actionSuccess = {
val pagingSource = bikeRepository.getAllBikes()
bikePagingFlowState = BikePagingFlowState(pagingSource.cachedIn(viewModelScope))
})
}
suspend fun deleteBike(bike: Bike) {
runInScope(actionSuccess = {
bikeRepository.deleteBike(bike)
})
}
}
data class BikePagingFlowState(
val flow: Flow<PagingData<Bike>> = emptyFlow(),
)

View File

@ -34,6 +34,7 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController
import com.example.myapplication.api.ApiStatus
import com.example.myapplication.composeui.navigation.Screen
import com.example.myapplication.database.entities.model.Bike
@ -50,7 +51,8 @@ fun BikeView(
LaunchedEffect(Unit) {
viewModel.refreshState()
}
when (viewModel.apiStatus) {
ApiStatus.DONE -> {
Column(
modifier = Modifier
.padding(16.dp)
@ -148,3 +150,12 @@ fun BikeView(
}
}
}
ApiStatus.LOADING -> LoadingPage()
else -> ErrorPage(
message = viewModel.apiError,
onBack = { navController.popBackStack() }
)
}
}

View File

@ -10,7 +10,7 @@ import com.example.myapplication.database.entities.repository.BikeRepository
class BikeViewModel(
savedStateHandle: SavedStateHandle, private val bikeRepository: BikeRepository
) : ViewModel() {
) : LoadingViewModel() {
private val bikeUid: Int = checkNotNull(savedStateHandle["id"])
var bikeUiState by mutableStateOf(BikeUiState())
@ -18,7 +18,11 @@ class BikeViewModel(
suspend fun refreshState() {
if (bikeUid > 0) {
runInScope(actionSuccess = {
bikeUiState = BikeUiState(bikeRepository.getBike(bikeUid))
}, actionError = {
bikeUiState = BikeUiState()
})
}
}

View File

@ -20,7 +20,7 @@ class CartViewModel(
private val rentRepository: RentRepository,
private val rentItemRepository: RentItemRepository,
private val userRepository: UserRepository,
) : ViewModel() {
) : LoadingViewModel() {
//private val userUid: Int = 1
var cartUiState by mutableStateOf(CartUiState())
private set

View File

@ -9,7 +9,7 @@ import com.example.myapplication.database.entities.model.User
import com.example.myapplication.database.entities.repository.UserRepository
import kotlinx.coroutines.launch
class CurrentUserViewModel(private val userRepository: UserRepository) : ViewModel(){
class CurrentUserViewModel(private val userRepository: UserRepository) : LoadingViewModel(){
val argument = mutableStateOf<String?>(null)
private val userid = mutableStateOf<Int?>(null)
var user by mutableStateOf<User?>(null)

View File

@ -9,7 +9,7 @@ import com.example.myapplication.database.entities.model.User
import com.example.myapplication.database.entities.repository.UserRepository
import kotlinx.coroutines.launch
class EntryUserViewModel(private val userRepository: UserRepository) : ViewModel() {
class EntryUserViewModel(private val userRepository: UserRepository) : LoadingViewModel() {
var userList by mutableStateOf<List<User>>(emptyList())
fun setUserList() {

View File

@ -10,7 +10,7 @@ import com.example.myapplication.database.entities.repository.UserItemRepository
class ItemListViewModel(
private val itemRepository: ItemRepository,
private val userItemRepository: UserItemRepository
) : ViewModel() {
) : LoadingViewModel() {
suspend fun deleteItem(item: ItemFromBike) {
itemRepository.deleteItem(
Item(

View File

@ -0,0 +1,64 @@
package com.example.myapplication.database.entities.composeui
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.TextUnitType
import androidx.compose.ui.unit.dp
import com.example.myapplication.R
@Composable
fun LoadingPage() {
Column(
modifier = Modifier
.fillMaxSize()
.padding(10.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(
modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.Center,
fontSize = TextUnit(value = 25F, type = TextUnitType.Sp),
text = stringResource(id = R.string.loading)
)
}
}
@Composable
fun ErrorPage(message: String, onBack: () -> Unit) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(10.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(
modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.Center,
fontSize = TextUnit(value = 20F, type = TextUnitType.Sp),
text = message,
color = Color(0xFFFF1744)
)
Spacer(modifier = Modifier.padding(bottom = 10.dp))
Button(
modifier = Modifier.fillMaxWidth(),
onClick = { onBack() }
) {
Text(stringResource(id = R.string.back))
}
}
}

View File

@ -0,0 +1,50 @@
package com.example.myapplication.database.entities.composeui
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.myapplication.api.ApiStatus
import kotlinx.coroutines.launch
import retrofit2.HttpException
import java.io.IOException
open class LoadingViewModel : ViewModel() {
var apiStatus by mutableStateOf(ApiStatus.DONE)
private set
var apiError by mutableStateOf("")
private set
fun runInScope(
actionSuccess: suspend () -> Unit,
actionError: suspend () -> Unit,
needLoadingScreen: Boolean = true,
) {
viewModelScope.launch {
if (needLoadingScreen)
apiStatus = ApiStatus.LOADING
runCatching {
actionSuccess()
apiStatus = ApiStatus.DONE
apiError = ""
}.onFailure { e: Throwable ->
when (e) {
is IOException,
is HttpException -> {
actionError()
apiStatus = ApiStatus.ERROR
apiError = e.localizedMessage ?: e.toString()
}
else -> throw e
}
}
}
}
fun runInScope(actionSuccess: suspend () -> Unit) {
runInScope(actionSuccess, actionError = {})
}
}

View File

@ -8,7 +8,7 @@ import com.example.myapplication.database.entities.model.User
import com.example.myapplication.database.entities.repository.UserRepository
import kotlinx.coroutines.launch
class RegisterUserViewModel(private val userRepository: UserRepository) : ViewModel() {
class RegisterUserViewModel(private val userRepository: UserRepository) : LoadingViewModel() {
private val _users = MutableLiveData<List<User>>()
val users: LiveData<List<User>> get() = _users

View File

@ -11,7 +11,7 @@ import kotlinx.coroutines.flow.flatMapLatest
class RentListViewModel(
private val rentRepository: RentRepository
) : ViewModel() {
) : LoadingViewModel() {
private val _userId = MutableStateFlow<Int?>(null)
val userId: StateFlow<Int?> get() = _userId

View File

@ -15,7 +15,7 @@ import kotlinx.coroutines.flow.stateIn
class RentViewModel(
savedStateHandle: SavedStateHandle,
private val rentRepository: RentRepository
) : ViewModel() {
) : LoadingViewModel() {
private val rentUid: Int = checkNotNull(savedStateHandle["id"])
val rentUiState: StateFlow<RentUiState> = flow{emit(rentRepository.getRent(rentUid))} .map {

View File

@ -15,7 +15,7 @@ import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
class ReportViewModel(private val itemRespository: RestItemRepository): ViewModel() {
class ReportViewModel(private val itemRespository: RestItemRepository): LoadingViewModel() {
var reportPageUiState by mutableStateOf(ReportPageUiState())
private set

View File

@ -19,7 +19,10 @@ import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController
import com.example.myapplication.R
import com.example.myapplication.api.ApiStatus
import com.example.myapplication.database.entities.composeui.AppViewModelProvider
import com.example.myapplication.database.entities.composeui.ErrorPage
import com.example.myapplication.database.entities.composeui.LoadingPage
import com.example.myapplication.ui.theme.PmudemoTheme
import kotlinx.coroutines.launch
@ -29,7 +32,8 @@ fun BikeEdit(
viewModel: BikeEditViewModel = viewModel(factory = AppViewModelProvider.Factory),
) {
val coroutineScope = rememberCoroutineScope()
when (viewModel.apiStatus) {
ApiStatus.DONE -> {
BikeEdit(
bikeUiState = viewModel.bikeUiState,
onClick = {
@ -41,6 +45,13 @@ fun BikeEdit(
onUpdate = viewModel::updateUiState,
)
}
ApiStatus.LOADING -> LoadingPage()
else -> ErrorPage(
message = viewModel.apiError,
onBack = { navController.popBackStack() }
)
}
}
@Composable
private fun BikeEdit(

View File

@ -6,6 +6,7 @@ import androidx.compose.runtime.setValue
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.myapplication.database.entities.composeui.LoadingViewModel
import com.example.myapplication.database.entities.model.Bike
import com.example.myapplication.database.entities.model.BikeWithItems
import com.example.myapplication.database.entities.model.ItemFromBike
@ -15,7 +16,7 @@ import kotlinx.coroutines.launch
class BikeEditViewModel(
savedStateHandle: SavedStateHandle,
private val bikeRepository: BikeRepository
) : ViewModel() {
) : LoadingViewModel() {
var bikeUiState by mutableStateOf(BikeUiState())
private set
@ -23,10 +24,15 @@ class BikeEditViewModel(
init {
viewModelScope.launch {
if (bikeUid > 0) {
runInScope(
actionSuccess = {
bikeUiState = bikeRepository.getBike(bikeUid)
.toUiState(true)
},
actionError = {
bikeUiState = BikeUiState()
}
)
}
}
@ -39,12 +45,16 @@ class BikeEditViewModel(
suspend fun saveBike() {
if (validateInput()) {
runInScope(
actionSuccess = {
if (bikeUid > 0) {
bikeRepository.updateBike(bikeUiState.bikeDetails.toBike(bikeUid))
} else {
bikeRepository.insertBike(bikeUiState.bikeDetails.toBike())
}
}
)
}
}
private fun validateInput(uiState: BikeDetails = bikeUiState.bikeDetails): Boolean {

View File

@ -6,6 +6,7 @@ import androidx.compose.runtime.setValue
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.myapplication.database.entities.composeui.LoadingViewModel
import com.example.myapplication.database.entities.model.Item
import com.example.myapplication.database.entities.repository.ItemRepository
import kotlinx.coroutines.launch
@ -14,7 +15,7 @@ import org.threeten.bp.LocalDateTime
class ItemEditViewModel(
savedStateHandle: SavedStateHandle,
private val itemRepository: ItemRepository
) : ViewModel() {
) : LoadingViewModel() {
var itemUiState by mutableStateOf(ItemUiState())
private set

View File

@ -21,4 +21,6 @@
<string name="item_bike_not_select">Велосипед не указан</string>
<string name="size">Размер загруженного изображения: %1$dx%2$d</string>
<string name="not_uploaded">Загрузите изображение</string>
<string name="loading">Загрузка…</string>
<string name="back">Назад</string>
</resources>