From 540056e2310f170bf5cd444b289ecd7f56c7bb4e Mon Sep 17 00:00:00 2001 From: comst19 Date: Thu, 8 Jan 2026 23:04:25 +0900 Subject: [PATCH 1/7] =?UTF-8?q?[PC-1627]=20=ED=8B=B0=EB=9D=BC=EB=AF=B8?= =?UTF-8?q?=EC=88=98=20=EC=9D=B4=ED=95=98=20=EB=B2=84=EC=A0=84=20=EC=95=8C?= =?UTF-8?q?=EB=9E=8C=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95,=20?= =?UTF-8?q?=EA=B6=8C=ED=95=9C=20=ED=97=88=EC=9A=A9=20=ED=8C=9D=EC=97=85=20?= =?UTF-8?q?=EC=A0=84=20=EC=9D=B4=EB=AF=B8=20=ED=97=88=EC=9A=A9=EB=90=9C=20?= =?UTF-8?q?=EA=B6=8C=ED=95=9C=EC=9D=80=20ui=EC=97=90=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../graph/signup/page/AccessRightsPage.kt | 45 ++++++++++++++++--- 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/feature/auth/src/main/java/com/puzzle/auth/graph/signup/page/AccessRightsPage.kt b/feature/auth/src/main/java/com/puzzle/auth/graph/signup/page/AccessRightsPage.kt index 3419ff07e..4b89a5c64 100644 --- a/feature/auth/src/main/java/com/puzzle/auth/graph/signup/page/AccessRightsPage.kt +++ b/feature/auth/src/main/java/com/puzzle/auth/graph/signup/page/AccessRightsPage.kt @@ -29,6 +29,8 @@ import androidx.compose.foundation.layout.size import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext @@ -39,6 +41,9 @@ import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.withStyle import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.core.app.NotificationManagerCompat +import androidx.lifecycle.compose.LocalLifecycleOwner +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.PermissionState import com.google.accompanist.permissions.PermissionStatus @@ -59,6 +64,10 @@ internal fun ColumnScope.AccessRightsPage( onDisEnabledButtonClick: () -> Unit, ) { val context = LocalContext.current + + val lifecycleOwner = LocalLifecycleOwner.current + val lifecycleState by lifecycleOwner.lifecycle.currentStateFlow.collectAsStateWithLifecycle() + val permissionList = rememberMultiplePermissionsState( listOfNotNull( when { @@ -70,6 +79,7 @@ internal fun ColumnScope.AccessRightsPage( READ_CONTACTS ) ) + val galleryPermission = permissionList.permissions .find { it.permission in when { @@ -78,15 +88,29 @@ internal fun ColumnScope.AccessRightsPage( else -> setOf(READ_MEDIA_IMAGES, READ_MEDIA_VISUAL_USER_SELECTED) } } - val notificationPermission = permissionList.permissions - .find { if (SDK_INT >= TIRAMISU) it.permission == POST_NOTIFICATIONS else true } + + val notificationPermission = if (SDK_INT >= TIRAMISU) { + permissionList.permissions.find { it.permission == POST_NOTIFICATIONS } + } else null + val contactsPermission = permissionList.permissions .find { it.permission == READ_CONTACTS } BackHandler { onBackClick() } - LaunchedEffect(permissionList) { - permissionList.launchMultiplePermissionRequest() + val isNotificationGranted = remember(lifecycleState, notificationPermission?.status) { + if (SDK_INT >= TIRAMISU) { + notificationPermission?.status == PermissionStatus.Granted + } else { + NotificationManagerCompat.from(context).areNotificationsEnabled() + } + } + + LaunchedEffect(Unit) { + val hasDenied = permissionList.permissions.any { it.status != PermissionStatus.Granted } + if (hasDenied) { + permissionList.launchMultiplePermissionRequest() + } } PieceSubBackTopBar( @@ -128,8 +152,17 @@ internal fun ColumnScope.AccessRightsPage( icon = R.drawable.ic_permission_alarm, label = stringResource(R.string.permission_notification), description = stringResource(R.string.permission_notification_description), - checked = notificationPermission?.status == PermissionStatus.Granted, - onCheckedChange = { handlePermission(context, notificationPermission) }, + checked = isNotificationGranted, + onCheckedChange = { + if (SDK_INT >= TIRAMISU) { + handlePermission(context, notificationPermission) + } else { + val intent = Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS).apply { + putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName) + } + context.startActivity(intent) + } + }, ) PiecePermissionRow( From 3792dd97e44526a4910f2c19530977d2e30436e4 Mon Sep 17 00:00:00 2001 From: comst19 Date: Thu, 8 Jan 2026 23:34:30 +0900 Subject: [PATCH 2/7] =?UTF-8?q?[PC-1627]=20SettingScreen=20=EC=97=90?= =?UTF-8?q?=EC=84=9C=EB=8F=84=20=ED=8B=B0=EB=9D=BC=EB=AF=B8=EC=88=98=20?= =?UTF-8?q?=EC=9D=B4=ED=95=98=20=EB=B2=84=EC=A0=84=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../puzzle/setting/graph/main/SettingScreen.kt | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 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 278eb1463..5a3cdf5b9 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 @@ -40,6 +40,7 @@ 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.core.app.NotificationManagerCompat import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.LocalLifecycleOwner import androidx.lifecycle.compose.collectAsStateWithLifecycle @@ -219,13 +220,21 @@ private fun NotificationBody( isPushNotificationEnabled: Boolean, onPushNotificationCheckedChange: () -> Unit, ) { + + val context = LocalContext.current + val notificationPermission = if (SDK_INT >= TIRAMISU) rememberPermissionState(POST_NOTIFICATIONS) else null - val isPermissionGranted = notificationPermission?.status == PermissionStatus.Granted - || notificationPermission == null - val context = LocalContext.current + val isPermissionGranted = + if (SDK_INT >= TIRAMISU) { + notificationPermission?.status == PermissionStatus.Granted + } else { + NotificationManagerCompat + .from(context) + .areNotificationsEnabled() + } Text( text = stringResource(R.string.setting_notification), From a299df3872ffde256940b6e8bc3560806ce03696 Mon Sep 17 00:00:00 2001 From: comst19 Date: Thu, 8 Jan 2026 23:40:06 +0900 Subject: [PATCH 3/7] =?UTF-8?q?[PC-1627]=20SettingScreen=20=EC=97=90?= =?UTF-8?q?=EC=84=9C=EB=8F=84=20=ED=8B=B0=EB=9D=BC=EB=AF=B8=EC=88=98=20?= =?UTF-8?q?=EC=9D=B4=ED=95=98=20=EB=B2=84=EC=A0=84=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/puzzle/setting/graph/main/SettingScreen.kt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) 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 5a3cdf5b9..43368c33a 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 @@ -262,7 +262,14 @@ private fun NotificationBody( if (isPermissionGranted) { onPushNotificationCheckedChange() } else { - handlePermission(context, notificationPermission) + if (SDK_INT >= TIRAMISU) { + handlePermission(context, notificationPermission) + } else { + val intent = Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS).apply { + putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName) + } + context.startActivity(intent) + } } } ) From 9ea910f865556df16e35c98cd1831572a070170a Mon Sep 17 00:00:00 2001 From: comst19 Date: Fri, 9 Jan 2026 05:24:39 +0900 Subject: [PATCH 4/7] =?UTF-8?q?[PC-1627]=20=ED=8B=B0=EB=9D=BC=EB=AF=B8?= =?UTF-8?q?=EC=88=98=EC=97=90=EC=84=9C=20=EC=95=8C=EB=A6=BC=20=EA=B6=8C?= =?UTF-8?q?=ED=95=9C=20=EB=B3=80=EA=B2=BD=20=EC=8B=9C=20=EA=B0=90=EC=A7=80?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../puzzle/setting/graph/main/SettingScreen.kt | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) 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 43368c33a..bce717489 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 @@ -223,11 +223,19 @@ private fun NotificationBody( val context = LocalContext.current + val lifecycleOwner = LocalLifecycleOwner.current + val lifecycleState by lifecycleOwner.lifecycle + .currentStateFlow + .collectAsStateWithLifecycle() + val notificationPermission = if (SDK_INT >= TIRAMISU) rememberPermissionState(POST_NOTIFICATIONS) else null - val isPermissionGranted = + val isPermissionGranted = remember( + lifecycleState, + notificationPermission?.status + ) { if (SDK_INT >= TIRAMISU) { notificationPermission?.status == PermissionStatus.Granted } else { @@ -235,6 +243,13 @@ private fun NotificationBody( .from(context) .areNotificationsEnabled() } + } + + LaunchedEffect(isPermissionGranted) { + if (isPermissionGranted && !isPushNotificationEnabled) { + onPushNotificationCheckedChange() + } + } Text( text = stringResource(R.string.setting_notification), From 686d2ccce2b9ba6b4fd285a513a0f8cd8a3fa266 Mon Sep 17 00:00:00 2001 From: comst19 Date: Fri, 9 Jan 2026 05:36:41 +0900 Subject: [PATCH 5/7] =?UTF-8?q?[PC-1627]=20=ED=8B=B0=EB=9D=BC=EB=AF=B8?= =?UTF-8?q?=EC=88=98=20=EC=9D=B4=EC=83=81=20=EB=B2=84=EC=A0=84=EC=97=90?= =?UTF-8?q?=EC=84=9C=20isNotificationGranted=20=ED=99=95=EC=9D=B8=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 시스템 권한 || 런타임 권한 체크 --- .../com/puzzle/auth/graph/signup/page/AccessRightsPage.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/feature/auth/src/main/java/com/puzzle/auth/graph/signup/page/AccessRightsPage.kt b/feature/auth/src/main/java/com/puzzle/auth/graph/signup/page/AccessRightsPage.kt index 4b89a5c64..25080cdaa 100644 --- a/feature/auth/src/main/java/com/puzzle/auth/graph/signup/page/AccessRightsPage.kt +++ b/feature/auth/src/main/java/com/puzzle/auth/graph/signup/page/AccessRightsPage.kt @@ -99,10 +99,12 @@ internal fun ColumnScope.AccessRightsPage( BackHandler { onBackClick() } val isNotificationGranted = remember(lifecycleState, notificationPermission?.status) { + val areNotificationsEnabled = NotificationManagerCompat.from(context).areNotificationsEnabled() + if (SDK_INT >= TIRAMISU) { - notificationPermission?.status == PermissionStatus.Granted + areNotificationsEnabled || notificationPermission?.status == PermissionStatus.Granted } else { - NotificationManagerCompat.from(context).areNotificationsEnabled() + areNotificationsEnabled } } From bdb9244eb15c6fa460af7201b8d6259d60250a27 Mon Sep 17 00:00:00 2001 From: comst19 Date: Sat, 10 Jan 2026 18:26:49 +0900 Subject: [PATCH 6/7] =?UTF-8?q?[PC-1627]=20=EC=95=8C=EB=A6=BC=20=EA=B6=8C?= =?UTF-8?q?=ED=95=9C=20=ED=97=88=EC=9A=A9=20=EC=97=AC=EB=B6=80=EB=8A=94=20?= =?UTF-8?q?=EB=9F=B0=ED=83=80=EC=9E=84=EC=9D=B4=20=EC=95=84=EB=8B=8C=20?= =?UTF-8?q?=EC=8B=9C=EC=8A=A4=ED=85=9C=EC=97=90=EC=84=9C=20=EA=B0=80?= =?UTF-8?q?=EC=A0=B8=EC=98=A4=EB=8F=84=EB=A1=9D=20=ED=86=B5=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/graph/signup/page/AccessRightsPage.kt | 13 +++++-------- .../com/puzzle/setting/graph/main/SettingScreen.kt | 8 +------- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/feature/auth/src/main/java/com/puzzle/auth/graph/signup/page/AccessRightsPage.kt b/feature/auth/src/main/java/com/puzzle/auth/graph/signup/page/AccessRightsPage.kt index 25080cdaa..09c894b9f 100644 --- a/feature/auth/src/main/java/com/puzzle/auth/graph/signup/page/AccessRightsPage.kt +++ b/feature/auth/src/main/java/com/puzzle/auth/graph/signup/page/AccessRightsPage.kt @@ -98,14 +98,11 @@ internal fun ColumnScope.AccessRightsPage( BackHandler { onBackClick() } - val isNotificationGranted = remember(lifecycleState, notificationPermission?.status) { - val areNotificationsEnabled = NotificationManagerCompat.from(context).areNotificationsEnabled() - - if (SDK_INT >= TIRAMISU) { - areNotificationsEnabled || notificationPermission?.status == PermissionStatus.Granted - } else { - areNotificationsEnabled - } + val isNotificationGranted = remember( + lifecycleState, + notificationPermission?.status + ) { + NotificationManagerCompat.from(context).areNotificationsEnabled() } LaunchedEffect(Unit) { 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 bce717489..3591dfe4f 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 @@ -236,13 +236,7 @@ private fun NotificationBody( lifecycleState, notificationPermission?.status ) { - if (SDK_INT >= TIRAMISU) { - notificationPermission?.status == PermissionStatus.Granted - } else { - NotificationManagerCompat - .from(context) - .areNotificationsEnabled() - } + NotificationManagerCompat.from(context).areNotificationsEnabled() } LaunchedEffect(isPermissionGranted) { From 5d96b9e578ae27a8fb1ba86901a3abd337118ccb Mon Sep 17 00:00:00 2001 From: comst19 Date: Sat, 10 Jan 2026 19:07:16 +0900 Subject: [PATCH 7/7] =?UTF-8?q?[PC-1627]=20=EC=84=A4=EC=A0=95=20=EB=B3=B4?= =?UTF-8?q?=EB=82=B4=EB=8A=94=20=EB=A1=9C=EC=A7=81=20=ED=95=A8=EC=88=98?= =?UTF-8?q?=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../graph/signup/page/AccessRightsPage.kt | 18 +++++++++-------- .../setting/graph/main/SettingScreen.kt | 20 ++++++++++--------- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/feature/auth/src/main/java/com/puzzle/auth/graph/signup/page/AccessRightsPage.kt b/feature/auth/src/main/java/com/puzzle/auth/graph/signup/page/AccessRightsPage.kt index 09c894b9f..2d954c27e 100644 --- a/feature/auth/src/main/java/com/puzzle/auth/graph/signup/page/AccessRightsPage.kt +++ b/feature/auth/src/main/java/com/puzzle/auth/graph/signup/page/AccessRightsPage.kt @@ -156,10 +156,7 @@ internal fun ColumnScope.AccessRightsPage( if (SDK_INT >= TIRAMISU) { handlePermission(context, notificationPermission) } else { - val intent = Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS).apply { - putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName) - } - context.startActivity(intent) + navigateToAppSettings(context) } }, ) @@ -254,16 +251,21 @@ private fun PiecePermissionRow( internal fun handlePermission(context: Context, permission: PermissionState?) { permission?.let { if (it.status == PermissionStatus.Granted || !it.status.shouldShowRationale) { - val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply { - data = Uri.fromParts("package", context.packageName, null) - } - context.startActivity(intent) + navigateToAppSettings(context) } else { it.launchPermissionRequest() } } } +private fun navigateToAppSettings(context: Context) { + context.startActivity( + Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply { + data = Uri.fromParts("package", context.packageName, null) + } + ) +} + @Preview @Composable private fun AccessRightsPagePreview() { 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 3591dfe4f..7519610a7 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 @@ -274,10 +274,7 @@ private fun NotificationBody( if (SDK_INT >= TIRAMISU) { handlePermission(context, notificationPermission) } else { - val intent = Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS).apply { - putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName) - } - context.startActivity(intent) + navigateToAppSettings(context) } } } @@ -424,19 +421,24 @@ private fun SystemSettingBody( } @OptIn(ExperimentalPermissionsApi::class) -internal fun handlePermission(context: Context, permission: PermissionState?) { +private fun handlePermission(context: Context, permission: PermissionState?) { permission?.let { if (it.status == PermissionStatus.Granted || !it.status.shouldShowRationale) { - val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply { - data = Uri.fromParts("package", context.packageName, null) - } - context.startActivity(intent) + navigateToAppSettings(context) } else { it.launchPermissionRequest() } } } +private fun navigateToAppSettings(context: Context) { + context.startActivity( + Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply { + data = Uri.fromParts("package", context.packageName, null) + } + ) +} + @Composable private fun InquiryBody(onContactUsClick: () -> Unit) { Text(