Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package com.example.tudee.presentation.components

import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
Expand Down Expand Up @@ -39,16 +38,15 @@ fun CategoryTaskComponent(
priorityBackgroundColor: Color = TudeeTheme.color.statusColors.yellowAccent,
taskIcon: @Composable () -> Unit,
priorityIcon: Painter,
dateText: String? = null,
onClick: () -> Unit,
dateText: String? = null, onClick: () -> Unit = {},
) {
Column(
modifier = modifier
.fillMaxWidth()
.clip(RoundedCornerShape(16.dp))
.clickWithRipple(onClick = onClick)
.border(1.dp, TudeeTheme.color.surfaceHigh, RoundedCornerShape(16.dp))
.background( TudeeTheme.color.surfaceHigh,RoundedCornerShape(16.dp))
.background(TudeeTheme.color.surfaceHigh, RoundedCornerShape(16.dp))
.padding(top = 4.dp, start = 4.dp, end = 12.dp),
verticalArrangement = Arrangement.spacedBy(2.dp)
) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
package com.example.tudee.presentation.screen.category.tasks

import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.spring
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
Expand All @@ -8,6 +17,7 @@ import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
Expand All @@ -22,6 +32,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
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
Expand All @@ -33,13 +44,16 @@ import androidx.navigation.compose.rememberNavController
import com.example.tudee.R
import com.example.tudee.designsystem.theme.TudeeTheme
import com.example.tudee.presentation.components.CategoryTaskComponent
import com.example.tudee.presentation.components.SnackBarComponent
import com.example.tudee.presentation.components.TabBarComponent
import com.example.tudee.presentation.components.TopAppBar
import com.example.tudee.presentation.components.TudeeScaffold
import com.example.tudee.presentation.components.buttons.ButtonState
import com.example.tudee.presentation.screen.category.component.CategorySheet
import com.example.tudee.presentation.screen.category.model.CategoryData
import com.example.tudee.presentation.screen.category.model.CategorySheetState
import com.example.tudee.presentation.screen.category.model.UiImage
import com.example.tudee.presentation.screen.task_screen.component.DeleteConfirmationBottomSheet
import com.example.tudee.presentation.screen.task_screen.ui.NotTaskForTodayDialogue
import kotlinx.coroutines.delay
import org.koin.androidx.compose.koinViewModel
Expand All @@ -51,20 +65,37 @@ fun CategoryTasksScreen(
viewModel: CategoryTasksViewModel = koinViewModel()
) {
val uiState by viewModel.categoryTasksUiState.collectAsState()
val showSnackBar = remember { mutableStateOf(false) }
var selectedTabIndex by remember { mutableIntStateOf(0) }
var isEditCategorySheetVisible by remember { mutableStateOf(false) }
var showSnackBar by remember { mutableStateOf(false) }
var snackBarMessageId by remember { mutableIntStateOf(0) }
var snackBarIconId by remember { mutableIntStateOf(0) }
val allTasks by viewModel.allTasks.collectAsState()
val coroutineScope = rememberCoroutineScope()
LaunchedEffect(Unit) {
viewModel.snackBarEvent.collect { event ->
when (event) {
is SnackBarEvent.ShowError -> {
showSnackBar.value = true
delay(3000L)
showSnackBar.value = false
showSnackBar = when (event) {
CategoryTasksSnackBarEvent.ShowDeleteError -> {
snackBarMessageId = R.string.failed_to_delete_category
snackBarIconId = R.drawable.ic_error
true
}

SnackBarEvent.ShowSuccess -> {}
CategoryTasksSnackBarEvent.ShowDeleteSuccess -> {
snackBarMessageId = R.string.delete_category_successfully
snackBarIconId = R.drawable.ic_success
true
}

CategoryTasksSnackBarEvent.ShowEditError -> {
snackBarMessageId = R.string.failed_to_edit_category
snackBarIconId = R.drawable.ic_error
true
}

CategoryTasksSnackBarEvent.ShowEditSuccess -> {
snackBarMessageId = R.string.edited_category_successfully
snackBarIconId = R.drawable.ic_success
true
}
}
}
}
Expand All @@ -79,9 +110,8 @@ fun CategoryTasksScreen(
uiState.categoryTasksUiModel?.isPredefined?.let {
if (!(it)) {
IconButton(
onClick = {
isEditCategorySheetVisible = true
}
onClick = viewModel::showEditCategorySheet

) {
Icon(
modifier = Modifier
Expand All @@ -107,23 +137,38 @@ fun CategoryTasksScreen(
CategoryTasksContent(
modifier = modifier.padding(paddingValues),
categoryTaskUIState = uiState,
isEditCategorySheetVisible = isEditCategorySheetVisible,
isEditCategorySheetVisible = uiState.isEditCategorySheetVisible,
isDeleteCategorySheetVisible = uiState.isDeleteCategorySheetVisible,
allTasks = allTasks,
onDeleteCategory = viewModel::deleteCategory,
onSaveButtonClicked = { categoryData ->
viewModel.editCategory(categoryData)
},
onTabSelected = { index ->
selectedTabIndex = index
viewModel.updateSelectedIndex(index)
},
onBottomSheetDismissed = { isEditCategorySheetVisible = false },
onCancelButtonClicked = { isEditCategorySheetVisible = false },
onBottomSheetDismissed = viewModel::hideEditCategorySheet,
onCancelButtonClicked = viewModel::hideEditCategorySheet,
showDeleteCategorySheet = {
viewModel.hideEditCategorySheet()
viewModel.showDeleteCategorySheet()
},
hideDeleteCategorySheet = {
viewModel.hideDeleteCategorySheet()
viewModel.showEditCategorySheet()
}
)
} else if (uiState.loading) {
LoadingState(modifier = modifier)
}
}

CategoryTasksSnackBar(
isSnackBarVisible = showSnackBar,
hideSnackBar = { showSnackBar = false },
snackBarStringId = snackBarMessageId,
snackBarIconId = snackBarIconId,
)
}


Expand All @@ -132,7 +177,10 @@ fun CategoryTasksContent(
modifier: Modifier = Modifier,
categoryTaskUIState: CategoryTasksUiState,
isEditCategorySheetVisible: Boolean,
isDeleteCategorySheetVisible: Boolean,
allTasks: List<TaskUIModel>,
showDeleteCategorySheet: () -> Unit,
hideDeleteCategorySheet: () -> Unit,
onDeleteCategory: () -> Unit,
onSaveButtonClicked: (CategoryData) -> Unit,
onTabSelected: (Int) -> Unit,
Expand All @@ -152,8 +200,11 @@ fun CategoryTasksContent(
allTasks = allTasks,
onTabSelected = { onTabSelected(it) },
isEditCategorySheetVisible = isEditCategorySheetVisible,
onBottomSheetDismissed = { onBottomSheetDismissed() },
onCancelButtonClicked = { onCancelButtonClicked() }
isDeleteCategorySheetVisible = isDeleteCategorySheetVisible,
onBottomSheetDismissed = onBottomSheetDismissed,
onCancelButtonClicked = onCancelButtonClicked,
showDeleteCategorySheet = showDeleteCategorySheet,
hideDeleteCategorySheet = hideDeleteCategorySheet
)
}
}
Expand All @@ -175,6 +226,9 @@ private fun SuccessState(
categoryTasks: List<TaskUIModel>,
isEditCategorySheetVisible: Boolean,
allTasks: List<TaskUIModel>,
isDeleteCategorySheetVisible: Boolean,
showDeleteCategorySheet: () -> Unit,
hideDeleteCategorySheet: () -> Unit,
onDeleteCategory: () -> Unit,
onSaveButtonClicked: (CategoryData) -> Unit,
onTabSelected: (Int) -> Unit,
Expand Down Expand Up @@ -236,10 +290,7 @@ private fun SuccessState(
tint = TudeeTheme.color.statusColors.purpleAccent
)
},
priorityIcon = painterResource(categoryTask.priority.drawableRes),
onClick = {
//TODO()
}
priorityIcon = painterResource(categoryTask.priority.drawableRes)
)
}
}
Expand All @@ -255,8 +306,61 @@ private fun SuccessState(
onDismiss = onBottomSheetDismissed,
onConfirm = { onSaveButtonClicked(it) },
onCancel = onCancelButtonClicked,
onDelete = onDeleteCategory
onDelete = showDeleteCategorySheet
)

DeleteConfirmationBottomSheet(
isBottomSheetVisible = isDeleteCategorySheetVisible,
title = stringResource(R.string.delete_category),
subtitle = stringResource(R.string.delete_category_confirmation),
deleteButtonUiState = ButtonState.IDLE,
cancelButtonUiState = ButtonState.IDLE,
onBottomSheetDismissed = hideDeleteCategorySheet,
onDeleteButtonClicked = onDeleteCategory,
onCancelButtonClicked = hideDeleteCategorySheet
)
}

}

@Composable
private fun CategoryTasksSnackBar(
isSnackBarVisible: Boolean,
hideSnackBar: () -> Unit,
@StringRes snackBarStringId: Int,
@DrawableRes snackBarIconId: Int
) {
LaunchedEffect(isSnackBarVisible) {
delay(3000)
hideSnackBar()
}

AnimatedVisibility(
visible = isSnackBarVisible, enter = slideInVertically(
initialOffsetY = { fullHeight -> -fullHeight }, animationSpec = spring(
stiffness = Spring.StiffnessLow, dampingRatio = Spring.DampingRatioMediumBouncy
)
) + fadeIn(),

exit = slideOutVertically(
targetOffsetY = { fullHeight -> fullHeight }, animationSpec = spring(
stiffness = Spring.StiffnessMedium, dampingRatio = Spring.DampingRatioNoBouncy
)
) + fadeOut()
) {
Box(
Modifier
.statusBarsPadding()
.padding(top = 16.dp)
.padding(horizontal = 16.dp)
) {
SnackBarComponent(
message = stringResource(snackBarStringId),
iconPainter = painterResource(id = snackBarIconId),
iconDescription = stringResource(snackBarStringId),
iconBackgroundColor = TudeeTheme.color.statusColors.greenVariant,
iconTint = TudeeTheme.color.statusColors.greenAccent
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import com.example.tudee.presentation.screen.category.model.UiImage

data class CategoryTasksUiState(
val loading: Boolean = false,
val isEditCategorySheetVisible: Boolean = false,
val isDeleteCategorySheetVisible: Boolean = false,
val categoryTasksUiModel: CategoryTasksUiModel? = null
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,36 @@ class CategoryTasksViewModel(
private val _categoryTasksUiState = MutableStateFlow(CategoryTasksUiState())
val categoryTasksUiState: StateFlow<CategoryTasksUiState> = _categoryTasksUiState

private val _snackBarEvent = MutableSharedFlow<SnackBarEvent>()
private val _snackBarEvent = MutableSharedFlow<CategoryTasksSnackBarEvent>()
val snackBarEvent = _snackBarEvent.asSharedFlow()

private val _allTasks = MutableStateFlow<MutableList<TaskUIModel>>(mutableListOf())
val allTasks = _allTasks.asStateFlow()

fun showEditCategorySheet() {
_categoryTasksUiState.update { currentState ->
currentState.copy(isEditCategorySheetVisible = true)
}
}

fun hideEditCategorySheet() {
_categoryTasksUiState.update { currentState ->
currentState.copy(isEditCategorySheetVisible = false)
}
}

fun showDeleteCategorySheet() {
_categoryTasksUiState.update { currentState ->
currentState.copy(isDeleteCategorySheetVisible = true)
}
}

fun hideDeleteCategorySheet() {
_categoryTasksUiState.update { currentState ->
currentState.copy(isDeleteCategorySheetVisible = false)
}
}

init {
viewModelScope.launch {
_categoryTasksUiState.update { it.copy(loading = true) }
Expand All @@ -55,8 +79,7 @@ class CategoryTasksViewModel(
)
}
updateSelectedIndex(0)
} catch (_: Exception) {
_snackBarEvent.emit(SnackBarEvent.ShowError)
} catch (e: Exception) {
_categoryTasksUiState.update { currentState ->
currentState.copy(
loading = false,
Expand Down Expand Up @@ -119,23 +142,44 @@ class CategoryTasksViewModel(
fun deleteCategory() {
_categoryTasksUiState.value.categoryTasksUiModel?.let {
viewModelScope.launch {
taskCategoryService.deleteCategory(it.id)
try {
taskCategoryService.deleteCategory(it.id)
_snackBarEvent.emit(CategoryTasksSnackBarEvent.ShowDeleteSuccess)

hideDeleteCategorySheet()
hideEditCategorySheet()
} catch (_: Exception) {
_snackBarEvent.emit(CategoryTasksSnackBarEvent.ShowDeleteError)
}
}
}
}

fun editCategory(category: CategoryData) {
_categoryTasksUiState.value.categoryTasksUiModel?.let {
viewModelScope.launch {
taskCategoryService.editCategory(
TaskCategory(
id = it.id,
title = category.name,
image = category.uiImage?.asString()!!,
isPredefined = it.isPredefined
try {
taskCategoryService.editCategory(
TaskCategory(
id = it.id,
title = category.name,
image = category.uiImage?.asString()!!,
isPredefined = it.isPredefined
)
)
)
hideEditCategorySheet()
_snackBarEvent.emit(CategoryTasksSnackBarEvent.ShowEditSuccess)
} catch (_: Exception) {
_snackBarEvent.emit(CategoryTasksSnackBarEvent.ShowEditError)
}
}
}
}
}

sealed class CategoryTasksSnackBarEvent() {
data object ShowEditError : CategoryTasksSnackBarEvent()
data object ShowEditSuccess : CategoryTasksSnackBarEvent()
data object ShowDeleteError : CategoryTasksSnackBarEvent()
data object ShowDeleteSuccess : CategoryTasksSnackBarEvent()
}
Loading