Skip to content

Commit 12a6613

Browse files
committed
feat(android-app): redesign chat TopBar with model chip as title and inline LoRA badge
1 parent 39049f6 commit 12a6613

1 file changed

Lines changed: 87 additions & 117 deletions

File tree

  • examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/chat

examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/chat/ChatScreen.kt

Lines changed: 87 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -320,111 +320,20 @@ fun ChatTopBar(
320320
TopAppBar(
321321
modifier = modifier,
322322
title = {
323-
Text(
324-
text = "Chat",
325-
style = MaterialTheme.typography.titleLarge,
326-
fontWeight = FontWeight.Bold,
327-
)
328-
},
329-
actions = {
330-
Surface(
331-
shape = RoundedCornerShape(50),
332-
color = MaterialTheme.colorScheme.surfaceContainerHigh,
333-
) {
334-
Row(
335-
verticalAlignment = Alignment.CenterVertically,
336-
modifier = Modifier.padding(4.dp),
337-
) {
338-
Box(
339-
contentAlignment = Alignment.Center,
340-
modifier = Modifier
341-
.size(34.dp)
342-
.clip(CircleShape)
343-
.clickable(
344-
interactionSource = remember { MutableInteractionSource() },
345-
indication = null,
346-
onClick = onHistoryClick,
347-
),
348-
) {
349-
Icon(
350-
imageVector = Icons.Default.History,
351-
contentDescription = "History",
352-
modifier = Modifier.size(20.dp),
353-
tint = MaterialTheme.colorScheme.onSurface,
354-
)
355-
}
356-
357-
Box(
358-
contentAlignment = Alignment.Center,
359-
modifier = Modifier
360-
.size(34.dp)
361-
.clip(CircleShape)
362-
.then(
363-
if (hasMessages) {
364-
Modifier
365-
.background(AppColors.primaryAccent, CircleShape)
366-
.clickable(
367-
interactionSource = remember { MutableInteractionSource() },
368-
indication = null,
369-
onClick = onInfoClick,
370-
)
371-
} else {
372-
Modifier
373-
}
374-
),
375-
) {
376-
Icon(
377-
imageVector = Icons.Default.Info,
378-
contentDescription = "Info",
379-
modifier = Modifier.size(20.dp),
380-
tint = if (hasMessages) Color.White else MaterialTheme.colorScheme.onSurfaceVariant,
381-
)
382-
}
383-
}
384-
}
385-
386-
// LoRA button — only shown when model supports LoRA
387-
if (supportsLora) {
388-
Spacer(modifier = Modifier.width(4.dp))
389-
Surface(
390-
onClick = onLoraClick,
391-
shape = RoundedCornerShape(50),
392-
color = if (hasActiveLoraAdapter) AppColors.primaryPurple.copy(alpha = 0.15f) else MaterialTheme.colorScheme.surfaceContainerHigh,
393-
) {
394-
Box(
395-
contentAlignment = Alignment.Center,
396-
modifier = Modifier.size(34.dp),
397-
) {
398-
Icon(
399-
imageVector = Icons.Default.Tune,
400-
contentDescription = "LoRA",
401-
modifier = Modifier.size(18.dp),
402-
tint = if (hasActiveLoraAdapter) AppColors.primaryPurple else MaterialTheme.colorScheme.onSurfaceVariant,
403-
)
404-
}
405-
}
406-
}
407-
408-
Spacer(modifier = Modifier.width(8.dp))
409-
323+
// Model chip as the title — clickable to switch model
410324
Surface(
411325
onClick = onModelClick,
412-
shape = RoundedCornerShape(50),
326+
shape = RoundedCornerShape(12.dp),
413327
color = MaterialTheme.colorScheme.surfaceContainerHigh,
414328
) {
415329
Row(
416330
verticalAlignment = Alignment.CenterVertically,
417-
modifier = Modifier.padding(
418-
start = 6.dp,
419-
end = 12.dp,
420-
top = 6.dp,
421-
bottom = 6.dp,
422-
),
331+
modifier = Modifier.padding(horizontal = 10.dp, vertical = 7.dp),
423332
) {
424333
if (modelName != null) {
425334
Box(
426335
modifier = Modifier
427-
.size(30.dp)
336+
.size(26.dp)
428337
.clip(RoundedCornerShape(6.dp)),
429338
) {
430339
Image(
@@ -434,34 +343,54 @@ fun ChatTopBar(
434343
contentScale = ContentScale.Fit,
435344
)
436345
}
437-
438346
Spacer(modifier = Modifier.width(8.dp))
439-
440-
Column(verticalArrangement = Arrangement.spacedBy(1.dp)) {
441-
Text(
442-
text = shortModelName(modelName, maxLength = 12),
443-
style = MaterialTheme.typography.labelMedium,
444-
fontWeight = FontWeight.SemiBold,
445-
maxLines = 1,
446-
overflow = TextOverflow.Ellipsis,
447-
)
347+
Column(verticalArrangement = Arrangement.spacedBy(2.dp)) {
448348
Row(
449349
verticalAlignment = Alignment.CenterVertically,
450-
horizontalArrangement = Arrangement.spacedBy(3.dp),
350+
horizontalArrangement = Arrangement.spacedBy(6.dp),
451351
) {
452-
Icon(
453-
imageVector = if (supportsStreaming) Icons.Default.Bolt else Icons.Default.Stop,
454-
contentDescription = null,
455-
modifier = Modifier.size(10.dp),
456-
tint = if (supportsStreaming) AppColors.primaryGreen else AppColors.primaryOrange,
352+
Text(
353+
text = shortModelName(modelName, maxLength = 14),
354+
style = MaterialTheme.typography.labelLarge,
355+
fontWeight = FontWeight.SemiBold,
356+
maxLines = 1,
357+
overflow = TextOverflow.Ellipsis,
358+
)
359+
// LoRA active badge — inline next to model name
360+
if (hasActiveLoraAdapter) {
361+
Surface(
362+
shape = RoundedCornerShape(4.dp),
363+
color = AppColors.primaryPurple,
364+
) {
365+
Text(
366+
text = "LoRA",
367+
style = MaterialTheme.typography.labelSmall.copy(
368+
fontWeight = FontWeight.Bold,
369+
fontSize = 9.sp,
370+
letterSpacing = 0.3.sp,
371+
),
372+
color = Color.White,
373+
modifier = Modifier.padding(horizontal = 5.dp, vertical = 2.dp),
374+
)
375+
}
376+
}
377+
}
378+
Row(
379+
verticalAlignment = Alignment.CenterVertically,
380+
horizontalArrangement = Arrangement.spacedBy(4.dp),
381+
) {
382+
Box(
383+
modifier = Modifier
384+
.size(6.dp)
385+
.clip(CircleShape)
386+
.background(
387+
if (supportsStreaming) AppColors.primaryGreen else AppColors.primaryOrange,
388+
),
457389
)
458390
Text(
459391
text = if (supportsStreaming) "Streaming" else "Batch",
460-
style = MaterialTheme.typography.labelSmall.copy(
461-
fontSize = 10.sp,
462-
fontWeight = FontWeight.Medium,
463-
),
464-
color = if (supportsStreaming) AppColors.primaryGreen else AppColors.primaryOrange,
392+
style = MaterialTheme.typography.labelSmall.copy(fontSize = 10.sp),
393+
color = MaterialTheme.colorScheme.onSurfaceVariant,
465394
)
466395
}
467396
}
@@ -475,12 +404,53 @@ fun ChatTopBar(
475404
Spacer(modifier = Modifier.width(6.dp))
476405
Text(
477406
text = "Select Model",
478-
style = MaterialTheme.typography.labelMedium,
407+
style = MaterialTheme.typography.labelLarge,
479408
fontWeight = FontWeight.Medium,
480409
)
481410
}
482411
}
483412
}
413+
},
414+
actions = {
415+
// LoRA button — ghost when no adapter, hidden when not supported
416+
if (supportsLora && !hasActiveLoraAdapter) {
417+
TextButton(
418+
onClick = onLoraClick,
419+
contentPadding = PaddingValues(horizontal = 10.dp, vertical = 0.dp),
420+
) {
421+
Text(
422+
text = "+ LoRA",
423+
style = MaterialTheme.typography.labelSmall.copy(
424+
fontWeight = FontWeight.SemiBold,
425+
letterSpacing = 0.3.sp,
426+
),
427+
color = MaterialTheme.colorScheme.onSurfaceVariant,
428+
)
429+
}
430+
}
431+
432+
// History
433+
IconButton(onClick = onHistoryClick) {
434+
Icon(
435+
imageVector = Icons.Default.History,
436+
contentDescription = "History",
437+
modifier = Modifier.size(20.dp),
438+
tint = MaterialTheme.colorScheme.onSurfaceVariant,
439+
)
440+
}
441+
442+
// Info — highlighted when there are messages
443+
IconButton(
444+
onClick = onInfoClick,
445+
enabled = hasMessages,
446+
) {
447+
Icon(
448+
imageVector = Icons.Default.Info,
449+
contentDescription = "Info",
450+
modifier = Modifier.size(20.dp),
451+
tint = if (hasMessages) AppColors.primaryAccent else MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.3f),
452+
)
453+
}
484454

485455
Spacer(modifier = Modifier.width(4.dp))
486456
},

0 commit comments

Comments
 (0)