Co-authored-by: M57 <hy4ri@users.noreply.github.com>
This commit is contained in:
1 parent
db3f8c736e
commit
5bc6e5f855
14 files changed
+461
-182
No files matched your search
@@ -191,6 +191,8 @@ internal fun SettingsChatPage(
|
||||
onTypingEffectEnabledChange = viewModel::onTypingEffectEnabledChange,
|
||||
typingEffectDelayMs = state.typingEffectDelayMs,
|
||||
onTypingEffectDelayMsChange = viewModel::onTypingEffectDelayMsChange,
|
||||
chatFontScale = state.chatFontScale,
|
||||
onChatFontScaleChange = viewModel::onChatFontScaleChange,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ data class SettingsUiState(
|
||||
val isSaved: Boolean = false,
|
||||
val typingEffectEnabled: Boolean = false,
|
||||
val typingEffectDelayMs: Int = 30,
|
||||
val chatFontScale: Float = 1.0f,
|
||||
val profiles: List<ConnectionProfile> = emptyList(),
|
||||
val selectedProfileId: String? = null,
|
||||
val renameProfileName: String = "",
|
||||
@@ -76,6 +77,7 @@ class SettingsViewModel(
|
||||
val themePreset = AuthManager.getThemePreset()
|
||||
val typingEffectEnabled = AuthManager.isTypingEffectEnabled()
|
||||
val typingEffectDelayMs = AuthManager.getTypingEffectDelayMs()
|
||||
val chatFontScale = AuthManager.getChatFontScale()
|
||||
val profiles = AuthManager.getConnectionProfiles()
|
||||
val appLanguage = AuthManager.getAppLanguage()
|
||||
val renameProfileName =
|
||||
@@ -95,6 +97,7 @@ class SettingsViewModel(
|
||||
themePreset = themePreset,
|
||||
typingEffectEnabled = typingEffectEnabled,
|
||||
typingEffectDelayMs = typingEffectDelayMs,
|
||||
chatFontScale = chatFontScale,
|
||||
profiles = profiles,
|
||||
selectedProfileId = selectedId,
|
||||
renameProfileName = renameProfileName,
|
||||
@@ -310,6 +313,11 @@ class SettingsViewModel(
|
||||
AuthManager.setTypingEffectDelayMs(delayMs)
|
||||
}
|
||||
|
||||
fun onChatFontScaleChange(scale: Float) {
|
||||
_uiState.update { it.copy(chatFontScale = scale, isSaved = false) }
|
||||
AuthManager.setChatFontScale(scale)
|
||||
}
|
||||
|
||||
/** Clear all auth credentials — logs out and returns to landing screen. */
|
||||
fun logout() {
|
||||
AuthManager.setToken(null)
|
||||
|
||||
@@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
@@ -18,22 +19,29 @@ import androidx.compose.material3.SegmentedButton
|
||||
import androidx.compose.material3.SegmentedButtonDefaults
|
||||
import androidx.compose.material3.SingleChoiceSegmentedButtonRow
|
||||
import androidx.compose.material3.Slider
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Switch
|
||||
import androidx.compose.material3.SwitchDefaults
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.Density
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.m57.hermescontrol.R
|
||||
import com.m57.hermescontrol.theme.ThemePreference
|
||||
import com.m57.hermescontrol.theme.ThemePreset
|
||||
import com.m57.hermescontrol.ui.settings.SectionCard
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@Composable
|
||||
internal fun AppearanceSection(
|
||||
@@ -194,10 +202,172 @@ internal fun ChatSection(
|
||||
onTypingEffectEnabledChange: (Boolean) -> Unit,
|
||||
typingEffectDelayMs: Int,
|
||||
onTypingEffectDelayMsChange: (Int) -> Unit,
|
||||
chatFontScale: Float = 1.0f,
|
||||
onChatFontScaleChange: (Float) -> Unit = {},
|
||||
) {
|
||||
val fontScaleOptions = listOf(0.85f, 1.0f, 1.15f, 1.30f, 1.50f)
|
||||
val currentIndex =
|
||||
fontScaleOptions.indexOfFirst { abs(it - chatFontScale) < 0.05f }
|
||||
.takeIf { it >= 0 } ?: 1
|
||||
|
||||
SectionCard {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
Text(
|
||||
text = stringResource(R.string.settings_item_chat_font_size),
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
)
|
||||
Text(
|
||||
text = stringResource(R.string.settings_desc_chat_font_size),
|
||||
style =
|
||||
MaterialTheme.typography.bodySmall.copy(
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
)
|
||||
}
|
||||
val scaleLabel =
|
||||
when (currentIndex) {
|
||||
0 -> stringResource(R.string.settings_font_scale_small)
|
||||
1 -> stringResource(R.string.settings_font_scale_default)
|
||||
2 -> stringResource(R.string.settings_font_scale_large)
|
||||
3 -> stringResource(R.string.settings_font_scale_xlarge)
|
||||
else -> stringResource(R.string.settings_font_scale_huge)
|
||||
}
|
||||
Text(
|
||||
text = scaleLabel,
|
||||
style =
|
||||
MaterialTheme.typography.labelMedium.copy(
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
Slider(
|
||||
value = currentIndex.toFloat(),
|
||||
onValueChange = { onChatFontScaleChange(fontScaleOptions[it.roundToInt()]) },
|
||||
valueRange = 0f..(fontScaleOptions.size - 1).toFloat(),
|
||||
steps = fontScaleOptions.size - 2,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
) {
|
||||
Text(
|
||||
text = "0.85×",
|
||||
style =
|
||||
MaterialTheme.typography.labelSmall.copy(
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
)
|
||||
Text(
|
||||
text = "1.0×",
|
||||
style =
|
||||
MaterialTheme.typography.labelSmall.copy(
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
)
|
||||
Text(
|
||||
text = "1.5×",
|
||||
style =
|
||||
MaterialTheme.typography.labelSmall.copy(
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
Text(
|
||||
text = stringResource(R.string.settings_chat_preview_title),
|
||||
style =
|
||||
MaterialTheme.typography.labelMedium.copy(
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
val currentDensity = LocalDensity.current
|
||||
val previewDensity =
|
||||
remember(currentDensity, chatFontScale) {
|
||||
Density(
|
||||
density = currentDensity.density,
|
||||
fontScale = currentDensity.fontScale * chatFontScale,
|
||||
)
|
||||
}
|
||||
|
||||
CompositionLocalProvider(LocalDensity provides previewDensity) {
|
||||
Surface(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
shape = RoundedCornerShape(12.dp),
|
||||
color = MaterialTheme.colorScheme.surfaceContainer,
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.padding(12.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
// User bubble preview
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.End,
|
||||
) {
|
||||
Surface(
|
||||
shape =
|
||||
RoundedCornerShape(
|
||||
topStart = 14.dp,
|
||||
topEnd = 14.dp,
|
||||
bottomStart = 14.dp,
|
||||
bottomEnd = 4.dp,
|
||||
),
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.settings_chat_preview_user),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onPrimary,
|
||||
modifier = Modifier.padding(horizontal = 10.dp, vertical = 6.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Assistant bubble preview
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.Start,
|
||||
) {
|
||||
Surface(
|
||||
shape =
|
||||
RoundedCornerShape(
|
||||
topStart = 14.dp,
|
||||
topEnd = 14.dp,
|
||||
bottomStart = 4.dp,
|
||||
bottomEnd = 14.dp,
|
||||
),
|
||||
color = MaterialTheme.colorScheme.surfaceContainerHigh,
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.settings_chat_preview_agent),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
modifier = Modifier.padding(horizontal = 10.dp, vertical = 6.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
|
||||
Reference in new issue
Block a user