Skip to content

Commit bae37b3

Browse files
authored
[Android] Use AlertDialog instead of Toast (mlc-ai#1039)
1 parent 6e40c21 commit bae37b3

File tree

3 files changed

+80
-35
lines changed

3 files changed

+80
-35
lines changed

android/MLCChat/app/src/main/java/ai/mlc/mlcchat/AppViewModel.kt

Lines changed: 40 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ package ai.mlc.mlcchat
22

33
import ai.mlc.mlcllm.ChatModule
44
import android.app.Application
5+
import android.content.ClipData
6+
import android.content.ClipboardManager
7+
import android.content.Context
58
import android.os.Environment
69
import android.widget.Toast
710
import androidx.compose.runtime.mutableStateOf
@@ -23,6 +26,8 @@ class AppViewModel(application: Application) : AndroidViewModel(application) {
2326
val modelList = emptyList<ModelState>().toMutableStateList()
2427
val chatState = ChatState()
2528
val modelSampleList = emptyList<ModelRecord>().toMutableStateList()
29+
private var showAlert = mutableStateOf(false)
30+
private var alertMessage = mutableStateOf("")
2631
private var appConfig = AppConfig(
2732
emptyList(),
2833
emptyList<ModelRecord>().toMutableList(),
@@ -44,25 +49,46 @@ class AppViewModel(application: Application) : AndroidViewModel(application) {
4449
loadAppConfig()
4550
}
4651

52+
fun supportedModelLibs(): List<String> {
53+
return appConfig.modelLibs
54+
}
55+
56+
fun isShowingAlert(): Boolean {
57+
return showAlert.value
58+
}
59+
60+
fun errorMessage(): String {
61+
return alertMessage.value
62+
}
63+
64+
fun dismissAlert() {
65+
require(showAlert.value)
66+
showAlert.value = false
67+
}
68+
69+
fun copyError() {
70+
require(showAlert.value)
71+
val clipboard =
72+
application.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
73+
clipboard.setPrimaryClip(ClipData.newPlainText("MLCChat", errorMessage()))
74+
}
75+
76+
private fun issueAlert(error: String) {
77+
showAlert.value = true
78+
alertMessage.value = error
79+
}
80+
4781
fun requestAddModel(url: String, localId: String?) {
4882
if (localId != null && localIdSet.contains(localId)) {
49-
Toast.makeText(
50-
application,
51-
"localId: $localId has been occupied",
52-
Toast.LENGTH_SHORT
53-
).show()
83+
issueAlert("localId: $localId has been occupied")
5484
} else {
5585
downloadModelConfig(if (url.endsWith("/")) url else "$url/", localId, false)
5686
}
5787
}
5888

5989
fun requestDeleteModel(localId: String) {
6090
deleteModel(localId)
61-
Toast.makeText(
62-
application,
63-
"Model: $localId has been deleted",
64-
Toast.LENGTH_SHORT
65-
).show()
91+
issueAlert("Model: $localId has been deleted")
6692
}
6793

6894

@@ -133,11 +159,7 @@ class AppViewModel(application: Application) : AndroidViewModel(application) {
133159
private fun isModelConfigAllowed(modelConfig: ModelConfig): Boolean {
134160
if (appConfig.modelLibs.contains(modelConfig.modelLib)) return true;
135161
viewModelScope.launch {
136-
Toast.makeText(
137-
application,
138-
"Model lib ${modelConfig.modelLib} is not supported.",
139-
Toast.LENGTH_SHORT
140-
).show()
162+
issueAlert("Model lib ${modelConfig.modelLib} is not supported.")
141163
}
142164
return false
143165
}
@@ -169,11 +191,7 @@ class AppViewModel(application: Application) : AndroidViewModel(application) {
169191
}
170192
if (localIdSet.contains(modelConfig.localId)) {
171193
tempFile.delete()
172-
Toast.makeText(
173-
application,
174-
"${modelConfig.localId} has been used, please consider another local ID",
175-
Toast.LENGTH_SHORT
176-
).show()
194+
issueAlert("${modelConfig.localId} has been used, please consider another local ID")
177195
return@launch
178196
}
179197
if (!isModelConfigAllowed(modelConfig)) {
@@ -188,21 +206,13 @@ class AppViewModel(application: Application) : AndroidViewModel(application) {
188206
addModelConfig(modelConfig, modelUrl, isBuiltin)
189207
} catch (e: Exception) {
190208
viewModelScope.launch {
191-
Toast.makeText(
192-
application,
193-
"Add model failed: ${e.localizedMessage}",
194-
Toast.LENGTH_SHORT
195-
).show()
209+
issueAlert("Add model failed: ${e.localizedMessage}")
196210
}
197211
}
198212
}
199213
} catch (e: Exception) {
200214
viewModelScope.launch {
201-
Toast.makeText(
202-
application,
203-
"Download model config failed: ${e.localizedMessage}",
204-
Toast.LENGTH_SHORT
205-
).show()
215+
issueAlert("Download model config failed: ${e.localizedMessage}")
206216
}
207217
}
208218

android/MLCChat/app/src/main/java/ai/mlc/mlcchat/StartView.kt

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import androidx.compose.material.icons.outlined.Delete
2020
import androidx.compose.material.icons.outlined.Download
2121
import androidx.compose.material.icons.outlined.Pause
2222
import androidx.compose.material.icons.outlined.Schedule
23+
import androidx.compose.material3.AlertDialog
2324
import androidx.compose.material3.Divider
2425
import androidx.compose.material3.ExperimentalMaterial3Api
2526
import androidx.compose.material3.Icon
@@ -94,9 +95,14 @@ fun StartView(
9495
}
9596
}
9697
if (isAddingModel) {
97-
Text(
98-
text = "Add Model Variant", modifier = Modifier.padding(top = 10.dp)
99-
)
98+
Text(text = "Supported Base Model Libs", modifier = Modifier.padding(top = 10.dp))
99+
for (lib in appViewModel.supportedModelLibs()) {
100+
Text(
101+
text = lib,
102+
style = MaterialTheme.typography.bodyMedium
103+
)
104+
}
105+
Text(text = "Add Model Variant", modifier = Modifier.padding(top = 10.dp))
100106
LazyColumn() {
101107
items(
102108
items = appViewModel.modelSampleList
@@ -148,10 +154,36 @@ fun StartView(
148154
}
149155
}
150156
}
151-
157+
if (appViewModel.isShowingAlert()) {
158+
AlertDialog(
159+
onDismissRequest = { appViewModel.dismissAlert() },
160+
onConfirmation = { appViewModel.copyError() },
161+
error = appViewModel.errorMessage()
162+
)
163+
}
152164
}
153165
}
154166

167+
@ExperimentalMaterial3Api
168+
@Composable
169+
fun AlertDialog(
170+
onDismissRequest: () -> Unit,
171+
onConfirmation: () -> Unit,
172+
error: String,
173+
) {
174+
AlertDialog(
175+
title = { Text(text = "Error") },
176+
text = { Text(text = error) },
177+
onDismissRequest = { onDismissRequest() },
178+
confirmButton = {
179+
TextButton(onClick = { onConfirmation() }) { Text("Copy") }
180+
},
181+
dismissButton = {
182+
TextButton(onClick = { onDismissRequest() }) { Text("Dismiss") }
183+
}
184+
)
185+
}
186+
155187
@Composable
156188
fun ModelView(
157189
navController: NavController,

android/prepare_libs.sh

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ python prepare_model_lib.py
99

1010
cd build
1111
touch config.cmake
12-
echo "set(TVM_HOME ${TVM_HOME})" >> config.cmake
12+
if [ ${TVM_HOME-0} -ne 0 ]; then
13+
echo "set(TVM_HOME ${TVM_HOME})" >> config.cmake
14+
fi
15+
1316
cmake .. \
1417
-DCMAKE_BUILD_TYPE=Release \
1518
-DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK}/build/cmake/android.toolchain.cmake \

0 commit comments

Comments
 (0)