@@ -56,6 +56,12 @@ import helium314.keyboard.latin.R
5656import helium314.keyboard.latin.permissions.PermissionsUtil
5757import helium314.keyboard.latin.settings.Defaults
5858import helium314.keyboard.latin.utils.JniUtils
59+ import helium314.keyboard.latin.utils.SubtypeSettings
60+ import helium314.keyboard.settings.dialogs.MultiListPickerDialog
61+ import helium314.keyboard.settings.WithSmallTitle
62+ import helium314.keyboard.settings.DropDownField
63+ import helium314.keyboard.latin.utils.SubtypeLocaleUtils.displayName
64+ import helium314.keyboard.latin.utils.locale
5965import helium314.keyboard.latin.utils.UncachedInputMethodManagerUtils
6066import helium314.keyboard.latin.utils.getActivity
6167import helium314.keyboard.latin.utils.prefs
@@ -131,7 +137,7 @@ fun WelcomeWizard(
131137 ) {
132138 // Progress indicator
133139 Row (Modifier .fillMaxWidth().padding(bottom = 24 .dp), horizontalArrangement = Arrangement .SpaceEvenly ) {
134- for (i in 1 .. 8 ) {
140+ for (i in 1 .. 9 ) {
135141 Box (
136142 modifier = Modifier
137143 .height(6 .dp)
@@ -218,19 +224,144 @@ fun WelcomeWizard(
218224 null
219225 )
220226 } else if (step == 3 ) {
227+ var showDialog by remember { mutableStateOf(false ) }
228+ val allSubtypes = remember { SubtypeSettings .getAllAvailableSubtypes() }
229+ var enabledSubtypes by remember { mutableStateOf(SubtypeSettings .getEnabledSubtypes(true )) }
230+
231+ val gestureMethods = listOf (
232+ stringResource(R .string.gesture_method_native) to " native" ,
233+ stringResource(R .string.gesture_method_fallback) to " fallback"
234+ )
235+ var selectedMethod by remember {
236+ mutableStateOf(
237+ ctx.prefs().getString(
238+ Settings .PREF_GESTURE_METHOD ,
239+ if (JniUtils .sHaveNativeGestureLib) " native" else " fallback"
240+ )!!
241+ )
242+ }
243+
221244 Step (
222245 3 ,
246+ " Language & Input Selection" ,
247+ " Configure your typing languages and choose the gesture typing engine type." ,
248+ " Next" ,
249+ painterResource(R .drawable.sym_keyboard_language_switch),
250+ { step++ },
251+ { step-- }
252+ ) {
253+ WithSmallTitle (" Typing Languages" ) {
254+ Column (
255+ modifier = Modifier
256+ .fillMaxWidth()
257+ .background(MaterialTheme .colorScheme.surfaceVariant, MaterialTheme .shapes.medium)
258+ .padding(16 .dp)
259+ ) {
260+ Text (
261+ " Enabled Languages:" ,
262+ style = MaterialTheme .typography.titleMedium,
263+ color = MaterialTheme .colorScheme.onSurface
264+ )
265+ Spacer (Modifier .height(8 .dp))
266+ enabledSubtypes.forEach { subtype ->
267+ Row (
268+ modifier = Modifier .fillMaxWidth().padding(vertical = 4 .dp),
269+ verticalAlignment = Alignment .CenterVertically
270+ ) {
271+ Icon (
272+ painter = painterResource(R .drawable.ic_setup_check),
273+ contentDescription = null ,
274+ tint = MaterialTheme .colorScheme.primary,
275+ modifier = Modifier .size(20 .dp).padding(end = 8 .dp)
276+ )
277+ Text (
278+ text = subtype.displayName(),
279+ style = MaterialTheme .typography.bodyLarge,
280+ color = MaterialTheme .colorScheme.onSurfaceVariant
281+ )
282+ }
283+ }
284+ Spacer (Modifier .height(12 .dp))
285+ androidx.compose.material3.Button (
286+ onClick = { showDialog = true },
287+ modifier = Modifier .fillMaxWidth()
288+ ) {
289+ Text (" Choose Languages" )
290+ }
291+ }
292+ }
293+
294+ if (showDialog) {
295+ MultiListPickerDialog (
296+ onDismissRequest = { showDialog = false },
297+ items = allSubtypes,
298+ initialSelection = enabledSubtypes,
299+ onConfirmed = { selected ->
300+ selected.forEach { subtype ->
301+ if (subtype !in enabledSubtypes) {
302+ SubtypeSettings .addEnabledSubtype(ctx.prefs(), subtype)
303+ }
304+ }
305+ enabledSubtypes.forEach { subtype ->
306+ if (subtype !in selected && selected.isNotEmpty()) {
307+ SubtypeSettings .removeEnabledSubtype(ctx, subtype)
308+ }
309+ }
310+ enabledSubtypes = SubtypeSettings .getEnabledSubtypes(true )
311+ showDialog = false
312+ },
313+ getItemName = { it.displayName() }
314+ )
315+ }
316+
317+ Spacer (Modifier .height(16 .dp))
318+
319+ WithSmallTitle (" Gesture Typing Engine" ) {
320+ Column (
321+ modifier = Modifier
322+ .fillMaxWidth()
323+ .background(MaterialTheme .colorScheme.surfaceVariant, MaterialTheme .shapes.medium)
324+ .padding(16 .dp)
325+ ) {
326+ DropDownField (
327+ items = gestureMethods,
328+ selectedItem = gestureMethods.first { it.second == selectedMethod },
329+ onSelected = { pair ->
330+ selectedMethod = pair.second
331+ ctx.prefs().edit { putString(Settings .PREF_GESTURE_METHOD , pair.second) }
332+ refreshTrigger++
333+ }
334+ ) { pair ->
335+ Text (pair.first, style = MaterialTheme .typography.bodyLarge)
336+ }
337+ Spacer (Modifier .height(8 .dp))
338+ Text (
339+ text = if (selectedMethod == " native" ) {
340+ " Note: Native engine provides high performance but requires swypelib to be downloaded in the next step."
341+ } else {
342+ " Note: Pure-Java engine works out of the box (Experimental)."
343+ },
344+ style = MaterialTheme .typography.bodyMedium,
345+ color = MaterialTheme .colorScheme.onSurfaceVariant
346+ )
347+ }
348+ }
349+ }
350+ } else if (step == 4 ) {
351+ Step (
352+ 4 ,
223353 " Libraries" ,
224354 " Download emoji and gesture libraries to improve typing and suggestions." ,
225355 " Next" ,
226356 painterResource(R .drawable.sym_keyboard_language_switch),
227357 { step++ },
228- null
358+ { step -- }
229359 ) {
230360 val trigger = refreshTrigger // Force recomposition
231361 val locale = helium314.keyboard.latin.RichInputMethodManager .getInstance().currentSubtype.locale
232362 val emojiLibInstalled = java.io.File (helium314.keyboard.latin.utils.DictionaryInfoUtils .getCacheDirectoryForLocale(locale, ctx), " emoji_${locale.language} .dict" ).exists()
233363 val gestureLibInstalled = java.io.File (ctx.filesDir, " libjni_latinime.so" ).exists() || JniUtils .sHaveGestureLib
364+ val showGestureDownload = ctx.prefs().getString(Settings .PREF_GESTURE_METHOD , " fallback" ) == " native"
234365
235366 Box (Modifier .fillMaxWidth().background(MaterialTheme .colorScheme.surfaceVariant, MaterialTheme .shapes.medium)) {
236367 LoadEmojiLibPreference (
@@ -241,24 +372,26 @@ fun WelcomeWizard(
241372 Icon (painterResource(R .drawable.ic_setup_check), null , Modifier .align(Alignment .CenterEnd ).padding(end = 16 .dp), tint = MaterialTheme .colorScheme.primary)
242373 }
243374 }
244- Spacer (Modifier .height(8 .dp))
245- Box (Modifier .fillMaxWidth().background(MaterialTheme .colorScheme.surfaceVariant, MaterialTheme .shapes.medium)) {
246- LoadGestureLibPreference (
247- title = " Gesture Typing Library" ,
248- restartOnSuccess = false ,
249- onSuccess = {
250- requiresRestart = true
251- refreshTrigger++
375+ if (showGestureDownload) {
376+ Spacer (Modifier .height(8 .dp))
377+ Box (Modifier .fillMaxWidth().background(MaterialTheme .colorScheme.surfaceVariant, MaterialTheme .shapes.medium)) {
378+ LoadGestureLibPreference (
379+ title = " Gesture Typing Library" ,
380+ restartOnSuccess = false ,
381+ onSuccess = {
382+ requiresRestart = true
383+ refreshTrigger++
384+ }
385+ )
386+ if (gestureLibInstalled) {
387+ Icon (painterResource(R .drawable.ic_setup_check), null , Modifier .align(Alignment .CenterEnd ).padding(end = 16 .dp), tint = MaterialTheme .colorScheme.primary)
252388 }
253- )
254- if (gestureLibInstalled) {
255- Icon (painterResource(R .drawable.ic_setup_check), null , Modifier .align(Alignment .CenterEnd ).padding(end = 16 .dp), tint = MaterialTheme .colorScheme.primary)
256389 }
257390 }
258391 }
259- } else if (step == 4 ) {
392+ } else if (step == 5 ) {
260393 Step (
261- 4 ,
394+ 5 ,
262395 " AI Integration" ,
263396 " Select an AI service and provide your API key for advanced proofreading features." ,
264397 " Next" ,
@@ -325,9 +458,9 @@ fun WelcomeWizard(
325458 Text (" AI features are not available in this build flavor." , color = MaterialTheme .colorScheme.onSurfaceVariant)
326459 }
327460 }
328- } else if (step == 5 ) {
461+ } else if (step == 6 ) {
329462 Step (
330- 5 ,
463+ 6 ,
331464 " Floating Keyboard" ,
332465 " Enable floating keyboard by granting the 'Display over other apps' permission." ,
333466 " Next" ,
@@ -354,9 +487,9 @@ fun WelcomeWizard(
354487 }
355488 }
356489 }
357- } else if (step == 6 ) {
490+ } else if (step == 7 ) {
358491 Step (
359- 6 ,
492+ 7 ,
360493 " Screenshot Suggestions" ,
361494 " Suggest recently taken screenshots in the suggestion strip. Note: This permission also allows saving screenshots to the clipboard." ,
362495 " Next" ,
@@ -392,9 +525,9 @@ fun WelcomeWizard(
392525 }.Preference ()
393526 }
394527 }
395- } else if (step == 7 ) {
528+ } else if (step == 8 ) {
396529 Step (
397- 7 ,
530+ 8 ,
398531 " Keyboard Height" ,
399532 " Adjust the height of the keyboard. Recommended: 77% for more square keys, 100% for taller keys." ,
400533 " Next" ,
@@ -421,9 +554,9 @@ fun WelcomeWizard(
421554 }
422555 }
423556 }
424- } else { // step 8
557+ } else { // step 9
425558 Step (
426- 8 ,
559+ 9 ,
427560 stringResource(R .string.setup_step3_title),
428561 stringResource(R .string.setup_step3_instruction, appName),
429562 stringResource(R .string.setup_finish_action),
0 commit comments