Skip to content

Commit e1729df

Browse files
committed
Continue fix
1 parent cf89408 commit e1729df

9 files changed

Lines changed: 452 additions & 242 deletions

File tree

llm/android/LlamaDemo/app/src/androidTest/java/com/example/executorchllamademo/UIWorkflowTest.kt

Lines changed: 249 additions & 168 deletions
Large diffs are not rendered by default.

llm/android/LlamaDemo/app/src/main/java/com/example/executorchllamademo/MainActivity.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,8 @@ class MainActivity : ComponentActivity() {
141141

142142
private fun askUserToSelectModel() {
143143
AlertDialog.Builder(this)
144-
.setTitle("Please Select a Model")
145-
.setMessage("To get started, please go to Settings and select a model and tokenizer file.")
144+
.setTitle(R.string.initial_dialog_title)
145+
.setMessage(R.string.initial_dialog_message)
146146
.setPositiveButton(android.R.string.ok) { dialog, _ ->
147147
dialog.dismiss()
148148
}

llm/android/LlamaDemo/app/src/main/java/com/example/executorchllamademo/Message.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ data class Message(
2020
private var _imagePath: String = "",
2121
var tokensPerSecond: Float = 0f,
2222
var totalGenerationTime: Long = 0L,
23-
val timestamp: Long = if (messageType != MessageType.SYSTEM) System.currentTimeMillis() else 0L
23+
val timestamp: Long = if (messageType != MessageType.SYSTEM) System.currentTimeMillis() else 0L,
24+
val id: String = java.util.UUID.randomUUID().toString()
2425
) {
2526
var text: String
2627
get() = _text

llm/android/LlamaDemo/app/src/main/java/com/example/executorchllamademo/ui/components/ChatInput.kt

Lines changed: 77 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import androidx.compose.ui.Modifier
2020
import androidx.compose.ui.graphics.SolidColor
2121
import androidx.compose.ui.platform.testTag
2222
import androidx.compose.ui.res.painterResource
23+
import androidx.compose.ui.res.stringResource
2324
import androidx.compose.ui.semantics.contentDescription
2425
import androidx.compose.ui.semantics.semantics
2526
import androidx.compose.ui.text.TextStyle
@@ -34,14 +35,19 @@ fun ChatInput(
3435
onSendClick: () -> Unit,
3536
onGalleryClick: () -> Unit,
3637
onCameraClick: () -> Unit,
38+
onAudioClick: () -> Unit = {},
39+
onRecordClick: () -> Unit = {},
3740
onThinkModeClick: () -> Unit,
3841
isGenerating: Boolean,
3942
isThinkingMode: Boolean,
4043
showMediaButtons: Boolean,
44+
isVisionModel: Boolean = false,
45+
isAudioModel: Boolean = false,
4146
modifier: Modifier = Modifier
4247
) {
4348
val isSendEnabled = text.isNotBlank() || isGenerating
44-
49+
var isExpanded by remember { mutableStateOf(false) }
50+
4551
Row(
4652
modifier = modifier
4753
.fillMaxWidth()
@@ -62,37 +68,82 @@ fun ChatInput(
6268
if (isThinkingMode) R.drawable.blue_lightbulb_24
6369
else R.drawable.baseline_lightbulb_24
6470
),
65-
contentDescription = "Think mode",
71+
contentDescription = stringResource(R.string.think_mode),
6672
tint = if (isThinkingMode) Primary else TextSecondary
6773
)
6874
}
6975

70-
// Media buttons
76+
// Media buttons with "+" toggle
7177
if (showMediaButtons) {
7278
IconButton(
73-
onClick = onGalleryClick,
79+
onClick = { isExpanded = !isExpanded },
7480
modifier = Modifier
7581
.size(40.dp)
76-
.testTag("galleryButton")
82+
.testTag("addMediaButton")
7783
) {
7884
Icon(
79-
painter = painterResource(R.drawable.outline_image_48),
80-
contentDescription = "Gallery",
81-
tint = TextSecondary
85+
painter = painterResource(R.drawable.baseline_add_24),
86+
contentDescription = stringResource(R.string.add_media_description),
87+
tint = if (isExpanded) Primary else TextSecondary
8288
)
8389
}
84-
85-
IconButton(
86-
onClick = onCameraClick,
87-
modifier = Modifier
88-
.size(40.dp)
89-
.testTag("cameraButton")
90-
) {
91-
Icon(
92-
painter = painterResource(R.drawable.outline_camera_alt_48),
93-
contentDescription = "Camera",
94-
tint = TextSecondary
95-
)
90+
91+
if (isExpanded) {
92+
if (isVisionModel) {
93+
IconButton(
94+
onClick = onGalleryClick,
95+
modifier = Modifier
96+
.size(40.dp)
97+
.testTag("galleryButton")
98+
) {
99+
Icon(
100+
painter = painterResource(R.drawable.outline_image_48),
101+
contentDescription = stringResource(R.string.gallery_description),
102+
tint = TextSecondary
103+
)
104+
}
105+
106+
IconButton(
107+
onClick = onCameraClick,
108+
modifier = Modifier
109+
.size(40.dp)
110+
.testTag("cameraButton")
111+
) {
112+
Icon(
113+
painter = painterResource(R.drawable.outline_camera_alt_48),
114+
contentDescription = stringResource(R.string.camera_description),
115+
tint = TextSecondary
116+
)
117+
}
118+
}
119+
120+
if (isAudioModel) {
121+
IconButton(
122+
onClick = onAudioClick,
123+
modifier = Modifier
124+
.size(40.dp)
125+
.testTag("audioButton")
126+
) {
127+
Icon(
128+
painter = painterResource(R.drawable.baseline_audio_file_48),
129+
contentDescription = stringResource(R.string.audio_description),
130+
tint = TextSecondary
131+
)
132+
}
133+
134+
IconButton(
135+
onClick = onRecordClick,
136+
modifier = Modifier
137+
.size(40.dp)
138+
.testTag("recordButton")
139+
) {
140+
Icon(
141+
painter = painterResource(R.drawable.outline_add_box_48), // Using this as placeholder for record
142+
contentDescription = stringResource(R.string.record_description),
143+
tint = TextSecondary
144+
)
145+
}
146+
}
96147
}
97148
}
98149

@@ -122,7 +173,7 @@ fun ChatInput(
122173
decorationBox = { innerTextField ->
123174
if (text.isEmpty()) {
124175
Text(
125-
text = "Type a message",
176+
text = stringResource(R.string.type_message_hint),
126177
style = MaterialTheme.typography.bodyMedium,
127178
color = TextSecondary
128179
)
@@ -133,7 +184,8 @@ fun ChatInput(
133184
}
134185

135186
// Send/Stop button
136-
val sendButtonDescription = if (isGenerating) "Stop" else "Send"
187+
val sendDesc = stringResource(R.string.send_description)
188+
val stopDesc = stringResource(R.string.stop_description)
137189
IconButton(
138190
onClick = onSendClick,
139191
enabled = isSendEnabled,
@@ -144,7 +196,9 @@ fun ChatInput(
144196
shape = CircleShape
145197
)
146198
.testTag("sendButton")
147-
.semantics { contentDescription = sendButtonDescription }
199+
.semantics {
200+
contentDescription = if (isGenerating) stopDesc else sendDesc
201+
}
148202
) {
149203
Icon(
150204
painter = painterResource(

llm/android/LlamaDemo/app/src/main/java/com/example/executorchllamademo/ui/components/SettingsComponents.kt

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import androidx.compose.ui.Modifier
1919
import androidx.compose.ui.draw.clip
2020
import androidx.compose.ui.platform.testTag
2121
import androidx.compose.ui.res.painterResource
22+
import androidx.compose.ui.res.stringResource
2223
import androidx.compose.ui.semantics.contentDescription
2324
import androidx.compose.ui.semantics.semantics
2425
import androidx.compose.ui.unit.dp
@@ -102,11 +103,11 @@ fun FilePickerRow(
102103
IconButton(
103104
onClick = onClick,
104105
modifier = (if (buttonTestTag.isNotEmpty()) Modifier.testTag(buttonTestTag) else Modifier)
105-
.semantics { contentDescription = "Select $label" }
106+
.semantics { contentDescription = label }
106107
) {
107108
Icon(
108109
painter = painterResource(R.drawable.outline_add_box_48),
109-
contentDescription = "Select $label",
110+
contentDescription = label,
110111
tint = Primary
111112
)
112113
}
@@ -185,7 +186,7 @@ fun TemperatureSlider(
185186
horizontalArrangement = Arrangement.SpaceBetween
186187
) {
187188
Text(
188-
text = "Temperature",
189+
text = stringResource(R.string.temperature_label),
189190
style = MaterialTheme.typography.bodyMedium,
190191
color = TextPrimary
191192
)
@@ -230,13 +231,19 @@ fun TextInputDialog(
230231
)
231232
},
232233
confirmButton = {
233-
TextButton(onClick = { onConfirm(text) }) {
234-
Text("OK")
234+
TextButton(
235+
onClick = { onConfirm(text) },
236+
modifier = Modifier.testTag("dialogConfirmButton")
237+
) {
238+
Text(stringResource(android.R.string.ok))
235239
}
236240
},
237241
dismissButton = {
238-
TextButton(onClick = onDismiss) {
239-
Text("Cancel")
242+
TextButton(
243+
onClick = onDismiss,
244+
modifier = Modifier.testTag("dialogDismissButton")
245+
) {
246+
Text(stringResource(android.R.string.cancel))
240247
}
241248
}
242249
)
@@ -254,13 +261,19 @@ fun ConfirmationDialog(
254261
title = { Text(title) },
255262
text = { Text(message) },
256263
confirmButton = {
257-
TextButton(onClick = onConfirm) {
258-
Text("OK")
264+
TextButton(
265+
onClick = onConfirm,
266+
modifier = Modifier.testTag("dialogConfirmButton")
267+
) {
268+
Text(stringResource(android.R.string.ok))
259269
}
260270
},
261271
dismissButton = {
262-
TextButton(onClick = onDismiss) {
263-
Text("Cancel")
272+
TextButton(
273+
onClick = onDismiss,
274+
modifier = Modifier.testTag("dialogDismissButton")
275+
) {
276+
Text(stringResource(android.R.string.cancel))
264277
}
265278
}
266279
)
@@ -280,7 +293,7 @@ fun FileSelectionDialog(
280293
Column {
281294
if (files.isEmpty()) {
282295
Text(
283-
text = "No files found",
296+
text = stringResource(R.string.no_files_found),
284297
style = MaterialTheme.typography.bodyMedium,
285298
color = TextSecondary
286299
)
@@ -300,8 +313,11 @@ fun FileSelectionDialog(
300313
}
301314
},
302315
confirmButton = {
303-
TextButton(onClick = onDismiss) {
304-
Text("Cancel")
316+
TextButton(
317+
onClick = onDismiss,
318+
modifier = Modifier.testTag("dialogDismissButton")
319+
) {
320+
Text(stringResource(android.R.string.cancel))
305321
}
306322
}
307323
)

llm/android/LlamaDemo/app/src/main/java/com/example/executorchllamademo/ui/screens/ChatScreen.kt

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,11 @@ import androidx.compose.ui.Modifier
2121
import androidx.compose.ui.platform.LocalContext
2222
import androidx.compose.ui.platform.testTag
2323
import androidx.compose.ui.res.painterResource
24+
import androidx.compose.ui.res.stringResource
2425
import androidx.compose.ui.semantics.contentDescription
2526
import androidx.compose.ui.semantics.semantics
2627
import androidx.compose.ui.unit.dp
28+
import com.example.executorchllamademo.MainActivity
2729
import com.example.executorchllamademo.LogsActivity
2830
import com.example.executorchllamademo.R
2931
import com.example.executorchllamademo.SettingsActivity
@@ -62,7 +64,7 @@ fun ChatScreen(
6264
TopAppBar(
6365
title = {
6466
Text(
65-
text = "LlamaDemo",
67+
text = stringResource(R.string.app_name),
6668
style = MaterialTheme.typography.titleLarge,
6769
color = TextPrimary
6870
)
@@ -80,7 +82,7 @@ fun ChatScreen(
8082
onClick = {
8183
context.startActivity(Intent(context, LogsActivity::class.java))
8284
},
83-
modifier = Modifier.semantics { contentDescription = "Logs" }
85+
modifier = Modifier.semantics { contentDescription = context.getString(R.string.logs_title) }
8486
) {
8587
Icon(
8688
painter = painterResource(R.drawable.baseline_article_24),
@@ -94,7 +96,7 @@ fun ChatScreen(
9496
},
9597
modifier = Modifier
9698
.testTag("settings")
97-
.semantics { contentDescription = "Settings" }
99+
.semantics { contentDescription = context.getString(R.string.settings_title) }
98100
) {
99101
Icon(
100102
painter = painterResource(R.drawable.baseline_settings_24),
@@ -113,15 +115,16 @@ fun ChatScreen(
113115
text = inputText,
114116
onTextChange = { viewModel.setInputText(it) },
115117
onSendClick = { viewModel.sendMessage() },
116-
onGalleryClick = { /* Will be handled by activity */ },
117-
onCameraClick = { /* Will be handled by activity */ },
118+
onGalleryClick = { (context as? MainActivity)?.openGallery() },
119+
onCameraClick = { (context as? MainActivity)?.openCamera() },
120+
onAudioClick = { /* Handle Audio */ },
121+
onRecordClick = { /* Handle Record */ },
118122
onThinkModeClick = { viewModel.toggleThinkingMode() },
119123
isGenerating = isGenerating,
120124
isThinkingMode = isThinkingMode,
121-
showMediaButtons = isModelLoaded && viewModel.settingsFields.value.modelType?.let {
122-
it == com.example.executorchllamademo.ModelType.LLAVA_1_5 ||
123-
it == com.example.executorchllamademo.ModelType.GEMMA_3
124-
} ?: false
125+
showMediaButtons = isModelLoaded && viewModel.canAttachMedia(),
126+
isVisionModel = viewModel.isVisionModel(),
127+
isAudioModel = viewModel.isAudioModel()
125128
)
126129
}
127130
) { paddingValues ->
@@ -133,7 +136,7 @@ fun ChatScreen(
133136
state = listState,
134137
contentPadding = PaddingValues(vertical = 8.dp)
135138
) {
136-
items(messages, key = { "${it.promptID}_${it.timestamp}_${it.isSent}" }) { message ->
139+
items(messages, key = { it.id }) { message ->
137140
MessageBubble(message = message)
138141
}
139142
}

0 commit comments

Comments
 (0)