Skip to content

Commit

Permalink
Feat/#134 개인정보 수집 동의 기능 추가 (#136)
Browse files Browse the repository at this point in the history
* feat: 홈 로고 변경

* feat: top app bar 수정

* feat: 정책 상세 추가정보 섹션 추가

* feat: 서비스 이용약관, 개인정보 처리방침 모듈 추가

* feat: 약관 동의 UI 완성

* feat: 정책 상세 UI 수정

* feat: gradle 설정 변경

* feat: 로깅 debug, release 구분

* refactor: 필요없는 로직 제거

* feat: 인앱 업데이트 및 약관 웹뷰 추가

* feat: padding 수정

* chore: 버전코드 수정
  • Loading branch information
rhkrwngud445 authored Jun 7, 2024
1 parent 5b9bf6a commit 04a6455
Show file tree
Hide file tree
Showing 67 changed files with 1,394 additions and 167 deletions.
9 changes: 7 additions & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ android {
defaultConfig {
applicationId = "com.withpeace.withpeace"
targetSdk = 34
versionCode = 2
versionCode = 4
versionName = "1.0.0"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
Expand All @@ -20,7 +20,6 @@ android {
}
packaging {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
merges += "META-INF/LICENSE.md"
merges += "META-INF/LICENSE-notice.md"
}
Expand All @@ -41,6 +40,9 @@ dependencies {
implementation(libs.androidx.core.splashscreen)
implementation(project(":feature:login"))
implementation(project(":feature:signup"))
implementation(project(":feature:policyconsent"))
implementation(project(":feature:privacypolicy"))
implementation(project(":feature:termsofservice"))
implementation(project(":feature:home"))
implementation(project(":feature:postlist"))
implementation(project(":feature:mypage"))
Expand All @@ -58,4 +60,7 @@ dependencies {
implementation(project(":core:analytics"))
implementation(project(":core:designsystem"))
testImplementation(project(":core:testing"))

implementation("com.google.android.play:app-update:2.1.0")
implementation("com.google.android.play:app-update-ktx:2.1.0")
}
2 changes: 1 addition & 1 deletion app/release/output-metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 2,
"versionCode": 3,
"versionName": "1.0.0",
"outputFile": "app-release.apk"
}
Expand Down
99 changes: 92 additions & 7 deletions app/src/main/java/com/withpeace/withpeace/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
package com.withpeace.withpeace

import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.result.ActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.compose.runtime.CompositionLocalProvider
import androidx.core.splashscreen.SplashScreen
Expand All @@ -11,6 +16,13 @@ import androidx.core.view.WindowCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.google.android.gms.tasks.Task
import com.google.android.play.core.appupdate.AppUpdateInfo
import com.google.android.play.core.appupdate.AppUpdateManager
import com.google.android.play.core.appupdate.AppUpdateManagerFactory
import com.google.android.play.core.appupdate.AppUpdateOptions
import com.google.android.play.core.install.model.AppUpdateType
import com.google.android.play.core.install.model.UpdateAvailability
import com.withpeace.withpeace.core.analytics.AnalyticsHelper
import com.withpeace.withpeace.core.analytics.LocalAnalyticsHelper
import com.withpeace.withpeace.core.designsystem.theme.WithpeaceTheme
Expand All @@ -28,9 +40,17 @@ class MainActivity : ComponentActivity() {
@Inject
lateinit var analyticsHelper: AnalyticsHelper

private val appUpdateManager by lazy { AppUpdateManagerFactory.create(this) }

private val updateActivityResultLauncher =
registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { result: ActivityResult ->
if (result.resultCode != RESULT_OK) {
finish()
}
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

// System Bar에 가려지는 뷰 영역을 개발자가 제어하겠다.
WindowCompat.setDecorFitsSystemWindows(window, false)

Expand All @@ -39,11 +59,16 @@ class MainActivity : ComponentActivity() {
splashScreen.setKeepOnScreenCondition { true }
// 처음 앱 켰을때만 2초기다림, 화면회전에는 기다리면 안됨
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.isLogin.collect { isLogin ->
when (isLogin) {
true -> composeStart(HOME_ROUTE)
false -> composeStart(LOGIN_ROUTE)
else -> {} // StateFlow의 상태를 Null로 설정함으로서, 로그인 상태가 업데이트 된 이후로 화면을 보여주도록 하기위함
viewModel.uiState.collect { uiState ->
when (uiState) {
MainUiState.Home -> composeStart(HOME_ROUTE)
MainUiState.Login -> composeStart(LOGIN_ROUTE)
MainUiState.Update -> {
compulsionUpdate()
}

MainUiState.Error -> finish()
MainUiState.Loading -> {}
}
splashScreen.setKeepOnScreenCondition { false }
}
Expand All @@ -62,4 +87,64 @@ class MainActivity : ComponentActivity() {
}
}
}
}
private fun compulsionUpdate() {
val appUpdateInfoTask: Task<AppUpdateInfo> = appUpdateManager.appUpdateInfo

appUpdateInfoTask.addOnSuccessListener { appUpdateInfo ->
if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE
&& appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)
) {
startUpdateFlow(appUpdateManager, appUpdateInfo)
} else {
Toast.makeText(this, "앱을 사용하려면 업데이트가 필요해요!", Toast.LENGTH_LONG).show()
redirectToPlayStore()
}
}
}

private fun startUpdateFlow(appUpdateManager: AppUpdateManager, appUpdateInfo: AppUpdateInfo) {
try {
appUpdateManager.startUpdateFlowForResult(
appUpdateInfo,
updateActivityResultLauncher,
AppUpdateOptions.newBuilder(AppUpdateType.IMMEDIATE).build(),
)
} catch (e: Exception) {
e.printStackTrace()
}
}

private fun redirectToPlayStore() {
val packageName = packageName
try {
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=$packageName")))
} catch (e: Exception) {
startActivity(
Intent(
Intent.ACTION_VIEW,
Uri.parse("https://play.google.com/store/apps/details?id=$packageName"),
),
)
}
finish()
}

override fun onResume() {
super.onResume()

appUpdateManager
.appUpdateInfo
.addOnSuccessListener { appUpdateInfo ->
if (appUpdateInfo.updateAvailability()
== UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS
) {
// If an in-app update is already running, resume the update.
appUpdateManager.startUpdateFlowForResult(
appUpdateInfo,
updateActivityResultLauncher,
AppUpdateOptions.newBuilder(AppUpdateType.IMMEDIATE).build(),
)
}
}
}
}
9 changes: 9 additions & 0 deletions app/src/main/java/com/withpeace/withpeace/MainUiState.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.withpeace.withpeace

sealed interface MainUiState {
data object Login : MainUiState
data object Update : MainUiState
data object Error : MainUiState
data object Home : MainUiState
data object Loading : MainUiState
}
35 changes: 30 additions & 5 deletions app/src/main/java/com/withpeace/withpeace/MainViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,46 @@ package com.withpeace.withpeace

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.withpeace.withpeace.core.domain.usecase.CheckAppUpdateUseCase
import com.withpeace.withpeace.core.domain.usecase.IsLoginUseCase
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class MainViewModel @Inject constructor(
private val isLoginUseCase: IsLoginUseCase,
private val checkAppUpdateUseCase: CheckAppUpdateUseCase,
) : ViewModel() {
private val _isLogin: MutableStateFlow<Boolean?> = MutableStateFlow(null)
val isLogin = _isLogin.asStateFlow()
private val _uiState: Channel<MainUiState> = Channel()
val uiState = _uiState.receiveAsFlow()

init {
viewModelScope.launch { _isLogin.value = isLoginUseCase() }
checkUpdate()
}

private fun checkUpdate() {
viewModelScope.launch {
checkAppUpdateUseCase(
currentVersion = BuildConfig.VERSION_CODE,
onError = {
_uiState.send(MainUiState.Error)
},
).collect { shouldUpdate ->
if (shouldUpdate) {
_uiState.send(MainUiState.Update)
return@collect
}
val isLogin = isLoginUseCase()
if (isLogin) {
_uiState.send(MainUiState.Home)
} else {
_uiState.send(MainUiState.Login)
}
}
}
}
}

34 changes: 33 additions & 1 deletion app/src/main/java/com/withpeace/withpeace/navigation/NavHost.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import com.withpeace.withpeace.feature.mypage.navigation.MY_PAGE_CHANGED_IMAGE_A
import com.withpeace.withpeace.feature.mypage.navigation.MY_PAGE_CHANGED_NICKNAME_ARGUMENT
import com.withpeace.withpeace.feature.mypage.navigation.MY_PAGE_ROUTE
import com.withpeace.withpeace.feature.mypage.navigation.myPageNavGraph
import com.withpeace.withpeace.feature.policyconsent.navigation.navigateToPolicyConsent
import com.withpeace.withpeace.feature.policyconsent.navigation.policyConsentGraph
import com.withpeace.withpeace.feature.policydetail.navigation.navigateToPolicyDetail
import com.withpeace.withpeace.feature.policydetail.navigation.policyDetailNavGraph
import com.withpeace.withpeace.feature.postdetail.navigation.POST_DETAIL_ROUTE_WITH_ARGUMENT
Expand All @@ -27,13 +29,17 @@ import com.withpeace.withpeace.feature.postdetail.navigation.postDetailGraph
import com.withpeace.withpeace.feature.postlist.navigation.POST_LIST_DELETED_POST_ID_ARGUMENT
import com.withpeace.withpeace.feature.postlist.navigation.POST_LIST_ROUTE
import com.withpeace.withpeace.feature.postlist.navigation.postListGraph
import com.withpeace.withpeace.feature.privacypolicy.navigation.navigateToPrivacyPolicy
import com.withpeace.withpeace.feature.privacypolicy.navigation.privacyPolicyGraph
import com.withpeace.withpeace.feature.registerpost.navigation.IMAGE_LIST_ARGUMENT
import com.withpeace.withpeace.feature.registerpost.navigation.REGISTER_POST_ARGUMENT
import com.withpeace.withpeace.feature.registerpost.navigation.REGISTER_POST_ROUTE
import com.withpeace.withpeace.feature.registerpost.navigation.navigateToRegisterPost
import com.withpeace.withpeace.feature.registerpost.navigation.registerPostNavGraph
import com.withpeace.withpeace.feature.signup.navigation.navigateSignUp
import com.withpeace.withpeace.feature.signup.navigation.signUpNavGraph
import com.withpeace.withpeace.feature.termsofservice.navigation.navigateToTermsOfService
import com.withpeace.withpeace.feature.termsofservice.navigation.termsOfServiceGraph

@Composable
fun WithpeaceNavHost(
Expand All @@ -50,7 +56,7 @@ fun WithpeaceNavHost(
loginNavGraph(
onShowSnackBar = onShowSnackBar,
onSignUpNeeded = {
navController.navigateSignUp()
navController.navigateToPolicyConsent()
},
onLoginSuccess = {
navController.navigateHome(
Expand All @@ -63,6 +69,32 @@ fun WithpeaceNavHost(
)
},
)
policyConsentGraph(
onShowSnackBar = onShowSnackBar,
onSuccessToNext = {
navController.navigateSignUp()
},
onShowTermsOfServiceClick = {
navController.navigateToTermsOfService()
},
onShowPrivacyPolicyClick = {
navController.navigateToPrivacyPolicy()
},
)
termsOfServiceGraph(
onShowSnackBar = onShowSnackBar,
onClickBackButton = {
navController.popBackStack()
},
)

privacyPolicyGraph(
onShowSnackBar = onShowSnackBar,
onClickBackButton = {
navController.popBackStack()
},
)

signUpNavGraph(
onShowSnackBar = onShowSnackBar,
onNavigateToGallery = {
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/drawable/splash_inset.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/app_logo"
android:drawable="@drawable/ic_app_logo"
android:insetLeft="20dp"
android:insetRight="20dp"
android:insetTop="20dp"
Expand Down
Loading

0 comments on commit 04a6455

Please sign in to comment.