Skip to content

Commit

Permalink
Merge pull request #11 from cgpathos/feat/RBP-20-splash
Browse files Browse the repository at this point in the history
[RBP-20] splash 화면 구현
  • Loading branch information
cgpathos authored May 6, 2024
2 parents 24fc250 + 778e52e commit 3a40c24
Show file tree
Hide file tree
Showing 13 changed files with 198 additions and 11 deletions.
1 change: 0 additions & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ android {

dependencies {
implementation(project(":presentation"))
implementation(project(":entity"))
implementation(project(":domain"))
implementation(project(":data"))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import today.pathos.android.portfolio.data.repository.OfflineFirstCacheRepository
import today.pathos.android.portfolio.data.repository.OfflineFirstCharacterRepository
import today.pathos.android.portfolio.data.repository.OfflineFirstFameRepository
import today.pathos.android.portfolio.domain.repository.CacheRepository
import today.pathos.android.portfolio.domain.repository.CharacterRepository
import today.pathos.android.portfolio.domain.repository.FameRepository

Expand All @@ -21,4 +23,9 @@ abstract class RepositoryModule {
abstract fun bindsCharacterRepository(
characterRepository: OfflineFirstCharacterRepository,
): CharacterRepository

@Binds
abstract fun bindsCacheRepository(
cacheRepository: OfflineFirstCacheRepository,
): CacheRepository
}
10 changes: 10 additions & 0 deletions app/src/main/res/values-v31/themes.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>

<style name="Theme.Portfolio" parent="android:Theme.Material.Light.NoActionBar">

<item name="android:windowSplashScreenAnimatedIcon">@android:color/transparent</item>
<item name="android:windowSplashScreenIconBackgroundColor">@color/white</item>
<item name="android:windowSplashScreenAnimationDuration">0</item>
</style>
</resources>
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package today.pathos.android.portfolio.data.datasource.local

import kotlinx.coroutines.flow.Flow
import today.pathos.android.portfolio.data.datasource.local.db.CacheDatabase
import today.pathos.android.portfolio.data.datasource.local.db.dao.CharacterDao
import today.pathos.android.portfolio.data.datasource.local.db.dao.FameDao
import today.pathos.android.portfolio.data.datasource.local.db.table.AvatarTbl
Expand All @@ -13,6 +14,7 @@ import today.pathos.android.portfolio.data.datasource.remote.dto.res.ResEquipmen
import javax.inject.Inject

class LocalDataSource @Inject constructor(
private val database: CacheDatabase,
private val fameDao: FameDao,
private val characterDao: CharacterDao,
) {
Expand Down Expand Up @@ -143,4 +145,8 @@ class LocalDataSource @Inject constructor(
}
)
}

suspend fun cleanCache() {
database.clearAllTables()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package today.pathos.android.portfolio.data.repository

import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.withContext
import today.pathos.android.portfolio.common.di.IoDispatcher
import today.pathos.android.portfolio.data.datasource.local.LocalDataSource
import today.pathos.android.portfolio.domain.repository.CacheRepository
import javax.inject.Inject

class OfflineFirstCacheRepository @Inject constructor(
private val localDataSource: LocalDataSource,
@IoDispatcher private val dispatcher: CoroutineDispatcher,
) : CacheRepository {
override suspend fun cleanCache() = withContext(dispatcher) {
localDataSource.cleanCache()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package today.pathos.android.portfolio.domain.repository

interface CacheRepository {
suspend fun cleanCache()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package today.pathos.android.portfolio.domain.usecase

import today.pathos.android.portfolio.domain.repository.CacheRepository
import today.pathos.android.portfolio.domain.repository.FameRepository
import javax.inject.Inject

class CleanupCacheUseCase @Inject constructor(
private val cacheRepository: CacheRepository,
) {

suspend operator fun invoke() {
cacheRepository.cleanCache()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,16 @@ fun PortfolioNavHost(

NavHost(
navController = navController,
startDestination = Main.route, // fixme: Splash 구현 끝나면 추가
startDestination = Splash.route, // fixme: Splash 구현 끝나면 추가
modifier = modifier
) {
composable(
route = Splash.route
) {
SplashRoute()
SplashRoute(
navigateToMain = { navController.navigateTo(Main.route, cleanHistory = true) },
closeApp = closeApp
)
}

composable(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package today.pathos.android.portfolio.presentation.view.screen

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import androidx.hilt.navigation.compose.hiltViewModel
import today.pathos.android.portfolio.presentation.composable.UiStateHandler
Expand Down Expand Up @@ -35,8 +38,10 @@ fun CharacterInfoScreen(
modifier: Modifier = Modifier,
) {
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
modifier = modifier.fillMaxSize()
.background(color = Color.Black)
) {
CharacterWithEquipment(
characterInfo = state.characterInfo,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,42 +1,105 @@
package today.pathos.android.portfolio.presentation.view.screen

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.flowWithLifecycle
import kotlinx.coroutines.flow.distinctUntilChanged
import today.pathos.android.portfolio.presentation.R
import today.pathos.android.portfolio.presentation.view.dialog.ErrorDialog
import today.pathos.android.portfolio.presentation.view.theme.Typography
import today.pathos.android.portfolio.presentation.viewmodel.SplashUiState
import today.pathos.android.portfolio.presentation.viewmodel.SplashViewModel

@Composable
fun SplashRoute(
navigateToMain: () -> Unit,
closeApp: () -> Unit,
modifier: Modifier = Modifier,
viewModel: SplashViewModel = hiltViewModel(),
) {
val state by viewModel.state.collectAsState()

SplashScreen(
state = state,
navigateToMain = navigateToMain,
closeApp = closeApp,
modifier = modifier
)
}

@Composable
fun SplashScreen(
state: SplashUiState,
navigateToMain: () -> Unit,
closeApp: () -> Unit,
modifier: Modifier = Modifier,
) {
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
modifier = modifier.fillMaxSize()
val lifecycle = LocalLifecycleOwner.current.lifecycle
LaunchedEffect(state) {
snapshotFlow { state }
.distinctUntilChanged()
.flowWithLifecycle(lifecycle)
.collect {
when (state) {
SplashUiState.Init -> {}
is SplashUiState.Error -> {
closeApp()
}

SplashUiState.NavigateToMain -> {
navigateToMain()
}
}
}
}

Box(
modifier = modifier
.fillMaxSize()
.padding(32.dp)
) {
Text(
text = "Splash Screen",
style = Typography.displayLarge
style = Typography.displayMedium,
modifier = Modifier.align(Alignment.Center)
)

Image(
painter = painterResource(id = R.drawable.neople_open_api_logo),
contentDescription = "Neople Open API Logo",
contentScale = ContentScale.Fit,
modifier = Modifier
.width(100.dp)
.aspectRatio(1.5f)
.align(Alignment.BottomEnd)
)
}
}

@Preview(showBackground = true)
@Composable
fun SplashScreenPreview() {
SplashScreen()
SplashScreen(
state = SplashUiState.Init,
navigateToMain = {},
closeApp = {}
)
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
package today.pathos.android.portfolio.presentation.viewmodel

import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
import today.pathos.android.portfolio.common.result.Result
import today.pathos.android.portfolio.common.result.asResult
Expand All @@ -23,6 +27,9 @@ class MainViewModel @Inject constructor(

val state: StateFlow<Result<MainUiState>> =
mainUiState(repository)
.onStart { Log.w("UiStateHandler", ":start") }
.onEach { Log.w("UiStateHandler", ":emit") }
.distinctUntilChanged()
.stateIn(
scope = viewModelScope,
started = SharingStarted.Eagerly,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package today.pathos.android.portfolio.presentation.viewmodel

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import today.pathos.android.portfolio.domain.usecase.CleanupCacheUseCase
import javax.inject.Inject

@HiltViewModel
class SplashViewModel @Inject constructor(
val cleanupCacheUseCase: CleanupCacheUseCase,
) : ViewModel() {
private val _state = MutableStateFlow<SplashUiState>(SplashUiState.Init)
val state: StateFlow<SplashUiState> = _state
.onStart {
initApp()
}
.catch { e ->
_state.update { SplashUiState.Error(e.message.toString()) }
}
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5000),
initialValue = SplashUiState.Init
)

private fun initApp() {
viewModelScope.launch {
cleanupCacheUseCase()
delay(2000) // 스플래시 화면을 잠시 보여주기 위한 딜레이

_state.update { SplashUiState.NavigateToMain }
}
}
}


sealed class SplashUiState {
data object Init : SplashUiState()
data class Error(val msg: String) : SplashUiState()
data object NavigateToMain : SplashUiState()
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 3a40c24

Please sign in to comment.