mirror of
https://github.com/jwinterm/grim.git
synced 2026-10-17 14:21:24 +02:00
android: migrate back to gameactivity, update to API 36, fix back navigation at network panel
This commit is contained in:
Generated
+20
-26
@@ -1498,7 +1498,7 @@ version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81"
|
||||
dependencies = [
|
||||
"unicode-width 0.2.2",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2392,9 +2392,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ecolor"
|
||||
version = "0.33.0"
|
||||
version = "0.33.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adf31f99fad93fe83c1055b92b5c1b135f1ecfa464789817c372000e768d4bd1"
|
||||
checksum = "084980ebede2fb1ad6c4f54285b3e489052ef2b6aa4016e4c19349417adc75c5"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"emath",
|
||||
@@ -2463,9 +2463,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "eframe"
|
||||
version = "0.33.0"
|
||||
version = "0.33.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b829d302a09deb4acde242262a1840ba14fadd0371980ebf713060077a1987bc"
|
||||
checksum = "4f60ee3c69cd01d5725b4ef476ed6a3a6009968c57843a2f1beb96f021e4a54b"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"bytemuck",
|
||||
@@ -2498,9 +2498,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "egui"
|
||||
version = "0.33.0"
|
||||
version = "0.33.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab9b5d3376c79439f53a78bf7da1e3c0b862ffa3e29f46ab0f3e107430f2e576"
|
||||
checksum = "b75645894de4ca1695ab3ab7201c7953bb95c1725aafeefa6822dc901ad2a81b"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"bitflags 2.10.0",
|
||||
@@ -2515,9 +2515,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "egui-wgpu"
|
||||
version = "0.33.0"
|
||||
version = "0.33.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cef1fe83ba30b3d045814b2d811804f2a7e50a832034c975408f71c20df596e4"
|
||||
checksum = "acdaac35a6e0ff458aaa5776b2bda578e38334a9d1258f7795042a70372745b7"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"bytemuck",
|
||||
@@ -2535,9 +2535,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "egui-winit"
|
||||
version = "0.33.0"
|
||||
version = "0.33.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb4ea8cb063c00d8f23ce11279c01eb63a195a72be0e21d429148246dab7983e"
|
||||
checksum = "4772ed5f16fa8ec2ba295e58f62b58ee83fcf49e67ec13d2b7ddf4e9a2dea34e"
|
||||
dependencies = [
|
||||
"arboard",
|
||||
"bytemuck",
|
||||
@@ -2556,9 +2556,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "egui_extras"
|
||||
version = "0.33.0"
|
||||
version = "0.33.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bdced1964ad8a02a116b1307f7b4f73dbe408c5f53dcdd488f527609f261da60"
|
||||
checksum = "550e844e608e356f4ad6843c510aa9bb5838b427e4700ed0056e9746ceeed866"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"egui",
|
||||
@@ -2572,9 +2572,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "egui_glow"
|
||||
version = "0.33.0"
|
||||
version = "0.33.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "668c0d4f726cc33838f0915f6b8c00af0ca0910e975ab58cf34b3e39c614552c"
|
||||
checksum = "17b94ff67a1d18933fff2519f5f57c388f932c093036c381fb9ae2853b3e1e09"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"egui",
|
||||
@@ -2614,9 +2614,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "emath"
|
||||
version = "0.33.0"
|
||||
version = "0.33.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c615516cdceec867065f20d7db13d8eb8aedd65c9e32cc0c7c379380fa42e6e8"
|
||||
checksum = "0e561352ae95c22ad179fb56c38d6e6eecd86cf4925cf5c70e738dd01df9b620"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
]
|
||||
@@ -2742,9 +2742,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "epaint"
|
||||
version = "0.33.0"
|
||||
version = "0.33.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9926b9500ccb917adb070207ec722dd8ea78b8321f94a85ebec776f501f2930c"
|
||||
checksum = "a909ce8cee63e8350fb0c251ad39277a5b24f19add60787e84a3b3ab3f2bd83a"
|
||||
dependencies = [
|
||||
"ab_glyph",
|
||||
"ahash",
|
||||
@@ -7206,7 +7206,7 @@ dependencies = [
|
||||
"is-terminal",
|
||||
"lazy_static",
|
||||
"term 0.7.0",
|
||||
"unicode-width 0.1.14",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -11124,12 +11124,6 @@ version = "0.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.1.0"
|
||||
|
||||
+5
-5
@@ -151,8 +151,8 @@ nokhwa-mac = { git = "https://code.gri.mw/ardocrat/nokhwa", rev = "612c861ef153c
|
||||
|
||||
[target.'cfg(not(target_os = "android"))'.dependencies]
|
||||
env_logger = "0.11.3"
|
||||
winit = { version = "0.30.11" }
|
||||
eframe = { version = "0.33.0", default-features = false, features = ["glow", "wayland"] }
|
||||
winit = { version = "0.30.12" }
|
||||
eframe = { version = "0.33.2", default-features = false, features = ["glow", "wayland"] }
|
||||
arboard = "3.2.0"
|
||||
rfd = "0.15.0"
|
||||
interprocess = { version = "2.2.1", features = ["tokio"] }
|
||||
@@ -160,6 +160,6 @@ interprocess = { version = "2.2.1", features = ["tokio"] }
|
||||
[target.'cfg(target_os = "android")'.dependencies]
|
||||
android_logger = "0.15.0"
|
||||
jni = "0.21.1"
|
||||
android-activity = { version = "0.6.0", features = ["native-activity"] }
|
||||
winit = { version = "0.30.11", features = ["android-native-activity"] }
|
||||
eframe = { version = "0.33.0", default-features = false, features = ["glow", "android-native-activity"] }
|
||||
android-activity = { version = "0.6.0", features = ["game-activity"] }
|
||||
winit = { version = "0.30.12", features = ["android-game-activity"] }
|
||||
eframe = { version = "0.33.2", default-features = false, features = ["glow", "android-game-activity"] }
|
||||
+18
-11
@@ -3,15 +3,19 @@ plugins {
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdk 35
|
||||
compileSdk 36
|
||||
ndkVersion '26.0.10792818'
|
||||
|
||||
defaultConfig {
|
||||
applicationId "mw.gri.android"
|
||||
minSdk 24
|
||||
targetSdk 35
|
||||
versionCode 4
|
||||
versionName "0.2.4"
|
||||
targetSdk 36
|
||||
versionCode 5
|
||||
versionName "0.3.0"
|
||||
}
|
||||
|
||||
lint {
|
||||
checkReleaseBuilds false
|
||||
}
|
||||
|
||||
def keystorePropertiesFile = rootProject.file("keystore.properties")
|
||||
@@ -27,6 +31,7 @@ android {
|
||||
storePassword keystoreProperties['storePassword']
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
@@ -46,8 +51,8 @@ android {
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
sourceCompatibility JavaVersion.VERSION_17
|
||||
targetCompatibility JavaVersion.VERSION_17
|
||||
}
|
||||
namespace 'mw.gri.android'
|
||||
}
|
||||
@@ -55,9 +60,11 @@ android {
|
||||
dependencies {
|
||||
implementation 'androidx.appcompat:appcompat:1.7.0'
|
||||
|
||||
// Android Camera
|
||||
implementation 'androidx.camera:camera-core:1.4.2'
|
||||
implementation 'androidx.camera:camera-camera2:1.4.2'
|
||||
implementation 'androidx.camera:camera-lifecycle:1.4.2'
|
||||
}
|
||||
// To use the Games Activity library
|
||||
implementation "androidx.games:games-activity:2.0.2"
|
||||
|
||||
// Android Camera
|
||||
implementation 'androidx.camera:camera-core:1.5.1'
|
||||
implementation 'androidx.camera:camera-camera2:1.5.1'
|
||||
implementation 'androidx.camera:camera-lifecycle:1.5.1'
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
>
|
||||
<manifest xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<uses-feature android:name="android.hardware.camera" android:required="false"/>
|
||||
|
||||
<uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
|
||||
@@ -15,31 +14,33 @@
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
|
||||
|
||||
<application
|
||||
android:hardwareAccelerated="true"
|
||||
android:largeHeap="true"
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="Grim"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:theme="@style/Theme.Main">
|
||||
android:hardwareAccelerated="true"
|
||||
android:largeHeap="true"
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="Grim"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:theme="@style/Theme.Main"
|
||||
android:enableOnBackInvokedCallback="false"
|
||||
tools:ignore="UnusedAttribute">
|
||||
|
||||
<receiver android:name=".NotificationActionsReceiver"/>
|
||||
|
||||
<provider
|
||||
android:name=".FileProvider"
|
||||
android:authorities="mw.gri.android.fileprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
android:name=".FileProvider"
|
||||
android:authorities="mw.gri.android.fileprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/paths" />
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/paths" />
|
||||
</provider>
|
||||
|
||||
<activity
|
||||
android:launchMode="singleTask"
|
||||
android:name=".MainActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:exported="true">
|
||||
android:launchMode="singleTask"
|
||||
android:name=".MainActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:exported="true">
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
@@ -52,6 +53,7 @@
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:mimeType="text/*" />
|
||||
<data android:pathPattern=".*\\.slatepack" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter android:scheme="http" tools:ignore="AppLinkUrlError">
|
||||
|
||||
@@ -16,7 +16,7 @@ import static android.app.Notification.EXTRA_NOTIFICATION_ID;
|
||||
|
||||
public class BackgroundService extends Service {
|
||||
private static final String TAG = BackgroundService.class.getSimpleName();
|
||||
|
||||
|
||||
private PowerManager.WakeLock mWakeLock;
|
||||
|
||||
private final Handler mHandler = new Handler(Looper.getMainLooper());
|
||||
@@ -31,7 +31,6 @@ public class BackgroundService extends Service {
|
||||
|
||||
public static final String ACTION_START_NODE = "start_node";
|
||||
public static final String ACTION_STOP_NODE = "stop_node";
|
||||
public static final String ACTION_EXIT = "exit";
|
||||
|
||||
private final Runnable mUpdateSyncStatus = new Runnable() {
|
||||
@SuppressLint("RestrictedApi")
|
||||
@@ -82,18 +81,6 @@ public class BackgroundService extends Service {
|
||||
.getBroadcast(BackgroundService.this, 1, startStopIntent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT);
|
||||
mNotificationBuilder.addAction(R.drawable.ic_stop, getStopText(), i);
|
||||
}
|
||||
|
||||
// Set up a button to exit from the app.
|
||||
if (canStart || canStop) {
|
||||
Intent exitIntent = new Intent(BackgroundService.this, NotificationActionsReceiver.class);
|
||||
if (Build.VERSION.SDK_INT > 25) {
|
||||
exitIntent.putExtra(EXTRA_NOTIFICATION_ID, NOTIFICATION_ID);
|
||||
}
|
||||
exitIntent.setAction(ACTION_EXIT);
|
||||
PendingIntent i = PendingIntent
|
||||
.getBroadcast(BackgroundService.this, 1, exitIntent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT);
|
||||
mNotificationBuilder.addAction(R.drawable.ic_close, getExitText(), i);
|
||||
}
|
||||
}
|
||||
|
||||
// Update notification.
|
||||
@@ -247,9 +234,6 @@ public class BackgroundService extends Service {
|
||||
// Check if stop node is possible.
|
||||
private native boolean canStopNode();
|
||||
|
||||
// Get exit text for notification.
|
||||
private native String getExitText();
|
||||
|
||||
// Check if app from the app is needed after node stop.
|
||||
private native boolean exitAppAfterNodeStop();
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@ package mw.gri.android;
|
||||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.NativeActivity;
|
||||
import android.content.*;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Configuration;
|
||||
@@ -13,19 +12,26 @@ import android.os.Process;
|
||||
import android.provider.Settings;
|
||||
import android.system.ErrnoException;
|
||||
import android.system.Os;
|
||||
import android.util.Log;
|
||||
import android.util.Size;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.window.OnBackInvokedDispatcher;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.camera.core.*;
|
||||
import androidx.camera.lifecycle.ProcessCameraProvider;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.content.FileProvider;
|
||||
import androidx.core.graphics.Insets;
|
||||
import androidx.core.os.BuildCompat;
|
||||
import androidx.core.view.DisplayCutoutCompat;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.view.WindowInsetsCompat;
|
||||
|
||||
import com.google.androidgamesdk.GameActivity;
|
||||
import com.google.androidgamesdk.gametextinput.State;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
import java.io.*;
|
||||
@@ -36,30 +42,27 @@ import java.util.concurrent.Executors;
|
||||
import static android.content.ClipDescription.MIMETYPE_TEXT_HTML;
|
||||
import static android.content.ClipDescription.MIMETYPE_TEXT_PLAIN;
|
||||
|
||||
public class MainActivity extends NativeActivity {
|
||||
private static final int FILE_PICK_REQUEST = 1001;
|
||||
private static final int FILE_PERMISSIONS_REQUEST = 1002;
|
||||
public class MainActivity extends GameActivity {
|
||||
public static String STOP_APP_ACTION = "STOP_APP";
|
||||
|
||||
private static final int NOTIFICATIONS_PERMISSION_CODE = 1;
|
||||
private static final int CAMERA_PERMISSION_CODE = 2;
|
||||
|
||||
public static final String STOP_APP_ACTION = "STOP_APP_ACTION";
|
||||
|
||||
static {
|
||||
System.loadLibrary("grim");
|
||||
}
|
||||
|
||||
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
||||
@SuppressLint("RestrictedApi")
|
||||
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (Objects.equals(intent.getAction(), MainActivity.STOP_APP_ACTION)) {
|
||||
public void onReceive(Context ctx, Intent i) {
|
||||
if (Objects.equals(i.getAction(), STOP_APP_ACTION)) {
|
||||
exit();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private final ImageAnalysis mImageAnalysis = new ImageAnalysis.Builder()
|
||||
.setTargetResolution(new Size(640, 480))
|
||||
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
|
||||
.build();
|
||||
|
||||
@@ -68,6 +71,9 @@ public class MainActivity extends NativeActivity {
|
||||
private ExecutorService mCameraExecutor = null;
|
||||
private boolean mUseBackCamera = true;
|
||||
|
||||
private ActivityResultLauncher<Intent> mFilePickResult = null;
|
||||
private ActivityResultLauncher<Intent> mOpenFilePermissionsResult = null;
|
||||
|
||||
@SuppressLint("UnspecifiedRegisterReceiverFlag")
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
@@ -79,15 +85,14 @@ public class MainActivity extends NativeActivity {
|
||||
}
|
||||
|
||||
// Clear cache on start.
|
||||
String cacheDir = Objects.requireNonNull(getExternalCacheDir()).getPath();
|
||||
if (savedInstanceState == null) {
|
||||
Utils.deleteDirectoryContent(new File(cacheDir), false);
|
||||
if (savedInstanceState == null && getExternalCacheDir() != null) {
|
||||
Utils.deleteDirectoryContent(new File(getExternalCacheDir().getPath()), false);
|
||||
}
|
||||
|
||||
// Setup environment variables for native code.
|
||||
try {
|
||||
Os.setenv("HOME", Objects.requireNonNull(getExternalFilesDir("")).getPath(), true);
|
||||
Os.setenv("XDG_CACHE_HOME", cacheDir, true);
|
||||
Os.setenv("XDG_CACHE_HOME", Objects.requireNonNull(getExternalCacheDir()).getPath(), true);
|
||||
Os.setenv("ARTI_FS_DISABLE_PERMISSION_CHECKS", "true", true);
|
||||
} catch (ErrnoException e) {
|
||||
throw new RuntimeException(e);
|
||||
@@ -95,10 +100,56 @@ public class MainActivity extends NativeActivity {
|
||||
|
||||
super.onCreate(null);
|
||||
|
||||
ContextCompat.registerReceiver(this, mReceiver, new IntentFilter(STOP_APP_ACTION), ContextCompat.RECEIVER_NOT_EXPORTED);
|
||||
// Register receiver to finish activity from the BackgroundService.
|
||||
ContextCompat.registerReceiver(this, mBroadcastReceiver, new IntentFilter(STOP_APP_ACTION), ContextCompat.RECEIVER_NOT_EXPORTED);
|
||||
|
||||
// Register associated file opening result.
|
||||
mOpenFilePermissionsResult = registerForActivityResult(
|
||||
new ActivityResultContracts.StartActivityForResult(),
|
||||
result -> {
|
||||
if (Build.VERSION.SDK_INT >= 30) {
|
||||
if (Environment.isExternalStorageManager()) {
|
||||
onFile();
|
||||
}
|
||||
} else if (result.getResultCode() == RESULT_OK) {
|
||||
onFile();
|
||||
}
|
||||
}
|
||||
);
|
||||
// Register file pick result.
|
||||
mFilePickResult = registerForActivityResult(
|
||||
new ActivityResultContracts.StartActivityForResult(),
|
||||
result -> {
|
||||
int resultCode = result.getResultCode();
|
||||
Intent data = result.getData();
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
String path = "";
|
||||
if (data != null && data.getData() != null) {
|
||||
Uri uri = data.getData();
|
||||
String name = "pick" + Utils.getFileExtension(uri, this);
|
||||
File file = new File(getExternalCacheDir(), name);
|
||||
try (InputStream is = getContentResolver().openInputStream(uri);
|
||||
OutputStream os = new FileOutputStream(file)) {
|
||||
byte[] buffer = new byte[1024];
|
||||
int length;
|
||||
while (true) {
|
||||
assert is != null;
|
||||
if (!((length = is.read(buffer)) > 0)) break;
|
||||
os.write(buffer, 0, length);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e("grim", e.toString());
|
||||
}
|
||||
path = file.getPath();
|
||||
}
|
||||
onFilePick(path);
|
||||
} else {
|
||||
onFilePick("");
|
||||
}
|
||||
});
|
||||
|
||||
// Listener for display insets (cutouts) to pass values into native code.
|
||||
View content = findViewById(android.R.id.content).getRootView();
|
||||
View content = getWindow().getDecorView().findViewById(android.R.id.content);
|
||||
ViewCompat.setOnApplyWindowInsetsListener(content, (v, insets) -> {
|
||||
// Get display cutouts.
|
||||
DisplayCutoutCompat dc = insets.getDisplayCutout();
|
||||
@@ -127,7 +178,7 @@ public class MainActivity extends NativeActivity {
|
||||
return insets;
|
||||
});
|
||||
|
||||
content.post(() -> {
|
||||
findViewById(android.R.id.content).post(() -> {
|
||||
// Request notifications permissions if needed.
|
||||
if (Build.VERSION.SDK_INT >= 33) {
|
||||
String notificationsPermission = Manifest.permission.POST_NOTIFICATIONS;
|
||||
@@ -149,43 +200,8 @@ public class MainActivity extends NativeActivity {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
switch (requestCode) {
|
||||
case FILE_PICK_REQUEST:
|
||||
if (Build.VERSION.SDK_INT >= 30) {
|
||||
if (Environment.isExternalStorageManager()) {
|
||||
onFile();
|
||||
}
|
||||
} else if (resultCode == RESULT_OK) {
|
||||
onFile();
|
||||
}
|
||||
case FILE_PERMISSIONS_REQUEST:
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
String path = "";
|
||||
if (data != null) {
|
||||
Uri uri = data.getData();
|
||||
String name = "pick" + Utils.getFileExtension(uri, this);
|
||||
File file = new File(getExternalCacheDir(), name);
|
||||
try (InputStream is = getContentResolver().openInputStream(uri);
|
||||
OutputStream os = new FileOutputStream(file)) {
|
||||
byte[] buffer = new byte[1024];
|
||||
int length;
|
||||
while ((length = is.read(buffer)) > 0) {
|
||||
os.write(buffer, 0, length);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
path = file.getPath();
|
||||
}
|
||||
onFilePick(path);
|
||||
} else {
|
||||
onFilePick("");
|
||||
}
|
||||
}
|
||||
}
|
||||
// Pass display insets into native code.
|
||||
public native void onDisplayInsets(int[] cutouts);
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
@@ -209,12 +225,13 @@ public class MainActivity extends NativeActivity {
|
||||
if (Build.VERSION.SDK_INT >= 30) {
|
||||
if (!Environment.isExternalStorageManager()) {
|
||||
Intent i = new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
|
||||
startActivityForResult(i, FILE_PERMISSIONS_REQUEST);
|
||||
mOpenFilePermissionsResult.launch(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
try {
|
||||
ParcelFileDescriptor parcelFile = getContentResolver().openFileDescriptor(data, "r");
|
||||
assert parcelFile != null;
|
||||
FileReader fileReader = new FileReader(parcelFile.getFileDescriptor());
|
||||
BufferedReader reader = new BufferedReader(fileReader);
|
||||
String line;
|
||||
@@ -228,7 +245,7 @@ public class MainActivity extends NativeActivity {
|
||||
// Provide file content into native code.
|
||||
onData(buff.toString());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Log.e("grim", e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,20 +268,87 @@ public class MainActivity extends NativeActivity {
|
||||
if (results.length != 0 && results[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
switch (requestCode) {
|
||||
case NOTIFICATIONS_PERMISSION_CODE: {
|
||||
// Start notification service.
|
||||
BackgroundService.start(this);
|
||||
return;
|
||||
}
|
||||
case CAMERA_PERMISSION_CODE: {
|
||||
// Start camera.
|
||||
startCamera();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Implemented into native code to handle display insets change.
|
||||
native void onDisplayInsets(int[] cutouts);
|
||||
@Override
|
||||
protected void onTextInputEventNative(long l, State state) {
|
||||
super.onTextInputEventNative(l, state);
|
||||
if (state.selectionEnd > state.composingRegionStart && state.composingRegionStart >= 0) {
|
||||
String input = String.valueOf(state.text.charAt(state.composingRegionStart));
|
||||
if (input.contains("\n")) {
|
||||
onEnterInput();
|
||||
} else {
|
||||
onTextInput(input);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
|
||||
onBack();
|
||||
return false;
|
||||
} else if (event.getKeyCode() == KeyEvent.KEYCODE_DEL) {
|
||||
onClearInput();
|
||||
return false;
|
||||
} else if (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) {
|
||||
onEnterInput();
|
||||
return false;
|
||||
} else if (event.getKeyCode() == KeyEvent.KEYCODE_0) {
|
||||
onTextInput("0");
|
||||
return false;
|
||||
} else if (event.getKeyCode() == KeyEvent.KEYCODE_1) {
|
||||
onTextInput("1");
|
||||
return false;
|
||||
} else if (event.getKeyCode() == KeyEvent.KEYCODE_2) {
|
||||
onTextInput("2");
|
||||
return false;
|
||||
} else if (event.getKeyCode() == KeyEvent.KEYCODE_3) {
|
||||
onTextInput("3");
|
||||
return false;
|
||||
} else if (event.getKeyCode() == KeyEvent.KEYCODE_4) {
|
||||
onTextInput("4");
|
||||
return false;
|
||||
} else if (event.getKeyCode() == KeyEvent.KEYCODE_5) {
|
||||
onTextInput("5");
|
||||
return false;
|
||||
} else if (event.getKeyCode() == KeyEvent.KEYCODE_6) {
|
||||
onTextInput("6");
|
||||
return false;
|
||||
} else if (event.getKeyCode() == KeyEvent.KEYCODE_7) {
|
||||
onTextInput("7");
|
||||
return false;
|
||||
} else if (event.getKeyCode() == KeyEvent.KEYCODE_8) {
|
||||
onTextInput("8");
|
||||
return false;
|
||||
} else if (event.getKeyCode() == KeyEvent.KEYCODE_9) {
|
||||
onTextInput("9");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return super.dispatchKeyEvent(event);
|
||||
}
|
||||
|
||||
// Pass back navigation event into native code.
|
||||
public native void onBack();
|
||||
|
||||
// Pass clear key event into native code.
|
||||
public native void onClearInput();
|
||||
|
||||
// Pass enter key event into native code.
|
||||
public native void onEnterInput();
|
||||
|
||||
// Pass last entered character from soft keyboard into native code.
|
||||
public native void onTextInput(String character);
|
||||
|
||||
// Called from native code to exit app.
|
||||
public void exit() {
|
||||
@@ -273,6 +357,7 @@ public class MainActivity extends NativeActivity {
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
unregisterReceiver(mBroadcastReceiver);
|
||||
BackgroundService.stop(this);
|
||||
|
||||
// Kill process after 3 secs if app was terminated from recent apps to prevent app hang.
|
||||
@@ -317,18 +402,6 @@ public class MainActivity extends NativeActivity {
|
||||
return text;
|
||||
}
|
||||
|
||||
// Called from native code to show keyboard.
|
||||
public void showKeyboard() {
|
||||
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
imm.showSoftInput(getWindow().getDecorView(), InputMethodManager.SHOW_IMPLICIT);
|
||||
}
|
||||
|
||||
// Called from native code to hide keyboard.
|
||||
public void hideKeyboard() {
|
||||
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
imm.hideSoftInputFromWindow(getWindow().getDecorView().getWindowToken(), 0);
|
||||
}
|
||||
|
||||
// Called from native code to start camera.
|
||||
public void startCamera() {
|
||||
String notificationsPermission = Manifest.permission.CAMERA;
|
||||
@@ -379,7 +452,7 @@ public class MainActivity extends NativeActivity {
|
||||
}
|
||||
// Apply declared configs to CameraX using the same lifecycle owner
|
||||
mCameraProvider.unbindAll();
|
||||
// mCameraProvider.bindToLifecycle(this, cameraSelector, mImageAnalysis);
|
||||
mCameraProvider.bindToLifecycle(this, cameraSelector, mImageAnalysis);
|
||||
}
|
||||
|
||||
// Called from native code to stop camera.
|
||||
@@ -418,7 +491,7 @@ public class MainActivity extends NativeActivity {
|
||||
Uri uri = FileProvider.getUriForFile(this, "mw.gri.android.fileprovider", file);
|
||||
Intent intent = new Intent(Intent.ACTION_SEND);
|
||||
intent.putExtra(Intent.EXTRA_STREAM, uri);
|
||||
intent.setType("*/*");
|
||||
intent.setType("text/*");
|
||||
startActivity(Intent.createChooser(intent, "Share data"));
|
||||
}
|
||||
|
||||
@@ -431,10 +504,10 @@ public class MainActivity extends NativeActivity {
|
||||
// Called from native code to pick the file.
|
||||
public void pickFile() {
|
||||
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
intent.setType("*/*");
|
||||
intent.setType("text/*");
|
||||
try {
|
||||
startActivityForResult(Intent.createChooser(intent, "Pick file"), FILE_PICK_REQUEST);
|
||||
} catch (ActivityNotFoundException ex) {
|
||||
mFilePickResult.launch(Intent.createChooser(intent, "Pick file"));
|
||||
} catch (android.content.ActivityNotFoundException ex) {
|
||||
onFilePick("");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,4 +153,4 @@ public class Utils {
|
||||
String fileType = context.getContentResolver().getType(uri);
|
||||
return MimeTypeMap.getSingleton().getExtensionFromMimeType(fileType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
plugins {
|
||||
id 'com.android.application' version '8.10.0' apply false
|
||||
id 'com.android.library' version '8.10.0' apply false
|
||||
id 'com.android.application' version '8.13.1' apply false
|
||||
id 'com.android.library' version '8.13.1' apply false
|
||||
}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
#Mon May 02 15:39:12 BST 2022
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionUrl=https\://code.gri.mw/ardocrat/gradle/releases/download/v8.11.1/gradle-8.11.1-bin.zip
|
||||
distributionUrl=https\://code.gri.mw/ardocrat/gradle/releases/download/v8.13/gradle-8.13-bin.zip
|
||||
distributionPath=wrapper/dists
|
||||
zipStorePath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
+1
-1
@@ -82,7 +82,7 @@ function build_apk() {
|
||||
done
|
||||
else
|
||||
# Get version
|
||||
version=v$2
|
||||
version=$2
|
||||
if [[ -z "$version" ]]; then
|
||||
version=v$(grep -m 1 -Po 'version = "\K[^"]*' ../Cargo.toml)
|
||||
fi
|
||||
|
||||
+31
-4
@@ -12,8 +12,10 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use egui::epaint::RectShape;
|
||||
use egui::{Align, Context, CornerRadius, CursorIcon, LayerId, Layout, Modifiers, Order, ResizeDirection, Stroke, StrokeKind, UiBuilder, ViewportCommand};
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use crate::gui::icons::{ARROWS_IN, ARROWS_OUT, CARET_DOWN, MOON, SUN, X};
|
||||
use crate::gui::platform::PlatformCallbacks;
|
||||
@@ -22,6 +24,11 @@ use crate::gui::views::{Content, KeyboardContent, Modal, TitlePanel, View};
|
||||
use crate::gui::Colors;
|
||||
use crate::AppConfig;
|
||||
|
||||
lazy_static! {
|
||||
/// State to check if platform Back button was pressed.
|
||||
static ref BACK_BUTTON_PRESSED: AtomicBool = AtomicBool::new(false);
|
||||
}
|
||||
|
||||
/// Implements ui entry point and contains platform-specific callbacks.
|
||||
pub struct App<Platform> {
|
||||
/// Handles platform-specific functionality.
|
||||
@@ -63,10 +70,15 @@ impl<Platform: PlatformCallbacks> App<Platform> {
|
||||
self.first_draw = false;
|
||||
}
|
||||
|
||||
// Handle Esc keyboard key event.
|
||||
if ctx.input_mut(|i| i.consume_key(Modifiers::NONE, egui::Key::Escape) ||
|
||||
// Handle Esc keyboard key event and platform Back button key event.
|
||||
let back_pressed = BACK_BUTTON_PRESSED.load(Ordering::Relaxed);
|
||||
if back_pressed || ctx.input_mut(|i| i.consume_key(Modifiers::NONE, egui::Key::Escape) ||
|
||||
i.consume_key(Modifiers::NONE, egui::Key::BrowserBack)) {
|
||||
self.content.on_back(&self.platform);
|
||||
// Pass event to content.
|
||||
self.content.on_back(ctx, &self.platform);
|
||||
if back_pressed {
|
||||
BACK_BUTTON_PRESSED.store(false, Ordering::Relaxed);
|
||||
}
|
||||
// Request repaint to update previous content.
|
||||
ctx.request_repaint();
|
||||
}
|
||||
@@ -134,7 +146,9 @@ impl<Platform: PlatformCallbacks> App<Platform> {
|
||||
false
|
||||
};
|
||||
if keyboard_showing {
|
||||
ctx.move_to_top(LayerId::new(Order::Middle, egui::Id::new(KeyboardContent::WINDOW_ID)));
|
||||
ctx.move_to_top(
|
||||
LayerId::new(Order::Middle, egui::Id::new(KeyboardContent::WINDOW_ID))
|
||||
);
|
||||
}
|
||||
}
|
||||
// Reset keyboard state for newly opened modal.
|
||||
@@ -397,4 +411,17 @@ impl<Platform: PlatformCallbacks> eframe::App for App<Platform> {
|
||||
}
|
||||
Colors::TRANSPARENT.to_normalized_gamma_f32()
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[cfg(target_os = "android")]
|
||||
#[allow(non_snake_case)]
|
||||
#[no_mangle]
|
||||
/// Handle Back key code event from Android.
|
||||
pub extern "C" fn Java_mw_gri_android_MainActivity_onBack(
|
||||
_env: jni::JNIEnv,
|
||||
_class: jni::objects::JObject,
|
||||
_activity: jni::objects::JObject,
|
||||
) {
|
||||
BACK_BUTTON_PRESSED.store(true, Ordering::Relaxed);
|
||||
}
|
||||
@@ -146,9 +146,15 @@ impl Content {
|
||||
pub const EXIT_CONFIRMATION_MODAL: &'static str = "exit_confirmation_modal";
|
||||
|
||||
/// Called to navigate back, return `true` if action was not consumed.
|
||||
pub fn on_back(&mut self, cb: &dyn PlatformCallbacks) -> bool {
|
||||
pub fn on_back(&mut self, ctx: &egui::Context, cb: &dyn PlatformCallbacks) -> bool {
|
||||
if Modal::on_back() {
|
||||
if self.wallets.on_back(cb) {
|
||||
let dual_panel = Self::is_dual_panel_mode(ctx);
|
||||
if !dual_panel && Self::is_network_panel_open() {
|
||||
if self.network.on_back() {
|
||||
Self::toggle_network_panel();
|
||||
return false;
|
||||
}
|
||||
} else if self.wallets.on_back(cb) {
|
||||
Self::show_exit_modal();
|
||||
return false;
|
||||
}
|
||||
|
||||
+89
-11
@@ -12,8 +12,12 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use egui::{Layout, TextBuffer, TextStyle, Widget, Align};
|
||||
use std::sync::Arc;
|
||||
use egui::{Layout, TextBuffer, TextStyle, Widget, Align, ViewportCommand};
|
||||
use egui::text_edit::TextEditState;
|
||||
use lazy_static::lazy_static;
|
||||
use parking_lot::RwLock;
|
||||
|
||||
use crate::gui::Colors;
|
||||
use crate::gui::icons::{CLIPBOARD_TEXT, COPY, EYE, EYE_SLASH, SCAN};
|
||||
use crate::gui::platform::PlatformCallbacks;
|
||||
@@ -24,11 +28,11 @@ use crate::gui::views::{KeyboardEvent, View};
|
||||
pub struct TextEdit {
|
||||
/// View identifier.
|
||||
id: egui::Id,
|
||||
/// Check if horizontal centering is needed.
|
||||
/// Horizontal text centering is needed.
|
||||
h_center: bool,
|
||||
/// Check if focus is needed.
|
||||
/// Focus is needed.
|
||||
focus: bool,
|
||||
/// Check if focus request was passed.
|
||||
/// Focus request was passed.
|
||||
focus_request: bool,
|
||||
/// Hide letters and draw button to show/hide letters.
|
||||
password: bool,
|
||||
@@ -38,9 +42,9 @@ pub struct TextEdit {
|
||||
paste: bool,
|
||||
/// Show button to scan QR code into text.
|
||||
scan_qr: bool,
|
||||
/// Callback when scan button was pressed.
|
||||
/// Scan button was pressed.
|
||||
pub scan_pressed: bool,
|
||||
/// Callback when Enter key was pressed.
|
||||
/// Tab or Enter keys were pressed to focus on next line.
|
||||
pub enter_pressed: bool,
|
||||
/// Flag to enter only numbers.
|
||||
numeric: bool,
|
||||
@@ -65,7 +69,7 @@ impl TextEdit {
|
||||
scan_pressed: false,
|
||||
enter_pressed: false,
|
||||
numeric: false,
|
||||
no_soft_keyboard: false,
|
||||
no_soft_keyboard: is_android(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,6 +155,7 @@ impl TextEdit {
|
||||
|
||||
// Reset keyboard state for newly focused.
|
||||
if clicked || self.focus_request {
|
||||
ui.ctx().send_viewport_cmd(ViewportCommand::IMEAllowed(true));
|
||||
KeyboardContent::reset_window_state();
|
||||
}
|
||||
|
||||
@@ -160,9 +165,10 @@ impl TextEdit {
|
||||
data.insert_temp(focused_input_id, self.id);
|
||||
});
|
||||
self.enter_pressed = self.on_soft_input(ui, self.id, false, input);
|
||||
// Check Enter key input.
|
||||
// Check Enter or Tab keys press.
|
||||
if !self.focus_request {
|
||||
if ui.ctx().input(|i| i.key_pressed(egui::Key::Enter)) {
|
||||
if ui.ctx().input(|i| i.key_pressed(egui::Key::Enter) ||
|
||||
i.key_pressed(egui::Key::Tab)) {
|
||||
self.enter_pressed = true;
|
||||
}
|
||||
}
|
||||
@@ -175,12 +181,24 @@ impl TextEdit {
|
||||
}
|
||||
});
|
||||
});
|
||||
// Repaint on Android to handle input from Java code without delays.
|
||||
if is_android() {
|
||||
ui.ctx().request_repaint();
|
||||
}
|
||||
}
|
||||
|
||||
/// Apply soft keyboard input data to provided String, returns `true` if Enter was pressed.
|
||||
fn on_soft_input(&self, ui: &mut egui::Ui, id: egui::Id, multiline: bool, value: &mut String)
|
||||
-> bool {
|
||||
if let Some(input) = KeyboardContent::consume_event() {
|
||||
let event: Option<KeyboardEvent> = if is_android() {
|
||||
let mut w_input = LAST_SOFT_KEYBOARD_EVENT.write();
|
||||
w_input.take()
|
||||
} else {
|
||||
KeyboardContent::consume_event()
|
||||
};
|
||||
|
||||
// Handle keyboard input event.
|
||||
if let Some(e) = event {
|
||||
let mut enter_pressed = false;
|
||||
let mut state = TextEditState::load(ui.ctx(), id).unwrap();
|
||||
match state.cursor.char_range() {
|
||||
@@ -194,7 +212,7 @@ impl TextEdit {
|
||||
r.secondary.index as f32) as usize;
|
||||
let end_select = f32::max(r.primary.index as f32,
|
||||
r.secondary.index as f32) as usize;
|
||||
match input {
|
||||
match e {
|
||||
KeyboardEvent::TEXT(text) => {
|
||||
if selected {
|
||||
*value = {
|
||||
@@ -318,4 +336,64 @@ impl TextEdit {
|
||||
self.no_soft_keyboard = true;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if current system is Android.
|
||||
fn is_android() -> bool {
|
||||
egui::os::OperatingSystem::from_target_os() == egui::os::OperatingSystem::Android
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref LAST_SOFT_KEYBOARD_EVENT: Arc<RwLock<Option<KeyboardEvent>>> = Arc::new(RwLock::new(None));
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[cfg(target_os = "android")]
|
||||
#[allow(non_snake_case)]
|
||||
#[no_mangle]
|
||||
/// Callback from Java code with last entered character from soft keyboard.
|
||||
pub extern "C" fn Java_mw_gri_android_MainActivity_onTextInput(
|
||||
_env: jni::JNIEnv,
|
||||
_class: jni::objects::JObject,
|
||||
char: jni::sys::jstring
|
||||
) {
|
||||
use jni::objects::JString;
|
||||
|
||||
unsafe {
|
||||
let j_obj = JString::from_raw(char);
|
||||
let j_str = _env.get_string_unchecked(j_obj.as_ref()).unwrap();
|
||||
match j_str.to_str() {
|
||||
Ok(str) => {
|
||||
let mut w_input = LAST_SOFT_KEYBOARD_EVENT.write();
|
||||
*w_input = Some(KeyboardEvent::TEXT(str.to_string()));
|
||||
}
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[cfg(target_os = "android")]
|
||||
#[allow(non_snake_case)]
|
||||
#[no_mangle]
|
||||
/// Callback from Java code when Clear key was pressed at soft keyboard.
|
||||
pub extern "C" fn Java_mw_gri_android_MainActivity_onClearInput(
|
||||
_env: jni::JNIEnv,
|
||||
_class: jni::objects::JObject,
|
||||
) {
|
||||
let mut w_input = LAST_SOFT_KEYBOARD_EVENT.write();
|
||||
*w_input = Some(KeyboardEvent::CLEAR);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[cfg(target_os = "android")]
|
||||
#[allow(non_snake_case)]
|
||||
#[no_mangle]
|
||||
/// Callback from Java code when Enter key was pressed at soft keyboard.
|
||||
pub extern "C" fn Java_mw_gri_android_MainActivity_onEnterInput(
|
||||
_env: jni::JNIEnv,
|
||||
_class: jni::objects::JObject,
|
||||
) {
|
||||
let mut w_input = LAST_SOFT_KEYBOARD_EVENT.write();
|
||||
*w_input = Some(KeyboardEvent::ENTER);
|
||||
}
|
||||
@@ -213,6 +213,16 @@ impl NetworkContent {
|
||||
}
|
||||
}
|
||||
|
||||
/// Navigate back, return `true` if action was not consumed.
|
||||
pub fn on_back(&mut self) -> bool {
|
||||
if self.showing_settings() {
|
||||
// Close settings.
|
||||
self.settings_content = None;
|
||||
return false;
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
/// Check if application settings content is showing.
|
||||
pub fn showing_settings(&self) -> bool {
|
||||
self.settings_content.is_some()
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::time::Duration;
|
||||
use egui::scroll_area::ScrollBarVisibility;
|
||||
use egui::{Align, CornerRadius, Id, Layout, Margin, RichText, ScrollArea, StrokeKind};
|
||||
use std::time::Duration;
|
||||
|
||||
use egui::os::OperatingSystem;
|
||||
use crate::gui::icons::{ARROW_LEFT, CARET_RIGHT, COMPUTER_TOWER, FOLDER_OPEN, FOLDER_PLUS, GEAR, GLOBE, GLOBE_SIMPLE, LOCK_KEY, PLUS, SIDEBAR_SIMPLE, SUITCASE};
|
||||
use crate::gui::platform::PlatformCallbacks;
|
||||
use crate::gui::views::settings::SettingsContent;
|
||||
@@ -130,6 +130,12 @@ impl ContentContainer for WalletsContent {
|
||||
}
|
||||
|
||||
fn container_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) {
|
||||
ui.ctx().request_repaint_after(if OperatingSystem::from_target_os() == OperatingSystem::Android {
|
||||
Duration::from_millis(100)
|
||||
} else {
|
||||
Duration::from_millis(1000)
|
||||
});
|
||||
|
||||
if let Some(data) = crate::consume_incoming_data() {
|
||||
if !data.is_empty() {
|
||||
self.on_data(ui, Some(data), cb);
|
||||
@@ -221,9 +227,6 @@ impl ContentContainer for WalletsContent {
|
||||
..Default::default()
|
||||
})
|
||||
.show_animated_inside(ui, !list_hidden, |ui| {
|
||||
if !dual_panel && !showing_wallet {
|
||||
ui.ctx().request_repaint_after(Duration::from_millis(1000));
|
||||
}
|
||||
// Show wallet list.
|
||||
self.wallet_list_ui(ui, cb);
|
||||
});
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
use egui::scroll_area::ScrollBarVisibility;
|
||||
use egui::{Id, Margin, RichText, ScrollArea};
|
||||
use grin_chain::SyncStatus;
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::gui::icons::{ARROWS_CLOCKWISE, FILE_ARROW_DOWN, FILE_ARROW_UP, GEAR_FINE, POWER, STACK};
|
||||
use crate::gui::platform::PlatformCallbacks;
|
||||
@@ -83,12 +82,6 @@ impl WalletContentContainer for WalletContent {
|
||||
}
|
||||
|
||||
fn container_ui(&mut self, ui: &mut egui::Ui, wallet: &Wallet, cb: &dyn PlatformCallbacks) {
|
||||
if self.account_content.can_back() {
|
||||
ui.ctx().request_repaint();
|
||||
} else {
|
||||
ui.ctx().request_repaint_after(Duration::from_millis(1000));
|
||||
}
|
||||
|
||||
let dual_panel = Content::is_dual_panel_mode(ui.ctx());
|
||||
let show_wallets_dual = AppConfig::show_wallets_at_dual_panel();
|
||||
|
||||
|
||||
+1
-1
@@ -52,7 +52,7 @@ fn android_main(app: AndroidApp) {
|
||||
{
|
||||
std::env::set_var("RUST_BACKTRACE", "full");
|
||||
let log_config = android_logger::Config::default()
|
||||
.with_max_level(log::LevelFilter::Info)
|
||||
.with_max_level(log::LevelFilter::Debug)
|
||||
.with_tag("grim");
|
||||
android_logger::init_once(log_config);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user