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
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,11 @@ package com.hilingual.core.designsystem.component.bottomsheet
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.ModalBottomSheetProperties
import androidx.compose.material3.SheetState
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
Expand All @@ -38,6 +37,7 @@ fun HilingualBasicBottomSheet(
sheetState: SheetState = rememberModalBottomSheetState(
skipPartiallyExpanded = true
),
properties: ModalBottomSheetProperties = ModalBottomSheetProperties(),
Copy link
Member

Choose a reason for hiding this comment

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

이거 정식 도입 됐구나ㅋㅋ

isDimEnabled: Boolean = true,
dragHandle: (@Composable () -> Unit)? = null,
content: @Composable () -> Unit
Expand All @@ -58,7 +58,8 @@ fun HilingualBasicBottomSheet(
containerColor = HilingualTheme.colors.white,
scrimColor = if (isDimEnabled) HilingualTheme.colors.dim1 else Color.Transparent,
shape = RoundedCornerShape(topStart = 12.dp, topEnd = 12.dp),
dragHandle = dragHandle
dragHandle = dragHandle,
properties = properties
) {
content()
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package com.hilingual.core.designsystem.component.indicator

import androidx.compose.animation.core.FastOutSlowInEasing
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.core.tween
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.hilingual.core.designsystem.theme.HilingualTheme
import kotlinx.coroutines.delay

@Composable
fun HilingualPagerIndicator(
pageCount: Int,
currentPage: Int,
modifier: Modifier = Modifier,
indicatorHeight: Dp = 8.dp,
indicatorSpacing: Dp = 8.dp,
activeIndicatorWidth: Dp = 20.dp,
inactiveIndicatorWidth: Dp = 8.dp,
activeIndicatorColor: Color = HilingualTheme.colors.hilingualOrange,
inactiveIndicatorColor: Color = HilingualTheme.colors.gray200
) {
if (pageCount <= 0) return
val selectedPage = currentPage.coerceIn(0, pageCount - 1)

val indicatorModifier = Modifier
.height(indicatorHeight)
.clip(CircleShape)

Row(
modifier = modifier,
horizontalArrangement = Arrangement.spacedBy(indicatorSpacing),
verticalAlignment = Alignment.CenterVertically
) {
repeat(pageCount) { index ->
val isSelected = index == selectedPage

val animatedWidth by animateDpAsState(
targetValue = if (isSelected) activeIndicatorWidth else inactiveIndicatorWidth,
animationSpec = tween(
durationMillis = 300,
easing = FastOutSlowInEasing
),
label = "indicatorWidth"
)

Box(
modifier = indicatorModifier
.width(animatedWidth)
.background(
color = if (isSelected) activeIndicatorColor else inactiveIndicatorColor
)
)
}
}
}

@Preview
@Composable
private fun HilingualPagerIndicatorPreview() {
val pageCount = 4
var currentPage by remember { mutableIntStateOf(0) }

LaunchedEffect(Unit) {
while (true) {
delay(1_000L)
currentPage = (currentPage + 1) % pageCount
}
}

HilingualTheme {
HilingualPagerIndicator(
pageCount = pageCount,
currentPage = currentPage
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.hilingual.core.localstorage

interface OnboardingStateManager {
suspend fun getIsHomeOnboardingCompleted(): Boolean

suspend fun updateIsHomeOnboardingCompleted(isCompleted: Boolean)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.hilingual.core.localstorage

import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.edit
import javax.inject.Inject
import kotlinx.coroutines.flow.first

class OnboardingStateManagerImpl @Inject constructor(
private val dataStore: DataStore<Preferences>
) : OnboardingStateManager {
private object PreferencesKeys {
val IS_HOME_ONBOARDING_COMPLETED = booleanPreferencesKey("is_home_onboarding_completed")
}

override suspend fun getIsHomeOnboardingCompleted(): Boolean =
dataStore.data.first()[PreferencesKeys.IS_HOME_ONBOARDING_COMPLETED] ?: true

override suspend fun updateIsHomeOnboardingCompleted(isCompleted: Boolean) {
dataStore.edit { preferences ->
preferences[PreferencesKeys.IS_HOME_ONBOARDING_COMPLETED] = isCompleted
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ object DataStoreConstant {
const val HILINGUAL_USER_INFO_PREFS = "hilingual_user_info_prefs"
const val ENCRYPTED_USER_PREFS = "encrypted_user_prefs.bin"
const val HILINGUAL_DIARY_TEMP_PREFS = "hilingual_diary_temp_prefs"
const val HILINGUAL_ONBOARDING_STATE_PREFS = "hilingual_onboarding_state_prefs"
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import androidx.datastore.dataStore
import androidx.datastore.preferences.preferencesDataStore
import com.hilingual.core.localstorage.DiaryTempManager
import com.hilingual.core.localstorage.DiaryTempManagerImpl
import com.hilingual.core.localstorage.OnboardingStateManager
import com.hilingual.core.localstorage.OnboardingStateManagerImpl
import com.hilingual.core.localstorage.TokenManager
import com.hilingual.core.localstorage.TokenManagerImpl
import com.hilingual.core.localstorage.UserInfoManager
Expand All @@ -46,6 +48,7 @@ object LocalStorageModule {
serializer = UserPreferencesSerializer
)
private val Context.diaryTempDataStore by preferencesDataStore(name = DataStoreConstant.HILINGUAL_DIARY_TEMP_PREFS)
private val Context.onboardingStateDataStore by preferencesDataStore(name = DataStoreConstant.HILINGUAL_ONBOARDING_STATE_PREFS)

@Provides
@Singleton
Expand All @@ -67,4 +70,12 @@ object LocalStorageModule {
dataStore = context.diaryTempDataStore,
imageStorage = imageStorage
)

@Provides
@Singleton
fun provideOnboardingStateManager(
@ApplicationContext context: Context
): OnboardingStateManager = OnboardingStateManagerImpl(
dataStore = context.onboardingStateDataStore
)
}
1 change: 1 addition & 0 deletions data/onboarding/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
9 changes: 9 additions & 0 deletions data/onboarding/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import com.hilingual.buildlogic.setNamespace

plugins {
alias(libs.plugins.hilingual.android.data)
}

android {
setNamespace("data.onboarding")
}
4 changes: 4 additions & 0 deletions data/onboarding/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.hilingual.data.onboarding.di

import com.hilingual.data.onboarding.repository.OnboardingRepository
import com.hilingual.data.onboarding.repositoryimpl.OnboardingRepositoryImpl
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import jakarta.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
internal abstract class RepositoryModule {
@Binds
@Singleton
abstract fun bindOnboardingRepository(impl: OnboardingRepositoryImpl): OnboardingRepository
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.hilingual.data.onboarding.repository

interface OnboardingRepository {
suspend fun getIsHomeOnboardingCompleted(): Result<Boolean>

suspend fun updateIsHomeOnboardingCompleted(isCompleted: Boolean): Result<Unit>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.hilingual.data.onboarding.repositoryimpl

import com.hilingual.core.common.util.suspendRunCatching
import com.hilingual.core.localstorage.OnboardingStateManager
import com.hilingual.data.onboarding.repository.OnboardingRepository
import javax.inject.Inject

class OnboardingRepositoryImpl @Inject constructor(
private val onboardingStateManager: OnboardingStateManager
) : OnboardingRepository {
override suspend fun getIsHomeOnboardingCompleted(): Result<Boolean> =
suspendRunCatching {
onboardingStateManager.getIsHomeOnboardingCompleted()
}

override suspend fun updateIsHomeOnboardingCompleted(isCompleted: Boolean): Result<Unit> =
suspendRunCatching {
onboardingStateManager.updateIsHomeOnboardingCompleted(isCompleted = isCompleted)
}
}
1 change: 1 addition & 0 deletions presentation/home/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,5 @@ dependencies {
implementation(projects.data.user)
implementation(projects.data.diary)
implementation(projects.data.calendar)
implementation(projects.data.onboarding)
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ import androidx.compose.material3.HorizontalDivider
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
Expand Down Expand Up @@ -79,6 +78,8 @@ import com.hilingual.presentation.home.component.footer.DiaryTimeInfo
import com.hilingual.presentation.home.component.footer.HomeDropDownMenu
import com.hilingual.presentation.home.component.footer.TodayTopic
import com.hilingual.presentation.home.component.footer.WriteDiaryButton
import com.hilingual.presentation.home.component.onboarding.HomeOnboardingBottomSheet
import com.hilingual.presentation.home.component.onboarding.HomeOnboardingContent
import com.hilingual.presentation.home.type.DiaryCardState
import java.time.LocalDate
import java.time.YearMonth
Expand Down Expand Up @@ -135,6 +136,8 @@ internal fun HomeRoute(
is HomeSideEffect.RequestNotificationPermission -> {
notificationPermissionLauncher.launch(sideEffect.permission)
}

is HomeSideEffect.ShowOnboarding -> homeState.showOnboardingBottomSheet()
}
}

Expand Down Expand Up @@ -194,6 +197,15 @@ internal fun HomeRoute(

else -> {}
}

HomeOnboardingBottomSheet(
isVisible = homeState.isOnboardingBottomSheetVisible,
onCloseButtonClick = homeState::hideOnboardingBottomSheet
) {
HomeOnboardingContent(
onStartButtonClick = homeState::hideOnboardingBottomSheet
)
}
}

@Composable
Expand Down Expand Up @@ -400,6 +412,7 @@ private fun CheckNotificationPermission(
Manifest.permission.POST_NOTIFICATIONS
) == PackageManager.PERMISSION_GRANTED
}

else -> true
}
onCheck(isGranted, requiresPermission)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ class HomeState(
var isMoreMenuExpanded by mutableStateOf(false)
private set

var isOnboardingBottomSheetVisible by mutableStateOf(false)
private set

var onErrorRetry: (() -> Unit)? = null
private set

Expand Down Expand Up @@ -65,6 +68,14 @@ class HomeState(
fun hideMoreMenu() {
isMoreMenuExpanded = false
}

fun showOnboardingBottomSheet() {
isOnboardingBottomSheetVisible = true
}

fun hideOnboardingBottomSheet() {
isOnboardingBottomSheetVisible = false
}
}

@Composable
Expand Down
Loading
Loading