Handle request runtime permission
This commit is contained in:
@@ -44,4 +44,32 @@
|
||||
<string name="action_retry">Retry</string>
|
||||
<string name="device_connecting">Connecting…</string>
|
||||
<string name="device_explanation">It should just take a moment…</string>
|
||||
|
||||
<string name="action_grant_permission">Grant permission</string>
|
||||
<string name="action_settings">Settings</string>
|
||||
<string name="action_enable">Enable</string>
|
||||
<string name="action_try_again">Try again</string>
|
||||
<string name="action_location_settings">Location settings</string>
|
||||
<string name="action_go_up">Back</string>
|
||||
|
||||
<string name="bluetooth_disabled_title">BLUETOOTH DISABLED</string>
|
||||
<string name="bluetooth_disabled_info">The Bluetooth adapter is turned off.\nClick the button below to enable it.</string>
|
||||
|
||||
<string name="location_permission_title">LOCATION PERMISSION REQUIRED</string>
|
||||
<string name="location_permission_info">From Android 6.0 Marshmallow until Android 11 the application requires Location permission in order to scan for Bluetooth Low Energy devices. This is because Bluetooth LE beacons, for example iBeacons or Eddystone, may be used to
|
||||
determine the phone's and user's location.\n
|
||||
The app will not use this information in any way.\n
|
||||
On Android 12 or newer a new Nearby permission can be requested instead, without the need for location.</string>
|
||||
|
||||
<string name="bluetooth_permission_title">BLUETOOTH PERMISSIONS REQUIRED</string>
|
||||
<string name="bluetooth_permission_info">The app needs to scan and connect to Bluetooth LE devices.</string>
|
||||
|
||||
<string name="bluetooth_not_available_title">BLUETOOTH NOT AVAILABLE</string>
|
||||
<string name="bluetooth_not_available_info">Bluetooth is not available on your phone.\nWe cannot provide you the feature.</string>
|
||||
<string name="location_required_title">Location required</string>
|
||||
<string name="bluetooth_required_title">Bluetooth required</string>
|
||||
|
||||
<string name="location_disabled_title">LOCATION DISABLED</string>
|
||||
<string name="location_disabled_info">Location is turned off. Most Android phones require it in order to scan for Bluetooth LE devices.\n
|
||||
Click the button below to enable Location.</string>
|
||||
</resources>
|
||||
|
||||
@@ -6,6 +6,7 @@ import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.digitoolsolutions.app.torquevaultkmp.screens.MainScreen
|
||||
import com.digitoolsolutions.app.torquevaultkmp.screens.bluetooth.BluetoothRequirementWrapper
|
||||
import com.digitoolsolutions.app.torquevaultkmp.theme.TorqueVaultTheme
|
||||
import io.github.aakira.napier.Napier
|
||||
import org.koin.compose.viewmodel.koinViewModel
|
||||
|
||||
@Composable
|
||||
|
||||
+6
-5
@@ -1,5 +1,6 @@
|
||||
package com.digitoolsolutions.app.torquevaultkmp.components
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.ColumnScope
|
||||
@@ -101,8 +102,8 @@ fun WarningView(
|
||||
) {
|
||||
WarningView(
|
||||
painterResource = painterResource,
|
||||
title = { Text(text = title) },
|
||||
hint = { Hint(text = hint, textAlign = hintTextAlign) },
|
||||
title = { Text(text = title, color = MaterialTheme.colorScheme.onBackground) },
|
||||
hint = { Hint(text = hint, textAlign = hintTextAlign, color = MaterialTheme.colorScheme.onBackground) },
|
||||
modifier = modifier,
|
||||
content = content,
|
||||
)
|
||||
@@ -128,8 +129,8 @@ fun WarningView(
|
||||
) {
|
||||
WarningView(
|
||||
painterResource = painterResource,
|
||||
title = { Text(text = title) },
|
||||
hint = { Hint(text = hint, textAlign = hintTextAlign) },
|
||||
title = { Text(text = title, color = MaterialTheme.colorScheme.onBackground) },
|
||||
hint = { Hint(text = hint, textAlign = hintTextAlign, color = MaterialTheme.colorScheme.onBackground) },
|
||||
modifier = modifier,
|
||||
content = content,
|
||||
)
|
||||
@@ -179,7 +180,7 @@ fun WarningView(
|
||||
content: @Composable ColumnScope.() -> Unit = {}
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier,
|
||||
modifier = modifier.background(MaterialTheme.colorScheme.background),
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp, Alignment.CenterVertically),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
|
||||
+1
@@ -36,6 +36,7 @@ import com.digitoolsolutions.app.torquevaultkmp.screens.scanner.ScannerScreen
|
||||
import com.digitoolsolutions.app.torquevaultkmp.screens.scanner.ScannerViewModel
|
||||
import com.digitoolsolutions.app.torquevaultkmp.screens.settings.SettingDestination
|
||||
import com.digitoolsolutions.app.torquevaultkmp.screens.settings.SettingScreen
|
||||
import io.github.aakira.napier.Napier
|
||||
import org.jetbrains.compose.resources.painterResource
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import org.koin.compose.viewmodel.koinViewModel
|
||||
|
||||
+46
-67
@@ -1,20 +1,10 @@
|
||||
package com.digitoolsolutions.app.torquevaultkmp.screens.bluetooth
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.BluetoothDisabled
|
||||
import androidx.compose.material.icons.filled.Security
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
@@ -22,55 +12,62 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.LifecycleResumeEffect
|
||||
import com.digitoolsolutions.app.torquevaultkmp.screens.bluetooth.views.BluetoothDisabledView
|
||||
import com.digitoolsolutions.app.torquevaultkmp.screens.bluetooth.views.LocationDisabledView
|
||||
import com.digitoolsolutions.app.torquevaultkmp.screens.bluetooth.views.LocationPermissionRequiredView
|
||||
import com.digitoolsolutions.app.torquevaultkmp.utils.BluetoothManager
|
||||
import com.digitoolsolutions.app.torquevaultkmp.utils.HandlePermissionRequest
|
||||
import com.digitoolsolutions.app.torquevaultkmp.utils.PermissionHandler
|
||||
import org.koin.compose.koinInject
|
||||
|
||||
@Composable
|
||||
fun BluetoothRequirementWrapper(
|
||||
content: @Composable () -> Unit
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
val bluetoothManager: BluetoothManager = koinInject()
|
||||
val permissionHandler: PermissionHandler = koinInject()
|
||||
val isEnabled by bluetoothManager.isBluetoothEnabled.collectAsState()
|
||||
val hasPermission by bluetoothManager.hasBluetoothPermission.collectAsState()
|
||||
|
||||
var hasPermanentlyDenied by remember { mutableStateOf(false) }
|
||||
val isLocationEnabled by permissionHandler.isLocationEnabled.collectAsState()
|
||||
var showPermissionRequest by remember { mutableStateOf(false) }
|
||||
|
||||
if (showPermissionRequest) {
|
||||
HandlePermissionRequest { _ ->
|
||||
showPermissionRequest = false
|
||||
bluetoothManager.checkBluetoothPermission()
|
||||
permissionHandler.HandlePermissionRequest(
|
||||
{ allGranted, denied ->
|
||||
showPermissionRequest = false
|
||||
bluetoothManager.checkBluetoothPermission()
|
||||
hasPermanentlyDenied = denied
|
||||
}
|
||||
) {
|
||||
requestPermissions ->
|
||||
LaunchedEffect(Unit) {
|
||||
requestPermissions()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LifecycleResumeEffect(Unit) {
|
||||
bluetoothManager.checkBluetoothState()
|
||||
bluetoothManager.checkBluetoothPermission()
|
||||
permissionHandler.checkLocationState()
|
||||
onPauseOrDispose { }
|
||||
}
|
||||
|
||||
LaunchedEffect(isEnabled, hasPermission) {
|
||||
if (!isEnabled && hasPermission) {
|
||||
bluetoothManager.enableBluetooth()
|
||||
}
|
||||
}
|
||||
|
||||
if (isEnabled && hasPermission) {
|
||||
content()
|
||||
} else {
|
||||
/* MainScreen */
|
||||
content()
|
||||
/* Overlay content */
|
||||
if (!isEnabled || !hasPermission || !isLocationEnabled) {
|
||||
BluetoothRequestScreen(
|
||||
isEnabled = isEnabled,
|
||||
hasPermission = hasPermission,
|
||||
hasPermanentlyDenied = hasPermanentlyDenied,
|
||||
isLocationEnabled = isLocationEnabled,
|
||||
onEnableBluetooth = { bluetoothManager.enableBluetooth() },
|
||||
onRequestPermission = {
|
||||
bluetoothManager.enableBluetooth()
|
||||
showPermissionRequest = true
|
||||
},
|
||||
onEnableLocation = { permissionHandler.enableLocation() },
|
||||
onRequestPermission = { showPermissionRequest = true },
|
||||
onOpenSettings = { bluetoothManager.openSettings() }
|
||||
)
|
||||
}
|
||||
@@ -80,46 +77,28 @@ fun BluetoothRequirementWrapper(
|
||||
fun BluetoothRequestScreen(
|
||||
isEnabled: Boolean,
|
||||
hasPermission: Boolean,
|
||||
hasPermanentlyDenied: Boolean,
|
||||
isLocationEnabled: Boolean,
|
||||
onEnableBluetooth: () -> Unit,
|
||||
onEnableLocation: () -> Unit,
|
||||
onRequestPermission: () -> Unit,
|
||||
onOpenSettings: () -> Unit
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize().padding(24.dp),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Icon(
|
||||
imageVector = if (!hasPermission) Icons.Default.Security else Icons.Default.BluetoothDisabled,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(80.dp),
|
||||
tint = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
Text(
|
||||
text = if (!hasPermission) "Bluetooth Permission Required" else "Bluetooth is Disabled",
|
||||
style = MaterialTheme.typography.headlineSmall,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
Text(
|
||||
text = if (!hasPermission)
|
||||
"This app needs Bluetooth permissions to connect to your devices. Please grant permission."
|
||||
else "Please enable Bluetooth to use this app's features.",
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
textAlign = TextAlign.Center,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
Spacer(modifier = Modifier.height(32.dp))
|
||||
|
||||
if (!hasPermission) {
|
||||
Button(onClick = onRequestPermission) {
|
||||
Text("Request Permission")
|
||||
}
|
||||
} else if (!isEnabled) {
|
||||
Button(onClick = onEnableBluetooth) {
|
||||
Text("Enable Bluetooth")
|
||||
}
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(MaterialTheme.colorScheme.background)
|
||||
.padding(12.dp)
|
||||
){
|
||||
when {
|
||||
!isEnabled -> BluetoothDisabledView(onEnable = onEnableBluetooth)
|
||||
!hasPermission -> LocationPermissionRequiredView(
|
||||
hasPermission = hasPermission,
|
||||
hasPermanentlyDenied = hasPermanentlyDenied,
|
||||
onRequestPermission = onRequestPermission,
|
||||
onOpenSetting = onOpenSettings
|
||||
)
|
||||
!isLocationEnabled -> LocationDisabledView(onEnable = onEnableLocation)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package com.digitoolsolutions.app.torquevaultkmp.screens.bluetooth.views
|
||||
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.BluetoothDisabled
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.digitoolsolutions.app.torquevaultkmp.components.WarningView
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import torquevaultkmp.composeapp.generated.resources.Res
|
||||
import torquevaultkmp.composeapp.generated.resources.action_enable
|
||||
import torquevaultkmp.composeapp.generated.resources.bluetooth_disabled_info
|
||||
import torquevaultkmp.composeapp.generated.resources.bluetooth_disabled_title
|
||||
|
||||
@Composable
|
||||
internal fun BluetoothDisabledView(
|
||||
onEnable: () -> Unit,
|
||||
) {
|
||||
WarningView(
|
||||
imageVector = Icons.Rounded.BluetoothDisabled,
|
||||
title = stringResource(Res.string.bluetooth_disabled_title),
|
||||
hint = stringResource(Res.string.bluetooth_disabled_info),
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState())
|
||||
) {
|
||||
Button(onClick = onEnable) {
|
||||
Text(text = stringResource(Res.string.action_enable))
|
||||
}
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.digitoolsolutions.app.torquevaultkmp.screens.bluetooth.views
|
||||
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.digitoolsolutions.app.torquevaultkmp.components.WarningView
|
||||
import org.jetbrains.compose.resources.painterResource
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import torquevaultkmp.composeapp.generated.resources.Res
|
||||
import torquevaultkmp.composeapp.generated.resources.baseline_bluetooth_disabled_24
|
||||
import torquevaultkmp.composeapp.generated.resources.bluetooth_not_available_info
|
||||
import torquevaultkmp.composeapp.generated.resources.bluetooth_not_available_title
|
||||
|
||||
@Composable
|
||||
internal fun BluetoothNotAvailableView() {
|
||||
WarningView(
|
||||
painterResource = painterResource(Res.drawable.baseline_bluetooth_disabled_24),
|
||||
title = stringResource(Res.string.bluetooth_not_available_title),
|
||||
hint = stringResource(Res.string.bluetooth_not_available_info),
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState())
|
||||
)
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
package com.digitoolsolutions.app.torquevaultkmp.screens.bluetooth.views
|
||||
|
||||
//import android.Manifest
|
||||
//import android.content.Context
|
||||
//import android.content.Intent
|
||||
//import android.net.Uri
|
||||
//import android.os.Build
|
||||
//import android.provider.Settings
|
||||
//import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
//import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.BluetoothDisabled
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.SegmentedButtonDefaults.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
//import androidx.compose.ui.platform.LocalContext
|
||||
import com.digitoolsolutions.app.torquevaultkmp.components.WarningView
|
||||
import org.jetbrains.compose.resources.painterResource
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import torquevaultkmp.composeapp.generated.resources.Res
|
||||
import torquevaultkmp.composeapp.generated.resources.action_grant_permission
|
||||
import torquevaultkmp.composeapp.generated.resources.action_settings
|
||||
import torquevaultkmp.composeapp.generated.resources.baseline_bluetooth_disabled_24
|
||||
import torquevaultkmp.composeapp.generated.resources.bluetooth_permission_info
|
||||
import torquevaultkmp.composeapp.generated.resources.bluetooth_permission_title
|
||||
|
||||
@Composable
|
||||
internal fun BluetoothPermissionRequiredView(
|
||||
hasPermission: Boolean,
|
||||
hasPermanentlyDenied: Boolean,
|
||||
onRequestPermission: () -> Unit,
|
||||
onOpenSetting: () -> Unit
|
||||
) {
|
||||
WarningView(
|
||||
imageVector = Icons.Rounded.BluetoothDisabled,
|
||||
title = stringResource(Res.string.bluetooth_permission_title),
|
||||
hint = stringResource(Res.string.bluetooth_permission_info),
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState())
|
||||
) {
|
||||
when {
|
||||
!hasPermission -> Button(
|
||||
onClick = { onRequestPermission() }
|
||||
) {
|
||||
Text(text = stringResource(Res.string.action_grant_permission))
|
||||
}
|
||||
!hasPermanentlyDenied -> Button(
|
||||
onClick = { onOpenSetting() }
|
||||
) {
|
||||
Text(text = stringResource(Res.string.action_settings))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package com.digitoolsolutions.app.torquevaultkmp.screens.bluetooth.views
|
||||
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.LocationOff
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.digitoolsolutions.app.torquevaultkmp.components.WarningView
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import torquevaultkmp.composeapp.generated.resources.Res
|
||||
import torquevaultkmp.composeapp.generated.resources.action_enable
|
||||
import torquevaultkmp.composeapp.generated.resources.location_disabled_info
|
||||
import torquevaultkmp.composeapp.generated.resources.location_disabled_title
|
||||
|
||||
@Composable
|
||||
internal fun LocationDisabledView(
|
||||
onEnable: () -> Unit,
|
||||
) {
|
||||
WarningView(
|
||||
imageVector = Icons.Rounded.LocationOff,
|
||||
title = stringResource(Res.string.location_disabled_title),
|
||||
hint = stringResource(Res.string.location_disabled_info),
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState())
|
||||
) {
|
||||
Button(onClick = onEnable) {
|
||||
Text(text = stringResource(Res.string.action_enable))
|
||||
}
|
||||
}
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
package com.digitoolsolutions.app.torquevaultkmp.screens.bluetooth.views
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.LocationOff
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.digitoolsolutions.app.torquevaultkmp.components.WarningView
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import torquevaultkmp.composeapp.generated.resources.Res
|
||||
import torquevaultkmp.composeapp.generated.resources.action_grant_permission
|
||||
import torquevaultkmp.composeapp.generated.resources.action_settings
|
||||
import torquevaultkmp.composeapp.generated.resources.location_permission_info
|
||||
import torquevaultkmp.composeapp.generated.resources.location_permission_title
|
||||
|
||||
@Composable
|
||||
internal fun LocationPermissionRequiredView(
|
||||
hasPermission: Boolean,
|
||||
hasPermanentlyDenied: Boolean,
|
||||
onRequestPermission: () -> Unit,
|
||||
onOpenSetting: () -> Unit
|
||||
) {
|
||||
WarningView(
|
||||
imageVector = Icons.Rounded.LocationOff,
|
||||
title = stringResource(Res.string.location_permission_title),
|
||||
hint = stringResource(Res.string.location_permission_info),
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState())
|
||||
) {
|
||||
when {
|
||||
!hasPermission && !hasPermanentlyDenied -> {
|
||||
Button(onClick = onRequestPermission) {
|
||||
Text(stringResource(Res.string.action_grant_permission))
|
||||
}
|
||||
}
|
||||
!hasPermission && hasPermanentlyDenied -> {
|
||||
Button(onClick = onOpenSetting) {
|
||||
Text(stringResource(Res.string.action_settings))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
-4
@@ -1,8 +1,15 @@
|
||||
package com.digitoolsolutions.app.torquevaultkmp.utils
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
@Composable
|
||||
expect fun HandlePermissionRequest(
|
||||
onPermissionResult: (Boolean) -> Unit
|
||||
)
|
||||
interface PermissionHandler {
|
||||
@Composable
|
||||
fun HandlePermissionRequest(
|
||||
onPermissionResult: (Boolean, Boolean) -> Unit,
|
||||
content: @Composable (requestPermissions: () -> Unit) -> Unit
|
||||
)
|
||||
val isLocationEnabled: StateFlow<Boolean>
|
||||
fun enableLocation()
|
||||
fun checkLocationState()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user