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
109 changes: 95 additions & 14 deletions app/src/main/java/com/mapgie/goflo/ui/components/DayLogSheet.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material.icons.outlined.WaterDrop
import androidx.compose.material3.Checkbox
import androidx.compose.material3.DropdownMenu
Expand Down Expand Up @@ -46,10 +48,14 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.unit.dp
import com.mapgie.goflo.data.database.entities.Group
import com.mapgie.goflo.data.database.entities.PeriodEntry
import com.mapgie.goflo.data.database.entities.TrackingCategory
import com.mapgie.goflo.data.database.entities.TrackingLog
import com.mapgie.goflo.data.repository.TrackingLogWithValues
import com.mapgie.goflo.ui.util.COLOR_TOKEN_INHERIT
import com.mapgie.goflo.ui.util.decodeScaleLabels
import com.mapgie.goflo.ui.util.effectiveColorToken
import com.mapgie.goflo.ui.util.toCategoryColor
import com.mapgie.goflo.ui.util.toCategoryIcon
import com.mapgie.goflo.ui.util.toCategoryOnColor
Expand All @@ -67,6 +73,10 @@ fun DayLogSheet(
onDismiss: () -> Unit,
onEditPeriod: (Long) -> Unit,
onEditTrackingLog: (categoryId: Long, logId: Long) -> Unit,
/** Deletes stored logs straight from the sheet (after confirmation). */
onDeleteTrackingLogs: (List<TrackingLog>) -> Unit,
/** Groups, so categories that inherit their colour render in it. */
groups: List<Group> = emptyList(),
/** Opens the full log menu so one category can be picked directly. */
onLogMore: () -> Unit,
/** Opens the unified day screen for this day, the standard logging surface. */
Expand All @@ -84,6 +94,31 @@ fun DayLogSheet(
}
var showAgainstTime by rememberSaveable { mutableStateOf(false) }
var showMenu by remember { mutableStateOf(false) }
/** Logs awaiting delete confirmation; empty when no dialog is open. */
var pendingDelete by remember { mutableStateOf<List<TrackingLogWithValues>>(emptyList()) }

if (pendingDelete.isNotEmpty()) {
val name = pendingDelete.first().category?.name ?: "this"
val n = pendingDelete.size
AlertDialog(
onDismissRequest = { pendingDelete = emptyList() },
title = { Text(if (n == 1) "Delete this entry?" else "Delete these entries?") },
text = { Text(
if (n == 1) "The $name entry for ${date.format(headerFormat)} will be permanently removed."
else "All $n $name entries for ${date.format(headerFormat)} will be permanently removed."
) },
confirmButton = {
TextButton(
onClick = {
onDeleteTrackingLogs(pendingDelete.map { it.log })
pendingDelete = emptyList()
},
colors = ButtonDefaults.textButtonColors(contentColor = MaterialTheme.colorScheme.error),
) { Text("Delete") }
},
dismissButton = { TextButton(onClick = { pendingDelete = emptyList() }) { Text("Cancel") } },
)
}

ModalBottomSheet(
onDismissRequest = onDismiss,
Expand Down Expand Up @@ -139,12 +174,23 @@ fun DayLogSheet(

HorizontalDivider()

// Split tracked categories into those logged with the period (the
// ones pinned into the day screen's flow context) and everything else.
// Split tracked categories into those that belong with the period
// (flow and symptoms, plus the ones pinned into the day screen's
// period context) and everything else. Flow leads.
val periodLinkedCats = if (period != null) {
categoryOrder.filter { catId ->
logsByCategory[catId]?.firstOrNull()?.category?.showInLogPeriod == true
}
categoryOrder
.filter { catId ->
val cat = logsByCategory[catId]?.firstOrNull()?.category
cat != null && (cat.isSystem || cat.showInLogPeriod)
}
.sortedBy { catId ->
val cat = logsByCategory[catId]?.firstOrNull()?.category
when {
cat?.systemKey == "flow" -> 0
cat?.isSystem == true -> 1
else -> 2
}
}
} else {
emptyList()
}
Expand Down Expand Up @@ -186,8 +232,10 @@ fun DayLogSheet(
)
CategoryLogEntry(
entries = entries,
groups = groups,
showAgainstTime = showAgainstTime,
onEditTrackingLog = onEditTrackingLog
onEditTrackingLog = onEditTrackingLog,
onDelete = { pendingDelete = it },
)
}
}
Expand All @@ -207,8 +255,10 @@ fun DayLogSheet(
val entries = logsByCategory[catId] ?: return@forEach
CategoryLogEntry(
entries = entries,
groups = groups,
showAgainstTime = showAgainstTime,
onEditTrackingLog = onEditTrackingLog
onEditTrackingLog = onEditTrackingLog,
onDelete = { pendingDelete = it },
)
}

Expand Down Expand Up @@ -243,15 +293,22 @@ fun DayLogSheet(
@Composable
private fun CategoryLogEntry(
entries: List<TrackingLogWithValues>,
groups: List<Group>,
showAgainstTime: Boolean,
onEditTrackingLog: (categoryId: Long, logId: Long) -> Unit,
/** Asks to delete the given logs (one timed entry, or the whole row). */
onDelete: (List<TrackingLogWithValues>) -> Unit,
) {
val first = entries.first()
val category = first.category
val bubbleColor = category?.colorToken?.toCategoryColor()
?: MaterialTheme.colorScheme.secondary
val onBubble = category?.colorToken?.toCategoryOnColor()
?: MaterialTheme.colorScheme.onSecondary
// The group's colour when the category inherits it; a category with no
// colour of its own and no group is neutral, and its value text must
// then read as ordinary text rather than vanish into the surface tint.
val token = category?.effectiveColorToken(groups)
val bubbleColor = token?.toCategoryColor() ?: MaterialTheme.colorScheme.secondary
val onBubble = token?.toCategoryOnColor() ?: MaterialTheme.colorScheme.onSecondary
val valueColor = if (token == null || token == COLOR_TOKEN_INHERIT)
MaterialTheme.colorScheme.onSurface else bubbleColor
val icon = category?.iconName?.toCategoryIcon()?.vector

val hasTimedEntries = showAgainstTime &&
Expand All @@ -263,7 +320,8 @@ private fun CategoryLogEntry(
iconColor = bubbleColor,
iconOnColor = onBubble,
label = category?.name ?: "Unknown",
onEdit = { onEditTrackingLog(first.log.categoryId, entries.last().log.id) }
onEdit = { onEditTrackingLog(first.log.categoryId, entries.last().log.id) },
onDelete = { onDelete(entries) },
) {
if (hasTimedEntries) {
// Show each entry with its timestamp on its own line
Expand Down Expand Up @@ -297,6 +355,16 @@ private fun CategoryLogEntry(
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.6f)
)
}
TextButton(
onClick = { onDelete(listOf(entry)) },
contentPadding = PaddingValues(horizontal = 4.dp, vertical = 0.dp)
) {
Text(
text = "delete",
style = MaterialTheme.typography.labelSmall,
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.6f)
)
}
}
}
} else {
Expand All @@ -314,7 +382,7 @@ private fun CategoryLogEntry(
Text(
text = allDisplayValues[0],
style = MaterialTheme.typography.titleMedium,
color = bubbleColor
color = valueColor
)
} else {
Text(
Expand Down Expand Up @@ -357,7 +425,8 @@ private fun LogEntryRow(
iconOnColor: Color,
label: String,
onEdit: () -> Unit,
content: @Composable ColumnScope.() -> Unit
onDelete: (() -> Unit)? = null,
content: @Composable ColumnScope.() -> Unit,
) {
Row(
modifier = Modifier.fillMaxWidth(),
Expand Down Expand Up @@ -404,6 +473,18 @@ private fun LogEntryRow(
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.6f)
)
}
if (onDelete != null) {
TextButton(
onClick = onDelete,
contentPadding = PaddingValues(horizontal = 4.dp, vertical = 0.dp)
) {
Text(
text = "delete",
style = MaterialTheme.typography.labelSmall,
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.6f)
)
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,9 @@ fun HomeScreen(
date = data.date,
period = data.period,
trackingLogs = data.trackingLogs,
groups = data.groups,
onDismiss = { viewModel.clearSelectedDay() },
onDeleteTrackingLogs = { viewModel.deleteTrackingLogs(it) },
onEditPeriod = {
viewModel.clearSelectedDay()
// The unified day screen edits this specific day's own flow
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ package com.mapgie.goflo.ui.screens.home
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import com.mapgie.goflo.data.database.entities.Group
import com.mapgie.goflo.data.database.entities.PeriodEntry
import com.mapgie.goflo.data.database.entities.TrackingCategory
import com.mapgie.goflo.data.database.entities.TrackingLog
import com.mapgie.goflo.data.preferences.AppPreferencesStore
import com.mapgie.goflo.data.repository.PeriodRepository
import com.mapgie.goflo.data.repository.TrackingLogWithValues
Expand Down Expand Up @@ -70,6 +72,8 @@ data class DayLogData(
val date: LocalDate,
val period: PeriodEntry?,
val trackingLogs: List<TrackingLogWithValues>,
/** Groups, so categories that inherit their colour render in it. */
val groups: List<Group> = emptyList(),
)

@OptIn(ExperimentalCoroutinesApi::class)
Expand Down Expand Up @@ -171,8 +175,9 @@ class HomeViewModel(

combine(
repository.getAllPeriods(),
trackingRepository.getLogsForDate(date)
) { periods, trackingLogs ->
trackingRepository.getLogsForDate(date),
trackingRepository.getAllGroups(),
) { periods, trackingLogs, groups ->
val period = periods.firstOrNull { p ->
val start = LocalDate.parse(p.startDate)
val end = p.endDate?.let { LocalDate.parse(it) } ?: LocalDate.now()
Expand All @@ -182,6 +187,7 @@ class HomeViewModel(
date = date,
period = period,
trackingLogs = trackingLogs,
groups = groups,
)
}
}
Expand All @@ -190,6 +196,16 @@ class HomeViewModel(
fun selectDay(date: LocalDate) { _selectedDay.value = date }
fun clearSelectedDay() { _selectedDay.value = null }

/**
* Deletes stored tracking logs from the day sheet. The sheet's data is a
* live query, so it refreshes on its own.
*/
fun deleteTrackingLogs(logs: List<TrackingLog>) {
viewModelScope.launch {
logs.forEach { trackingRepository.deleteLog(it) }
}
}

// ── Quick increment (Plus One categories) ───────────────────────────────────

/** Transient confirmation message after an instant increment; null when none pending. */
Expand Down
6 changes: 6 additions & 0 deletions changelog/unreleased/day-sheet-delete-and-colours.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"bump": "patch",
"fixed": [
"The calendar day sheet now lets you delete any entry (including Flow and Symptoms) with a confirmation, shows Flow and Symptoms alongside the period instead of under \"Tracked\", and renders categories that inherit their group's colour in that colour so their values are readable"
]
}
Loading