Skip to content

Commit

Permalink
Improve setup screen, add plumbing for granting manage/read/write sto…
Browse files Browse the repository at this point in the history
…rage access.
  • Loading branch information
d4rken committed Jan 2, 2023
1 parent 48fcf05 commit 13836d3
Show file tree
Hide file tree
Showing 22 changed files with 500 additions and 202 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ class StorageVolumeX constructor(
methodGetPath?.invoke(volumeObj) as? String
} catch (e: ReflectiveOperationException) {
Timber.tag(TAG).d("StorageVolume.path reflection failed.")
null
directory?.path
}

private val methodGetPathFile: Method? by lazy {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,8 @@ enum class Permission(
ContextCompat.checkSelfPermission(it, permissionId) == PackageManager.PERMISSION_GRANTED
},
) {
ACCESS_COARSE_LOCATION(
permissionId = "android.permission.ACCESS_COARSE_LOCATION",
),
ACCESS_FINE_LOCATION(
permissionId = "android.permission.ACCESS_FINE_LOCATION",
POST_NOTIFICATIONS(
permissionId = "android.permission.POST_NOTIFICATIONS",
),
IGNORE_BATTERY_OPTIMIZATION(
permissionId = "android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS",
Expand All @@ -25,7 +22,13 @@ enum class Permission(
pwm.isIgnoringBatteryOptimizations(BuildConfigWrap.APPLICATION_ID)
},
),
POST_NOTIFICATIONS(
permissionId = "android.permission.POST_NOTIFICATIONS",
MANAGE_EXTERNAL_STORAGE(
permissionId = "android.permission.MANAGE_EXTERNAL_STORAGE",
),
WRITE_EXTERNAL_STORAGE(
permissionId = "android.permission.WRITE_EXTERNAL_STORAGE",
),
READ_EXTERNAL_STORAGE(
permissionId = "android.permission.READ_EXTERNAL_STORAGE",
),
}
6 changes: 3 additions & 3 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,9 @@ dependencies {

implementation("androidx.core:core-splashscreen:1.0.0")

implementation("androidx.navigation:navigation-fragment-ktx:2.5.0")
implementation("androidx.navigation:navigation-ui-ktx:2.5.0")
androidTestImplementation("androidx.navigation:navigation-testing:2.5.0")
implementation("androidx.navigation:navigation-fragment-ktx:${Versions.AndroidX.Navigation.core}")
implementation("androidx.navigation:navigation-ui-ktx:${Versions.AndroidX.Navigation.core}")
androidTestImplementation("androidx.navigation:navigation-testing:${Versions.AndroidX.Navigation.core}")


testImplementation("org.robolectric:robolectric:4.9.1")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,9 @@ class DashboardFragmentVM @Inject constructor(
refreshTrigger.value = rngString
},
onContinue = {
DashboardFragmentDirections.actionDashboardFragmentToSetupFragment().navigate()
DashboardFragmentDirections.actionDashboardFragmentToSetupFragment(
showCompleted = false
).navigate()
}
).run { items.add(this) }
}
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/eu/darken/sdmse/setup/SetupAdapter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import eu.darken.sdmse.common.lists.modular.ModularAdapter
import eu.darken.sdmse.common.lists.modular.mods.DataBinderMod
import eu.darken.sdmse.common.lists.modular.mods.TypedVHCreatorMod
import eu.darken.sdmse.setup.saf.SAFSetupCardVH
import eu.darken.sdmse.setup.storage.StorageSetupCardVH
import javax.inject.Inject


Expand All @@ -25,6 +26,7 @@ class SetupAdapter @Inject constructor() :

init {
modules.add(DataBinderMod(data))
modules.add(TypedVHCreatorMod({ data[it] is StorageSetupCardVH.Item }) { StorageSetupCardVH(it) })
modules.add(TypedVHCreatorMod({ data[it] is SAFSetupCardVH.Item }) { SAFSetupCardVH(it) })
}

Expand Down
5 changes: 5 additions & 0 deletions app/src/main/java/eu/darken/sdmse/setup/SetupEvents.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package eu.darken.sdmse.setup

import eu.darken.sdmse.common.permissions.Permission
import eu.darken.sdmse.setup.saf.SAFSetupModule

sealed interface SetupEvents {
Expand All @@ -10,4 +11,8 @@ sealed interface SetupEvents {
data class SafWrongPathError(
val exception: Exception
) : SetupEvents

data class RuntimePermissionRequests(
val item: Set<Permission>,
) : SetupEvents
}
8 changes: 8 additions & 0 deletions app/src/main/java/eu/darken/sdmse/setup/SetupFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package eu.darken.sdmse.setup
import android.os.Bundle
import android.view.View
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.fragment.app.viewModels
import androidx.navigation.findNavController
import androidx.navigation.ui.setupWithNavController
Expand All @@ -29,12 +30,16 @@ class SetupFragment : Fragment3(R.layout.setup_fragment) {
@Inject lateinit var webpageTool: WebpageTool

private lateinit var safRequestLauncher: ActivityResultLauncher<SAFSetupModule.State.PathAccess>
private lateinit var runtimePermissionLauncher: ActivityResultLauncher<String>

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
safRequestLauncher = registerForActivityResult(SafGrantPrimaryContract()) {
vm.onSafAccessGranted(it)
}
runtimePermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()) {
vm.onRuntimePermissionGranted(it)
}
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
Expand Down Expand Up @@ -67,6 +72,9 @@ class SetupFragment : Fragment3(R.layout.setup_fragment) {
}
.show()
}
is SetupEvents.RuntimePermissionRequests -> {

}
}
}

Expand Down
27 changes: 24 additions & 3 deletions app/src/main/java/eu/darken/sdmse/setup/SetupFragmentVM.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,17 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.SavedStateHandle
import dagger.hilt.android.lifecycle.HiltViewModel
import eu.darken.sdmse.common.SingleLiveEvent
import eu.darken.sdmse.common.WebpageTool
import eu.darken.sdmse.common.coroutine.DispatcherProvider
import eu.darken.sdmse.common.debug.logging.log
import eu.darken.sdmse.common.debug.logging.logTag
import eu.darken.sdmse.common.flow.setupCommonEventHandlers
import eu.darken.sdmse.common.navigation.navArgs
import eu.darken.sdmse.common.uix.ViewModel3
import eu.darken.sdmse.setup.saf.SAFSetupCardVH
import eu.darken.sdmse.setup.saf.SAFSetupModule
import eu.darken.sdmse.setup.storage.StorageSetupCardVH
import eu.darken.sdmse.setup.storage.StorageSetupModule
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import javax.inject.Inject
Expand All @@ -22,23 +26,36 @@ class SetupFragmentVM @Inject constructor(
dispatcherProvider: DispatcherProvider,
private val setupManager: SetupManager,
private val safSetupModule: SAFSetupModule,
private val storageSetupModule: StorageSetupModule,
private val webpageTool: WebpageTool,
) : ViewModel3(dispatcherProvider = dispatcherProvider) {

private val navArgs by handle.navArgs<SetupFragmentArgs>()

val events = SingleLiveEvent<SetupEvents>()

val listItems: LiveData<List<SetupAdapter.Item>> = setupManager.state
.map { setupState ->
val items = mutableListOf<SetupAdapter.Item>()

setupState.moduleStates
.filter { !it.isComplete }
.filter { !it.isComplete || navArgs.showCompleted }
.map { state ->
when (state) {
is SAFSetupModule.State -> SAFSetupCardVH.Item(
setupState = state,
onPathClicked = { events.postValue(SetupEvents.SafRequestAccess(it)) },
onHelp = {
TODO()
webpageTool.open("https://github.com/d4rken/sdmaid-se/wiki/Setup#storage-access-framework")
},
)
is StorageSetupModule.State -> StorageSetupCardVH.Item(
setupState = state,
onPathClicked = {
events.postValue(SetupEvents.RuntimePermissionRequests(state.missingPermission))
},
onHelp = {
webpageTool.open("https://github.com/d4rken/sdmaid-se/wiki/Setup#manage-storage")
},
)
else -> throw IllegalArgumentException("Unknown state: $state")
Expand All @@ -58,12 +75,16 @@ class SetupFragmentVM @Inject constructor(
if (uri == null) return@launch
try {
safSetupModule.takePermission(uri)
setupManager.refresh()
} catch (e: IllegalArgumentException) {
events.postValue(SetupEvents.SafWrongPathError(e))
}
}

fun onRuntimePermissionGranted(granted: Boolean) = launch {
log(TAG) { "onRuntimePermissionGranted(granted=$granted)" }
if (granted) storageSetupModule.refresh()
}

companion object {
private val TAG = logTag("Setup", "Fragment", "VM")
}
Expand Down
Loading

0 comments on commit 13836d3

Please sign in to comment.