Skip to content

Commit

Permalink
fix: Handle version check for AboutController
Browse files Browse the repository at this point in the history
  • Loading branch information
null2264 committed Jan 3, 2025
1 parent eba5aa1 commit e06b28a
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 49 deletions.
7 changes: 3 additions & 4 deletions app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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 {
Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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))
}
},
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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(
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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" }
}
}
Expand All @@ -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) }
}
}
}
Expand Down

0 comments on commit e06b28a

Please sign in to comment.