final
This commit is contained in:
parent
ef95904c6f
commit
702d8972bd
@ -1,4 +1,3 @@
|
||||
<?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">
|
||||
|
@ -75,6 +75,8 @@ dependencies {
|
||||
implementation("androidx.compose.ui:ui-graphics:1.6.0-beta02")
|
||||
implementation("androidx.compose.ui:ui-tooling-preview:1.6.0-beta02")
|
||||
implementation("androidx.compose.material3:material3:1.1.2")
|
||||
implementation("androidx.compose.material:material:1.5.4")
|
||||
implementation("androidx.paging:paging-compose:3.2.1")
|
||||
|
||||
// Room
|
||||
val room_version = "2.6.1"
|
||||
|
@ -27,5 +27,6 @@ class AppDataContainer(private val context: Context) : AppContainer {
|
||||
|
||||
companion object {
|
||||
const val TIMEOUT = 5000L
|
||||
const val LIMIT = 10
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package com.zyzf.coffeepreorder.database.dao
|
||||
|
||||
import androidx.paging.PagingSource
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Query
|
||||
@ -10,10 +11,10 @@ import kotlinx.coroutines.flow.Flow
|
||||
@Dao
|
||||
interface CoffeeDao {
|
||||
@Query("select * from coffee order by name collate nocase asc")
|
||||
fun getAll(): Flow<List<Coffee>>
|
||||
fun getAll(): PagingSource<Int, Coffee>
|
||||
|
||||
@Query("select * from coffee where cart_id is not null and count > 0 order by name collate nocase asc")
|
||||
fun getAllInCart(): Flow<List<Coffee>>
|
||||
fun getAllInCart(): PagingSource<Int, Coffee>
|
||||
|
||||
@Query("select sum(cost) from coffee where cart_id is not null and count > 0")
|
||||
fun getSumInCart(): Double
|
||||
|
@ -17,7 +17,7 @@ import androidx.room.PrimaryKey
|
||||
])
|
||||
data class Coffee(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
val uid: Int?,
|
||||
val uid: Int = 0,
|
||||
@ColumnInfo(name = "name")
|
||||
var name: String,
|
||||
@ColumnInfo(name = "cost")
|
||||
@ -36,7 +36,7 @@ data class Coffee(
|
||||
ingredients: String,
|
||||
cartId: Int?,
|
||||
count: Int?
|
||||
) : this(null, name, cost, ingredients, null, 0)
|
||||
) : this(0, name, cost, ingredients, null, 0)
|
||||
|
||||
companion object {
|
||||
fun getCoffee(index: Int = 0): Coffee {
|
||||
|
@ -1,12 +1,13 @@
|
||||
package com.zyzf.coffeepreorder.database.repository
|
||||
|
||||
import androidx.paging.PagingData
|
||||
import com.zyzf.coffeepreorder.database.model.Coffee
|
||||
import com.zyzf.coffeepreorder.database.model.CoffeeWithCart
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface CoffeeRepository {
|
||||
fun getAll(): Flow<List<Coffee>>
|
||||
fun getAllInCart(): Flow<List<Coffee>>
|
||||
fun getAll(): Flow<PagingData<Coffee>>
|
||||
fun getAllInCart(): Flow<PagingData<Coffee>>
|
||||
fun getSumInCart(): Double
|
||||
suspend fun getByUid(uid: Int): CoffeeWithCart?
|
||||
suspend fun insert(name: String, cost: Double, ingredients: String): Long
|
||||
|
@ -1,13 +1,29 @@
|
||||
package com.zyzf.coffeepreorder.database.repository
|
||||
|
||||
import androidx.paging.Pager
|
||||
import androidx.paging.PagingConfig
|
||||
import androidx.paging.PagingData
|
||||
import com.zyzf.coffeepreorder.database.AppDataContainer
|
||||
import com.zyzf.coffeepreorder.database.dao.CoffeeDao
|
||||
import com.zyzf.coffeepreorder.database.model.Coffee
|
||||
import com.zyzf.coffeepreorder.database.model.CoffeeWithCart
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
class OfflineCoffeeRepository(private val coffeeDao: CoffeeDao) : CoffeeRepository {
|
||||
override fun getAll(): Flow<List<Coffee>> = coffeeDao.getAll()
|
||||
override fun getAllInCart(): Flow<List<Coffee>> = coffeeDao.getAllInCart()
|
||||
override fun getAll(): Flow<PagingData<Coffee>> = Pager(
|
||||
config = PagingConfig(
|
||||
pageSize = AppDataContainer.LIMIT,
|
||||
enablePlaceholders = false
|
||||
),
|
||||
pagingSourceFactory = coffeeDao::getAll
|
||||
).flow
|
||||
override fun getAllInCart(): Flow<PagingData<Coffee>> = Pager(
|
||||
config = PagingConfig(
|
||||
pageSize = AppDataContainer.LIMIT,
|
||||
enablePlaceholders = false
|
||||
),
|
||||
pagingSourceFactory = coffeeDao::getAllInCart
|
||||
).flow
|
||||
override fun getSumInCart(): Double = coffeeDao.getSumInCart()
|
||||
override suspend fun getByUid(uid: Int): CoffeeWithCart? = coffeeDao.getByUid(uid)
|
||||
override suspend fun insert(name: String, cost: Double, ingredients: String): Long = coffeeDao.insert(name, cost, ingredients)
|
||||
|
@ -5,6 +5,7 @@ import androidx.lifecycle.viewmodel.CreationExtras
|
||||
import androidx.lifecycle.viewmodel.initializer
|
||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||
import com.zyzf.coffeepreorder.CoffeeApplication
|
||||
import com.zyzf.coffeepreorder.ui.cart.CartViewModel
|
||||
import com.zyzf.coffeepreorder.ui.coffee.CoffeeListViewModel
|
||||
|
||||
object AppViewModelProvider {
|
||||
@ -12,6 +13,9 @@ object AppViewModelProvider {
|
||||
initializer {
|
||||
CoffeeListViewModel(coffeeApplication().container.coffeeRepository, coffeeApplication().container.cartRepository)
|
||||
}
|
||||
initializer {
|
||||
CartViewModel(coffeeApplication().container.coffeeRepository, coffeeApplication().container.cartRepository)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.zyzf.coffeepreorder.ui.cart
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
@ -15,24 +16,32 @@ import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material.icons.filled.Clear
|
||||
import androidx.compose.material.pullrefresh.PullRefreshIndicator
|
||||
import androidx.compose.material.pullrefresh.rememberPullRefreshState
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.ExtendedFloatingActionButton
|
||||
import androidx.compose.material3.FloatingActionButton
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.material3.rememberModalBottomSheetState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
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
|
||||
@ -43,12 +52,21 @@ import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.zIndex
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import androidx.paging.compose.LazyPagingItems
|
||||
import androidx.paging.compose.collectAsLazyPagingItems
|
||||
import androidx.paging.compose.itemContentType
|
||||
import androidx.paging.compose.itemKey
|
||||
import coil.compose.AsyncImage
|
||||
import coil.request.ImageRequest
|
||||
import com.zyzf.coffeepreorder.R
|
||||
import com.zyzf.coffeepreorder.database.AppDatabase
|
||||
import com.zyzf.coffeepreorder.database.model.Coffee
|
||||
import com.zyzf.coffeepreorder.ui.AppViewModelProvider
|
||||
import com.zyzf.coffeepreorder.ui.coffee.CoffeeList
|
||||
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
|
||||
@ -57,88 +75,153 @@ import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
@OptIn(DelicateCoroutinesApi::class, ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
fun Cart(navController: NavController?) {
|
||||
fun Cart(
|
||||
navController: NavController?,
|
||||
viewModel: CartViewModel = viewModel(factory = AppViewModelProvider.Factory)
|
||||
) {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val coffeeListUiState = viewModel.coffeeListUiState.collectAsLazyPagingItems()
|
||||
val openDialog = remember { mutableStateOf(false) }
|
||||
var coffee by remember { mutableStateOf(Coffee("", 0.0, "", null, 0)) }
|
||||
val context = LocalContext.current
|
||||
val itemsList = remember { mutableStateListOf<Coffee>() }
|
||||
LaunchedEffect(Unit) {
|
||||
withContext(Dispatchers.IO) {
|
||||
AppDatabase.getInstance(context).coffeeDao().getAllInCart().collect { data ->
|
||||
itemsList.clear()
|
||||
itemsList.addAll(data)
|
||||
val coffee = remember { mutableStateOf(Coffee.getCoffee()) }
|
||||
var refreshing by remember { mutableStateOf(false) }
|
||||
fun refresh() = coroutineScope.launch {
|
||||
refreshing = true
|
||||
coffeeListUiState.refresh()
|
||||
refreshing = false
|
||||
}
|
||||
val state = rememberPullRefreshState(refreshing, ::refresh)
|
||||
Scaffold(
|
||||
topBar = {},
|
||||
floatingActionButton = {
|
||||
ExtendedFloatingActionButton(
|
||||
onClick = { navController?.navigate(Screen.Order.route) },
|
||||
icon = { Icon(Icons.Filled.Add, "Сделать заказ") },
|
||||
text = { Text(text = "Сделать заказ") },
|
||||
modifier = Modifier
|
||||
.padding(all = 20.dp),
|
||||
containerColor = MaterialTheme.colorScheme.primaryContainer,
|
||||
contentColor = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
}
|
||||
) { innerPadding ->
|
||||
PullRefreshIndicator(
|
||||
refreshing, state,
|
||||
Modifier
|
||||
.zIndex(100f)
|
||||
)
|
||||
CartList(
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
coffeeList = coffeeListUiState,
|
||||
onDeleteFromCartClick = {currentCoffee: Coffee ->
|
||||
coffee.value = currentCoffee
|
||||
openDialog.value = true
|
||||
}
|
||||
)
|
||||
}
|
||||
DeleteFromCartAlertDialog(
|
||||
openDialog = openDialog,
|
||||
onConfirmClick = {
|
||||
coroutineScope.launch {
|
||||
viewModel.deleteCoffeeFromCart(coffee.value)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CartList(
|
||||
modifier: Modifier = Modifier,
|
||||
coffeeList: LazyPagingItems<Coffee>,
|
||||
onDeleteFromCartClick: (coffee: Coffee) -> Unit
|
||||
) {
|
||||
LazyColumn(
|
||||
horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
items(
|
||||
count = coffeeList.itemCount,
|
||||
key = coffeeList.itemKey(),
|
||||
contentType = coffeeList.itemContentType()
|
||||
) {index ->
|
||||
val coffee = coffeeList[index]
|
||||
coffee?.let {
|
||||
CartListItem(
|
||||
coffee = coffee,
|
||||
onDeleteFromCartClick = onDeleteFromCartClick
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
LazyColumn(
|
||||
horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
items(itemsList) { currentCoffee ->
|
||||
Row(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.heightIn(max = 140.dp)
|
||||
.padding(bottom = 10.dp, top = 10.dp),
|
||||
horizontalArrangement = Arrangement.SpaceAround) {
|
||||
AsyncImage(
|
||||
model = ImageRequest.Builder(context = LocalContext.current).data("https://zyzf.space/s/zXgFRTmbR4KMxMH/download?path=&files=coffee_image_" + currentCoffee.uid +".png")
|
||||
.crossfade(true).build(),
|
||||
error = painterResource(R.drawable.ic_broken_image),
|
||||
placeholder = painterResource(R.drawable.loading_img),
|
||||
contentDescription = "Кофе",
|
||||
contentScale = ContentScale.Crop,
|
||||
modifier = Modifier
|
||||
.size(100.dp)
|
||||
.clip(RoundedCornerShape(50.dp))
|
||||
)
|
||||
Column(
|
||||
Modifier
|
||||
.weight(2f)
|
||||
.padding(start = 20.dp)) {
|
||||
val currentCoffeeName: String = if (currentCoffee.count > 1) {
|
||||
currentCoffee.name + " x" + currentCoffee.count.toString()
|
||||
} else {
|
||||
currentCoffee.name
|
||||
}
|
||||
Text(text = currentCoffeeName, fontSize = 25.sp)
|
||||
Text(text = String.format("%.2f", currentCoffee.cost), fontSize = 20.sp)
|
||||
Text(text = currentCoffee.ingredients, fontSize = 15.sp)
|
||||
Row(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 5.dp)) {
|
||||
Button(
|
||||
onClick = { coffee = currentCoffee; openDialog.value = true },
|
||||
shape = CircleShape,
|
||||
modifier = Modifier.padding(start = 10.dp, end = 10.dp),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = MaterialTheme.colorScheme.errorContainer,
|
||||
contentColor = MaterialTheme.colorScheme.error
|
||||
)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Clear,
|
||||
contentDescription = "Favorite",
|
||||
modifier = Modifier.size(20.dp)
|
||||
)
|
||||
Spacer(Modifier.size(ButtonDefaults.IconSpacing))
|
||||
Text(text = "Удалить из корзины")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CartListItem (
|
||||
coffee: Coffee,
|
||||
modifier: Modifier = Modifier,
|
||||
onDeleteFromCartClick: (coffee: Coffee) -> Unit
|
||||
) {
|
||||
Row(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.heightIn(max = 140.dp)
|
||||
.padding(bottom = 10.dp, top = 10.dp),
|
||||
horizontalArrangement = Arrangement.SpaceAround) {
|
||||
AsyncImage(
|
||||
model = ImageRequest.Builder(context = LocalContext.current).data("https://zyzf.space/s/zXgFRTmbR4KMxMH/download?path=&files=coffee_image_" + coffee.uid +".png")
|
||||
.crossfade(true).build(),
|
||||
error = painterResource(R.drawable.ic_broken_image),
|
||||
placeholder = painterResource(R.drawable.loading_img),
|
||||
contentDescription = "Кофе",
|
||||
contentScale = ContentScale.Crop,
|
||||
modifier = Modifier
|
||||
.size(100.dp)
|
||||
.clip(RoundedCornerShape(50.dp))
|
||||
)
|
||||
Column(
|
||||
Modifier
|
||||
.weight(2f)
|
||||
.padding(start = 20.dp)) {
|
||||
val currentCoffeeName: String = if (coffee.count > 1) {
|
||||
coffee.name + " x" + coffee.count.toString()
|
||||
} else {
|
||||
coffee.name
|
||||
}
|
||||
Text(text = currentCoffeeName, fontSize = 25.sp)
|
||||
Text(text = String.format("%.2f", coffee.cost), fontSize = 20.sp)
|
||||
Text(text = coffee.ingredients, fontSize = 15.sp)
|
||||
Row(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 5.dp)) {
|
||||
Button(
|
||||
onClick = { onDeleteFromCartClick(coffee) },
|
||||
shape = CircleShape,
|
||||
modifier = Modifier.padding(start = 10.dp, end = 10.dp),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = MaterialTheme.colorScheme.errorContainer,
|
||||
contentColor = MaterialTheme.colorScheme.error
|
||||
)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Clear,
|
||||
contentDescription = "Favorite",
|
||||
modifier = Modifier.size(20.dp)
|
||||
)
|
||||
Spacer(Modifier.size(ButtonDefaults.IconSpacing))
|
||||
Text(text = "Удалить из корзины")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
ExtendedFloatingActionButton(
|
||||
onClick = { navController?.navigate(Screen.Order.route) },
|
||||
icon = { Icon(Icons.Filled.Add, "Сделать заказ") },
|
||||
text = { Text(text = "Сделать заказ") },
|
||||
modifier = Modifier.align(alignment = Alignment.BottomEnd).padding(all = 20.dp),
|
||||
containerColor = MaterialTheme.colorScheme.primaryContainer,
|
||||
contentColor = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DeleteFromCartAlertDialog(
|
||||
modifier: Modifier = Modifier,
|
||||
openDialog: MutableState<Boolean>,
|
||||
onConfirmClick: () -> Unit
|
||||
) {
|
||||
if (openDialog.value) {
|
||||
AlertDialog(
|
||||
icon = {
|
||||
@ -156,12 +239,7 @@ fun Cart(navController: NavController?) {
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
GlobalScope.launch (Dispatchers.Main) {
|
||||
coffee.uid?.let {
|
||||
AppDatabase.getInstance(context).cartDao().deleteCoffee(it, 1)
|
||||
}
|
||||
}
|
||||
|
||||
onConfirmClick()
|
||||
openDialog.value = false
|
||||
}
|
||||
) {
|
||||
|
@ -0,0 +1,19 @@
|
||||
package com.zyzf.coffeepreorder.ui.cart
|
||||
|
||||
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(
|
||||
private val coffeeRepository: CoffeeRepository,
|
||||
private val cartRepository: CartRepository
|
||||
) : ViewModel() {
|
||||
val coffeeListUiState: Flow<PagingData<Coffee>> = coffeeRepository.getAllInCart()
|
||||
|
||||
suspend fun deleteCoffeeFromCart(coffee: Coffee) {
|
||||
cartRepository.deleteCoffee(coffee.uid, 1)
|
||||
}
|
||||
}
|
@ -21,12 +21,17 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material.icons.outlined.Create
|
||||
import androidx.compose.material.pullrefresh.PullRefreshIndicator
|
||||
import androidx.compose.material.pullrefresh.rememberPullRefreshState
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
@ -51,6 +56,7 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Alignment.Companion.CenterHorizontally
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
@ -61,31 +67,46 @@ import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.zIndex
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.paging.PagingData
|
||||
import androidx.paging.compose.LazyPagingItems
|
||||
import androidx.paging.compose.collectAsLazyPagingItems
|
||||
import androidx.paging.compose.itemContentType
|
||||
import androidx.paging.compose.itemKey
|
||||
import coil.compose.AsyncImage
|
||||
import coil.request.ImageRequest
|
||||
import com.zyzf.coffeepreorder.R
|
||||
import com.zyzf.coffeepreorder.database.model.Coffee
|
||||
import com.zyzf.coffeepreorder.ui.AppViewModelProvider
|
||||
import com.zyzf.coffeepreorder.ui.theme.CoffeePreorderTheme
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
fun CoffeeList(
|
||||
viewModel: CoffeeListViewModel = viewModel(factory = AppViewModelProvider.Factory)
|
||||
) {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val coffeeListUiState = viewModel.coffeeListUiState.collectAsState()
|
||||
val coffeeListUiState = viewModel.coffeeListUiState.collectAsLazyPagingItems()
|
||||
val sheetState = rememberModalBottomSheetState()
|
||||
val openDialog = remember { mutableStateOf(false) }
|
||||
val coffee = remember { mutableStateOf(Coffee.getCoffee()) }
|
||||
var imageUri: Any? by remember { mutableStateOf(R.drawable.img) }
|
||||
var refreshing by remember { mutableStateOf(false) }
|
||||
fun refresh() = coroutineScope.launch {
|
||||
refreshing = true
|
||||
coffeeListUiState.refresh()
|
||||
refreshing = false
|
||||
}
|
||||
val state = rememberPullRefreshState(refreshing, ::refresh)
|
||||
val photoPicker = rememberLauncherForActivityResult(
|
||||
contract = ActivityResultContracts.PickVisualMedia()
|
||||
) {
|
||||
if (it != null) {
|
||||
Log.d("PhotoPicker", "Selected URI: $it")
|
||||
viewModel.imageUri = it
|
||||
imageUri = it
|
||||
} else {
|
||||
Log.d("PhotoPicker", "No media selected")
|
||||
}
|
||||
@ -111,48 +132,51 @@ fun CoffeeList(
|
||||
}
|
||||
}
|
||||
) { innerPadding ->
|
||||
coffeeListUiState.value.coffeeList.let {
|
||||
CoffeeList(
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
coffeeList = it,
|
||||
onAddToCartClick = { coffeeUid: Int ->
|
||||
coroutineScope.launch {
|
||||
viewModel.addCoffeeToCart(coffeeUid = coffeeUid)
|
||||
}
|
||||
},
|
||||
onEditClick = { curcoffee: Coffee ->
|
||||
coroutineScope.launch {
|
||||
coffee.value = curcoffee
|
||||
openDialog.value = true
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
AddEditModalBottomSheet(
|
||||
coffee = coffee,
|
||||
sheetState = sheetState,
|
||||
openDialog = openDialog,
|
||||
onAddClick = { coffee: Coffee, context: Context ->
|
||||
PullRefreshIndicator(
|
||||
refreshing, state,
|
||||
Modifier
|
||||
.zIndex(100f)
|
||||
)
|
||||
CoffeeList(
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
coffeeList = coffeeListUiState,
|
||||
onAddToCartClick = { coffeeUid: Int ->
|
||||
coroutineScope.launch {
|
||||
viewModel.createCoffee(coffee, context)
|
||||
viewModel.addCoffeeToCart(coffeeUid = coffeeUid)
|
||||
}
|
||||
},
|
||||
onEditClick = { coffee: Coffee, context: Context ->
|
||||
onEditClick = { curcoffee: Coffee ->
|
||||
coroutineScope.launch {
|
||||
viewModel.editCoffee(coffee, context)
|
||||
coffee.value = curcoffee
|
||||
openDialog.value = true
|
||||
}
|
||||
},
|
||||
onDeleteClick = { coffee: Coffee ->
|
||||
coroutineScope.launch {
|
||||
viewModel.deleteCoffee(coffee)
|
||||
}
|
||||
},
|
||||
photoPicker = photoPicker,
|
||||
imageUri = viewModel.imageUri
|
||||
}
|
||||
)
|
||||
}
|
||||
AddEditModalBottomSheet(
|
||||
coffee = coffee,
|
||||
sheetState = sheetState,
|
||||
openDialog = openDialog,
|
||||
onAddClick = { coffee: Coffee, context: Context ->
|
||||
coroutineScope.launch {
|
||||
viewModel.createCoffee(coffee, imageUri as Uri, context)
|
||||
}
|
||||
},
|
||||
onEditClick = { coffee: Coffee, context: Context ->
|
||||
coroutineScope.launch {
|
||||
viewModel.editCoffee(coffee, imageUri as Uri, context)
|
||||
}
|
||||
},
|
||||
onDeleteClick = { coffee: Coffee ->
|
||||
coroutineScope.launch {
|
||||
viewModel.deleteCoffee(coffee)
|
||||
}
|
||||
},
|
||||
photoPicker = photoPicker,
|
||||
imageUri = imageUri
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@ -269,14 +293,21 @@ private fun AddEditModalBottomSheet(
|
||||
@Composable
|
||||
private fun CoffeeList(
|
||||
modifier: Modifier = Modifier,
|
||||
coffeeList: List<Coffee>,
|
||||
coffeeList: LazyPagingItems<Coffee>,
|
||||
onAddToCartClick: (coffeeUid: Int) -> Unit,
|
||||
onEditClick: (coffee: Coffee) -> Unit
|
||||
) {
|
||||
LazyColumn(
|
||||
horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
items(items = coffeeList, key = { it.uid!! }) { coffee ->
|
||||
CoffeeListItem(coffee = coffee, onAddToCartClick = onAddToCartClick, onEditClick = onEditClick)
|
||||
items(
|
||||
count = coffeeList.itemCount,
|
||||
key = coffeeList.itemKey(),
|
||||
contentType = coffeeList.itemContentType()
|
||||
) {index ->
|
||||
val coffee = coffeeList[index]
|
||||
coffee?.let {
|
||||
CoffeeListItem(coffee = coffee, onAddToCartClick = onAddToCartClick, onEditClick = onEditClick)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -319,7 +350,7 @@ private fun CoffeeListItem(
|
||||
.padding(top = 5.dp)) {
|
||||
Button(
|
||||
onClick = {
|
||||
coffee.uid?.let { onAddToCartClick(it) }
|
||||
coffee.uid.let { onAddToCartClick(it) }
|
||||
},
|
||||
shape = CircleShape,
|
||||
modifier = Modifier.fillMaxWidth(fraction = 0.75f)
|
||||
@ -350,6 +381,7 @@ private fun CoffeeListItem(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO)
|
||||
@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
@ -359,7 +391,29 @@ fun CoffeeListPreview() {
|
||||
color = MaterialTheme.colorScheme.background
|
||||
) {
|
||||
CoffeeList(
|
||||
coffeeList = (1..20).map { i -> Coffee.getCoffee(i) },
|
||||
coffeeList = MutableStateFlow(
|
||||
PagingData.from((1..20).map { i -> Coffee.getCoffee(i) })
|
||||
).collectAsLazyPagingItems(),
|
||||
onAddToCartClick = {},
|
||||
onEditClick = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO)
|
||||
@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
fun CoffeeEmptyListPreview() {
|
||||
CoffeePreorderTheme {
|
||||
Surface(
|
||||
color = MaterialTheme.colorScheme.background
|
||||
) {
|
||||
CoffeeList(
|
||||
coffeeList = MutableStateFlow(
|
||||
PagingData.empty<Coffee>()
|
||||
).collectAsLazyPagingItems(),
|
||||
onAddToCartClick = {},
|
||||
onEditClick = {}
|
||||
)
|
||||
|
@ -6,24 +6,19 @@ import android.graphics.BitmapFactory
|
||||
import android.net.Uri
|
||||
import android.os.StrictMode
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.paging.PagingData
|
||||
import com.jcraft.jsch.Channel
|
||||
import com.jcraft.jsch.ChannelSftp
|
||||
import com.jcraft.jsch.JSch
|
||||
import com.jcraft.jsch.JSchException
|
||||
import com.jcraft.jsch.Session
|
||||
import com.jcraft.jsch.SftpException
|
||||
import com.zyzf.coffeepreorder.R
|
||||
import com.zyzf.coffeepreorder.database.AppDataContainer
|
||||
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
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.File
|
||||
@ -34,22 +29,15 @@ class CoffeeListViewModel(
|
||||
private val coffeeRepository: CoffeeRepository,
|
||||
private val cartRepository: CartRepository
|
||||
) : ViewModel() {
|
||||
val coffeeListUiState: StateFlow<CoffeeListUiState> = coffeeRepository.getAll().map {
|
||||
CoffeeListUiState(it)
|
||||
}.stateIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.WhileSubscribed(stopTimeoutMillis = AppDataContainer.TIMEOUT),
|
||||
initialValue = CoffeeListUiState()
|
||||
)
|
||||
var imageUri: Any? = R.drawable.img
|
||||
val coffeeListUiState: Flow<PagingData<Coffee>> = coffeeRepository.getAll()
|
||||
|
||||
suspend fun addCoffeeToCart(coffeeUid: Int) {
|
||||
val cart: Cart = cartRepository.get()
|
||||
cart.uid?.let { cartRepository.insertCoffee(it, coffeeUid, 1) }
|
||||
}
|
||||
suspend fun createCoffee(coffee: Coffee, context: Context) {
|
||||
suspend fun createCoffee(coffee: Coffee, imageUri: Uri, context: Context) {
|
||||
val newCoffee: Long = coffeeRepository.insert(coffee.name, coffee.cost, coffee.ingredients)
|
||||
val inputStream = context.contentResolver.openInputStream(imageUri as Uri)
|
||||
val inputStream = context.contentResolver.openInputStream(imageUri)
|
||||
val bitmap = BitmapFactory.decodeStream(inputStream)
|
||||
|
||||
val f = File(context.cacheDir, "coffee_image_$newCoffee.png")
|
||||
@ -66,9 +54,9 @@ class CoffeeListViewModel(
|
||||
|
||||
copyFileToSftp(f, "/mnt/nextcloud/data/Zyzf/files/Images")
|
||||
}
|
||||
suspend fun editCoffee(coffee: Coffee, context: Context) {
|
||||
suspend fun editCoffee(coffee: Coffee, imageUri: Uri, context: Context) {
|
||||
val editedCoffee: Int = coffeeRepository.update(coffee.uid!!, coffee.name, coffee.cost, coffee.ingredients, coffee.cartId, coffee.count)!!
|
||||
val inputStream = context.contentResolver.openInputStream(imageUri as Uri)
|
||||
val inputStream = context.contentResolver.openInputStream(imageUri)
|
||||
val bitmap = BitmapFactory.decodeStream(inputStream)
|
||||
|
||||
val f = File(context.cacheDir, "coffee_image_$editedCoffee.png")
|
||||
@ -89,8 +77,6 @@ class CoffeeListViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
data class CoffeeListUiState(val coffeeList: List<Coffee> = listOf())
|
||||
|
||||
const val REMOTE_HOST = "109.197.199.134"
|
||||
const val USERNAME = "zyzf"
|
||||
const val PASSWORD = "250303Zyzf-d-grad"
|
||||
|
Loading…
Reference in New Issue
Block a user