Coverage Summary for Class: GoalDateFieldKt (com.georgeci.moneysurfer.feature.goal)

Class Class, % Method, % Branch, % Line, % Instruction, %
GoalDateFieldKt 0% (0/1) 0% (0/7) 0% (0/28) 0% (0/53) 0% (0/666)


 package com.georgeci.moneysurfer.feature.goal
 
 import androidx.compose.foundation.border
 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.RowScope
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.heightIn
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.size
 import androidx.compose.material3.DatePicker
 import androidx.compose.material3.DatePickerDialog
 import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.material3.Icon
 import androidx.compose.material3.Text
 import androidx.compose.material3.TextButton
 import androidx.compose.material3.rememberDatePickerState
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.clip
 import androidx.compose.ui.unit.dp
 import com.georgeci.moneysurfer.uikit.icons.SurferIcons
 import com.georgeci.moneysurfer.uikit.semantics.SurferSemantics
 import com.georgeci.moneysurfer.uikit.theme.AppTheme
 import kotlinx.datetime.LocalDate
 import kotlinx.datetime.TimeZone
 import kotlinx.datetime.atStartOfDayIn
 import kotlinx.datetime.toLocalDateTime
 import moneysurfer.feature.goal.generated.resources.Res
 import moneysurfer.feature.goal.generated.resources.goal_edit_cancel
 import moneysurfer.feature.goal.generated.resources.goal_edit_save
 import org.jetbrains.compose.resources.stringResource
 import kotlin.time.Instant
 
 private val FIELD_MIN_HEIGHT = 56.dp
 private val FIELD_VERTICAL_PADDING = 14.dp
 private val FIELD_ICON_SIZE = 20.dp
 
 /**
  * Read-only date row that opens a picker — the goal editor's deadline and the contribution
  * date look and behave the same, so they share one field.
  */
 @Composable
 internal fun GoalDateField(
     label: String,
     value: String,
     onClick: () -> Unit,
     modifier: Modifier = Modifier,
     trailing: @Composable (RowScope.() -> Unit)? = null,
 ) {
     val shape = AppTheme.shapes.extraSmall
     Row(
         modifier = modifier
             .fillMaxWidth()
             .heightIn(min = FIELD_MIN_HEIGHT)
             .clip(shape)
             .border(1.dp, AppTheme.materialColors.outline, shape)
             .clickable(onClick = onClick)
             .padding(horizontal = AppTheme.spacing.default, vertical = FIELD_VERTICAL_PADDING),
         verticalAlignment = Alignment.CenterVertically,
         horizontalArrangement = Arrangement.spacedBy(AppTheme.spacing.medium),
     ) {
         Icon(
             imageVector = SurferIcons.Event,
             contentDescription = SurferSemantics.Decorative,
             tint = AppTheme.materialColors.onSurfaceVariant,
             modifier = Modifier.size(FIELD_ICON_SIZE),
         )
         Column(modifier = Modifier.weight(1f)) {
             Text(
                 text = label,
                 style = AppTheme.typography.bodySmall,
                 color = AppTheme.materialColors.onSurfaceVariant,
             )
             Text(
                 text = value,
                 style = AppTheme.typography.bodyLarge,
                 color = AppTheme.materialColors.onSurface,
             )
         }
         trailing?.invoke(this)
     }
 }
 
 /**
  * Date picker for the goal screens. Unlike the transaction picker, future dates are
  * selectable — a goal deadline is by definition ahead.
  */
 @OptIn(ExperimentalMaterial3Api::class)
 @Composable
 internal fun GoalDatePickerDialog(
     initialDate: LocalDate?,
     onDismiss: () -> Unit,
     onConfirm: (LocalDate) -> Unit,
 ) {
     val zone = TimeZone.currentSystemDefault()
     val state = rememberDatePickerState(
         initialSelectedDateMillis = initialDate?.atStartOfDayIn(zone)?.toEpochMilliseconds(),
     )
     DatePickerDialog(
         onDismissRequest = onDismiss,
         confirmButton = {
             TextButton(
                 onClick = {
                     state.selectedDateMillis?.let { millis ->
                         onConfirm(Instant.fromEpochMilliseconds(millis).toLocalDateTime(zone).date)
                     }
                 },
                 enabled = state.selectedDateMillis != null,
             ) { Text(stringResource(Res.string.goal_edit_save)) }
         },
         dismissButton = {
             TextButton(onClick = onDismiss) { Text(stringResource(Res.string.goal_edit_cancel)) }
         },
     ) {
         DatePicker(state = state)
     }
 }