Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,21 @@ class ActivePromptManager private constructor(context: Context) {
}
}

suspend fun applyVisualThemeToAllCharacterCards(values: ThemePreferenceValues) {
themeOperations.runTransition {
val characterCardIds = characterCardManager.getAllCharacterCards()
.map { it.id }
.toMutableList()
if (characterCardIds.none { it == CharacterCardManager.DEFAULT_CHARACTER_CARD_ID }) {
characterCardIds.add(0, CharacterCardManager.DEFAULT_CHARACTER_CARD_ID)
}
userPreferencesManager.applyVisualThemeToCharacterCards(
values = values,
characterCardIds = characterCardIds,
)
}
}

suspend fun saveAiAvatarForPrompt(target: ActivePrompt, avatarUri: String?) {
themeOperations.runTransition {
when (target) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1180,6 +1180,28 @@ class UserPreferencesManager private constructor(private val context: Context) {
)
}

/**
* Overwrite the visual theme of every listed character card.
* Background, fonts, and user avatars are part of that visual set and
* are copied with it. Character-card identity keys stay on each card.
*/
suspend fun applyVisualThemeToCharacterCards(
values: ThemePreferenceValues,
characterCardIds: Collection<String>,
) {
val targetIds = characterCardIds.map { it.trim() }.filter { it.isNotEmpty() }.distinct()
if (targetIds.isEmpty()) return
context.userPreferencesDataStore.edit { preferences ->
targetIds.forEach { characterCardId ->
writeVisualThemeValues(
preferences,
getCharacterCardThemePrefix(characterCardId),
values,
)
}
}
}

suspend fun deleteCharacterCardTheme(characterCardId: String) {
deleteThemeByPrefix(getCharacterCardThemePrefix(characterCardId))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ internal fun ThemeSettingsContentEditor(
var pendingAction by remember { mutableStateOf<ThemeEditorPendingAction?>(null) }
var exitContinuation by remember { mutableStateOf<CancellableContinuation<Boolean>?>(null) }
var isSaving by remember { mutableStateOf(false) }
var showApplyToAllConfirm by remember { mutableStateOf(false) }
var targetSwitchesInFlight by remember { mutableStateOf(0) }
val scrollState = androidx.compose.foundation.rememberScrollState()

Expand Down Expand Up @@ -310,6 +311,48 @@ internal fun ThemeSettingsContentEditor(
}
}

fun applyCurrentThemeToAllCharacterCards() {
val state = editorState ?: return
if (state.target !is ActivePrompt.CharacterCard) return
val draft = state.session
if (isSaving || pendingAction != null) return
val savedValues = draft.currentValues
val resetRequested = draft.isResetRequested
isSaving = true
showApplyToAllConfirm = false
draft.beginSave(savedValues)
scope.launch {
try {
if (resetRequested) {
activePromptManager.resetThemeDraft(state.target, savedValues)
} else {
activePromptManager.commitThemeDraft(state.target, savedValues)
}
activePromptManager.applyVisualThemeToAllCharacterCards(savedValues)
draft.markSaved(savedValues)
showSaveSuccessMessage = true
Toast.makeText(
context,
context.getString(R.string.theme_applied_to_all_character_cards),
Toast.LENGTH_SHORT,
).show()
} catch (e: CancellationException) {
draft.cancelSave()
throw e
} catch (e: Exception) {
draft.cancelSave()
AppLogger.e("ThemeSettings", "Failed to apply theme to all character cards", e)
Toast.makeText(
context,
context.getString(R.string.theme_apply_to_all_character_cards_failed),
Toast.LENGTH_LONG,
).show()
} finally {
isSaving = false
}
}
}

RegisterRouteBackGuard {
if (pendingAction != null) {
return@RegisterRouteBackGuard false
Expand Down Expand Up @@ -417,15 +460,46 @@ internal fun ThemeSettingsContentEditor(
onShowSaveSuccessMessageChange = { showSaveSuccessMessage = it },
saveEnabled = hasUnsavedChanges && !isSaving,
isSaving = isSaving,
showApplyToAll = editorTarget is ActivePrompt.CharacterCard,
applyToAllEnabled = editorState != null && !isSaving && pendingAction == null,
onSave = ::saveCurrentDraft,
onReset = draft::reset,
onApplyToAllCharacterCards = { showApplyToAllConfirm = true },
)
},
)
}
}
}

if (showApplyToAllConfirm) {
AlertDialog(
onDismissRequest = {
if (!isSaving) {
showApplyToAllConfirm = false
}
},
title = { Text(stringResource(R.string.theme_apply_to_all_character_cards_title)) },
text = { Text(stringResource(R.string.theme_apply_to_all_character_cards_message)) },
confirmButton = {
TextButton(
onClick = ::applyCurrentThemeToAllCharacterCards,
enabled = !isSaving,
) {
Text(stringResource(R.string.theme_apply_to_all_character_cards_confirm))
}
},
dismissButton = {
TextButton(
onClick = { showApplyToAllConfirm = false },
enabled = !isSaving,
) {
Text(stringResource(R.string.cancel_action))
}
},
)
}

if (pendingAction != null) {
AlertDialog(
onDismissRequest = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,11 @@ internal fun ThemeSettingsFooter(
onShowSaveSuccessMessageChange: (Boolean) -> Unit,
saveEnabled: Boolean,
isSaving: Boolean,
showApplyToAll: Boolean,
applyToAllEnabled: Boolean,
onSave: () -> Unit,
onReset: () -> Unit,
onApplyToAllCharacterCards: () -> Unit,
) {
Button(
onClick = onSave,
Expand All @@ -131,6 +134,16 @@ internal fun ThemeSettingsFooter(
Text(stringResource(id = R.string.save_action))
}

if (showApplyToAll) {
OutlinedButton(
onClick = onApplyToAllCharacterCards,
enabled = applyToAllEnabled,
modifier = Modifier.fillMaxWidth().padding(top = 8.dp),
) {
Text(stringResource(id = R.string.theme_apply_to_all_character_cards))
}
}

OutlinedButton(
onClick = onReset,
enabled = !isSaving,
Expand Down
6 changes: 6 additions & 0 deletions app/src/main/res/values-en/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -839,6 +839,12 @@
<string name="theme_select_image">Select Image</string>
<string name="theme_bg_opacity">Background opacity: %1$d%%</string>
<string name="theme_reset">Reset to Default Theme</string>
<string name="theme_apply_to_all_character_cards">Apply to all character cards</string>
<string name="theme_apply_to_all_character_cards_title">Apply to all character cards?</string>
<string name="theme_apply_to_all_character_cards_message">The current theme will overwrite every character card and cannot be undone. Continue?</string>
<string name="theme_apply_to_all_character_cards_confirm">Continue</string>
<string name="theme_applied_to_all_character_cards">Applied to all character cards</string>
<string name="theme_apply_to_all_character_cards_failed">Failed to apply theme to all character cards</string>
<string name="theme_saved">Settings saved</string>
<string name="theme_select_target">Select theme target</string>
<string name="theme_unsaved_title">Save theme changes?</string>
Expand Down
6 changes: 6 additions & 0 deletions app/src/main/res/values-es/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,12 @@
<string name="theme_select_image">Seleccionar imagen</string>
<string name="theme_bg_opacity">Opacidad del fondo: %1$d%%</string>
<string name="theme_reset">Restablecer al tema predeterminado</string>
<string name="theme_apply_to_all_character_cards">Aplicar a todas las tarjetas de personaje</string>
<string name="theme_apply_to_all_character_cards_title">¿Aplicar a todas las tarjetas de personaje?</string>
<string name="theme_apply_to_all_character_cards_message">La opción actual sobrescribirá todas las tarjetas de personaje y no se puede deshacer. ¿Continuar?</string>
<string name="theme_apply_to_all_character_cards_confirm">Continuar</string>
<string name="theme_applied_to_all_character_cards">Aplicado a todas las tarjetas de personaje</string>
<string name="theme_apply_to_all_character_cards_failed">Error al aplicar el tema a todas las tarjetas de personaje</string>
<string name="theme_saved">Configuración guardada</string>
<string name="theme_video_too_large">El archivo de video es demasiado grande, lo que puede causar que la aplicación se retrase o se bloquee. Por favor, seleccione un video de menos de 30MB.</string>
<string name="theme_video_saved">Video de fondo guardado</string>
Expand Down
6 changes: 6 additions & 0 deletions app/src/main/res/values-id/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,12 @@
<string name="theme_select_image">Pilih Gambar</string>
<string name="theme_bg_opacity">Opasitas Latar Belakang: %1$d%%</string>
<string name="theme_reset">Reset ke Tema Bawaan</string>
<string name="theme_apply_to_all_character_cards">Terapkan ke semua kartu karakter</string>
<string name="theme_apply_to_all_character_cards_title">Terapkan ke semua kartu karakter?</string>
<string name="theme_apply_to_all_character_cards_message">Pilihan saat ini akan menimpa semua kartu karakter dan tidak dapat dibatalkan. Lanjutkan?</string>
<string name="theme_apply_to_all_character_cards_confirm">Lanjutkan</string>
<string name="theme_applied_to_all_character_cards">Diterapkan ke semua kartu karakter</string>
<string name="theme_apply_to_all_character_cards_failed">Gagal menerapkan tema ke semua kartu karakter</string>
<string name="theme_saved">Pengaturan telah disimpan</string>
<string name="theme_video_too_large">File video terlalu besar, dapat menyebabkan aplikasi lag atau crash. Pilih video kurang dari 30MB.</string>
<string name="theme_video_saved">Video latar belakang telah disimpan</string>
Expand Down
6 changes: 6 additions & 0 deletions app/src/main/res/values-ko/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -685,6 +685,12 @@
<string name="theme_select_image">이미지 선택</string>
<string name="theme_bg_opacity">배경 불투명도: %1$d%%</string>
<string name="theme_reset">기본 테마로 재설정</string>
<string name="theme_apply_to_all_character_cards">모든 캐릭터 카드에 적용</string>
<string name="theme_apply_to_all_character_cards_title">모든 캐릭터 카드에 적용할까요?</string>
<string name="theme_apply_to_all_character_cards_message">현재 옵션이 모든 캐릭터 카드를 덮어쓰며 되돌릴 수 없습니다. 계속할까요?</string>
<string name="theme_apply_to_all_character_cards_confirm">계속</string>
<string name="theme_applied_to_all_character_cards">모든 캐릭터 카드에 적용되었습니다</string>
<string name="theme_apply_to_all_character_cards_failed">모든 캐릭터 카드에 테마를 적용하지 못했습니다</string>
<string name="theme_saved">설정이 저장되었습니다.</string>
<string name="theme_video_too_large">동영상 파일이 너무 커서 지연이나 충돌이 발생할 수 있습니다. 30MB 미만의 동영상을 선택하세요.</string>
<string name="theme_video_saved">배경 동영상이 저장되었습니다.</string>
Expand Down
6 changes: 6 additions & 0 deletions app/src/main/res/values-ms/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,12 @@
<string name="theme_select_image">Pilih Gambar</string>
<string name="theme_bg_opacity">Kelegapan latar belakang: %1$d%%</string>
<string name="theme_reset">Tetapkan Semula ke Tema Lalai</string>
<string name="theme_apply_to_all_character_cards">Gunakan pada semua kad watak</string>
<string name="theme_apply_to_all_character_cards_title">Gunakan pada semua kad watak?</string>
<string name="theme_apply_to_all_character_cards_message">Pilihan semasa akan menimpa semua kad watak dan tidak boleh dibuat asal. Teruskan?</string>
<string name="theme_apply_to_all_character_cards_confirm">Teruskan</string>
<string name="theme_applied_to_all_character_cards">Telah digunakan pada semua kad watak</string>
<string name="theme_apply_to_all_character_cards_failed">Gagal menggunakan tema pada semua kad watak</string>
<string name="theme_saved">Tetapan telah disimpan</string>
<string name="theme_video_too_large">Fail video terlalu besar, mungkin menyebabkan aplikasi tersekat atau terhenti. Sila pilih video kurang daripada 30MB.</string>
<string name="theme_video_saved">Video latar belakang telah disimpan</string>
Expand Down
6 changes: 6 additions & 0 deletions app/src/main/res/values-pt-rBR/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -675,6 +675,12 @@
<string name="theme_select_image">Selecione a imagem</string>
<string name="theme_bg_opacity">Opacidade do plano de fundo: %1$d%%</string>
<string name="theme_reset">Redefinir para o tema padrão</string>
<string name="theme_apply_to_all_character_cards">Aplicar a todos os cartões de personagem</string>
<string name="theme_apply_to_all_character_cards_title">Aplicar a todos os cartões de personagem?</string>
<string name="theme_apply_to_all_character_cards_message">A opção atual substituirá todos os cartões de personagem e não poderá ser desfeita. Continuar?</string>
<string name="theme_apply_to_all_character_cards_confirm">Continuar</string>
<string name="theme_applied_to_all_character_cards">Aplicado a todos os cartões de personagem</string>
<string name="theme_apply_to_all_character_cards_failed">Falha ao aplicar o tema a todos os cartões de personagem</string>
<string name="theme_saved">Configurações salvas</string>
<string name="theme_video_too_large">Arquivos de vídeo muito grandes podem fazer com que o aplicativo congele ou trave. Escolha um vídeo menor que 30 MB.</string>
<string name="theme_video_saved">Vídeo de fundo salvo</string>
Expand Down
6 changes: 6 additions & 0 deletions app/src/main/res/values-ro/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -751,6 +751,12 @@
<string name="theme_select_image">Alege o imagine</string>
<string name="theme_bg_opacity">Opacitatea fundalului: %1$d%%</string>
<string name="theme_reset">Researează la tema implicită</string>
<string name="theme_apply_to_all_character_cards">Aplică la toate cărțile de personaj</string>
<string name="theme_apply_to_all_character_cards_title">Aplici la toate cărțile de personaj?</string>
<string name="theme_apply_to_all_character_cards_message">Opțiunea curentă va suprascrie toate cărțile de personaj și nu poate fi anulată. Continui?</string>
<string name="theme_apply_to_all_character_cards_confirm">Continuă</string>
<string name="theme_applied_to_all_character_cards">Aplicat la toate cărțile de personaj</string>
<string name="theme_apply_to_all_character_cards_failed">Nu s-a putut aplica tema la toate cărțile de personaj</string>
<string name="theme_saved">Setările au fost salvate</string>
<string name="theme_video_too_large">Fișierul video este prea mare, ceea ce poate duce la încetinirea sau blocarea aplicației. Vă rugăm să alegeți un fișier mai mic de30MBvideoclipul.</string>
<string name="theme_video_saved">Videoclipul de fundal a fost salvat</string>
Expand Down
6 changes: 6 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,12 @@
<string name="theme_select_image">选择图片</string>
<string name="theme_bg_opacity">背景不透明度: %1$d%%</string>
<string name="theme_reset">重置为默认主题</string>
<string name="theme_apply_to_all_character_cards">应用到全部角色卡</string>
<string name="theme_apply_to_all_character_cards_title">应用到全部角色卡?</string>
<string name="theme_apply_to_all_character_cards_message">当前选项会覆盖所有角色卡,且不可撤销,是否继续?</string>
<string name="theme_apply_to_all_character_cards_confirm">继续</string>
<string name="theme_applied_to_all_character_cards">已应用到全部角色卡</string>
<string name="theme_apply_to_all_character_cards_failed">应用到全部角色卡失败</string>
<string name="theme_saved">设置已保存</string>
<string name="theme_select_target">选择主题对象</string>
<string name="theme_unsaved_title">保存主题修改?</string>
Expand Down