diff --git a/retroshare-qml-app/src/ContactDetails.qml b/retroshare-qml-app/src/ContactDetails.qml index 0336e74ca..2f9a799bf 100644 --- a/retroshare-qml-app/src/ContactDetails.qml +++ b/retroshare-qml-app/src/ContactDetails.qml @@ -27,6 +27,45 @@ Item id: cntDt property var md property bool is_contact: cntDt.md.is_contact + property bool isOwn: cntDt.md.own + + Button + { + id: avatarPicker + + text: "Change your Avatar" + visible: isOwn + + anchors.top: parent.top + anchors.horizontalCenter: parent.horizontalCenter + + onClicked: + { + fileChooser.open() + } + CustomFileChooser + { + id: fileChooser + onResultFileChanged: + { + console.log("Result file changed! " , resultFile) + + var base64Image = androidImagePicker.imageToBase64(resultFile) + + rsApi.request("/identity/set_avatar", JSON.stringify({"gxs_id": cntDt.md.gxs_id, "avatar": base64Image }), + function (par) + { + var jP = JSON.parse(par.response) + if (jP.returncode === "ok") + { + console.log("Avatar changed! ") + topFace.getDetails() + } + }) + } + } + } + AvatarOrColorHash { @@ -34,7 +73,7 @@ Item gxs_id: cntDt.md.gxs_id - anchors.top: parent.top + anchors.top: (isOwn)? avatarPicker.bottom : parent.top anchors.topMargin: 6 anchors.horizontalCenter: parent.horizontalCenter } diff --git a/retroshare-qml-app/src/android/AndroidManifest.xml b/retroshare-qml-app/src/android/AndroidManifest.xml index 321e1bd15..fb102300e 100644 --- a/retroshare-qml-app/src/android/AndroidManifest.xml +++ b/retroshare-qml-app/src/android/AndroidManifest.xml @@ -207,4 +207,8 @@ + + + + diff --git a/retroshare-qml-app/src/android/src/org/retroshare/android/qml_app/RetroShareQmlActivity.java b/retroshare-qml-app/src/android/src/org/retroshare/android/qml_app/RetroShareQmlActivity.java index 8d3479f95..365778142 100644 --- a/retroshare-qml-app/src/android/src/org/retroshare/android/qml_app/RetroShareQmlActivity.java +++ b/retroshare-qml-app/src/android/src/org/retroshare/android/qml_app/RetroShareQmlActivity.java @@ -19,17 +19,25 @@ package org.retroshare.android.qml_app; import android.app.ActivityManager; +import android.content.ContentValues; import android.content.Context; import android.content.Intent; +import android.database.Cursor; import android.os.Bundle; +import android.provider.MediaStore; import android.util.Log; +import android.net.Uri; + import org.qtproject.qt5.android.bindings.QtActivity; import org.retroshare.android.qml_app.jni.NativeCalls; public class RetroShareQmlActivity extends QtActivity { + + static final int PICK_PHOTO = 1; + @Override public void onCreate(Bundle savedInstanceState) { @@ -84,4 +92,88 @@ public class RetroShareQmlActivity extends QtActivity return true; return false; } + + private Uri capturedImageURI; + + public void openImagePicker() + { + Log.i("RetroShareQmlActivity", "openImagePicker()"); + + Intent pickIntent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI); + pickIntent.setType("image/*"); + + ContentValues values = new ContentValues(); + values.put(MediaStore.Images.Media.TITLE, "Retroshare Avatar"); + capturedImageURI = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); + Intent takePicture = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); + takePicture.putExtra(MediaStore.EXTRA_OUTPUT, capturedImageURI); + + Intent chooserIntent = Intent.createChooser(pickIntent, "Select Image"); + chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Intent[] {takePicture}); + + startActivityForResult( chooserIntent, PICK_PHOTO); + }; + + public void onActivityResult(int requestCode, int resultCode, Intent data) + { + Log.i("RetroShareQmlActivity", "onActivityResult()" + String.valueOf(requestCode)); + + if (resultCode == RESULT_OK) + { + if (requestCode == PICK_PHOTO) + { + final boolean isCamera; + + if (data == null) + { + isCamera = true; + } + else + { + final String action = data.getAction(); + if (action == null) + { + isCamera = false; + } + else + { + isCamera = action.equals(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); + } + } + + Uri selectedImageUri; + if (isCamera) + { + selectedImageUri = capturedImageURI; + } + else + { + selectedImageUri = data == null ? null : data.getData(); + } + + String uri = getRealPathFromURI(selectedImageUri); + if (uri != null) + { + Log.i("RetroShareQmlActivity", "Image path from uri found!" + uri); + NativeCalls.notifyIntentUri("//file"+uri); // Add the authority for get it on qml code + } + } + } + } + + public String getRealPathFromURI(Uri uri) { + String[] projection = { MediaStore.Images.Media.DATA }; + @SuppressWarnings("deprecation") + Cursor cursor = managedQuery(uri, projection, null, null, null); + int column_index = cursor + .getColumnIndexOrThrow(MediaStore.Images.Media.DATA); + cursor.moveToFirst(); + String result = cursor.getString(column_index); + return result; + } + + + + + } diff --git a/retroshare-qml-app/src/androidimagepicker.h b/retroshare-qml-app/src/androidimagepicker.h new file mode 100644 index 000000000..ad5f0e302 --- /dev/null +++ b/retroshare-qml-app/src/androidimagepicker.h @@ -0,0 +1,66 @@ +#pragma once + +#include +#include + +#include +#include +#include +#include +#include + + +#ifdef __ANDROID__ +# include +# include +#endif // __ANDROID__ + +struct AndroidImagePicker : QObject +{ + Q_OBJECT + +public slots: + + static void openPicker() + { + qDebug() << "Starting image picker intent"; + +#ifdef __ANDROID__ + QtAndroid::androidActivity().callMethod( + "openImagePicker", + "()V" ); +#endif // __ANDROID__ + + } + + // Used to convert a given image path into a png base64 string + static QString imageToBase64 (QString const& path) + { + // Get local path from uri + QUrl url (path); + QString localPath = url.toLocalFile(); + + qDebug() << "imageToBase64() local path:" << localPath ; + + // Read the image + QImageReader reader; + reader.setFileName(localPath); + QImage image = reader.read(); + + image = image.scaled(96,96,Qt::KeepAspectRatio,Qt::SmoothTransformation); + + // Transform image into PNG format + QByteArray ba; + QBuffer buffer( &ba ); + buffer.open( QIODevice::WriteOnly ); + image.save( &buffer, "png" ); + + // Get Based 64 image string + QString encoded = QString(ba.toBase64()); + + qDebug() << "imageToBase64() encoded" ; + + return encoded; + + } +}; diff --git a/retroshare-qml-app/src/components/CustomFileChooser.qml b/retroshare-qml-app/src/components/CustomFileChooser.qml new file mode 100644 index 000000000..e7451dee5 --- /dev/null +++ b/retroshare-qml-app/src/components/CustomFileChooser.qml @@ -0,0 +1,60 @@ +import QtQuick 2.7 +import QtQuick.Dialogs 1.2 + +import "../URI.js" as UriJs + +Item +{ + id: compRoot + + property var resultFile + + FileDialog + { + id: fileDialog + title: "Please choose a file" + folder: shortcuts.pictures + nameFilters: [ "Image files (*.png *.jpg)"] + visible: false + selectMultiple: false + onAccepted: { + console.log("You chose: " + fileDialog.fileUrl) + resultFile = fileDialog.fileUrl + } + onRejected: { + console.log("Canceled") + } + } + + + function open() + { + if (Qt.platform.os === "android") + { + console.log("ImagePicker Android platform detected") + mainWindow.addUriHandler("file", androidResult) + androidImagePicker.openPicker() + } + else + { + fileDialog.visible = true + } + } + + function androidResult (uri) + { + console.log("QML Android image uri found" , uri) + resultFile = normalizeUriToFilePath (uri) + mainWindow.delUriHandler("media", androidResult) + } + + function normalizeUriToFilePath (uriStr) + { + var uri = new UriJs.URI(uriStr) + var hPath = uri.path() + return "file:///"+hPath + + } + + +} diff --git a/retroshare-qml-app/src/main-app.cpp b/retroshare-qml-app/src/main-app.cpp index 5e5fd532f..b52febcfb 100644 --- a/retroshare-qml-app/src/main-app.cpp +++ b/retroshare-qml-app/src/main-app.cpp @@ -38,9 +38,9 @@ #include "libresapilocalclient.h" #include "rsqmlappengine.h" +#include "androidimagepicker.h" #include "platforminteracions.h" - int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); @@ -52,6 +52,7 @@ int main(int argc, char *argv[]) "org.retroshare.qml_components.LibresapiLocalClient", 1, 0, "LibresapiLocalClient"); + QString sockPath = QDir::homePath() + "/.retroshare"; sockPath.append("/libresapi.sock"); @@ -61,6 +62,14 @@ int main(int argc, char *argv[]) RsQmlAppEngine engine(true); QQmlContext& rootContext = *engine.rootContext(); + qmlRegisterType( + "org.retroshare.qml_components.AndroidImagePicker", 1, 0, + "AndroidImagePicker"); + + AndroidImagePicker androidImagePicker; + engine.rootContext()->setContextProperty("androidImagePicker", + &androidImagePicker); + QStringList mainArgs = app.arguments(); #ifdef Q_OS_ANDROID diff --git a/retroshare-qml-app/src/main-app.qml b/retroshare-qml-app/src/main-app.qml index 889bf7ace..17634d741 100644 --- a/retroshare-qml-app/src/main-app.qml +++ b/retroshare-qml-app/src/main-app.qml @@ -364,7 +364,7 @@ ApplicationWindow function handleIntentUri(uriStr) { - console.log("handleIntentUri(uriStr)") + console.log("handleIntentUri(uriStr)", uriStr) if(!Array.isArray(uriStr.match(/:\/\/[a-zA-Z.-]*\//g))) { @@ -382,7 +382,10 @@ ApplicationWindow var uri = new UriJs.URI(uriStr) var hPath = uri.path() // no nesting ATM segmentCoded() - console.log(hPath) + console.log("hPath", hPath) + + var authority = uri.authority() + console.log("authority", authority) if(typeof uriHandlersRegister[hPath] == "function") { @@ -390,6 +393,13 @@ ApplicationWindow hPath, uriHandlersRegister[hPath]) uriHandlersRegister[hPath](uriStr) } + + else if (typeof uriHandlersRegister[authority] == "function" ) + { + console.log("handleIntentUri(uriStr)", "found handler for path", + authority, uriHandlersRegister[authority]) + uriHandlersRegister[authority](uriStr) + } } function certificateLinkHandler(uriStr) diff --git a/retroshare-qml-app/src/qml.qrc b/retroshare-qml-app/src/qml.qrc index 6332dc6da..fb2a636f0 100644 --- a/retroshare-qml-app/src/qml.qrc +++ b/retroshare-qml-app/src/qml.qrc @@ -53,5 +53,6 @@ components/emoji/emoji.js icons/network-connect.svg icons/network-disconnect.svg + components/CustomFileChooser.qml diff --git a/retroshare-qml-app/src/retroshare-qml-app.pro b/retroshare-qml-app/src/retroshare-qml-app.pro index 8dc2db67f..ff10bbc6b 100644 --- a/retroshare-qml-app/src/retroshare-qml-app.pro +++ b/retroshare-qml-app/src/retroshare-qml-app.pro @@ -6,6 +6,7 @@ CONFIG += c++11 HEADERS += libresapilocalclient.h \ rsqmlappengine.h \ + androidimagepicker.h \ platforminteracions.h SOURCES += main-app.cpp \ libresapilocalclient.cpp \