This commit is contained in:
Stranni15k 2024-01-08 22:05:09 +04:00
parent c5b54562d3
commit 7ed6a7e9b9
9 changed files with 157 additions and 33 deletions

BIN
.vs/Lection5/v17/.wsuo Normal file

Binary file not shown.

3
.vs/ProjectSettings.json Normal file
View File

@ -0,0 +1,3 @@
{
"CurrentProjectSetting": null
}

View File

@ -0,0 +1,6 @@
{
"ExpandedNodes": [
""
],
"PreviewInSolutionExplorer": false
}

BIN
.vs/slnx.sqlite Normal file

Binary file not shown.

View File

@ -67,6 +67,7 @@ dependencies {
implementation("androidx.compose.ui:ui-tooling-preview")
implementation("androidx.compose.material3:material3:1.1.2")
implementation("com.google.firebase:protolite-well-known-types:18.0.0")
implementation("com.google.android.material:material:1.10.0")
// Room
val room_version = "2.5.2"

View File

@ -1,14 +1,25 @@
package ru.ulstu.`is`.pmu.ui.task.edit
import android.content.res.Configuration
import android.view.ContextThemeWrapper
import android.widget.CalendarView
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.DatePickerDefaults
import androidx.compose.material3.DatePickerFormatter
import androidx.compose.material3.DatePickerState
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
@ -18,6 +29,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
@ -25,14 +37,19 @@ 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.input.KeyboardType
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController
import com.google.android.material.datepicker.MaterialDatePicker
import java.util.Date
import kotlinx.coroutines.launch
import ru.ulstu.`is`.pmu.R
@ -40,6 +57,11 @@ import ru.ulstu.`is`.pmu.database.task.model.User
import ru.ulstu.`is`.pmu.database.task.model.Task
import ru.ulstu.`is`.pmu.ui.AppViewModelProvider
import ru.ulstu.`is`.pmu.ui.theme.PmudemoTheme
import java.text.SimpleDateFormat
import java.time.LocalDate
import java.time.format.DateTimeFormatter
import java.util.Calendar
import java.util.Locale
@Composable
fun TaskEdit(
@ -113,7 +135,6 @@ private fun UserDropDown(
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun TaskEdit(
@ -144,13 +165,33 @@ private fun TaskEdit(
label = { Text(stringResource(id = R.string.task_lastname)) },
singleLine = true
)
var showDatePicker by remember { mutableStateOf(false) }
if (showDatePicker) {
DatePicker(
onDateSelected = { selectedDate ->
onUpdate(taskUiState.taskDetails.copy(endDate = SimpleDateFormat("dd.MM.yyyy").format(selectedDate)))
showDatePicker = false
},
onDismissRequest = {
showDatePicker = false
}
)
}
Button(
onClick = { showDatePicker = true },
modifier = Modifier.fillMaxWidth()
) {
Text("Выбрать дату окончания")
}
OutlinedTextField(
modifier = Modifier.fillMaxWidth(),
value = taskUiState.taskDetails.endDate,
onValueChange = { newDate -> onUpdate(taskUiState.taskDetails.copy(endDate = newDate)) },
label = { Text(stringResource(id = R.string.task_endDate)) },
singleLine = true,
keyboardOptions = KeyboardOptions.Default.copy(keyboardType = KeyboardType.Number)
keyboardOptions = KeyboardOptions.Default.copy(keyboardType = KeyboardType.Number),
enabled = false
)
// UserDropDown(
// userUiState = userUiState,
@ -169,7 +210,6 @@ private fun TaskEdit(
}
},
enabled = taskUiState.isEntryValid,
shape = MaterialTheme.shapes.small,
modifier = Modifier.fillMaxWidth()
) {
Text(text = stringResource(R.string.task_save_button))
@ -183,7 +223,7 @@ private fun TaskEdit(
text = { Text("Введите дату по шаблону: 01.12.2023") },
confirmButton = {
Button(onClick = { showInvalidDateDialog = false }) {
Text("ОК")
Text("Подтвердить")
}
}
)
@ -195,22 +235,99 @@ fun isValidDate(date: String): Boolean {
return regex.matches(date)
}
@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 TaskEditPreview() {
PmudemoTheme {
Surface(
color = MaterialTheme.colorScheme.background
) {
TaskEdit(
taskUiState = Task.getTask().toUiState(true),
userUiState = User.DEMO_User.toUiState(),
usersListUiState = UsersListUiState(listOf()),
onClick = {},
onUpdate = {},
onUserUpdate = {}
fun CustomCalendarView(onDateSelected: (Date) -> Unit) {
AndroidView(
modifier = Modifier.wrapContentSize(),
factory = { context ->
// Используем стандартный контекст, без применения кастомной темы
CalendarView(context).apply {
// Настройки CalendarView
val calendar = Calendar.getInstance()
setOnDateChangeListener { _, year, month, dayOfMonth ->
calendar.set(Calendar.YEAR, year)
calendar.set(Calendar.MONTH, month)
calendar.set(Calendar.DAY_OF_MONTH, dayOfMonth)
onDateSelected(calendar.time)
}
}
}
)
}
@Composable
fun DatePicker(onDateSelected: (Date) -> Unit, onDismissRequest: () -> Unit) {
val selDate = remember { mutableStateOf(Date()) }
//todo - add strings to resource after POC
Dialog(onDismissRequest = { onDismissRequest() }, properties = DialogProperties()) {
Column(
modifier = Modifier
.wrapContentSize()
.background(
color = Color.White
)
) {
Column(
Modifier
.defaultMinSize(minHeight = 72.dp)
.fillMaxWidth()
.background(
color = MaterialTheme.colorScheme.primary
)
.padding(16.dp)
) {
Text(
text = "Выберите дату"
)
Spacer(modifier = Modifier.size(24.dp))
Text(
text = SimpleDateFormat("MMM d, yyyy", Locale.getDefault()).format(selDate.value)
)
Spacer(modifier = Modifier.size(16.dp))
}
CustomCalendarView(onDateSelected = {
selDate.value = it
})
Spacer(modifier = Modifier.size(8.dp))
Row(
modifier = Modifier
.align(Alignment.End)
.padding(bottom = 16.dp, end = 16.dp)
.background(
color = Color.White,
shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp)
)
) {
TextButton(
onClick = onDismissRequest
) {
//TODO - hardcode string
Text(
text = "Отмена"
)
}
TextButton(
onClick = {
onDateSelected(selDate.value)
onDismissRequest()
}
) {
//TODO - hardcode string
Text(
text = "Подтвердить"
)
}
}
}
}
}

View File

@ -73,7 +73,7 @@ fun TaskList(
}
}
) { innerPadding ->
TaskListContent( // Изменил имя, чтобы избежать путаницы с функцией TaskList
TaskListContent(
modifier = Modifier
.padding(innerPadding)
.fillMaxSize(),
@ -82,12 +82,12 @@ fun TaskList(
val route = Screen.TaskEdit.route.replace("{id}", uid.toString())
navController.navigate(route)
},
onSwipeLeft = { task: Task -> // Обработка свайпа влево (удаление)
onSwipeLeft = { task: Task ->
coroutineScope.launch {
viewModel.deleteTask(task)
}
},
onSwipeRight = { task: Task -> // Обработка свайпа вправо (добавить в избранное)
onSwipeRight = { task: Task ->
coroutineScope.launch {
viewModel.favoriteTask(task)
}
@ -102,20 +102,20 @@ private fun SwipeToAction(
dismissState: DismissState,
task: Task,
onClick: (uid: Int) -> Unit,
onSwipeRight: (task: Task) -> Unit, // Для добавления в избранное
onSwipeLeft: (task: Task) -> Unit // Для удаления
onSwipeRight: (task: Task) -> Unit,
onSwipeLeft: (task: Task) -> Unit
) {
SwipeToDismiss(
state = dismissState,
directions = setOf(
DismissDirection.EndToStart, // Для удаления
DismissDirection.StartToEnd // Для добавления в избранное
DismissDirection.EndToStart,
DismissDirection.StartToEnd
),
background = {
val backgroundColor by animateColorAsState(
when (dismissState.targetValue) {
DismissedToStart -> Color.Red.copy(alpha = 0.8f)
DismissValue.DismissedToEnd -> Color.Green.copy(alpha = 0.8f) // Цвет фона для избранного
DismissValue.DismissedToEnd -> Color.Green.copy(alpha = 0.8f)
else -> Color.White
}, label = ""
)
@ -132,7 +132,7 @@ private fun SwipeToAction(
) {
Icon(
modifier = Modifier.scale(iconScale),
imageVector = if (dismissState.targetValue == DismissedToStart) Icons.Outlined.Delete else Icons.Default.Star, // Иконка для избранного
imageVector = if (dismissState.targetValue == DismissedToStart) Icons.Outlined.Delete else Icons.Default.Star,
contentDescription = if (dismissState.targetValue == DismissedToStart) "Delete" else "Favorite",
tint = Color.White
)
@ -160,7 +160,6 @@ private fun TaskListContent(
modifier = modifier
) {
if (taskList.isEmpty()) {
// Код для отображения пустого списка
} else {
LazyColumn(modifier = Modifier.padding(all = 10.dp)) {
items(items = taskList, key = { it.uid }) { task ->
@ -169,14 +168,14 @@ private fun TaskListContent(
if (dismissState.isDismissed(DismissDirection.EndToStart)) {
LaunchedEffect(task) {
onSwipeLeft(task)
dismissState.reset() // Сбросить состояние после обработки свайпа
dismissState.reset()
}
}
if (dismissState.isDismissed(DismissDirection.StartToEnd)) {
LaunchedEffect(task) {
onSwipeRight(task)
dismissState.reset() // Сбросить состояние после обработки свайпа
dismissState.reset()
}
}

View File

@ -17,7 +17,7 @@ class TaskListViewModel(
val taskListFavoriteUiState: StateFlow<TaskListUiState> = taskRepository.getAllTasks()
.map { tasks ->
val filteredTasks = tasks.filter { task ->
task.favorite // Оставить только задачи, у которых favorite = true
task.favorite
}
val sortedTasks = filteredTasks.sortedByDescending { task ->
parseDate(task.endDate)?.timeInMillis ?: Long.MIN_VALUE
@ -26,7 +26,6 @@ class TaskListViewModel(
}
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(AppDataContainer.TIMEOUT), TaskListUiState())
// Для TaskListEndDate (Сортировка по endDate)
val taskListEndDateUiState: StateFlow<TaskListUiState> = taskRepository.getAllTasks()
.map { tasks ->
val sortedTasks = tasks.sortedByDescending { task ->
@ -36,7 +35,6 @@ class TaskListViewModel(
}
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(AppDataContainer.TIMEOUT), TaskListUiState())
// Для TaskList (Сортировка по uid)
val taskListUiState: StateFlow<TaskListUiState> = taskRepository.getAllTasks()
.map { tasks ->
val sortedTasks = tasks.sortedBy { task ->