Skip to content

Commit

Permalink
perf: sync state
Browse files Browse the repository at this point in the history
  • Loading branch information
lisonge committed Aug 2, 2024
1 parent 8adbf71 commit 3c2c544
Show file tree
Hide file tree
Showing 22 changed files with 349 additions and 288 deletions.
4 changes: 3 additions & 1 deletion app/src/main/kotlin/li/songe/gkd/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,11 @@ class App : Application() {
LogUtils.d("UncaughtExceptionHandler", t, e)
errorHandler?.uncaughtException(t, e)
}
MMKV.initialize(this)

Toaster.init(this)
setReactiveToastStyle()
MMKV.initialize(this)

LogUtils.getConfig().apply {
setConsoleSwitch(BuildConfig.DEBUG)
saveDays = 7
Expand Down
16 changes: 10 additions & 6 deletions app/src/main/kotlin/li/songe/gkd/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,10 @@ import li.songe.gkd.service.GkdAbService
import li.songe.gkd.service.ManageService
import li.songe.gkd.service.updateLauncherAppId
import li.songe.gkd.ui.NavGraphs
import li.songe.gkd.ui.component.ConfirmDialog
import li.songe.gkd.ui.component.BuildDialog
import li.songe.gkd.ui.theme.AppTheme
import li.songe.gkd.util.LocalLauncher
import li.songe.gkd.util.LocalMainViewModel
import li.songe.gkd.util.LocalNavController
import li.songe.gkd.util.LocalPickContentLauncher
import li.songe.gkd.util.UpgradeDialog
Expand Down Expand Up @@ -64,16 +65,19 @@ class MainActivity : CompositionActivity({
CompositionLocalProvider(
LocalLauncher provides launcher,
LocalPickContentLauncher provides pickContentLauncher,
LocalNavController provides navController
LocalNavController provides navController,
LocalMainViewModel provides mainVm
) {
DestinationsNavHost(
navGraph = NavGraphs.root,
navController = navController
)
AuthDialog(mainVm.authReasonFlow)
BuildDialog(mainVm.dialogFlow)
if (BuildConfig.ENABLED_UPDATE) {
UpgradeDialog(mainVm.updateStatus)
}
}
ConfirmDialog()
AuthDialog()
UpgradeDialog()
}
}
}) {
Expand Down Expand Up @@ -112,7 +116,7 @@ fun Activity.navToMainActivity() {
finish()
}

fun updateServiceRunning() {
private fun updateServiceRunning() {
ManageService.isRunning.value = ServiceUtils.isServiceRunning(ManageService::class.java)
GkdAbService.isRunning.value = ServiceUtils.isServiceRunning(GkdAbService::class.java)
FloatingService.isRunning.value = ServiceUtils.isServiceRunning(FloatingService::class.java)
Expand Down
42 changes: 22 additions & 20 deletions app/src/main/kotlin/li/songe/gkd/MainViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.blankj.utilcode.util.LogUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.map
Expand All @@ -13,8 +14,10 @@ import li.songe.gkd.BuildConfig.ENABLED_UPDATE
import li.songe.gkd.data.RawSubscription
import li.songe.gkd.data.SubsItem
import li.songe.gkd.db.DbSet
import li.songe.gkd.permission.authReasonFlow
import li.songe.gkd.permission.AuthReason
import li.songe.gkd.ui.component.AlertDialogOptions
import li.songe.gkd.util.LOCAL_SUBS_ID
import li.songe.gkd.util.UpdateStatus
import li.songe.gkd.util.checkUpdate
import li.songe.gkd.util.clearCache
import li.songe.gkd.util.launchTry
Expand All @@ -23,6 +26,22 @@ import li.songe.gkd.util.storeFlow
import li.songe.gkd.util.updateSubscription

class MainViewModel : ViewModel() {
val enableDarkThemeFlow = storeFlow.debounce(200).map { s -> s.enableDarkTheme }.stateIn(
viewModelScope,
SharingStarted.Eagerly,
storeFlow.value.enableDarkTheme
)
val enableDynamicColorFlow = storeFlow.debounce(300).map { s -> s.enableDynamicColor }.stateIn(
viewModelScope,
SharingStarted.Eagerly,
storeFlow.value.enableDynamicColor
)

val dialogFlow = MutableStateFlow<AlertDialogOptions?>(null)
val authReasonFlow = MutableStateFlow<AuthReason?>(null)

val updateStatus = UpdateStatus()

init {
viewModelScope.launchTry(Dispatchers.IO) {
val subsItems = DbSet.subsItemDao.queryAll()
Expand All @@ -49,9 +68,9 @@ class MainViewModel : ViewModel() {
}

if (ENABLED_UPDATE && storeFlow.value.autoCheckAppUpdate) {
appScope.launch(Dispatchers.IO) {
viewModelScope.launch(Dispatchers.IO) {
try {
checkUpdate()
updateStatus.checkUpdate()
} catch (e: Exception) {
e.printStackTrace()
LogUtils.d(e)
Expand All @@ -65,21 +84,4 @@ class MainViewModel : ViewModel() {
}
}
}

val enableDarkThemeFlow = storeFlow.debounce(200).map { s -> s.enableDarkTheme }.stateIn(
viewModelScope,
SharingStarted.Eagerly,
storeFlow.value.enableDarkTheme
)
val enableDynamicColorFlow = storeFlow.debounce(300).map { s -> s.enableDynamicColor }.stateIn(
viewModelScope,
SharingStarted.Eagerly,
storeFlow.value.enableDynamicColor
)


override fun onCleared() {
super.onCleared()
authReasonFlow.value = null
}
}
57 changes: 19 additions & 38 deletions app/src/main/kotlin/li/songe/gkd/permission/PermissionDialog.kt
Original file line number Diff line number Diff line change
@@ -1,26 +1,23 @@
package li.songe.gkd.permission

import android.app.Activity
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import com.hjq.permissions.OnPermissionCallback
import com.hjq.permissions.XXPermissions
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
import kotlinx.coroutines.yield
import li.songe.gkd.MainActivity
import kotlin.coroutines.coroutineContext

data class AuthReason(
val text: String,
val confirm: () -> Unit
)

val authReasonFlow = MutableStateFlow<AuthReason?>(null)

@Composable
fun AuthDialog() {
fun AuthDialog(authReasonFlow: MutableStateFlow<AuthReason?>) {
val authAction = authReasonFlow.collectAsState().value
if (authAction != null) {
AlertDialog(
Expand Down Expand Up @@ -53,45 +50,29 @@ sealed class PermissionResult {
data class Denied(val doNotAskAgain: Boolean) : PermissionResult()
}

suspend fun asyncRequestPermission(
context: Activity,
permission: String,
): PermissionResult {
if (XXPermissions.isGranted(context, permission)) {
return PermissionResult.Granted
}
return suspendCoroutine { continuation ->
XXPermissions.with(context)
.unchecked()
.permission(permission)
.request(object : OnPermissionCallback {
override fun onGranted(permissions: MutableList<String>, allGranted: Boolean) {
if (allGranted) {
continuation.resume(PermissionResult.Granted)
} else {
continuation.resume(PermissionResult.Denied(false))
}
}

override fun onDenied(permissions: MutableList<String>, doNotAskAgain: Boolean) {
continuation.resume(PermissionResult.Denied(doNotAskAgain))
}
})
}
}

suspend fun checkOrRequestPermission(
context: Activity,
private suspend fun checkOrRequestPermission(
context: MainActivity,
permissionState: PermissionState
): Boolean {
if (!permissionState.updateAndGet()) {
val result = permissionState.request?.let { it(context) } ?: return false
if (result is PermissionResult.Denied) {
if (result.doNotAskAgain) {
authReasonFlow.value = permissionState.reason
context.mainVm.authReasonFlow.value = permissionState.reason
}
return false
}
}
return true
}

suspend fun requiredPermission(
context: MainActivity,
permissionState: PermissionState
) {
val r = checkOrRequestPermission(context, permissionState)
if (!r) {
coroutineContext[Job]?.cancel()
yield()
}
}
40 changes: 35 additions & 5 deletions app/src/main/kotlin/li/songe/gkd/permission/PermissionState.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import android.content.pm.PackageManager
import android.os.Build
import android.provider.Settings
import androidx.core.content.ContextCompat
import com.hjq.permissions.OnPermissionCallback
import com.hjq.permissions.Permission
import com.hjq.permissions.XXPermissions
import kotlinx.coroutines.flow.MutableStateFlow
Expand All @@ -17,6 +18,8 @@ import li.songe.gkd.shizuku.safeGetTasks
import li.songe.gkd.shizuku.shizukuIsSafeOK
import li.songe.gkd.util.initOrResetAppInfoCache
import li.songe.gkd.util.launchTry
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine

class PermissionState(
val check: suspend () -> Boolean,
Expand All @@ -39,6 +42,33 @@ private fun checkSelfPermission(permission: String): Boolean {
) == PackageManager.PERMISSION_GRANTED
}

private suspend fun asyncRequestPermission(
context: Activity,
permission: String,
): PermissionResult {
if (XXPermissions.isGranted(context, permission)) {
return PermissionResult.Granted
}
return suspendCoroutine { continuation ->
XXPermissions.with(context)
.unchecked()
.permission(permission)
.request(object : OnPermissionCallback {
override fun onGranted(permissions: MutableList<String>, allGranted: Boolean) {
if (allGranted) {
continuation.resume(PermissionResult.Granted)
} else {
continuation.resume(PermissionResult.Denied(false))
}
}

override fun onDenied(permissions: MutableList<String>, doNotAskAgain: Boolean) {
continuation.resume(PermissionResult.Denied(doNotAskAgain))
}
})
}
}

val notificationState by lazy {
PermissionState(
check = {
Expand Down Expand Up @@ -114,7 +144,7 @@ val canSaveToAlbumState by lazy {
reason = AuthReason(
text = "当前操作需要[写入外部存储权限]\n\n您需要前往应用权限设置打开此权限",
confirm = {
XXPermissions.startPermissionActivity(app, Permission.SYSTEM_ALERT_WINDOW)
XXPermissions.startPermissionActivity(app, Permission.WRITE_EXTERNAL_STORAGE)
}
),
)
Expand All @@ -133,10 +163,10 @@ val shizukuOkState by lazy {
)
}

private val checkLoading = MutableStateFlow(false)
private val checkAuthLoading = MutableStateFlow(false)
suspend fun updatePermissionState() {
if (checkLoading.value) return
checkLoading.value = true
if (checkAuthLoading.value) return
checkAuthLoading.value = true
arrayOf(
notificationState,
canDrawOverlaysState,
Expand All @@ -148,5 +178,5 @@ suspend fun updatePermissionState() {
initOrResetAppInfoCache()
}
}
checkLoading.value = false
checkAuthLoading.value = false
}
Loading

0 comments on commit 3c2c544

Please sign in to comment.