diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt index 331171c6..d5754bef 100644 --- a/src/main/kotlin/Main.kt +++ b/src/main/kotlin/Main.kt @@ -55,6 +55,7 @@ import androidx.compose.material.icons.filled.Refresh import androidx.compose.material.icons.filled.VideoLabel import androidx.compose.material.rememberScaffoldState import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue @@ -97,6 +98,7 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.text.platform.Font import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp @@ -1162,7 +1164,7 @@ fun App() Slider(value = ui_scale, onValueChange = { ui_scale = it globalstore.updateUiScale(it) - Log.i(TAG, "density: $ui_scale") + Log.i(TAG, "updateUiScale:density: $ui_scale") }, onValueChangeFinished = { }, valueRange = 0.6f..3f, steps = 6, // todo: without setting the width explicitly, // the slider takes up the whole remaining space modifier = Modifier.width(150.dp)) @@ -1955,6 +1957,8 @@ object AboutIcon : Painter() { @Composable private fun MainAppStart() { + globalstore.setDefaultDensity(LocalDensity.current.density) + var use_custom_font_with_color_emoji = true try { @@ -2094,10 +2098,10 @@ private fun MainAppStart() singleLine = true, textStyle = TextStyle(fontSize = 18.sp), colors = TextFieldDefaults.textFieldColors(backgroundColor = Color(ChatColorsConfig.LIGHT__TEXTFIELD_BGCOLOR)), - keyboardOptions = KeyboardOptions(capitalization = KeyboardCapitalization.None,autoCorrect = false), + keyboardOptions = KeyboardOptions(capitalization = KeyboardCapitalization.None, autoCorrect = false), value = inputTextToxSelfName, - placeholder = { Text("") }, - onValueChange = {inputTextToxSelfName = it}) + placeholder = { Text("") }, + onValueChange = { inputTextToxSelfName = it }) if (isAskingToClose) { @@ -2150,72 +2154,82 @@ private fun MainAppStart() } catch(_: java.lang.Exception) {} + globalstore.loadUiDensity() Window(onCloseRequest = { isAskingToClose = true }, - title = "TRIfA - " + win_title_addon, - icon = appIcon, state = state, - focusable = true, - onKeyEvent = { - when (it.key) { - Key.F11 -> { - state.placement = WindowPlacement.Fullscreen - true - } - Key.Escape -> { - state.placement = WindowPlacement.Floating - true + title = "TRIfA - " + win_title_addon, + icon = appIcon, state = state, + focusable = true, + onKeyEvent = { + when (it.key) + { + Key.F11 -> + { + state.placement = WindowPlacement.Fullscreen + true + } + Key.Escape -> + { + state.placement = WindowPlacement.Floating + true + } + else -> false } - else -> false } - } - ) { - @OptIn(ExperimentalComposeUiApi::class) - window.exceptionHandler = WindowExceptionHandler { e -> println("Exception in Compose: $e") } - if (isAskingToClose) - { - Dialog( - onCloseRequest = { isAskingToClose = false }, - title = i18n("ui.close_trifa"), - ) { - Button(onClick = { - if (tox_running_state_wrapper == "running") - { - set_tox_running_state("stopping ...") - TrifaToxService.stop_me = true - runBlocking(Dispatchers.Default) { - Log.i(TAG, "waiting to shutdown ...") - while (tox_running_state_wrapper != "stopped") - { - delay(100) - Log.i(TAG, "waiting ...") + ) { + @OptIn(ExperimentalComposeUiApi::class) + window.exceptionHandler = WindowExceptionHandler { e -> println("Exception in Compose: $e") } + if (isAskingToClose) + { + Dialog( + onCloseRequest = { isAskingToClose = false }, + title = i18n("ui.close_trifa"), + ) { + Button(onClick = { + if (tox_running_state_wrapper == "running") + { + set_tox_running_state("stopping ...") + TrifaToxService.stop_me = true + runBlocking(Dispatchers.Default) { + Log.i(TAG, "waiting to shutdown ...") + while (tox_running_state_wrapper != "stopped") + { + delay(100) + Log.i(TAG, "waiting ...") + } + Log.i(TAG, "closing application") + closing_application = true + isOpen = false } + } else + { Log.i(TAG, "closing application") - closing_application = true isOpen = false + closing_application = true } - } else - { - Log.i(TAG, "closing application") - isOpen = false - closing_application = true + }) { + Text(i18n("ui.yes")) } - }) { - Text(i18n("ui.yes")) } } - } - val windowInfo = LocalWindowInfo.current - LaunchedEffect(windowInfo) { - snapshotFlow { windowInfo.isWindowFocused }.collect { onWindowFocused -> - onWindowFocused(onWindowFocused) + val windowInfo = LocalWindowInfo.current + LaunchedEffect(windowInfo) { + snapshotFlow { windowInfo.isWindowFocused }.collect { onWindowFocused -> + onWindowFocused(onWindowFocused) + } + } + LaunchedEffect(state) { + snapshotFlow { state.isMinimized }.onEach(::onWindowMinimised).launchIn(this) + snapshotFlow { state.size }.onEach(::onWindowResize).launchIn(this) + snapshotFlow { state.position }.filter { it.isSpecified }.onEach(::onWindowRelocate).launchIn(this) + } + CompositionLocalProvider( + LocalDensity provides Density(globalstore.state.ui_density) + ) + { + App() } } - LaunchedEffect(state) { - snapshotFlow { state.isMinimized }.onEach(::onWindowMinimised).launchIn(this) - snapshotFlow { state.size }.onEach(::onWindowResize).launchIn(this) - snapshotFlow { state.position }.filter { it.isSpecified }.onEach(::onWindowRelocate).launchIn(this) - } - App() - } + } // ----------- main app screen ----------- // ----------- main app screen ----------- diff --git a/src/main/kotlin/com/zoffcc/applications/trifa/savepathenabled_state.kt b/src/main/kotlin/com/zoffcc/applications/trifa/savepathenabled_state.kt index a3477c2e..7789c8e8 100644 --- a/src/main/kotlin/com/zoffcc/applications/trifa/savepathenabled_state.kt +++ b/src/main/kotlin/com/zoffcc/applications/trifa/savepathenabled_state.kt @@ -1,5 +1,6 @@ package com.zoffcc.applications.trifa +import androidx.compose.ui.platform.LocalDensity import com.zoffcc.applications.trifa.MainActivity.Companion.PREF__database_files_dir import com.zoffcc.applications.trifa.MainActivity.Companion.PREF__tox_savefile_dir import com.zoffcc.applications.trifa.TRIFAGlobals.VFS_FILE_DIR @@ -23,6 +24,8 @@ data class globalstore_state( val firstRun: Boolean = false, val startupSelfname: String = "", val ui_scale: Float = 1.0f, + val ui_density: Float = 1.0f, + val default_density: Float = 1.0f, val toxRunning: Boolean = false, val ormaRunning: Boolean = false ) @@ -35,12 +38,16 @@ interface GlobalStore { fun updateFirstRun(value: Boolean) fun updateStartupSelfname(value: String) fun updateUiScale(value: Float) + fun updateUiDensity(value: Float) + fun setDefaultDensity(value: Float) fun isMinimized(): Boolean fun isFocused(): Boolean fun isFirstRun(): Boolean fun getStartupSelfname(): String fun loadUiScale() fun getUiScale(): Float + fun loadUiDensity() + fun getUiDensity(): Float fun setToxRunning(value: Boolean) fun getToxRunning(): Boolean fun setOrmaRunning(value: Boolean) @@ -98,6 +105,25 @@ fun CoroutineScope.createGlobalStore(): GlobalStore { mutableStateFlow.value = state.copy(ui_scale = value) } + override fun setDefaultDensity(value: Float) + { + mutableStateFlow.value = state.copy(default_density = value) + } + + override fun updateUiDensity(value: Float) + { + GlobalScope.launch { + try + { + global_prefs.putFloat("main.ui_density_factor", value) + } + catch(_: Exception) + { + } + } + mutableStateFlow.value = state.copy(ui_density = value) + } + override fun isMinimized(): Boolean { return state.mainwindow_minimized @@ -147,7 +173,7 @@ fun CoroutineScope.createGlobalStore(): GlobalStore { if (tmp != null) { value = tmp.toFloat() - Log.i(TAG, "density: $value") + Log.i(TAG, "loadUiScale:density: $value") } } catch (_: Exception) { @@ -155,11 +181,42 @@ fun CoroutineScope.createGlobalStore(): GlobalStore { mutableStateFlow.value = state.copy(ui_scale = value) } + override fun loadUiDensity() + { + var value = 1.0f + try + { + value = state.default_density + Log.i(TAG, "current default density = " + value) + } + catch(_: Exception) + { + } + try + { + val tmp = global_prefs.get("main.ui_density_factor", null) + if (tmp != null) + { + value = tmp.toFloat() + Log.i(TAG, "loadUiDensity:density: $value") + } + } catch (_: Exception) + { + } + Log.i(TAG, "loading density = " + value) + mutableStateFlow.value = state.copy(ui_density = value) + } + override fun getUiScale(): Float { return state.ui_scale } + override fun getUiDensity(): Float + { + return state.ui_density + } + override fun increase_unread_message_count() { mutableStateFlow.value = state.copy(contacts_unread_message_count = (state.contacts_unread_message_count + 1)) diff --git a/src/main/kotlin/org/briarproject/briar/desktop/SettingDetails.kt b/src/main/kotlin/org/briarproject/briar/desktop/SettingDetails.kt index c2006647..e4332473 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/SettingDetails.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/SettingDetails.kt @@ -20,6 +20,7 @@ package org.briarproject.briar.desktop import SETTINGS_HEADER_SIZE import SnackBarToast +import UIScaleItem import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -38,11 +39,15 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.Button +import androidx.compose.material.Icon import androidx.compose.material.MaterialTheme +import androidx.compose.material.Slider import androidx.compose.material.Switch import androidx.compose.material.Text import androidx.compose.material.TextField import androidx.compose.material.TextFieldDefaults +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.FormatSize import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue @@ -51,8 +56,10 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.scale import androidx.compose.ui.draw.shadow import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.TextStyle @@ -67,6 +74,7 @@ import com.zoffcc.applications.trifa.HelperOSFile.show_containing_dir_in_explore import com.zoffcc.applications.trifa.HelperRelay.add_or_update_own_relay import com.zoffcc.applications.trifa.HelperRelay.get_own_relay_pubkey import com.zoffcc.applications.trifa.HelperRelay.remove_own_relay_in_db +import com.zoffcc.applications.trifa.Log import com.zoffcc.applications.trifa.MainActivity import com.zoffcc.applications.trifa.MainActivity.Companion.DB_PREF__notifications_active import com.zoffcc.applications.trifa.MainActivity.Companion.DB_PREF__open_files_directly @@ -74,6 +82,7 @@ import com.zoffcc.applications.trifa.MainActivity.Companion.DB_PREF__send_push_n import com.zoffcc.applications.trifa.MainActivity.Companion.DB_PREF__use_other_toxproxies import com.zoffcc.applications.trifa.MainActivity.Companion.tox_self_get_name import com.zoffcc.applications.trifa.MainActivity.Companion.tox_self_set_name +import com.zoffcc.applications.trifa.TAG import com.zoffcc.applications.trifa.TrifaToxService.Companion.orma import global_prefs import globalstore @@ -352,6 +361,39 @@ private fun general_settings() ) } // ---- use custom font that has color emoji AND normal text ---- + + + + + // ---- set global density to scale the whole UI ---- + var ui_density by remember { mutableStateOf(globalstore.getUiDensity()) } + DetailItem(label = "UI Scale", + description = "UI Scale") { + UIScaleItem( + label = "" + "%06.2f".format(ui_density), + description = i18n("ui.drag_slider_to_change")) { + Row(horizontalArrangement = Arrangement.spacedBy(2.dp), + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.fillMaxWidth()) { + Icon(Icons.Default.FormatSize, null, Modifier.scale(0.7f)) + Slider(value = ui_density, onValueChange = { + ui_density = it + }, onValueChangeFinished = { + globalstore.updateUiDensity(ui_density) + // TODO: set density here + Log.i(TAG, "updateUiDensity:ui_density:1: $ui_density") + }, valueRange = 0.25f..10f, steps = 64) + Icon(Icons.Default.FormatSize, null) + } + } + } + + //Row(Modifier.wrapContentHeight().fillMaxWidth().padding(start = 15.dp)) { + //} + // ---- set global density to scale the whole UI ---- + + + } @Composable diff --git a/src/main/resources/strings/trifa_material.properties b/src/main/resources/strings/trifa_material.properties index a79c1af8..cd017618 100644 --- a/src/main/resources/strings/trifa_material.properties +++ b/src/main/resources/strings/trifa_material.properties @@ -19,6 +19,7 @@ ui.about.list_general=General ui.about.list_dependencies=Dependencies ui.about.category_dependencies=Dependencies ui.return_to_previous_screen=return to previous screen +ui.ui_density=UI Density ui.ui_scale=UI Scale ui.current_value=current value ui.drag_slider_to_change=drag Slider to change