Skip to content

Commit

Permalink
Merge pull request #46 from YAPP-Github/ui/#45-alarm-snooze
Browse files Browse the repository at this point in the history
[UI/YAF-74] ์•Œ๋žŒ ์„ค์ • ์‹œ ์•Œ๋žŒ ๋ฏธ๋ฃจ๊ธฐ๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค
  • Loading branch information
DongChyeon authored Jan 19, 2025
2 parents 3496d8f + c824f11 commit 0bfc6c8
Show file tree
Hide file tree
Showing 13 changed files with 827 additions and 123 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ import androidx.navigation.NavHostController
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navOptions
import com.yapp.common.navigation.destination.OnboardingDestination
import com.yapp.common.navigation.destination.HomeDestination
import com.yapp.common.navigation.destination.TopLevelDestination

class OrbitNavigator(
val navController: NavHostController,
) {
val startDestination = OnboardingDestination.Route.route
val startDestination = HomeDestination.Route.route

private val currentDestination: NavDestination?
@Composable get() = navController
Expand Down
13 changes: 13 additions & 0 deletions core/designsystem/src/main/res/drawable/ic_arrow_right.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M9,18L15,12L9,6"
android:strokeLineJoin="round"
android:strokeWidth="1.5"
android:fillColor="#00000000"
android:strokeColor="#A5B2C5"
android:strokeLineCap="round"/>
</vector>
52 changes: 49 additions & 3 deletions core/ui/src/main/java/com/yapp/ui/component/OrbitBottomSheet.kt
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
package com.yapp.ui.component

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.SheetState
import androidx.compose.material3.Text
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.tooling.preview.Preview
Expand Down Expand Up @@ -54,12 +61,51 @@ fun OrbitBottomSheet(
@Preview
@Composable
fun OrbitBottomSheetPreview() {
var isSheetOpen by rememberSaveable { mutableStateOf(false) }
var isSheetOpen by rememberSaveable { mutableStateOf(true) }
val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
val scope = rememberCoroutineScope()

OrbitTheme {
Button(
onClick = {
scope.launch {
sheetState.show()
}.invokeOnCompletion {
if (!isSheetOpen) {
isSheetOpen = true
}
}
},
) {
Text("Toggle Bottom Sheet")
}

OrbitBottomSheet(
isSheetOpen = true,
isSheetOpen = isSheetOpen,
sheetState = sheetState,
onDismissRequest = { isSheetOpen = !isSheetOpen },
content = {},
content = {
Box(
modifier = Modifier
.fillMaxWidth()
.height(600.dp),
contentAlignment = Alignment.Center,
) {
Button(
onClick = {
scope.launch {
sheetState.hide()
}.invokeOnCompletion {
if (isSheetOpen) {
isSheetOpen = false
}
}
},
) {
Text("Toggle Bottom Sheet")
}
}
},
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import com.yapp.designsystem.theme.OrbitTheme
@Composable
fun OrbitRadioButton(
isSelected: Boolean,
isEnabled: Boolean = true,
onClick: (Boolean) -> Unit,
) {
val backgroundColor = if (isSelected) {
Expand Down Expand Up @@ -50,7 +51,9 @@ fun OrbitRadioButton(
)
.clip(CircleShape)
.clickable {
onClick(!isSelected)
if (isEnabled) {
onClick(!isSelected)
}
},
contentAlignment = Alignment.Center,
) {
Expand Down
117 changes: 83 additions & 34 deletions core/ui/src/main/java/com/yapp/ui/component/switch/Switch.kt
Original file line number Diff line number Diff line change
@@ -1,54 +1,87 @@
package com.yapp.ui.component.switch

import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
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.material3.Switch
import androidx.compose.material3.SwitchDefaults
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.draw.clip
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import com.yapp.designsystem.theme.OrbitTheme
import kotlin.math.roundToInt

@Composable
fun OrbitSwitch(
isSelected: Boolean,
onClick: (Boolean) -> Unit,
modifier: Modifier = Modifier,
isChecked: Boolean,
isEnabled: Boolean = true,
onClick: () -> Unit,
) {
val thumbColor = if (isSelected) {
OrbitTheme.colors.gray_900
val (thumbColor, backgroundColor) = if (isChecked && isEnabled) {
Pair(OrbitTheme.colors.gray_900, OrbitTheme.colors.main)
} else if (!isEnabled) {
Pair(OrbitTheme.colors.gray_500, OrbitTheme.colors.gray_700)
} else {
OrbitTheme.colors.gray_300
Pair(OrbitTheme.colors.gray_300, OrbitTheme.colors.gray_600)
}

Switch(
checked = isSelected,
onCheckedChange = onClick,
thumbContent = {
Box(
modifier = Modifier
.size(20.dp)
.background(
color = thumbColor,
shape = CircleShape,
),
)
},
colors = SwitchDefaults.colors(
checkedThumbColor = Color.Transparent,
checkedTrackColor = OrbitTheme.colors.main,
uncheckedThumbColor = Color.Transparent,
uncheckedTrackColor = OrbitTheme.colors.gray_600,
uncheckedBorderColor = Color.Transparent,
),
val density = LocalDensity.current
val minBound = with(density) { 0.dp.toPx() }
val maxBound = with(density) { 20.dp.toPx() }
val state by animateFloatAsState(
targetValue = if (isChecked && isEnabled) maxBound else minBound,
animationSpec = tween(durationMillis = 200),
label = "custom_switch",
)

Box(
modifier = modifier
.size(width = 46.dp, height = 26.dp)
.background(
color = backgroundColor,
shape = CircleShape,
)
.clip(CircleShape)
.padding(3.dp)
.pointerInput(isEnabled) {
detectTapGestures(
onTap = {
if (isEnabled) {
onClick()
}
},
)
},
) {
Box(
modifier = Modifier
.offset { IntOffset(state.roundToInt(), 0) }
.size(20.dp)
.background(
color = thumbColor,
shape = CircleShape,
),
)
}
}

@Preview
Expand All @@ -57,11 +90,27 @@ fun OrbitTogglePreview() {
OrbitTheme {
var isSelected by remember { mutableStateOf(false) }

OrbitSwitch(
isSelected = isSelected,
onClick = {
isSelected = it
},
)
var isEnabled by remember { mutableStateOf(true) }

Column {
OrbitSwitch(
isChecked = isSelected,
isEnabled = isEnabled,
onClick = {
isSelected = !isSelected
},
)
Spacer(modifier = Modifier.height(20.dp))
Button(
onClick = {
isEnabled = !isEnabled
},
) {
Text(
text = "์Šค์œ„์น˜ ํ™œ์„ฑํ™” ์—ฌ๋ถ€ ๋ฐ˜์˜",
style = OrbitTheme.typography.title2Medium,
)
}
}
}
}
34 changes: 32 additions & 2 deletions feature/home/src/main/java/com/yapp/alarm/AlarmAddEditContract.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,52 @@ import com.yapp.ui.base.UiState
sealed class AlarmAddEditContract {

data class State(
val timeState: AlarmTimeState = AlarmTimeState(),
val daySelectionState: AlarmDaySelectionState = AlarmDaySelectionState(),
val holidayState: AlarmHolidayState = AlarmHolidayState(),
val snoozeState: AlarmSnoozeState = AlarmSnoozeState(),
) : UiState

data class AlarmTimeState(
val currentAmPm: String = "์˜ค์ „",
val currentHour: Int = 6,
val currentHour: Int = 1,
val currentMinute: Int = 0,
val alarmMessage: String = "",
)

data class AlarmDaySelectionState(
val days: Set<AlarmDay> = enumValues<AlarmDay>().toSet(),
val isWeekdaysChecked: Boolean = false,
val isWeekendsChecked: Boolean = false,
val selectedDays: Set<AlarmDay> = setOf(),
)

data class AlarmHolidayState(
val isDisableHolidayEnabled: Boolean = false,
val isDisableHolidayChecked: Boolean = false,
) : UiState
)

data class AlarmSnoozeState(
val isSnoozeEnabled: Boolean = true,
val snoozeIntervalIndex: Int = 2,
val snoozeCountIndex: Int = 1,
val isBottomSheetOpen: Boolean = false,
val snoozeIntervals: List<String> = listOf("1๋ถ„", "3๋ถ„", "5๋ถ„", "10๋ถ„", "15๋ถ„"),
val snoozeCounts: List<String> = listOf("1ํšŒ", "3ํšŒ", "5ํšŒ", "10ํšŒ", "๋ฌดํ•œ"),
)

sealed class Action {
data object ClickBack : Action()
data object ClickSave : Action()
data class UpdateAlarmTime(val amPm: String, val hour: Int, val minute: Int) : Action()
data object ToggleWeekdaysChecked : Action()
data object ToggleWeekendsChecked : Action()
data class ToggleDaySelection(val day: AlarmDay) : Action()
data object ToggleDisableHolidayChecked : Action()
data object ToggleSnoozeSettingBottomSheetOpen : Action()
data object ToggleSnoozeEnabled : Action()
data class UpdateSnoozeInterval(val index: Int) : Action()
data class UpdateSnoozeCount(val index: Int) : Action()
}

sealed class SideEffect : com.yapp.ui.base.SideEffect {
Expand Down
Loading

0 comments on commit 0bfc6c8

Please sign in to comment.