Skip to content

Commit 35afc92

Browse files
committed
chore: mobile MVP fixes
- fixup Android permissions and local file access - tooltip metrics - Browser settings subsection properly enabled/disabled
1 parent 6d4aa75 commit 35afc92

File tree

14 files changed

+91
-48
lines changed

14 files changed

+91
-48
lines changed

mobile/android/qt6/AndroidManifest.xml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,13 @@
2121
<uses-feature android:name="android.hardware.fingerprint" android:required="false" />
2222

2323
<!-- dangerous permissions -->
24+
<uses-permission android:name="android.permission.CAMERA"/>
25+
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
2426
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
25-
<uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" />
27+
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
2628
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
2729
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
30+
<uses-permission android:name="android.permission.RECORD_AUDIO" />
2831

2932
<supports-screens
3033
android:anyDensity="true"

src/app/modules/main/profile_section/advanced/module.nim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ method onFleetSet*(self: Module) =
6363
quit(QuitSuccess) # quits the app TODO: change this to logout instead when supported
6464

6565
method getLogDir*(self: Module): string =
66-
return url_fromLocalFile(constants.LOGDIR)
66+
return constants.LOGDIR
6767

6868
method getWakuV2LightClientEnabled*(self: Module): bool =
6969
return self.controller.getWakuV2LightClientEnabled()

ui/StatusQ/include/StatusQ/urlutils.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,8 @@ class UrlUtils : public QObject
4040
// ["jpg", "jpe", "jp", "jpeg", "png", "webp", "gif", "svg"]
4141
QStringList m_allImgExtensions;
4242
QStringList allValidImageExtensions() const { return m_allImgExtensions; }
43+
44+
#ifdef Q_OS_ANDROID
45+
QString resolveAndroidContentUrl(const QString& urlPath) const;
46+
#endif
4347
};

ui/StatusQ/src/StatusQ/Controls/StatusToolTip.qml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ ToolTip {
2525
Math.max(implicitBackgroundWidth + leftInset + rightInset,
2626
implicitContentWidth + leftPadding + rightPadding)
2727
)
28-
padding: Theme.halfPadding
29-
horizontalPadding: padding + 4
28+
horizontalPadding: Theme.padding
29+
verticalPadding: Theme.halfPadding
3030
margins: Theme.halfPadding
3131
delay: Utils.isMobile ? Application.styleHints.mousePressAndHoldInterval
3232
: 200
@@ -43,8 +43,8 @@ ToolTip {
4343
Rectangle {
4444
id: arrow
4545
color: statusToolTipContentBackground.color
46-
height: 20
47-
width: 20
46+
height: Theme.padding
47+
width: Theme.padding
4848
rotation: 45
4949
radius: 1
5050
x: {

ui/StatusQ/src/StatusQ/Popups/Dialog/StatusFileDialog.qml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ QObject {
1818
property alias currentFolder: dlg.currentFolder
1919

2020
property string picturesShortcut: Utils.isIOS ? "assets-library://" :
21-
StandardPaths.writableLocation(StandardPaths.PicturesLocation)
21+
StandardPaths.standardLocations(StandardPaths.PicturesLocation)[0]
2222

2323
signal accepted
2424
signal rejected
@@ -45,6 +45,7 @@ QObject {
4545
resolvedLocalFile = "file:" + resolvedLocalFile
4646
return resolvedLocalFile
4747
}
48+
4849
function resolveSelectedFiles(selectedFiles) {
4950
if (selectedFiles.length === 0)
5051
return []

ui/StatusQ/src/systemutilsinternal.cpp

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,21 @@
1-
#ifdef Q_OS_ANDROID
2-
#include <QJniObject>
3-
#include <QtCore/qnativeinterface.h>
4-
#endif
51
#include "StatusQ/systemutilsinternal.h"
62

7-
#include <QDir>
83
#include <QGuiApplication>
94
#include <QMimeDatabase>
105
#include <QNetworkAccessManager>
116
#include <QNetworkReply>
127
#include <QProcess>
138
#include <QSaveFile>
9+
#include <QStandardPaths>
1410

1511
#ifdef Q_OS_ANDROID
1612
#include <QJniObject>
1713
#include <QtCore/qnativeinterface.h>
1814
#endif
1915

16+
#ifdef Q_OS_IOS
2017
#include "ios_utils.h"
18+
#endif
2119

2220
class QuitFilter : public QObject
2321
{
@@ -26,7 +24,7 @@ class QuitFilter : public QObject
2624
public:
2725
using QObject::QObject;
2826

29-
bool eventFilter(QObject* obj, QEvent* ev)
27+
bool eventFilter(QObject* obj, QEvent* ev) override
3028
{
3129
if (ev->type() == QEvent::Quit)
3230
emit quit(ev->spontaneous());
@@ -60,12 +58,6 @@ void SystemUtilsInternal::restartApplication() const
6058
QMetaObject::invokeMethod(QCoreApplication::instance(), &QCoreApplication::exit, Qt::QueuedConnection, EXIT_SUCCESS);
6159
}
6260

63-
#if defined(Q_OS_IOS)
64-
void save(const QByteArray& imageData)
65-
{
66-
saveImageToPhotosAlbum(imageData);
67-
}
68-
#else
6961
void save(const QByteArray& imageData, const QString& targetDir)
7062
{
7163

@@ -99,7 +91,6 @@ void save(const QByteArray& imageData, const QString& targetDir)
9991
"Downloading image failed while saving to file:"
10092
<< targetFile;
10193
}
102-
#endif
10394

10495
void SystemUtilsInternal::downloadImageByUrl(
10596
const QUrl& url, const QString& path) const
@@ -110,10 +101,15 @@ void SystemUtilsInternal::downloadImageByUrl(
110101
QNetworkReply *reply = manager.get(QNetworkRequest(url));
111102

112103
// accept both "file:/foo/bar" and "/foo/bar"
113-
auto targetDir = QUrl::fromUserInput(path).toLocalFile();
104+
auto targetDir = QUrl::fromUserInput(path)
105+
#ifndef Q_OS_ANDROID
106+
.toLocalFile();
107+
#else
108+
.toString(); // don't touch the "content://" URI
109+
#endif
114110

115111
if (targetDir.isEmpty())
116-
targetDir = QDir::homePath();
112+
targetDir = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
117113

118114
QObject::connect(reply, &QNetworkReply::finished, this, [reply, targetDir] {
119115
if(reply->error() != QNetworkReply::NoError) {
@@ -125,11 +121,11 @@ void SystemUtilsInternal::downloadImageByUrl(
125121
// Extract the image data to be able to load and save it
126122
const auto btArray = reply->readAll();
127123
Q_ASSERT(!btArray.isEmpty());
128-
#ifdef Q_OS_IOS
129-
save(btArray);
130-
#else
124+
#ifdef Q_OS_IOS
125+
saveImageToPhotosAlbum(btArray);
126+
#else
131127
save(btArray, targetDir);
132-
#endif
128+
#endif
133129
});
134130
}
135131

ui/StatusQ/src/urlutils.cpp

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
#include "StatusQ/urlutils.h"
22

3+
#include <QDir>
34
#include <QFile>
45
#include <QImageReader>
6+
#include <QStandardPaths>
57
#include <QUrl>
68

9+
#ifdef Q_OS_IOS
710
#include "ios_utils.h"
11+
#endif
812

913
namespace {
1014
constexpr auto webpMime = "image/webp";
@@ -30,34 +34,57 @@ UrlUtils::UrlUtils(QObject *parent): QObject(parent) {
3034

3135
bool UrlUtils::isValidImageUrl(const QUrl &url) const
3236
{
33-
QString mimeType;
34-
if (url.isLocalFile())
35-
mimeType = m_mimeDb.mimeTypeForFile(url.toLocalFile(), QMimeDatabase::MatchContent).name();
36-
else
37-
mimeType = m_mimeDb.mimeTypeForUrl(url).name();
37+
// don't convert "content:/" like URLs to an empty path
38+
const auto filePath = url.isLocalFile() ? url.toLocalFile() : url.toString();
39+
const auto mimeType = m_mimeDb.mimeTypeForFile(filePath, QMimeDatabase::MatchContent).name();
3840

3941
return m_validImageMimeTypes.contains(mimeType);
4042
}
4143

4244
qint64 UrlUtils::getFileSize(const QUrl& url)
4345
{
44-
if (url.isLocalFile())
45-
return QFile(url.toLocalFile()).size();
46-
47-
return 0;
46+
// don't convert "content:/" like URLs to an empty path
47+
const auto filePath = url.isLocalFile() ? url.toLocalFile() : url.toString();
48+
return QFile(filePath).size(); // will return 0 for unknown file paths
4849
}
4950

5051
QString UrlUtils::convertUrlToLocalPath(const QString &url) const {
52+
#ifdef Q_OS_ANDROID
53+
return resolveAndroidContentUrl(url);
54+
#endif
55+
5156
const auto localFileOrUrl = urlFromUserInput(url); // accept both "file:/foo/bar" and "/foo/bar"
5257
if (localFileOrUrl.isLocalFile()) {
53-
#ifdef Q_OS_IOS
58+
#ifdef Q_OS_IOS
5459
return resolveIOSPhotoAsset(localFileOrUrl.toLocalFile());
55-
#endif // Q_OS_IOS
60+
#endif
5661
return localFileOrUrl.toLocalFile();
5762
}
5863
return {};
5964
}
6065

66+
#ifdef Q_OS_ANDROID
67+
QString UrlUtils::resolveAndroidContentUrl(const QString& urlPath) const {
68+
QDir dir(urlPath);
69+
if (urlPath.endsWith('/') || dir.exists())
70+
return urlPath; // a directory, just return it
71+
72+
QFile fileIn(urlPath);
73+
if (!fileIn.open(QIODevice::ReadOnly))
74+
return urlPath;
75+
76+
// save to a temp file, and return the filepath
77+
const auto newFilePath = QStandardPaths::writableLocation(QStandardPaths::TempLocation) + '/' + QUuid::createUuid().toString(QUuid::WithoutBraces);
78+
QFile fileOut(newFilePath);
79+
if (!fileOut.open(QIODevice::WriteOnly | QIODevice::Truncate))
80+
return urlPath;
81+
if (fileOut.write(fileIn.readAll()) != -1)
82+
return fileOut.fileName(); // return the real filename, not the virtual "content:/" URI
83+
84+
return urlPath;
85+
}
86+
#endif
87+
6188
QStringList UrlUtils::convertUrlsToLocalPaths(const QStringList &urls) const {
6289
QStringList result;
6390
for (const auto& url: urls) {

ui/app/AppLayouts/Profile/ProfileLayout.qml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ StatusSectionLayout {
150150
id: settingsEntriesModel
151151

152152
showWalletEntries: root.walletStore.isWalletEnabled
153-
showBrowserEntries: root.isBrowserEnabled
153+
showBrowserEntries: root.isBrowserEnabled && localAccountSensitiveSettings.isBrowserEnabled
154154
showBackUpSeed: !root.privacyStore.mnemonicBackedUp
155155
backUpSeedBadgeCount: root.profileStore.userDeclinedBackupBanner ? 0 : showBackUpSeed
156156
isKeycardEnabled: root.isKeycardEnabled

ui/app/AppLayouts/Profile/helpers/SettingsEntriesModel.qml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ SortFilterProxyModel {
217217
case Constants.settingsSubsection.ensUsernames:
218218
case Constants.settingsSubsection.wallet:
219219
return root.showWalletEntries
220-
case Constants.settingsSubsection.browser:
220+
case Constants.settingsSubsection.browserSettings:
221221
return root.showBrowserEntries
222222
case Constants.settingsSubsection.backUpSeed:
223223
return root.showBackUpSeed

ui/app/AppLayouts/Profile/views/AdvancedView.qml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import shared.popups
1111
import shared.status
1212
import shared.controls
1313

14+
import StatusQ
1415
import StatusQ.Components
1516
import StatusQ.Controls
1617
import StatusQ.Controls.Validators
@@ -104,7 +105,7 @@ SettingsContentBase {
104105
cursorShape: Qt.PointingHandCursor
105106
hoverEnabled: true
106107
onClicked: {
107-
Qt.openUrlExternally(root.advancedStore.logDir())
108+
Qt.openUrlExternally(UrlUtils.urlFromUserInput(root.advancedStore.logDir()));
108109
}
109110
}
110111
}

0 commit comments

Comments
 (0)