UI: allow hide or show model card on Conversation & Benchmark screens; fix message arrangement
This commit is contained in:
parent
43d9d300aa
commit
81ad468c78
|
|
@ -257,6 +257,7 @@ fun AppContent(
|
||||||
// Benchmark screen
|
// Benchmark screen
|
||||||
currentRoute.startsWith(AppDestinations.BENCHMARK_ROUTE) -> {
|
currentRoute.startsWith(AppDestinations.BENCHMARK_ROUTE) -> {
|
||||||
val engineState by benchmarkViewModel.engineState.collectAsState()
|
val engineState by benchmarkViewModel.engineState.collectAsState()
|
||||||
|
val showModelCard by benchmarkViewModel.showModelCard.collectAsState()
|
||||||
val benchmarkResults by benchmarkViewModel.benchmarkResults.collectAsState()
|
val benchmarkResults by benchmarkViewModel.benchmarkResults.collectAsState()
|
||||||
|
|
||||||
ScaffoldConfig(
|
ScaffoldConfig(
|
||||||
|
|
@ -285,12 +286,16 @@ fun AppContent(
|
||||||
handleScaffoldEvent(ScaffoldEvent.ShareText(it.text))
|
handleScaffoldEvent(ScaffoldEvent.ShareText(it.text))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
showModelCard = showModelCard,
|
||||||
|
onToggleModelCard = benchmarkViewModel::toggleModelCard,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Conversation screen
|
// Conversation screen
|
||||||
currentRoute.startsWith(AppDestinations.CONVERSATION_ROUTE) -> {
|
currentRoute.startsWith(AppDestinations.CONVERSATION_ROUTE) -> {
|
||||||
|
val showModelCard by conversationViewModel.showModelCard.collectAsState()
|
||||||
|
|
||||||
val modelThinkingOrSpeaking =
|
val modelThinkingOrSpeaking =
|
||||||
engineState is State.ProcessingUserPrompt || engineState is State.Generating
|
engineState is State.ProcessingUserPrompt || engineState is State.Generating
|
||||||
|
|
||||||
|
|
@ -313,6 +318,8 @@ fun AppContent(
|
||||||
isEnabled = !modelThinkingOrSpeaking,
|
isEnabled = !modelThinkingOrSpeaking,
|
||||||
textFieldState = conversationViewModel.inputFieldState,
|
textFieldState = conversationViewModel.inputFieldState,
|
||||||
onSendClick = conversationViewModel::sendMessage,
|
onSendClick = conversationViewModel::sendMessage,
|
||||||
|
showModelCard = showModelCard,
|
||||||
|
onToggleModelCard = conversationViewModel::toggleModelCard,
|
||||||
onAttachPhotoClick = showStubMessage,
|
onAttachPhotoClick = showStubMessage,
|
||||||
onAttachFileClick = showStubMessage,
|
onAttachFileClick = showStubMessage,
|
||||||
onAudioInputClick = showStubMessage,
|
onAudioInputClick = showStubMessage,
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,9 @@ fun AppScaffold(
|
||||||
BenchmarkBottomBar(
|
BenchmarkBottomBar(
|
||||||
engineIdle = config.engineIdle,
|
engineIdle = config.engineIdle,
|
||||||
onRerun = config.onRerun,
|
onRerun = config.onRerun,
|
||||||
onShare = config.onShare
|
onShare = config.onShare,
|
||||||
|
showModelCard = config.showModelCard,
|
||||||
|
onToggleModelCard = config.onToggleModelCard,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -115,6 +117,8 @@ fun AppScaffold(
|
||||||
isReady = config.isEnabled,
|
isReady = config.isEnabled,
|
||||||
textFieldState = config.textFieldState,
|
textFieldState = config.textFieldState,
|
||||||
onSendClick = config.onSendClick,
|
onSendClick = config.onSendClick,
|
||||||
|
showModelCard = config.showModelCard,
|
||||||
|
onToggleModelCard = config.onToggleModelCard,
|
||||||
onAttachPhotoClick = config.onAttachPhotoClick,
|
onAttachPhotoClick = config.onAttachPhotoClick,
|
||||||
onAttachFileClick = config.onAttachFileClick,
|
onAttachFileClick = config.onAttachFileClick,
|
||||||
onAudioInputClick = config.onAudioInputClick,
|
onAudioInputClick = config.onAudioInputClick,
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,10 @@ import androidx.compose.animation.fadeOut
|
||||||
import androidx.compose.animation.scaleIn
|
import androidx.compose.animation.scaleIn
|
||||||
import androidx.compose.animation.scaleOut
|
import androidx.compose.animation.scaleOut
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Badge
|
||||||
import androidx.compose.material.icons.filled.Replay
|
import androidx.compose.material.icons.filled.Replay
|
||||||
import androidx.compose.material.icons.filled.Share
|
import androidx.compose.material.icons.filled.Share
|
||||||
|
import androidx.compose.material.icons.outlined.Badge
|
||||||
import androidx.compose.material3.BottomAppBar
|
import androidx.compose.material3.BottomAppBar
|
||||||
import androidx.compose.material3.FloatingActionButton
|
import androidx.compose.material3.FloatingActionButton
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
|
|
@ -20,6 +22,8 @@ fun BenchmarkBottomBar(
|
||||||
engineIdle: Boolean,
|
engineIdle: Boolean,
|
||||||
onRerun: () -> Unit,
|
onRerun: () -> Unit,
|
||||||
onShare: () -> Unit,
|
onShare: () -> Unit,
|
||||||
|
showModelCard: Boolean,
|
||||||
|
onToggleModelCard: (Boolean) -> Unit,
|
||||||
) {
|
) {
|
||||||
BottomAppBar(
|
BottomAppBar(
|
||||||
actions = {
|
actions = {
|
||||||
|
|
@ -32,6 +36,13 @@ fun BenchmarkBottomBar(
|
||||||
else MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.3f)
|
else MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.3f)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IconButton(onClick = { onToggleModelCard(!showModelCard) } ) {
|
||||||
|
Icon(
|
||||||
|
imageVector = if (showModelCard) Icons.Default.Badge else Icons.Outlined.Badge,
|
||||||
|
contentDescription = "${if (showModelCard) "Hide" else "Show"} model card"
|
||||||
|
)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
floatingActionButton = {
|
floatingActionButton = {
|
||||||
// Only show FAB if the benchmark result is ready
|
// Only show FAB if the benchmark result is ready
|
||||||
|
|
|
||||||
|
|
@ -89,12 +89,16 @@ sealed class BottomBarConfig {
|
||||||
val engineIdle: Boolean,
|
val engineIdle: Boolean,
|
||||||
val onRerun: () -> Unit,
|
val onRerun: () -> Unit,
|
||||||
val onShare: () -> Unit,
|
val onShare: () -> Unit,
|
||||||
|
val showModelCard: Boolean,
|
||||||
|
val onToggleModelCard: (Boolean) -> Unit,
|
||||||
) : BottomBarConfig()
|
) : BottomBarConfig()
|
||||||
|
|
||||||
data class Conversation(
|
data class Conversation(
|
||||||
val isEnabled: Boolean,
|
val isEnabled: Boolean,
|
||||||
val textFieldState: TextFieldState,
|
val textFieldState: TextFieldState,
|
||||||
val onSendClick: () -> Unit,
|
val onSendClick: () -> Unit,
|
||||||
|
val showModelCard: Boolean,
|
||||||
|
val onToggleModelCard: (Boolean) -> Unit,
|
||||||
val onAttachPhotoClick: () -> Unit,
|
val onAttachPhotoClick: () -> Unit,
|
||||||
val onAttachFileClick: () -> Unit,
|
val onAttachFileClick: () -> Unit,
|
||||||
val onAudioInputClick: () -> Unit,
|
val onAudioInputClick: () -> Unit,
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,11 @@ import androidx.compose.foundation.text.input.TextFieldLineLimits
|
||||||
import androidx.compose.foundation.text.input.TextFieldState
|
import androidx.compose.foundation.text.input.TextFieldState
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.automirrored.filled.Send
|
import androidx.compose.material.icons.automirrored.filled.Send
|
||||||
|
import androidx.compose.material.icons.filled.Badge
|
||||||
import androidx.compose.material.icons.filled.Mic
|
import androidx.compose.material.icons.filled.Mic
|
||||||
import androidx.compose.material.icons.outlined.AddPhotoAlternate
|
import androidx.compose.material.icons.outlined.AddPhotoAlternate
|
||||||
import androidx.compose.material.icons.outlined.AttachFile
|
import androidx.compose.material.icons.outlined.AttachFile
|
||||||
|
import androidx.compose.material.icons.outlined.Badge
|
||||||
import androidx.compose.material3.BottomAppBar
|
import androidx.compose.material3.BottomAppBar
|
||||||
import androidx.compose.material3.BottomAppBarDefaults
|
import androidx.compose.material3.BottomAppBarDefaults
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
|
|
@ -37,6 +39,8 @@ fun ConversationBottomBar(
|
||||||
textFieldState: TextFieldState,
|
textFieldState: TextFieldState,
|
||||||
isReady: Boolean,
|
isReady: Boolean,
|
||||||
onSendClick: () -> Unit,
|
onSendClick: () -> Unit,
|
||||||
|
showModelCard: Boolean,
|
||||||
|
onToggleModelCard: (Boolean) -> Unit,
|
||||||
onAttachPhotoClick: () -> Unit,
|
onAttachPhotoClick: () -> Unit,
|
||||||
onAttachFileClick: () -> Unit,
|
onAttachFileClick: () -> Unit,
|
||||||
onAudioInputClick: () -> Unit,
|
onAudioInputClick: () -> Unit,
|
||||||
|
|
@ -58,7 +62,7 @@ fun ConversationBottomBar(
|
||||||
) {
|
) {
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
state = textFieldState,
|
state = textFieldState,
|
||||||
modifier = Modifier.Companion.fillMaxWidth().padding(end = 8.dp),
|
modifier = Modifier.Companion.fillMaxWidth(),
|
||||||
enabled = isReady,
|
enabled = isReady,
|
||||||
placeholder = { Text(placeholder) },
|
placeholder = { Text(placeholder) },
|
||||||
lineLimits = TextFieldLineLimits.MultiLine(maxHeightInLines = 5),
|
lineLimits = TextFieldLineLimits.MultiLine(maxHeightInLines = 5),
|
||||||
|
|
@ -102,6 +106,13 @@ fun ConversationBottomBar(
|
||||||
contentDescription = "Input with voice",
|
contentDescription = "Input with voice",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IconButton(onClick = { onToggleModelCard(!showModelCard) } ) {
|
||||||
|
Icon(
|
||||||
|
imageVector = if (showModelCard) Icons.Default.Badge else Icons.Outlined.Badge,
|
||||||
|
contentDescription = "${if (showModelCard) "Hide" else "Show"} model card"
|
||||||
|
)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
floatingActionButton = {
|
floatingActionButton = {
|
||||||
FloatingActionButton(
|
FloatingActionButton(
|
||||||
|
|
|
||||||
|
|
@ -54,10 +54,13 @@ fun BenchmarkScreen(
|
||||||
) {
|
) {
|
||||||
// View model states
|
// View model states
|
||||||
val engineState by viewModel.engineState.collectAsState()
|
val engineState by viewModel.engineState.collectAsState()
|
||||||
val benchmarkResults by viewModel.benchmarkResults.collectAsState()
|
|
||||||
val selectedModel by viewModel.selectedModel.collectAsState()
|
|
||||||
val unloadDialogState by viewModel.unloadModelState.collectAsState()
|
val unloadDialogState by viewModel.unloadModelState.collectAsState()
|
||||||
|
|
||||||
|
val showModelCard by viewModel.showModelCard.collectAsState()
|
||||||
|
val selectedModel by viewModel.selectedModel.collectAsState()
|
||||||
|
|
||||||
|
val benchmarkResults by viewModel.benchmarkResults.collectAsState()
|
||||||
|
|
||||||
// UI states
|
// UI states
|
||||||
var isModelCardExpanded by remember { mutableStateOf(false) }
|
var isModelCardExpanded by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
|
@ -71,94 +74,91 @@ fun BenchmarkScreen(
|
||||||
viewModel.onBackPressed(onNavigateBack)
|
viewModel.onBackPressed(onNavigateBack)
|
||||||
}
|
}
|
||||||
|
|
||||||
Column(
|
Box(
|
||||||
modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState())
|
modifier = Modifier.fillMaxSize()
|
||||||
) {
|
) {
|
||||||
// Selected model card
|
// Benchmark results
|
||||||
selectedModel?.let { model ->
|
LazyColumn(
|
||||||
Box(
|
modifier = Modifier.fillMaxSize(),
|
||||||
modifier = Modifier.padding(start = 16.dp, top = 16.dp, end = 16.dp)
|
contentPadding = PaddingValues(8.dp),
|
||||||
) {
|
verticalArrangement = Arrangement.Bottom,
|
||||||
ModelCardWithLoadingMetrics(
|
|
||||||
model = model,
|
|
||||||
loadingMetrics = loadingMetrics,
|
|
||||||
isExpanded = isModelCardExpanded,
|
|
||||||
onExpanded = { isModelCardExpanded = !isModelCardExpanded },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Box(
|
|
||||||
modifier = Modifier.fillMaxWidth().weight(1f),
|
|
||||||
contentAlignment = Alignment.Center
|
|
||||||
) {
|
) {
|
||||||
// Benchmark results
|
items(items = benchmarkResults) { result ->
|
||||||
LazyColumn(
|
Card(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxWidth().padding(8.dp)
|
||||||
verticalArrangement = Arrangement.spacedBy(16.dp),
|
) {
|
||||||
contentPadding = PaddingValues(horizontal = 16.dp, vertical = 16.dp),
|
Column(
|
||||||
) {
|
modifier = Modifier
|
||||||
items(items = benchmarkResults) { result ->
|
.fillMaxWidth()
|
||||||
Card(
|
.background(
|
||||||
modifier = Modifier.fillMaxWidth()
|
color = MaterialTheme.colorScheme.surfaceVariant,
|
||||||
) {
|
shape = RoundedCornerShape(8.dp)
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.background(
|
|
||||||
color = MaterialTheme.colorScheme.surfaceVariant,
|
|
||||||
shape = RoundedCornerShape(8.dp)
|
|
||||||
)
|
|
||||||
.padding(16.dp)
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = result.text,
|
|
||||||
style = MonospacedTextStyle,
|
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
|
||||||
)
|
)
|
||||||
|
.padding(16.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = result.text,
|
||||||
|
style = MonospacedTextStyle,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
|
)
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(4.dp))
|
Spacer(modifier = Modifier.height(4.dp))
|
||||||
|
|
||||||
ModelCardContentField("Time spent: ", formatMilliSeconds(result.duration))
|
ModelCardContentField("Time spent: ", formatMilliSeconds(result.duration))
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Loading indicator
|
// Loading indicator
|
||||||
if (engineState is State.Benchmarking) {
|
if (engineState is State.Benchmarking) {
|
||||||
Card(
|
Card(
|
||||||
modifier = Modifier.align(Alignment.Center),
|
modifier = Modifier.align(Alignment.Center),
|
||||||
colors = CardDefaults.cardColors(
|
colors = CardDefaults.cardColors(
|
||||||
containerColor = MaterialTheme.colorScheme.primaryContainer
|
containerColor = MaterialTheme.colorScheme.primaryContainer
|
||||||
),
|
),
|
||||||
shape = MaterialTheme.shapes.extraLarge
|
shape = MaterialTheme.shapes.extraLarge
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(horizontal = 32.dp, vertical = 48.dp),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
) {
|
) {
|
||||||
Column(
|
CircularProgressIndicator(
|
||||||
modifier = Modifier.padding(horizontal = 32.dp, vertical = 48.dp),
|
modifier = Modifier.size(64.dp),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
strokeWidth = ProgressIndicatorDefaults.CircularStrokeWidth * 1.5f
|
||||||
) {
|
)
|
||||||
CircularProgressIndicator(
|
|
||||||
modifier = Modifier.size(64.dp),
|
|
||||||
strokeWidth = ProgressIndicatorDefaults.CircularStrokeWidth * 1.5f
|
|
||||||
)
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = "Running benchmark...",
|
text = "Running benchmark...",
|
||||||
style = MaterialTheme.typography.headlineSmall
|
style = MaterialTheme.typography.headlineSmall
|
||||||
)
|
)
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = "This usually takes a few minutes",
|
text = "This usually takes a few minutes",
|
||||||
style = MaterialTheme.typography.bodyLarge,
|
style = MaterialTheme.typography.bodyLarge,
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Selected model card and loading metrics
|
||||||
|
if (showModelCard) {
|
||||||
|
selectedModel?.let { model ->
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.padding(start = 16.dp, top = 16.dp, end = 16.dp)
|
||||||
|
) {
|
||||||
|
ModelCardWithLoadingMetrics(
|
||||||
|
model = model,
|
||||||
|
loadingMetrics = loadingMetrics,
|
||||||
|
isExpanded = isModelCardExpanded,
|
||||||
|
onExpanded = { isModelCardExpanded = !isModelCardExpanded },
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import androidx.compose.animation.core.infiniteRepeatable
|
||||||
import androidx.compose.animation.core.rememberInfiniteTransition
|
import androidx.compose.animation.core.rememberInfiniteTransition
|
||||||
import androidx.compose.animation.core.tween
|
import androidx.compose.animation.core.tween
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
|
@ -26,19 +27,11 @@ import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.filled.Send
|
|
||||||
import androidx.compose.material3.Card
|
import androidx.compose.material3.Card
|
||||||
import androidx.compose.material3.CardDefaults
|
import androidx.compose.material3.CardDefaults
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
|
||||||
import androidx.compose.material3.HorizontalDivider
|
import androidx.compose.material3.HorizontalDivider
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.IconButton
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.OutlinedTextField
|
|
||||||
import androidx.compose.material3.Surface
|
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextFieldDefaults
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.DisposableEffect
|
import androidx.compose.runtime.DisposableEffect
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
|
@ -52,15 +45,12 @@ import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.graphics.StrokeCap
|
|
||||||
import androidx.compose.ui.text.font.FontStyle
|
import androidx.compose.ui.text.font.FontStyle
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.LifecycleEventObserver
|
import androidx.lifecycle.LifecycleEventObserver
|
||||||
import androidx.lifecycle.compose.LocalLifecycleOwner
|
import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||||
import com.example.llama.revamp.APP_NAME
|
|
||||||
import com.example.llama.revamp.data.model.ModelInfo
|
import com.example.llama.revamp.data.model.ModelInfo
|
||||||
import com.example.llama.revamp.engine.ModelLoadingMetrics
|
import com.example.llama.revamp.engine.ModelLoadingMetrics
|
||||||
import com.example.llama.revamp.ui.components.ModelCardContentArchitectureRow
|
import com.example.llama.revamp.ui.components.ModelCardContentArchitectureRow
|
||||||
|
|
@ -84,11 +74,14 @@ fun ConversationScreen(
|
||||||
) {
|
) {
|
||||||
// View model states
|
// View model states
|
||||||
val engineState by viewModel.engineState.collectAsState()
|
val engineState by viewModel.engineState.collectAsState()
|
||||||
val messages by viewModel.messages.collectAsState()
|
|
||||||
val systemPrompt by viewModel.systemPrompt.collectAsState()
|
|
||||||
val selectedModel by viewModel.selectedModel.collectAsState()
|
|
||||||
val unloadDialogState by viewModel.unloadModelState.collectAsState()
|
val unloadDialogState by viewModel.unloadModelState.collectAsState()
|
||||||
|
|
||||||
|
val showModelCard by viewModel.showModelCard.collectAsState()
|
||||||
|
val selectedModel by viewModel.selectedModel.collectAsState()
|
||||||
|
val systemPrompt by viewModel.systemPrompt.collectAsState()
|
||||||
|
|
||||||
|
val messages by viewModel.messages.collectAsState()
|
||||||
|
|
||||||
val isGenerating = engineState is State.Generating
|
val isGenerating = engineState is State.Generating
|
||||||
|
|
||||||
// UI states
|
// UI states
|
||||||
|
|
@ -140,17 +133,19 @@ fun ConversationScreen(
|
||||||
listState = listState,
|
listState = listState,
|
||||||
)
|
)
|
||||||
|
|
||||||
selectedModel?.let {
|
if (showModelCard) {
|
||||||
Box(
|
selectedModel?.let {
|
||||||
modifier = Modifier.fillMaxWidth().padding(16.dp).align(Alignment.TopCenter)
|
Box(
|
||||||
) {
|
modifier = Modifier.fillMaxWidth().padding(16.dp).align(Alignment.TopCenter)
|
||||||
ModelCardWithSystemPrompt(
|
) {
|
||||||
model = it,
|
ModelCardWithSystemPrompt(
|
||||||
loadingMetrics = loadingMetrics,
|
model = it,
|
||||||
systemPrompt = systemPrompt,
|
loadingMetrics = loadingMetrics,
|
||||||
isExpanded = isModelCardExpanded,
|
systemPrompt = systemPrompt,
|
||||||
onExpanded = { isModelCardExpanded = !isModelCardExpanded }
|
isExpanded = isModelCardExpanded,
|
||||||
)
|
onExpanded = { isModelCardExpanded = !isModelCardExpanded }
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -225,6 +220,7 @@ private fun ConversationMessageList(
|
||||||
state = listState,
|
state = listState,
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
contentPadding = PaddingValues(horizontal = 16.dp, vertical = 16.dp),
|
contentPadding = PaddingValues(horizontal = 16.dp, vertical = 16.dp),
|
||||||
|
verticalArrangement = Arrangement.Bottom,
|
||||||
) {
|
) {
|
||||||
items(
|
items(
|
||||||
items = messages,
|
items = messages,
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,8 @@ import javax.inject.Inject
|
||||||
class BenchmarkViewModel @Inject constructor(
|
class BenchmarkViewModel @Inject constructor(
|
||||||
private val benchmarkService: BenchmarkService
|
private val benchmarkService: BenchmarkService
|
||||||
) : ModelUnloadingViewModel(benchmarkService) {
|
) : ModelUnloadingViewModel(benchmarkService) {
|
||||||
/**
|
|
||||||
* UI states
|
// Data
|
||||||
*/
|
|
||||||
val selectedModel: StateFlow<ModelInfo?> = benchmarkService.currentSelectedModel
|
val selectedModel: StateFlow<ModelInfo?> = benchmarkService.currentSelectedModel
|
||||||
|
|
||||||
private val _benchmarkDuration = MutableSharedFlow<Long>()
|
private val _benchmarkDuration = MutableSharedFlow<Long>()
|
||||||
|
|
@ -30,6 +29,14 @@ class BenchmarkViewModel @Inject constructor(
|
||||||
private val _benchmarkResults = MutableStateFlow<List<BenchmarkResult>>(emptyList())
|
private val _benchmarkResults = MutableStateFlow<List<BenchmarkResult>>(emptyList())
|
||||||
val benchmarkResults: StateFlow<List<BenchmarkResult>> = _benchmarkResults.asStateFlow()
|
val benchmarkResults: StateFlow<List<BenchmarkResult>> = _benchmarkResults.asStateFlow()
|
||||||
|
|
||||||
|
// UI state: Model card
|
||||||
|
private val _showModelCard = MutableStateFlow(true)
|
||||||
|
val showModelCard = _showModelCard.asStateFlow()
|
||||||
|
|
||||||
|
fun toggleModelCard(show: Boolean) {
|
||||||
|
_showModelCard.value = show
|
||||||
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
benchmarkService.benchmarkResults
|
benchmarkService.benchmarkResults
|
||||||
|
|
|
||||||
|
|
@ -28,11 +28,19 @@ class ConversationViewModel @Inject constructor(
|
||||||
val selectedModel = conversationService.currentSelectedModel
|
val selectedModel = conversationService.currentSelectedModel
|
||||||
val systemPrompt = conversationService.systemPrompt
|
val systemPrompt = conversationService.systemPrompt
|
||||||
|
|
||||||
// Messages state
|
// UI state: Model card
|
||||||
|
private val _showModelCard = MutableStateFlow(true)
|
||||||
|
val showModelCard = _showModelCard.asStateFlow()
|
||||||
|
|
||||||
|
fun toggleModelCard(show: Boolean) {
|
||||||
|
_showModelCard.value = show
|
||||||
|
}
|
||||||
|
|
||||||
|
// UI state: conversation messages
|
||||||
private val _messages = MutableStateFlow<List<Message>>(emptyList())
|
private val _messages = MutableStateFlow<List<Message>>(emptyList())
|
||||||
val messages: StateFlow<List<Message>> = _messages.asStateFlow()
|
val messages: StateFlow<List<Message>> = _messages.asStateFlow()
|
||||||
|
|
||||||
// Input text field state
|
// UI state: Input text field
|
||||||
val inputFieldState = TextFieldState()
|
val inputFieldState = TextFieldState()
|
||||||
|
|
||||||
// Token generation job
|
// Token generation job
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue