Search code examples
qtqmlphoto-gallery

Photo gallery in iOS and Android


I am developing an app for mobile to run in iOS and Android and I am facing some difficulties to access the image gallery of the devices with Qml.

I need to list the images from image gallery in a GridView.

I have tried to return the pictures folder using QStandardPaths but it just works for desktop computers. For smartphones running iOS and Android it returns a folder that is not the folder of the gallery.

Could someone help me to figure out how I can do that? My code is below:

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>

#include <QtQml>

#include "caminhoimagens.h"

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    qmlRegisterType<caminhoImagens>("PathImagens", 1, 0, "CaminhoImagens");

    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    return app.exec();
}

main.qml

import QtQuick 2.4
import QtQuick.Window 2.2
import QtQuick.Controls 1.3
import QtQuick.Dialogs 1.2

import Qt.labs.folderlistmodel 2.1

import PathImagens 1.0

Window {
    visible: true

    width: 360
    height: 640

    maximumHeight: 640
    minimumHeight: 640

    maximumWidth: 360
    minimumWidth: 360

    title: "Acessar Galeria Test"

    Rectangle {
        id: principal

        anchors.fill: parent

        ListModel {
            id: listModel
        }

        FolderListModel {
            id: folderListModel

            folder: "file://" + caminhoImagens.retornaCaminhoImagens()
            nameFilters: "*.jpeg"
        }

        CaminhoImagens {
            id: caminhoImagens
        }

        Item {
            id: listaFotosDelegate

            property Component delegateComponent: listaFotosDelegateComponent

            Component {
                id: listaFotosDelegateComponent

                Image {
                    id: imagem

                    source: folderListModel.folder + "/" + fileName

                    width: principal.width / 4.2
                    height: principal.width / 4.2

                    fillMode: Image.PreserveAspectCrop
                }
            }
        }

        GridView {
            id: listaFotosGridView

            anchors.fill: parent

            clip: true

            model: folderListModel

            delegate: listaFotosDelegate.delegateComponent

            cellWidth: parent.width / 4
            cellHeight: parent.width / 4
        }
    }
}

caminhoimagens.h

#ifndef CAMINHOIMAGENS_H
#define CAMINHOIMAGENS_H

#include <QObject>
#include <QStandardPaths>

class caminhoImagens : public QObject
{
    Q_OBJECT

public slots:
    QString retornaCaminhoImagens();

public:
    caminhoImagens();
};

#endif // CAMINHOIMAGENS_H

caminhoimagens.cpp

#include "caminhoimagens.h"

caminhoImagens::caminhoImagens()
{

}

QString caminhoImagens::retornaCaminhoImagens()
{
    return QStandardPaths::locate(QStandardPaths::PicturesLocation, QString(), QStandardPaths::LocateDirectory);
}

Solution

  • Answering my own question.

    in iOS just create a FileDialog inside the QML file and set folder: shortcuts.pictures. It will call the iOS gallery.

    In Android it is a harder job once it's needed to integrate java code.

    I have done my code in Qt using QAndroidJniObject to write a equivalent java code.

    caminhoimagens.h

    #ifndef CAMINHOIMAGENS_H
    #define CAMINHOIMAGENS_H
    
    #include <QObject>
    
    #include "imagepickerandroid.h"
    
    #include <QDebug>
    
    class caminhoImagens : public QObject
    {
        Q_OBJECT
    
        Q_PROPERTY(QString imagemCaminho READ imagemCaminho NOTIFY imagemCaminhoChanged)
    
    public slots:
        void buscaImagem();
        void retornaImagem(QString path);
    
    public:
        caminhoImagens();
    
        QString imagemCaminho();
    
    private:
        QString m_imagemCaminho = "";
    
    signals:
        void imagemCaminhoChanged();
    };
    
    #endif //CAMINHOIMAGENS_H
    

    caminhoimagens.cpp

    #include "caminhoimagens.h"
    
    caminhoImagens::caminhoImagens()
    {
    
    }
    
    void caminhoImagens::buscaImagem()
    {
        imagePickerAndroid *imagePicker = new imagePickerAndroid();
        connect(imagePicker, SIGNAL(imagemCaminhoSignal(QString)), this, SLOT(retornaImagem(QString)));
    
        imagePicker->buscaImagem();
    }
    
    void caminhoImagens::retornaImagem(QString path)
    {
        qDebug() << path;
    
        m_imagemCaminho = path;
    
        emit imagemCaminhoChanged();
    }
    
    QString caminhoImagens::imagemCaminho()
    {
        return m_imagemCaminho;
    }
    

    imagepickerandroid.h

    #ifndef IMAGEPICKERANDROID_H
    #define IMAGEPICKERANDROID_H
    
    
    #include <QObject>
    #include <QtAndroidExtras>
    
    #include <QDebug>
    
    class imagePickerAndroid : public QObject, public QAndroidActivityResultReceiver
    {
        Q_OBJECT
    
    public:
        imagePickerAndroid();
    
        void buscaImagem();
    
        virtual void handleActivityResult(int receiverRequestCode, int resultCode, const QAndroidJniObject & data);
    
    signals:
        void imagemCaminhoSignal(QString);
    };
    
    #endif // IMAGEPICKERANDROID_H
    

    imagepickerandroid.cpp

    #include "imagepickerandroid.h"
    
    imagePickerAndroid::imagePickerAndroid()
    {
    
    }
    
    void imagePickerAndroid::buscaImagem()
    {
        QAndroidJniObject ACTION_PICK = QAndroidJniObject::fromString("android.intent.action.GET_CONTENT");
        QAndroidJniObject intent("android/content/Intent");
        if (ACTION_PICK.isValid() && intent.isValid())
        {
            intent.callObjectMethod("setAction", "(Ljava/lang/String;)Landroid/content/Intent;", ACTION_PICK.object<jstring>());
            intent.callObjectMethod("setType", "(Ljava/lang/String;)Landroid/content/Intent;", QAndroidJniObject::fromString("image/*").object<jstring>());
            QtAndroid::startActivity(intent.object<jobject>(), 101, this);
            qDebug() << "OK";
        }
        else
        {
            qDebug() << "ERRO";
        }
    }
    
    void imagePickerAndroid::handleActivityResult(int receiverRequestCode, int resultCode, const QAndroidJniObject &data)
    {
        qDebug() << "Trabalha com os dados";
    
        jint RESULT_OK = QAndroidJniObject::getStaticField<jint>("android/app/Activity", "RESULT_OK");
        if (receiverRequestCode == 101 && resultCode == RESULT_OK) {
            QString imagemCaminho = data.callObjectMethod("getData", "()Landroid/net/Uri;").callObjectMethod("getPath", "()Ljava/lang/String;").toString();
            emit imagemCaminhoSignal(imagemCaminho);
    
            qDebug() << imagemCaminho;
        }
        else
        {
            qDebug() << "Caminho errado";
        }
    }