mirror of
https://github.com/amir1376/ab-download-manager.git
synced 2025-02-20 11:43:24 +08:00
add support follow system light,dark mode
This commit is contained in:
parent
8f302c1259
commit
e8f552934d
@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
- support follow system Dark/Light mode
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
### Deprecated
|
### Deprecated
|
||||||
|
@ -6,6 +6,7 @@ plugins {
|
|||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
google()
|
google()
|
||||||
|
maven("https://jitpack.io")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getOptIns() = setOf(
|
fun getOptIns() = setOf(
|
||||||
|
@ -13,7 +13,9 @@ plugins {
|
|||||||
id(Plugins.aboutLibraries)
|
id(Plugins.aboutLibraries)
|
||||||
// id(MyPlugins.proguardDesktop)
|
// id(MyPlugins.proguardDesktop)
|
||||||
}
|
}
|
||||||
|
repositories{
|
||||||
|
maven("https://jitpack.io")
|
||||||
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(libs.decompose)
|
implementation(libs.decompose)
|
||||||
implementation(libs.decompose.jbCompose)
|
implementation(libs.decompose.jbCompose)
|
||||||
@ -41,9 +43,13 @@ dependencies {
|
|||||||
implementation(libs.arrow.core)
|
implementation(libs.arrow.core)
|
||||||
implementation(libs.arrow.optics)
|
implementation(libs.arrow.optics)
|
||||||
ksp(libs.arrow.opticKsp)
|
ksp(libs.arrow.opticKsp)
|
||||||
|
|
||||||
implementation(libs.androidx.datastore)
|
implementation(libs.androidx.datastore)
|
||||||
|
|
||||||
implementation(libs.aboutLibraries.core)
|
implementation(libs.aboutLibraries.core)
|
||||||
|
|
||||||
|
implementation(libs.osThemeDetector)
|
||||||
|
|
||||||
implementation(project(":downloader:core"))
|
implementation(project(":downloader:core"))
|
||||||
implementation(project(":downloader:monitor"))
|
implementation(project(":downloader:monitor"))
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import com.abdownloadmanager.desktop.AppArguments
|
|||||||
import com.abdownloadmanager.integration.IntegrationHandler
|
import com.abdownloadmanager.integration.IntegrationHandler
|
||||||
import com.abdownloadmanager.desktop.AppComponent
|
import com.abdownloadmanager.desktop.AppComponent
|
||||||
import com.abdownloadmanager.desktop.integration.IntegrationHandlerImp
|
import com.abdownloadmanager.desktop.integration.IntegrationHandlerImp
|
||||||
|
import com.abdownloadmanager.desktop.pages.settings.ThemeManager
|
||||||
import ir.amirab.downloader.queue.QueueManager
|
import ir.amirab.downloader.queue.QueueManager
|
||||||
import com.abdownloadmanager.desktop.repository.AppRepository
|
import com.abdownloadmanager.desktop.repository.AppRepository
|
||||||
import com.abdownloadmanager.desktop.storage.*
|
import com.abdownloadmanager.desktop.storage.*
|
||||||
@ -157,6 +158,9 @@ val appModule = module {
|
|||||||
single {
|
single {
|
||||||
AppRepository()
|
AppRepository()
|
||||||
}
|
}
|
||||||
|
single {
|
||||||
|
ThemeManager(get(),get())
|
||||||
|
}
|
||||||
single {
|
single {
|
||||||
AppSettingsStorage(
|
AppSettingsStorage(
|
||||||
createMyConfigPreferences(
|
createMyConfigPreferences(
|
||||||
|
@ -6,16 +6,14 @@ import com.abdownloadmanager.desktop.repository.AppRepository
|
|||||||
import com.abdownloadmanager.desktop.storage.AppSettingsStorage
|
import com.abdownloadmanager.desktop.storage.AppSettingsStorage
|
||||||
import com.abdownloadmanager.desktop.ui.icon.IconSource
|
import com.abdownloadmanager.desktop.ui.icon.IconSource
|
||||||
import com.abdownloadmanager.desktop.ui.icon.MyIcons
|
import com.abdownloadmanager.desktop.ui.icon.MyIcons
|
||||||
import com.abdownloadmanager.desktop.ui.theme.darkColors
|
|
||||||
import com.abdownloadmanager.desktop.ui.theme.lightColors
|
|
||||||
import com.abdownloadmanager.desktop.utils.BaseComponent
|
import com.abdownloadmanager.desktop.utils.BaseComponent
|
||||||
import com.abdownloadmanager.desktop.utils.convertSpeedToHumanReadable
|
import com.abdownloadmanager.desktop.utils.convertSpeedToHumanReadable
|
||||||
import ir.amirab.util.flow.mapTwoWayStateFlow
|
|
||||||
import com.abdownloadmanager.desktop.utils.mvi.ContainsEffects
|
import com.abdownloadmanager.desktop.utils.mvi.ContainsEffects
|
||||||
import com.abdownloadmanager.desktop.utils.mvi.supportEffects
|
import com.abdownloadmanager.desktop.utils.mvi.supportEffects
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import com.arkivanov.decompose.ComponentContext
|
import com.arkivanov.decompose.ComponentContext
|
||||||
import ir.amirab.util.FileUtils
|
import ir.amirab.util.FileUtils
|
||||||
|
import ir.amirab.util.flow.createMutableStateFlowFromStateFlow
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import org.koin.core.component.KoinComponent
|
import org.koin.core.component.KoinComponent
|
||||||
import org.koin.core.component.inject
|
import org.koin.core.component.inject
|
||||||
@ -25,7 +23,8 @@ sealed class SettingSections(
|
|||||||
val name: String,
|
val name: String,
|
||||||
) {
|
) {
|
||||||
data object Appearance : SettingSections(MyIcons.appearance, "Appearance")
|
data object Appearance : SettingSections(MyIcons.appearance, "Appearance")
|
||||||
// TODO ADD Network section (proxy , etc..)
|
|
||||||
|
// TODO ADD Network section (proxy , etc..)
|
||||||
// data object Network : SettingSections(MyIcons.network, "Network")
|
// data object Network : SettingSections(MyIcons.network, "Network")
|
||||||
data object DownloadEngine : SettingSections(MyIcons.downloadEngine, "Download Engine")
|
data object DownloadEngine : SettingSections(MyIcons.downloadEngine, "Download Engine")
|
||||||
data object BrowserIntegration : SettingSections(MyIcons.network, "Browser Integration")
|
data object BrowserIntegration : SettingSections(MyIcons.network, "Browser Integration")
|
||||||
@ -47,6 +46,7 @@ fun threadCountConfig(appRepository: AppRepository): IntConfigurable {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun dynamicPartDownloadConfig(appRepository: AppRepository): BooleanConfigurable {
|
fun dynamicPartDownloadConfig(appRepository: AppRepository): BooleanConfigurable {
|
||||||
return BooleanConfigurable(
|
return BooleanConfigurable(
|
||||||
title = "Dynamic part creation",
|
title = "Dynamic part creation",
|
||||||
@ -55,7 +55,7 @@ fun dynamicPartDownloadConfig(appRepository: AppRepository): BooleanConfigurable
|
|||||||
describe = {
|
describe = {
|
||||||
if (it) {
|
if (it) {
|
||||||
"Enabled"
|
"Enabled"
|
||||||
}else{
|
} else {
|
||||||
"Disabled"
|
"Disabled"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -131,23 +131,26 @@ fun uiScaleConfig(appSettings: AppSettings): EnumConfigurable<Float?> {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
fun themeConfig(appSettings: AppSettingsStorage, scope: CoroutineScope): ThemeConfigurable {
|
fun themeConfig(
|
||||||
val defaultTheme = "dark"
|
themeManager: ThemeManager,
|
||||||
val themes = mapOf(
|
scope: CoroutineScope,
|
||||||
"dark" to darkColors,
|
): ThemeConfigurable {
|
||||||
"light" to lightColors
|
val currentThemeName = themeManager.currentThemeInfo
|
||||||
)
|
val themes = themeManager.possibleThemesToSelect
|
||||||
return ThemeConfigurable(
|
return ThemeConfigurable(
|
||||||
title = "Theme",
|
title = "Theme",
|
||||||
description = "Select theme",
|
description = "Select theme",
|
||||||
//maybe try a better way?
|
backedBy = createMutableStateFlowFromStateFlow(
|
||||||
backedBy = appSettings.theme.mapTwoWayStateFlow({
|
flow = currentThemeName,
|
||||||
themes[it]?:themes[defaultTheme]!!
|
updater = {
|
||||||
}, { myColors ->
|
themeManager.setTheme(it.id)
|
||||||
themes.entries.firstOrNull() { it.value == myColors }?.key ?: defaultTheme
|
},
|
||||||
}),
|
scope = scope,
|
||||||
possibleValues = listOf(darkColors, lightColors),
|
),
|
||||||
describe = { it.name },
|
possibleValues = themes.value,
|
||||||
|
describe = {
|
||||||
|
it.name
|
||||||
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,6 +169,7 @@ fun autoStartConfig(appSettings: AppSettingsStorage): BooleanConfigurable {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun playSoundNotification(appSettings: AppSettingsStorage): BooleanConfigurable {
|
fun playSoundNotification(appSettings: AppSettingsStorage): BooleanConfigurable {
|
||||||
return BooleanConfigurable(
|
return BooleanConfigurable(
|
||||||
title = "Notification Sound",
|
title = "Notification Sound",
|
||||||
@ -221,11 +225,12 @@ class SettingsComponent(
|
|||||||
ContainsEffects<SettingPageEffects> by supportEffects() {
|
ContainsEffects<SettingPageEffects> by supportEffects() {
|
||||||
val appSettings by inject<AppSettingsStorage>()
|
val appSettings by inject<AppSettingsStorage>()
|
||||||
val appRepository by inject<AppRepository>()
|
val appRepository by inject<AppRepository>()
|
||||||
|
val themeManager by inject<ThemeManager>()
|
||||||
val allConfigs = object : SettingSectionGetter {
|
val allConfigs = object : SettingSectionGetter {
|
||||||
override operator fun get(key: SettingSections): List<Configurable<*>> {
|
override operator fun get(key: SettingSections): List<Configurable<*>> {
|
||||||
return when (key) {
|
return when (key) {
|
||||||
Appearance -> listOf(
|
Appearance -> listOf(
|
||||||
themeConfig(appSettings, scope),
|
themeConfig(themeManager, scope),
|
||||||
// uiScaleConfig(appSettings),
|
// uiScaleConfig(appSettings),
|
||||||
autoStartConfig(appSettings),
|
autoStartConfig(appSettings),
|
||||||
playSoundNotification(appSettings),
|
playSoundNotification(appSettings),
|
||||||
|
@ -0,0 +1,160 @@
|
|||||||
|
package com.abdownloadmanager.desktop.pages.settings
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Stable
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import com.abdownloadmanager.desktop.storage.AppSettingsStorage
|
||||||
|
import com.abdownloadmanager.desktop.ui.theme.MyColors
|
||||||
|
import com.abdownloadmanager.desktop.ui.theme.SystemThemeDetector
|
||||||
|
import com.abdownloadmanager.desktop.ui.theme.darkColors
|
||||||
|
import com.abdownloadmanager.desktop.ui.theme.lightColors
|
||||||
|
import ir.amirab.util.flow.combineStateFlows
|
||||||
|
import ir.amirab.util.flow.mapStateFlow
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.flow.*
|
||||||
|
|
||||||
|
class ThemeManager(
|
||||||
|
private val scope: CoroutineScope,
|
||||||
|
private val appSettings: AppSettingsStorage,
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
val defaultThemes = listOf(
|
||||||
|
darkColors,
|
||||||
|
lightColors,
|
||||||
|
)
|
||||||
|
val defaultDarkTheme = darkColors
|
||||||
|
val defaultLightTheme = lightColors
|
||||||
|
val DefaultTheme = defaultDarkTheme
|
||||||
|
val DEFAULT_THEME_ID = DefaultTheme.id
|
||||||
|
val systemThemeInfo = ThemeInfo(
|
||||||
|
id = "system",
|
||||||
|
name = "System",
|
||||||
|
color = Color.Gray,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val _availableThemes = MutableStateFlow(emptyList<MyColors>())
|
||||||
|
val availableThemes = _availableThemes.asStateFlow()
|
||||||
|
|
||||||
|
private fun getThemeById(themeId: String): MyColors? {
|
||||||
|
return availableThemes.value.find {
|
||||||
|
it.id == themeId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val possibleThemesToSelect = availableThemes.mapStateFlow {
|
||||||
|
buildList {
|
||||||
|
addAll(it.map {
|
||||||
|
it.toThemeInfo()
|
||||||
|
})
|
||||||
|
if (osThemeDetector.isSupported) {
|
||||||
|
add(systemThemeInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private val themeIds = possibleThemesToSelect.mapStateFlow {
|
||||||
|
it.map { it.id }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
val currentThemeInfo = combineStateFlows(
|
||||||
|
appSettings.theme, possibleThemesToSelect
|
||||||
|
) { themeId, possibleThemes ->
|
||||||
|
possibleThemes.find {
|
||||||
|
it.id == themeId
|
||||||
|
} ?: possibleThemes.find {
|
||||||
|
it.id == DEFAULT_THEME_ID
|
||||||
|
}!!
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private val osThemeDetector = SystemThemeDetector()
|
||||||
|
private var osDarkModeFlow = MutableStateFlow(true)
|
||||||
|
|
||||||
|
val currentThemeColor = combineStateFlows(
|
||||||
|
themeIds, appSettings.theme, osDarkModeFlow
|
||||||
|
) { themes, themeId, osThemeIsDark ->
|
||||||
|
if (themeId == systemThemeInfo.id) {
|
||||||
|
if (osThemeIsDark) {
|
||||||
|
defaultDarkTheme
|
||||||
|
} else {
|
||||||
|
defaultLightTheme
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (themes.contains(themeId)) {
|
||||||
|
getThemeById(themeId)!!
|
||||||
|
} else {
|
||||||
|
defaultDarkTheme
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setTheme(themeId: String) {
|
||||||
|
synchronized(this) {
|
||||||
|
if (themeId == systemThemeInfo.id) {
|
||||||
|
registerSystemThemeDetector()
|
||||||
|
} else {
|
||||||
|
unRegisterSystemThemeDetector()
|
||||||
|
}
|
||||||
|
if (themeIds.value.contains(themeId)) {
|
||||||
|
appSettings.theme.value = themeId
|
||||||
|
} else {
|
||||||
|
// theme id in setting is invalid update it
|
||||||
|
appSettings.theme.value = DEFAULT_THEME_ID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Volatile
|
||||||
|
private var booted = false
|
||||||
|
|
||||||
|
fun boot() {
|
||||||
|
if (booted) return
|
||||||
|
// now we can load custom themes here
|
||||||
|
// loadCustomThemes()
|
||||||
|
//
|
||||||
|
_availableThemes.update {
|
||||||
|
it.plus(defaultThemes)
|
||||||
|
}
|
||||||
|
setTheme(appSettings.theme.value)
|
||||||
|
booted = true
|
||||||
|
}
|
||||||
|
|
||||||
|
private var osUpdateFlowJob: Job? = null
|
||||||
|
private fun registerSystemThemeDetector() {
|
||||||
|
osUpdateFlowJob?.cancel()
|
||||||
|
if (osThemeDetector.isSupported) {
|
||||||
|
// update immediately
|
||||||
|
osDarkModeFlow.value = osThemeDetector.isDark
|
||||||
|
osUpdateFlowJob = osThemeDetector.systemThemeFlow.onEach { isDark ->
|
||||||
|
osDarkModeFlow.value = isDark
|
||||||
|
}.launchIn(scope)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun unRegisterSystemThemeDetector() {
|
||||||
|
osUpdateFlowJob?.cancel()
|
||||||
|
osUpdateFlowJob = null
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is for demonstration purposes of a theme
|
||||||
|
*/
|
||||||
|
@Stable
|
||||||
|
data class ThemeInfo(
|
||||||
|
val id: String,
|
||||||
|
val name: String,
|
||||||
|
val color: Color,
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun MyColors.toThemeInfo(): ThemeInfo {
|
||||||
|
return ThemeInfo(
|
||||||
|
id = id,
|
||||||
|
name = name,
|
||||||
|
color = surface,
|
||||||
|
)
|
||||||
|
}
|
@ -1,5 +1,8 @@
|
|||||||
package com.abdownloadmanager.desktop.pages.settings.configurable
|
package com.abdownloadmanager.desktop.pages.settings.configurable
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Stable
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import com.abdownloadmanager.desktop.pages.settings.ThemeInfo
|
||||||
import com.abdownloadmanager.desktop.pages.settings.configurable.BooleanConfigurable.RenderMode
|
import com.abdownloadmanager.desktop.pages.settings.configurable.BooleanConfigurable.RenderMode
|
||||||
import com.abdownloadmanager.desktop.ui.theme.MyColors
|
import com.abdownloadmanager.desktop.ui.theme.MyColors
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
@ -230,12 +233,12 @@ open class EnumConfigurable<T>(
|
|||||||
class ThemeConfigurable(
|
class ThemeConfigurable(
|
||||||
title: String,
|
title: String,
|
||||||
description: String,
|
description: String,
|
||||||
backedBy: MutableStateFlow<MyColors>,
|
backedBy: MutableStateFlow<ThemeInfo>,
|
||||||
describe: (MyColors) -> String,
|
describe: (ThemeInfo) -> String,
|
||||||
possibleValues: List<MyColors>,
|
possibleValues: List<ThemeInfo>,
|
||||||
enabled: StateFlow<Boolean> = DefaultEnabledValue,
|
enabled: StateFlow<Boolean> = DefaultEnabledValue,
|
||||||
visible: StateFlow<Boolean> = DefaultVisibleValue,
|
visible: StateFlow<Boolean> = DefaultVisibleValue,
|
||||||
) : BaseEnumConfigurable<MyColors>(
|
) : BaseEnumConfigurable<ThemeInfo>(
|
||||||
title = title,
|
title = title,
|
||||||
description = description,
|
description = description,
|
||||||
backedBy = backedBy,
|
backedBy = backedBy,
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
package com.abdownloadmanager.desktop.pages.settings.configurable.widgets
|
package com.abdownloadmanager.desktop.pages.settings.configurable.widgets
|
||||||
|
|
||||||
import com.abdownloadmanager.desktop.pages.settings.configurable.EnumConfigurable
|
|
||||||
import com.abdownloadmanager.desktop.pages.settings.configurable.ThemeConfigurable
|
import com.abdownloadmanager.desktop.pages.settings.configurable.ThemeConfigurable
|
||||||
import com.abdownloadmanager.desktop.ui.theme.myColors
|
import com.abdownloadmanager.desktop.ui.theme.myColors
|
||||||
import com.abdownloadmanager.desktop.ui.theme.myTextSizes
|
import com.abdownloadmanager.desktop.ui.theme.myTextSizes
|
||||||
import com.abdownloadmanager.desktop.utils.div
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.border
|
import androidx.compose.foundation.border
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
@ -18,7 +16,6 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Brush
|
import androidx.compose.ui.graphics.Brush
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun RenderThemeConfig(cfg: ThemeConfigurable, modifier: Modifier) {
|
fun RenderThemeConfig(cfg: ThemeConfigurable, modifier: Modifier) {
|
||||||
@ -49,7 +46,7 @@ fun RenderThemeConfig(cfg: ThemeConfigurable, modifier: Modifier) {
|
|||||||
)
|
)
|
||||||
.padding(1.dp)
|
.padding(1.dp)
|
||||||
.background(
|
.background(
|
||||||
it.surface,
|
it.color,
|
||||||
)
|
)
|
||||||
.size(16.dp)
|
.size(16.dp)
|
||||||
)
|
)
|
||||||
|
@ -26,6 +26,7 @@ import com.abdownloadmanager.desktop.utils.mvi.HandleEffects
|
|||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.window.*
|
import androidx.compose.ui.window.*
|
||||||
import com.abdownloadmanager.desktop.pages.home.HomeWindow
|
import com.abdownloadmanager.desktop.pages.home.HomeWindow
|
||||||
|
import com.abdownloadmanager.desktop.pages.settings.ThemeManager
|
||||||
import com.abdownloadmanager.utils.compose.ProvideDebugInfo
|
import com.abdownloadmanager.utils.compose.ProvideDebugInfo
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -41,14 +42,17 @@ object Ui : KoinComponent {
|
|||||||
globalAppExceptionHandler: GlobalAppExceptionHandler,
|
globalAppExceptionHandler: GlobalAppExceptionHandler,
|
||||||
) {
|
) {
|
||||||
val appComponent: AppComponent = get()
|
val appComponent: AppComponent = get()
|
||||||
|
val themeManager: ThemeManager = get()
|
||||||
|
themeManager.boot()
|
||||||
if (!appArguments.startSilent) {
|
if (!appArguments.startSilent) {
|
||||||
appComponent.openHome()
|
appComponent.openHome()
|
||||||
}
|
}
|
||||||
application {
|
application {
|
||||||
|
val theme by themeManager.currentThemeColor.collectAsState()
|
||||||
ProvideDebugInfo(AppInfo.isInDebugMode()) {
|
ProvideDebugInfo(AppInfo.isInDebugMode()) {
|
||||||
ProvideNotificationManager {
|
ProvideNotificationManager {
|
||||||
ABDownloaderTheme(
|
ABDownloaderTheme(
|
||||||
theme = appComponent.theme.collectAsState().value,
|
myColors = theme,
|
||||||
// uiScale = appComponent.uiScale.collectAsState().value
|
// uiScale = appComponent.uiScale.collectAsState().value
|
||||||
) {
|
) {
|
||||||
ProvideGlobalExceptionHandler(globalAppExceptionHandler) {
|
ProvideGlobalExceptionHandler(globalAppExceptionHandler) {
|
||||||
|
@ -24,6 +24,7 @@ import androidx.compose.ui.unit.sp
|
|||||||
import androidx.compose.ui.window.Popup
|
import androidx.compose.ui.window.Popup
|
||||||
import androidx.compose.ui.window.PopupProperties
|
import androidx.compose.ui.window.PopupProperties
|
||||||
import androidx.compose.ui.window.rememberPopupPositionProviderAtPosition
|
import androidx.compose.ui.window.rememberPopupPositionProviderAtPosition
|
||||||
|
import com.abdownloadmanager.desktop.pages.settings.ThemeManager
|
||||||
|
|
||||||
/*
|
/*
|
||||||
fun MyColors.asMaterial2Colors(): Colors {
|
fun MyColors.asMaterial2Colors(): Colors {
|
||||||
@ -67,6 +68,7 @@ val darkColors = MyColors(
|
|||||||
onInfo = Color.White,
|
onInfo = Color.White,
|
||||||
isLight = false,
|
isLight = false,
|
||||||
name = "Dark",
|
name = "Dark",
|
||||||
|
id = "dark",
|
||||||
)
|
)
|
||||||
val lightColors = MyColors(
|
val lightColors = MyColors(
|
||||||
primary = Color(0xFF4791BF),
|
primary = Color(0xFF4791BF),
|
||||||
@ -91,6 +93,7 @@ val lightColors = MyColors(
|
|||||||
onInfo = Color.White,
|
onInfo = Color.White,
|
||||||
isLight = true,
|
isLight = true,
|
||||||
name = "Light",
|
name = "Light",
|
||||||
|
id = "light",
|
||||||
)
|
)
|
||||||
|
|
||||||
private val textSizes = TextSizes(
|
private val textSizes = TextSizes(
|
||||||
@ -103,16 +106,10 @@ private val textSizes = TextSizes(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ABDownloaderTheme(
|
fun ABDownloaderTheme(
|
||||||
theme: String,
|
myColors: MyColors,
|
||||||
// uiScale: Float? = null,
|
// uiScale: Float? = null,
|
||||||
content: @Composable () -> Unit,
|
content: @Composable () -> Unit,
|
||||||
) {
|
) {
|
||||||
val myColors = if (theme == "light") {
|
|
||||||
lightColors
|
|
||||||
} else {
|
|
||||||
darkColors
|
|
||||||
}
|
|
||||||
|
|
||||||
CompositionLocalProvider(
|
CompositionLocalProvider(
|
||||||
LocalMyColors provides AnimatedColors(myColors, tween(500)),
|
LocalMyColors provides AnimatedColors(myColors, tween(500)),
|
||||||
// LocalUiScale provides uiScale,
|
// LocalUiScale provides uiScale,
|
||||||
|
@ -20,6 +20,7 @@ val myColors
|
|||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
class MyColors(
|
class MyColors(
|
||||||
|
val id:String,
|
||||||
val name:String,
|
val name:String,
|
||||||
|
|
||||||
|
|
||||||
@ -163,5 +164,6 @@ fun AnimatedColors(
|
|||||||
onInfo=onInfo,
|
onInfo=onInfo,
|
||||||
isLight = isLight,
|
isLight = isLight,
|
||||||
name = toBeAnimated.name,
|
name = toBeAnimated.name,
|
||||||
|
id = toBeAnimated.id,
|
||||||
)
|
)
|
||||||
}
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
package com.abdownloadmanager.desktop.ui.theme
|
||||||
|
|
||||||
|
import com.jthemedetecor.OsThemeDetector
|
||||||
|
import kotlinx.coroutines.channels.awaitClose
|
||||||
|
import kotlinx.coroutines.flow.callbackFlow
|
||||||
|
import kotlinx.coroutines.flow.emitAll
|
||||||
|
import kotlinx.coroutines.flow.flow
|
||||||
|
|
||||||
|
class SystemThemeDetector {
|
||||||
|
val isSupported by lazy {
|
||||||
|
OsThemeDetector.isSupported()
|
||||||
|
}
|
||||||
|
private val detector by lazy { OsThemeDetector.getDetector() }
|
||||||
|
|
||||||
|
private val isSystemDarkFlowByLibrary = callbackFlow<Boolean> {
|
||||||
|
val listener: (Boolean) -> Unit = { isDark: Boolean ->
|
||||||
|
trySend(isDark)
|
||||||
|
}
|
||||||
|
detector.registerListener(listener)
|
||||||
|
awaitClose {
|
||||||
|
detector.removeListener(listener)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val isDark = detector.isDark
|
||||||
|
val systemThemeFlow = flow {
|
||||||
|
if (!isSupported){
|
||||||
|
return@flow
|
||||||
|
}
|
||||||
|
emit(detector.isDark)
|
||||||
|
emitAll(isSystemDarkFlowByLibrary)
|
||||||
|
}
|
||||||
|
}
|
@ -8,6 +8,7 @@ import androidx.compose.runtime.DisposableEffect
|
|||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||||
import androidx.compose.ui.window.*
|
import androidx.compose.ui.window.*
|
||||||
|
import com.abdownloadmanager.desktop.pages.settings.ThemeManager
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import java.awt.Window
|
import java.awt.Window
|
||||||
@ -67,7 +68,7 @@ private class GlobalExceptionHandlerImpl : GlobalAppExceptionHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ABDownloaderTheme(
|
ABDownloaderTheme(
|
||||||
"dark",
|
ThemeManager.DefaultTheme,
|
||||||
) {
|
) {
|
||||||
ErrorWindow(throwable, close)
|
ErrorWindow(throwable, close)
|
||||||
}
|
}
|
||||||
|
@ -105,6 +105,7 @@ arrow-optics = { module = "io.arrow-kt:arrow-optics", version.ref = "arrow" }
|
|||||||
arrow-opticKsp = { module = "io.arrow-kt:arrow-optics-ksp-plugin", version.ref = "arrow" }
|
arrow-opticKsp = { module = "io.arrow-kt:arrow-optics-ksp-plugin", version.ref = "arrow" }
|
||||||
|
|
||||||
androidx-datastore = { module = "androidx.datastore:datastore", version.ref = "datastore" }
|
androidx-datastore = { module = "androidx.datastore:datastore", version.ref = "datastore" }
|
||||||
|
osThemeDetector = "com.github.Dansoftowner:jSystemThemeDetector:3.9.1"
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user