From 6b704cc9eacdb301439138a160543b65af36f896 Mon Sep 17 00:00:00 2001 From: AmirHossein Abdolmotallebi Date: Tue, 3 Dec 2024 17:53:02 +0330 Subject: [PATCH] add ui scale feature --- .../abdownloadmanager/desktop/AppComponent.kt | 2 +- .../pages/settings/SettingsComponent.kt | 19 ++-- .../desktop/repository/AppRepository.kt | 2 +- .../desktop/storage/AppSettingsStorage.kt | 17 +++- .../com/abdownloadmanager/desktop/ui/Ui.kt | 2 +- .../desktop/ui/customwindow/CustomWindow.kt | 89 +++++++++-------- .../desktop/ui/customwindow/OptionsDialog.kt | 16 +-- .../desktop/ui/theme/ABDownloaderTheme.kt | 19 +++- .../desktop/ui/theme/Sizing.kt | 4 +- desktop/custom-window-frame/build.gradle.kts | 3 + .../amirab/util/customwindow/ToolbarItem.kt | 25 +++-- .../util/desktop/screen/DesktopScreen.kt | 97 +++++++++++++++++++ .../ir/amirab/util/config/extensions.kt | 31 +++--- .../resources/locales/en_US.properties | 3 + 14 files changed, 246 insertions(+), 83 deletions(-) create mode 100644 desktop/shared/src/main/kotlin/ir/amirab/util/desktop/screen/DesktopScreen.kt diff --git a/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/AppComponent.kt b/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/AppComponent.kt index a864fe1..90372a3 100644 --- a/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/AppComponent.kt +++ b/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/AppComponent.kt @@ -852,7 +852,7 @@ class AppComponent( val showOpenSourceLibraries = MutableStateFlow(false) val showTranslators = MutableStateFlow(false) val theme = appRepository.theme -// val uiScale = appRepository.uiScale + val uiScale = appRepository.uiScale } interface DownloadDialogManager { diff --git a/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/pages/settings/SettingsComponent.kt b/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/pages/settings/SettingsComponent.kt index 3452df0..39af102 100644 --- a/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/pages/settings/SettingsComponent.kt +++ b/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/pages/settings/SettingsComponent.kt @@ -199,17 +199,17 @@ fun proxyConfig(proxyManager: ProxyManager, scope: CoroutineScope): ProxyConfigu ) } -/* -fun uiScaleConfig(appSettings: AppSettings): EnumConfigurable { +fun uiScaleConfig(appSettings: AppSettingsStorage): EnumConfigurable { return EnumConfigurable( - title = "Ui Scale", - description = "Scale Ui Elements", + title = Res.string.settings_ui_scale.asStringSource(), + description = Res.string.settings_ui_scale_description.asStringSource(), backedBy = appSettings.uiScale, possibleValues = listOf( null, - 0.5f, - 0.75f, + 0.8f, + 0.9f, 1f, + 1.1f, 1.25f, 1.5f, 1.75f, @@ -218,14 +218,13 @@ fun uiScaleConfig(appSettings: AppSettings): EnumConfigurable { renderMode = EnumConfigurable.RenderMode.Spinner, describe = { if (it == null) { - "System" + Res.string.system.asStringSource() } else { - "$it x" + "$it x".asStringSource() } } ) } -*/ fun themeConfig( themeManager: ThemeManager, @@ -377,7 +376,7 @@ class SettingsComponent( Appearance -> listOf( themeConfig(themeManager, scope), languageConfig(languageManager, scope), -// uiScaleConfig(appSettings), + uiScaleConfig(appSettings), autoStartConfig(appSettings), mergeTopBarWithTitleBarConfig(appSettings), playSoundNotification(appSettings), diff --git a/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/repository/AppRepository.kt b/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/repository/AppRepository.kt index 241101e..1334950 100644 --- a/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/repository/AppRepository.kt +++ b/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/repository/AppRepository.kt @@ -23,7 +23,7 @@ class AppRepository : KoinComponent { private val proxyManager: ProxyManager by inject() val theme = appSettings.theme - // val uiScale = appSettings.uiScale + val uiScale = appSettings.uiScale private val downloadSystem : DownloadSystem by inject() private val downloadSettings: DownloadSettings by inject() private val downloadManager: DownloadManager = downloadSystem.downloadManager diff --git a/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/storage/AppSettingsStorage.kt b/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/storage/AppSettingsStorage.kt index e14b0ef..55a4d1c 100644 --- a/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/storage/AppSettingsStorage.kt +++ b/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/storage/AppSettingsStorage.kt @@ -4,6 +4,7 @@ import com.abdownloadmanager.desktop.utils.* import androidx.datastore.core.DataStore import arrow.optics.Lens import arrow.optics.optics +import com.abdownloadmanager.desktop.App import ir.amirab.util.compose.localizationmanager.LanguageStorage import ir.amirab.util.config.* import kotlinx.serialization.Serializable @@ -15,6 +16,7 @@ import java.io.File data class AppSettingsModel( val theme: String = "dark", val language: String = "en", + val uiScale: Float? = null, val mergeTopBarWithTitleBar: Boolean = false, val threadCount: Int = 8, val dynamicPartCreation: Boolean = true, @@ -40,6 +42,7 @@ data class AppSettingsModel( object Keys { val theme = stringKeyOf("theme") val language = stringKeyOf("language") + val uiScale = floatKeyOf("uiScale") val mergeTopBarWithTitleBar = booleanKeyOf("mergeTopBarWithTitleBar") val threadCount = intKeyOf("threadCount") val dynamicPartCreation = booleanKeyOf("dynamicPartCreation") @@ -57,12 +60,12 @@ data class AppSettingsModel( } - override fun get(source: MapConfig): AppSettingsModel { val default by lazy { AppSettingsModel.default } return AppSettingsModel( theme = source.get(Keys.theme) ?: default.theme, language = source.get(Keys.language) ?: default.language, + uiScale = source.get(Keys.uiScale) ?: default.uiScale, mergeTopBarWithTitleBar = source.get(Keys.mergeTopBarWithTitleBar) ?: default.mergeTopBarWithTitleBar, threadCount = source.get(Keys.threadCount) ?: default.threadCount, dynamicPartCreation = source.get(Keys.dynamicPartCreation) ?: default.dynamicPartCreation, @@ -88,6 +91,7 @@ data class AppSettingsModel( return source.apply { put(Keys.theme, focus.theme) put(Keys.language, focus.language) + putNullable(Keys.uiScale, focus.uiScale) put(Keys.mergeTopBarWithTitleBar, focus.mergeTopBarWithTitleBar) put(Keys.threadCount, focus.threadCount) put(Keys.dynamicPartCreation, focus.dynamicPartCreation) @@ -107,6 +111,16 @@ data class AppSettingsModel( } } +private val uiScaleLens: Lens + get() = Lens( + get = { + it.uiScale + }, + set = { s, f -> + s.copy(uiScale = f) + } + ) + class AppSettingsStorage( settings: DataStore, ) : @@ -114,6 +128,7 @@ class AppSettingsStorage( LanguageStorage { var theme = from(AppSettingsModel.theme) override val selectedLanguage = from(AppSettingsModel.language) + var uiScale = from(uiScaleLens) var mergeTopBarWithTitleBar = from(AppSettingsModel.mergeTopBarWithTitleBar) val threadCount = from(AppSettingsModel.threadCount) val dynamicPartCreation = from(AppSettingsModel.dynamicPartCreation) diff --git a/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/ui/Ui.kt b/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/ui/Ui.kt index c197031..97d6b33 100644 --- a/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/ui/Ui.kt +++ b/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/ui/Ui.kt @@ -60,7 +60,7 @@ object Ui : KoinComponent { ProvideNotificationManager { ABDownloaderTheme( myColors = theme, -// uiScale = appComponent.uiScale.collectAsState().value + uiScale = appComponent.uiScale.collectAsState().value ) { ProvideGlobalExceptionHandler(globalAppExceptionHandler) { val trayState = rememberTrayState() diff --git a/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/ui/customwindow/CustomWindow.kt b/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/ui/customwindow/CustomWindow.kt index 18a87b0..8c70409 100644 --- a/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/ui/customwindow/CustomWindow.kt +++ b/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/ui/customwindow/CustomWindow.kt @@ -5,7 +5,7 @@ import com.abdownloadmanager.utils.compose.WithContentAlpha import com.abdownloadmanager.utils.compose.WithContentColor import ir.amirab.util.compose.IconSource import com.abdownloadmanager.desktop.ui.icon.MyIcons -//import com.abdownloadmanager.desktop.ui.theme.LocalUiScale +import com.abdownloadmanager.desktop.ui.theme.LocalUiScale import com.abdownloadmanager.desktop.ui.theme.myColors import com.abdownloadmanager.desktop.ui.theme.myTextSizes import com.abdownloadmanager.desktop.utils.* @@ -25,9 +25,11 @@ import androidx.compose.ui.graphics.RectangleShape import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.graphics.takeOrElse import androidx.compose.ui.input.key.KeyEvent +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.platform.LocalWindowInfo import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.dp import androidx.compose.ui.window.FrameWindowScope import androidx.compose.ui.window.Window @@ -323,52 +325,63 @@ fun CustomWindow( else Color.Black }.toWindowColorType() } - CompositionLocalProvider( - LocalWindowController provides windowController, - LocalWindowState provides state, - LocalWindow provides window, - ) { - if (preventMinimize) { - PreventMinimize() - } - // a window frame which totally rendered with compose - CustomWindowFrame( - onRequestMinimize = onRequestMinimize, - onRequestClose = onCloseRequest, - onRequestToggleMaximize = onRequestToggleMaximize, - title = title, - titlePosition = titlePosition, - windowIcon = icon, - background = background, - onBackground = myColors.onBackground, - start = start, - end = end, + UiScaledContent { + CompositionLocalProvider( + LocalWindowController provides windowController, + LocalWindowState provides state, + LocalWindow provides window, ) { -// val defaultDensity = LocalDensity.current -// val uiScale = LocalUiScale.current -// val density = remember(uiScale) { -// if (uiScale == null) { -// defaultDensity -// } else { -// Density(uiScale) -// } -// } -// CompositionLocalProvider( -// LocalDensity provides density -// ) { - ResponsiveBox { - Box(Modifier.clearFocusOnTap()) { - PopUpContainer { - content() + if (preventMinimize) { + PreventMinimize() + } + // a window frame which totally rendered with compose + CustomWindowFrame( + onRequestMinimize = onRequestMinimize, + onRequestClose = onCloseRequest, + onRequestToggleMaximize = onRequestToggleMaximize, + title = title, + titlePosition = titlePosition, + windowIcon = icon, + background = background, + onBackground = myColors.onBackground, + start = start, + end = end, + ) { + ResponsiveBox { + Box(Modifier.clearFocusOnTap()) { + PopUpContainer { + content() + } } } } -// } } } } } +/** + * put this in every window because [Window] composable override [LocalDensity] + */ +@Composable +fun UiScaledContent( + defaultDensity: Density = LocalDensity.current, + uiScale: Float? = LocalUiScale.current, + content: @Composable () -> Unit, +) { + val density = remember(uiScale) { + if (uiScale == null) { + defaultDensity + } else { + Density(uiScale) + } + } + CompositionLocalProvider( + LocalDensity provides density, + content, + ) +} + @Composable private fun PreventMinimize() { val state = LocalWindowState.current diff --git a/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/ui/customwindow/OptionsDialog.kt b/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/ui/customwindow/OptionsDialog.kt index 17bb92c..91b9914 100644 --- a/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/ui/customwindow/OptionsDialog.kt +++ b/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/ui/customwindow/OptionsDialog.kt @@ -10,7 +10,7 @@ import java.awt.event.WindowFocusListener fun BaseOptionDialog( onCloseRequest: () -> Unit, state: DialogState = rememberDialogState(), - resizeable:Boolean=true, + resizeable: Boolean = true, content: @Composable WindowScope.() -> Unit, ) { DialogWindow( @@ -21,7 +21,7 @@ fun BaseOptionDialog( resizable = resizeable, onCloseRequest = onCloseRequest, ) { - val focusListener=remember { + val focusListener = remember { object : WindowFocusListener { override fun windowGainedFocus(e: WindowEvent?) { //do nothing @@ -32,16 +32,18 @@ fun BaseOptionDialog( } } } - DisposableEffect(window){ + DisposableEffect(window) { window.addWindowFocusListener(focusListener); - window.isAlwaysOnTop=true + window.isAlwaysOnTop = true //we need this to allow click outside - window.modalityType=java.awt.Dialog.ModalityType.MODELESS - onDispose{ + window.modalityType = java.awt.Dialog.ModalityType.MODELESS + onDispose { window.removeWindowFocusListener(focusListener) } } // window.subtractInset() - content() + UiScaledContent { + content() + } } } \ No newline at end of file diff --git a/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/ui/theme/ABDownloaderTheme.kt b/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/ui/theme/ABDownloaderTheme.kt index 564f927..43ab5fa 100644 --- a/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/ui/theme/ABDownloaderTheme.kt +++ b/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/ui/theme/ABDownloaderTheme.kt @@ -12,12 +12,15 @@ import androidx.compose.foundation.* import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.runtime.* import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.TextUnit import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.compose.ui.window.Popup import androidx.compose.ui.window.PopupProperties import androidx.compose.ui.window.rememberPopupPositionProviderAtPosition +import com.abdownloadmanager.desktop.ui.customwindow.UiScaledContent import ir.amirab.util.compose.asStringSource /* @@ -101,12 +104,14 @@ private val textSizes = TextSizes( @Composable fun ABDownloaderTheme( myColors: MyColors, -// uiScale: Float? = null, + uiScale: Float? = null, content: @Composable () -> Unit, ) { + val systemDensity = LocalDensity.current CompositionLocalProvider( LocalMyColors provides AnimatedColors(myColors, tween(500)), -// LocalUiScale provides uiScale, + LocalUiScale provides uiScale, + LocalSystemDensity provides systemDensity, ) { CompositionLocalProvider( LocalContextMenuRepresentation provides myContextMenuRepresentation(), @@ -120,7 +125,11 @@ fun ABDownloaderTheme( fontSize = textSizes.base, ), ) { - content() + // it is overridden by [Window] Composable, + // but I put this here. maybe I need this outside of window scope! + UiScaledContent { + content() + } } } } @@ -172,7 +181,7 @@ private fun myDefaultScrollBarStyle(): ScrollbarStyle { thickness = 12.dp, shape = RoundedCornerShape(4.dp), hoverDurationMillis = 300, - unhoverColor = myColors.onBackground/10, - hoverColor = myColors.onBackground/30 + unhoverColor = myColors.onBackground / 10, + hoverColor = myColors.onBackground / 30 ) } diff --git a/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/ui/theme/Sizing.kt b/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/ui/theme/Sizing.kt index 5e7ccc0..3cbb726 100644 --- a/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/ui/theme/Sizing.kt +++ b/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/ui/theme/Sizing.kt @@ -4,9 +4,11 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.Stable import androidx.compose.runtime.compositionLocalOf import androidx.compose.runtime.staticCompositionLocalOf +import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.TextUnit -//val LocalUiScale = staticCompositionLocalOf { null as Float? } +val LocalSystemDensity = staticCompositionLocalOf { null } +val LocalUiScale = staticCompositionLocalOf { null } val LocalTextSizes = compositionLocalOf { error("LocalTextSizes not provided") diff --git a/desktop/custom-window-frame/build.gradle.kts b/desktop/custom-window-frame/build.gradle.kts index d689d75..a47852e 100644 --- a/desktop/custom-window-frame/build.gradle.kts +++ b/desktop/custom-window-frame/build.gradle.kts @@ -1,4 +1,7 @@ plugins{ id(MyPlugins.kotlin) id(MyPlugins.composeDesktop) +} +dependencies { + implementation(project(":desktop:shared")) } \ No newline at end of file diff --git a/desktop/custom-window-frame/src/main/kotlin/ir/amirab/util/customwindow/ToolbarItem.kt b/desktop/custom-window-frame/src/main/kotlin/ir/amirab/util/customwindow/ToolbarItem.kt index 6c096e1..a037855 100644 --- a/desktop/custom-window-frame/src/main/kotlin/ir/amirab/util/customwindow/ToolbarItem.kt +++ b/desktop/custom-window-frame/src/main/kotlin/ir/amirab/util/customwindow/ToolbarItem.kt @@ -1,4 +1,5 @@ package ir.amirab.util.customwindow + import androidx.compose.foundation.layout.Box import androidx.compose.runtime.* import androidx.compose.ui.Modifier @@ -6,16 +7,17 @@ import androidx.compose.ui.composed import androidx.compose.ui.geometry.Offset import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.layout.positionInWindow -import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalWindowInfo import androidx.compose.ui.unit.* import androidx.compose.ui.window.FrameWindowScope import ir.amirab.util.customwindow.util.CustomWindowDecorationAccessing +import ir.amirab.util.desktop.GlobalDensity import java.awt.Rectangle import java.awt.Shape import java.awt.Window import java.awt.event.ComponentAdapter import java.awt.event.ComponentEvent +import kotlin.math.roundToInt object HitSpots { const val NO_HIT_SPOT = 0 @@ -56,7 +58,9 @@ context (FrameWindowScope) private fun Modifier.onPositionInRect( onChange: (Rectangle) -> Unit, ) = composed { - val density = LocalDensity.current + // we use Global for sake of awt here. + // because we want to calculate height and pass it to awt + val density = GlobalDensity onGloballyPositioned { onChange( it.positionInWindow().toDpRectangle( @@ -114,8 +118,10 @@ context (FrameWindowScope) fun ProvideWindowSpotContainer( content: @Composable () -> Unit, ) { - val density = LocalDensity.current - val windowSize =getCurrentWindowSize() + // we use Global for sake of awt here. + // because we want to calculate height and pass it to awt + val density = GlobalDensity + val windowSize = getCurrentWindowSize() val containerSize = with(density) { LocalWindowInfo.current.containerSize.let { DpSize(it.width.toDp(), it.height.toDp()) @@ -142,10 +148,15 @@ fun ProvideWindowSpotContainer( // if (CustomWindowDecorationAccessing.isSupported) { val startOffset = (windowSize - containerSize) / 2 - val startWidthOffsetInDp = startOffset.width.value.toInt() -// val startHeightInDp=delta.height.value.toInt() //it seems no need here + val startWidthOffsetInDp = startOffset.width.value.roundToInt() +// val startHeightOffsetInDp = startOffset.width.value.roundToInt() //it seems no need here val spots: Map = spotsWithInfo.values.associate { (rect, spot) -> - Rectangle(rect.x + startWidthOffsetInDp, rect.y, rect.width, rect.height) to spot + Rectangle( + rect.x + startWidthOffsetInDp, + rect.y /*+ startHeightOffsetInDp*/, + rect.width, + rect.height + ) to spot } placeHitSpots(window, spots, toolbarHeight) } diff --git a/desktop/shared/src/main/kotlin/ir/amirab/util/desktop/screen/DesktopScreen.kt b/desktop/shared/src/main/kotlin/ir/amirab/util/desktop/screen/DesktopScreen.kt new file mode 100644 index 0000000..71020ee --- /dev/null +++ b/desktop/shared/src/main/kotlin/ir/amirab/util/desktop/screen/DesktopScreen.kt @@ -0,0 +1,97 @@ +package ir.amirab.util.desktop.screen + +import androidx.compose.ui.unit.* +//import androidx.compose.ui.window.WindowPlacement +//import androidx.compose.ui.window.WindowPosition +//import androidx.compose.ui.window.WindowState +import ir.amirab.util.desktop.GlobalDensity +import java.awt.GraphicsEnvironment + +fun getGlobalScale(): Float { + val graphicsEnvironment = GraphicsEnvironment.getLocalGraphicsEnvironment() + val defaultScreenDevice = graphicsEnvironment.defaultScreenDevice + val defaultTransform = defaultScreenDevice.defaultConfiguration.defaultTransform + return defaultTransform.scaleX.toFloat() // Assuming uniform scaling +} + +fun Int.applyUiScale( + userUiScale: Float?, + systemUiScale: Float = GlobalDensity.density, +): Int { + if (userUiScale == null) return this + return (this * userUiScale / systemUiScale).toInt() +} + +fun Int.unApplyUiScale( + userUiScale: Float?, + systemUiScale: Float = GlobalDensity.density, +): Int { + if (userUiScale == null) return this + return (this * systemUiScale / userUiScale).toInt() +} + +fun DpSize.applyUiScale( + userUiScale: Float?, + systemUiScale: Float = GlobalDensity.density, +): DpSize { + if (userUiScale == null) return this + if (this == DpSize.Unspecified) return this + return DpSize( + width = width.let { + if (isSpecified) it.value.toInt().applyUiScale(userUiScale, systemUiScale).dp + else it + }, + height = height.let { + if (isSpecified) it.value.toInt().applyUiScale(userUiScale, systemUiScale).dp + else it + }, + ) +} + +fun DpSize.unApplyUiScale( + userUiScale: Float?, + systemUiScale: Float = GlobalDensity.density, +): DpSize { + if (userUiScale == null) return this + if (this == DpSize.Unspecified) return this + return DpSize( + width = width.let { + if (isSpecified) it.value.toInt().unApplyUiScale(userUiScale, systemUiScale).dp + else it + }, + height = height.let { + if (isSpecified) it.value.toInt().applyUiScale(userUiScale, systemUiScale).dp + else it + }, + ) +} + +/* +class WindowStateUiScaleAware( + private val delegate: WindowState, + private val uiScale: Float?, +) : WindowState { + override var isMinimized: Boolean + get() = delegate.isMinimized + set(value) { + delegate.isMinimized = value + } + override var placement: WindowPlacement + get() = delegate.placement + set(value) { + delegate.placement = value + } + override var position: WindowPosition + get() = delegate.position + set(value) { + delegate.position = value + } + override var size: DpSize + get() = run { + val s = delegate.size + s.applyUiScale(uiScale) + } + set(value) { + delegate.size = value.unApplyUiScale(uiScale) + } +}*/ diff --git a/shared/config/src/main/kotlin/ir/amirab/util/config/extensions.kt b/shared/config/src/main/kotlin/ir/amirab/util/config/extensions.kt index 508e283..37b771f 100644 --- a/shared/config/src/main/kotlin/ir/amirab/util/config/extensions.kt +++ b/shared/config/src/main/kotlin/ir/amirab/util/config/extensions.kt @@ -5,27 +5,27 @@ import kotlinx.serialization.serializer context(Json) -inline fun MapConfig.putEncoded(key:String, value:T){ - putString(key,encodeToString(serializer(),value)) +inline fun MapConfig.putEncoded(key: String, value: T) { + putString(key, encodeToString(serializer(), value)) } context(Json) -inline fun MapConfig.putEncodedNullable(key: ConfigKey.OfNotPrimitiveType, value:T?){ - if (value != null){ - putString(key.keyName,encodeToString(serializer(),value)) - }else{ +inline fun MapConfig.putEncodedNullable(key: ConfigKey.OfNotPrimitiveType, value: T?) { + if (value != null) { + putString(key.keyName, encodeToString(serializer(), value)) + } else { removeKey(key) } } context(Json) -inline fun MapConfig.putEncoded(key: ConfigKey.OfNotPrimitiveType, value: T){ - putEncoded(key.keyName,value) +inline fun MapConfig.putEncoded(key: ConfigKey.OfNotPrimitiveType, value: T) { + putEncoded(key.keyName, value) } context(Json) -inline fun MapConfig.getDecoded(key:String):T?{ - val str=getString(key)?:return null +inline fun MapConfig.getDecoded(key: String): T? { + val str = getString(key) ?: return null return runCatching { decodeFromString(str) } @@ -34,7 +34,16 @@ inline fun MapConfig.getDecoded(key:String):T?{ } .getOrNull() } + context(Json) -inline fun MapConfig.getDecoded(key: ConfigKey.OfNotPrimitiveType):T?{ +inline fun MapConfig.getDecoded(key: ConfigKey.OfNotPrimitiveType): T? { return getDecoded(key.keyName) +} + +inline fun MapConfig.putNullable(key: ConfigKey.OfPrimitiveType, value: T?) { + if (value == null) { + removeKey(key) + } else { + put(key, value) + } } \ No newline at end of file diff --git a/shared/resources/src/main/resources/com/abdownloadmanager/resources/locales/en_US.properties b/shared/resources/src/main/resources/com/abdownloadmanager/resources/locales/en_US.properties index 2fc3782..4280059 100644 --- a/shared/resources/src/main/resources/com/abdownloadmanager/resources/locales/en_US.properties +++ b/shared/resources/src/main/resources/com/abdownloadmanager/resources/locales/en_US.properties @@ -56,6 +56,7 @@ file=File tasks=Tasks tools=Tools help=Help +system=System all_finished=All Finished all_unfinished=All Unfinished entire_list=Entire List @@ -194,6 +195,8 @@ settings_use_proxy_describe_system_proxy=System Proxy will be used settings_use_proxy_describe_manual_proxy="{{value}}" will be used settings_theme=Theme settings_theme_description=Select a theme for the App +settings_ui_scale=UI Scale +settings_ui_scale_description=Adjust the scale of the user interface to make elements larger or smaller settings_language=Language settings_compact_top_bar=Compact Top Bar settings_compact_top_bar_description=Merge top bar with title bar when the main window has enough width