mirror of
https://github.com/mihonapp/mihon.git
synced 2026-10-16 13:48:09 -07:00
@@ -45,4 +45,9 @@ class BasePreferences(
|
|||||||
Preference.appStateKey("donation_campaign_shown"),
|
Preference.appStateKey("donation_campaign_shown"),
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val skippedAppUpdate: Preference<String> = preferenceStore.getString(
|
||||||
|
Preference.appStateKey("skipped_app_update"),
|
||||||
|
"",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,12 +5,17 @@ import androidx.compose.foundation.layout.Spacer
|
|||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.material3.AlertDialog
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.OutlinedButton
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextButton
|
import androidx.compose.material3.TextButton
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||||
import eu.kanade.presentation.manga.components.MarkdownRender
|
import eu.kanade.presentation.manga.components.MarkdownRender
|
||||||
@@ -18,6 +23,7 @@ import eu.kanade.presentation.theme.TachiyomiPreviewTheme
|
|||||||
import eu.kanade.tachiyomi.ui.more.NewUpdateScreenModel
|
import eu.kanade.tachiyomi.ui.more.NewUpdateScreenModel
|
||||||
import mihon.icons.materialsymbols.MaterialSymbols
|
import mihon.icons.materialsymbols.MaterialSymbols
|
||||||
import mihon.icons.materialsymbols.automirroredrounded.OpenInNew
|
import mihon.icons.materialsymbols.automirroredrounded.OpenInNew
|
||||||
|
import mihon.icons.materialsymbols.rounded.UpdateDisabled
|
||||||
import mihon.icons.materialsymbols.rounded.Verified
|
import mihon.icons.materialsymbols.rounded.Verified
|
||||||
import org.intellij.markdown.flavours.gfm.GFMFlavourDescriptor
|
import org.intellij.markdown.flavours.gfm.GFMFlavourDescriptor
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
@@ -34,7 +40,33 @@ fun NewUpdateScreen(
|
|||||||
onOpenInBrowser: () -> Unit,
|
onOpenInBrowser: () -> Unit,
|
||||||
onAcceptUpdate: () -> Unit,
|
onAcceptUpdate: () -> Unit,
|
||||||
onRejectUpdate: () -> Unit,
|
onRejectUpdate: () -> Unit,
|
||||||
|
onSkipUpdate: () -> Unit,
|
||||||
) {
|
) {
|
||||||
|
var showSkipDialog by remember { mutableStateOf(false) }
|
||||||
|
if (showSkipDialog) {
|
||||||
|
val dismiss = { showSkipDialog = false }
|
||||||
|
AlertDialog(
|
||||||
|
onDismissRequest = dismiss,
|
||||||
|
title = { Text(text = stringResource(MR.strings.update_check_skip_title, versionName)) },
|
||||||
|
text = { Text(text = stringResource(MR.strings.update_check_skip_message)) },
|
||||||
|
dismissButton = {
|
||||||
|
TextButton(onClick = dismiss) {
|
||||||
|
Text(text = stringResource(MR.strings.action_cancel))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
confirmButton = {
|
||||||
|
TextButton(
|
||||||
|
onClick = {
|
||||||
|
dismiss()
|
||||||
|
onSkipUpdate()
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
Text(text = stringResource(MR.strings.action_ok))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
InfoScreen(
|
InfoScreen(
|
||||||
icon = MaterialSymbols.Rounded.Verified,
|
icon = MaterialSymbols.Rounded.Verified,
|
||||||
headingText = stringResource(MR.strings.update_check_notification_update_available),
|
headingText = stringResource(MR.strings.update_check_notification_update_available),
|
||||||
@@ -52,6 +84,14 @@ fun NewUpdateScreen(
|
|||||||
canAccept = stage != NewUpdateScreenModel.Stage.Downloading,
|
canAccept = stage != NewUpdateScreenModel.Stage.Downloading,
|
||||||
rejectText = stringResource(MR.strings.action_not_now),
|
rejectText = stringResource(MR.strings.action_not_now),
|
||||||
onRejectClick = onRejectUpdate,
|
onRejectClick = onRejectUpdate,
|
||||||
|
rejectAction = {
|
||||||
|
OutlinedButton(onClick = { showSkipDialog = true }) {
|
||||||
|
Icon(
|
||||||
|
imageVector = MaterialSymbols.Rounded.UpdateDisabled,
|
||||||
|
contentDescription = stringResource(MR.strings.update_check_skip),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -94,6 +134,7 @@ private fun NewUpdateScreenPreview() {
|
|||||||
onOpenInBrowser = {},
|
onOpenInBrowser = {},
|
||||||
onAcceptUpdate = {},
|
onAcceptUpdate = {},
|
||||||
onRejectUpdate = {},
|
onRejectUpdate = {},
|
||||||
|
onSkipUpdate = {},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -355,7 +355,10 @@ class MainActivity : BaseActivity() {
|
|||||||
if (updaterEnabled) {
|
if (updaterEnabled) {
|
||||||
try {
|
try {
|
||||||
val result = context.appGraph.updateChecker.checkForUpdate()
|
val result = context.appGraph.updateChecker.checkForUpdate()
|
||||||
if (result is GetApplicationRelease.Result.NewUpdate) {
|
if (
|
||||||
|
result is GetApplicationRelease.Result.NewUpdate &&
|
||||||
|
result.release.version != preferences.skippedAppUpdate.get()
|
||||||
|
) {
|
||||||
val updateScreen = NewUpdateScreen(
|
val updateScreen = NewUpdateScreen(
|
||||||
versionName = result.release.version,
|
versionName = result.release.version,
|
||||||
changelogInfo = result.release.info,
|
changelogInfo = result.release.info,
|
||||||
|
|||||||
@@ -43,6 +43,10 @@ class NewUpdateScreen(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRejectUpdate = navigator::pop,
|
onRejectUpdate = navigator::pop,
|
||||||
|
onSkipUpdate = {
|
||||||
|
viewModel.skipUpdate(versionName)
|
||||||
|
navigator.pop()
|
||||||
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import dev.zacsweers.metro.AssistedInject
|
|||||||
import dev.zacsweers.metro.ContributesIntoMap
|
import dev.zacsweers.metro.ContributesIntoMap
|
||||||
import dev.zacsweers.metrox.viewmodel.ManualViewModelAssistedFactory
|
import dev.zacsweers.metrox.viewmodel.ManualViewModelAssistedFactory
|
||||||
import dev.zacsweers.metrox.viewmodel.ManualViewModelAssistedFactoryKey
|
import dev.zacsweers.metrox.viewmodel.ManualViewModelAssistedFactoryKey
|
||||||
|
import eu.kanade.domain.base.BasePreferences
|
||||||
import eu.kanade.tachiyomi.extension.util.ExtensionInstaller
|
import eu.kanade.tachiyomi.extension.util.ExtensionInstaller
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||||
@@ -38,6 +39,7 @@ class NewUpdateScreenModel(
|
|||||||
@Assisted private val downloadLink: String,
|
@Assisted private val downloadLink: String,
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val network: NetworkHelper,
|
private val network: NetworkHelper,
|
||||||
|
private val preferences: BasePreferences,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
val state: StateFlow<NewUpdateScreenModel.State>
|
val state: StateFlow<NewUpdateScreenModel.State>
|
||||||
@@ -96,6 +98,11 @@ class NewUpdateScreenModel(
|
|||||||
response.body.source().saveTo(apkFile)
|
response.body.source().saveTo(apkFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun skipUpdate(versionName: String) {
|
||||||
|
downloadJob?.cancel()
|
||||||
|
preferences.skippedAppUpdate.set(versionName)
|
||||||
|
}
|
||||||
|
|
||||||
fun installUpdate() {
|
fun installUpdate() {
|
||||||
val intent = Intent(Intent.ACTION_VIEW).apply {
|
val intent = Intent(Intent.ACTION_VIEW).apply {
|
||||||
setDataAndType(apkFile.getUriCompat(context), ExtensionInstaller.APK_MIME)
|
setDataAndType(apkFile.getUriCompat(context), ExtensionInstaller.APK_MIME)
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ class CrashLogUtil(
|
|||||||
App ID: ${BuildConfig.APPLICATION_ID}
|
App ID: ${BuildConfig.APPLICATION_ID}
|
||||||
App version: ${BuildConfig.VERSION_NAME} (${BuildConfig.COMMIT_SHA}, ${BuildConfig.VERSION_CODE}, ${BuildConfig.BUILD_TIME})
|
App version: ${BuildConfig.VERSION_NAME} (${BuildConfig.COMMIT_SHA}, ${BuildConfig.VERSION_CODE}, ${BuildConfig.BUILD_TIME})
|
||||||
Installation ID: ${preferences.installationId.get()}
|
Installation ID: ${preferences.installationId.get()}
|
||||||
|
Skipped app update: ${preferences.skippedAppUpdate.get().ifEmpty { "None" }}
|
||||||
Android version: ${Build.VERSION.RELEASE} (SDK ${Build.VERSION.SDK_INT}; build ${Build.DISPLAY})
|
Android version: ${Build.VERSION.RELEASE} (SDK ${Build.VERSION.SDK_INT}; build ${Build.DISPLAY})
|
||||||
Device brand: ${Build.BRAND}
|
Device brand: ${Build.BRAND}
|
||||||
Device manufacturer: ${Build.MANUFACTURER}
|
Device manufacturer: ${Build.MANUFACTURER}
|
||||||
|
|||||||
@@ -993,6 +993,9 @@
|
|||||||
<!--UpdateCheck-->
|
<!--UpdateCheck-->
|
||||||
<string name="update_check_confirm">Download</string>
|
<string name="update_check_confirm">Download</string>
|
||||||
<string name="update_check_open">Open on GitHub</string>
|
<string name="update_check_open">Open on GitHub</string>
|
||||||
|
<string name="update_check_skip">Skip this version</string>
|
||||||
|
<string name="update_check_skip_title">Skip %s?</string>
|
||||||
|
<string name="update_check_skip_message">Updates often contain bug fixes and security improvements. You won\'t be reminded about this version again, but you\'ll still be notified when a newer one is released.</string>
|
||||||
<!-- reserved for future use -->
|
<!-- reserved for future use -->
|
||||||
<string name="update_check_eol">This Android version is no longer supported</string>
|
<string name="update_check_eol">This Android version is no longer supported</string>
|
||||||
<string name="update_check_no_new_updates">No new updates available</string>
|
<string name="update_check_no_new_updates">No new updates available</string>
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<!--
|
||||||
|
Material Symbols Rounded 'update_disabled', v399.
|
||||||
|
Copyright (C) Google LLC
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
-->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="m763-84-92-91q-42 26-90 40.5T480-120q-75 0-140.5-28.5t-114-77q-48.5-48.5-77-114T120-480q0-53 14.5-101t40.5-90l-92-92q-12-12-12-28.5T83-820q12-12 28.5-12t28.5 12l680 680q12 12 12 28t-12 28q-12 12-28.5 12T763-84ZM480-200q36 0 69.5-8.5T613-233L233-613q-16 30-24.5 63.5T200-480q0 117 81.5 198.5T480-200Zm160-360q-17 0-28.5-11.5T600-600q0-17 11.5-28.5T640-640h70q-41-56-101-88t-129-32q-27 0-56 5.5T370-738q-15 7-30 .5T318-759q-7-15-.5-30.5T339-811q32-14 69-21.5t72-7.5q82 0 155.5 35T760-706v-54q0-17 11.5-28.5T800-800q17 0 28.5 11.5T840-760v160q0 17-11.5 28.5T800-560H640Zm-188.5-45.5Q440-617 440-634v-6q0-17 11.5-28.5T480-680q17 0 28.5 11.5T520-640v6q0 17-11.5 28.5T480-594q-17 0-28.5-11.5ZM759-316q-14-6-22-20.5t0-33.5q3-8 7-18t6-18q5-16 18.5-24.5T798-437q17 2 27 14.5t6 27.5q-4 14-9.5 29T811-338q-8 19-23 23.5t-29-1.5Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.0 KiB |
@@ -1,9 +1,12 @@
|
|||||||
package tachiyomi.presentation.core.screens
|
package tachiyomi.presentation.core.screens
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.ColumnScope
|
import androidx.compose.foundation.layout.ColumnScope
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.RowScope
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
@@ -42,6 +45,7 @@ fun InfoScreen(
|
|||||||
canAccept: Boolean = true,
|
canAccept: Boolean = true,
|
||||||
rejectText: String? = null,
|
rejectText: String? = null,
|
||||||
onRejectClick: (() -> Unit)? = null,
|
onRejectClick: (() -> Unit)? = null,
|
||||||
|
rejectAction: (@Composable RowScope.() -> Unit)? = null,
|
||||||
content: @Composable ColumnScope.() -> Unit,
|
content: @Composable ColumnScope.() -> Unit,
|
||||||
) {
|
) {
|
||||||
Scaffold(
|
Scaffold(
|
||||||
@@ -73,11 +77,14 @@ fun InfoScreen(
|
|||||||
Text(text = acceptText)
|
Text(text = acceptText)
|
||||||
}
|
}
|
||||||
if (rejectText != null && onRejectClick != null) {
|
if (rejectText != null && onRejectClick != null) {
|
||||||
OutlinedButton(
|
Row(horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.extraSmall)) {
|
||||||
modifier = Modifier.fillMaxWidth(),
|
OutlinedButton(
|
||||||
onClick = onRejectClick,
|
modifier = Modifier.weight(1f),
|
||||||
) {
|
onClick = onRejectClick,
|
||||||
Text(text = rejectText)
|
) {
|
||||||
|
Text(text = rejectText)
|
||||||
|
}
|
||||||
|
rejectAction?.invoke(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user