Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 0 additions & 34 deletions app/androidutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -186,40 +186,6 @@ QString AndroidUtils::getDeviceModel()
return deviceModel;
}

QVector<int> AndroidUtils::getSafeArea()
{
QVector<int> ret;

#ifdef ANDROID
const auto activity = QJniObject( QNativeInterface::QAndroidApplication::context() );
const auto safeArrayStringObj = activity.callMethod<jintArray>( "getSafeArea", "()Ljava/lang/String;" );

if ( safeArrayStringObj.isValid() )
{
const QString safeArrayString = safeArrayStringObj.toString();

QStringList stringParts = safeArrayString.split( "," );
if ( stringParts.length() != 4 )
{
CoreUtils::log( "SafeArea", "Android returned malformed string from getSafeArea method" );
return ret;
}

const int top = stringParts[0].toInt(); // top inset
const int right = stringParts[1].toInt(); // right inset
const int bottom = stringParts[2].toInt(); // bottom inset
const int left = stringParts[3].toInt(); // left inset

ret << top << right << bottom << left;
return ret;
}

CoreUtils::log( "SafeArea", "Android returned null from getSafeArea method" );
return ret;
#endif
return ret;
}

void AndroidUtils::hideSplashScreen()
{
#ifdef ANDROID
Expand Down
2 changes: 0 additions & 2 deletions app/androidutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,6 @@ class AndroidUtils: public QObject

static QString getManufacturer();
static QString getDeviceModel();
Q_INVOKABLE QVector<int> getSafeArea();

static void hideSplashScreen();

/**
Expand Down
8 changes: 0 additions & 8 deletions app/ios/iosutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,6 @@ QString IosUtils::readExif( const QString &filepath, const QString &tag )
#endif
}

QVector<int> IosUtils::getSafeArea()
{
#ifdef Q_OS_IOS
return getSafeAreaImpl();
#endif
return QVector<int>();
}

QString IosUtils::getManufacturer()
{
#ifdef Q_OS_IOS
Expand Down
4 changes: 0 additions & 4 deletions app/ios/iosutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@ class IosUtils: public QObject
IOSImagePicker *imagePicker() const;
static QString readExif( const QString &filepath, const QString &tag );

Q_INVOKABLE QVector<int> getSafeArea();

Q_INVOKABLE static bool openFile( const QString &filePath );

static Q_INVOKABLE QString getManufacturer();
Expand All @@ -68,8 +66,6 @@ class IosUtils: public QObject
*/
void setIdleTimerDisabled();

QVector<int> getSafeAreaImpl();

static QString getManufacturerImpl();
static QString getDeviceModelImpl();
static bool openFileImpl( const QString &filePath );
Expand Down
20 changes: 0 additions & 20 deletions app/ios/iosutils.mm
Original file line number Diff line number Diff line change
Expand Up @@ -26,26 +26,6 @@
[[UIApplication sharedApplication] setIdleTimerDisabled:YES];
}

QVector<int> IosUtils::getSafeAreaImpl()
{
QVector<int> ret;

if ( @available( iOS 11.0, * ) )
{
UIWindow *window = UIApplication.sharedApplication.windows.firstObject;

int top = window.safeAreaInsets.top;
int right = window.safeAreaInsets.right;
int bottom = window.safeAreaInsets.bottom;
int left = window.safeAreaInsets.left;

ret << top << right << bottom << left;
return ret;
}

return ret;
}

QString IosUtils::getManufacturerImpl()
{
return "APPLE INC.";
Expand Down
56 changes: 16 additions & 40 deletions app/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -812,46 +812,6 @@ int main( int argc, char *argv[] )

engine.rootContext()->setContextProperty( "__version", version );

// Set safe areas for mobile devices
#ifdef ANDROID
auto safeAreaInsets = androidUtils.getSafeArea();

if ( safeAreaInsets.length() == 4 )
{
// Values from Android API must be scaled with dpr
qreal dpr = QGuiApplication::primaryScreen()->devicePixelRatio();
style->setSafeAreaTop( safeAreaInsets[0] / dpr );
style->setSafeAreaRight( safeAreaInsets[1] / dpr );
style->setSafeAreaBottom( safeAreaInsets[2] / dpr );
style->setSafeAreaLeft( safeAreaInsets[3] / dpr );
}
#elif defined( Q_OS_IOS )

//
// After migration to Qt 6.8.3, we can no longer reliably read the safe area on app startup (on iOS).
// It appears the UIWindow is not fully initialized, returning zero safe area insets.
// However, the window is correctly initialized once the event loop begins processing events.
// Therefore, we delay the safe area retrieval until after the event loop starts.
// This is a temporary workaround and might be replaced in the future by
// the more robust approach described in https://www.qt.io/blog/expanded-client-areas-and-safe-areas-in-qt-6.9.
//

const int SAFE_AREA_REFRESH_DELAY_MS = 10;

QTimer::singleShot( SAFE_AREA_REFRESH_DELAY_MS, &lambdaContext, [&iosUtils, &style]()
{
auto safeAreaInsets = iosUtils.getSafeArea();

if ( safeAreaInsets.length() == 4 )
{
style->setSafeAreaTop( safeAreaInsets[0] );
style->setSafeAreaRight( safeAreaInsets[1] );
style->setSafeAreaBottom( safeAreaInsets[2] );
style->setSafeAreaLeft( safeAreaInsets[3] );
}
} );

#endif

// Set simulated position for desktop builds
#ifdef DESKTOP_OS
Expand Down Expand Up @@ -914,6 +874,22 @@ int main( int argc, char *argv[] )
if ( QQuickWindow *quickWindow = qobject_cast<QQuickWindow *>( object ) )
{
quickWindow->setIcon( QIcon( logoUrl ) );

#if defined( ANDROID ) || defined( Q_OS_IOS )
// Qt 6.9+ provides QWindow::safeAreaMargins() natively for both Android and iOS.

auto applyMargins = [style, quickWindow]()
{
const QMargins m = quickWindow->safeAreaMargins();
Comment on lines +881 to +883
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we even need to read and store these if it is automatically handled by Qt?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are QML components that still use safe area values from MM style for calculating padding or heights/widths.
It is feasible to take them out completely, but I think we should do that after we have all the builds set up, because it needs comprehensive testing on all platforms. In this case, I would keep it as it is right now

style->setSafeAreaTop( m.top() );
style->setSafeAreaRight( m.right() );
style->setSafeAreaBottom( m.bottom() );
style->setSafeAreaLeft( m.left() );
};

QObject::connect( quickWindow, &QWindow::safeAreaMarginsChanged, &lambdaContext, applyMargins );
QTimer::singleShot( 10, &lambdaContext, applyMargins );
#endif
}

#ifdef DESKTOP_OS
Expand Down
7 changes: 7 additions & 0 deletions app/qml/components/MMPage.qml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ Page {

enum BottomMarginPolicy { UseMargin, PaintBehindSystemBar }

// Qt 6.9+ Page automatically adds safe area margins as padding.
// MMPageHeader and page content already handle safe areas manually.
topPadding: 0
bottomPadding: 0
leftPadding: 0
rightPadding: 0

implicitHeight: ApplicationWindow.window?.height ?? 0
implicitWidth: ApplicationWindow.window?.width ?? 0

Expand Down
7 changes: 7 additions & 0 deletions app/qml/form/MMFormController.qml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,13 @@ Item {
Drawer {
id: drawer

// Qt 6.9+ Popup/Drawer automatically applies safe area margins as padding.
// MMFormPage and MMPreviewDrawer already handle safe areas manually.
topPadding: 0
bottomPadding: 0
leftPadding: 0
rightPadding: 0

StateGroup {
id: statesManager

Expand Down
8 changes: 8 additions & 0 deletions app/qml/form/MMFormPage.qml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ import "../dialogs"
Page {
id: root

// Qt 6.9+ Page automatically adds safe area margins as padding.
// MMPageHeader and MMToolbar already handle safe areas manually, so
// we set them to zero to avoid double-applying the insets.
topPadding: 0
bottomPadding: 0
leftPadding: 0
rightPadding: 0

/**
* When feature in the form is saved.
*/
Expand Down
6 changes: 6 additions & 0 deletions app/qml/layers/MMLayerDetailPage.qml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ import "../inputs"
Page {
id: root

// Qt 6.9+ auto-applies safe area padding; child MMPage instances handle it manually.
topPadding: 0
bottomPadding: 0
leftPadding: 0
rightPadding: 0

signal close()
signal featureClicked( var featurePair )
signal addFeatureClicked( var targetLayer )
Expand Down
36 changes: 7 additions & 29 deletions app/qml/main.qml
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,13 @@ ApplicationWindow {

title: "Mergin Maps" // Do not translate

readonly property bool isPortraitOrientation: ( Screen.primaryOrientation === Qt.PortraitOrientation
|| Screen.primaryOrientation === Qt.InvertedPortraitOrientation )

onIsPortraitOrientationChanged: recalculateSafeArea()
// Qt 6.9+ ApplicationWindow automatically adds safe area margins as padding to its
// contentItem. Since this app manages safe areas manually via __style,
// we override the automatic padding to avoid double-applying the insets.
topPadding: 0
bottomPadding: 0
leftPadding: 0
rightPadding: 0

// start window where it was closed last time
onXChanged: storeWindowPosition()
Expand Down Expand Up @@ -1231,31 +1234,6 @@ ApplicationWindow {
}
}

function recalculateSafeArea() {
let safeArea = []

// Should be merged in future with the same code in main.cpp
if ( Qt.platform.os === "ios" ) {
safeArea = Array.from( __iosUtils.getSafeArea() )
}
else if ( Qt.platform.os === "android" ) {
safeArea = Array.from( __androidUtils.getSafeArea() )

// Values from Android API must be divided by dpr
safeArea[0] = safeArea[0] / Screen.devicePixelRatio
safeArea[1] = safeArea[1] / Screen.devicePixelRatio
safeArea[2] = safeArea[2] / Screen.devicePixelRatio
safeArea[3] = safeArea[3] / Screen.devicePixelRatio
}

if ( safeArea.length === 4 ) {
__style.safeAreaTop = safeArea[0]
__style.safeAreaRight = safeArea[1]
__style.safeAreaBottom = safeArea[2]
__style.safeAreaLeft = safeArea[3]
}
}

function storeWindowPosition() {
if ( Qt.platform.os !== "ios" && Qt.platform.os !== "android")
{
Expand Down
Loading