fix: fix ui android issues (#1980)

* Fix UI issues

* Fix Screen Swipe
This commit is contained in:
NickVs2015
2025-11-11 17:03:27 +03:00
committed by GitHub
parent 2ee61a040b
commit 5fdce1e49e
20 changed files with 156 additions and 15 deletions
+1 -1
View File
@@ -470,7 +470,7 @@ jobs:
env: env:
ANDROID_BUILD_PLATFORM: android-36 ANDROID_BUILD_PLATFORM: android-36
QT_VERSION: 6.9.3 QT_VERSION: 6.8.3
QT_MODULES: 'qtremoteobjects qt5compat qtimageformats qtshadertools' QT_MODULES: 'qtremoteobjects qt5compat qtimageformats qtshadertools'
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }} PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }} PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }}
+2 -2
View File
@@ -45,7 +45,7 @@
android:configChanges="uiMode|screenSize|smallestScreenSize|screenLayout|orientation|density android:configChanges="uiMode|screenSize|smallestScreenSize|screenLayout|orientation|density
|fontScale|layoutDirection|locale|keyboard|keyboardHidden|navigation|mcc|mnc" |fontScale|layoutDirection|locale|keyboard|keyboardHidden|navigation|mcc|mnc"
android:launchMode="singleInstance" android:launchMode="singleInstance"
android:windowSoftInputMode="stateUnchanged|adjustResize" android:windowSoftInputMode="adjustResize|stateUnchanged"
android:enableOnBackInvokedCallback="false" android:enableOnBackInvokedCallback="false"
android:exported="true"> android:exported="true">
@@ -215,4 +215,4 @@
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/qtprovider_paths" /> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/qtprovider_paths" />
</provider> </provider>
</application> </application>
</manifest> </manifest>
@@ -35,6 +35,10 @@ import android.widget.Toast
import androidx.annotation.MainThread import androidx.annotation.MainThread
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.graphics.Insets
import androidx.core.view.OnApplyWindowInsetsListener
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat import androidx.core.view.WindowInsetsControllerCompat
import java.io.IOException import java.io.IOException
import kotlin.LazyThreadSafetyMode.NONE import kotlin.LazyThreadSafetyMode.NONE
@@ -300,6 +304,11 @@ class AmneziaActivity : QtActivity() {
isAppearanceLightStatusBars = false isAppearanceLightStatusBars = false
isAppearanceLightNavigationBars = false isAppearanceLightNavigationBars = false
} }
// Workaround for Android 14 (API 34+) IME adjustResize bug
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
setupImeInsetsListener()
}
} else { } else {
window.apply { window.apply {
addFlags(LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) addFlags(LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
@@ -308,6 +317,34 @@ class AmneziaActivity : QtActivity() {
} }
} }
private fun setupImeInsetsListener() {
ViewCompat.setOnApplyWindowInsetsListener(window.decorView) { view, windowInsets ->
val imeInsets = windowInsets.getInsets(WindowInsetsCompat.Type.ime())
val imeVisible = windowInsets.isVisible(WindowInsetsCompat.Type.ime())
val imeHeight = if (imeVisible) imeInsets.bottom else 0
val density = resources.displayMetrics.density
val imeHeightDp = (imeHeight / density).toInt()
// Also track system bars (navigation bar, status bar) changes
val systemBarsInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
val navBarHeight = systemBarsInsets.bottom
val navBarHeightDp = (navBarHeight / density).toInt()
val statusBarHeight = systemBarsInsets.top
val statusBarHeightDp = (statusBarHeight / density).toInt()
mainScope.launch {
qtInitialized.await()
QtAndroidController.onImeInsetsChanged(imeHeightDp)
QtAndroidController.onSystemBarsInsetsChanged(navBarHeightDp, statusBarHeightDp)
}
// Return windowInsets instead of CONSUMED to allow proper handling
windowInsets
}
}
override fun onDestroy() { override fun onDestroy() {
Log.d(TAG, "Destroy Amnezia activity") Log.d(TAG, "Destroy Amnezia activity")
unregisterBroadcastReceiver(notificationStateReceiver) unregisterBroadcastReceiver(notificationStateReceiver)
@@ -28,4 +28,7 @@ object QtAndroidController {
external fun onAuthResult(result: Boolean) external fun onAuthResult(result: Boolean)
external fun decodeQrCode(data: String): Boolean external fun decodeQrCode(data: String): Boolean
external fun onImeInsetsChanged(heightDp: Int)
external fun onSystemBarsInsetsChanged(navBarHeightDp: Int, statusBarHeightDp: Int)
} }
@@ -99,7 +99,9 @@ bool AndroidController::initialize()
{"onFileOpened", "(Ljava/lang/String;)V", reinterpret_cast<void *>(onFileOpened)}, {"onFileOpened", "(Ljava/lang/String;)V", reinterpret_cast<void *>(onFileOpened)},
{"onConfigImported", "(Ljava/lang/String;)V", reinterpret_cast<void *>(onConfigImported)}, {"onConfigImported", "(Ljava/lang/String;)V", reinterpret_cast<void *>(onConfigImported)},
{"onAuthResult", "(Z)V", reinterpret_cast<void *>(onAuthResult)}, {"onAuthResult", "(Z)V", reinterpret_cast<void *>(onAuthResult)},
{"decodeQrCode", "(Ljava/lang/String;)Z", reinterpret_cast<bool *>(decodeQrCode)} {"decodeQrCode", "(Ljava/lang/String;)Z", reinterpret_cast<bool *>(decodeQrCode)},
{"onImeInsetsChanged", "(I)V", reinterpret_cast<void *>(onImeInsetsChanged)},
{"onSystemBarsInsetsChanged", "(II)V", reinterpret_cast<void *>(onSystemBarsInsetsChanged)}
}; };
QJniEnvironment env; QJniEnvironment env;
@@ -536,3 +538,23 @@ bool AndroidController::decodeQrCode(JNIEnv *env, jobject thiz, jstring data)
return ImportController::decodeQrCode(AndroidUtils::convertJString(env, data)); return ImportController::decodeQrCode(AndroidUtils::convertJString(env, data));
} }
// static
void AndroidController::onImeInsetsChanged(JNIEnv *env, jobject thiz, jint heightDp)
{
Q_UNUSED(env);
Q_UNUSED(thiz);
qDebug() << "Android IME insets changed: height =" << heightDp << "dp";
emit AndroidController::instance()->imeInsetsChanged(heightDp);
}
// static
void AndroidController::onSystemBarsInsetsChanged(JNIEnv *env, jobject thiz, jint navBarHeightDp, jint statusBarHeightDp)
{
Q_UNUSED(env);
Q_UNUSED(thiz);
qDebug() << "Android system bars insets changed: nav bar =" << navBarHeightDp << "dp, status bar =" << statusBarHeightDp << "dp";
emit AndroidController::instance()->systemBarsInsetsChanged(navBarHeightDp, statusBarHeightDp);
}
@@ -73,6 +73,8 @@ signals:
void importConfigFromOutside(QString config); void importConfigFromOutside(QString config);
void initConnectionState(Vpn::ConnectionState state); void initConnectionState(Vpn::ConnectionState state);
void authenticationResult(bool result); void authenticationResult(bool result);
void imeInsetsChanged(int heightDp);
void systemBarsInsetsChanged(int navBarHeightDp, int statusBarHeightDp);
private: private:
bool isWaitingStatus = true; bool isWaitingStatus = true;
@@ -101,6 +103,8 @@ private:
static void onFileOpened(JNIEnv *env, jobject thiz, jstring uri); static void onFileOpened(JNIEnv *env, jobject thiz, jstring uri);
static void onAuthResult(JNIEnv *env, jobject thiz, jboolean result); static void onAuthResult(JNIEnv *env, jobject thiz, jboolean result);
static bool decodeQrCode(JNIEnv *env, jobject thiz, jstring data); static bool decodeQrCode(JNIEnv *env, jobject thiz, jstring data);
static void onImeInsetsChanged(JNIEnv *env, jobject thiz, jint heightDp);
static void onSystemBarsInsetsChanged(JNIEnv *env, jobject thiz, jint navBarHeightDp, jint statusBarHeightDp);
template <typename Ret, typename ...Args> template <typename Ret, typename ...Args>
static auto callActivityMethod(const char *methodName, const char *signature, Args &&...args); static auto callActivityMethod(const char *methodName, const char *signature, Args &&...args);
@@ -1,6 +1,7 @@
#include "settingsController.h" #include "settingsController.h"
#include <QStandardPaths> #include <QStandardPaths>
#include <QOperatingSystemVersion>
#include "logger.h" #include "logger.h"
#include "systemController.h" #include "systemController.h"
@@ -33,6 +34,17 @@ SettingsController::SettingsController(const QSharedPointer<ServersModel> &serve
checkIfNeedDisableLogs(); checkIfNeedDisableLogs();
#ifdef Q_OS_ANDROID #ifdef Q_OS_ANDROID
connect(AndroidController::instance(), &AndroidController::notificationStateChanged, this, &SettingsController::onNotificationStateChanged); connect(AndroidController::instance(), &AndroidController::notificationStateChanged, this, &SettingsController::onNotificationStateChanged);
connect(AndroidController::instance(), &AndroidController::imeInsetsChanged, this, [this](int heightDp) {
m_imeHeight = heightDp;
emit imeHeightChanged(heightDp);
emit safeAreaBottomMarginChanged();
});
connect(AndroidController::instance(), &AndroidController::systemBarsInsetsChanged, this, [this](int navBarHeightDp, int statusBarHeightDp) {
m_cachedNavigationBarHeight = navBarHeightDp;
m_cachedStatusBarHeight = statusBarHeightDp;
emit safeAreaBottomMarginChanged();
emit safeAreaTopMarginChanged();
});
#endif #endif
m_isDevModeEnabled = m_settings->isDevGatewayEnv(); m_isDevModeEnabled = m_settings->isDevGatewayEnv();
@@ -480,6 +492,10 @@ int SettingsController::getSafeAreaBottomMargin()
{ {
#ifdef Q_OS_ANDROID #ifdef Q_OS_ANDROID
if (isEdgeToEdgeEnabled()) { if (isEdgeToEdgeEnabled()) {
if (m_imeHeight > 0) {
return 0;
}
int height = getNavigationBarHeight(); int height = getNavigationBarHeight();
int result = height > 0 ? height : 56; // fallback to 56 if system returns 0 int result = height > 0 ? height : 56; // fallback to 56 if system returns 0
return result; return result;
@@ -488,6 +504,11 @@ int SettingsController::getSafeAreaBottomMargin()
return 0; return 0;
} }
int SettingsController::getImeHeight()
{
return m_imeHeight;
}
bool SettingsController::isHomeAdLabelVisible() bool SettingsController::isHomeAdLabelVisible()
{ {
return m_settings->isHomeAdLabelVisible(); return m_settings->isHomeAdLabelVisible();
+9 -2
View File
@@ -33,8 +33,9 @@ public:
Q_PROPERTY(bool isHomeAdLabelVisible READ isHomeAdLabelVisible NOTIFY isHomeAdLabelVisibleChanged) Q_PROPERTY(bool isHomeAdLabelVisible READ isHomeAdLabelVisible NOTIFY isHomeAdLabelVisibleChanged)
Q_PROPERTY(bool startMinimized READ isStartMinimizedEnabled NOTIFY startMinimizedChanged) Q_PROPERTY(bool startMinimized READ isStartMinimizedEnabled NOTIFY startMinimizedChanged)
Q_PROPERTY(int safeAreaTopMargin READ getSafeAreaTopMargin CONSTANT) Q_PROPERTY(int safeAreaTopMargin READ getSafeAreaTopMargin NOTIFY safeAreaTopMarginChanged)
Q_PROPERTY(int safeAreaBottomMargin READ getSafeAreaBottomMargin CONSTANT) Q_PROPERTY(int safeAreaBottomMargin READ getSafeAreaBottomMargin NOTIFY safeAreaBottomMarginChanged)
Q_PROPERTY(int imeHeight READ getImeHeight NOTIFY imeHeightChanged)
public slots: public slots:
void toggleAmneziaDns(bool enable); void toggleAmneziaDns(bool enable);
@@ -103,6 +104,7 @@ public slots:
int getNavigationBarHeight(); int getNavigationBarHeight();
int getSafeAreaTopMargin(); int getSafeAreaTopMargin();
int getSafeAreaBottomMargin(); int getSafeAreaBottomMargin();
int getImeHeight();
bool isHomeAdLabelVisible(); bool isHomeAdLabelVisible();
void disableHomeAdLabel(); void disableHomeAdLabel();
@@ -131,6 +133,10 @@ signals:
void devModeEnabled(); void devModeEnabled();
void gatewayEndpointChanged(const QString &endpoint); void gatewayEndpointChanged(const QString &endpoint);
void devGatewayEnvChanged(bool enabled); void devGatewayEnvChanged(bool enabled);
void imeHeightChanged(int height);
void safeAreaTopMarginChanged();
void safeAreaBottomMarginChanged();
void isHomeAdLabelVisibleChanged(bool visible); void isHomeAdLabelVisibleChanged(bool visible);
void startMinimizedChanged(); void startMinimizedChanged();
@@ -144,6 +150,7 @@ private:
mutable int m_cachedStatusBarHeight = -1; mutable int m_cachedStatusBarHeight = -1;
mutable int m_cachedNavigationBarHeight = -1; mutable int m_cachedNavigationBarHeight = -1;
int m_imeHeight = 0;
std::shared_ptr<Settings> m_settings; std::shared_ptr<Settings> m_settings;
QString m_appVersion; QString m_appVersion;
+16
View File
@@ -49,6 +49,22 @@ Item {
return drawerContent.state === stateName return drawerContent.state === stateName
} }
Connections {
target: Qt.application
function onStateChanged() {
if (Qt.application.state !== Qt.ApplicationActive) {
if (dragArea.drag.active) {
dragArea.drag.target = null
dragArea.drag.target = drawerContent
}
if (isOpened && !isCollapsedStateActive()) {
root.closeTriggered()
}
}
}
}
Connections { Connections {
target: PageController target: PageController
+12
View File
@@ -74,6 +74,18 @@ Item {
FocusController.nextKeyRightItem() FocusController.nextKeyRightItem()
} }
Connections {
target: Qt.application
function onStateChanged() {
if (Qt.application.state !== Qt.ApplicationActive) {
if (!menu.isClosed) {
menu.closeTriggered()
}
}
}
}
implicitWidth: rootButtonContent.implicitWidth implicitWidth: rootButtonContent.implicitWidth
implicitHeight: rootButtonContent.implicitHeight implicitHeight: rootButtonContent.implicitHeight
+1 -1
View File
@@ -45,7 +45,7 @@ PageType {
BaseHeaderType { BaseHeaderType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 20 Layout.topMargin: 20 + SettingsController.safeAreaTopMargin
Layout.leftMargin: 16 Layout.leftMargin: 16
Layout.rightMargin: 16 Layout.rightMargin: 16
+1 -1
View File
@@ -22,7 +22,7 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
} }
ListViewType { ListViewType {
+15
View File
@@ -20,6 +20,21 @@ import "../Components"
PageType { PageType {
id: root id: root
Connections {
target: Qt.application
function onStateChanged() {
if (Qt.application.state !== Qt.ApplicationActive) {
if (drawer.isOpened) {
drawer.closeTriggered()
}
if (homeSplitTunnelingDrawer.isOpened) {
homeSplitTunnelingDrawer.closeTriggered()
}
}
}
}
Connections { Connections {
objectName: "pageControllerConnections" objectName: "pageControllerConnections"
@@ -22,7 +22,7 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
onActiveFocusChanged: { onActiveFocusChanged: {
if(backButton.enabled && backButton.activeFocus) { if(backButton.enabled && backButton.activeFocus) {
@@ -66,7 +66,7 @@ PageType {
id: backButton id: backButton
objectName: "backButton" objectName: "backButton"
Layout.topMargin: 20 Layout.topMargin: 20 + SettingsController.safeAreaTopMargin
} }
HeaderTypeWithButton { HeaderTypeWithButton {
@@ -61,7 +61,7 @@ PageType {
width: root.width width: root.width
BackButtonType { BackButtonType {
Layout.topMargin: 20 Layout.topMargin: 20 + SettingsController.safeAreaTopMargin
} }
Label { Label {
@@ -103,7 +103,7 @@ PageType {
BaseHeaderType { BaseHeaderType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 20 Layout.topMargin: 20 + SettingsController.safeAreaTopMargin
Layout.leftMargin: 16 Layout.leftMargin: 16
Layout.rightMargin: 16 Layout.rightMargin: 16
@@ -147,6 +147,7 @@ PageType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 24 Layout.topMargin: 24
Layout.bottomMargin: 24 + SettingsController.safeAreaBottomMargin
Layout.leftMargin: 16 Layout.leftMargin: 16
Layout.rightMargin: 16 Layout.rightMargin: 16
@@ -20,7 +20,7 @@ PageType {
anchors.left: parent.left anchors.left: parent.left
anchors.top: parent.top anchors.top: parent.top
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
} }
ParagraphTextType { ParagraphTextType {
@@ -25,7 +25,7 @@ PageType {
source: "qrc:/images/amneziaBigLogo.png" source: "qrc:/images/amneziaBigLogo.png"
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Layout.topMargin: 32 Layout.topMargin: 32 + SettingsController.safeAreaTopMargin
Layout.preferredWidth: 360 Layout.preferredWidth: 360
Layout.preferredHeight: 287 Layout.preferredHeight: 287
} }
@@ -33,7 +33,7 @@ PageType {
BasicButtonType { BasicButtonType {
id: startButton id: startButton
Layout.fillWidth: true Layout.fillWidth: true
Layout.bottomMargin: 48 Layout.bottomMargin: 48 + SettingsController.safeAreaBottomMargin
Layout.leftMargin: 16 Layout.leftMargin: 16
Layout.rightMargin: 16 Layout.rightMargin: 16
Layout.alignment: Qt.AlignBottom Layout.alignment: Qt.AlignBottom
+3
View File
@@ -304,6 +304,9 @@ PageType {
anchors.right: parent.right anchors.right: parent.right
anchors.left: parent.left anchors.left: parent.left
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
// Also adjust TabBar position when keyboard appears (Android 14+ workaround)
anchors.bottomMargin: SettingsController.imeHeight
topPadding: 8 topPadding: 8
bottomPadding: 8 + SettingsController.safeAreaBottomMargin bottomPadding: 8 + SettingsController.safeAreaBottomMargin