Fix date issues

Change primary theme color
This commit is contained in:
Geoffroy Bonneville
2025-09-25 20:46:24 -04:00
parent b71fa4fdb7
commit 4522296cf1
10 changed files with 52 additions and 42 deletions

View File

@@ -366,18 +366,6 @@
<option name="screenX" value="384" /> <option name="screenX" value="384" />
<option name="screenY" value="384" /> <option name="screenY" value="384" />
</PersistentDeviceSelectionData> </PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="35" />
<option name="brand" value="motorola" />
<option name="codename" value="eqe" />
<option name="id" value="eqe" />
<option name="labId" value="google" />
<option name="manufacturer" value="Motorola" />
<option name="name" value="edge 50 pro" />
<option name="screenDensity" value="450" />
<option name="screenX" value="1220" />
<option name="screenY" value="2712" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData> <PersistentDeviceSelectionData>
<option name="api" value="33" /> <option name="api" value="33" />
<option name="brand" value="google" /> <option name="brand" value="google" />

View File

@@ -125,8 +125,8 @@ abstract class AppDatabase : RoomDatabase() {
// insert default lists // insert default lists
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
val dao = DB_INSTANCE?.taskListDao() val dao = DB_INSTANCE?.taskListDao()
dao?.insertTaskList(TaskListEntity(name = "Work", order = 2))
dao?.insertTaskList(TaskListEntity(name = "Personal", order = 1)) dao?.insertTaskList(TaskListEntity(name = "Personal", order = 1))
dao?.insertTaskList(TaskListEntity(name = "Work", order = 2))
dao?.insertTaskList(TaskListEntity(name = "Shopping", order = 3)) dao?.insertTaskList(TaskListEntity(name = "Shopping", order = 3))
} }
} }

View File

@@ -0,0 +1,10 @@
package com.wismna.geoffroy.donext.domain.extension
import java.time.Instant
import java.time.LocalDate
import java.time.ZoneId
fun Long.toLocalDate(): LocalDate =
Instant.ofEpochMilli(this)
.atZone(ZoneId.systemDefault())
.toLocalDate()

View File

@@ -218,7 +218,7 @@ fun AddListBottomSheet(
//var description by remember { mutableStateOf("") } //var description by remember { mutableStateOf("") }
Column(modifier = Modifier.padding(16.dp)) { Column(modifier = Modifier.padding(16.dp)) {
Text("Create New List", style = MaterialTheme.typography.titleMedium) Text("New List", style = MaterialTheme.typography.titleMedium)
Spacer(Modifier.height(8.dp)) Spacer(Modifier.height(8.dp))
/*TextField( /*TextField(
@@ -234,8 +234,7 @@ fun AddListBottomSheet(
label = { Text("Title") }, label = { Text("Title") },
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.focusRequester(titleFocusRequester), .focusRequester(titleFocusRequester)
isError = name.isEmpty(),
) )
Spacer(Modifier.height(8.dp)) Spacer(Modifier.height(8.dp))
@@ -253,11 +252,14 @@ fun AddListBottomSheet(
Row(horizontalArrangement = Arrangement.End, modifier = Modifier.fillMaxWidth()) { Row(horizontalArrangement = Arrangement.End, modifier = Modifier.fillMaxWidth()) {
//TextButton(onClick = onDismiss) { Text("Cancel") } //TextButton(onClick = onDismiss) { Text("Cancel") }
//Spacer(Modifier.width(8.dp)) //Spacer(Modifier.width(8.dp))
Button(onClick = { Button(
viewModel.createTaskList(name/*, type, description*/, 1) onClick = {
onDismiss() viewModel.createTaskList(name/*, type, description*/, viewModel.taskCount + 1)
}) { onDismiss()
Text("Add") },
enabled = name.isNotBlank()
) {
Text("Create")
} }
} }
} }

View File

@@ -38,9 +38,9 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.wismna.geoffroy.donext.domain.extension.toLocalDate
import com.wismna.geoffroy.donext.domain.model.Priority import com.wismna.geoffroy.donext.domain.model.Priority
import com.wismna.geoffroy.donext.presentation.viewmodel.TaskViewModel import com.wismna.geoffroy.donext.presentation.viewmodel.TaskViewModel
import java.time.Instant
import java.time.LocalDate import java.time.LocalDate
import java.time.ZoneId import java.time.ZoneId
import java.time.ZoneOffset import java.time.ZoneOffset
@@ -76,8 +76,7 @@ fun TaskBottomSheet(
label = { Text("Title") }, label = { Text("Title") },
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.focusRequester(titleFocusRequester), .focusRequester(titleFocusRequester)
isError = viewModel.title.isEmpty(),
) )
Spacer(Modifier.height(12.dp)) Spacer(Modifier.height(12.dp))
@@ -107,12 +106,9 @@ fun TaskBottomSheet(
// --- Due Date --- // --- Due Date ---
var showDatePicker by remember { mutableStateOf(false) } var showDatePicker by remember { mutableStateOf(false) }
val formattedDate = viewModel.dueDate?.let { val formattedDate = viewModel.dueDate?.toLocalDate()?.format(
Instant.ofEpochMilli(it) DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM))
.atZone(ZoneId.systemDefault()) ?: ""
.toLocalDate()
.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM))
} ?: ""
OutlinedTextField( OutlinedTextField(
value = formattedDate, value = formattedDate,
@@ -143,11 +139,11 @@ fun TaskBottomSheet(
initialSelectedDateMillis = viewModel.dueDate, initialSelectedDateMillis = viewModel.dueDate,
selectableDates = object: SelectableDates { selectableDates = object: SelectableDates {
override fun isSelectableDate(utcTimeMillis: Long): Boolean { override fun isSelectableDate(utcTimeMillis: Long): Boolean {
val todayStartMillis = LocalDate.now(ZoneOffset.UTC) val todayStartUtcMillis = LocalDate.now(ZoneId.systemDefault())
.atStartOfDay(ZoneOffset.UTC) .atStartOfDay(ZoneOffset.UTC)
.toInstant() .toInstant()
.toEpochMilli() .toEpochMilli()
return utcTimeMillis >= todayStartMillis return utcTimeMillis >= todayStartUtcMillis
} }
} }
) )
@@ -155,7 +151,8 @@ fun TaskBottomSheet(
DatePickerDialog( DatePickerDialog(
onDismissRequest = { showDatePicker = false }, onDismissRequest = { showDatePicker = false },
confirmButton = { confirmButton = {
TextButton(onClick = { TextButton(
onClick = {
datePickerState.selectedDateMillis?.let { viewModel.onDueDateChanged(it) } datePickerState.selectedDateMillis?.let { viewModel.onDueDateChanged(it) }
showDatePicker = false showDatePicker = false
}) { Text("OK") } }) { Text("OK") }

View File

@@ -3,7 +3,7 @@ package com.wismna.geoffroy.donext.presentation.ui.theme
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
// Primary shades // Primary shades
val Purple80 = Color(0xFFD0BCFF) // Light theme primary val Purple80 = Color(0xFF6A59C7) // Light theme primary
val Purple40 = Color(0xFF6650A4) // Dark theme primary val Purple40 = Color(0xFF6650A4) // Dark theme primary
val PurpleGrey80 = Color(0xFFCCC2DC) val PurpleGrey80 = Color(0xFFCCC2DC)

View File

@@ -48,7 +48,7 @@ fun DoNextTheme(
else -> lightColorScheme( else -> lightColorScheme(
primary = Purple80, primary = Purple80,
onPrimary = DarkSurfaceContainer, onPrimary = LightSurfaceContainer,
primaryContainer = Purple80Container, primaryContainer = Purple80Container,
onPrimaryContainer = DarkSurfaceContainer, onPrimaryContainer = DarkSurfaceContainer,
secondary = PurpleGrey80, secondary = PurpleGrey80,

View File

@@ -1,6 +1,7 @@
package com.wismna.geoffroy.donext.presentation.viewmodel package com.wismna.geoffroy.donext.presentation.viewmodel
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
@@ -26,11 +27,14 @@ class ManageListsViewModel @Inject constructor(
var taskLists by mutableStateOf<List<TaskList>>(emptyList()) var taskLists by mutableStateOf<List<TaskList>>(emptyList())
private set private set
var taskCount by mutableIntStateOf(0)
private set
init { init {
getTaskListsUseCase() getTaskListsUseCase()
.onEach { lists -> .onEach { lists ->
taskLists = lists taskLists = lists
taskCount = lists.size
} }
.launchIn(viewModelScope) .launchIn(viewModelScope)
} }

View File

@@ -1,8 +1,8 @@
package com.wismna.geoffroy.donext.presentation.viewmodel package com.wismna.geoffroy.donext.presentation.viewmodel
import com.wismna.geoffroy.donext.domain.extension.toLocalDate
import com.wismna.geoffroy.donext.domain.model.Priority import com.wismna.geoffroy.donext.domain.model.Priority
import com.wismna.geoffroy.donext.domain.model.Task import com.wismna.geoffroy.donext.domain.model.Task
import java.time.Instant
import java.time.LocalDate import java.time.LocalDate
import java.time.ZoneId import java.time.ZoneId
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
@@ -21,16 +21,14 @@ class TaskItemViewModel(task: Task) {
val today: LocalDate = LocalDate.now(ZoneId.systemDefault()) val today: LocalDate = LocalDate.now(ZoneId.systemDefault())
val isOverdue: Boolean = task.dueDate?.let { millis -> val isOverdue: Boolean = task.dueDate?.let { millis ->
val dueDate = Instant.ofEpochMilli(millis) val dueDate = millis.toLocalDate()
.atZone(ZoneId.systemDefault())
.toLocalDate()
dueDate.isBefore(today) dueDate.isBefore(today)
} ?: false } ?: false
val dueDateText: String? = task.dueDate?.let { formatDueDate(it) } val dueDateText: String? = task.dueDate?.let { formatDueDate(it) }
private fun formatDueDate(dueMillis: Long): String { private fun formatDueDate(dueMillis: Long): String {
val dueDate = Instant.ofEpochMilli(dueMillis).atZone(ZoneId.systemDefault()).toLocalDate() val dueDate = dueMillis.toLocalDate()
return when { return when {
dueDate.isEqual(today) -> "Today" dueDate.isEqual(today) -> "Today"

View File

@@ -12,6 +12,9 @@ import com.wismna.geoffroy.donext.domain.usecase.ToggleTaskDeletedUseCase
import com.wismna.geoffroy.donext.domain.usecase.UpdateTaskUseCase import com.wismna.geoffroy.donext.domain.usecase.UpdateTaskUseCase
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.time.Instant
import java.time.ZoneId
import java.time.ZoneOffset
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel @HiltViewModel
@@ -59,9 +62,17 @@ class TaskViewModel @Inject constructor(
fun onTitleChanged(value: String) { title = value } fun onTitleChanged(value: String) { title = value }
fun onDescriptionChanged(value: String) { description = value } fun onDescriptionChanged(value: String) { description = value }
fun onPriorityChanged(value: Priority) { priority = value } fun onPriorityChanged(value: Priority) { priority = value }
fun onDueDateChanged(value: Long?) { dueDate = value } fun onDueDateChanged(value: Long?) {
dueDate = if (value == null) null else
Instant.ofEpochMilli(value)
.atZone(ZoneOffset.UTC)
.toLocalDate()
.atStartOfDay(ZoneId.systemDefault())
.toInstant()
.toEpochMilli()
}
fun save(onDone: (() -> Unit)? = null) { fun save(onDone: (() -> Unit)? = null) {
if (title.isBlank()) return if (title.isBlank()) return
viewModelScope.launch { viewModelScope.launch {