Skip to content

Commit

Permalink
Merge pull request #72 from step-Mate/develop
Browse files Browse the repository at this point in the history
Release : 1.0.3
  • Loading branch information
jowunnal authored Jul 25, 2024
2 parents c35a6fd + 6c59ab7 commit 9dfedbd
Show file tree
Hide file tree
Showing 11 changed files with 78 additions and 154 deletions.
4 changes: 2 additions & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ android {
defaultConfig {
applicationId = "com.stepmate.app"
targetSdk = 34
versionCode = 9
versionName = "1.0.2"
versionCode = 11
versionName = "1.0.3"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
Expand Down
19 changes: 0 additions & 19 deletions app/src/main/kotlin/com/stepmate/app/StepMateActivity.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.stepmate.app

import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import android.view.View
import android.view.ViewTreeObserver
Expand Down Expand Up @@ -37,13 +36,11 @@ import androidx.core.view.WindowCompat
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.lifecycleScope
import androidx.navigation.compose.rememberNavController
import androidx.navigation.findNavController
import com.stepmate.app.ui.StepMateViewModel
import com.stepmate.app.ui.navigation.NavigationDefaults
import com.stepmate.app.ui.navigation.NavigationGraph
import com.stepmate.app.ui.navigation.Router
import com.stepmate.app.ui.navigation.isShownBar
import com.stepmate.app.ui.navigation.permission.PermissionViewModel
import com.stepmate.app.ui.navigation.stepMateNavigationSuiteItems
import com.stepmate.design.component.StepMateSnackBar
import com.stepmate.design.theme.StepMateTheme
Expand Down Expand Up @@ -95,22 +92,6 @@ class StepMateActivity : ComponentActivity() {
}
}

@Deprecated("Deprecated in Java")
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray,
) {
when (requestCode) {
PermissionViewModel.ACTIVITY_RECOGNITION_CODE ->
stepMateViewModel.updateActivityRecognition(grantResults.first() == PackageManager.PERMISSION_GRANTED)

PermissionViewModel.HEALTH_CONNECT_CODE ->
stepMateViewModel.updateHealthConnect(grantResults.all { r -> r == PackageManager.PERMISSION_GRANTED })
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}

@OptIn(
ExperimentalMaterial3AdaptiveNavigationSuiteApi::class,
ExperimentalMaterial3AdaptiveApi::class
Expand Down
43 changes: 4 additions & 39 deletions app/src/main/kotlin/com/stepmate/app/ui/StepMateViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,26 +27,6 @@ internal class StepMateViewModel @Inject constructor(

fun updateIsNeedLogin(bool: Boolean) = _isNeedReLogin.update { bool }

fun updateActivityRecognition(bool: Boolean) {
_startDestinationInfo.update { info ->
info.copy(
underApi31HasPermission = info.underApi31HasPermission.copy(
isActivityRecognitionGranted = bool
)
)
}
}

fun updateHealthConnect(bool: Boolean) {
_startDestinationInfo.update { info ->
info.copy(
underApi31HasPermission = info.underApi31HasPermission.copy(
isHealthConnectGranted = bool
)
)
}
}

private val _startDestinationInfo = MutableStateFlow(StartDestinationInfo())

val startDestinationInfo = _startDestinationInfo.asStateFlow()
Expand All @@ -56,20 +36,11 @@ internal class StepMateViewModel @Inject constructor(
}.first()

suspend fun checkPermission() {
val isNotificationGranted =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU)
PermissionRequester.checkNotification(applicationContext)
else
true

val isActivityRecognitionGranted =
PermissionRequester.checkActivityRecognition(applicationContext)
val permissionResults = PermissionRequester.checkAllPermissions(applicationContext)

val isExactAlarmGranted =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
PermissionRequester.checkExactAlarm(applicationContext)
else
true
val isNotificationGranted = permissionResults.notification
val isActivityRecognitionGranted = permissionResults.activityRecognition
val isExactAlarmGranted = permissionResults.exactAlarm

val isHealthConnectGranted = runCatching {
healthConnector.checkPermissions(HealthConnector.healthConnectPermissions)
Expand All @@ -87,10 +58,4 @@ internal class StepMateViewModel @Inject constructor(
data class StartDestinationInfo(
val hasPermission: Boolean = false,
val hasBodyData: Boolean = false,
val underApi31HasPermission: UnderApi31Permission = UnderApi31Permission(),
)

data class UnderApi31Permission(
val isActivityRecognitionGranted: Boolean = false,
val isHealthConnectGranted: Boolean = false,
)
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ internal fun NavigationGraph(
modifier = modifier
) {
permissionNavGraph(
underApi31Permission = startDestinationInfo.underApi31HasPermission,
paddingValues = paddingValues,
showSnackBar = showSnackBar,
navigateToHomeGraph = navController::navigateToHomeGraph,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import androidx.navigation.NavOptions
import androidx.navigation.compose.composable
import androidx.navigation.navOptions
import androidx.navigation.navigation
import com.stepmate.app.ui.UnderApi31Permission
import com.stepmate.app.ui.navigation.permission.PermissionRoute.permissionGraph
import com.stepmate.app.ui.navigation.permission.PermissionRoute.permissionRoute
import com.stepmate.core.SnackBarMessage
Expand All @@ -19,7 +18,6 @@ object PermissionRoute {
}

fun NavGraphBuilder.permissionNavGraph(
underApi31Permission: UnderApi31Permission,
paddingValues: PaddingValues,
showSnackBar: (SnackBarMessage) -> Unit,
navigateToHomeGraph: (NavOptions?) -> Unit,
Expand All @@ -30,7 +28,6 @@ fun NavGraphBuilder.permissionNavGraph(
) {
composable(route = permissionRoute) {
PermissionScreen(
underApi31Permission = underApi31Permission,
modifier = Modifier.padding(paddingValues),
showSnackBar = showSnackBar,
navigateToHomeGraph = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,39 @@ object PermissionRequester {
}

@RequiresApi(Build.VERSION_CODES.S)
fun checkExactAlarm(context: Context) : Boolean {
fun checkExactAlarm(context: Context): Boolean {
val alarmManager =
context.getSystemService(Context.ALARM_SERVICE) as AlarmManager

return alarmManager.canScheduleExactAlarms()
}

class PermissionResults(
val notification: Boolean = false,
val activityRecognition: Boolean = false,
val exactAlarm: Boolean = false,
)

fun checkAllPermissions(applicationContext: Context): PermissionResults {
val isNotificationGranted =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU)
checkNotification(applicationContext)
else
true

val isActivityRecognitionGranted =
checkActivityRecognition(applicationContext)

val isExactAlarmGranted =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
checkExactAlarm(applicationContext)
else
true

return PermissionResults(
notification = isNotificationGranted,
activityRecognition = isActivityRecognitionGranted,
exactAlarm = isExactAlarmGranted,
)
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
package com.stepmate.app.ui.navigation.permission

import android.Manifest
import android.app.AlarmManager
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.os.Build
import android.provider.Settings
import androidx.activity.ComponentActivity
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContract
import androidx.activity.result.contract.ActivityResultContracts
Expand All @@ -25,19 +23,15 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.produceState
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.core.app.ActivityCompat
import androidx.health.connect.client.PermissionController
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.LifecycleStartEffect
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.stepmate.app.ui.UnderApi31Permission
import com.stepmate.core.SnackBarMessage
import com.stepmate.design.component.DescriptionLargeText
import com.stepmate.design.component.DescriptionSmallText
Expand All @@ -50,11 +44,11 @@ import com.stepmate.design.component.VerticalSpacer
import com.stepmate.design.component.clickableAvoidingDuplication
import com.stepmate.design.component.layout.DefaultLayout
import com.stepmate.design.theme.StepMateTheme
import com.stepmate.home.HealthConnector
import com.stepmate.home.HealthConnector.Companion.healthConnectPermissions

@Composable
internal fun PermissionScreen(
underApi31Permission: UnderApi31Permission,
modifier: Modifier = Modifier,
permissionViewModel: PermissionViewModel = hiltViewModel(),
showSnackBar: (SnackBarMessage) -> Unit,
Expand All @@ -65,31 +59,14 @@ internal fun PermissionScreen(
val exactAlarmPermission by permissionViewModel.exactAlarmPermission.collectAsStateWithLifecycle()
val healthConnectPermission by permissionViewModel.healthConnectPermission.collectAsStateWithLifecycle()
val dialogState by permissionViewModel.dialogState.collectAsStateWithLifecycle()
val healthConnectPermissionContract = remember {
permissionViewModel.healthConnectPermissionContract
}

val underApi31PermissionGranted by produceState(
initialValue = false,
key1 = underApi31Permission.isActivityRecognitionGranted,
key2 = underApi31Permission.isHealthConnectGranted,
) {
this.value =
underApi31Permission.isActivityRecognitionGranted && underApi31Permission.isHealthConnectGranted
}

SideEffect {
if (Build.VERSION.SDK_INT >= 31) {
if (notificationPermission && activityRecognitionPermission && exactAlarmPermission && healthConnectPermission)
navigateToHomeGraph()
} else
if (underApi31PermissionGranted)
navigateToHomeGraph()
if (notificationPermission && activityRecognitionPermission && exactAlarmPermission && healthConnectPermission)
navigateToHomeGraph()
}

PermissionScreen(
modifier = modifier,
healthConnectPermissionContract = healthConnectPermissionContract,
requireInstallHealthApk = permissionViewModel::requireInstallHealthApk,
showSnackBar = showSnackBar,
notificationPermission = notificationPermission,
Expand All @@ -107,7 +84,6 @@ internal fun PermissionScreen(
private fun PermissionScreen(
modifier: Modifier = Modifier,
context: Context = LocalContext.current,
healthConnectPermissionContract: ActivityResultContract<Set<String>, Set<String>>,
requireInstallHealthApk: () -> Unit,
showSnackBar: (SnackBarMessage) -> Unit,
notificationPermission: Boolean,
Expand Down Expand Up @@ -162,7 +138,6 @@ private fun PermissionScreen(
PermissionActivityResultDescription(
buttonStatus = notificationPermission,
headline = "알림",
type = PermissionViewModel.Permission.NOTIFICATION,
desc = "실시간 만보기 수치 표시, 미션 달성, 친구 신청, 공지 사항 등의 기능을 수신하기 위한 알림 권한이 필요해요.",
permissionContract = ActivityResultContracts.RequestPermission(),
onPermissionResult = { result ->
Expand All @@ -172,13 +147,12 @@ private fun PermissionScreen(
context
)
},
permission = Manifest.permission.POST_NOTIFICATIONS,
permission = PermissionViewModel.Permission.NOTIFICATION.toAppSettingsPermissionOrNull(),
showSnackBar = showSnackBar,
)
VerticalSpacer(height = 40.dp)
PermissionActivityResultDescription(
buttonStatus = activityRecognitionPermission,
type = PermissionViewModel.Permission.ACTIVITY_RECOGNITION,
headline = "신체 활동",
desc = "만보기 기능을 이용하기 위해 실시간으로 스마트폰의 센서로 부터 걸음수를 수집하고 있어요.\n해당 권한을 수락해 주셔야 걸음수를 수집할 수 있어요.",
permissionContract = ActivityResultContracts.RequestPermission(),
Expand All @@ -189,16 +163,15 @@ private fun PermissionScreen(
context
)
},
permission = Manifest.permission.ACTIVITY_RECOGNITION,
permission = PermissionViewModel.Permission.ACTIVITY_RECOGNITION.toAppSettingsPermissionOrNull(),
showSnackBar = showSnackBar,
)
VerticalSpacer(height = 40.dp)
PermissionActivityResultDescription(
buttonStatus = healthConnectPermission,
type = PermissionViewModel.Permission.HEALTH_CONNECT,
headline = "헬스 커넥트",
desc = "수집한 걸음수를 저장하기 위해 헬스 커넥트에 읽고 쓸수 있는 권한이 필요해요.\nStepMate는 차후 걸음수 뿐만 아니라 다양한 헬스 데이터를 활용하여 더 좋은 경험을 제공해 드릴 예정이에요.",
permissionContract = healthConnectPermissionContract,
permissionContract = HealthConnector.requestPermissionsActivityContract(),
onPermissionResult = { result ->
val isGranted = result.containsAll(
healthConnectPermissions
Expand All @@ -210,7 +183,7 @@ private fun PermissionScreen(
context
)
},
permission = healthConnectPermissions,
permission = PermissionViewModel.Permission.HEALTH_CONNECT.toHealthConnectPermissionOrNull(),
showSnackBar = showSnackBar,
onException = { t ->
if (t is ActivityNotFoundException)
Expand All @@ -236,14 +209,12 @@ private fun PermissionScreen(

@Composable
internal fun <I, O> PermissionActivityResultDescription(
context: Context = LocalContext.current,
buttonStatus: Boolean,
type: PermissionViewModel.Permission,
headline: String,
desc: String,
permissionContract: ActivityResultContract<I, O>,
onPermissionResult: (O) -> Unit,
permission: I,
permission: I?,
showSnackBar: (SnackBarMessage) -> Unit,
onException: (Throwable) -> Unit = {},
) {
Expand All @@ -257,26 +228,13 @@ internal fun <I, O> PermissionActivityResultDescription(
headline = headline,
desc = desc,
requestPermission = {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
runCatching {
runCatching {
permission?.let {
permissionLauncher.launch(permission)
}.onFailure { e ->
onException(e)
}
else
ActivityCompat.requestPermissions(
context as ComponentActivity,
when (permission) {
is Set<*> -> permission.filterIsInstance<String>().toTypedArray()
is String -> arrayOf(permission)
else -> emptyArray()
},
when (type) {
PermissionViewModel.Permission.ACTIVITY_RECOGNITION -> PermissionViewModel.ACTIVITY_RECOGNITION_CODE
PermissionViewModel.Permission.HEALTH_CONNECT -> PermissionViewModel.HEALTH_CONNECT_CODE
else -> 0
}
)
} ?: onException(Throwable("[$permission] 은 잘못된 권한 입니다."))
}.onFailure { e ->
onException(e)
}
},
showSnackBar = showSnackBar,
)
Expand Down Expand Up @@ -333,7 +291,6 @@ internal fun PermissionDescription(
@Preview
private fun PreviewPermissionScreen() = StepMateTheme {
PermissionScreen(
healthConnectPermissionContract = PermissionController.createRequestPermissionResultContract(),
showSnackBar = {},
notificationPermission = true,
activityRecognitionPermission = false,
Expand Down
Loading

0 comments on commit 9dfedbd

Please sign in to comment.