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

[Feature/#66] splash 로띠 #70

Merged
merged 18 commits into from
Sep 5, 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 @@ -18,7 +18,7 @@ internal class DefaultPostingRepository @Inject constructor(
override suspend fun postingMultiPart(title: String, content: String, uriImage: String?): Result<Unit> {
return runCatching {
val textRequestBody = createContentRequestBody(title, content)
val imagePart = contentResolver.createImagePart(uriImage)
val imagePart = contentResolver.createImagePart(uriImage, FILE_NAME)

postingService.postingMultiPart(textRequestBody, imagePart)
Unit
Expand All @@ -32,4 +32,8 @@ internal class DefaultPostingRepository @Inject constructor(
}.toString()
return contentJson.toRequestBody("application/json".toMediaTypeOrNull())
}

companion object {
private const val FILE_NAME = "image"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ internal class DefaultProfileRepository @Inject constructor(

override suspend fun patchUserProfile(info: MemberInfoEditModel, imgUrl: String?): Result<Unit> = runCatching {
val infoRequestBody = createContentRequestBody(info)
val filePart = contentResolver.createImagePart(imgUrl)
val filePart = contentResolver.createImagePart(imgUrl, FILE_NAME)

apiService.patchUserProfile(infoRequestBody, filePart)
Unit
Expand Down Expand Up @@ -75,4 +75,8 @@ internal class DefaultProfileRepository @Inject constructor(
}.onFailure {
return it.handleThrowable()
}

companion object {
private const val FILE_NAME = "file"
}
}
1 change: 1 addition & 0 deletions core/network/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,5 @@ dependencies {
implementation(project(":core:datastore"))
implementation(libs.androidx.exifinterface)
implementation(libs.paging)
implementation(libs.process.phoenix)
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.teamwable.network

import android.app.Application
import android.content.Intent
import android.widget.Toast
import com.jakewharton.processphoenix.ProcessPhoenix
import com.teamwable.datastore.datasource.DefaultWablePreferenceDatasource
import com.teamwable.network.datasource.AuthService
import com.teamwable.network.util.UNKNOWN_ERROR_MESSAGE
Expand All @@ -14,6 +14,7 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext
import okhttp3.Interceptor
import okhttp3.Request
import okhttp3.Response
Expand Down Expand Up @@ -74,14 +75,12 @@ class TokenInterceptor @Inject constructor(
}
}

private fun handleFailedTokenReissue() = with(context) {
private fun handleFailedTokenReissue() {
CoroutineScope(Dispatchers.Main).launch {
defaultWablePreferenceDatasource.clear()
startActivity(
Intent.makeRestartActivityTask(
packageManager.getLaunchIntentForPackage(packageName)?.component,
),
)
withContext(Dispatchers.IO) {
defaultWablePreferenceDatasource.clear()
}
ProcessPhoenix.triggerRebirth(context)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okhttp3.MultipartBody

suspend fun ContentResolver.createImagePart(uriString: String?): MultipartBody.Part? {
suspend fun ContentResolver.createImagePart(uriString: String?, fileName: String): MultipartBody.Part? {
if (uriString.isNullOrEmpty()) return null
val uri = runCatching { Uri.parse(uriString) }.getOrElse { return null }

return withContext(Dispatchers.IO) {
val imageRequestBody = ContentUriRequestBody(this@createImagePart, uri)
imageRequestBody.toMultiPartData("image")
imageRequestBody.toMultiPartData(fileName)
}
}
1 change: 1 addition & 0 deletions core/ui/src/main/res/values/themes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<item name="android:statusBarColor">@android:color/white</item>
<item name="android:windowLightStatusBar">true</item>
<item name="android:windowBackground">@color/white</item>
<item name="android:windowIsTranslucent">true</item>
</style>

<style name="Theme.Wable" parent="Base.Theme.Wable" />
Expand Down
4 changes: 0 additions & 4 deletions feature/auth/src/main/java/com/teamwable/auth/LoginScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,6 @@ fun LoginRoute(

val showDialog by viewModel.showDialog.collectAsStateWithLifecycle()

LaunchedEffect(Unit) {
viewModel.observeAutoLogin()
}

LaunchedEffect(lifecycleOwner) {
viewModel.loginSideEffect.flowWithLifecycle(lifecycleOwner.lifecycle)
.collect { sideEffect ->
Expand Down
11 changes: 0 additions & 11 deletions feature/auth/src/main/java/com/teamwable/auth/LoginViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import javax.inject.Inject
Expand All @@ -34,16 +33,6 @@ class LoginViewModel @Inject constructor(
private val _showDialog = MutableStateFlow(false)
val showDialog: StateFlow<Boolean> get() = _showDialog

fun observeAutoLogin() {
viewModelScope.launch {
userInfoRepository.getAutoLogin().collectLatest { isAutoLogin ->
if (isAutoLogin) {
_loginSideEffect.emit(LoginSideEffect.NavigateToMain)
}
}
}
}

fun showLoginDialog(show: Boolean) {
_showDialog.update { show }
}
Expand Down
1 change: 1 addition & 0 deletions feature/main-compose/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ android {
dependencies {
implementation(project(":feature:auth"))
implementation(project(":feature:onboarding"))
implementation(libs.lottie.compose)
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class MainNavigator(
@Composable get() = navController
.currentBackStackEntryAsState().value?.destination

val startDestination = Route.Login
val startDestination = Route.Splash

fun navigateToLogin(navOptions: NavOptions) {
navController.navigateLogin(navOptions)
Expand Down Expand Up @@ -57,8 +57,8 @@ class MainNavigator(

fun resetToLogin() {
val navOptions = navOptions {
popUpTo(startDestination) {
saveState = true
popUpTo(Route.Login) {
inclusive = true
}
launchSingleTop = true
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ internal fun MainScreen(
)
},
navigateToHome = { startActivity(localContext, intent, null) },
intentProvider = intentProvider,
)
loginNavGraph(
navigateToFirstLckWatch = { navigator.navigateToFirstLckWatch() },
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package com.teamwable.main_compose.splash

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.lifecycle.flowWithLifecycle
import com.airbnb.lottie.LottieComposition
import com.airbnb.lottie.compose.LottieAnimation
import com.airbnb.lottie.compose.LottieCompositionSpec
import com.airbnb.lottie.compose.LottieConstants
import com.airbnb.lottie.compose.animateLottieCompositionAsState
import com.airbnb.lottie.compose.rememberLottieComposition
import com.teamwable.designsystem.theme.WableTheme
import com.teamwable.main_compose.R
import com.teamwable.main_compose.splash.model.SplashSideEffect
import kotlinx.coroutines.delay

@Composable
fun SplashRoute(
viewModel: SplashViewModel = hiltViewModel(),
navigateToHome: () -> Unit,
navigateToLogIn: () -> Unit,
) {
val lifecycleOwner = LocalLifecycleOwner.current
val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw.wable_splash))
val progress by animateLottieCompositionAsState(
composition = composition,
iterations = LottieConstants.IterateForever,
)

LaunchedEffect(Unit) {
delay(2000)
viewModel.observeAutoLogin()
}

LaunchedEffect(lifecycleOwner) {
viewModel.sideEffect.flowWithLifecycle(lifecycleOwner.lifecycle)
.collect { sideEffect ->
when (sideEffect) {
is SplashSideEffect.NavigateToHome -> navigateToHome()
is SplashSideEffect.NavigateToLogin -> navigateToLogIn()
}
}
}

WableSplashScreen(
composition = composition,
progress = progress,
)
}

@Composable
fun WableSplashScreen(
composition: LottieComposition?,
progress: Float,
) {
Box(
modifier = Modifier.fillMaxSize(),
) {
LottieAnimation(
composition = composition,
progress = { progress },
modifier = Modifier.align(Alignment.Center),
)
}
}

@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
WableTheme {
WableSplashScreen(
composition = rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw.wable_splash)).value,
progress = 1.0f,
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.teamwable.main_compose.splash

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.teamwable.data.repository.UserInfoRepository
import com.teamwable.main_compose.splash.model.SplashSideEffect
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class SplashViewModel @Inject constructor(
private val userInfoRepository: UserInfoRepository,
) : ViewModel() {
private val _sideEffect = MutableSharedFlow<SplashSideEffect>()
val sideEffect: SharedFlow<SplashSideEffect> = _sideEffect.asSharedFlow()

fun observeAutoLogin() {
viewModelScope.launch {
userInfoRepository.getAutoLogin().collectLatest { isAutoLogin ->
if (isAutoLogin) _sideEffect.emit(SplashSideEffect.NavigateToHome)
else _sideEffect.emit(SplashSideEffect.NavigateToLogin)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.teamwable.main_compose.splash.model

sealed interface SplashSideEffect {
data object NavigateToHome : SplashSideEffect

data object NavigateToLogin : SplashSideEffect
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,17 @@ package com.teamwable.main_compose.splash.navigation

import androidx.navigation.NavGraphBuilder
import androidx.navigation.compose.composable
import com.teamwable.common.intentprovider.IntentProvider
import com.teamwable.main_compose.splash.SplashRoute
import com.teamwable.navigation.Route

fun NavGraphBuilder.splashNavGraph(
navigateToLogIn: () -> Unit,
navigateToHome: () -> Unit,
intentProvider: IntentProvider,
) {
composable<Route.Splash> {
/* SplashScreen(
navigateToHome = navigateToHome,
navigateToLogIn = navigateToLogIn
intentProvider: IntentProvider,
)*/
SplashRoute(
navigateToHome = navigateToHome,
navigateToLogIn = navigateToLogIn,
)
}
}
Loading