added offical support for Android 15 (upgraded the target and compile SDKs to 35)
This commit is contained in:
parent
d7506e72d9
commit
80d50fb546
14 changed files with 162 additions and 30 deletions
|
|
@ -49,7 +49,7 @@ To support a new language one needs to:
|
|||
- Find a suitable dictionary and add it to the `app/languages/dictionaries/` folder. Two file formats are supported, [see below](#dictionary-formats).
|
||||
- Do not forget to include the dictionary license (or readme) file in the `docs/` folder.
|
||||
- Create a new `.yml` file in `app/languages/definitions/` and define the language properties.
|
||||
- `locale` contains the language and the country codes (e.g. "en-US", "es-AR", "it-IT"). Refer to the list of [supported locales in Java](https://www.oracle.com/java/technologies/javase/jdk8-jre8-suported-locales.html#util-text).
|
||||
- `locale` contains the language and the country codes (e.g. "en-US", "es-AR", "it-IT"). Refer to the list of [supported locales in Java](https://www.oracle.com/java/technologies/javase/jdk17-suported-locales.html#modules).
|
||||
- `dictionaryFile` is the name of the dictionary in `app/languages/dictionaries/` folder.
|
||||
- `layout` contains the letters and punctuation marks associated with each key.
|
||||
- For 0-key `[SPECIAL]`, will be fine in most languages, but you could define your own set of special characters, for example: `[@, #, $]`.
|
||||
|
|
|
|||
|
|
@ -69,12 +69,12 @@ def getVersionString = { flavor -> return flavor == 'debug' ? getDebugVersion()
|
|||
|
||||
android {
|
||||
namespace PACKAGE_NAME
|
||||
compileSdk 34
|
||||
compileSdk 35
|
||||
|
||||
defaultConfig {
|
||||
applicationId PACKAGE_NAME
|
||||
minSdk 19
|
||||
targetSdk 34
|
||||
targetSdk 35
|
||||
versionCode getVerCode()
|
||||
versionName getVerName()
|
||||
}
|
||||
|
|
@ -97,6 +97,10 @@ android {
|
|||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_17
|
||||
targetCompatibility JavaVersion.VERSION_17
|
||||
}
|
||||
|
||||
flavorDimensions = ['app']
|
||||
productFlavors {
|
||||
|
|
|
|||
|
|
@ -230,6 +230,11 @@ public class TraditionalT9 extends MainViewHandler {
|
|||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTimeout(int startId) {
|
||||
onZombie();
|
||||
super.onTimeout(startId);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onNumber(int key, boolean hold, int repeat) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
package io.github.sspanak.tt9.languages;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Deals with inconsistencies between Java and Android language codes.
|
||||
*/
|
||||
class LocaleCompat {
|
||||
private final Locale locale;
|
||||
|
||||
LocaleCompat(Locale locale) {
|
||||
this.locale = locale;
|
||||
}
|
||||
|
||||
private String getCountry() {
|
||||
String country = locale != null ? locale.getCountry() : "";
|
||||
return country.equals("YI") ? "JI" : country;
|
||||
}
|
||||
|
||||
private String getLanguage() {
|
||||
String language = locale != null ? locale.getLanguage() : "";
|
||||
return switch (language) {
|
||||
case "yi" -> "ji";
|
||||
case "he" -> "iw";
|
||||
case "id" -> "in";
|
||||
default -> language;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return (getLanguage() + getCountry()).toUpperCase();
|
||||
}
|
||||
}
|
||||
|
|
@ -134,7 +134,7 @@ public class NaturalLanguage extends Language implements Comparable<NaturalLangu
|
|||
@Override
|
||||
public int getId() {
|
||||
if (id == 0) {
|
||||
String idString = (locale.getLanguage() + locale.getCountry()).toUpperCase();
|
||||
String idString = new LocaleCompat(locale).toString();
|
||||
for (int i = 0; i < idString.length(); i++) {
|
||||
id |= (idString.codePointAt(i) & 31) << (i * 5);
|
||||
}
|
||||
|
|
@ -149,14 +149,11 @@ public class NaturalLanguage extends Language implements Comparable<NaturalLangu
|
|||
return "hi";
|
||||
}
|
||||
|
||||
switch (getLocale().getLanguage()) {
|
||||
case "fi":
|
||||
return "su";
|
||||
case "sw":
|
||||
return "ki";
|
||||
default:
|
||||
return getLocale().toString();
|
||||
}
|
||||
return switch (getLocale().getLanguage()) {
|
||||
case "fi" -> "su";
|
||||
case "sw" -> "ki";
|
||||
default -> getLocale().toString();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -60,6 +60,13 @@ public class PreferencesActivity extends ActivityWithNavigation implements Prefe
|
|||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
preventEdgeToEdge(findViewById(R.id.preferences_container));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceStartFragment(@NonNull PreferenceFragmentCompat caller, @NonNull Preference pref) {
|
||||
BaseScreenFragment fragment = getScreen((getScreenName(pref)));
|
||||
|
|
@ -68,6 +75,7 @@ public class PreferencesActivity extends ActivityWithNavigation implements Prefe
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
|
|
|||
|
|
@ -84,7 +84,6 @@ abstract public class BaseScreenFragment extends PreferenceFragmentCompat {
|
|||
}
|
||||
|
||||
|
||||
|
||||
public void resetFontSize(boolean reloadList) {
|
||||
initPreferencesList();
|
||||
preferencesList.getAll(reloadList, true);
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import android.view.inputmethod.InputConnection;
|
|||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
|
|
@ -17,7 +16,7 @@ import io.github.sspanak.tt9.ime.helpers.Key;
|
|||
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
|
||||
import io.github.sspanak.tt9.util.Logger;
|
||||
|
||||
abstract public class ActivityWithNavigation extends AppCompatActivity {
|
||||
abstract public class ActivityWithNavigation extends EdgeToEdgeActivity {
|
||||
public static final String LOG_TAG = ActivityWithNavigation.class.getSimpleName();
|
||||
|
||||
protected SettingsStore settings;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
package io.github.sspanak.tt9.ui;
|
||||
|
||||
import android.os.Build;
|
||||
import android.view.View;
|
||||
import android.view.WindowInsets;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
|
||||
public class EdgeToEdgeActivity extends AppCompatActivity {
|
||||
public void preventEdgeToEdge(View view) {
|
||||
if (view == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM) {
|
||||
return;
|
||||
}
|
||||
|
||||
WindowInsets insets = getInsets(view);
|
||||
if (insets == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
view.setPadding(
|
||||
insets.getStableInsetLeft(),
|
||||
insets.getStableInsetTop(),
|
||||
insets.getStableInsetRight(),
|
||||
insets.getStableInsetBottom()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
applyThemeToSystemUi();
|
||||
}
|
||||
|
||||
private void applyThemeToSystemUi() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
getWindow().setStatusBarContrastEnforced(true);
|
||||
}
|
||||
}
|
||||
|
||||
private WindowInsets getInsets(View view) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
||||
return null;
|
||||
}
|
||||
|
||||
WindowInsets newInsets = view != null ? view.getRootWindowInsets() : null;
|
||||
return newInsets == null ? getWindow().getDecorView().getRootWindowInsets() : newInsets;
|
||||
}
|
||||
}
|
||||
|
|
@ -2,19 +2,36 @@ package io.github.sspanak.tt9.ui;
|
|||
|
||||
import android.os.Bundle;
|
||||
import android.util.Base64;
|
||||
import android.view.View;
|
||||
import android.webkit.WebView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
abstract public class WebViewActivity extends AppCompatActivity {
|
||||
abstract public class WebViewActivity extends EdgeToEdgeActivity implements View.OnAttachStateChangeListener {
|
||||
private WebView container;
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
buildLayout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewAttachedToWindow(@NonNull View view) {
|
||||
preventEdgeToEdge((View) view.getParent());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewDetachedFromWindow(@NonNull View view) {}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
container.removeOnAttachStateChangeListener(this);
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSupportNavigateUp() {
|
||||
finish();
|
||||
|
|
@ -35,7 +52,8 @@ abstract public class WebViewActivity extends AppCompatActivity {
|
|||
}
|
||||
|
||||
private void setContent() {
|
||||
WebView container = new WebView(this);
|
||||
container = new WebView(this);
|
||||
container.addOnAttachStateChangeListener(this);
|
||||
|
||||
// On API > 30 the WebView does not load the entire String with .loadData(),
|
||||
// so we need to do this weird shit.
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
package io.github.sspanak.tt9.ui.main;
|
||||
|
||||
import android.os.Build;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowInsets;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
|
|
@ -60,6 +62,21 @@ abstract class BaseMainLayout {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculate the bottom padding for the edge-to-edge mode in Android 15+. Without padding,
|
||||
* the bottom of the View will be cut off by the system navigation bar.
|
||||
*/
|
||||
protected int getBottomInsetSize() {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM || tt9 == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
final int DEFAULT_SIZE = 96;
|
||||
WindowInsets insets = tt9.getWindow().findViewById(android.R.id.content).getRootWindowInsets();
|
||||
return insets != null ? insets.getStableInsetBottom() : DEFAULT_SIZE;
|
||||
}
|
||||
|
||||
|
||||
protected void enableClickHandlers() {
|
||||
for (SoftKey key : getKeys()) {
|
||||
key.setTT9(tt9);
|
||||
|
|
|
|||
|
|
@ -203,7 +203,8 @@ class MainLayoutNumpad extends BaseMainLayout {
|
|||
Resources resources = tt9.getResources();
|
||||
height = getKeyHeightCompat() * 4
|
||||
+ resources.getDimensionPixelSize(R.dimen.numpad_candidate_height)
|
||||
+ resources.getDimensionPixelSize(R.dimen.numpad_padding_bottom) * 4;
|
||||
+ Math.round(resources.getDimension(R.dimen.numpad_padding_bottom))
|
||||
+ getBottomInsetSize();
|
||||
}
|
||||
|
||||
return height;
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ class MainLayoutTray extends BaseMainLayout {
|
|||
int getHeight(boolean forceRecalculate) {
|
||||
if (height <= 0 || forceRecalculate) {
|
||||
Resources resources = tt9.getResources();
|
||||
height = resources.getDimensionPixelSize(R.dimen.candidate_height);
|
||||
height = resources.getDimensionPixelSize(R.dimen.candidate_height) + getBottomInsetSize();
|
||||
|
||||
if (isCommandPaletteShown() || isTextEditingPaletteShown()) {
|
||||
height += resources.getDimensionPixelSize(R.dimen.numpad_key_height);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package io.github.sspanak.tt9.ui.main;
|
||||
|
||||
import android.os.Build;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
|
@ -29,9 +30,11 @@ public class ResizableMainView extends MainView implements View.OnAttachStateCha
|
|||
|
||||
|
||||
private void calculateSnapHeights() {
|
||||
heightNumpad = new MainLayoutNumpad(tt9).getHeight();
|
||||
heightSmall = new MainLayoutSmall(tt9).getHeight();
|
||||
heightTray = new MainLayoutTray(tt9).getHeight();
|
||||
boolean forceRecalculate = Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM;
|
||||
|
||||
heightNumpad = new MainLayoutNumpad(tt9).getHeight(forceRecalculate);
|
||||
heightSmall = new MainLayoutSmall(tt9).getHeight(forceRecalculate);
|
||||
heightTray = new MainLayoutTray(tt9).getHeight(forceRecalculate);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -55,13 +58,7 @@ public class ResizableMainView extends MainView implements View.OnAttachStateCha
|
|||
}
|
||||
}
|
||||
|
||||
private void onCreateAdjustHeight() {
|
||||
if (tt9.getSettings().isMainLayoutNumpad() && height > heightSmall && height <= heightNumpad) {
|
||||
setHeight(height, heightSmall, heightNumpad);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void onViewAttachedToWindow(@NonNull View v) { onCreateAdjustHeight(); }
|
||||
@Override public void onViewAttachedToWindow(@NonNull View v) { setHeight(height, heightSmall, heightNumpad); }
|
||||
@Override public void onViewDetachedFromWindow(@NonNull View v) {}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue