the Settings screen now follows the Dynamic Color theme on Android 12 and higher
This commit is contained in:
parent
28801ba95b
commit
ada5261773
19 changed files with 286 additions and 63 deletions
|
|
@ -163,6 +163,7 @@ android {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
implementation 'com.google.android.material:material:1.12.0'
|
||||||
implementation 'androidx.preference:preference:1.2.1'
|
implementation 'androidx.preference:preference:1.2.1'
|
||||||
implementation 'androidx.constraintlayout:constraintlayout:2.2.0'
|
implementation 'androidx.constraintlayout:constraintlayout:2.2.0'
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
<application
|
<application
|
||||||
android:icon="@drawable/ic_launcher"
|
android:icon="@drawable/ic_launcher"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:theme="@style/TT9Theme"
|
android:theme="@style/TTheme"
|
||||||
android:supportsRtl="true">
|
android:supportsRtl="true">
|
||||||
|
|
||||||
<service android:name="io.github.sspanak.tt9.ime.TraditionalT9" android:permission="android.permission.BIND_INPUT_METHOD"
|
<service android:name="io.github.sspanak.tt9.ime.TraditionalT9" android:permission="android.permission.BIND_INPUT_METHOD"
|
||||||
|
|
@ -42,7 +42,7 @@
|
||||||
android:excludeFromRecents="true"
|
android:excludeFromRecents="true"
|
||||||
android:label=""
|
android:label=""
|
||||||
android:name="io.github.sspanak.tt9.ui.dialogs.PopupDialogActivity"
|
android:name="io.github.sspanak.tt9.ui.dialogs.PopupDialogActivity"
|
||||||
android:theme="@style/alertDialog" />
|
android:theme="@style/TTheme.AddWord" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:label="@string/pref_help"
|
android:label="@string/pref_help"
|
||||||
|
|
|
||||||
|
|
@ -47,11 +47,11 @@ abstract public class ScreenPreference extends Preference {
|
||||||
if (pref instanceof PreferenceCategory) {
|
if (pref instanceof PreferenceCategory) {
|
||||||
return R.layout.pref_category;
|
return R.layout.pref_category;
|
||||||
} else if (pref instanceof SwitchPreferenceCompat) {
|
} else if (pref instanceof SwitchPreferenceCompat) {
|
||||||
return R.layout.pref_switch;
|
return R.layout.pref_switch_large;
|
||||||
} else if (pref instanceof DropDownPreference) {
|
} else if (pref instanceof DropDownPreference) {
|
||||||
return R.layout.pref_dropdown;
|
return R.layout.pref_dropdown;
|
||||||
} else {
|
} else {
|
||||||
return R.layout.pref_text;
|
return R.layout.pref_default_large;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
package io.github.sspanak.tt9.preferences.items;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.preference.PreferenceViewHolder;
|
||||||
|
|
||||||
|
import com.google.android.material.search.SearchView;
|
||||||
|
|
||||||
|
import io.github.sspanak.tt9.R;
|
||||||
|
|
||||||
|
abstract public class ItemSearch extends ItemTextInput {
|
||||||
|
private final boolean isModernDevice = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S;
|
||||||
|
|
||||||
|
|
||||||
|
public ItemSearch(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||||
|
super(context, attrs, defStyleAttr, defStyleRes);
|
||||||
|
}
|
||||||
|
public ItemSearch(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||||
|
super(context, attrs, defStyleAttr);
|
||||||
|
}
|
||||||
|
public ItemSearch(@NonNull Context context, @Nullable AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
}
|
||||||
|
public ItemSearch(@NonNull Context context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override protected int getDefaultLayout() {
|
||||||
|
return isModernDevice ? R.layout.pref_search_v31 : R.layout.pref_input_text;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override protected int getLargeLayout() {
|
||||||
|
return isModernDevice ? R.layout.pref_search_v31 : R.layout.pref_input_text_large;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected void setTextField(@NonNull PreferenceViewHolder holder) {
|
||||||
|
if (!isModernDevice) {
|
||||||
|
super.setTextField(holder);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchView searchView = holder.itemView.findViewById(R.id.search_view);
|
||||||
|
if (searchView != null) {
|
||||||
|
this.textField = searchView.getEditText();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,11 +3,8 @@ package io.github.sspanak.tt9.preferences.items;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.text.Editable;
|
|
||||||
import android.text.TextWatcher;
|
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.View;
|
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
@ -17,70 +14,86 @@ import androidx.preference.PreferenceViewHolder;
|
||||||
import io.github.sspanak.tt9.R;
|
import io.github.sspanak.tt9.R;
|
||||||
import io.github.sspanak.tt9.preferences.custom.ScreenPreference;
|
import io.github.sspanak.tt9.preferences.custom.ScreenPreference;
|
||||||
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
|
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
|
||||||
import io.github.sspanak.tt9.util.Logger;
|
|
||||||
|
|
||||||
abstract public class ItemTextInput extends ScreenPreference implements TextWatcher {
|
abstract public class ItemTextInput extends ScreenPreference {
|
||||||
@NonNull private final Handler debouncer = new Handler(Looper.getMainLooper());
|
@NonNull private final Handler listener = new Handler(Looper.getMainLooper());
|
||||||
private EditText editText;
|
protected EditText textField;
|
||||||
|
@NonNull protected String text = "";
|
||||||
|
|
||||||
|
|
||||||
public ItemTextInput(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
public ItemTextInput(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||||
super(context, attrs, defStyleAttr, defStyleRes);
|
super(context, attrs, defStyleAttr, defStyleRes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ItemTextInput(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
public ItemTextInput(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||||
super(context, attrs, defStyleAttr);
|
super(context, attrs, defStyleAttr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ItemTextInput(@NonNull Context context, @Nullable AttributeSet attrs) {
|
public ItemTextInput(@NonNull Context context, @Nullable AttributeSet attrs) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ItemTextInput(@NonNull Context context) {
|
public ItemTextInput(@NonNull Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(@NonNull PreferenceViewHolder holder) {
|
public void onBindViewHolder(@NonNull PreferenceViewHolder holder) {
|
||||||
super.onBindViewHolder(holder);
|
super.onBindViewHolder(holder);
|
||||||
EditText editText = holder.itemView.findViewById(R.id.input_text_input_field);
|
setTextField(holder);
|
||||||
if (editText == null) {
|
if (textField != null) {
|
||||||
Logger.e(getClass().getSimpleName(), "Cannot attach a text change listener. Unable to find the EditText element.");
|
ignoreEnter();
|
||||||
} else {
|
checkTextChange();
|
||||||
this.editText = editText;
|
|
||||||
editText.addTextChangedListener(this);
|
|
||||||
editText.setOnKeyListener(this::ignoreEnter);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override protected int getDefaultLayout() { return R.layout.pref_input_text; }
|
@Override protected int getDefaultLayout() { return R.layout.pref_input_text; }
|
||||||
@Override protected int getLargeLayout() { return R.layout.pref_input_text_large; }
|
@Override protected int getLargeLayout() { return R.layout.pref_input_text_large; }
|
||||||
|
|
||||||
@Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
|
|
||||||
@Override public void onTextChanged(CharSequence s, int start, int before, int count) {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterTextChanged(Editable s) {
|
|
||||||
debouncer.removeCallbacksAndMessages(null);
|
|
||||||
debouncer.postDelayed(() -> onChange(s.toString()), getChangeHandlerDebounceTime());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int getChangeHandlerDebounceTime() {
|
protected int getChangeHandlerDebounceTime() {
|
||||||
return SettingsStore.TEXT_INPUT_DEBOUNCE_TIME;
|
return SettingsStore.TEXT_INPUT_DEBOUNCE_TIME;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setText(CharSequence text) {
|
|
||||||
|
protected void setTextField(@NonNull PreferenceViewHolder holder) {
|
||||||
|
EditText editText = holder.itemView.findViewById(R.id.input_text_input_field);
|
||||||
if (editText != null) {
|
if (editText != null) {
|
||||||
editText.setText(text);
|
this.textField = editText;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected void setText(CharSequence newText) {
|
||||||
|
if (textField != null && newText != null && !text.equals(newText.toString())) {
|
||||||
|
textField.setText(newText);
|
||||||
|
text = newText.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal text change detector that calls the onTextChange() when needed.
|
||||||
|
* IMPORTANT: do not call this method more than once per instance to avoid creating multiple
|
||||||
|
* listeners and memory leaks.
|
||||||
|
*/
|
||||||
|
private void checkTextChange() {
|
||||||
|
String newText = textField != null ? textField.getText().toString() : "";
|
||||||
|
if (!text.equals(newText)) {
|
||||||
|
text = newText;
|
||||||
|
onTextChange();
|
||||||
|
}
|
||||||
|
listener.postDelayed(this::checkTextChange, getChangeHandlerDebounceTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This prevents IllegalStateException "focus search returned a view that wasn't able to take focus!",
|
* This prevents IllegalStateException "focus search returned a view that wasn't able to take focus!",
|
||||||
* which is thrown when the EditText is focused and it receives a simulated ENTER key event.
|
* which is thrown when the EditText is focused and it receives a simulated ENTER key event.
|
||||||
*/
|
*/
|
||||||
private boolean ignoreEnter(View v, int keyCode, KeyEvent e) {
|
private void ignoreEnter() {
|
||||||
return keyCode == KeyEvent.KEYCODE_ENTER;
|
textField.setOnKeyListener((v, keyCode, e) -> keyCode == KeyEvent.KEYCODE_ENTER);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract void onChange(String word);
|
|
||||||
|
abstract protected void onTextChange();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,12 @@ import androidx.annotation.Nullable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import io.github.sspanak.tt9.db.DataStore;
|
import io.github.sspanak.tt9.db.DataStore;
|
||||||
import io.github.sspanak.tt9.preferences.items.ItemTextInput;
|
import io.github.sspanak.tt9.preferences.items.ItemSearch;
|
||||||
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
|
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
|
||||||
import io.github.sspanak.tt9.util.ConsumerCompat;
|
import io.github.sspanak.tt9.util.ConsumerCompat;
|
||||||
import io.github.sspanak.tt9.util.Logger;
|
import io.github.sspanak.tt9.util.Logger;
|
||||||
|
|
||||||
public class PreferenceSearchWords extends ItemTextInput {
|
public class PreferenceSearchWords extends ItemSearch {
|
||||||
public static final String NAME = "dictionary_delete_words_search";
|
public static final String NAME = "dictionary_delete_words_search";
|
||||||
private static final String LOG_TAG = PreferenceSearchWords.class.getSimpleName();
|
private static final String LOG_TAG = PreferenceSearchWords.class.getSimpleName();
|
||||||
|
|
||||||
|
|
@ -31,17 +31,15 @@ public class PreferenceSearchWords extends ItemTextInput {
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onChange(String word) {
|
protected void onTextChange() {
|
||||||
search(word);
|
search(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public String getLastSearchTerm() {
|
public String getLastSearchTerm() {
|
||||||
return lastSearchTerm;
|
return lastSearchTerm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void search(String word) {
|
void search(String word) {
|
||||||
lastSearchTerm = word == null || word.trim().isEmpty() ? "" : word.trim();
|
lastSearchTerm = word == null || word.trim().isEmpty() ? "" : word.trim();
|
||||||
|
|
||||||
|
|
@ -56,7 +54,6 @@ public class PreferenceSearchWords extends ItemTextInput {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void setOnWordsHandler(ConsumerCompat<ArrayList<String>> onWords) {
|
void setOnWordsHandler(ConsumerCompat<ArrayList<String>> onWords) {
|
||||||
this.onWords = onWords;
|
this.onWords = onWords;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,37 +9,37 @@ import androidx.preference.Preference;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import io.github.sspanak.tt9.preferences.items.ItemTextInput;
|
import io.github.sspanak.tt9.preferences.items.ItemSearch;
|
||||||
|
|
||||||
public class PreferenceSearchLanguage extends ItemTextInput {
|
public class PreferenceSearchLanguage extends ItemSearch {
|
||||||
@NonNull private ArrayList<PreferenceSwitchLanguage> languageItems = new ArrayList<>();
|
@NonNull private ArrayList<PreferenceSwitchLanguage> languageItems = new ArrayList<>();
|
||||||
private Preference noResultItem;
|
private Preference noResultItem;
|
||||||
|
|
||||||
|
|
||||||
public PreferenceSearchLanguage(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
public PreferenceSearchLanguage(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||||
super(context, attrs, defStyleAttr, defStyleRes);
|
super(context, attrs, defStyleAttr, defStyleRes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PreferenceSearchLanguage(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
public PreferenceSearchLanguage(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||||
super(context, attrs, defStyleAttr);
|
super(context, attrs, defStyleAttr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PreferenceSearchLanguage(@NonNull Context context, @Nullable AttributeSet attrs) {
|
public PreferenceSearchLanguage(@NonNull Context context, @Nullable AttributeSet attrs) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PreferenceSearchLanguage(@NonNull Context context) {
|
public PreferenceSearchLanguage(@NonNull Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void showNoResultItem(boolean show) {
|
private void showNoResultItem(boolean show) {
|
||||||
if (noResultItem != null) {
|
if (noResultItem != null) {
|
||||||
noResultItem.setVisible(show);
|
noResultItem.setVisible(show);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onChange(String word) {
|
protected void onTextChange() {
|
||||||
word = word == null ? "" : word.trim().toLowerCase();
|
String word = text.trim().toLowerCase();
|
||||||
String wordInTheMiddle = " " + word;
|
String wordInTheMiddle = " " + word;
|
||||||
String wordInParenthesis = "(" + word;
|
String wordInParenthesis = "(" + word;
|
||||||
|
|
||||||
|
|
@ -63,11 +63,13 @@ public class PreferenceSearchLanguage extends ItemTextInput {
|
||||||
showNoResultItem(visibleLanguages == 0);
|
showNoResultItem(visibleLanguages == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PreferenceSearchLanguage setLanguageItems(@NonNull ArrayList<PreferenceSwitchLanguage> languageItems) {
|
PreferenceSearchLanguage setLanguageItems(@NonNull ArrayList<PreferenceSwitchLanguage> languageItems) {
|
||||||
this.languageItems = languageItems;
|
this.languageItems = languageItems;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void setNoResultItem(Preference noResultItem) {
|
void setNoResultItem(Preference noResultItem) {
|
||||||
this.noResultItem = noResultItem;
|
this.noResultItem = noResultItem;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,8 +48,8 @@ abstract class AbstractPreferenceCharList extends ItemTextInput {
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onChange(String word) {
|
protected void onTextChange() {
|
||||||
currentChars = word == null ? "" : word;
|
currentChars = text;
|
||||||
validateCurrentChars();
|
validateCurrentChars();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -78,7 +78,7 @@ abstract class AbstractPreferenceCharList extends ItemTextInput {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setText(optional.toString());
|
setText(currentChars = optional.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,15 @@ import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.inputmethodservice.InputMethodService;
|
import android.inputmethodservice.InputMethodService;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.view.inputmethod.InputMethodManager;
|
import android.view.inputmethod.InputMethodManager;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
import io.github.sspanak.tt9.preferences.PreferencesActivity;
|
import io.github.sspanak.tt9.preferences.PreferencesActivity;
|
||||||
|
|
@ -23,6 +26,7 @@ public class UI {
|
||||||
((InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE)).showInputMethodPicker();
|
((InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE)).showInputMethodPicker();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static boolean showSystemSpellCheckerSettings(Context context) {
|
public static boolean showSystemSpellCheckerSettings(Context context) {
|
||||||
ComponentName component = new ComponentName(
|
ComponentName component = new ComponentName(
|
||||||
"com.android.settings",
|
"com.android.settings",
|
||||||
|
|
@ -50,20 +54,33 @@ public class UI {
|
||||||
ims.startActivity(prefIntent);
|
ims.startActivity(prefIntent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void confirm(Context context, String title, String message, String OKLabel, Runnable onOk, Runnable onCancel) {
|
public static void confirm(Context context, String title, String message, String OKLabel, Runnable onOk, Runnable onCancel) {
|
||||||
new AlertDialog.Builder(context)
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
|
||||||
.setTitle(title)
|
new AlertDialog.Builder(context)
|
||||||
.setMessage(message)
|
.setTitle(title)
|
||||||
.setPositiveButton(OKLabel, (dialog, whichButton) -> { if (onOk != null) onOk.run(); })
|
.setMessage(message)
|
||||||
.setNegativeButton(android.R.string.cancel, (dialog, whichButton) -> { if (onCancel != null) onCancel.run(); })
|
.setPositiveButton(OKLabel, (dialog, whichButton) -> { if (onOk != null) onOk.run(); })
|
||||||
.setCancelable(false)
|
.setNegativeButton(android.R.string.cancel, (dialog, whichButton) -> { if (onCancel != null) onCancel.run(); })
|
||||||
.show();
|
.setCancelable(false)
|
||||||
|
.show();
|
||||||
|
} else {
|
||||||
|
new MaterialAlertDialogBuilder(context)
|
||||||
|
.setTitle(title)
|
||||||
|
.setMessage(message)
|
||||||
|
.setPositiveButton(OKLabel, (dialog, whichButton) -> { if (onOk != null) onOk.run(); })
|
||||||
|
.setNegativeButton(android.R.string.cancel, (dialog, whichButton) -> { if (onCancel != null) onCancel.run(); })
|
||||||
|
.setCancelable(false)
|
||||||
|
.show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void toast(Context context, CharSequence msg) {
|
public static void toast(Context context, CharSequence msg) {
|
||||||
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
|
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void toastFromAsync(Context context, CharSequence msg) {
|
public static void toastFromAsync(Context context, CharSequence msg) {
|
||||||
if (Looper.myLooper() == null) {
|
if (Looper.myLooper() == null) {
|
||||||
Looper.prepare();
|
Looper.prepare();
|
||||||
|
|
@ -71,10 +88,12 @@ public class UI {
|
||||||
toast(context, msg);
|
toast(context, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void toast(Context context, int resourceId) {
|
public static void toast(Context context, int resourceId) {
|
||||||
Toast.makeText(context, resourceId, Toast.LENGTH_SHORT).show();
|
Toast.makeText(context, resourceId, Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void toastFromAsync(Context context, int resourceId) {
|
public static void toastFromAsync(Context context, int resourceId) {
|
||||||
if (Looper.myLooper() == null) {
|
if (Looper.myLooper() == null) {
|
||||||
Looper.prepare();
|
Looper.prepare();
|
||||||
|
|
@ -82,14 +101,17 @@ public class UI {
|
||||||
toast(context, resourceId);
|
toast(context, resourceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void toastLong(Context context, int resourceId) {
|
public static void toastLong(Context context, int resourceId) {
|
||||||
Toast.makeText(context, resourceId, Toast.LENGTH_LONG).show();
|
Toast.makeText(context, resourceId, Toast.LENGTH_LONG).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void toastLong(Context context, CharSequence msg) {
|
public static void toastLong(Context context, CharSequence msg) {
|
||||||
Toast.makeText(context, msg, Toast.LENGTH_LONG).show();
|
Toast.makeText(context, msg, Toast.LENGTH_LONG).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void toastLongFromAsync(Context context, CharSequence msg) {
|
public static void toastLongFromAsync(Context context, CharSequence msg) {
|
||||||
if (Looper.myLooper() == null) {
|
if (Looper.myLooper() == null) {
|
||||||
Looper.prepare();
|
Looper.prepare();
|
||||||
|
|
@ -97,6 +119,7 @@ public class UI {
|
||||||
toastLong(context, msg);
|
toastLong(context, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void toastSingle(@NonNull Context context, @NonNull String uniqueId, @NonNull String message, boolean isShort) {
|
public static void toastSingle(@NonNull Context context, @NonNull String uniqueId, @NonNull String message, boolean isShort) {
|
||||||
Toast toast = singleToasts.get(uniqueId);
|
Toast toast = singleToasts.get(uniqueId);
|
||||||
|
|
||||||
|
|
@ -111,14 +134,17 @@ public class UI {
|
||||||
singleToasts.put(uniqueId, toast);
|
singleToasts.put(uniqueId, toast);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void toastShortSingle(@NonNull Context context, @NonNull String uniqueId, @NonNull String message) {
|
public static void toastShortSingle(@NonNull Context context, @NonNull String uniqueId, @NonNull String message) {
|
||||||
toastSingle(context, uniqueId, message, true);
|
toastSingle(context, uniqueId, message, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void toastShortSingle(@NonNull Context context, int resourceId) {
|
public static void toastShortSingle(@NonNull Context context, int resourceId) {
|
||||||
toastSingle(context, String.valueOf(resourceId), context.getString(resourceId), true);
|
toastSingle(context, String.valueOf(resourceId), context.getString(resourceId), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void toastLongSingle(@NonNull Context context, int resourceId) {
|
public static void toastLongSingle(@NonNull Context context, int resourceId) {
|
||||||
toastSingle(context, String.valueOf(resourceId), context.getString(resourceId), false);
|
toastSingle(context, String.valueOf(resourceId), context.getString(resourceId), false);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ abstract class BaseMainLayout {
|
||||||
// Adding the ContextThemeWrapper fixes this error log:
|
// Adding the ContextThemeWrapper fixes this error log:
|
||||||
// "View class SoftKeyXXX is an AppCompat widget that can only be used with a
|
// "View class SoftKeyXXX is an AppCompat widget that can only be used with a
|
||||||
// Theme.AppCompat theme (or descendant)."
|
// Theme.AppCompat theme (or descendant)."
|
||||||
ContextThemeWrapper themedCtx = new ContextThemeWrapper(tt9, R.style.TT9Theme);
|
ContextThemeWrapper themedCtx = new ContextThemeWrapper(tt9, R.style.TTheme);
|
||||||
view = View.inflate(themedCtx, xml, null);
|
view = View.inflate(themedCtx, xml, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@android:id/title"
|
android:id="@android:id/title"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:labelFor="@id/input_text_input_field"
|
android:labelFor="@id/input_text_input_field"
|
||||||
android:text="?android:title" />
|
android:text="?android:title" />
|
||||||
|
|
|
||||||
23
app/src/main/res/layout/pref_search_v31.xml
Normal file
23
app/src/main/res/layout/pref_search_v31.xml
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="@dimen/preference_search_height">
|
||||||
|
|
||||||
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
<com.google.android.material.search.SearchBar
|
||||||
|
android:id="@+id/search_bar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.search.SearchView
|
||||||
|
android:id="@+id/search_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:layout_anchor="@id/search_bar" />
|
||||||
|
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
11
app/src/main/res/layout/pref_switch_v31.xml
Normal file
11
app/src/main/res/layout/pref_switch_v31.xml
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<!-- Derived from https://github.com/androidx/androidx/blob/8cb282cc/preference/preference/res/layout/preference_widget_switch_compat.xml -->
|
||||||
|
<!-- Thanks to https://stackoverflow.com/a/73782598 -->
|
||||||
|
<com.google.android.material.materialswitch.MaterialSwitch xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/switchWidget"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:focusable="false"
|
||||||
|
android:clickable="false"
|
||||||
|
android:background="@null" />
|
||||||
41
app/src/main/res/values-night-v31/styles.xml
Normal file
41
app/src/main/res/values-night-v31/styles.xml
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<style name="TTheme" parent="Theme.Material3.DynamicColors.Dark">
|
||||||
|
<item name="preferenceTheme">@style/PreferenceOverlay</item>
|
||||||
|
|
||||||
|
<!-- title bar -->
|
||||||
|
<item name="tint">@color/material_dynamic_neutral90</item> <!-- back button color -->
|
||||||
|
<item name="colorOnSurface">@color/material_dynamic_neutral90</item> <!-- title text color -->
|
||||||
|
<item name="colorSurfaceContainer">@color/material_dynamic_neutral_variant30</item> <!-- title background -->
|
||||||
|
|
||||||
|
<!-- page -->
|
||||||
|
<item name="android:windowBackground">@color/material_dynamic_neutral10</item> <!-- page background -->
|
||||||
|
<item name="colorSecondary">@color/material_dynamic_primary70</item> <!-- category title -->
|
||||||
|
<item name="android:textAppearanceListItem">@style/TextAppearance.Material3.TitleLarge</item> <!-- preference title -->
|
||||||
|
<!-- <item name="android:popupMenuStyle">@style/AppDropDownStyle</item> <!– dropdown background –>-->
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="PreferenceOverlay" parent="@style/PreferenceThemeOverlay">
|
||||||
|
<item name="switchPreferenceCompatStyle">@style/AppSwitchStyle</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!-- <style name="AppDropDownStyle" parent="Widget.AppCompat.ListPopupWindow">-->
|
||||||
|
<!-- <item name="android:background">@color/material_dynamic_neutral_variant30</item>-->
|
||||||
|
<!-- <item name="popupMenuBackground">@color/material_dynamic_neutral_variant30</item>-->
|
||||||
|
<!-- </style>-->
|
||||||
|
|
||||||
|
<style name="AppSwitchStyle" parent="@style/Preference.SwitchPreferenceCompat.Material">
|
||||||
|
<item name="widgetLayout">@layout/pref_switch_v31</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="TTheme.AddWord" parent="Theme.Material3.Dark.Dialog.Alert">
|
||||||
|
<item name="windowNoTitle">true</item> <!-- hide some weird floating rectangle above the dialog -->
|
||||||
|
<item name="android:textColor">@color/material_dynamic_neutral99</item> <!-- headline (title) text color -->
|
||||||
|
<item name="android:textColorPrimary">@color/material_dynamic_neutral_variant95</item> <!-- supporting text (body text) color -->
|
||||||
|
<item name="android:background">@color/material_dynamic_neutral20</item> <!-- container background -->
|
||||||
|
<item name="colorPrimary">@color/material_dynamic_primary90</item> <!-- label text (button text) color -->
|
||||||
|
|
||||||
|
<item name="textAppearanceBodyMedium">@style/TextAppearance.AppCompat.Widget.PopupMenu.Large</item> <!-- body text size -->
|
||||||
|
<item name="textAppearanceLabelLarge">@style/TextAppearance.MaterialComponents.Button</item> <!-- button text size -->
|
||||||
|
</style>
|
||||||
|
</resources>
|
||||||
54
app/src/main/res/values-v31/styles.xml
Normal file
54
app/src/main/res/values-v31/styles.xml
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<style name="TTheme" parent="Theme.Material3.DynamicColors.Light">
|
||||||
|
<item name="preferenceTheme">@style/PreferenceOverlay</item>
|
||||||
|
|
||||||
|
<!-- title bar -->
|
||||||
|
<item name="tint">@color/material_dynamic_neutral20</item> <!-- back button color -->
|
||||||
|
<item name="colorSurfaceContainer">@color/material_dynamic_neutral_variant90</item> <!-- title bar background -->
|
||||||
|
|
||||||
|
<!-- page -->
|
||||||
|
<item name="android:windowBackground">@color/material_dynamic_neutral95</item> <!-- page background -->
|
||||||
|
<item name="colorSecondary">@color/material_dynamic_primary40</item> <!-- category title -->
|
||||||
|
<item name="android:textAppearanceListItem">@style/TextAppearance.Material3.TitleLarge</item> <!-- preference title -->
|
||||||
|
|
||||||
|
<!-- <item name="android:popupWindowStyle">@style/AppDropDownStyle</item> <!– dropdown background –>-->
|
||||||
|
|
||||||
|
<!--
|
||||||
|
// ANY PREFERENCE
|
||||||
|
android:textColor = preference text color
|
||||||
|
android:textColorSecondary = preference summary color
|
||||||
|
|
||||||
|
// SWITCH
|
||||||
|
colorOutline = switch outline
|
||||||
|
colorSurfaceContainerHighest = switch background when off
|
||||||
|
colorPrimary = switch background when on
|
||||||
|
colorOnPrimary = switch handle color
|
||||||
|
colorPrimaryContainer = switch handle color when moving
|
||||||
|
-->
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="PreferenceOverlay" parent="@style/PreferenceThemeOverlay">
|
||||||
|
<item name="switchPreferenceCompatStyle">@style/AppSwitchStyle</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="AppSwitchStyle" parent="@style/Preference.SwitchPreferenceCompat.Material">
|
||||||
|
<item name="widgetLayout">@layout/pref_switch_v31</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!-- <style name="AppDropDownStyle" parent="Widget.Material3.PopupMenu.ListPopupWindow">-->
|
||||||
|
<!-- <item name="android:background">@color/material_dynamic_neutral_variant90</item>-->
|
||||||
|
<!-- <item name="popupMenuBackground">@color/material_dynamic_neutral_variant90</item>-->
|
||||||
|
<!-- </style>-->
|
||||||
|
|
||||||
|
<style name="TTheme.AddWord" parent="Theme.Material3.Light.Dialog.Alert">
|
||||||
|
<item name="windowNoTitle">true</item> <!-- hide some weird floating rectangle above the dialog -->
|
||||||
|
<item name="android:textColor">@color/material_dynamic_neutral10</item> <!-- headline (title) text color -->
|
||||||
|
<item name="android:textColorPrimary">@color/material_dynamic_neutral_variant10</item> <!-- supporting text (body text) color -->
|
||||||
|
<item name="android:background">@color/material_dynamic_neutral95</item> <!-- container background -->
|
||||||
|
<item name="colorPrimary">@color/material_dynamic_primary20</item> <!-- label text (button text) color -->
|
||||||
|
|
||||||
|
<item name="textAppearanceBodyMedium">@style/TextAppearance.AppCompat.Widget.PopupMenu.Large</item> <!-- body text size -->
|
||||||
|
<item name="textAppearanceLabelLarge">@style/TextAppearance.MaterialComponents.Button</item> <!-- button text size -->
|
||||||
|
</style>
|
||||||
|
</resources>
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
<dimen name="candidate_padding_horizontal">6sp</dimen>
|
<dimen name="candidate_padding_horizontal">6sp</dimen>
|
||||||
|
|
||||||
<dimen name="preferences_text_min_height">48dp</dimen>
|
<dimen name="preferences_text_min_height">48dp</dimen>
|
||||||
|
<dimen name="preference_search_height">72dp</dimen>
|
||||||
|
|
||||||
<dimen name="soft_key_height">44dp</dimen>
|
<dimen name="soft_key_height">44dp</dimen>
|
||||||
<dimen name="soft_key_icon_size">24sp</dimen>
|
<dimen name="soft_key_icon_size">24sp</dimen>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<style name="TT9Theme" parent="Theme.AppCompat.DayNight" />
|
<style name="TTheme" parent="Theme.AppCompat.DayNight" />
|
||||||
|
|
||||||
<style name="hSeparator">
|
<style name="hSeparator">
|
||||||
<item name="android:layout_height">match_parent</item>
|
<item name="android:layout_height">match_parent</item>
|
||||||
|
|
@ -22,7 +22,7 @@
|
||||||
<item name="android:layout_width">match_parent</item>
|
<item name="android:layout_width">match_parent</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="alertDialog" parent="Theme.AppCompat.DayNight.Dialog.Alert">
|
<style name="TTheme.AddWord" parent="Theme.AppCompat.DayNight.Dialog.Alert">
|
||||||
<item name="android:windowBackground">@android:color/transparent</item>
|
<item name="windowNoTitle">true</item> <!-- hide some weird floating rectangle above the dialog -->
|
||||||
</style>
|
</style>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue