From d94b08eafdca26f203cf10d7012a8dfa455201e2 Mon Sep 17 00:00:00 2001 From: tgyuuAn Date: Thu, 13 Feb 2025 15:47:00 +0900 Subject: [PATCH 1/9] =?UTF-8?q?[PC-596]=20WebViewScreen=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/google-services.json | 29 +++++++++++ .../com/puzzle/data/image/ImageResizerImpl.kt | 4 +- .../src/main/res/values/strings.xml | 3 +- .../main/java/com/puzzle/navigation/Route.kt | 5 +- .../graph/verification/VerificationScreen.kt | 4 +- .../setting/graph/main/SettingScreen.kt | 8 ++-- .../setting/graph/webview/WebViewScreen.kt | 48 +++++++++++++++++++ .../setting/graph/webview/WebViewViewModel.kt | 11 +++++ .../setting/navigation/SettingNavigation.kt | 10 ++++ .../java/com/puzzle/presentation/ui/App.kt | 1 + 10 files changed, 114 insertions(+), 9 deletions(-) create mode 100644 app/google-services.json create mode 100644 feature/setting/src/main/java/com/puzzle/setting/graph/webview/WebViewScreen.kt create mode 100644 feature/setting/src/main/java/com/puzzle/setting/graph/webview/WebViewViewModel.kt diff --git a/app/google-services.json b/app/google-services.json new file mode 100644 index 00000000..dfca723b --- /dev/null +++ b/app/google-services.json @@ -0,0 +1,29 @@ +{ + "project_info": { + "project_number": "226421567171", + "project_id": "piece-android", + "storage_bucket": "piece-android.firebasestorage.app" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:226421567171:android:b32a573b96c7625af3bc76", + "android_client_info": { + "package_name": "com.puzzle.piece" + } + }, + "oauth_client": [], + "api_key": [ + { + "current_key": "AIzaSyAoANdCZFkJ_WgeFDGXG_s_7iHnZuKNeno" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/core/data/src/main/java/com/puzzle/data/image/ImageResizerImpl.kt b/core/data/src/main/java/com/puzzle/data/image/ImageResizerImpl.kt index 0bb2a1a6..ea59bd0c 100644 --- a/core/data/src/main/java/com/puzzle/data/image/ImageResizerImpl.kt +++ b/core/data/src/main/java/com/puzzle/data/image/ImageResizerImpl.kt @@ -53,7 +53,9 @@ class ImageResizerImpl @Inject constructor( } private fun calculateInSampleSize( - options: BitmapFactory.Options, reqWidth: Int, reqHeight: Int + options: BitmapFactory.Options, + reqWidth: Int, + reqHeight: Int, ): Int { val (height: Int, width: Int) = options.run { outHeight to outWidth } var inSampleSize = 1 diff --git a/core/designsystem/src/main/res/values/strings.xml b/core/designsystem/src/main/res/values/strings.xml index b7ff3846..5eb5dbc3 100644 --- a/core/designsystem/src/main/res/values/strings.xml +++ b/core/designsystem/src/main/res/values/strings.xml @@ -56,7 +56,7 @@ 신뢰도 높은 매칭과 안전한 커뮤니티를 위해\n휴대폰 번호로 인증해 주세요. - 확인 + 확인 다음 어떤 경우에도 타인에게 공유하지 마세요 전화번호 인증을 완료했어요 @@ -136,6 +136,7 @@ Setting 기타 로그아웃 + 로그아웃하시겠습니까? 안내 공지사항 개인정보처리방침 diff --git a/core/navigation/src/main/java/com/puzzle/navigation/Route.kt b/core/navigation/src/main/java/com/puzzle/navigation/Route.kt index caa3072a..efdf9b77 100644 --- a/core/navigation/src/main/java/com/puzzle/navigation/Route.kt +++ b/core/navigation/src/main/java/com/puzzle/navigation/Route.kt @@ -27,6 +27,9 @@ sealed class SettingGraphDest : Route { @Serializable data object WithdrawRoute : SettingGraphDest() + + @Serializable + data class WebViewRoute(val title: String, val url: String) : SettingGraphDest() } @Serializable @@ -46,7 +49,7 @@ sealed class MatchingGraphDest : Route { data class BlockRoute(val userId: Int, val userName: String) : MatchingGraphDest() @Serializable - data object ContactRoute: MatchingGraphDest() + data object ContactRoute : MatchingGraphDest() } @Serializable diff --git a/feature/auth/src/main/java/com/puzzle/auth/graph/verification/VerificationScreen.kt b/feature/auth/src/main/java/com/puzzle/auth/graph/verification/VerificationScreen.kt index 4413a11e..32e27e3f 100644 --- a/feature/auth/src/main/java/com/puzzle/auth/graph/verification/VerificationScreen.kt +++ b/feature/auth/src/main/java/com/puzzle/auth/graph/verification/VerificationScreen.kt @@ -169,7 +169,7 @@ private fun VerificationScreen( Spacer(modifier = Modifier.weight(1f)) PieceSolidButton( - label = stringResource(R.string.verification_submit), + label = stringResource(R.string.confirm), onClick = { navigate(NavigationEvent.NavigateTo(AuthGraphDest.SignUpRoute)) }, enabled = state.authCodeStatus == VERIFIED, modifier = Modifier @@ -282,7 +282,7 @@ private fun AuthCodeBody( ) PieceSolidButton( - label = stringResource(R.string.verification_submit), + label = stringResource(R.string.confirm), onClick = onVerifyClick, enabled = isVerifyButtonEnabled, modifier = Modifier.padding(start = 8.dp) diff --git a/feature/setting/src/main/java/com/puzzle/setting/graph/main/SettingScreen.kt b/feature/setting/src/main/java/com/puzzle/setting/graph/main/SettingScreen.kt index 495e5ec4..1099e2bb 100644 --- a/feature/setting/src/main/java/com/puzzle/setting/graph/main/SettingScreen.kt +++ b/feature/setting/src/main/java/com/puzzle/setting/graph/main/SettingScreen.kt @@ -83,14 +83,14 @@ private fun SettingScreen( onDismissRequest = { isLogoutDialogShow = false }, dialogTop = { PieceDialogDefaultTop( - title = "로그아웃", - subText = "로그아웃하시겠습니까?", + title = stringResource(R.string.setting_logout), + subText = stringResource(R.string.setting_logout_description), ) }, dialogBottom = { PieceDialogBottom( - leftButtonText = "취소", - rightButtonText = "확인", + leftButtonText = stringResource(R.string.cancel), + rightButtonText = stringResource(R.string.confirm), onLeftButtonClick = { isLogoutDialogShow = false }, onRightButtonClick = { onLogoutClick() }, ) diff --git a/feature/setting/src/main/java/com/puzzle/setting/graph/webview/WebViewScreen.kt b/feature/setting/src/main/java/com/puzzle/setting/graph/webview/WebViewScreen.kt new file mode 100644 index 00000000..f116b596 --- /dev/null +++ b/feature/setting/src/main/java/com/puzzle/setting/graph/webview/WebViewScreen.kt @@ -0,0 +1,48 @@ +package com.puzzle.setting.graph.webview + +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.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import com.puzzle.designsystem.component.PieceSubBackTopBar +import com.puzzle.designsystem.component.PieceWebView +import com.puzzle.navigation.NavigationEvent + +@Composable +internal fun WebViewRoute( + title: String, + url: String, + viewModel: WebViewViewModel = hiltViewModel(), +) { + WebViewScreen( + title = title, + url = url, + onBackClick = { viewModel.navigationHelper.navigate(NavigationEvent.NavigateUp) }, + ) +} + +@Composable +private fun WebViewScreen( + title: String, + url: String, + onBackClick: () -> Unit, +) { + Column(modifier = Modifier.fillMaxSize()) { + PieceSubBackTopBar( + title = title, + onBackClick = onBackClick, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 20.dp), + ) + + PieceWebView( + url = url, + modifier = Modifier.weight(1f), + ) + } +} diff --git a/feature/setting/src/main/java/com/puzzle/setting/graph/webview/WebViewViewModel.kt b/feature/setting/src/main/java/com/puzzle/setting/graph/webview/WebViewViewModel.kt new file mode 100644 index 00000000..23db5e13 --- /dev/null +++ b/feature/setting/src/main/java/com/puzzle/setting/graph/webview/WebViewViewModel.kt @@ -0,0 +1,11 @@ +package com.puzzle.setting.graph.webview + +import androidx.lifecycle.ViewModel +import com.puzzle.navigation.NavigationHelper +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject + +@HiltViewModel +class WebViewViewModel @Inject constructor( + internal val navigationHelper: NavigationHelper, +) : ViewModel() diff --git a/feature/setting/src/main/java/com/puzzle/setting/navigation/SettingNavigation.kt b/feature/setting/src/main/java/com/puzzle/setting/navigation/SettingNavigation.kt index 285308f4..e3fed719 100644 --- a/feature/setting/src/main/java/com/puzzle/setting/navigation/SettingNavigation.kt +++ b/feature/setting/src/main/java/com/puzzle/setting/navigation/SettingNavigation.kt @@ -3,9 +3,11 @@ package com.puzzle.setting.navigation import androidx.navigation.NavGraphBuilder import androidx.navigation.compose.composable import androidx.navigation.compose.navigation +import androidx.navigation.toRoute import com.puzzle.navigation.SettingGraph import com.puzzle.navigation.SettingGraphDest import com.puzzle.setting.graph.main.SettingRoute +import com.puzzle.setting.graph.webview.WebViewRoute import com.puzzle.setting.graph.withdraw.WithdrawRoute fun NavGraphBuilder.settingNavGraph() { @@ -19,5 +21,13 @@ fun NavGraphBuilder.settingNavGraph() { composable { WithdrawRoute() } + + composable { backStackEntry -> + val webView = backStackEntry.toRoute() + WebViewRoute( + title = webView.title, + url = webView.url, + ) + } } } diff --git a/presentation/src/main/java/com/puzzle/presentation/ui/App.kt b/presentation/src/main/java/com/puzzle/presentation/ui/App.kt index 9f958503..df3c1dfd 100644 --- a/presentation/src/main/java/com/puzzle/presentation/ui/App.kt +++ b/presentation/src/main/java/com/puzzle/presentation/ui/App.kt @@ -178,6 +178,7 @@ private val HIDDEN_BOTTOM_NAV_ROUTES = setOf( ProfileGraphDest.ValuePickProfileRoute::class, ProfileGraphDest.BasicProfileRoute::class, SettingGraphDest.WithdrawRoute::class, + SettingGraphDest.WebViewRoute::class, ) private fun NavDestination?.shouldHideBottomNavigation(): Boolean = From 37b7dfc0d574a4e7ee13f72028b751b2023da333 Mon Sep 17 00:00:00 2001 From: tgyuuAn Date: Thu, 13 Feb 2025 16:39:35 +0900 Subject: [PATCH 2/9] =?UTF-8?q?[PC-596]=20=EB=85=B8=EC=85=98=20WebView=20?= =?UTF-8?q?=EB=AC=B8=EC=A0=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../puzzle/designsystem/component/WebView.kt | 10 ++- feature/setting/build.gradle.kts | 31 +++++++++ .../setting/graph/main/SettingScreen.kt | 65 +++++++++---------- .../setting/graph/main/SettingViewModel.kt | 31 ++++++++- .../graph/main/contract/SettingIntent.kt | 4 ++ .../graph/main/contract/SettingSideEffect.kt | 6 +- .../com/puzzle/presentation/MainViewModel.kt | 3 +- .../presentation/navigation/AppNavHost.kt | 4 +- 8 files changed, 107 insertions(+), 47 deletions(-) diff --git a/core/designsystem/src/main/java/com/puzzle/designsystem/component/WebView.kt b/core/designsystem/src/main/java/com/puzzle/designsystem/component/WebView.kt index 8cba18cf..6b8efda6 100644 --- a/core/designsystem/src/main/java/com/puzzle/designsystem/component/WebView.kt +++ b/core/designsystem/src/main/java/com/puzzle/designsystem/component/WebView.kt @@ -1,6 +1,6 @@ package com.puzzle.designsystem.component -import android.webkit.WebChromeClient +import android.view.ViewGroup import android.webkit.WebView import android.webkit.WebViewClient import androidx.compose.runtime.Composable @@ -23,9 +23,13 @@ fun PieceWebView( AndroidView( factory = { webView = WebView(context).apply { - settings.javaScriptEnabled = true + layoutParams = ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT, + ) webViewClient = object : WebViewClient() {} - webChromeClient = object : WebChromeClient() {} + settings.javaScriptEnabled = true + settings.domStorageEnabled = true } webView!! }, diff --git a/feature/setting/build.gradle.kts b/feature/setting/build.gradle.kts index 5d23cc98..c327ae82 100644 --- a/feature/setting/build.gradle.kts +++ b/feature/setting/build.gradle.kts @@ -1,7 +1,38 @@ +import java.util.Properties + plugins { id("piece.android.feature") } android { namespace = "com.puzzle.setting" + + defaultConfig { + val localProperties = Properties() + localProperties.load(project.rootProject.file("local.properties").bufferedReader()) + buildConfigField( + type = "String", + name = "PIECE_CHANNEL_TALK_URL", + value = "\"${localProperties["PIECE_CHANNEL_TALK_URL"]}\"" + ) + buildConfigField( + type = "String", + name = "PIECE_TERMS_OF_USE_URL", + value = "\"${localProperties["PIECE_TERMS_OF_USE_URL"]}\"" + ) + buildConfigField( + type = "String", + name = "PIECE_PRIVACY_AND_POLICY_URL", + value = "\"${localProperties["PIECE_PRIVACY_AND_POLICY_URL"]}\"" + ) + buildConfigField( + type = "String", + name = "PIECE_NOTICE_URL", + value = "\"${localProperties["PIECE_NOTICE_URL"]}\"" + ) + } + + buildFeatures { + buildConfig = true + } } diff --git a/feature/setting/src/main/java/com/puzzle/setting/graph/main/SettingScreen.kt b/feature/setting/src/main/java/com/puzzle/setting/graph/main/SettingScreen.kt index 1099e2bb..efb4a617 100644 --- a/feature/setting/src/main/java/com/puzzle/setting/graph/main/SettingScreen.kt +++ b/feature/setting/src/main/java/com/puzzle/setting/graph/main/SettingScreen.kt @@ -41,7 +41,6 @@ import com.puzzle.designsystem.component.PieceToggle import com.puzzle.designsystem.foundation.PieceTheme import com.puzzle.domain.model.auth.OAuthProvider import com.puzzle.setting.graph.main.contract.SettingIntent -import com.puzzle.setting.graph.main.contract.SettingSideEffect import com.puzzle.setting.graph.main.contract.SettingState @Composable @@ -54,10 +53,6 @@ internal fun SettingRoute( LaunchedEffect(viewModel) { lifecycleOwner.repeatOnStarted { viewModel.sideEffects.collect { sideEffect -> - when (sideEffect) { - is SettingSideEffect.Navigate -> viewModel.navigationHelper - .navigate(sideEffect.navigationEvent) - } } } } @@ -66,6 +61,10 @@ internal fun SettingRoute( state = state, onWithdrawClick = { viewModel.onIntent(SettingIntent.OnWithdrawClick) }, onLogoutClick = { viewModel.onIntent(SettingIntent.OnLogoutClick) }, + onNoticeClick = { viewModel.onIntent(SettingIntent.OnNoticeClick) }, + onPrivacyAndPolicyClick = { viewModel.onIntent(SettingIntent.OnPrivacyAndPolicyClick) }, + onTermsOfUseClick = { viewModel.onIntent(SettingIntent.OnTermsOfUseClick) }, + onInquiryClick = { viewModel.onIntent(SettingIntent.OnInquiryClick) }, ) } @@ -74,7 +73,10 @@ private fun SettingScreen( state: SettingState, onWithdrawClick: () -> Unit, onLogoutClick: () -> Unit, - modifier: Modifier = Modifier, + onNoticeClick: () -> Unit, + onPrivacyAndPolicyClick: () -> Unit, + onTermsOfUseClick: () -> Unit, + onInquiryClick: () -> Unit, ) { var isLogoutDialogShow by remember { mutableStateOf(false) } @@ -99,7 +101,7 @@ private fun SettingScreen( } Column( - modifier = modifier + modifier = Modifier .fillMaxSize() .background(PieceTheme.colors.white) ) { @@ -140,14 +142,14 @@ private fun SettingScreen( ) InquiryBody( - onContactUsClick = {}, + onContactUsClick = onInquiryClick, ) AnnouncementBody( version = state.version, - onAnnouncementClick = {}, - onPrivacyPolicy = {}, - onTermsClick = {}, + onNoticeClick = onNoticeClick, + onPrivacyPolicy = onPrivacyAndPolicyClick, + onTermsClick = onTermsOfUseClick, ) OthersBody(onLogoutClick = { isLogoutDialogShow = true }) @@ -161,9 +163,7 @@ private fun SettingScreen( modifier = Modifier .align(Alignment.CenterHorizontally) .padding(top = 16.dp, bottom = 60.dp) - .clickable { - onWithdrawClick() - }, + .clickable { onWithdrawClick() }, ) } } @@ -198,8 +198,7 @@ private fun LoginAccountBody( Image( painter = painterResource(it), contentDescription = null, - modifier = Modifier - .size(24.dp), + modifier = Modifier.size(24.dp), ) } @@ -392,7 +391,8 @@ private fun InquiryBody(onContactUsClick: () -> Unit) { verticalAlignment = Alignment.CenterVertically, modifier = Modifier .fillMaxWidth() - .padding(vertical = 17.dp), + .padding(vertical = 17.dp) + .clickable { onContactUsClick() }, ) { Text( text = stringResource(R.string.setting_contact_us), @@ -404,9 +404,7 @@ private fun InquiryBody(onContactUsClick: () -> Unit) { Image( painter = painterResource(R.drawable.ic_arrow_right), contentDescription = "상세 내용", - modifier = Modifier - .padding(start = 4.dp) - .clickable { onContactUsClick() }, + modifier = Modifier.padding(start = 4.dp), ) } @@ -421,7 +419,7 @@ private fun InquiryBody(onContactUsClick: () -> Unit) { @Composable private fun AnnouncementBody( version: String, - onAnnouncementClick: () -> Unit, + onNoticeClick: () -> Unit, onPrivacyPolicy: () -> Unit, onTermsClick: () -> Unit, ) { @@ -436,7 +434,8 @@ private fun AnnouncementBody( verticalAlignment = Alignment.CenterVertically, modifier = Modifier .fillMaxWidth() - .padding(vertical = 17.dp), + .padding(vertical = 17.dp) + .clickable { onNoticeClick() }, ) { Text( text = stringResource(R.string.setting_announcement), @@ -448,9 +447,7 @@ private fun AnnouncementBody( Image( painter = painterResource(R.drawable.ic_arrow_right), contentDescription = "상세 내용", - modifier = Modifier - .padding(start = 4.dp) - .clickable { onAnnouncementClick() }, + modifier = Modifier.padding(start = 4.dp), ) } @@ -458,7 +455,8 @@ private fun AnnouncementBody( verticalAlignment = Alignment.CenterVertically, modifier = Modifier .fillMaxWidth() - .padding(vertical = 17.dp), + .padding(vertical = 17.dp) + .clickable { onPrivacyPolicy() }, ) { Text( text = stringResource(R.string.setting_privacy_policy), @@ -470,9 +468,7 @@ private fun AnnouncementBody( Image( painter = painterResource(R.drawable.ic_arrow_right), contentDescription = "상세 내용", - modifier = Modifier - .padding(start = 4.dp) - .clickable { onPrivacyPolicy() }, + modifier = Modifier.padding(start = 4.dp), ) } @@ -480,7 +476,8 @@ private fun AnnouncementBody( verticalAlignment = Alignment.CenterVertically, modifier = Modifier .fillMaxWidth() - .padding(vertical = 17.dp), + .padding(vertical = 17.dp) + .clickable { onTermsClick() }, ) { Text( text = stringResource(R.string.setting_term), @@ -492,9 +489,7 @@ private fun AnnouncementBody( Image( painter = painterResource(R.drawable.ic_arrow_right), contentDescription = "상세 내용", - modifier = Modifier - .padding(start = 4.dp) - .clickable { onTermsClick() }, + modifier = Modifier.padding(start = 4.dp), ) } @@ -551,6 +546,10 @@ private fun PreviewSettingScreen() { ), onWithdrawClick = {}, onLogoutClick = {}, + onNoticeClick = {}, + onPrivacyAndPolicyClick = { }, + onTermsOfUseClick = {}, + onInquiryClick = {}, ) } } diff --git a/feature/setting/src/main/java/com/puzzle/setting/graph/main/SettingViewModel.kt b/feature/setting/src/main/java/com/puzzle/setting/graph/main/SettingViewModel.kt index 518d4f17..0efb1aae 100644 --- a/feature/setting/src/main/java/com/puzzle/setting/graph/main/SettingViewModel.kt +++ b/feature/setting/src/main/java/com/puzzle/setting/graph/main/SettingViewModel.kt @@ -11,6 +11,7 @@ import com.puzzle.navigation.NavigationEvent import com.puzzle.navigation.NavigationEvent.NavigateTo import com.puzzle.navigation.NavigationHelper import com.puzzle.navigation.SettingGraphDest +import com.puzzle.setting.BuildConfig import com.puzzle.setting.graph.main.contract.SettingIntent import com.puzzle.setting.graph.main.contract.SettingSideEffect import com.puzzle.setting.graph.main.contract.SettingState @@ -49,12 +50,36 @@ class SettingViewModel @AssistedInject constructor( when (intent) { is SettingIntent.OnWithdrawClick -> moveToWithdrawScreen() is SettingIntent.OnLogoutClick -> logout() + SettingIntent.OnInquiryClick -> navigateToWebView( + "문의하기", + BuildConfig.PIECE_CHANNEL_TALK_URL + ) + + SettingIntent.OnNoticeClick -> navigateToWebView("공지사항", BuildConfig.PIECE_NOTICE_URL) + SettingIntent.OnPrivacyAndPolicyClick -> navigateToWebView( + "개인정보처리방침", + BuildConfig.PIECE_PRIVACY_AND_POLICY_URL + ) + + SettingIntent.OnTermsOfUseClick -> navigateToWebView( + "이용약관", + BuildConfig.PIECE_TERMS_OF_USE_URL + ) } } - private suspend fun moveToWithdrawScreen() { - _sideEffects.send(SettingSideEffect.Navigate(NavigateTo(SettingGraphDest.WithdrawRoute))) - } + private fun moveToWithdrawScreen() = + navigationHelper.navigate(NavigateTo(SettingGraphDest.WithdrawRoute)) + + private fun navigateToWebView(title: String, url: String) = + navigationHelper.navigate( + NavigateTo( + SettingGraphDest.WebViewRoute( + title = title, + url = url + ) + ) + ) private suspend fun logout() { authRepository.logout() diff --git a/feature/setting/src/main/java/com/puzzle/setting/graph/main/contract/SettingIntent.kt b/feature/setting/src/main/java/com/puzzle/setting/graph/main/contract/SettingIntent.kt index b5c3fb52..c99dba96 100644 --- a/feature/setting/src/main/java/com/puzzle/setting/graph/main/contract/SettingIntent.kt +++ b/feature/setting/src/main/java/com/puzzle/setting/graph/main/contract/SettingIntent.kt @@ -3,4 +3,8 @@ package com.puzzle.setting.graph.main.contract sealed class SettingIntent { data object OnWithdrawClick : SettingIntent() data object OnLogoutClick : SettingIntent() + data object OnNoticeClick : SettingIntent() + data object OnPrivacyAndPolicyClick : SettingIntent() + data object OnTermsOfUseClick : SettingIntent() + data object OnInquiryClick : SettingIntent() } diff --git a/feature/setting/src/main/java/com/puzzle/setting/graph/main/contract/SettingSideEffect.kt b/feature/setting/src/main/java/com/puzzle/setting/graph/main/contract/SettingSideEffect.kt index b0d31a00..31aa5ef1 100644 --- a/feature/setting/src/main/java/com/puzzle/setting/graph/main/contract/SettingSideEffect.kt +++ b/feature/setting/src/main/java/com/puzzle/setting/graph/main/contract/SettingSideEffect.kt @@ -1,7 +1,3 @@ package com.puzzle.setting.graph.main.contract -import com.puzzle.navigation.NavigationEvent - -sealed class SettingSideEffect { - data class Navigate(val navigationEvent: NavigationEvent) : SettingSideEffect() -} +sealed class SettingSideEffect diff --git a/presentation/src/main/java/com/puzzle/presentation/MainViewModel.kt b/presentation/src/main/java/com/puzzle/presentation/MainViewModel.kt index d3940ad5..02eab72a 100644 --- a/presentation/src/main/java/com/puzzle/presentation/MainViewModel.kt +++ b/presentation/src/main/java/com/puzzle/presentation/MainViewModel.kt @@ -43,7 +43,8 @@ class MainViewModel @Inject constructor( init { handleError() initConfigure() - checkRedirection() +// checkRedirection() + _isInitialized.value = true } private fun handleError() = viewModelScope.launch { diff --git a/presentation/src/main/java/com/puzzle/presentation/navigation/AppNavHost.kt b/presentation/src/main/java/com/puzzle/presentation/navigation/AppNavHost.kt index 2933dbae..c6f98e64 100644 --- a/presentation/src/main/java/com/puzzle/presentation/navigation/AppNavHost.kt +++ b/presentation/src/main/java/com/puzzle/presentation/navigation/AppNavHost.kt @@ -9,7 +9,7 @@ import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import com.puzzle.auth.navigation.authNavGraph import com.puzzle.matching.navigation.matchingNavGraph -import com.puzzle.navigation.AuthGraph +import com.puzzle.navigation.SettingGraph import com.puzzle.onboarding.navigation.onboardingNavigation import com.puzzle.profile.navigation.profileNavGraph import com.puzzle.setting.navigation.settingNavGraph @@ -23,7 +23,7 @@ fun AppNavHost( navController = navController, popExitTransition = { fadeOut(tween(700)) }, popEnterTransition = { fadeIn(tween(700)) }, - startDestination = AuthGraph, + startDestination = SettingGraph, modifier = modifier, ) { onboardingNavigation() From d722d88d438ff3c1c583d92dd2076efbe4d3bc2f Mon Sep 17 00:00:00 2001 From: tgyuuAn Date: Thu, 13 Feb 2025 16:50:11 +0900 Subject: [PATCH 3/9] =?UTF-8?q?[PC-596]=20SettingInfo=20Api=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/puzzle/data/di/DataModule.kt | 2 +- .../data/{ => repository}/TokenManagerImpl.kt | 2 +- .../data/repository/UserRepositoryImpl.kt | 7 +++++++ .../com/puzzle/domain/model/user/UserSetting.kt | 7 +++++++ .../puzzle/domain/repository/UserRepository.kt | 2 ++ .../java/com/puzzle/network/api/PieceApi.kt | 4 ++++ .../model/user/GetSettingInfoResponse.kt | 17 +++++++++++++++++ .../network/source/user/UserDataSource.kt | 13 +++++++++++++ 8 files changed, 52 insertions(+), 2 deletions(-) rename core/data/src/main/java/com/puzzle/data/{ => repository}/TokenManagerImpl.kt (95%) create mode 100644 core/domain/src/main/java/com/puzzle/domain/model/user/UserSetting.kt create mode 100644 core/network/src/main/java/com/puzzle/network/model/user/GetSettingInfoResponse.kt create mode 100644 core/network/src/main/java/com/puzzle/network/source/user/UserDataSource.kt diff --git a/core/data/src/main/java/com/puzzle/data/di/DataModule.kt b/core/data/src/main/java/com/puzzle/data/di/DataModule.kt index c3d8b130..76969433 100644 --- a/core/data/src/main/java/com/puzzle/data/di/DataModule.kt +++ b/core/data/src/main/java/com/puzzle/data/di/DataModule.kt @@ -1,6 +1,6 @@ package com.puzzle.data.di -import com.puzzle.data.TokenManagerImpl +import com.puzzle.data.repository.TokenManagerImpl import com.puzzle.data.image.ImageResizer import com.puzzle.data.image.ImageResizerImpl import com.puzzle.data.repository.AuthRepositoryImpl diff --git a/core/data/src/main/java/com/puzzle/data/TokenManagerImpl.kt b/core/data/src/main/java/com/puzzle/data/repository/TokenManagerImpl.kt similarity index 95% rename from core/data/src/main/java/com/puzzle/data/TokenManagerImpl.kt rename to core/data/src/main/java/com/puzzle/data/repository/TokenManagerImpl.kt index 7a280a48..a9c7c832 100644 --- a/core/data/src/main/java/com/puzzle/data/TokenManagerImpl.kt +++ b/core/data/src/main/java/com/puzzle/data/repository/TokenManagerImpl.kt @@ -1,4 +1,4 @@ -package com.puzzle.data +package com.puzzle.data.repository import com.puzzle.datastore.datasource.token.LocalTokenDataSource import com.puzzle.network.interceptor.TokenManager diff --git a/core/data/src/main/java/com/puzzle/data/repository/UserRepositoryImpl.kt b/core/data/src/main/java/com/puzzle/data/repository/UserRepositoryImpl.kt index 5911b80a..30afcbc8 100644 --- a/core/data/src/main/java/com/puzzle/data/repository/UserRepositoryImpl.kt +++ b/core/data/src/main/java/com/puzzle/data/repository/UserRepositoryImpl.kt @@ -3,15 +3,22 @@ package com.puzzle.data.repository import com.puzzle.common.suspendRunCatching import com.puzzle.datastore.datasource.user.LocalUserDataSource import com.puzzle.domain.model.user.UserRole +import com.puzzle.domain.model.user.UserSetting import com.puzzle.domain.repository.UserRepository +import com.puzzle.network.model.user.GetSettingInfoResponse +import com.puzzle.network.source.user.UserDataSource import kotlinx.coroutines.flow.first import javax.inject.Inject class UserRepositoryImpl @Inject constructor( private val localUserDataSource: LocalUserDataSource, + private val userDataSource: UserDataSource, ) : UserRepository { override suspend fun getUserRole(): Result = suspendRunCatching { val userRoleString = localUserDataSource.userRole.first() UserRole.create(userRoleString) } + + override suspend fun getUserSettingInfo(): Result = + userDataSource.getSettingsInfo().mapCatching(GetSettingInfoResponse::toDomain) } diff --git a/core/domain/src/main/java/com/puzzle/domain/model/user/UserSetting.kt b/core/domain/src/main/java/com/puzzle/domain/model/user/UserSetting.kt new file mode 100644 index 00000000..937fe23d --- /dev/null +++ b/core/domain/src/main/java/com/puzzle/domain/model/user/UserSetting.kt @@ -0,0 +1,7 @@ +package com.puzzle.domain.model.user + +data class UserSetting( + val isNotificationEnabled: Boolean, + val isMatchNotificationEnabled: Boolean, + val isAcquaintanceBlockEnabled: Boolean, +) diff --git a/core/domain/src/main/java/com/puzzle/domain/repository/UserRepository.kt b/core/domain/src/main/java/com/puzzle/domain/repository/UserRepository.kt index ff3575e9..5e4c2fee 100644 --- a/core/domain/src/main/java/com/puzzle/domain/repository/UserRepository.kt +++ b/core/domain/src/main/java/com/puzzle/domain/repository/UserRepository.kt @@ -1,7 +1,9 @@ package com.puzzle.domain.repository import com.puzzle.domain.model.user.UserRole +import com.puzzle.domain.model.user.UserSetting interface UserRepository { suspend fun getUserRole(): Result + suspend fun getUserSettingInfo(): Result } diff --git a/core/network/src/main/java/com/puzzle/network/api/PieceApi.kt b/core/network/src/main/java/com/puzzle/network/api/PieceApi.kt index 85ee07b1..7fd36c8d 100644 --- a/core/network/src/main/java/com/puzzle/network/api/PieceApi.kt +++ b/core/network/src/main/java/com/puzzle/network/api/PieceApi.kt @@ -21,6 +21,7 @@ import com.puzzle.network.model.terms.AgreeTermsRequest import com.puzzle.network.model.terms.LoadTermsResponse import com.puzzle.network.model.token.RefreshTokenRequest import com.puzzle.network.model.token.RefreshTokenResponse +import com.puzzle.network.model.user.GetSettingInfoResponse import okhttp3.MultipartBody import retrofit2.http.Body import retrofit2.http.GET @@ -98,4 +99,7 @@ interface PieceApi { @POST("/api/matches/accept") suspend fun acceptMatching(): Result> + + @GET("/api/settings/infos") + suspend fun getSettingInfos(): Result> } diff --git a/core/network/src/main/java/com/puzzle/network/model/user/GetSettingInfoResponse.kt b/core/network/src/main/java/com/puzzle/network/model/user/GetSettingInfoResponse.kt new file mode 100644 index 00000000..a14e09a3 --- /dev/null +++ b/core/network/src/main/java/com/puzzle/network/model/user/GetSettingInfoResponse.kt @@ -0,0 +1,17 @@ +package com.puzzle.network.model.user + +import com.puzzle.domain.model.user.UserSetting +import kotlinx.serialization.Serializable + +@Serializable +data class GetSettingInfoResponse( + val isNotificationEnabled: Boolean?, + val isMatchNotificationEnabled: Boolean?, + val isAcquaintanceBlockEnabled: Boolean?, +) { + fun toDomain() = UserSetting( + isNotificationEnabled = isNotificationEnabled ?: false, + isMatchNotificationEnabled = isMatchNotificationEnabled ?: false, + isAcquaintanceBlockEnabled = isAcquaintanceBlockEnabled ?: false, + ) +} diff --git a/core/network/src/main/java/com/puzzle/network/source/user/UserDataSource.kt b/core/network/src/main/java/com/puzzle/network/source/user/UserDataSource.kt new file mode 100644 index 00000000..729930a7 --- /dev/null +++ b/core/network/src/main/java/com/puzzle/network/source/user/UserDataSource.kt @@ -0,0 +1,13 @@ +package com.puzzle.network.source.user + +import com.puzzle.network.api.PieceApi +import com.puzzle.network.model.unwrapData +import com.puzzle.network.model.user.GetSettingInfoResponse +import javax.inject.Inject + +class UserDataSource @Inject constructor( + private val pieceApi: PieceApi, +) { + suspend fun getSettingsInfo(): Result = + pieceApi.getSettingInfos().unwrapData() +} From a5b6da87eea453d1554398fdd9e91e8d9c4a8cef Mon Sep 17 00:00:00 2001 From: tgyuuAn Date: Thu, 13 Feb 2025 16:52:18 +0900 Subject: [PATCH 4/9] =?UTF-8?q?[PC-596]=20Setting=20=ED=99=94=EB=A9=B4=20?= =?UTF-8?q?=EC=8B=A4=EC=A0=9C=20=EB=8D=B0=EC=9D=B4=ED=84=B0=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../setting/graph/main/SettingViewModel.kt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/feature/setting/src/main/java/com/puzzle/setting/graph/main/SettingViewModel.kt b/feature/setting/src/main/java/com/puzzle/setting/graph/main/SettingViewModel.kt index 0efb1aae..67178bd1 100644 --- a/feature/setting/src/main/java/com/puzzle/setting/graph/main/SettingViewModel.kt +++ b/feature/setting/src/main/java/com/puzzle/setting/graph/main/SettingViewModel.kt @@ -6,6 +6,7 @@ import com.airbnb.mvrx.hilt.AssistedViewModelFactory import com.airbnb.mvrx.hilt.hiltMavericksViewModelFactory import com.puzzle.domain.model.error.ErrorHelper import com.puzzle.domain.repository.AuthRepository +import com.puzzle.domain.repository.UserRepository import com.puzzle.navigation.AuthGraph import com.puzzle.navigation.NavigationEvent import com.puzzle.navigation.NavigationEvent.NavigateTo @@ -28,6 +29,7 @@ import kotlinx.coroutines.launch class SettingViewModel @AssistedInject constructor( @Assisted initialState: SettingState, private val authRepository: AuthRepository, + private val userRepository: UserRepository, internal val navigationHelper: NavigationHelper, private val errorHelper: ErrorHelper, ) : MavericksViewModel(initialState) { @@ -37,11 +39,27 @@ class SettingViewModel @AssistedInject constructor( val sideEffects = _sideEffects.receiveAsFlow() init { + initSetting() + _intents.receiveAsFlow() .onEach(::processIntent) .launchIn(viewModelScope) } + private fun initSetting() = viewModelScope.launch { + userRepository.getUserSettingInfo() + .onSuccess { + setState { + copy( + isContactBlocked = it.isAcquaintanceBlockEnabled, + isPushNotificationEnabled = it.isNotificationEnabled, + isMatchingNotificationEnabled = it.isMatchNotificationEnabled, + ) + } + } + .onFailure { errorHelper.sendError(it) } + } + internal fun onIntent(intent: SettingIntent) = viewModelScope.launch { _intents.send(intent) } From fbcde45084d9abbe2b67da92e0ad6837026fd78a Mon Sep 17 00:00:00 2001 From: tgyuuAn Date: Thu, 13 Feb 2025 17:05:24 +0900 Subject: [PATCH 5/9] =?UTF-8?q?[PC-596]=20=EC=8B=A4=EC=A0=9C=20=EC=95=B1?= =?UTF-8?q?=20=EB=B2=84=EC=A0=84=20=EB=8D=B0=EC=9D=B4=ED=84=B0=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../setting/graph/main/SettingScreen.kt | 31 +++++++++++++++++-- .../setting/graph/main/SettingViewModel.kt | 6 +++- .../graph/main/contract/SettingState.kt | 2 +- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/feature/setting/src/main/java/com/puzzle/setting/graph/main/SettingScreen.kt b/feature/setting/src/main/java/com/puzzle/setting/graph/main/SettingScreen.kt index efb4a617..8be35cf8 100644 --- a/feature/setting/src/main/java/com/puzzle/setting/graph/main/SettingScreen.kt +++ b/feature/setting/src/main/java/com/puzzle/setting/graph/main/SettingScreen.kt @@ -1,5 +1,7 @@ package com.puzzle.setting.graph.main +import android.content.Context +import android.content.pm.PackageManager import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement @@ -22,6 +24,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextDecoration @@ -43,14 +46,22 @@ import com.puzzle.domain.model.auth.OAuthProvider import com.puzzle.setting.graph.main.contract.SettingIntent import com.puzzle.setting.graph.main.contract.SettingState + @Composable internal fun SettingRoute( viewModel: SettingViewModel = mavericksViewModel(), ) { val state by viewModel.collectAsState() + val context = LocalContext.current val lifecycleOwner = LocalLifecycleOwner.current LaunchedEffect(viewModel) { + val version = getVersionInfo( + context = context, + onError = { viewModel.errorHelper.sendError(it) }, + ) + viewModel.setAppVersion(version?.let { "v$it" } ?: "") + lifecycleOwner.repeatOnStarted { viewModel.sideEffects.collect { sideEffect -> } @@ -131,7 +142,7 @@ private fun SettingScreen( isMatchingNotificationEnabled = state.isMatchingNotificationEnabled, isPushNotificationEnabled = state.isPushNotificationEnabled, onMatchingNotificationCheckedChange = {}, - onPushNotificationCheckedChagne = {}, + onPushNotificationCheckedChange = {}, ) SystemSettingBody( @@ -220,7 +231,7 @@ private fun NotificationBody( isMatchingNotificationEnabled: Boolean, isPushNotificationEnabled: Boolean, onMatchingNotificationCheckedChange: () -> Unit, - onPushNotificationCheckedChagne: () -> Unit, + onPushNotificationCheckedChange: () -> Unit, ) { Text( text = stringResource(R.string.setting_notification), @@ -263,7 +274,7 @@ private fun NotificationBody( PieceToggle( checked = isPushNotificationEnabled, - onCheckedChange = onPushNotificationCheckedChagne, + onCheckedChange = onPushNotificationCheckedChange, ) } @@ -577,3 +588,17 @@ private fun PreviewLogoutDialog() { ) } } + +private fun getVersionInfo( + context: Context, + onError: (Exception) -> Unit, +): String? { + var version: String? = null + try { + val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0) + version = packageInfo.versionName + } catch (e: PackageManager.NameNotFoundException) { + onError(e) + } + return version +} diff --git a/feature/setting/src/main/java/com/puzzle/setting/graph/main/SettingViewModel.kt b/feature/setting/src/main/java/com/puzzle/setting/graph/main/SettingViewModel.kt index 67178bd1..4d1b6c47 100644 --- a/feature/setting/src/main/java/com/puzzle/setting/graph/main/SettingViewModel.kt +++ b/feature/setting/src/main/java/com/puzzle/setting/graph/main/SettingViewModel.kt @@ -31,7 +31,7 @@ class SettingViewModel @AssistedInject constructor( private val authRepository: AuthRepository, private val userRepository: UserRepository, internal val navigationHelper: NavigationHelper, - private val errorHelper: ErrorHelper, + internal val errorHelper: ErrorHelper, ) : MavericksViewModel(initialState) { private val _intents = Channel(BUFFERED) @@ -60,6 +60,10 @@ class SettingViewModel @AssistedInject constructor( .onFailure { errorHelper.sendError(it) } } + internal fun setAppVersion(version: String) = setState { + copy(version = version) + } + internal fun onIntent(intent: SettingIntent) = viewModelScope.launch { _intents.send(intent) } diff --git a/feature/setting/src/main/java/com/puzzle/setting/graph/main/contract/SettingState.kt b/feature/setting/src/main/java/com/puzzle/setting/graph/main/contract/SettingState.kt index 016308bb..8722440a 100644 --- a/feature/setting/src/main/java/com/puzzle/setting/graph/main/contract/SettingState.kt +++ b/feature/setting/src/main/java/com/puzzle/setting/graph/main/contract/SettingState.kt @@ -11,5 +11,5 @@ data class SettingState( val isPushNotificationEnabled: Boolean = false, val isContactBlocked: Boolean = false, val lastRefreshTime: String = "MM월 DD일 오전 00:00", - val version: String = "v1.0", + val version: String = "", ) : MavericksState From 72dbc03f939baeefe604c6d7ffec327c25b130ab Mon Sep 17 00:00:00 2001 From: tgyuuAn Date: Thu, 13 Feb 2025 17:16:32 +0900 Subject: [PATCH 6/9] =?UTF-8?q?[PC-596]=20=ED=86=A0=EA=B8=80=20=EA=B6=8C?= =?UTF-8?q?=ED=95=9C=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=20API=20?= =?UTF-8?q?=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/repository/UserRepositoryImpl.kt | 9 ++++++++ .../domain/repository/UserRepository.kt | 3 +++ .../java/com/puzzle/network/api/PieceApi.kt | 11 ++++++++++ .../model/user/UpdateSettingRequest.kt | 5 +++++ .../network/source/user/UserDataSource.kt | 10 +++++++++ .../setting/graph/main/SettingViewModel.kt | 22 +++++++++++++++++++ .../graph/main/contract/SettingIntent.kt | 3 +++ 7 files changed, 63 insertions(+) create mode 100644 core/network/src/main/java/com/puzzle/network/model/user/UpdateSettingRequest.kt diff --git a/core/data/src/main/java/com/puzzle/data/repository/UserRepositoryImpl.kt b/core/data/src/main/java/com/puzzle/data/repository/UserRepositoryImpl.kt index 30afcbc8..179eef5b 100644 --- a/core/data/src/main/java/com/puzzle/data/repository/UserRepositoryImpl.kt +++ b/core/data/src/main/java/com/puzzle/data/repository/UserRepositoryImpl.kt @@ -21,4 +21,13 @@ class UserRepositoryImpl @Inject constructor( override suspend fun getUserSettingInfo(): Result = userDataSource.getSettingsInfo().mapCatching(GetSettingInfoResponse::toDomain) + + override suspend fun updatePushNotification(toggle: Boolean): Result = + userDataSource.updatePushNotification(toggle) + + override suspend fun updateMatchNotification(toggle: Boolean): Result = + userDataSource.updateMatchNotification(toggle) + + override suspend fun updateBlockAcquaintances(toggle: Boolean): Result = + userDataSource.updateBlockAcquaintances(toggle) } diff --git a/core/domain/src/main/java/com/puzzle/domain/repository/UserRepository.kt b/core/domain/src/main/java/com/puzzle/domain/repository/UserRepository.kt index 5e4c2fee..004f93bd 100644 --- a/core/domain/src/main/java/com/puzzle/domain/repository/UserRepository.kt +++ b/core/domain/src/main/java/com/puzzle/domain/repository/UserRepository.kt @@ -6,4 +6,7 @@ import com.puzzle.domain.model.user.UserSetting interface UserRepository { suspend fun getUserRole(): Result suspend fun getUserSettingInfo(): Result + suspend fun updatePushNotification(toggle: Boolean): Result + suspend fun updateMatchNotification(toggle: Boolean): Result + suspend fun updateBlockAcquaintances(toggle: Boolean): Result } diff --git a/core/network/src/main/java/com/puzzle/network/api/PieceApi.kt b/core/network/src/main/java/com/puzzle/network/api/PieceApi.kt index 7fd36c8d..e6a65a7b 100644 --- a/core/network/src/main/java/com/puzzle/network/api/PieceApi.kt +++ b/core/network/src/main/java/com/puzzle/network/api/PieceApi.kt @@ -22,12 +22,14 @@ import com.puzzle.network.model.terms.LoadTermsResponse import com.puzzle.network.model.token.RefreshTokenRequest import com.puzzle.network.model.token.RefreshTokenResponse import com.puzzle.network.model.user.GetSettingInfoResponse +import com.puzzle.network.model.user.UpdateSettingRequest import okhttp3.MultipartBody import retrofit2.http.Body import retrofit2.http.GET import retrofit2.http.Multipart import retrofit2.http.PATCH import retrofit2.http.POST +import retrofit2.http.PUT import retrofit2.http.Part import retrofit2.http.Path import retrofit2.http.Query @@ -102,4 +104,13 @@ interface PieceApi { @GET("/api/settings/infos") suspend fun getSettingInfos(): Result> + + @PUT("/api/settings/notification") + suspend fun updatePushNotification(@Body updateSettingRequest: UpdateSettingRequest): Result> + + @PUT("/api/settings/notification/match") + suspend fun updateMatchNotification(@Body updateSettingRequest: UpdateSettingRequest): Result> + + @PUT("/api/settings/block/acquaintance") + suspend fun updateBlockAcquaintances(@Body updateSettingRequest: UpdateSettingRequest): Result> } diff --git a/core/network/src/main/java/com/puzzle/network/model/user/UpdateSettingRequest.kt b/core/network/src/main/java/com/puzzle/network/model/user/UpdateSettingRequest.kt new file mode 100644 index 00000000..bb810f8f --- /dev/null +++ b/core/network/src/main/java/com/puzzle/network/model/user/UpdateSettingRequest.kt @@ -0,0 +1,5 @@ +package com.puzzle.network.model.user + +data class UpdateSettingRequest( + val toggle: Boolean, +) diff --git a/core/network/src/main/java/com/puzzle/network/source/user/UserDataSource.kt b/core/network/src/main/java/com/puzzle/network/source/user/UserDataSource.kt index 729930a7..1d0da7c0 100644 --- a/core/network/src/main/java/com/puzzle/network/source/user/UserDataSource.kt +++ b/core/network/src/main/java/com/puzzle/network/source/user/UserDataSource.kt @@ -3,6 +3,7 @@ package com.puzzle.network.source.user import com.puzzle.network.api.PieceApi import com.puzzle.network.model.unwrapData import com.puzzle.network.model.user.GetSettingInfoResponse +import com.puzzle.network.model.user.UpdateSettingRequest import javax.inject.Inject class UserDataSource @Inject constructor( @@ -10,4 +11,13 @@ class UserDataSource @Inject constructor( ) { suspend fun getSettingsInfo(): Result = pieceApi.getSettingInfos().unwrapData() + + suspend fun updatePushNotification(toggle: Boolean): Result = + pieceApi.updatePushNotification(UpdateSettingRequest(toggle)).unwrapData() + + suspend fun updateMatchNotification(toggle: Boolean): Result = + pieceApi.updateMatchNotification(UpdateSettingRequest(toggle)).unwrapData() + + suspend fun updateBlockAcquaintances(toggle: Boolean): Result = + pieceApi.updateBlockAcquaintances(UpdateSettingRequest(toggle)).unwrapData() } diff --git a/feature/setting/src/main/java/com/puzzle/setting/graph/main/SettingViewModel.kt b/feature/setting/src/main/java/com/puzzle/setting/graph/main/SettingViewModel.kt index 4d1b6c47..10d55072 100644 --- a/feature/setting/src/main/java/com/puzzle/setting/graph/main/SettingViewModel.kt +++ b/feature/setting/src/main/java/com/puzzle/setting/graph/main/SettingViewModel.kt @@ -87,6 +87,10 @@ class SettingViewModel @AssistedInject constructor( "이용약관", BuildConfig.PIECE_TERMS_OF_USE_URL ) + + is SettingIntent.UpdateBlockAcquaintances -> updateBlockAcquaintances(intent.toggle) + is SettingIntent.UpdateMatchNotification -> updateMatchNotification(intent.toggle) + is SettingIntent.UpdatePushNotification -> updatePushNotification(intent.toggle) } } @@ -109,6 +113,24 @@ class SettingViewModel @AssistedInject constructor( .onFailure { errorHelper.sendError(it) } } + private fun updateBlockAcquaintances(toggle: Boolean) = viewModelScope.launch { + userRepository.updateBlockAcquaintances(toggle) + .onSuccess { setState { copy(isContactBlocked = toggle) } } + .onFailure { errorHelper.sendError(it) } + } + + private fun updateMatchNotification(toggle: Boolean) = viewModelScope.launch { + userRepository.updateMatchNotification(toggle) + .onSuccess { setState { copy(isMatchingNotificationEnabled = toggle) } } + .onFailure { errorHelper.sendError(it) } + } + + private fun updatePushNotification(toggle: Boolean) = viewModelScope.launch { + userRepository.updatePushNotification(toggle) + .onSuccess { setState { copy(isPushNotificationEnabled = toggle) } } + .onFailure { errorHelper.sendError(it) } + } + @AssistedFactory interface Factory : AssistedViewModelFactory { override fun create(state: SettingState): SettingViewModel diff --git a/feature/setting/src/main/java/com/puzzle/setting/graph/main/contract/SettingIntent.kt b/feature/setting/src/main/java/com/puzzle/setting/graph/main/contract/SettingIntent.kt index c99dba96..6791ba76 100644 --- a/feature/setting/src/main/java/com/puzzle/setting/graph/main/contract/SettingIntent.kt +++ b/feature/setting/src/main/java/com/puzzle/setting/graph/main/contract/SettingIntent.kt @@ -7,4 +7,7 @@ sealed class SettingIntent { data object OnPrivacyAndPolicyClick : SettingIntent() data object OnTermsOfUseClick : SettingIntent() data object OnInquiryClick : SettingIntent() + data class UpdatePushNotification(val toggle: Boolean) : SettingIntent() + data class UpdateMatchNotification(val toggle: Boolean) : SettingIntent() + data class UpdateBlockAcquaintances(val toggle: Boolean) : SettingIntent() } From 880affd40f5ae474d47204d8e93f94c774ae501a Mon Sep 17 00:00:00 2001 From: tgyuuAn Date: Thu, 13 Feb 2025 17:29:45 +0900 Subject: [PATCH 7/9] =?UTF-8?q?[PC-596]=20=EC=97=B0=EB=9D=BD=EC=B2=98=20?= =?UTF-8?q?=EB=8F=99=EA=B8=B0=ED=99=94=20=EC=95=A0=EB=8B=88=EB=A9=94?= =?UTF-8?q?=EC=9D=B4=EC=85=98=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/user/UpdateSettingRequest.kt | 3 ++ .../setting/graph/main/SettingScreen.kt | 48 +++++++++++-------- .../setting/graph/main/SettingViewModel.kt | 36 ++++++++------ .../graph/main/contract/SettingIntent.kt | 6 +-- .../graph/main/contract/SettingState.kt | 1 - 5 files changed, 54 insertions(+), 40 deletions(-) diff --git a/core/network/src/main/java/com/puzzle/network/model/user/UpdateSettingRequest.kt b/core/network/src/main/java/com/puzzle/network/model/user/UpdateSettingRequest.kt index bb810f8f..83d8afff 100644 --- a/core/network/src/main/java/com/puzzle/network/model/user/UpdateSettingRequest.kt +++ b/core/network/src/main/java/com/puzzle/network/model/user/UpdateSettingRequest.kt @@ -1,5 +1,8 @@ package com.puzzle.network.model.user +import kotlinx.serialization.Serializable + +@Serializable data class UpdateSettingRequest( val toggle: Boolean, ) diff --git a/feature/setting/src/main/java/com/puzzle/setting/graph/main/SettingScreen.kt b/feature/setting/src/main/java/com/puzzle/setting/graph/main/SettingScreen.kt index 8be35cf8..0107a73a 100644 --- a/feature/setting/src/main/java/com/puzzle/setting/graph/main/SettingScreen.kt +++ b/feature/setting/src/main/java/com/puzzle/setting/graph/main/SettingScreen.kt @@ -2,6 +2,11 @@ package com.puzzle.setting.graph.main import android.content.Context import android.content.pm.PackageManager +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.fadeIn +import androidx.compose.animation.shrinkOut +import androidx.compose.animation.slideInVertically +import androidx.compose.animation.slideOutVertically import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement @@ -30,11 +35,9 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.lifecycle.compose.LocalLifecycleOwner import com.airbnb.mvrx.compose.collectAsState import com.airbnb.mvrx.compose.mavericksViewModel import com.puzzle.common.ui.clickable -import com.puzzle.common.ui.repeatOnStarted import com.puzzle.designsystem.R import com.puzzle.designsystem.component.PieceDialog import com.puzzle.designsystem.component.PieceDialogBottom @@ -53,7 +56,6 @@ internal fun SettingRoute( ) { val state by viewModel.collectAsState() val context = LocalContext.current - val lifecycleOwner = LocalLifecycleOwner.current LaunchedEffect(viewModel) { val version = getVersionInfo( @@ -61,11 +63,6 @@ internal fun SettingRoute( onError = { viewModel.errorHelper.sendError(it) }, ) viewModel.setAppVersion(version?.let { "v$it" } ?: "") - - lifecycleOwner.repeatOnStarted { - viewModel.sideEffects.collect { sideEffect -> - } - } } SettingScreen( @@ -76,6 +73,9 @@ internal fun SettingRoute( onPrivacyAndPolicyClick = { viewModel.onIntent(SettingIntent.OnPrivacyAndPolicyClick) }, onTermsOfUseClick = { viewModel.onIntent(SettingIntent.OnTermsOfUseClick) }, onInquiryClick = { viewModel.onIntent(SettingIntent.OnInquiryClick) }, + onUpdatePushNotification = { viewModel.onIntent(SettingIntent.UpdatePushNotification) }, + onUpdateMatchNotification = { viewModel.onIntent(SettingIntent.UpdateMatchNotification) }, + onUpdateBlockAcquaintances = { viewModel.onIntent(SettingIntent.UpdateBlockAcquaintances) }, ) } @@ -88,6 +88,9 @@ private fun SettingScreen( onPrivacyAndPolicyClick: () -> Unit, onTermsOfUseClick: () -> Unit, onInquiryClick: () -> Unit, + onUpdatePushNotification: () -> Unit, + onUpdateMatchNotification: () -> Unit, + onUpdateBlockAcquaintances: () -> Unit, ) { var isLogoutDialogShow by remember { mutableStateOf(false) } @@ -141,14 +144,14 @@ private fun SettingScreen( NotificationBody( isMatchingNotificationEnabled = state.isMatchingNotificationEnabled, isPushNotificationEnabled = state.isPushNotificationEnabled, - onMatchingNotificationCheckedChange = {}, - onPushNotificationCheckedChange = {}, + onMatchingNotificationCheckedChange = onUpdateMatchNotification, + onPushNotificationCheckedChange = onUpdatePushNotification, ) SystemSettingBody( isContactBlocked = state.isContactBlocked, lastRefreshTime = state.lastRefreshTime, - onContactBlockedCheckedChange = {}, + onContactBlockedCheckedChange = onUpdateBlockAcquaintances, onRefreshClick = {}, ) @@ -318,16 +321,17 @@ private fun SystemSettingBody( ) } - if (isContactBlocked) { + AnimatedVisibility( + visible = isContactBlocked, + enter = fadeIn() + slideInVertically(), + exit = shrinkOut() + slideOutVertically(), + modifier = Modifier.fillMaxWidth(), + ) { Row( verticalAlignment = Alignment.CenterVertically, - modifier = Modifier - .fillMaxWidth() - .padding(vertical = 16.dp), + modifier = Modifier.padding(vertical = 16.dp), ) { - Column( - modifier = Modifier.weight(1f) - ) { + Column(modifier = Modifier.weight(1f)) { Text( text = stringResource(R.string.setting_sync_contacts), style = PieceTheme.typography.headingSSB, @@ -546,21 +550,23 @@ private fun PreviewSettingScreen() { PieceTheme { SettingScreen( state = SettingState( - isLoading = false, oAuthProvider = OAuthProvider.KAKAO, email = "example@kakao.com", isMatchingNotificationEnabled = true, isPushNotificationEnabled = false, isContactBlocked = true, lastRefreshTime = "MM월 DD일 오전 00:00", - version = "v1.0", + version = "v1.0.0", ), onWithdrawClick = {}, onLogoutClick = {}, onNoticeClick = {}, - onPrivacyAndPolicyClick = { }, + onPrivacyAndPolicyClick = {}, onTermsOfUseClick = {}, onInquiryClick = {}, + onUpdatePushNotification = {}, + onUpdateMatchNotification = {}, + onUpdateBlockAcquaintances = {}, ) } } diff --git a/feature/setting/src/main/java/com/puzzle/setting/graph/main/SettingViewModel.kt b/feature/setting/src/main/java/com/puzzle/setting/graph/main/SettingViewModel.kt index 10d55072..5a1e1b49 100644 --- a/feature/setting/src/main/java/com/puzzle/setting/graph/main/SettingViewModel.kt +++ b/feature/setting/src/main/java/com/puzzle/setting/graph/main/SettingViewModel.kt @@ -88,9 +88,9 @@ class SettingViewModel @AssistedInject constructor( BuildConfig.PIECE_TERMS_OF_USE_URL ) - is SettingIntent.UpdateBlockAcquaintances -> updateBlockAcquaintances(intent.toggle) - is SettingIntent.UpdateMatchNotification -> updateMatchNotification(intent.toggle) - is SettingIntent.UpdatePushNotification -> updatePushNotification(intent.toggle) + SettingIntent.UpdateBlockAcquaintances -> updateBlockAcquaintances() + SettingIntent.UpdateMatchNotification -> updateMatchNotification() + SettingIntent.UpdatePushNotification -> updatePushNotification() } } @@ -113,22 +113,28 @@ class SettingViewModel @AssistedInject constructor( .onFailure { errorHelper.sendError(it) } } - private fun updateBlockAcquaintances(toggle: Boolean) = viewModelScope.launch { - userRepository.updateBlockAcquaintances(toggle) - .onSuccess { setState { copy(isContactBlocked = toggle) } } - .onFailure { errorHelper.sendError(it) } + private fun updateBlockAcquaintances() = withState { state -> + viewModelScope.launch { + userRepository.updateBlockAcquaintances(!state.isContactBlocked) + .onSuccess { setState { copy(isContactBlocked = !state.isContactBlocked) } } + .onFailure { errorHelper.sendError(it) } + } } - private fun updateMatchNotification(toggle: Boolean) = viewModelScope.launch { - userRepository.updateMatchNotification(toggle) - .onSuccess { setState { copy(isMatchingNotificationEnabled = toggle) } } - .onFailure { errorHelper.sendError(it) } + private fun updateMatchNotification() = withState { state -> + viewModelScope.launch { + userRepository.updateMatchNotification(!state.isMatchingNotificationEnabled) + .onSuccess { setState { copy(isMatchingNotificationEnabled = !state.isMatchingNotificationEnabled) } } + .onFailure { errorHelper.sendError(it) } + } } - private fun updatePushNotification(toggle: Boolean) = viewModelScope.launch { - userRepository.updatePushNotification(toggle) - .onSuccess { setState { copy(isPushNotificationEnabled = toggle) } } - .onFailure { errorHelper.sendError(it) } + private fun updatePushNotification() = withState { state -> + viewModelScope.launch { + userRepository.updatePushNotification(!state.isPushNotificationEnabled) + .onSuccess { setState { copy(isPushNotificationEnabled = !state.isPushNotificationEnabled) } } + .onFailure { errorHelper.sendError(it) } + } } @AssistedFactory diff --git a/feature/setting/src/main/java/com/puzzle/setting/graph/main/contract/SettingIntent.kt b/feature/setting/src/main/java/com/puzzle/setting/graph/main/contract/SettingIntent.kt index 6791ba76..5493b72e 100644 --- a/feature/setting/src/main/java/com/puzzle/setting/graph/main/contract/SettingIntent.kt +++ b/feature/setting/src/main/java/com/puzzle/setting/graph/main/contract/SettingIntent.kt @@ -7,7 +7,7 @@ sealed class SettingIntent { data object OnPrivacyAndPolicyClick : SettingIntent() data object OnTermsOfUseClick : SettingIntent() data object OnInquiryClick : SettingIntent() - data class UpdatePushNotification(val toggle: Boolean) : SettingIntent() - data class UpdateMatchNotification(val toggle: Boolean) : SettingIntent() - data class UpdateBlockAcquaintances(val toggle: Boolean) : SettingIntent() + data object UpdatePushNotification : SettingIntent() + data object UpdateMatchNotification : SettingIntent() + data object UpdateBlockAcquaintances : SettingIntent() } diff --git a/feature/setting/src/main/java/com/puzzle/setting/graph/main/contract/SettingState.kt b/feature/setting/src/main/java/com/puzzle/setting/graph/main/contract/SettingState.kt index 8722440a..d68c834c 100644 --- a/feature/setting/src/main/java/com/puzzle/setting/graph/main/contract/SettingState.kt +++ b/feature/setting/src/main/java/com/puzzle/setting/graph/main/contract/SettingState.kt @@ -4,7 +4,6 @@ import com.airbnb.mvrx.MavericksState import com.puzzle.domain.model.auth.OAuthProvider data class SettingState( - val isLoading: Boolean = false, val oAuthProvider: OAuthProvider? = OAuthProvider.KAKAO, val email: String = "example@kakao.com", val isMatchingNotificationEnabled: Boolean = false, From d8e2fe28491dc548acfc3e8da18d771bace8d582 Mon Sep 17 00:00:00 2001 From: tgyuuAn Date: Thu, 13 Feb 2025 18:09:30 +0900 Subject: [PATCH 8/9] =?UTF-8?q?[PC-596]=20CI/CD=EC=97=90=20URL=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/android_cd.yml | 4 ++++ .github/workflows/android_ci.yml | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/.github/workflows/android_cd.yml b/.github/workflows/android_cd.yml index e1269f47..6955f54c 100644 --- a/.github/workflows/android_cd.yml +++ b/.github/workflows/android_cd.yml @@ -35,6 +35,10 @@ jobs: echo "KAKAO_APP_KEY=${{ secrets.KAKAO_APP_KEY }}" >> local.properties echo "PIECE_DEV_BASE_URL=${{ secrets.PIECE_DEV_BASE_URL }}" >> local.properties echo "PIECE_PROD_BASE_URL=${{ secrets.PIECE_PROD_BASE_URL }}" >> local.properties + echo "PIECE_NOTICE_URL=${{ secrets.PIECE_NOTICE_URL }}" >> local.properties + echo "PIECE_PRIVACY_AND_POLICY_URL=${{ secrets.PIECE_PRIVACY_AND_POLICY_URL }}" >> local.properties + echo "PIECE_TERMS_OF_USE_URL=${{ secrets.PIECE_TERMS_OF_USE_URL }}" >> local.properties + echo "PIECE_CHANNEL_TALK_URL=${{ secrets.PIECE_CHANNEL_TALK_URL }}" >> local.properties echo "GOOGLE_WEB_CLIENT_ID=${{ secrets.GOOGLE_WEB_CLIENT_ID }}" >> local.properties - name: Build with Gradle diff --git a/.github/workflows/android_ci.yml b/.github/workflows/android_ci.yml index 6077ce6d..4285def3 100644 --- a/.github/workflows/android_ci.yml +++ b/.github/workflows/android_ci.yml @@ -38,6 +38,10 @@ jobs: echo "KAKAO_APP_KEY=${{ secrets.KAKAO_APP_KEY }}" >> local.properties echo "PIECE_DEV_BASE_URL=${{ secrets.PIECE_DEV_BASE_URL }}" >> local.properties echo "PIECE_PROD_BASE_URL=${{ secrets.PIECE_PROD_BASE_URL }}" >> local.properties + echo "PIECE_NOTICE_URL=${{ secrets.PIECE_NOTICE_URL }}" >> local.properties + echo "PIECE_PRIVACY_AND_POLICY_URL=${{ secrets.PIECE_PRIVACY_AND_POLICY_URL }}" >> local.properties + echo "PIECE_TERMS_OF_USE_URL=${{ secrets.PIECE_TERMS_OF_USE_URL }}" >> local.properties + echo "PIECE_CHANNEL_TALK_URL=${{ secrets.PIECE_CHANNEL_TALK_URL }}" >> local.properties echo "GOOGLE_WEB_CLIENT_ID=${{ secrets.GOOGLE_WEB_CLIENT_ID }}" >> local.properties - name: Build with Gradle From 3571ebb48605c2508fdacebbea515bb3872129be Mon Sep 17 00:00:00 2001 From: tgyuuAn Date: Thu, 13 Feb 2025 18:10:28 +0900 Subject: [PATCH 9/9] =?UTF-8?q?[PC-596]=20CI/CD=EC=97=90=20URL=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/ISSUE_TEMPLATE/.DS_Store | Bin 6148 -> 0 bytes app/google-services.json | 29 ----------------------------- 2 files changed, 29 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/.DS_Store delete mode 100644 app/google-services.json diff --git a/.github/ISSUE_TEMPLATE/.DS_Store b/.github/ISSUE_TEMPLATE/.DS_Store deleted file mode 100644 index 5008ddfcf53c02e82d7eee2e57c38e5672ef89f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0