Course work: implement full performance CRUD
This commit is contained in:
parent
a687ff002f
commit
2eca8db087
@ -67,7 +67,8 @@ dependencies {
|
||||
implementation("androidx.compose.ui:ui")
|
||||
implementation("androidx.compose.ui:ui-graphics")
|
||||
implementation("androidx.compose.ui:ui-tooling-preview")
|
||||
implementation("androidx.compose.material3:material3")
|
||||
implementation("androidx.compose.material3:material3:1.1.2")
|
||||
implementation("androidx.compose.material:material:1.4.3")
|
||||
|
||||
// Room
|
||||
val room_version = "2.5.2"
|
||||
|
@ -60,6 +60,22 @@ interface MyServerService {
|
||||
@Body credentials: Credentials
|
||||
): Token
|
||||
|
||||
@POST("api/performances")
|
||||
suspend fun createPerformance(
|
||||
@Body performance: PerformanceRemote,
|
||||
)
|
||||
|
||||
@PUT("api/performances/{id}")
|
||||
suspend fun updatePerformance(
|
||||
@Path("id") id: Int,
|
||||
@Body student: PerformanceRemote,
|
||||
)
|
||||
|
||||
@DELETE("api/performances/{id}")
|
||||
suspend fun deletePerformance(
|
||||
@Path("id") id: Int,
|
||||
)
|
||||
|
||||
companion object {
|
||||
private const val BASE_URL = "http://10.0.2.2:8000/"
|
||||
|
||||
|
@ -40,4 +40,14 @@ suspend fun PerformanceRemote.toPerformanceWithPeople(service: MyServerService):
|
||||
service.getPerson(director_id).toPerson(),
|
||||
actorsList.toList()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun Performance.toPerformanceRemote(): PerformanceRemote = PerformanceRemote(
|
||||
performance_uid!!,
|
||||
title,
|
||||
description,
|
||||
authorId!!,
|
||||
directorId!!,
|
||||
imageURL,
|
||||
previewImageURL
|
||||
)
|
@ -6,6 +6,7 @@ import androidx.paging.PagingConfig
|
||||
import androidx.paging.PagingData
|
||||
import com.example.mobile_labs.api.MyServerService
|
||||
import com.example.mobile_labs.api.models.toPerformance
|
||||
import com.example.mobile_labs.api.models.toPerformanceRemote
|
||||
import com.example.mobile_labs.api.models.toPerformanceWithPeople
|
||||
import com.example.mobile_labs.api.people.RestPersonRepository
|
||||
import com.example.mobile_labs.common.AppDataContainer
|
||||
@ -50,4 +51,16 @@ class RestPerformanceRepository(
|
||||
|
||||
override suspend fun getPerformance(uid: Int): PerformanceWithPeople =
|
||||
service.getPerformance(uid).toPerformanceWithPeople(service)
|
||||
|
||||
override suspend fun insertPerformance(performance: Performance) {
|
||||
service.createPerformance(performance.toPerformanceRemote())
|
||||
}
|
||||
|
||||
override suspend fun updatePerformance(performance: Performance) {
|
||||
service.updatePerformance(performance.performance_uid!!, performance.toPerformanceRemote())
|
||||
}
|
||||
|
||||
override suspend fun deletePerformance(performance: Performance) {
|
||||
service.deletePerformance(performance.performance_uid !!)
|
||||
}
|
||||
}
|
@ -64,6 +64,6 @@ class AppDataContainer(val context: Context) : AppContainer {
|
||||
|
||||
companion object {
|
||||
const val TIMEOUT = 5000L
|
||||
const val LIMIT = 3
|
||||
const val LIMIT = 20
|
||||
}
|
||||
}
|
@ -8,7 +8,9 @@ import androidx.lifecycle.viewmodel.viewModelFactory
|
||||
import com.example.mobile_labs.TheatreApplication
|
||||
import com.example.mobile_labs.ui.event.list.EventListViewModel
|
||||
import com.example.mobile_labs.ui.login.LoginViewModel
|
||||
import com.example.mobile_labs.ui.performance.list.AdminPerformanceListViewModel
|
||||
import com.example.mobile_labs.ui.performance.list.PerformanceListViewModel
|
||||
import com.example.mobile_labs.ui.performance.view.AdminPerformanceViewModel
|
||||
import com.example.mobile_labs.ui.performance.view.PerformanceViewModel
|
||||
import com.example.mobile_labs.ui.person.list.PeopleListViewModel
|
||||
|
||||
@ -29,6 +31,12 @@ object AppViewModelProvider {
|
||||
initializer {
|
||||
LoginViewModel()
|
||||
}
|
||||
initializer {
|
||||
AdminPerformanceListViewModel(theatreApplication().container.performanceRestRepository)
|
||||
}
|
||||
initializer {
|
||||
AdminPerformanceViewModel(this.createSavedStateHandle(), theatreApplication().container.performanceRestRepository)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,4 +8,7 @@ import kotlinx.coroutines.flow.Flow
|
||||
interface PerformanceRepository {
|
||||
fun getAllPerformances(): Flow<PagingData<Performance>>
|
||||
suspend fun getPerformance(uid: Int): PerformanceWithPeople
|
||||
suspend fun insertPerformance(performance: Performance)
|
||||
suspend fun updatePerformance(performance: Performance)
|
||||
suspend fun deletePerformance(performance: Performance)
|
||||
}
|
@ -24,11 +24,11 @@ class OfflinePerformanceRepository(private val performanceDao: PerformanceDao) :
|
||||
).flow
|
||||
override suspend fun getPerformance(uid: Int): PerformanceWithPeople = performanceDao.getByUid(uid).first();
|
||||
|
||||
suspend fun insertPerformance(performance: Performance) = performanceDao.insert(performance);
|
||||
override suspend fun insertPerformance(performance: Performance) = performanceDao.insert(performance);
|
||||
|
||||
suspend fun updatePerformance(performance: Performance) = performanceDao.update(performance);
|
||||
override suspend fun updatePerformance(performance: Performance) = performanceDao.update(performance);
|
||||
|
||||
suspend fun deletePerformance(performance: Performance) = performanceDao.delete(performance);
|
||||
override suspend fun deletePerformance(performance: Performance) = performanceDao.delete(performance);
|
||||
|
||||
suspend fun clearPerformances() = performanceDao.deleteAll()
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.example.mobile_labs.ui.navigation
|
||||
|
||||
import android.content.res.Configuration
|
||||
import android.util.Log
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.icons.Icons
|
||||
@ -37,7 +38,9 @@ import com.example.mobile_labs.api.MyServerService
|
||||
import com.example.mobile_labs.ui.about.About
|
||||
import com.example.mobile_labs.ui.event.list.EventList
|
||||
import com.example.mobile_labs.ui.login.Login
|
||||
import com.example.mobile_labs.ui.performance.list.AdminPerformanceList
|
||||
import com.example.mobile_labs.ui.performance.list.PerformanceList
|
||||
import com.example.mobile_labs.ui.performance.view.AdminPerformanceView
|
||||
import com.example.mobile_labs.ui.performance.view.PerformanceView
|
||||
import com.example.mobile_labs.ui.person.list.PeopleList
|
||||
|
||||
@ -79,8 +82,26 @@ fun Navbar(
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
NavigationBar(modifier) {
|
||||
Screen.bottomBarItems.forEach { screen ->
|
||||
if (MyServerService.getToken().isBlank() || screen.route !== "login") {
|
||||
if (MyServerService.getToken().isBlank()) {
|
||||
Screen.bottomBarItems.forEach { screen ->
|
||||
NavigationBarItem(
|
||||
icon = { Icon(screen.icon, contentDescription = null) },
|
||||
label = { Text(stringResource(screen.resourceId)) },
|
||||
selected = currentDestination?.hierarchy?.any { it.route == screen.route } == true,
|
||||
onClick = {
|
||||
navController.navigate(screen.route) {
|
||||
popUpTo(navController.graph.findStartDestination().id) {
|
||||
saveState = false
|
||||
}
|
||||
launchSingleTop = true
|
||||
restoreState = false
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
else {
|
||||
Screen.adminBottomBarItems.forEach { screen ->
|
||||
NavigationBarItem(
|
||||
icon = { Icon(screen.icon, contentDescription = null) },
|
||||
label = { Text(stringResource(screen.resourceId)) },
|
||||
@ -113,7 +134,12 @@ fun Navhost(
|
||||
) {
|
||||
composable(Screen.Schedule.route) { EventList(navController) }
|
||||
composable(Screen.Repertoire.route) {
|
||||
PerformanceList(navController)
|
||||
if (MyServerService.getToken().isNotBlank()) {
|
||||
AdminPerformanceList(navController)
|
||||
}
|
||||
else {
|
||||
PerformanceList(navController)
|
||||
}
|
||||
}
|
||||
composable(Screen.PeopleList.route) { PeopleList() }
|
||||
composable(Screen.About.route) { About() }
|
||||
@ -124,7 +150,12 @@ fun Navhost(
|
||||
Screen.PerformanceView.route,
|
||||
arguments = listOf(navArgument("id") { type = NavType.IntType })
|
||||
) { backStackEntry ->
|
||||
backStackEntry.arguments?.let { PerformanceView() }
|
||||
if (MyServerService.getToken().isNotBlank()) {
|
||||
AdminPerformanceView(navController)
|
||||
}
|
||||
else {
|
||||
backStackEntry.arguments?.let { PerformanceView() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -38,16 +38,16 @@ enum class Screen(
|
||||
);
|
||||
|
||||
companion object {
|
||||
val bottomBarItems = if (MyServerService.getToken().isBlank()) listOf(
|
||||
val bottomBarItems = listOf(
|
||||
Schedule,
|
||||
Repertoire,
|
||||
PeopleList,
|
||||
About,
|
||||
Login
|
||||
) else listOf(
|
||||
Schedule,
|
||||
)
|
||||
|
||||
val adminBottomBarItems = listOf(
|
||||
Repertoire,
|
||||
PeopleList,
|
||||
About,
|
||||
)
|
||||
|
||||
|
@ -0,0 +1,261 @@
|
||||
package com.example.mobile_labs.ui.performance.list
|
||||
|
||||
import android.content.res.Configuration
|
||||
import android.util.Log
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.core.spring
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material.icons.filled.Delete
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.DismissDirection
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.DismissState
|
||||
import androidx.compose.material3.DismissValue
|
||||
import androidx.compose.material3.FloatingActionButton
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.SwipeToDismiss
|
||||
import androidx.compose.material3.rememberDismissState
|
||||
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
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
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.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.zIndex
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
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 com.example.mobile_labs.R
|
||||
import com.example.mobile_labs.api.MyServerService
|
||||
import com.example.mobile_labs.database.performance.model.Performance
|
||||
import com.example.mobile_labs.common.AppViewModelProvider
|
||||
import com.example.mobile_labs.ui.navigation.Screen
|
||||
import com.example.mobile_labs.ui.theme.Mobile_LabsTheme
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
fun AdminPerformanceList(
|
||||
navController: NavController,
|
||||
viewModel: AdminPerformanceListViewModel = viewModel(factory = AppViewModelProvider.Factory)
|
||||
) {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val performanceListUiState = viewModel.performanceListUiState.collectAsLazyPagingItems()
|
||||
Scaffold(
|
||||
topBar = {},
|
||||
floatingActionButton = {
|
||||
FloatingActionButton(
|
||||
onClick = {
|
||||
val route = Screen.PerformanceView.route.replace("{id}", 0.toString())
|
||||
navController.navigate(route)
|
||||
},
|
||||
) {
|
||||
Icon(Icons.Filled.Add, "Добавить")
|
||||
}
|
||||
}
|
||||
) { innerPadding ->
|
||||
PerformanceList(
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
performanceList = performanceListUiState,
|
||||
onClick = { uid: Int ->
|
||||
val route = Screen.PerformanceView.route.replace("{id}", uid.toString())
|
||||
navController.navigate(route)
|
||||
},
|
||||
onSwipe = { performance: Performance ->
|
||||
coroutineScope.launch {
|
||||
viewModel.deleteStudent(performance)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun DismissBackground(dismissState: DismissState) {
|
||||
val color = when (dismissState.dismissDirection) {
|
||||
DismissDirection.StartToEnd -> Color.Transparent
|
||||
DismissDirection.EndToStart -> Color(0xFFFF1744)
|
||||
null -> Color.Transparent
|
||||
}
|
||||
val direction = dismissState.dismissDirection
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(color)
|
||||
.padding(12.dp, 8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.End
|
||||
) {
|
||||
if (direction == DismissDirection.EndToStart) {
|
||||
Icon(
|
||||
Icons.Default.Delete,
|
||||
contentDescription = "delete",
|
||||
tint = Color.White
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun SwipeToDelete(
|
||||
dismissState: DismissState,
|
||||
performance: Performance,
|
||||
onClick: (uid: Int) -> Unit
|
||||
) {
|
||||
SwipeToDismiss(
|
||||
modifier = Modifier.zIndex(1f),
|
||||
state = dismissState,
|
||||
directions = setOf(
|
||||
DismissDirection.EndToStart
|
||||
),
|
||||
background = {
|
||||
DismissBackground(dismissState)
|
||||
},
|
||||
dismissContent = {
|
||||
PerformanceListItem(performance = performance,
|
||||
modifier = Modifier
|
||||
.padding(vertical = 7.dp)
|
||||
.clickable { onClick(performance.performance_uid!!) })
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun PerformanceList(
|
||||
modifier: Modifier = Modifier,
|
||||
performanceList: LazyPagingItems<Performance>,
|
||||
onClick: (uid: Int) -> Unit,
|
||||
onSwipe: (performance: Performance) -> Unit
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
) {
|
||||
if (performanceList.itemCount == 0) {
|
||||
Text(
|
||||
text = stringResource(R.string.performance_missing_description),
|
||||
textAlign = TextAlign.Center,
|
||||
style = MaterialTheme.typography.titleLarge
|
||||
)
|
||||
} else {
|
||||
LazyColumn(modifier = Modifier.padding(all = 10.dp)) {
|
||||
items(
|
||||
count = performanceList.itemCount,
|
||||
key = performanceList.itemKey(),
|
||||
contentType = performanceList.itemContentType()
|
||||
) { index ->
|
||||
val performance = performanceList[index]
|
||||
performance?.let {
|
||||
var show by remember { mutableStateOf(true) }
|
||||
val dismissState = rememberDismissState(
|
||||
confirmValueChange = {
|
||||
if (it == DismissValue.DismissedToStart ||
|
||||
it == DismissValue.DismissedToEnd
|
||||
) {
|
||||
show = false
|
||||
true
|
||||
} else false
|
||||
}, positionalThreshold = { 200.dp.toPx() }
|
||||
)
|
||||
|
||||
AnimatedVisibility(
|
||||
show, exit = fadeOut(spring())
|
||||
) {
|
||||
SwipeToDelete(
|
||||
dismissState = dismissState,
|
||||
performance = performance,
|
||||
onClick = onClick
|
||||
)
|
||||
}
|
||||
|
||||
LaunchedEffect(show) {
|
||||
if (!show) {
|
||||
delay(800)
|
||||
onSwipe(performance)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun PerformanceListItem(
|
||||
performance: Performance,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Card(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
elevation = CardDefaults.cardElevation(defaultElevation = 2.dp)
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier.padding(all = 10.dp)
|
||||
) {
|
||||
AsyncImage(model = performance.imageURL, contentDescription = "")
|
||||
Button(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(all = 10.dp),
|
||||
onClick = { }) {
|
||||
Text(performance.title)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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 AdminSchedulePreview() {
|
||||
Mobile_LabsTheme {
|
||||
Surface(
|
||||
color = MaterialTheme.colorScheme.background
|
||||
) {
|
||||
PerformanceList(
|
||||
performanceList = MutableStateFlow(
|
||||
PagingData.empty<Performance>()
|
||||
).collectAsLazyPagingItems(),
|
||||
onClick = {},
|
||||
onSwipe = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.example.mobile_labs.ui.performance.list
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.paging.PagingData
|
||||
import com.example.mobile_labs.common.PerformanceRepository
|
||||
import com.example.mobile_labs.database.performance.model.Performance
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
class AdminPerformanceListViewModel(
|
||||
private val performanceRepository: PerformanceRepository
|
||||
) : ViewModel() {
|
||||
val performanceListUiState: Flow<PagingData<Performance>> = performanceRepository.getAllPerformances()
|
||||
|
||||
suspend fun deleteStudent(performance: Performance) {
|
||||
performanceRepository.deletePerformance(performance)
|
||||
}
|
||||
}
|
@ -0,0 +1,129 @@
|
||||
package com.example.mobile_labs.ui.performance.view
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import coil.compose.AsyncImage
|
||||
import com.example.mobile_labs.R
|
||||
import com.example.mobile_labs.common.AppViewModelProvider
|
||||
import com.example.mobile_labs.ui.theme.Mobile_LabsTheme
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun AdminPerformanceView(
|
||||
navController: NavController,
|
||||
viewModel: AdminPerformanceViewModel = viewModel(factory = AppViewModelProvider.Factory)
|
||||
) {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
PerformanceEdit(
|
||||
performanceUiState = viewModel.performanceUiState,
|
||||
onClick = {
|
||||
coroutineScope.launch {
|
||||
viewModel.savePerformance()
|
||||
navController.popBackStack()
|
||||
}
|
||||
},
|
||||
onUpdate = viewModel::updateUiState,
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun PerformanceEdit(
|
||||
performanceUiState: AdminPerformanceUiState,
|
||||
onClick: () -> Unit,
|
||||
onUpdate: (AdminPerformanceDetails) -> Unit,
|
||||
) {
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(all = 10.dp)
|
||||
) {
|
||||
OutlinedTextField(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
value = performanceUiState.performanceDetails.title,
|
||||
onValueChange = { onUpdate(performanceUiState.performanceDetails.copy(title = it)) },
|
||||
label = {Text("Название")},
|
||||
singleLine = true
|
||||
)
|
||||
OutlinedTextField(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
value = performanceUiState.performanceDetails.description,
|
||||
onValueChange = { onUpdate(performanceUiState.performanceDetails.copy(description = it)) },
|
||||
label = {Text("Описание")},
|
||||
singleLine = true
|
||||
)
|
||||
OutlinedTextField(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
value = performanceUiState.performanceDetails.imageURL,
|
||||
onValueChange = { onUpdate(performanceUiState.performanceDetails.copy(imageURL = it)) },
|
||||
label = { Text("URL изображения") },
|
||||
singleLine = true,
|
||||
)
|
||||
OutlinedTextField(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
value = performanceUiState.performanceDetails.previewImageUrl,
|
||||
onValueChange = { onUpdate(performanceUiState.performanceDetails.copy(previewImageUrl = it)) },
|
||||
label = {Text("URL превью")},
|
||||
singleLine = true
|
||||
)
|
||||
OutlinedTextField(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
value = performanceUiState.performanceDetails.authorId.toString(),
|
||||
onValueChange = { onUpdate(performanceUiState.performanceDetails.copy(authorId = it.toInt())) },
|
||||
label = {Text("Автор")},
|
||||
singleLine = true,
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Phone)
|
||||
)
|
||||
OutlinedTextField(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
value = performanceUiState.performanceDetails.directorId.toString(),
|
||||
onValueChange = { onUpdate(performanceUiState.performanceDetails.copy(directorId = it.toInt())) },
|
||||
label = {Text("Режиссер")},
|
||||
singleLine = true,
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Phone)
|
||||
)
|
||||
Button(
|
||||
onClick = onClick,
|
||||
enabled = performanceUiState.isEntryValid,
|
||||
shape = MaterialTheme.shapes.small,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text(text = "Сохранить")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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 AdminPerformanceViewPreview() {
|
||||
Mobile_LabsTheme {
|
||||
Surface(
|
||||
color = MaterialTheme.colorScheme.background
|
||||
) {
|
||||
PerformanceView()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
package com.example.mobile_labs.ui.performance.view
|
||||
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.example.mobile_labs.database.performance.model.PerformanceWithPeople
|
||||
import com.example.mobile_labs.common.PerformanceRepository
|
||||
import com.example.mobile_labs.database.performance.model.Performance
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class AdminPerformanceViewModel(
|
||||
savedStateHandle: SavedStateHandle,
|
||||
private val performanceRepository: PerformanceRepository
|
||||
) : ViewModel() {
|
||||
|
||||
var performanceUiState by mutableStateOf(AdminPerformanceUiState())
|
||||
private set
|
||||
|
||||
private val performanceUid: Int = checkNotNull(savedStateHandle["id"])
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
if (performanceUid > 0) {
|
||||
performanceUiState = performanceRepository.getPerformance(performanceUid)
|
||||
.toUiStateAdmin()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun updateUiState(performanceDetails: AdminPerformanceDetails) {
|
||||
performanceUiState = AdminPerformanceUiState(
|
||||
performanceDetails = performanceDetails,
|
||||
isEntryValid = validateInput(performanceDetails)
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun savePerformance() {
|
||||
if (validateInput()) {
|
||||
if (performanceUid > 0) {
|
||||
performanceRepository.updatePerformance(
|
||||
performanceUiState.performanceDetails.toPerformance(performanceUid)
|
||||
)
|
||||
} else {
|
||||
performanceRepository.insertPerformance(
|
||||
performanceUiState.performanceDetails.toPerformance()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun validateInput(uiState: AdminPerformanceDetails = performanceUiState.performanceDetails): Boolean {
|
||||
return with(uiState) {
|
||||
title.isNotBlank()
|
||||
&& description.isNotBlank()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class AdminPerformanceUiState(
|
||||
val performanceDetails: AdminPerformanceDetails = AdminPerformanceDetails(),
|
||||
val isEntryValid: Boolean = false
|
||||
)
|
||||
|
||||
data class AdminPerformanceDetails(
|
||||
val title: String = "",
|
||||
val authorName: String = "",
|
||||
val actorsList: String = "",
|
||||
val imageURL: String = "",
|
||||
val description: String = "",
|
||||
val authorId: Int = 0,
|
||||
val directorId: Int = 0,
|
||||
val previewImageUrl: String = "",
|
||||
)
|
||||
|
||||
fun PerformanceWithPeople.toAdminDetails(): AdminPerformanceDetails = AdminPerformanceDetails(
|
||||
title = performance.title,
|
||||
authorName = String.format("%s %s", author.last_name, author.first_name),
|
||||
actorsList = buildString { for (actor in actors) append(actor.last_name + " " + actor.first_name + "\n") },
|
||||
imageURL = performance.imageURL,
|
||||
description = performance.description,
|
||||
authorId = performance.authorId!!,
|
||||
directorId = performance.directorId!!,
|
||||
previewImageUrl = performance.previewImageURL,
|
||||
)
|
||||
|
||||
fun PerformanceWithPeople.toUiStateAdmin(): AdminPerformanceUiState = AdminPerformanceUiState(
|
||||
performanceDetails = this.toAdminDetails(),
|
||||
)
|
||||
|
||||
fun AdminPerformanceDetails.toPerformance(uid: Int = 0): Performance = Performance(
|
||||
performance_uid = uid,
|
||||
title = title,
|
||||
authorId = authorId,
|
||||
directorId = directorId,
|
||||
imageURL = imageURL,
|
||||
description = description,
|
||||
previewImageURL = previewImageUrl
|
||||
)
|
Loading…
Reference in New Issue
Block a user