1
0
Fork 0

significantly simpler language change dialog (no Activity hack)

This commit is contained in:
sspanak 2025-05-10 12:33:34 +03:00 committed by Dimo Karaivanov
parent 32b172827e
commit 18c2ab8440
9 changed files with 71 additions and 119 deletions

View file

@ -170,7 +170,7 @@ abstract public class CommandHandler extends TextEditingHandler {
protected void changeLang() {
suggestionOps.cancelDelayedAccept();
stopVoiceInput();
ChangeLanguageDialog.show(this, mInputMode.getSequence(), textField.getComposingText());
new ChangeLanguageDialog(getFinalContext(), this::setLang).show();
}

View file

@ -11,7 +11,6 @@ import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import io.github.sspanak.tt9.R;
import io.github.sspanak.tt9.db.DataStore;
@ -21,7 +20,6 @@ import io.github.sspanak.tt9.ime.modes.InputModeKind;
import io.github.sspanak.tt9.languages.LanguageCollection;
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
import io.github.sspanak.tt9.ui.UI;
import io.github.sspanak.tt9.ui.dialogs.ChangeLanguageDialog;
import io.github.sspanak.tt9.ui.dialogs.PopupDialog;
import io.github.sspanak.tt9.ui.dialogs.RequestPermissionDialog;
import io.github.sspanak.tt9.util.Logger;
@ -122,12 +120,6 @@ public class TraditionalT9 extends MainViewHandler {
if (!message.isEmpty()) {
UI.toastLong(this, message);
} else if (ChangeLanguageDialog.INTENT_SET_LANGUAGE.equals(intent.getStringExtra(ChangeLanguageDialog.INTENT_SET_LANGUAGE))) {
onResume(
intent.getStringExtra(ChangeLanguageDialog.PARAMETER_LANGUAGE),
intent.getStringExtra(ChangeLanguageDialog.PARAMETER_SEQUENCE),
intent.getStringExtra(ChangeLanguageDialog.PARAMETER_WORD)
);
}
return result;
@ -184,24 +176,6 @@ public class TraditionalT9 extends MainViewHandler {
}
private void onResume(@Nullable String langStringId, @Nullable String sequence, @Nullable String word) {
int languageId;
try {
langStringId = langStringId == null ? "(null)" : langStringId;
languageId = Integer.parseInt(langStringId);
} catch (NumberFormatException e) {
Logger.e(LOG_TAG, "Can not resume typing. Failed to parse language ID '" + langStringId + "'. " + e);
return;
}
if (word != null && !word.isEmpty() && sequence != null && !sequence.isEmpty()) {
mInputMode.setSequence(sequence);
}
setLang(languageId);
}
@Override
protected void onStop() {
stopVoiceInput();

View file

@ -5,12 +5,18 @@ import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import io.github.sspanak.tt9.ui.main.MainView;
import io.github.sspanak.tt9.util.Logger;
import io.github.sspanak.tt9.util.sys.DeviceInfo;
public class PopupBuilder {
private static final String LOG_TAG = PopupBuilder.class.getSimpleName();
private final Context context;
private MaterialAlertDialogBuilder builder12;
private AlertDialog.Builder builderLegacy;
@ -112,4 +118,35 @@ public class PopupBuilder {
public Dialog show() {
return DeviceInfo.AT_LEAST_ANDROID_12 ? builder12.show() : builderLegacy.show();
}
/**
* In IME context, it is not that easy to show a popup dialog. We need to make it "valid" using
* the hacks below. Made possible thanks to:
* <a href="https://stackoverflow.com/questions/51906586/display-dialog-from-input-method-service-in-android-9-android-pie">Philipp</a>
* <a href="https://stackoverflow.com/questions/3494476/android-ime-how-to-show-a-pop-up-dialog/3508462#3508462">Maher Abuthraa</a>
*/
public Dialog showFromIme(MainView main) {
if (main == null || main.getView() == null) {
Logger.e(LOG_TAG, "Cannot show a popup dialog. Main view is null.");
return null;
}
Dialog dialog = DeviceInfo.AT_LEAST_ANDROID_12 ? builder12.create() : builderLegacy.create();
Window window = dialog.getWindow();
if (window == null) {
Logger.e(LOG_TAG, "Cannot show a popup dialog. AlertDialog generated a Dialog with NULL Window.");
return null;
}
WindowManager.LayoutParams layout = window.getAttributes();
layout.token = main.getView().getWindowToken();
layout.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
window.setAttributes(layout);
window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
dialog.show();
return dialog;
}
}

View file

@ -57,13 +57,13 @@ public class AddWordDialog extends ThemedPopupDialog {
@Override
void render() {
void show() {
if (message == null || word == null || word.isEmpty()) {
close();
return;
}
super.render(this::onOK);
super.show(this::onOK);
}

View file

@ -36,7 +36,7 @@ public class AutoUpdateMonolog extends PopupDialog {
@Override
void render() {
void show() {
if (language != null) {
DictionaryLoader.load(context, language);
}

View file

@ -2,65 +2,55 @@ package io.github.sspanak.tt9.ui.dialogs;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.inputmethodservice.InputMethodService;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.HashMap;
import io.github.sspanak.tt9.R;
import io.github.sspanak.tt9.ime.TraditionalT9;
import io.github.sspanak.tt9.ime.helpers.Key;
import io.github.sspanak.tt9.languages.Language;
import io.github.sspanak.tt9.languages.LanguageCollection;
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
import io.github.sspanak.tt9.ui.LanguageRadioButton;
import io.github.sspanak.tt9.ui.PopupBuilder;
import io.github.sspanak.tt9.ui.main.MainView;
import io.github.sspanak.tt9.util.ConsumerCompat;
import io.github.sspanak.tt9.util.sys.DeviceInfo;
public class ChangeLanguageDialog extends ThemedPopupDialog {
public static final String TYPE = "tt9.popup_dialog.change_language";
public static final String INTENT_SET_LANGUAGE = "tt9.popup_dialog.command.set_language";
public static final String PARAMETER_LANGUAGE = "tt9.popup_dialog.parameter.language";
public static final String PARAMETER_SEQUENCE = "tt9.popup_dialog.parameter.sequence";
public static final String PARAMETER_WORD = "tt9.popup_dialog.parameter.word";
private final ConsumerCompat<HashMap<String, String>> activityFinisher;
private final LayoutInflater inflater;
private final ArrayList<Language> languages;
private final MainView mainView;
private final SettingsStore settings;
private final String currentSequence;
private final String currentWord;
private final ArrayList<LanguageRadioButton> radioButtonsCache = new ArrayList<>();
private final ConsumerCompat<Integer> onLanguageChanged;
private Dialog popup;
private final ArrayList<LanguageRadioButton> radioButtonsCache = new ArrayList<>();
ChangeLanguageDialog(@NonNull AppCompatActivity context, @NonNull Intent intent, ConsumerCompat<HashMap<String, String>> activityFinisher) {
super(context, null, R.style.TTheme_AddWord);
public ChangeLanguageDialog(@NonNull TraditionalT9 tt9, @Nullable ConsumerCompat<Integer> changeHandler) {
super(tt9, null, R.style.TTheme_AddWord);
this.activityFinisher = activityFinisher;
title = context.getResources().getString(R.string.language_popup_title);
title = tt9.getResources().getString(R.string.language_popup_title);
OKLabel = null;
inflater = context.getLayoutInflater();
settings = new SettingsStore(context);
mainView = tt9.getMainView();
settings = tt9.getSettings();
languages = LanguageCollection.getAll(settings.getEnabledLanguageIds(), true);
currentSequence = intent.getStringExtra(PARAMETER_SEQUENCE);
currentWord = intent.getStringExtra(PARAMETER_WORD);
onLanguageChanged = changeHandler;
}
private void onClick(View button) {
changeLanguage(button.getId());
if (onLanguageChanged != null) {
onLanguageChanged.accept(button.getId());
}
close();
}
@ -85,7 +75,10 @@ public class ChangeLanguageDialog extends ThemedPopupDialog {
return false;
}
changeLanguage(languageId);
if (onLanguageChanged != null) {
onLanguageChanged.accept(languageId);
}
close();
return true;
}
@ -113,25 +106,6 @@ public class ChangeLanguageDialog extends ThemedPopupDialog {
popup.dismiss();
popup = null;
}
activityFinisher.accept(null);
}
private void changeLanguage(int languageId) {
detachRadioButtons();
if (popup != null) {
popup.dismiss();
popup = null;
}
if (activityFinisher != null) {
HashMap<String, String> messages = new HashMap<>();
messages.put(INTENT_SET_LANGUAGE, INTENT_SET_LANGUAGE);
messages.put(PARAMETER_LANGUAGE, String.valueOf(languageId));
messages.put(PARAMETER_SEQUENCE, currentSequence);
messages.put(PARAMETER_WORD, currentWord);
activityFinisher.accept(messages);
}
}
@ -148,7 +122,7 @@ public class ChangeLanguageDialog extends ThemedPopupDialog {
private View generateRadioButtons() {
final int currentLanguageId = settings.getInputLanguage();
final View view = inflater.inflate(R.layout.popup_language_select, null);
final View view = View.inflate(context, R.layout.popup_language_select, null);
final LinearLayout radioGroup = view.findViewById(R.id.language_select_list);
radioButtonsCache.clear();
@ -169,31 +143,14 @@ public class ChangeLanguageDialog extends ThemedPopupDialog {
}
@Override
void render() {
public void show() {
popup = new PopupBuilder(context)
.setCancelable(false)
.setCancelable(true)
.setTitle(title)
.setMessage(message)
.setNegativeButton(true, this::close)
.setOnKeyListener(this)
.setView(generateRadioButtons())
.show();
}
/**
* Open a popup dialog containing a list of the enabled languages. After a language is selected,
* "currentSequence" and "currentWord" are passed back to the IME, in case it wants to recompose them.
*/
public static void show(InputMethodService ims, String currentSequence, String currentWord) {
Intent intent = new Intent(ims, PopupDialogActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
intent.putExtra(PARAMETER_DIALOG_TYPE, TYPE);
intent.putExtra(PARAMETER_SEQUENCE, currentSequence);
intent.putExtra(PARAMETER_WORD, currentWord);
ims.startActivity(intent);
.showFromIme(mainView);
}
}

View file

@ -36,7 +36,7 @@ abstract public class PopupDialog implements DialogInterface.OnKeyListener {
return false;
}
protected void render(Runnable OKAction) {
protected void show(Runnable OKAction) {
new PopupBuilder(context)
.setCancelable(false)
.setTitle(title)
@ -47,5 +47,5 @@ abstract public class PopupDialog implements DialogInterface.OnKeyListener {
.show();
}
abstract void render();
abstract void show();
}

View file

@ -6,8 +6,6 @@ import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import java.util.HashMap;
import io.github.sspanak.tt9.ime.TraditionalT9;
import io.github.sspanak.tt9.util.Logger;
@ -20,7 +18,7 @@ public class PopupDialogActivity extends AppCompatActivity {
super.onCreate(savedData);
PopupDialog dialog = getDialog();
if (dialog != null) {
dialog.render();
dialog.show();
} else {
onDialogClose("");
}
@ -36,7 +34,6 @@ public class PopupDialogActivity extends AppCompatActivity {
return switch (popupType) {
case AddWordDialog.TYPE -> new AddWordDialog(this, i, this::onDialogClose);
case AutoUpdateMonolog.TYPE -> new AutoUpdateMonolog(this, i, this::onDialogClose);
case ChangeLanguageDialog.TYPE -> new ChangeLanguageDialog(this, i, this::onDialogClose);
default -> {
Logger.w(LOG_TAG, "Unknown popup type: '" + popupType + "'. Not displaying anything.");
yield null;
@ -53,23 +50,10 @@ public class PopupDialogActivity extends AppCompatActivity {
startService(intent);
}
private void onDialogClose(HashMap<String, String> messages) {
finish();
Intent intent = new Intent(this, TraditionalT9.class);
if (messages != null) {
intent.putExtra(PopupDialog.INTENT_CLOSE, "");
for (String key : messages.keySet()) {
intent.putExtra(key, messages.get(key));
}
}
startService(intent);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
onDialogClose((String) null);
onDialogClose(null);
}
}

View file

@ -37,8 +37,8 @@
</style>
<style name="TTheme.LanguageSelect.RadioButton.Label">
<item name="android:paddingTop">0dp</item>
<item name="android:paddingBottom">0dp</item>
<item name="android:paddingTop">12dp</item>
<item name="android:paddingBottom">12dp</item>
<item name="android:paddingStart">0dp</item>
<item name="android:paddingEnd">0dp</item>
<item name="android:textAppearance">@style/TextAppearance.AppCompat.Widget.PopupMenu.Large</item>