-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #49 from Team-Walkie/compose/permission_settings
권한 요청 및 gps, 네트워크 상태 관리 다이얼로그 추가
- Loading branch information
Showing
21 changed files
with
498 additions
and
145 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
151 changes: 151 additions & 0 deletions
151
app/src/main/java/com/whyranoid/walkie/walkiedialog/AppManageDialog.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
package com.whyranoid.walkie.walkiedialog | ||
|
||
import android.Manifest | ||
import android.app.Activity | ||
import android.os.Build | ||
import androidx.annotation.RequiresApi | ||
import androidx.compose.foundation.clickable | ||
import androidx.compose.foundation.interaction.MutableInteractionSource | ||
import androidx.compose.foundation.layout.Column | ||
import androidx.compose.foundation.layout.fillMaxWidth | ||
import androidx.compose.foundation.layout.padding | ||
import androidx.compose.foundation.shape.RoundedCornerShape | ||
import androidx.compose.material.AlertDialog | ||
import androidx.compose.material.Text | ||
import androidx.compose.runtime.Composable | ||
import androidx.compose.runtime.LaunchedEffect | ||
import androidx.compose.runtime.remember | ||
import androidx.compose.ui.Alignment | ||
import androidx.compose.ui.Modifier | ||
import androidx.compose.ui.draw.clip | ||
import androidx.compose.ui.platform.LocalContext | ||
import androidx.compose.ui.text.style.TextAlign | ||
import androidx.compose.ui.unit.dp | ||
import androidx.lifecycle.compose.collectAsStateWithLifecycle | ||
import com.google.accompanist.permissions.ExperimentalPermissionsApi | ||
import com.google.accompanist.permissions.isGranted | ||
import com.google.accompanist.permissions.rememberPermissionState | ||
import com.google.accompanist.permissions.shouldShowRationale | ||
import com.whyranoid.presentation.theme.WalkieColor | ||
import com.whyranoid.presentation.theme.WalkieTypography | ||
import com.whyranoid.presentation.util.openSettings | ||
import com.whyranoid.presentation.util.openStatusBar | ||
import org.koin.androidx.compose.koinViewModel | ||
|
||
/** | ||
* Provide dialog | ||
* | ||
* 권한, gps, 네트워크 상태에 따른 다이얼로그 보여주기 | ||
* | ||
* 분리한 이유: ExperimentalPermissionsApi 로써 언제든 변화 가능하기 때문에 메인 비지니스 로직, UI 로직에 포함시키지 않고 따로 분리 | ||
* | ||
*/ | ||
|
||
@RequiresApi(Build.VERSION_CODES.TIRAMISU) | ||
@OptIn(ExperimentalPermissionsApi::class) | ||
@Composable | ||
fun AppManageDialog() { | ||
val viewModel = koinViewModel<DialogViewModel>() | ||
val activity = LocalContext.current as Activity | ||
|
||
val locationPermissionState = rememberPermissionState( | ||
Manifest.permission.ACCESS_FINE_LOCATION, | ||
) { isGranted -> | ||
viewModel.setPermission(Manifest.permission.ACCESS_FINE_LOCATION, isGranted) | ||
} | ||
|
||
val storagePermissionState = rememberPermissionState( | ||
Manifest.permission.READ_EXTERNAL_STORAGE, | ||
) { isGranted -> | ||
viewModel.setPermission(Manifest.permission.READ_EXTERNAL_STORAGE, isGranted) | ||
} | ||
|
||
val locationDialogState = viewModel.locationPermissionDialogState.collectAsStateWithLifecycle() | ||
val storageDialogState = viewModel.storagePermissionDialogState.collectAsStateWithLifecycle() | ||
val gpsDialogState = | ||
viewModel.gpsDialogState.collectAsStateWithLifecycle(initialValue = DialogState.Initialized) | ||
val networkDialogState = | ||
viewModel.networkDialogState.collectAsStateWithLifecycle(initialValue = DialogState.Initialized) | ||
|
||
LaunchedEffect( | ||
locationDialogState.value, | ||
storageDialogState.value, | ||
gpsDialogState.value, | ||
networkDialogState.value, | ||
) { | ||
if (locationPermissionState.status.isGranted.not() && locationPermissionState.status.shouldShowRationale.not()) { | ||
locationPermissionState.launchPermissionRequest() | ||
} else if (storagePermissionState.status.isGranted.not() && storagePermissionState.status.shouldShowRationale.not()) { | ||
storagePermissionState.launchPermissionRequest() | ||
} | ||
} | ||
|
||
if (locationPermissionState.status.isGranted.not() && locationPermissionState.status.shouldShowRationale) { | ||
PermissionDialog( | ||
dialog = DialogContentProvider.LocationPermission, | ||
onAction = { activity.openSettings() }, | ||
modifier = Modifier.clip(RoundedCornerShape(20.dp)), | ||
) | ||
} else if (storagePermissionState.status.isGranted.not() && storagePermissionState.status.shouldShowRationale) { | ||
PermissionDialog( | ||
dialog = DialogContentProvider.StoragePermission, | ||
onAction = { activity.openSettings() }, | ||
modifier = Modifier.clip(RoundedCornerShape(20.dp)), | ||
) | ||
} else if (gpsDialogState.value is DialogState.InValid) { | ||
PermissionDialog( | ||
dialog = DialogContentProvider.GPS, | ||
onAction = { | ||
activity.openStatusBar() | ||
}, | ||
modifier = Modifier.clip(RoundedCornerShape(20.dp)), | ||
) | ||
} else if (networkDialogState.value is DialogState.InValid) { | ||
PermissionDialog( | ||
dialog = DialogContentProvider.Network, | ||
onAction = { | ||
activity.openStatusBar() | ||
}, | ||
modifier = Modifier.clip(RoundedCornerShape(20.dp)), | ||
) | ||
} | ||
} | ||
|
||
@Composable | ||
fun PermissionDialog( | ||
dialog: DialogContentProvider, | ||
onAction: () -> Unit, | ||
modifier: Modifier = Modifier, | ||
) { | ||
AlertDialog( | ||
onDismissRequest = onAction, | ||
buttons = { | ||
Column(modifier = Modifier.fillMaxWidth()) { | ||
Text( | ||
text = "동의", | ||
style = WalkieTypography.SubTitle.copy(color = WalkieColor.Primary), | ||
textAlign = TextAlign.Center, | ||
modifier = Modifier | ||
.align(Alignment.End) | ||
.clickable( | ||
indication = null, | ||
interactionSource = remember { MutableInteractionSource() }, | ||
) { | ||
onAction() | ||
} | ||
.padding(bottom = 20.dp) | ||
.padding(horizontal = 20.dp) | ||
.clip(RoundedCornerShape(12.dp)), | ||
) | ||
} | ||
}, | ||
title = { Text(dialog.title, style = WalkieTypography.SubTitle) }, | ||
text = { | ||
Text( | ||
text = dialog.description, | ||
style = WalkieTypography.Body1_Normal, | ||
) | ||
}, | ||
modifier = modifier, | ||
) | ||
} |
31 changes: 31 additions & 0 deletions
31
app/src/main/java/com/whyranoid/walkie/walkiedialog/DialogContentProvider.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package com.whyranoid.walkie.walkiedialog | ||
|
||
sealed class DialogContentProvider( | ||
val title: String, | ||
val description: String, | ||
) { | ||
object LocationPermission : | ||
DialogContentProvider( | ||
"위치 정보 제공 동의", | ||
"러닝 기능을 사용하려면 사용자의 위치 권한 동의가 반드시 필요해요.", | ||
) { | ||
const val PERMISSION = android.Manifest.permission.ACCESS_FINE_LOCATION | ||
} | ||
|
||
object StoragePermission : DialogContentProvider( | ||
"미디어 및 파일 접근 동의", | ||
"러닝 정보를 기록하려면 미디어 및 파일 접근 권한 동의가 반드시 필요해요.", | ||
) { | ||
const val PERMISSION = android.Manifest.permission.READ_EXTERNAL_STORAGE | ||
} | ||
|
||
object GPS : DialogContentProvider( | ||
"위치 상태 확인 요망", | ||
"러닝 기능을 사용하려면 위치 정보 상태가 켜져야해요.", | ||
) | ||
|
||
object Network : DialogContentProvider( | ||
"네트워크 상태 확인 요망", | ||
"러닝 기능을 사용하려면 네트워트가 연결되어야해요.", | ||
) | ||
} |
9 changes: 9 additions & 0 deletions
9
app/src/main/java/com/whyranoid/walkie/walkiedialog/DialogState.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package com.whyranoid.walkie.walkiedialog | ||
|
||
sealed class DialogState { | ||
object Initialized : DialogState() | ||
|
||
object Valid : DialogState() | ||
|
||
data class InValid(val dialogContentProvider: DialogContentProvider) : DialogState() | ||
} |
56 changes: 56 additions & 0 deletions
56
app/src/main/java/com/whyranoid/walkie/walkiedialog/DialogViewModel.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
package com.whyranoid.walkie.walkiedialog | ||
|
||
import androidx.lifecycle.ViewModel | ||
import com.whyranoid.domain.usecase.broadcast.AddGpsListener | ||
import com.whyranoid.domain.usecase.broadcast.AddNetworkListener | ||
import com.whyranoid.domain.usecase.broadcast.GetGpsState | ||
import com.whyranoid.domain.usecase.broadcast.GetNetworkState | ||
import com.whyranoid.domain.usecase.broadcast.RemoveGpsListener | ||
import kotlinx.coroutines.flow.MutableStateFlow | ||
import kotlinx.coroutines.flow.asStateFlow | ||
import kotlinx.coroutines.flow.map | ||
|
||
class DialogViewModel( | ||
private val addNetworkListener: AddNetworkListener, | ||
private val removeNetworkListener: AddNetworkListener, | ||
private val getNetworkState: GetNetworkState, | ||
private val addGpsListener: AddGpsListener, | ||
private val removeGpsListener: RemoveGpsListener, | ||
private val getGpsState: GetGpsState, | ||
) : ViewModel() { | ||
init { | ||
addNetworkListener() | ||
addGpsListener() | ||
} | ||
|
||
private val _locationPermissionDialogState = | ||
MutableStateFlow<DialogState>(DialogState.Initialized) | ||
private val _storagePermissionDialogState = | ||
MutableStateFlow<DialogState>(DialogState.Initialized) | ||
|
||
val locationPermissionDialogState get() = _locationPermissionDialogState.asStateFlow() | ||
val storagePermissionDialogState get() = _storagePermissionDialogState.asStateFlow() | ||
|
||
val gpsDialogState = getGpsState().map { | ||
if (it) DialogState.Valid else DialogState.InValid(DialogContentProvider.GPS) | ||
} | ||
val networkDialogState = getNetworkState().map { | ||
if (it) DialogState.Valid else DialogState.InValid(DialogContentProvider.Network) | ||
} | ||
|
||
fun setPermission(permission: String, showDialog: Boolean) { | ||
if (permission == DialogContentProvider.LocationPermission.PERMISSION) { | ||
_locationPermissionDialogState.value = | ||
if (showDialog) DialogState.Valid else DialogState.InValid(DialogContentProvider.LocationPermission) | ||
} else if (permission == DialogContentProvider.StoragePermission.PERMISSION) { | ||
_storagePermissionDialogState.value = | ||
if (showDialog) DialogState.Valid else DialogState.InValid(DialogContentProvider.StoragePermission) | ||
} | ||
} | ||
|
||
override fun onCleared() { | ||
removeGpsListener() | ||
removeNetworkListener() | ||
super.onCleared() | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
app/src/main/java/com/whyranoid/walkie/wlakiedialog/DialogState.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package com.whyranoid.walkie.wlakiedialog | ||
|
||
import com.whyranoid.walkie.walkiedialog.DialogContentProvider | ||
|
||
sealed class DialogState { | ||
object Initialized : DialogState() | ||
|
||
object Valid : DialogState() | ||
|
||
data class InValid(val dialogContentProvider: DialogContentProvider) : DialogState() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
9 changes: 9 additions & 0 deletions
9
domain/src/main/java/com/whyranoid/domain/usecase/broadcast/AddGpsListener.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package com.whyranoid.domain.usecase.broadcast | ||
|
||
import com.whyranoid.domain.repository.GpsRepository | ||
|
||
class AddGpsListener(private val gpsRepository: GpsRepository) { | ||
operator fun invoke() { | ||
gpsRepository.registerReceiver() | ||
} | ||
} |
9 changes: 9 additions & 0 deletions
9
domain/src/main/java/com/whyranoid/domain/usecase/broadcast/AddNetworkListener.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package com.whyranoid.domain.usecase.broadcast | ||
|
||
import com.whyranoid.domain.repository.NetworkRepository | ||
|
||
class AddNetworkListener(private val networkRepository: NetworkRepository) { | ||
operator fun invoke() { | ||
networkRepository.addNetworkConnectionCallback() | ||
} | ||
} |
Oops, something went wrong.