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

[#331] 온보딩 화면 #333

Merged
merged 8 commits into from
Oct 3, 2024
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 @@ -155,12 +155,21 @@ class LocalDataSourceImpl @Inject constructor(
return getBoolean(KEY_VOTE_FIRST_VISIT, true)
}

override fun saveIsFirstOpen(isFirstOpen: Boolean) {
putBoolean(KEY_IS_FIRST_OPEN, isFirstOpen)
}

override fun getIsFirstOpen(): Boolean {
return getBoolean(KEY_IS_FIRST_OPEN, true)
}

companion object {
private const val TAG = "preferences"
private const val PREF_NAME = "pic_preferences"
private const val KEY_ACCESS_TOKEN = "key_access_token"
private const val KEY_REFRESH_TOKEN = "key_refresh_token"
private const val KEY_USER_NAME = "key_user_name"
private const val KEY_VOTE_FIRST_VISIT = "key_vote_first_visit"
private const val KEY_IS_FIRST_OPEN = "key_is_first_open"
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package com.mashup.gabbangzip.sharedalbum.data.di

import com.mashup.gabbangzip.sharedalbum.data.repository.ConfigRepositoryImpl
import com.mashup.gabbangzip.sharedalbum.data.repository.EventRepositoryImpl
import com.mashup.gabbangzip.sharedalbum.data.repository.FileRepositoryImpl
import com.mashup.gabbangzip.sharedalbum.data.repository.GroupRepositoryImpl
import com.mashup.gabbangzip.sharedalbum.data.repository.LoginRepositoryImpl
import com.mashup.gabbangzip.sharedalbum.data.repository.NotificationRepositoryImpl
import com.mashup.gabbangzip.sharedalbum.data.repository.UserRepositoryImpl
import com.mashup.gabbangzip.sharedalbum.data.repository.VoteRepositoryImpl
import com.mashup.gabbangzip.sharedalbum.domain.repository.ConfigRepository
import com.mashup.gabbangzip.sharedalbum.domain.repository.EventRepository
import com.mashup.gabbangzip.sharedalbum.domain.repository.FileRepository
import com.mashup.gabbangzip.sharedalbum.domain.repository.GroupRepository
Expand Down Expand Up @@ -50,4 +52,8 @@ interface RepositoryModule {
@Singleton
@Binds
fun bindEventRepository(eventRepository: EventRepositoryImpl): EventRepository

@Singleton
@Binds
fun bindConfigRepository(configRepositoryImpl: ConfigRepositoryImpl): ConfigRepository
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.mashup.gabbangzip.sharedalbum.data.repository

import com.mashup.gabbangzip.sharedalbum.domain.datasource.LocalDataSource
import com.mashup.gabbangzip.sharedalbum.domain.repository.ConfigRepository
import javax.inject.Inject

class ConfigRepositoryImpl @Inject constructor(
private val localDataSource: LocalDataSource,
) : ConfigRepository {
override suspend fun saveIsFirstOpen(isFirstOpen: Boolean) {
localDataSource.saveIsFirstOpen(isFirstOpen)
}

override suspend fun getIsFirstOpen(): Boolean {
return localDataSource.getIsFirstOpen()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,6 @@ interface LocalDataSource {
fun removeUserInfo()
fun saveVoteFirstVisit(isFirstVisit: Boolean)
fun getVoteFirstVisit(): Boolean
fun saveIsFirstOpen(isFirstOpen: Boolean)
fun getIsFirstOpen(): Boolean
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.mashup.gabbangzip.sharedalbum.domain.repository

interface ConfigRepository {
oreocube marked this conversation as resolved.
Show resolved Hide resolved
suspend fun saveIsFirstOpen(isFirstOpen: Boolean)
suspend fun getIsFirstOpen(): Boolean
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.mashup.gabbangzip.sharedalbum.domain.usecase.config

import com.mashup.gabbangzip.sharedalbum.domain.repository.ConfigRepository
import javax.inject.Inject

class GetIsFirstOpenUseCase @Inject constructor(
private val configRepository: ConfigRepository,
) {
suspend operator fun invoke(): Result<Boolean> {
return runCatching {
configRepository.getIsFirstOpen()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.mashup.gabbangzip.sharedalbum.domain.usecase.config

import com.mashup.gabbangzip.sharedalbum.domain.repository.ConfigRepository
import javax.inject.Inject

class SaveIsFirstOpenUseCase @Inject constructor(
private val configRepository: ConfigRepository,
) {
suspend operator fun invoke(isFirstOpen: Boolean) {
configRepository.saveIsFirstOpen(isFirstOpen)
}
}
6 changes: 6 additions & 0 deletions presentation/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@
android:screenOrientation="portrait"
tools:ignore="DiscouragedApi" />

<activity
android:name="com.mashup.gabbangzip.sharedalbum.presentation.ui.onboarding.OnboardingActivity"
android:exported="false"
android:screenOrientation="portrait"
tools:ignore="DiscouragedApi" />

<activity
android:name="com.kakao.sdk.auth.AuthCodeHandlerActivity"
android:exported="true"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package com.mashup.gabbangzip.sharedalbum.presentation.ui.common

import androidx.annotation.IntRange
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
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.ui.Modifier
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.mashup.gabbangzip.sharedalbum.presentation.theme.Gray50
import com.mashup.gabbangzip.sharedalbum.presentation.theme.Gray80

@Composable
fun PicHorizontalDotIndicator(
circleSize: Dp,
selectedColor: Color,
unselectedColor: Color,
@IntRange(from = 1) totalPage: Int,
@IntRange(from = 1) currentPage: Int,
indicatorSpacing: Dp,
) {
Row {
for (i in 1..totalPage) {
CircleUi(
modifier = Modifier.padding(start = if (i > 1) indicatorSpacing else 0.dp),
size = circleSize,
color = if (currentPage == i) selectedColor else unselectedColor,
)
}
}
}

@Composable
private fun CircleUi(
modifier: Modifier = Modifier,
size: Dp,
color: Color,
) {
Box(
modifier = modifier
.size(size)
.background(color, shape = CircleShape),
)
}

@Preview(showBackground = true)
@Composable
private fun HorizontalDotIndicatorPreview() {
PicHorizontalDotIndicator(
circleSize = 50.dp,
selectedColor = Gray80,
unselectedColor = Gray50,
totalPage = 4,
currentPage = 2,
indicatorSpacing = 30.dp,
)
}

@Preview(showBackground = true)
@Composable
private fun CircleUiPreview() {
CircleUi(Modifier, 50.dp, Gray50)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.mashup.gabbangzip.sharedalbum.presentation.ui.onboarding

import android.app.Activity
import android.content.Intent
import android.graphics.Color
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.SystemBarStyle
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.ui.Modifier
import com.mashup.gabbangzip.sharedalbum.presentation.R
import com.mashup.gabbangzip.sharedalbum.presentation.theme.SharedAlbumTheme
import com.mashup.gabbangzip.sharedalbum.presentation.ui.login.LoginActivity
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class OnboardingActivity : ComponentActivity() {
private val viewModel by viewModels<OnboardingViewModel>()
private val pageResourceIdList = listOf(
R.drawable.onboarding_1,
R.drawable.onboarding_2,
R.drawable.onboarding_3,
R.drawable.onboarding_4,
)

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge(
SystemBarStyle.light(
Color.TRANSPARENT,
Color.TRANSPARENT,
),
)
setContent {
SharedAlbumTheme {
Scaffold { contentPadding ->
Box(modifier = Modifier.padding(contentPadding)) {
oreocube marked this conversation as resolved.
Show resolved Hide resolved
OnboardingScreen(
pageResourceIdList = pageResourceIdList,
onClickStart = {
viewModel.saveIsNotFirstOpen()
LoginActivity.openActivity(this@OnboardingActivity)
},
)
}
}
}
}
}

companion object {
fun openActivity(context: Activity) {
context.startActivity(
Intent(context, OnboardingActivity::class.java),
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package com.mashup.gabbangzip.sharedalbum.presentation.ui.onboarding

import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.mashup.gabbangzip.sharedalbum.presentation.R
import com.mashup.gabbangzip.sharedalbum.presentation.theme.Gray50
import com.mashup.gabbangzip.sharedalbum.presentation.theme.Gray80
import com.mashup.gabbangzip.sharedalbum.presentation.ui.common.PicButton
import com.mashup.gabbangzip.sharedalbum.presentation.ui.common.PicHorizontalDotIndicator
import com.mashup.gabbangzip.sharedalbum.presentation.utils.StableImage

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun OnboardingScreen(
pageResourceIdList: List<Int>,
onClickStart: () -> Unit,
) {
val pagerState = rememberPagerState { pageResourceIdList.size }
val pageDescription = stringResource(id = R.string.page_description)

Box(modifier = Modifier.fillMaxSize()) {
HorizontalPager(
modifier = Modifier.fillMaxSize(),
state = pagerState,
) { page ->
StableImage(
modifier = Modifier.fillMaxSize(),
drawableResId = pageResourceIdList[page],
contentDescription = pageDescription.format(page),
contentScale = ContentScale.FillWidth,
)
}
Column(
modifier = Modifier
.padding(bottom = 16.dp, start = 21.dp, end = 21.dp)
.fillMaxWidth()
.align(Alignment.BottomCenter),
horizontalAlignment = Alignment.CenterHorizontally,
) {
PicHorizontalDotIndicator(
circleSize = 8.dp,
selectedColor = Gray80,
unselectedColor = Gray50,
totalPage = pagerState.pageCount,
currentPage = pagerState.currentPage + 1,
indicatorSpacing = 10.dp,
)
PicButton(
modifier = Modifier
.fillMaxWidth()
.padding(top = 32.dp),
text = stringResource(id = R.string.start),
onButtonClicked = onClickStart,
)
}
}
}

@Preview(showBackground = true)
@Composable
private fun OnboardingScreenPreview() {
OnboardingScreen(
pageResourceIdList = listOf(),
onClickStart = {},
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.mashup.gabbangzip.sharedalbum.presentation.ui.onboarding

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.mashup.gabbangzip.sharedalbum.domain.usecase.config.SaveIsFirstOpenUseCase
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class OnboardingViewModel @Inject constructor(
private val saveIsFirstOpenUseCase: SaveIsFirstOpenUseCase,
) : ViewModel() {
fun saveIsNotFirstOpen() {
viewModelScope.launch {
saveIsFirstOpenUseCase(false)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.mashup.gabbangzip.sharedalbum.presentation.theme.SharedAlbumTheme
import com.mashup.gabbangzip.sharedalbum.presentation.ui.login.LoginActivity
import com.mashup.gabbangzip.sharedalbum.presentation.ui.main.MainActivity
import com.mashup.gabbangzip.sharedalbum.presentation.ui.onboarding.OnboardingActivity
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
Expand Down Expand Up @@ -55,18 +56,20 @@ class SplashActivity : ComponentActivity() {
SplashScreen()
}

when (state.isUserLoggedIn) {
true -> {
when {
state.isFirstOpen == true -> {
OnboardingActivity.openActivity(this)
finish()
}
state.isFirstOpen == false && state.isUserLoggedIn == true -> {
MainActivity.openActivity(this)
finish()
}

false -> {
state.isFirstOpen == false && state.isUserLoggedIn == false -> {
LoginActivity.openActivity(this)
finish()
}

else -> {}
else -> Unit // isFirstOpen, isUserLoggedIn 업데이트를 기다리기
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ package com.mashup.gabbangzip.sharedalbum.presentation.ui.splash
data class SplashUiState(
val isLoading: Boolean = false,
val isUserLoggedIn: Boolean? = null,
val isFirstOpen: Boolean? = null,
)
Loading
Loading