Compare commits
3 Commits
6b3fc223c1
...
2eca8db087
Author | SHA1 | Date | |
---|---|---|---|
|
2eca8db087 | ||
|
a687ff002f | ||
|
d79f6982fe |
@ -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"
|
||||
@ -94,4 +95,7 @@ dependencies {
|
||||
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
|
||||
debugImplementation("androidx.compose.ui:ui-tooling")
|
||||
debugImplementation("androidx.compose.ui:ui-test-manifest")
|
||||
|
||||
implementation("javax.inject:javax.inject:1")
|
||||
implementation("androidx.compose.runtime:runtime-livedata")
|
||||
}
|
@ -1,8 +1,11 @@
|
||||
package com.example.mobile_labs.api
|
||||
|
||||
import android.util.Log
|
||||
import com.example.mobile_labs.api.models.Credentials
|
||||
import com.example.mobile_labs.api.models.EventRemote
|
||||
import com.example.mobile_labs.api.models.PerformanceRemote
|
||||
import com.example.mobile_labs.api.models.PersonRemote
|
||||
import com.example.mobile_labs.api.models.Token
|
||||
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
|
||||
import kotlinx.serialization.json.Json
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
@ -16,53 +19,96 @@ import retrofit2.http.POST
|
||||
import retrofit2.http.PUT
|
||||
import retrofit2.http.Path
|
||||
import retrofit2.http.Query
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
interface MyServerService {
|
||||
@GET("persons")
|
||||
@GET("api/persons")
|
||||
suspend fun getPeople(
|
||||
@Query("_page") page: Int,
|
||||
@Query("_limit") limit: Int,
|
||||
): List<PersonRemote>
|
||||
|
||||
@GET("performances")
|
||||
@GET("api/performances")
|
||||
suspend fun getPerformances(
|
||||
@Query("_page") page: Int,
|
||||
@Query("_limit") limit: Int,
|
||||
): List<PerformanceRemote>
|
||||
|
||||
@GET("events")
|
||||
@GET("api/events")
|
||||
suspend fun getEvents(
|
||||
@Query("_page") page: Int,
|
||||
@Query("_limit") limit: Int,
|
||||
): List<EventRemote>
|
||||
|
||||
@GET("performances/{id}")
|
||||
@GET("api/performances/{id}")
|
||||
suspend fun getPerformance(
|
||||
@Path("id") id: Int,
|
||||
): PerformanceRemote
|
||||
|
||||
@GET("persons/{id}")
|
||||
@GET("api/persons/{id}")
|
||||
suspend fun getPerson(
|
||||
@Path("id") id: Int,
|
||||
): PersonRemote
|
||||
|
||||
@GET("events/{id}")
|
||||
@GET("api/events/{id}")
|
||||
suspend fun getEvent(
|
||||
@Path("id") id: Int,
|
||||
): EventRemote
|
||||
|
||||
@POST("api/login")
|
||||
suspend fun login(
|
||||
@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:26000/"
|
||||
private const val BASE_URL = "http://10.0.2.2:8000/"
|
||||
|
||||
@Volatile
|
||||
private var INSTANCE: MyServerService? = null
|
||||
|
||||
private var _token: String = ""
|
||||
|
||||
fun getInstance(): MyServerService {
|
||||
return INSTANCE ?: synchronized(this) {
|
||||
val logger = HttpLoggingInterceptor()
|
||||
logger.level = HttpLoggingInterceptor.Level.BASIC
|
||||
val client = OkHttpClient.Builder()
|
||||
.connectTimeout(1, TimeUnit.DAYS)
|
||||
.readTimeout(1, TimeUnit.DAYS)
|
||||
.writeTimeout(1, TimeUnit.DAYS)
|
||||
.retryOnConnectionFailure(false)
|
||||
.callTimeout(1, TimeUnit.DAYS)
|
||||
.addInterceptor(logger)
|
||||
.addInterceptor {
|
||||
val originalRequest = it.request()
|
||||
if (_token.isEmpty()) {
|
||||
it.proceed(originalRequest)
|
||||
} else {
|
||||
it.proceed(
|
||||
originalRequest
|
||||
.newBuilder()
|
||||
.header("Authorization", "Bearer $_token")
|
||||
.method(originalRequest.method, originalRequest.body)
|
||||
.build()
|
||||
)
|
||||
}
|
||||
}
|
||||
.build()
|
||||
return Retrofit.Builder()
|
||||
.baseUrl(BASE_URL)
|
||||
@ -73,5 +119,13 @@ interface MyServerService {
|
||||
.also { INSTANCE = it }
|
||||
}
|
||||
}
|
||||
|
||||
fun getToken(): String {
|
||||
return _token
|
||||
}
|
||||
|
||||
fun setToken(token: String) {
|
||||
_token = token
|
||||
}
|
||||
}
|
||||
}
|
@ -73,6 +73,9 @@ class EventRemoteMediator(
|
||||
nextKey = nextKey
|
||||
)
|
||||
}
|
||||
dbRemoteKeyRepository.deleteRemoteKey(RemoteKeyType.EVENT)
|
||||
dbEventRepository.clearEvents()
|
||||
|
||||
performanceRestRepository.getAllPerformances()
|
||||
dbRemoteKeyRepository.createRemoteKeys(keys)
|
||||
dbEventRepository.insertEvents(events)
|
||||
|
@ -0,0 +1,9 @@
|
||||
package com.example.mobile_labs.api.models
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class Credentials(
|
||||
val email: String = "",
|
||||
val password: String = "",
|
||||
)
|
@ -10,16 +10,16 @@ import java.time.LocalDate
|
||||
data class EventRemote(
|
||||
val id: Int = 0,
|
||||
val date: String = "",
|
||||
val performanceId: Int = 0,
|
||||
val performance_id: Int = 0,
|
||||
)
|
||||
|
||||
fun EventRemote.toEvent(): Event = Event(
|
||||
id,
|
||||
LocalDate.parse(date),
|
||||
performanceId
|
||||
performance_id
|
||||
)
|
||||
|
||||
suspend fun EventRemote.toEventWithPerformance(service: MyServerService): EventWithPerformance = EventWithPerformance(
|
||||
service.getEvent(id).toEvent(),
|
||||
service.getPerformance(performanceId).toPerformance()
|
||||
service.getPerformance(performance_id).toPerformance()
|
||||
)
|
@ -11,10 +11,10 @@ data class PerformanceRemote(
|
||||
val id: Int = 0,
|
||||
val title: String = "",
|
||||
val description: String = "",
|
||||
val authorId: Int = 0,
|
||||
val directorId: Int = 0,
|
||||
val imageURL: String = "",
|
||||
val previewImageURL: String = "",
|
||||
val author_id: Int = 0,
|
||||
val director_id: Int = 0,
|
||||
val image_url: String = "",
|
||||
val preview_image_url: String = "",
|
||||
val actors: List<Int> = listOf()
|
||||
)
|
||||
|
||||
@ -22,10 +22,10 @@ fun PerformanceRemote.toPerformance(): Performance = Performance(
|
||||
id,
|
||||
title,
|
||||
description,
|
||||
authorId,
|
||||
directorId,
|
||||
imageURL,
|
||||
previewImageURL
|
||||
author_id,
|
||||
director_id,
|
||||
image_url,
|
||||
preview_image_url
|
||||
)
|
||||
|
||||
suspend fun PerformanceRemote.toPerformanceWithPeople(service: MyServerService): PerformanceWithPeople {
|
||||
@ -36,8 +36,18 @@ suspend fun PerformanceRemote.toPerformanceWithPeople(service: MyServerService):
|
||||
|
||||
return PerformanceWithPeople(
|
||||
service.getPerformance(id).toPerformance(),
|
||||
service.getPerson(authorId).toPerson(),
|
||||
service.getPerson(directorId).toPerson(),
|
||||
service.getPerson(author_id).toPerson(),
|
||||
service.getPerson(director_id).toPerson(),
|
||||
actorsList.toList()
|
||||
)
|
||||
}
|
||||
|
||||
fun Performance.toPerformanceRemote(): PerformanceRemote = PerformanceRemote(
|
||||
performance_uid!!,
|
||||
title,
|
||||
description,
|
||||
authorId!!,
|
||||
directorId!!,
|
||||
imageURL,
|
||||
previewImageURL
|
||||
)
|
@ -10,12 +10,12 @@ data class PersonRemote(
|
||||
val id: Int = 0,
|
||||
val last_name: String = "",
|
||||
val first_name: String = "",
|
||||
val imageURL: String = ""
|
||||
val image_url: String = ""
|
||||
)
|
||||
|
||||
fun PersonRemote.toPerson(): Person = Person(
|
||||
id,
|
||||
last_name,
|
||||
first_name,
|
||||
imageURL
|
||||
image_url
|
||||
)
|
@ -0,0 +1,8 @@
|
||||
package com.example.mobile_labs.api.models
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class Token(
|
||||
val token: String
|
||||
)
|
@ -71,6 +71,9 @@ class PeopleRemoteMediator(
|
||||
nextKey = nextKey
|
||||
)
|
||||
}
|
||||
|
||||
dbRemoteKeyRepository.deleteRemoteKey(RemoteKeyType.PERSON)
|
||||
dbPersonRepository.clearPeople()
|
||||
dbRemoteKeyRepository.createRemoteKeys(keys)
|
||||
dbPersonRepository.insertPeople(people)
|
||||
}
|
||||
|
@ -1,9 +1,11 @@
|
||||
package com.example.mobile_labs.api.performance
|
||||
|
||||
import android.util.Log
|
||||
import androidx.paging.ExperimentalPagingApi
|
||||
import androidx.paging.LoadType
|
||||
import androidx.paging.PagingState
|
||||
import androidx.paging.RemoteMediator
|
||||
import androidx.paging.log
|
||||
import androidx.room.withTransaction
|
||||
import com.example.mobile_labs.api.MyServerService
|
||||
import com.example.mobile_labs.api.models.toPerformance
|
||||
@ -73,6 +75,9 @@ class PerformanceRemoteMediator(
|
||||
nextKey = nextKey
|
||||
)
|
||||
}
|
||||
dbRemoteKeyRepository.deleteRemoteKey(RemoteKeyType.PERFORMANCE)
|
||||
dbPerformanceRepository.clearPerformances()
|
||||
|
||||
personRestRepository.getAllPeople()
|
||||
dbRemoteKeyRepository.createRemoteKeys(keys)
|
||||
dbPerformanceRepository.insertPerformances(performances)
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -7,7 +7,10 @@ import androidx.lifecycle.viewmodel.initializer
|
||||
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
|
||||
|
||||
@ -25,6 +28,15 @@ object AppViewModelProvider {
|
||||
initializer {
|
||||
PerformanceViewModel(this.createSavedStateHandle(), theatreApplication().container.performanceRestRepository)
|
||||
}
|
||||
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()
|
||||
|
||||
|
116
app/src/main/java/com/example/mobile_labs/ui/login/Login.kt
Normal file
116
app/src/main/java/com/example/mobile_labs/ui/login/Login.kt
Normal file
@ -0,0 +1,116 @@
|
||||
package com.example.mobile_labs.ui.login
|
||||
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.ui.*
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import androidx.compose.ui.unit.*
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavHostController
|
||||
import com.example.mobile_labs.R
|
||||
import com.example.mobile_labs.common.AppViewModelProvider
|
||||
import com.example.mobile_labs.ui.navigation.Screen
|
||||
|
||||
@Composable
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
fun Login(
|
||||
navController: NavHostController,
|
||||
viewModel: LoginViewModel = viewModel(factory = AppViewModelProvider.Factory)
|
||||
) {
|
||||
val success = viewModel.successState.observeAsState().value
|
||||
|
||||
val login = remember { mutableStateOf(TextFieldValue(""))}
|
||||
val password = remember { mutableStateOf(TextFieldValue(""))}
|
||||
|
||||
if (success == false) {
|
||||
AlertDialog(
|
||||
title = {
|
||||
Text(
|
||||
text = "Ошибка авторизации",
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 20.sp
|
||||
)
|
||||
},
|
||||
text = {
|
||||
Text(
|
||||
text = "Неверный логин или пароль",
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 16.sp
|
||||
)
|
||||
},
|
||||
onDismissRequest = {
|
||||
viewModel.calmSuccessState()
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
viewModel.calmSuccessState()
|
||||
}
|
||||
) {
|
||||
Text("OK")
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier.fillMaxWidth(0.7f).fillMaxHeight().padding(vertical=100.dp)
|
||||
) {
|
||||
Text(
|
||||
text = "Вход",
|
||||
style = TextStyle(
|
||||
fontSize = 40.sp,
|
||||
fontWeight = FontWeight(400),
|
||||
),
|
||||
modifier = Modifier.fillMaxHeight(0.3f)
|
||||
)
|
||||
OutlinedTextField(
|
||||
modifier = Modifier.fillMaxWidth().padding(bottom=30.dp),
|
||||
value = login.value,
|
||||
onValueChange = { login.value = it },
|
||||
label = { Text(stringResource(id = R.string.login)) },
|
||||
singleLine = true
|
||||
)
|
||||
OutlinedTextField(
|
||||
modifier = Modifier.fillMaxWidth().padding(bottom=30.dp),
|
||||
value = password.value,
|
||||
onValueChange = { password.value = it },
|
||||
label = { Text(stringResource(id = R.string.password)) },
|
||||
singleLine = true
|
||||
)
|
||||
Button(
|
||||
{
|
||||
viewModel.login(login.value.text, password.value.text, navController)
|
||||
},
|
||||
modifier = Modifier.padding(bottom=20.dp).fillMaxWidth(0.5f)
|
||||
) {
|
||||
Text(
|
||||
text = "Войти",
|
||||
style = TextStyle(
|
||||
fontSize = 24.sp,
|
||||
fontWeight = FontWeight(400),
|
||||
color = Color(0xFFFFFFFF),
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package com.example.mobile_labs.ui.login
|
||||
|
||||
import android.util.Log
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.navigation.NavHostController
|
||||
import com.example.mobile_labs.api.MyServerService
|
||||
import com.example.mobile_labs.api.models.Credentials
|
||||
import com.example.mobile_labs.ui.navigation.Screen
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
class LoginViewModel : ViewModel() {
|
||||
private val _successState = MutableLiveData<Boolean?>()
|
||||
val successState: LiveData<Boolean?>
|
||||
get() = _successState
|
||||
|
||||
fun calmSuccessState() {
|
||||
_successState.postValue(null)
|
||||
}
|
||||
|
||||
fun login(login: String, password: String, navController: NavHostController) {
|
||||
viewModelScope.launch {
|
||||
val token = MyServerService.getInstance().login(Credentials(login, password))
|
||||
|
||||
if (token.token.isEmpty()) {
|
||||
_successState.postValue(false)
|
||||
return@launch
|
||||
}
|
||||
|
||||
MyServerService.setToken(token.token)
|
||||
|
||||
_successState.setValue(true)
|
||||
|
||||
navigate(navController)
|
||||
}
|
||||
}
|
||||
fun navigate(navController: NavHostController) {
|
||||
Screen.About.route.let {
|
||||
navController.navigate(it) {
|
||||
popUpTo(it) {
|
||||
inclusive = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
@ -33,9 +34,13 @@ import androidx.navigation.compose.rememberNavController
|
||||
import androidx.navigation.navArgument
|
||||
import com.example.mobile_labs.ui.theme.Mobile_LabsTheme
|
||||
import com.example.mobile_labs.R
|
||||
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
|
||||
|
||||
@ -77,21 +82,41 @@ fun Navbar(
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
NavigationBar(modifier) {
|
||||
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 = true
|
||||
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
|
||||
}
|
||||
launchSingleTop = true
|
||||
restoreState = true
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
else {
|
||||
Screen.adminBottomBarItems.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
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -108,14 +133,29 @@ fun Navhost(
|
||||
modifier.padding(innerPadding)
|
||||
) {
|
||||
composable(Screen.Schedule.route) { EventList(navController) }
|
||||
composable(Screen.Repertoire.route) { PerformanceList(navController) }
|
||||
composable(Screen.Repertoire.route) {
|
||||
if (MyServerService.getToken().isNotBlank()) {
|
||||
AdminPerformanceList(navController)
|
||||
}
|
||||
else {
|
||||
PerformanceList(navController)
|
||||
}
|
||||
}
|
||||
composable(Screen.PeopleList.route) { PeopleList() }
|
||||
composable(Screen.About.route) { About() }
|
||||
composable(Screen.About.route) { About() }
|
||||
if (MyServerService.getToken().isBlank()) {
|
||||
composable(Screen.Login.route) { Login(navController) }
|
||||
}
|
||||
composable(
|
||||
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() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,12 +3,14 @@ package com.example.mobile_labs.ui.navigation
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.DateRange
|
||||
import androidx.compose.material.icons.filled.Face
|
||||
import androidx.compose.material.icons.filled.Favorite
|
||||
import androidx.compose.material.icons.filled.Info
|
||||
import androidx.compose.material.icons.filled.List
|
||||
import androidx.compose.material.icons.filled.Person
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import com.example.mobile_labs.R
|
||||
import com.example.mobile_labs.api.MyServerService
|
||||
|
||||
enum class Screen(
|
||||
val route: String,
|
||||
@ -30,6 +32,9 @@ enum class Screen(
|
||||
),
|
||||
About(
|
||||
"about", R.string.about_main_title, Icons.Filled.Info
|
||||
),
|
||||
Login(
|
||||
"login", R.string.login_main_title, Icons.Filled.Face
|
||||
);
|
||||
|
||||
companion object {
|
||||
@ -38,6 +43,12 @@ enum class Screen(
|
||||
Repertoire,
|
||||
PeopleList,
|
||||
About,
|
||||
Login
|
||||
)
|
||||
|
||||
val adminBottomBarItems = listOf(
|
||||
Repertoire,
|
||||
About,
|
||||
)
|
||||
|
||||
fun getItem(route: String): Screen? {
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package com.example.mobile_labs.ui.performance.list
|
||||
|
||||
import android.content.res.Configuration
|
||||
import android.util.Log
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
@ -28,6 +29,7 @@ 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
|
||||
|
@ -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
|
||||
)
|
@ -6,12 +6,15 @@
|
||||
<string name="performance_author">Автор</string>
|
||||
<string name="performance_director">Режиссёр</string>
|
||||
<string name="performance_actors">Актёры</string>
|
||||
<string name="people_main_title">Люди театра</string>
|
||||
<string name="people_main_title">Труппа</string>
|
||||
<string name="about_main_title">О нас</string>
|
||||
<string name="login_main_title">Вход</string>
|
||||
<string name="performance_view_main_title">Представление</string>
|
||||
<string name="people_missing_description">Данные о людях отсутствуют</string>
|
||||
<string name="events_missing_description">Данные о событиях отсутствуют</string>
|
||||
<string name="performance_missing_description">Данные о представлениях отсутствуют</string>
|
||||
<string name="login">Логин</string>
|
||||
<string name="password">Пароль</string>
|
||||
<string name="about_text">
|
||||
<p>
|
||||
Netus quis congue nascetur ullamcorper nibh, nostra iaculis turpis! Facilisi pretium vehicula purus porttitor vitae aliquet dignissim. Donec diam molestie litora magnis dolor aptent scelerisque mus. Sit mi, venenatis interdum. Commodo vel malesuada tincidunt eget. Aenean laoreet lacinia platea sem? Libero urna odio diam? Nisl, sodales nisi gravida. Interdum elementum libero turpis dapibus tristique per sed maecenas ante integer massa? Tortor molestie sapien himenaeos condimentum. Facilisis accumsan ullamcorper semper fermentum elementum quisque. Curae;, vivamus ante hac elit fringilla odio ornare curabitur quisque magna commodo. Placerat proin!
|
||||
|
Loading…
Reference in New Issue
Block a user