feat(chat): remove legacy bubble renderer, full-bleed is the only chat style (#881)

Deletes the ChatMessageList/ChatStreaming bubble path and the ChatStyle
setting (issue #866 phase 6). ChatScreen now renders FullBleedChatList
directly; ChatBubble becomes the user-message anchor with the shared
SystemBubble/InlineAttachment/formatTimestamp helpers intact. Stubs of
AuthManager.getChatStyle() removed from four test suites; TodoTaskCardTest
renders ToolBubble directly.

Verified: ktlintCheck green, testDebugUnitTest 962/962 pass, assembleDebug
APK builds.

Co-authored-by: M57 <hy4ri@users.noreply.github.com>
This commit is contained in:
M57andM57 authored and GitHub committed 2026-08-12 11:02:33 +03:00
1 parent a59c8c6a4f
commit 345d2e4e89
20 files changed
+154 -737

No files matched your search

@@ -163,8 +163,6 @@ internal fun SettingsChatPage(
onTypingEffectEnabledChange = viewModel::onTypingEffectEnabledChange,
typingEffectDelayMs = state.typingEffectDelayMs,
onTypingEffectDelayMsChange = viewModel::onTypingEffectDelayMsChange,
chatStyle = state.chatStyle,
onChatStyleChange = viewModel::onChatStyleChange,
)
}
}
@@ -11,7 +11,6 @@ import com.m57.hermescontrol.data.remote.NetworkResult
import com.m57.hermescontrol.data.remote.ServerEndpoint
import com.m57.hermescontrol.data.remote.safeApiCall
import com.m57.hermescontrol.data.ws.HermesWsClient
import com.m57.hermescontrol.theme.ChatStyle
import com.m57.hermescontrol.theme.ThemePreference
import com.m57.hermescontrol.theme.ThemePreset
import kotlinx.coroutines.CoroutineDispatcher
@@ -36,7 +35,6 @@ data class SettingsUiState(
val isSaved: Boolean = false,
val typingEffectEnabled: Boolean = false,
val typingEffectDelayMs: Int = 30,
val chatStyle: ChatStyle = ChatStyle.FULL_BLEED,
val profiles: List<ConnectionProfile> = emptyList(),
val selectedProfileId: String? = null,
val renameProfileName: String = "",
@@ -77,7 +75,6 @@ class SettingsViewModel(
val themePreset = AuthManager.getThemePreset()
val typingEffectEnabled = AuthManager.isTypingEffectEnabled()
val typingEffectDelayMs = AuthManager.getTypingEffectDelayMs()
val chatStyle = AuthManager.getChatStyle()
val profiles = AuthManager.getConnectionProfiles()
val appLanguage = AuthManager.getAppLanguage()
val renameProfileName =
@@ -97,7 +94,6 @@ class SettingsViewModel(
themePreset = themePreset,
typingEffectEnabled = typingEffectEnabled,
typingEffectDelayMs = typingEffectDelayMs,
chatStyle = chatStyle,
profiles = profiles,
selectedProfileId = selectedId,
renameProfileName = renameProfileName,
@@ -298,11 +294,6 @@ class SettingsViewModel(
AuthManager.setTypingEffectDelayMs(delayMs)
}
fun onChatStyleChange(style: ChatStyle) {
_uiState.update { it.copy(chatStyle = style, isSaved = false) }
AuthManager.setChatStyle(style)
}
/** Clear all auth credentials — logs out and returns to landing screen. */
fun logout() {
AuthManager.setToken(null)
@@ -329,7 +320,6 @@ class SettingsViewModel(
AuthManager.setThemePreset(state.themePreset)
AuthManager.setTypingEffectEnabled(state.typingEffectEnabled)
AuthManager.setTypingEffectDelayMs(state.typingEffectDelayMs)
AuthManager.setChatStyle(state.chatStyle)
ApiClient.rebuild()
viewModelScope.launch(ioDispatcher) {
@@ -32,7 +32,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.m57.hermescontrol.R
import com.m57.hermescontrol.theme.ChatStyle
import com.m57.hermescontrol.theme.ThemePreference
import com.m57.hermescontrol.theme.ThemePreset
import com.m57.hermescontrol.ui.settings.SectionCard
@@ -235,46 +234,8 @@ internal fun ChatSection(
onTypingEffectEnabledChange: (Boolean) -> Unit,
typingEffectDelayMs: Int,
onTypingEffectDelayMsChange: (Int) -> Unit,
chatStyle: ChatStyle,
onChatStyleChange: (ChatStyle) -> Unit,
) {
SectionCard {
// Chat rendering style (issue #866): bubble renderer (default) or the
// parallel full-bleed renderer. Kept at the top of the section — it's
// the primary chat-behavior choice.
Text(
text = stringResource(R.string.settings_item_chat_style),
style = MaterialTheme.typography.bodyLarge,
)
Text(
text = stringResource(R.string.settings_desc_chat_style),
style =
MaterialTheme.typography.bodySmall.copy(
color = MaterialTheme.colorScheme.onSurfaceVariant,
),
)
Spacer(modifier = Modifier.height(8.dp))
SingleChoiceSegmentedButtonRow(modifier = Modifier.fillMaxWidth()) {
ChatStyle.entries.forEachIndexed { index, style ->
SegmentedButton(
selected = chatStyle == style,
onClick = { onChatStyleChange(style) },
shape =
SegmentedButtonDefaults.itemShape(
index = index,
count = ChatStyle.entries.size,
),
) {
Text(
when (style) {
ChatStyle.BUBBLES -> stringResource(R.string.chat_style_bubbles)
ChatStyle.FULL_BLEED -> stringResource(R.string.chat_style_full_bleed)
},
)
}
}
}
Spacer(modifier = Modifier.height(16.dp))
Row(