From 08ab2bb4438f8503093c26f572ab9c9e0c1d65cc Mon Sep 17 00:00:00 2001 From: Ash Date: Wed, 27 Mar 2024 12:07:46 +0800 Subject: [PATCH] feat(font): automatically restart the app after loading external fonts --- .../preference/BasicFontsPreference.kt | 4 ++ .../preference/ReadingFontsPreference.kt | 4 ++ .../java/me/ash/reader/ui/ext/ContextExt.kt | 6 ++ .../java/me/ash/reader/ui/ext/StringExt.kt | 8 +++ .../page/settings/color/ColorAndStylePage.kt | 64 ++++++++++++++++--- .../color/reading/ReadingStylePage.kt | 8 ++- 6 files changed, 81 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/me/ash/reader/infrastructure/preference/BasicFontsPreference.kt b/app/src/main/java/me/ash/reader/infrastructure/preference/BasicFontsPreference.kt index 9126215ee..699ba192e 100644 --- a/app/src/main/java/me/ash/reader/infrastructure/preference/BasicFontsPreference.kt +++ b/app/src/main/java/me/ash/reader/infrastructure/preference/BasicFontsPreference.kt @@ -11,6 +11,7 @@ import me.ash.reader.ui.ext.DataStoreKeys import me.ash.reader.ui.ext.ExternalFonts import me.ash.reader.ui.ext.dataStore import me.ash.reader.ui.ext.put +import me.ash.reader.ui.ext.restart import me.ash.reader.ui.theme.SystemTypography sealed class BasicFontsPreference(val value: Int) : Preference() { @@ -20,6 +21,9 @@ sealed class BasicFontsPreference(val value: Int) : Preference() { override fun put(context: Context, scope: CoroutineScope) { scope.launch { context.dataStore.put(DataStoreKeys.BasicFonts, value) + if (this@BasicFontsPreference == External) { + context.restart() + } } } diff --git a/app/src/main/java/me/ash/reader/infrastructure/preference/ReadingFontsPreference.kt b/app/src/main/java/me/ash/reader/infrastructure/preference/ReadingFontsPreference.kt index c2b7405eb..a9cb9033c 100644 --- a/app/src/main/java/me/ash/reader/infrastructure/preference/ReadingFontsPreference.kt +++ b/app/src/main/java/me/ash/reader/infrastructure/preference/ReadingFontsPreference.kt @@ -10,6 +10,7 @@ import me.ash.reader.ui.ext.DataStoreKeys import me.ash.reader.ui.ext.ExternalFonts import me.ash.reader.ui.ext.dataStore import me.ash.reader.ui.ext.put +import me.ash.reader.ui.ext.restart sealed class ReadingFontsPreference(val value: Int) : Preference() { object System : ReadingFontsPreference(0) @@ -22,6 +23,9 @@ sealed class ReadingFontsPreference(val value: Int) : Preference() { override fun put(context: Context, scope: CoroutineScope) { scope.launch { context.dataStore.put(DataStoreKeys.ReadingFonts, value) + if (this@ReadingFontsPreference == External) { + context.restart() + } } } diff --git a/app/src/main/java/me/ash/reader/ui/ext/ContextExt.kt b/app/src/main/java/me/ash/reader/ui/ext/ContextExt.kt index e263dda24..c441f5a3b 100644 --- a/app/src/main/java/me/ash/reader/ui/ext/ContextExt.kt +++ b/app/src/main/java/me/ash/reader/ui/ext/ContextExt.kt @@ -21,6 +21,12 @@ import me.ash.reader.infrastructure.preference.OpenLinkPreference import me.ash.reader.infrastructure.preference.OpenLinkSpecificBrowserPreference import java.io.File +fun Context.restart() { + packageManager.getLaunchIntentForPackage(packageName)?.let { + startActivity(Intent.makeRestartActivityTask(it.component)) + Runtime.getRuntime().exit(0) + } +} fun Context.findActivity(): Activity? = when (this) { is Activity -> this diff --git a/app/src/main/java/me/ash/reader/ui/ext/StringExt.kt b/app/src/main/java/me/ash/reader/ui/ext/StringExt.kt index c453e7b78..735cc3fc5 100644 --- a/app/src/main/java/me/ash/reader/ui/ext/StringExt.kt +++ b/app/src/main/java/me/ash/reader/ui/ext/StringExt.kt @@ -5,6 +5,14 @@ import android.util.Base64 import java.math.BigInteger import java.security.MessageDigest +object MimeType { + + const val ANY = "*/*" + const val FONT = "font/ttf" // Not supported yet + const val OPML = "text/x-opml" // Not supported yet + const val JSON = "application/json" +} + fun String.formatUrl(): String { if (this.startsWith("//")) { return "https:$this" diff --git a/app/src/main/java/me/ash/reader/ui/page/settings/color/ColorAndStylePage.kt b/app/src/main/java/me/ash/reader/ui/page/settings/color/ColorAndStylePage.kt index 2243586bb..a08efcadc 100644 --- a/app/src/main/java/me/ash/reader/ui/page/settings/color/ColorAndStylePage.kt +++ b/app/src/main/java/me/ash/reader/ui/page/settings/color/ColorAndStylePage.kt @@ -4,24 +4,45 @@ import android.content.Context import android.os.Build import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts -import androidx.compose.animation.* +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.expandIn +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.shrinkOut import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.horizontalScroll -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.navigationBars +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.windowInsetsBottomHeight import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.rounded.ArrowBack import androidx.compose.material.icons.outlined.Check import androidx.compose.material.icons.outlined.Palette -import androidx.compose.material.icons.automirrored.rounded.ArrowBack import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text -import androidx.compose.runtime.* +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -31,16 +52,39 @@ import androidx.compose.ui.text.TextStyle import androidx.compose.ui.unit.dp import androidx.navigation.NavHostController import me.ash.reader.R -import me.ash.reader.infrastructure.preference.* -import me.ash.reader.ui.component.base.* +import me.ash.reader.infrastructure.preference.BasicFontsPreference +import me.ash.reader.infrastructure.preference.CustomPrimaryColorPreference +import me.ash.reader.infrastructure.preference.LocalBasicFonts +import me.ash.reader.infrastructure.preference.LocalCustomPrimaryColor +import me.ash.reader.infrastructure.preference.LocalDarkTheme +import me.ash.reader.infrastructure.preference.LocalThemeIndex +import me.ash.reader.infrastructure.preference.ThemeIndexPreference +import me.ash.reader.infrastructure.preference.not +import me.ash.reader.ui.component.base.BlockRadioButton +import me.ash.reader.ui.component.base.BlockRadioGroupButtonItem +import me.ash.reader.ui.component.base.DisplayText +import me.ash.reader.ui.component.base.DynamicSVGImage +import me.ash.reader.ui.component.base.FeedbackIconButton +import me.ash.reader.ui.component.base.RYScaffold +import me.ash.reader.ui.component.base.RYSwitch +import me.ash.reader.ui.component.base.RadioDialog +import me.ash.reader.ui.component.base.RadioDialogOption +import me.ash.reader.ui.component.base.Subtitle +import me.ash.reader.ui.component.base.TextFieldDialog import me.ash.reader.ui.ext.ExternalFonts +import me.ash.reader.ui.ext.MimeType +import me.ash.reader.ui.ext.showToast import me.ash.reader.ui.page.common.RouteName import me.ash.reader.ui.page.settings.SettingItem import me.ash.reader.ui.svg.PALETTE import me.ash.reader.ui.svg.SVGString -import me.ash.reader.ui.theme.palette.* +import me.ash.reader.ui.theme.palette.TonalPalettes import me.ash.reader.ui.theme.palette.TonalPalettes.Companion.toTonalPalettes +import me.ash.reader.ui.theme.palette.checkColorHex import me.ash.reader.ui.theme.palette.dynamic.extractTonalPalettesFromUserWallpaper +import me.ash.reader.ui.theme.palette.onDark +import me.ash.reader.ui.theme.palette.onLight +import me.ash.reader.ui.theme.palette.safeHexToColor @Composable fun ColorAndStylePage( @@ -58,11 +102,11 @@ fun ColorAndStylePage( var radioButtonSelected by remember { mutableStateOf(if (themeIndex > 4) 0 else 1) } var fontsDialogVisible by remember { mutableStateOf(false) } - val launcher = rememberLauncherForActivityResult(ActivityResultContracts.GetContent()) { uri -> + val launcher = rememberLauncherForActivityResult(ActivityResultContracts.OpenDocument()) { uri -> uri?.let { ExternalFonts(context, it, ExternalFonts.FontType.BasicFont).copyToInternalStorage() BasicFontsPreference.External.put(context, scope) - } + } ?: context.showToast("Cannot get activity result with launcher") } RYScaffold( @@ -218,7 +262,7 @@ fun ColorAndStylePage( selected = it == fonts, ) { if (it.value == BasicFontsPreference.External.value) { - launcher.launch("*/*") + launcher.launch(arrayOf(MimeType.FONT)) } else { it.put(context, scope) } diff --git a/app/src/main/java/me/ash/reader/ui/page/settings/color/reading/ReadingStylePage.kt b/app/src/main/java/me/ash/reader/ui/page/settings/color/reading/ReadingStylePage.kt index 744fec57d..b05bdba88 100644 --- a/app/src/main/java/me/ash/reader/ui/page/settings/color/reading/ReadingStylePage.kt +++ b/app/src/main/java/me/ash/reader/ui/page/settings/color/reading/ReadingStylePage.kt @@ -59,6 +59,8 @@ import me.ash.reader.ui.component.base.RadioDialog import me.ash.reader.ui.component.base.RadioDialogOption import me.ash.reader.ui.component.base.Subtitle import me.ash.reader.ui.ext.ExternalFonts +import me.ash.reader.ui.ext.MimeType +import me.ash.reader.ui.ext.showToast import me.ash.reader.ui.page.common.RouteName import me.ash.reader.ui.page.settings.SettingItem import me.ash.reader.ui.theme.palette.onLight @@ -82,11 +84,11 @@ fun ReadingStylePage( var tonalElevationDialogVisible by remember { mutableStateOf(false) } var fontsDialogVisible by remember { mutableStateOf(false) } - val launcher = rememberLauncherForActivityResult(ActivityResultContracts.GetContent()) { uri -> + val launcher = rememberLauncherForActivityResult(ActivityResultContracts.OpenDocument()) { uri -> uri?.let { ExternalFonts(context, it, ExternalFonts.FontType.ReadingFont).copyToInternalStorage() ReadingFontsPreference.External.put(context, scope) - } + } ?: context.showToast("Cannot get activity result with launcher") } RYScaffold( @@ -298,7 +300,7 @@ fun ReadingStylePage( selected = it == fonts, ) { if (it.value == ReadingFontsPreference.External.value) { - launcher.launch("*/*") + launcher.launch(arrayOf(MimeType.FONT)) } else { it.put(context, scope) }