Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[UI/YAF-79] 알람 설정 시 사운드 설정을 할 수 있다 #49

Merged
merged 10 commits into from
Jan 20, 2025

Conversation

DongChyeon
Copy link
Member

@DongChyeon DongChyeon commented Jan 19, 2025

Related issue 🛠

closed #48

어떤 변경사항이 있었나요?

  • 🐞 BugFix Something isn't working
  • 🎨 Design Markup & styling
  • 📃 Docs Documentation writing and editing (README.md, etc.)
  • ✨ Feature Feature
  • 🔨 Refactor Code refactoring
  • ⚙️ Setting Development environment setup
  • ✅ Test Test related (Junit, etc.)

CheckPoint ✅

PR이 다음 요구 사항을 충족하는지 확인하세요.

  • PR 컨벤션에 맞게 작성했습니다. (필수)
  • merge할 브랜치의 위치를 확인해 주세요(main❌/develop⭕) (필수)
  • Approve된 PR은 assigner가 머지하고, 수정 요청이 온 경우 수정 후 다시 push를 합니다. (필수)
  • BugFix의 경우, 버그의 원인을 파악하였습니다. (선택)

Work Description ✏️

default.mp4
  • 알람 미루기, 사운드 설정 바텀시트 상단 패딩값 수정
  • Slider 구현
  • 사운드 설정 바텀시트 연동

Uncompleted Tasks 😅

  • N/A

To Reviewers 📢

val snoozeBottomSheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
val soundBottomSheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
val scope = rememberCoroutineScope()

AlarmSnoozeBottomSheet(
    isSnoozeEnabled = snoozeState.isSnoozeEnabled,
    snoozeIntervalIndex = snoozeState.snoozeIntervalIndex,
    snoozeCountIndex = snoozeState.snoozeCountIndex,
    snoozeIntervals = snoozeState.snoozeIntervals,
    snoozeCounts = snoozeState.snoozeCounts,
    onSnoozeToggle = { eventDispatcher(AlarmAddEditContract.Action.ToggleSnoozeEnabled) },
    onIntervalSelected = { index -> eventDispatcher(AlarmAddEditContract.Action.UpdateSnoozeInterval(index)) },
    onCountSelected = { index -> eventDispatcher(AlarmAddEditContract.Action.UpdateSnoozeCount(index)) },
    onComplete = {
        scope.launch {
            snoozeBottomSheetState.hide()
        }.invokeOnCompletion {
            eventDispatcher(AlarmAddEditContract.Action.ToggleSnoozeSettingBottomSheetOpen)
        }
    },
    isSheetOpen = snoozeState.isBottomSheetOpen,
    onDismiss = {
        scope.launch {
            snoozeBottomSheetState.hide()
        }.invokeOnCompletion {
            eventDispatcher(AlarmAddEditContract.Action.ToggleSnoozeSettingBottomSheetOpen)
        }
    },
)

AlarmSoundBottomSheet(
    isVibrationEnabled = state.soundState.isVibrationEnabled,
    isSoundEnabled = state.soundState.isSoundEnabled,
    soundVolume = state.soundState.soundVolume,
    soundIndex = state.soundState.soundIndex,
    sounds = state.soundState.sounds,
    onVibrationToggle = { eventDispatcher(AlarmAddEditContract.Action.ToggleVibrationEnabled) },
    onSoundToggle = { eventDispatcher(AlarmAddEditContract.Action.ToggleSoundEnabled) },
    onVolumeChanged = { eventDispatcher(AlarmAddEditContract.Action.UpdateSoundVolume(it)) },
    onSoundSelected = { eventDispatcher(AlarmAddEditContract.Action.UpdateSoundIndex(it)) },
    onComplete = {
        scope.launch {
            soundBottomSheetState.hide()
        }.invokeOnCompletion {
            eventDispatcher(AlarmAddEditContract.Action.ToggleSoundSettingBottomSheetOpen)
        }
    },
    isSheetOpen = state.soundState.isBottomSheetOpen,
    onDismiss = {
        scope.launch {
            soundBottomSheetState.hide()
        }.invokeOnCompletion {
            eventDispatcher(AlarmAddEditContract.Action.ToggleSoundSettingBottomSheetOpen)
        }
    },
)

바텀 시트 하나당 BottomSheetState 관리해야 되는게 별로인 것 같아서
나중에 ModalBottomSheetLayout 으로 마이그레이션 고려중입니다...

앞으로 한 화면에 BottomSheet가 여러개면 BottomSheetState 도 여러 개가 될 것 같아서
더 좋은 의견 있으면 말씀해주세요.

@DongChyeon DongChyeon added 📱 UI 사용자 인터페이스 관련 작업 💪 동현동현동현동현동현 labels Jan 19, 2025
@DongChyeon DongChyeon requested a review from MoonsuKang January 19, 2025 17:35
@DongChyeon DongChyeon self-assigned this Jan 19, 2025
Copy link
Member

@MoonsuKang MoonsuKang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수고하셨습니다.
ModalBottomSheetLayout로 마이그레이션 밖에 생각 안나긴 하네요
음 Enum type SNOOZE, SOUND 정의해서 type 별로 처리하는 방법도 추가하면 좋을듯?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p3
파일명?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image
전부 다 Orbit 접두사 쓰도록 바꿀까요??

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

네네 공통 컴포넌트는 Orbit 접두사 쓰는걸로 하죠!

Comment on lines 56 to 60
.onSizeChanged {
size ->
sliderSize = size
thumbX = startOffset + (value / 100f) * (sliderSize.width - startOffset * 2)
},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p4
slidersize가 변경될때마다 thumbx를 초기화한다? 라고 이해하면 될까요?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

사이즈가 바뀔일은 없으므로
최초 sliderSize와 thumbX를 받아오는 부분을 저기에 넣었었습니다.

현재 코드는 로직 수정했습니다.

Comment on lines 49 to 74
Canvas(
modifier = modifier
.fillMaxWidth()
.height(trackHeight)
.align(Alignment.Center)
.clip(RoundedCornerShape(100.dp)),
) {
val totalWidth = size.width
val activeWidth = thumbX

drawRect(
color = activeBarColor,
size = size.copy(width = activeWidth),
)

drawRect(
color = inactiveBarColor,
topLeft = Offset(activeWidth, 0f),
size = size.copy(width = totalWidth - activeWidth),
)
}

Canvas(
modifier = modifier
.fillMaxWidth()
.height(thumbSize)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p2
칸바를 두개 사용해서 트랙이랑 슬라이더를 그리고 있잖아요?
그러면 제가 생각하기엔 overDraw인거 같은데 혹시 단일 canva 내에서 처리하도록 해보심이 어떠십니까?
참고로 이런 것도 있음

    fun drawRoundRect(
        brush: Brush,
        topLeft: Offset = Offset.Zero,
        size: Size = this.size.offsetSize(topLeft),
        cornerRadius: CornerRadius = CornerRadius.Zero,
        @FloatRange(from = 0.0, to = 1.0) alpha: Float = 1.0f,
        style: DrawStyle = Fill,
        colorFilter: ColorFilter? = null,
        blendMode: BlendMode = DefaultBlendMode
    )

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Composable
fun OrbitSlider(
    value: Int,
    onValueChange: (Int) -> Unit,
    modifier: Modifier = Modifier,
    trackHeight: Dp = 6.dp,
    thumbSize: Dp = 22.dp,
    thumbColor: Color = Color.White,
    inactiveBarColor: Color = OrbitTheme.colors.gray_600,
    activeBarColor: Color = OrbitTheme.colors.main,
) {
    val thumbRadius = thumbSize.toPx() / 2
    var sliderWidth by remember { mutableFloatStateOf(0f) }
    val startOffset = thumbRadius + 1.dp.toPx()

    var thumbX = remember(value, startOffset, sliderWidth) {
        startOffset + (value / 100f) * (sliderWidth - startOffset * 2)
    }

    var isDragging by remember { mutableStateOf(false) }

    Canvas(
        modifier = modifier
            .fillMaxWidth()
            .height(thumbSize)
            .pointerInput(Unit) {
                detectTapGestures(
                    onPress = { offset ->
                        isDragging = isInCircle(
                            offset.x,
                            offset.y,
                            thumbX,
                            thumbRadius,
                            thumbRadius,
                        )
                    },
                )
            }
            .pointerInput(Unit) {
                detectHorizontalDragGestures(
                    onDragEnd = { isDragging = false },
                ) { _, dragAmount ->
                    if (isDragging) {
                        thumbX += dragAmount
                        thumbX = thumbX.coerceIn(startOffset, sliderWidth - startOffset)
                        val newValue = (((thumbX - startOffset) / (sliderWidth - 2 * startOffset)) * 100)
                            .toInt()
                            .coerceIn(0, 100)
                        onValueChange(newValue)
                    }
                }
            },
    ) {
        sliderWidth = size.width

        val normalizedThumbX by derivedStateOf {
            thumbX.coerceIn(startOffset, sliderWidth - startOffset)
        }
        val activeWidth = (normalizedThumbX - startOffset).coerceAtLeast(0f)

        drawRoundRect(
            color = activeBarColor,
            size = Size(activeWidth + 3.dp.toPx(), trackHeight.toPx()),
            topLeft = Offset(0f, (size.height - trackHeight.toPx()) / 2),
            cornerRadius = CornerRadius(100.dp.toPx(), 100.dp.toPx()),
        )

        drawRoundRect(
            color = inactiveBarColor,
            size = Size(size.width - activeWidth - 5.dp.toPx(), trackHeight.toPx()),
            topLeft = Offset(activeWidth + 2.dp.toPx(), (size.height - trackHeight.toPx()) / 2),
            cornerRadius = CornerRadius(100.dp.toPx(), 100.dp.toPx()),
        )

        drawCircle(
            color = thumbColor,
            radius = thumbSize.toPx() / 2,
            center = Offset(normalizedThumbX, size.height / 2),
        )
    }
}

canvas 하나만 쓰도록 변경 완료!!

.height(trackHeight)
.align(Alignment.Center),
) {
val normalizedThumbX = thumbX.coerceIn(startOffset, sliderSize.width - startOffset)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p4

Suggested change
val normalizedThumbX = thumbX.coerceIn(startOffset, sliderSize.width - startOffset)
val normalizedThumbX by derivedStateOf {
thumbX.coerceIn(startOffset, sliderSize.width - startOffset)
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

위와 동일

import com.yapp.ui.base.BaseViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class AlarmAddEditViewModel @Inject constructor() : BaseViewModel<AlarmAddEditContract.State, AlarmAddEditContract.SideEffect>(
initialState = AlarmAddEditContract.State(),
) {
fun processAction(action: AlarmAddEditContract.Action) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ㅋㅋ 상태가 쫌 많긴 하네요

@DongChyeon DongChyeon merged commit 1ee79e2 into develop Jan 20, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
💪 동현동현동현동현동현 📱 UI 사용자 인터페이스 관련 작업
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[UI] 알람 설정 시 사운드 설정을 할 수 있다
2 participants