mirror of
https://github.com/null2264/yokai.git
synced 2025-06-21 10:44:42 +00:00
fix: Handle version check for AboutController
This commit is contained in:
parent
eba5aa1d2e
commit
e06b28a60e
4 changed files with 90 additions and 49 deletions
|
@ -117,6 +117,7 @@ import eu.kanade.tachiyomi.util.system.prepareSideNavContext
|
|||
import eu.kanade.tachiyomi.util.system.rootWindowInsetsCompat
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import eu.kanade.tachiyomi.util.system.tryTakePersistableUriPermission
|
||||
import eu.kanade.tachiyomi.util.system.withUIContext
|
||||
import eu.kanade.tachiyomi.util.view.BackHandlerControllerInterface
|
||||
import eu.kanade.tachiyomi.util.view.backgroundColor
|
||||
import eu.kanade.tachiyomi.util.view.blurBehindWindow
|
||||
|
@ -136,12 +137,10 @@ import kotlin.collections.set
|
|||
import kotlin.math.abs
|
||||
import kotlin.math.min
|
||||
import kotlin.math.roundToLong
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.withContext
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import yokai.core.migration.Migrator
|
||||
import yokai.domain.base.BasePreferences
|
||||
|
@ -198,6 +197,7 @@ open class MainActivity : BaseActivity<MainActivityBinding>() {
|
|||
dimenW to dimenH
|
||||
}
|
||||
|
||||
@Deprecated("Create contract directly from Composable")
|
||||
private val requestNotificationPermissionLauncher =
|
||||
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
|
||||
if (!isGranted) {
|
||||
|
@ -1001,7 +1001,6 @@ open class MainActivity : BaseActivity<MainActivityBinding>() {
|
|||
}
|
||||
|
||||
private fun checkForAppUpdates() {
|
||||
// FIXME: Show Compose version of NewUpdateDialog for AboutController
|
||||
if (isUpdaterEnabled && router.backstack.lastOrNull()?.controller !is AboutController) {
|
||||
lifecycleScope.launchIO {
|
||||
try {
|
||||
|
@ -1012,7 +1011,7 @@ open class MainActivity : BaseActivity<MainActivityBinding>() {
|
|||
val isBeta = result.release.preRelease == true
|
||||
|
||||
// Create confirmation window
|
||||
withContext(Dispatchers.Main) {
|
||||
withUIContext {
|
||||
showNotificationPermissionPrompt()
|
||||
AppUpdateNotifier.releasePageUrl = result.release.releaseLink
|
||||
AboutController.NewUpdateDialogController(body, url, isBeta).showDialog(router)
|
||||
|
|
|
@ -21,23 +21,18 @@ import androidx.compose.material3.MaterialTheme
|
|||
import androidx.compose.material3.OutlinedButton
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||
import eu.kanade.tachiyomi.R
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.compose.LifecycleEventEffect
|
||||
import dev.icerock.moko.resources.compose.stringResource
|
||||
import eu.kanade.tachiyomi.util.system.isShizukuInstalled
|
||||
import yokai.i18n.MR
|
||||
import yokai.util.lang.getString
|
||||
import dev.icerock.moko.resources.compose.stringResource
|
||||
import yokai.presentation.component.Gap
|
||||
import yokai.presentation.theme.Size
|
||||
|
||||
|
@ -53,35 +48,26 @@ internal class PermissionStep : OnboardingStep {
|
|||
@Composable
|
||||
override fun Content() {
|
||||
val context = LocalContext.current
|
||||
val lifecycleOwner = LocalLifecycleOwner.current
|
||||
|
||||
DisposableEffect(lifecycleOwner.lifecycle) {
|
||||
val observer = object : DefaultLifecycleObserver {
|
||||
override fun onResume(owner: LifecycleOwner) {
|
||||
installGranted =
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
context.packageManager.canRequestPackageInstalls()
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
Settings.Secure.getInt(
|
||||
context.contentResolver,
|
||||
Settings.Secure.INSTALL_NON_MARKET_APPS
|
||||
) != 0
|
||||
} || context.isShizukuInstalled
|
||||
notificationGranted = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
context.checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) ==
|
||||
PackageManager.PERMISSION_GRANTED
|
||||
} else {
|
||||
true
|
||||
}
|
||||
batteryGranted = context.getSystemService<PowerManager>()!!
|
||||
.isIgnoringBatteryOptimizations(context.packageName)
|
||||
}
|
||||
}
|
||||
lifecycleOwner.lifecycle.addObserver(observer)
|
||||
onDispose {
|
||||
lifecycleOwner.lifecycle.removeObserver(observer)
|
||||
LifecycleEventEffect(Lifecycle.Event.ON_RESUME) {
|
||||
installGranted =
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
context.packageManager.canRequestPackageInstalls()
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
Settings.Secure.getInt(
|
||||
context.contentResolver,
|
||||
Settings.Secure.INSTALL_NON_MARKET_APPS
|
||||
) != 0
|
||||
} || context.isShizukuInstalled
|
||||
notificationGranted = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
context.checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) ==
|
||||
PackageManager.PERMISSION_GRANTED
|
||||
} else {
|
||||
true
|
||||
}
|
||||
batteryGranted = context.getSystemService<PowerManager>()!!
|
||||
.isIgnoringBatteryOptimizations(context.packageName)
|
||||
}
|
||||
|
||||
Column(
|
||||
|
|
|
@ -10,14 +10,17 @@ import androidx.compose.material3.TextButton
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import com.google.android.material.textview.MaterialTextView
|
||||
import dev.icerock.moko.resources.compose.stringResource
|
||||
import eu.kanade.tachiyomi.data.updater.AppDownloadInstallJob
|
||||
import eu.kanade.tachiyomi.ui.more.parseReleaseNotes
|
||||
import java.io.Serializable
|
||||
import kotlin.coroutines.resume
|
||||
import yokai.domain.DialogHostState
|
||||
import yokai.i18n.MR
|
||||
import android.R as AR
|
||||
|
||||
data class NewUpdateData(
|
||||
val body: String,
|
||||
|
@ -89,3 +92,17 @@ private fun MarkdownText(text: String) {
|
|||
},
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun DialogHostState.awaitNotificationPermissionDeniedDialog(): Unit = dialog { cont ->
|
||||
// cont.resume(Unit) so that new update dialog will be shown next
|
||||
AlertDialog(
|
||||
onDismissRequest = { if (cont.isActive) cont.resume(Unit) },
|
||||
title = { Text(text = stringResource(MR.strings.warning)) },
|
||||
text = { Text(text = stringResource(MR.strings.allow_notifications_recommended)) },
|
||||
confirmButton = {
|
||||
TextButton(onClick = { if (cont.isActive) cont.resume(Unit) }) {
|
||||
Text(text = stringResource(AR.string.ok))
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@ import android.content.ClipData
|
|||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.FlowRow
|
||||
|
@ -25,8 +27,11 @@ import androidx.compose.ui.platform.LocalContext
|
|||
import androidx.compose.ui.platform.LocalUriHandler
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.compose.LifecycleEventEffect
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import co.touchlab.kermit.Logger
|
||||
import dev.icerock.moko.resources.StringResource
|
||||
import dev.icerock.moko.resources.compose.stringResource
|
||||
import eu.kanade.tachiyomi.BuildConfig
|
||||
import eu.kanade.tachiyomi.core.storage.preference.asDateFormat
|
||||
|
@ -39,7 +44,9 @@ import eu.kanade.tachiyomi.util.CrashLogUtil
|
|||
import eu.kanade.tachiyomi.util.compose.LocalDialogHostState
|
||||
import eu.kanade.tachiyomi.util.compose.currentOrThrow
|
||||
import eu.kanade.tachiyomi.util.lang.toTimestampString
|
||||
import eu.kanade.tachiyomi.util.showNotificationPermissionPrompt
|
||||
import eu.kanade.tachiyomi.util.system.isOnline
|
||||
import eu.kanade.tachiyomi.util.system.launchIO
|
||||
import eu.kanade.tachiyomi.util.system.localeContext
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import eu.kanade.tachiyomi.util.system.withUIContext
|
||||
|
@ -49,7 +56,8 @@ import java.text.SimpleDateFormat
|
|||
import java.util.Locale
|
||||
import java.util.TimeZone
|
||||
import kotlinx.coroutines.launch
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import yokai.domain.DialogHostState
|
||||
import yokai.i18n.MR
|
||||
import yokai.presentation.component.preference.widget.TextPreferenceWidget
|
||||
|
@ -70,11 +78,34 @@ class AboutScreen : Screen() {
|
|||
val dialogHostState = LocalDialogHostState.currentOrThrow
|
||||
val uriHandler = LocalUriHandler.current
|
||||
|
||||
val preferences = remember { Injekt.get<PreferencesHelper>() }
|
||||
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
val scope = rememberCoroutineScope()
|
||||
val listState = rememberLazyListState()
|
||||
|
||||
val preferences: PreferencesHelper by injectLazy()
|
||||
val requestNotificationPermission = rememberLauncherForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
|
||||
if (!isGranted) {
|
||||
scope.launch { dialogHostState.awaitNotificationPermissionDeniedDialog() }
|
||||
}
|
||||
}
|
||||
LifecycleEventEffect(Lifecycle.Event.ON_RESUME) {
|
||||
// FIXME: Move this to MainActivity once the app is fully migrated to Compose
|
||||
scope.launchIO {
|
||||
context.checkVersion(
|
||||
dialogState = dialogHostState,
|
||||
isUserPrompt = false,
|
||||
notificationPrompt = {
|
||||
context.showNotificationPermissionPrompt(
|
||||
requestNotificationPermission,
|
||||
false,
|
||||
preferences,
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val dateFormat by lazy { preferences.dateFormatRaw().get().asDateFormat() }
|
||||
|
||||
SettingsScaffold(
|
||||
|
@ -108,7 +139,7 @@ class AboutScreen : Screen() {
|
|||
onPreferenceClick = {
|
||||
if (context.isOnline()) {
|
||||
scope.launch {
|
||||
context.checkVersion(dialogHostState)
|
||||
context.checkVersion(dialogHostState, true)
|
||||
}
|
||||
} else {
|
||||
context.toast(MR.strings.no_network_connection)
|
||||
|
@ -192,16 +223,25 @@ class AboutScreen : Screen() {
|
|||
else -> "Release ${BuildConfig.VERSION_NAME}"
|
||||
}
|
||||
|
||||
private suspend fun Context.checkVersion(dialogState: DialogHostState) {
|
||||
private fun Context.toastIfNotUserPrompt(message: StringResource, isUserPrompt: Boolean) {
|
||||
toastIfNotUserPrompt(getString(message), isUserPrompt)
|
||||
}
|
||||
|
||||
private fun Context.toastIfNotUserPrompt(message: String?, isUserPrompt: Boolean) {
|
||||
if (!isUserPrompt) return
|
||||
toast(message)
|
||||
}
|
||||
|
||||
private suspend fun Context.checkVersion(dialogState: DialogHostState, isUserPrompt: Boolean, notificationPrompt: () -> Unit = {}) {
|
||||
val updateChecker = AppUpdateChecker()
|
||||
|
||||
withUIContext { toast(MR.strings.searching_for_updates) }
|
||||
withUIContext { toastIfNotUserPrompt(MR.strings.searching_for_updates, isUserPrompt) }
|
||||
|
||||
val result = try {
|
||||
updateChecker.checkForUpdate(this, true)
|
||||
updateChecker.checkForUpdate(this, isUserPrompt)
|
||||
} catch (error: Exception) {
|
||||
withUIContext {
|
||||
toast(error.message)
|
||||
toastIfNotUserPrompt(error.message, isUserPrompt)
|
||||
Logger.e(error) { "Couldn't check new update" }
|
||||
}
|
||||
}
|
||||
|
@ -215,14 +255,13 @@ class AboutScreen : Screen() {
|
|||
|
||||
// Create confirmation window
|
||||
withUIContext {
|
||||
if (!isUserPrompt) { notificationPrompt() }
|
||||
AppUpdateNotifier.releasePageUrl = result.release.releaseLink
|
||||
dialogState.awaitNewUpdateDialog(data)
|
||||
}
|
||||
}
|
||||
is AppUpdateResult.NoNewUpdate -> {
|
||||
withUIContext {
|
||||
toast(MR.strings.no_new_updates_available)
|
||||
}
|
||||
withUIContext { toastIfNotUserPrompt(MR.strings.no_new_updates_available, isUserPrompt) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue