Coverage Summary for Class: SurferSettingsTogglesKt (com.georgeci.moneysurfer.uikit.components.settings)

Class Class, % Method, % Branch, % Line, % Instruction, %
SurferSettingsTogglesKt 100% (1/1) 66.7% (2/3) 59.1% (13/22) 100% (43/43) 97.9% (424/433)


 package com.georgeci.moneysurfer.uikit.components.settings
 
 import androidx.compose.animation.core.Spring
 import androidx.compose.animation.core.animateDpAsState
 import androidx.compose.animation.core.spring
 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.Row
 import androidx.compose.foundation.layout.offset
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.size
 import androidx.compose.foundation.shape.CircleShape
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.clip
 import androidx.compose.ui.draw.shadow
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.tooling.preview.Preview
 import androidx.compose.ui.unit.dp
 import com.georgeci.moneysurfer.uikit.preview.SurferComponentPreview
 import com.georgeci.moneysurfer.uikit.theme.AppTheme
 
 /**
  * iOS-style pill toggle: 51x31 track, 27dp white knob with subtle shadow. Used as the trailing
  * slot on [SurferSettingsRow]. Matches the design's preference for a clean toggle without M3's
  * inline icon clutter — fill + position carries the state.
  */
 @Composable
 fun SurferSettingsSwitch(
     checked: Boolean,
     onCheckedChange: (Boolean) -> Unit,
     modifier: Modifier = Modifier,
 ) {
     val colors = AppTheme.materialColors
     val trackColor = if (checked) colors.primary else colors.surfaceContainerHighest
     val knobOffset by animateDpAsState(
         targetValue = if (checked) 20.dp else 0.dp,
         animationSpec = spring(stiffness = Spring.StiffnessMediumLow),
     )
     Box(
         modifier = modifier
             .size(width = 51.dp, height = 31.dp)
             .clip(CircleShape)
             .background(trackColor)
             .clickable { onCheckedChange(!checked) }
             .padding(2.dp),
         contentAlignment = Alignment.CenterStart,
     ) {
         Box(
             modifier = Modifier
                 .offset(x = knobOffset)
                 .size(27.dp)
                 .shadow(elevation = 2.dp, shape = CircleShape)
                 .clip(CircleShape)
                 .background(Color.White),
         )
     }
 }
 
 /** Round radio dot — used in radio-list rows (e.g. theme picker). */
 @Composable
 fun SurferSettingsRadio(
     selected: Boolean,
     modifier: Modifier = Modifier,
 ) {
     val colors = AppTheme.materialColors
     val ring = if (selected) colors.primary else colors.outline
     Box(
         modifier = modifier
             .size(22.dp)
             .clip(CircleShape)
             .border(2.dp, ring, CircleShape),
         contentAlignment = Alignment.Center,
     ) {
         if (selected) {
             Box(
                 modifier = Modifier
                     .size(10.dp)
                     .clip(CircleShape)
                     .background(colors.primary),
             )
         }
     }
 }
 
 @Preview
 @Composable
 private fun SurferSettingsSwitchPreview() {
     SurferComponentPreview {
         Row(
             modifier = Modifier.padding(16.dp),
             horizontalArrangement = Arrangement.spacedBy(16.dp),
             verticalAlignment = Alignment.CenterVertically,
         ) {
             SurferSettingsSwitch(checked = true, onCheckedChange = {})
             SurferSettingsSwitch(checked = false, onCheckedChange = {})
             SurferSettingsRadio(selected = true)
             SurferSettingsRadio(selected = false)
         }
     }
 }