Add import for new color scheme format
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
plugins {
|
||||
alias(libs.plugins.android.library)
|
||||
alias(libs.plugins.kotlin.android)
|
||||
alias(libs.plugins.kotlin.plugin.serialization)
|
||||
alias(libs.plugins.kotlin.plugin.compose)
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@ import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
@@ -46,7 +45,6 @@ import androidx.compose.ui.unit.dp
|
||||
import de.mm20.launcher2.preferences.SearchBarStyle
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.layout.BottomReversed
|
||||
import de.mm20.launcher2.ui.locals.LocalCardStyle
|
||||
import de.mm20.launcher2.ui.theme.transparency.LocalTransparencyScheme
|
||||
|
||||
@Composable
|
||||
@@ -61,6 +59,7 @@ fun SearchBar(
|
||||
onUnfocus: () -> Unit = {},
|
||||
reverse: Boolean = false,
|
||||
darkColors: Boolean = false,
|
||||
readOnly: Boolean = false,
|
||||
menu: @Composable RowScope.() -> Unit = {},
|
||||
actions: @Composable ColumnScope.() -> Unit = {},
|
||||
onKeyboardActionGo: (KeyboardActionScope.() -> Unit)? = null
|
||||
@@ -190,7 +189,8 @@ fun SearchBar(
|
||||
),
|
||||
keyboardActions = KeyboardActions(
|
||||
onGo = onKeyboardActionGo,
|
||||
)
|
||||
),
|
||||
readOnly = readOnly,
|
||||
)
|
||||
}
|
||||
Row(
|
||||
|
||||
@@ -6,6 +6,7 @@ import de.mm20.launcher2.ui.base.BaseActivity
|
||||
import de.mm20.launcher2.ui.base.ProvideSettings
|
||||
import de.mm20.launcher2.ui.common.ImportThemeSheet
|
||||
import de.mm20.launcher2.ui.overlays.OverlayHost
|
||||
import de.mm20.launcher2.ui.settings.appearance.ImportThemeSettingsScreen
|
||||
import de.mm20.launcher2.ui.theme.LauncherTheme
|
||||
|
||||
class ImportThemeActivity : BaseActivity() {
|
||||
@@ -19,10 +20,7 @@ class ImportThemeActivity : BaseActivity() {
|
||||
LauncherTheme {
|
||||
ProvideSettings {
|
||||
OverlayHost {
|
||||
ImportThemeSheet(
|
||||
onDismiss = { finish() },
|
||||
uri = uri,
|
||||
)
|
||||
ImportThemeSettingsScreen(uri)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package de.mm20.launcher2.ui.settings
|
||||
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import androidx.activity.SystemBarStyle
|
||||
import androidx.activity.compose.setContent
|
||||
@@ -22,11 +23,13 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.core.net.toUri
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import androidx.navigation.navArgument
|
||||
import androidx.navigation.toRoute
|
||||
import de.mm20.launcher2.licenses.AppLicense
|
||||
import de.mm20.launcher2.licenses.OpenSourceLicenses
|
||||
import de.mm20.launcher2.ui.base.BaseActivity
|
||||
@@ -38,6 +41,8 @@ import de.mm20.launcher2.ui.overlays.OverlayHost
|
||||
import de.mm20.launcher2.ui.settings.about.AboutSettingsScreen
|
||||
import de.mm20.launcher2.ui.settings.appearance.AppearanceSettingsScreen
|
||||
import de.mm20.launcher2.ui.settings.appearance.ExportThemeSettingsScreen
|
||||
import de.mm20.launcher2.ui.settings.appearance.ImportThemeSettingsRoute
|
||||
import de.mm20.launcher2.ui.settings.appearance.ImportThemeSettingsScreen
|
||||
import de.mm20.launcher2.ui.settings.backup.BackupSettingsScreen
|
||||
import de.mm20.launcher2.ui.settings.breezyweather.BreezyWeatherSettingsScreen
|
||||
import de.mm20.launcher2.ui.settings.buildinfo.BuildInfoSettingsScreen
|
||||
@@ -163,6 +168,10 @@ class SettingsActivity : BaseActivity() {
|
||||
composable("settings/appearance/export") {
|
||||
ExportThemeSettingsScreen()
|
||||
}
|
||||
composable<ImportThemeSettingsRoute> {
|
||||
val route: ImportThemeSettingsRoute = it.toRoute() ?: return@composable
|
||||
ImportThemeSettingsScreen(route.fromUri.toUri())
|
||||
}
|
||||
composable("settings/homescreen") {
|
||||
HomescreenSettingsScreen()
|
||||
}
|
||||
|
||||
+15
-2
@@ -1,5 +1,7 @@
|
||||
package de.mm20.launcher2.ui.settings.appearance
|
||||
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.ArrowCircleDown
|
||||
import androidx.compose.material.icons.rounded.ArrowCircleUp
|
||||
@@ -35,6 +37,14 @@ fun AppearanceSettingsScreen() {
|
||||
val colorThemeName by viewModel.colorThemeName.collectAsStateWithLifecycle(null)
|
||||
val shapeThemeName by viewModel.shapeThemeName.collectAsStateWithLifecycle(null)
|
||||
val compatModeColors by viewModel.compatModeColors.collectAsState()
|
||||
|
||||
val importLauncher = rememberLauncherForActivityResult(ActivityResultContracts.OpenDocument()) {
|
||||
if (it == null) {
|
||||
return@rememberLauncherForActivityResult
|
||||
}
|
||||
navController?.navigate(ImportThemeSettingsRoute(it.toString()))
|
||||
}
|
||||
|
||||
PreferenceScreen(title = stringResource(id = R.string.preference_screen_appearance)) {
|
||||
item {
|
||||
PreferenceCategory {
|
||||
@@ -105,11 +115,14 @@ fun AppearanceSettingsScreen() {
|
||||
item {
|
||||
PreferenceCategory {
|
||||
Preference(
|
||||
title = "Import",
|
||||
title = stringResource(R.string.theme_import_title),
|
||||
icon = Icons.Rounded.ArrowCircleDown,
|
||||
onClick = {
|
||||
importLauncher.launch(arrayOf("*/*"))
|
||||
}
|
||||
)
|
||||
Preference(
|
||||
title = "Export",
|
||||
title = stringResource(R.string.theme_export_title),
|
||||
icon = Icons.Rounded.ArrowCircleUp,
|
||||
onClick = {
|
||||
navController?.navigate("settings/appearance/export")
|
||||
|
||||
+350
@@ -0,0 +1,350 @@
|
||||
package de.mm20.launcher2.ui.settings.appearance
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.activity.compose.LocalActivity
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.ChangeCircle
|
||||
import androidx.compose.material.icons.rounded.CropSquare
|
||||
import androidx.compose.material.icons.rounded.DarkMode
|
||||
import androidx.compose.material.icons.rounded.Edit
|
||||
import androidx.compose.material.icons.rounded.ErrorOutline
|
||||
import androidx.compose.material.icons.rounded.LightMode
|
||||
import androidx.compose.material.icons.rounded.MoreVert
|
||||
import androidx.compose.material.icons.rounded.Palette
|
||||
import androidx.compose.material.icons.rounded.PublishedWithChanges
|
||||
import androidx.compose.material.icons.rounded.Star
|
||||
import androidx.compose.material.icons.rounded.Upgrade
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.FilledTonalIconButton
|
||||
import androidx.compose.material3.FilterChip
|
||||
import androidx.compose.material3.FilterChipDefaults
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedButton
|
||||
import androidx.compose.material3.SegmentedButton
|
||||
import androidx.compose.material3.SegmentedButtonDefaults
|
||||
import androidx.compose.material3.SingleChoiceSegmentedButtonRow
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
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
|
||||
import androidx.compose.ui.draw.innerShadow
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.shadow.InnerShadow
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import de.mm20.launcher2.preferences.SearchBarStyle
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.component.Banner
|
||||
import de.mm20.launcher2.ui.component.SearchBar
|
||||
import de.mm20.launcher2.ui.component.SearchBarLevel
|
||||
import de.mm20.launcher2.ui.component.preferences.Preference
|
||||
import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
|
||||
import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
|
||||
import de.mm20.launcher2.ui.component.preferences.SwitchPreference
|
||||
import de.mm20.launcher2.ui.locals.LocalDarkTheme
|
||||
import de.mm20.launcher2.ui.theme.colorscheme.darkColorSchemeOf
|
||||
import de.mm20.launcher2.ui.theme.colorscheme.lightColorSchemeOf
|
||||
import de.mm20.launcher2.ui.theme.shapes.shapesOf
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class ImportThemeSettingsRoute(val fromUri: String)
|
||||
|
||||
@Composable
|
||||
fun ImportThemeSettingsScreen(
|
||||
fromUri: Uri,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val activity = LocalActivity.current
|
||||
val viewModel: ImportThemeSettingsScreenVM = viewModel()
|
||||
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
val themeBundle = viewModel.themeBundle
|
||||
|
||||
LaunchedEffect(fromUri) {
|
||||
viewModel.init(context, fromUri)
|
||||
}
|
||||
|
||||
PreferenceScreen(title = stringResource(R.string.theme_import_title)) {
|
||||
|
||||
if (viewModel.error) {
|
||||
item {
|
||||
PreferenceCategory {
|
||||
Banner(
|
||||
text = stringResource(R.string.import_theme_error),
|
||||
icon = Icons.Rounded.ErrorOutline,
|
||||
modifier = Modifier
|
||||
.background(MaterialTheme.colorScheme.surface)
|
||||
.padding(16.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
} else if (themeBundle != null) {
|
||||
item {
|
||||
PreferenceCategory {
|
||||
Preference(
|
||||
title = themeBundle.name,
|
||||
summary = themeBundle.author?.takeIf { it.isNotBlank() })
|
||||
}
|
||||
}
|
||||
item {
|
||||
val isDarkMode = LocalDarkTheme.current
|
||||
var darkModePreview by remember { mutableStateOf(isDarkMode) }
|
||||
MaterialTheme(
|
||||
colorScheme = themeBundle.colors?.let {
|
||||
if (darkModePreview) darkColorSchemeOf(it) else lightColorSchemeOf(it)
|
||||
} ?: MaterialTheme.colorScheme,
|
||||
shapes = themeBundle.shapes?.let { shapesOf(it) } ?: MaterialTheme.shapes,
|
||||
) {
|
||||
ThemePreview(
|
||||
darkMode = darkModePreview,
|
||||
onDarkModeChanged = { darkModePreview = it }
|
||||
)
|
||||
}
|
||||
}
|
||||
item {
|
||||
PreferenceCategory {
|
||||
if (themeBundle.colors != null) {
|
||||
Preference(
|
||||
icon = Icons.Rounded.Palette,
|
||||
title = stringResource(R.string.preference_screen_colors),
|
||||
summary = themeBundle.colors?.name,
|
||||
controls = if (viewModel.colorsExists) {
|
||||
{
|
||||
Icon(Icons.Rounded.ChangeCircle, null)
|
||||
}
|
||||
} else null,
|
||||
)
|
||||
}
|
||||
if (themeBundle.shapes != null) {
|
||||
Preference(
|
||||
icon = Icons.Rounded.CropSquare,
|
||||
title = stringResource(R.string.preference_screen_shapes),
|
||||
summary = themeBundle.shapes?.name,
|
||||
controls = if (viewModel.shapesExists) {
|
||||
{
|
||||
Icon(Icons.Rounded.ChangeCircle, null)
|
||||
}
|
||||
} else null,
|
||||
)
|
||||
}
|
||||
if (viewModel.colorsExists || viewModel.shapesExists) {
|
||||
Banner(
|
||||
modifier = Modifier
|
||||
.background(
|
||||
MaterialTheme.colorScheme.surface,
|
||||
MaterialTheme.shapes.extraSmall
|
||||
)
|
||||
.padding(16.dp),
|
||||
icon = Icons.Rounded.ChangeCircle,
|
||||
text = stringResource(R.string.import_theme_exists)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
item {
|
||||
PreferenceCategory {
|
||||
SwitchPreference(
|
||||
title = stringResource(R.string.import_theme_apply),
|
||||
value = viewModel.applyTheme,
|
||||
onValueChanged = { viewModel.applyTheme = it },
|
||||
)
|
||||
Button(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(
|
||||
MaterialTheme.colorScheme.surface,
|
||||
MaterialTheme.shapes.extraSmall
|
||||
)
|
||||
.padding(16.dp),
|
||||
enabled = !viewModel.loading,
|
||||
onClick = {
|
||||
scope.launch {
|
||||
viewModel.import()?.join()
|
||||
activity?.onBackPressed()
|
||||
}
|
||||
|
||||
}
|
||||
) {
|
||||
Text(stringResource(R.string.action_import))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ThemePreview(
|
||||
darkMode: Boolean,
|
||||
onDarkModeChanged: (Boolean) -> Unit,
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(MaterialTheme.shapes.medium)
|
||||
.background(
|
||||
MaterialTheme.colorScheme.surfaceContainer,
|
||||
MaterialTheme.shapes.medium
|
||||
)
|
||||
.innerShadow(
|
||||
MaterialTheme.shapes.medium,
|
||||
InnerShadow(8.dp, color = Color(0f, 0f, 0f, 0.2f))
|
||||
)
|
||||
) {
|
||||
SearchBar(
|
||||
style = SearchBarStyle.Solid,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 12.dp, start = 12.dp, end = 12.dp),
|
||||
level = SearchBarLevel.Active,
|
||||
value = "",
|
||||
onValueChange = {},
|
||||
readOnly = true,
|
||||
menu = {
|
||||
IconButton(onClick = {}) {
|
||||
Icon(Icons.Rounded.MoreVert, null)
|
||||
}
|
||||
}
|
||||
)
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 12.dp, start = 12.dp, end = 12.dp)
|
||||
.background(MaterialTheme.colorScheme.surface, MaterialTheme.shapes.medium)
|
||||
.padding(12.dp)
|
||||
) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(80.dp)
|
||||
.background(
|
||||
MaterialTheme.colorScheme.secondaryContainer,
|
||||
MaterialTheme.shapes.small
|
||||
),
|
||||
)
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
) {
|
||||
Text(
|
||||
"Title",
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
)
|
||||
Text(
|
||||
"Subtitle",
|
||||
style = MaterialTheme.typography.titleSmall,
|
||||
color = MaterialTheme.colorScheme.secondary
|
||||
)
|
||||
Text(
|
||||
"Body",
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
modifier = Modifier.padding(top = 4.dp),
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
)
|
||||
}
|
||||
}
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 16.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
FilterChip(
|
||||
selected = true,
|
||||
label = { Text("Chip") },
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
Icons.Rounded.Star, null,
|
||||
modifier = Modifier.size(FilterChipDefaults.IconSize)
|
||||
)
|
||||
},
|
||||
onClick = { },
|
||||
)
|
||||
FilterChip(
|
||||
selected = false,
|
||||
label = { Text("Chip") },
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
Icons.Rounded.Star, null,
|
||||
modifier = Modifier.size(FilterChipDefaults.IconSize)
|
||||
)
|
||||
},
|
||||
onClick = { },
|
||||
)
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
FilledTonalIconButton(onClick = {}) {
|
||||
Icon(Icons.Rounded.Edit, null)
|
||||
}
|
||||
}
|
||||
HorizontalDivider(
|
||||
modifier = Modifier.padding(vertical = 8.dp)
|
||||
)
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.End),
|
||||
) {
|
||||
Button(onClick = {}) { Text("Button") }
|
||||
OutlinedButton(onClick = {}) { Text("Button") }
|
||||
}
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(12.dp),
|
||||
contentAlignment = Alignment.CenterEnd,
|
||||
) {
|
||||
SingleChoiceSegmentedButtonRow {
|
||||
SegmentedButton(
|
||||
shape = SegmentedButtonDefaults.itemShape(index = 0, count = 2),
|
||||
selected = !darkMode,
|
||||
onClick = { onDarkModeChanged(false) }
|
||||
) {
|
||||
Icon(Icons.Rounded.LightMode, null)
|
||||
}
|
||||
SegmentedButton(
|
||||
shape = SegmentedButtonDefaults.itemShape(index = 1, count = 2),
|
||||
selected = darkMode,
|
||||
onClick = { onDarkModeChanged(true) }
|
||||
) {
|
||||
Icon(Icons.Rounded.DarkMode, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun ThemePreviewPreview() {
|
||||
ThemePreview(
|
||||
darkMode = false,
|
||||
onDarkModeChanged = {}
|
||||
)
|
||||
}
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
package de.mm20.launcher2.ui.settings.appearance
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.crashreporter.CrashReporter
|
||||
import de.mm20.launcher2.preferences.ColorsDescriptor
|
||||
import de.mm20.launcher2.preferences.ShapesDescriptor
|
||||
import de.mm20.launcher2.preferences.ui.UiSettings
|
||||
import de.mm20.launcher2.themes.ThemeBundle
|
||||
import de.mm20.launcher2.themes.ThemeRepository
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
import kotlin.getValue
|
||||
|
||||
class ImportThemeSettingsScreenVM: ViewModel(), KoinComponent {
|
||||
|
||||
private val themeRepository by inject<ThemeRepository>()
|
||||
private val uiSettings by inject<UiSettings>()
|
||||
|
||||
var themeBundle by mutableStateOf<ThemeBundle?>(null)
|
||||
private set
|
||||
|
||||
var colorsExists by mutableStateOf(false)
|
||||
private set
|
||||
|
||||
var shapesExists by mutableStateOf(false)
|
||||
private set
|
||||
|
||||
var loading by mutableStateOf(false)
|
||||
private set
|
||||
|
||||
var error by mutableStateOf(false)
|
||||
private set
|
||||
|
||||
var applyTheme by mutableStateOf(true)
|
||||
|
||||
fun init(context: Context, fromUri: Uri) {
|
||||
themeBundle = null
|
||||
error = false
|
||||
applyTheme = true
|
||||
loading = true
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
context.contentResolver.openInputStream(fromUri)?.reader()?.use {
|
||||
val text = it.readText()
|
||||
val theme = ThemeBundle.fromJson(text)
|
||||
if (theme != null) {
|
||||
val colors = theme.colors?.id?.let { themeRepository.getColors(it) }?.first()
|
||||
val shapes = theme.shapes?.id?.let { themeRepository.getShapes(it) }?.first()
|
||||
|
||||
colorsExists = colors != null
|
||||
shapesExists = shapes != null
|
||||
themeBundle = theme
|
||||
loading = false
|
||||
} else {
|
||||
error = true
|
||||
}
|
||||
}
|
||||
} catch (e: SecurityException) {
|
||||
CrashReporter.logException(e)
|
||||
error = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun import(): Job? {
|
||||
val themeBundle = this.themeBundle ?: return null
|
||||
|
||||
val colors = themeBundle.colors
|
||||
val shapes = themeBundle.shapes
|
||||
|
||||
val colorsExist = this.colorsExists
|
||||
val shapesExist = this.shapesExists
|
||||
|
||||
loading = true
|
||||
return viewModelScope.launch {
|
||||
if (colors != null) {
|
||||
if (colorsExist) {
|
||||
themeRepository.updateColors(colors)
|
||||
} else {
|
||||
themeRepository.createColors(colors)
|
||||
}
|
||||
if (applyTheme) {
|
||||
uiSettings.setColors(ColorsDescriptor.Custom(colors.id.toString()))
|
||||
}
|
||||
}
|
||||
if (shapes != null) {
|
||||
if (shapesExist) {
|
||||
themeRepository.updateShapes(shapes)
|
||||
} else {
|
||||
themeRepository.createShapes(shapes)
|
||||
}
|
||||
if (applyTheme) {
|
||||
uiSettings.setShapes(ShapesDescriptor.Custom(shapes.id.toString()))
|
||||
}
|
||||
}
|
||||
loading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -97,7 +97,8 @@ fun CorePaletteColorPreference(
|
||||
value = currentValue == null,
|
||||
onValueChanged = {
|
||||
currentValue = if (it) null else defaultValue
|
||||
}
|
||||
},
|
||||
containerColor = Color.Transparent,
|
||||
)
|
||||
AnimatedVisibility(
|
||||
currentValue != null,
|
||||
|
||||
Reference in New Issue
Block a user