HowTo get Photos from iOS assets-library sorted by lastModified ?


  • Qt Champions 2016

    no problem to get the assets-library - directory and iterate over entries

    QDir theDir = QDir("assets-library://");
    QFileInfoList entryList = theDir.entryInfoList();
    for (int i = 0; i < entryList.size(); ++i) {
        QFileInfo fileInfo = entryList.at(i);
    	// fileInfo.filePath() is something like this:
    	// "assets-library://asset/asset.JPG?id=01DC0CE7-0A57-4B42-BF2E-9A5719D04E1D&ext=JPG" 
    

    having access to the Photos from QML or C++ and display as Image - no problem

    unfortunately the Photos are not sorted
    fileInfo.lastModified() and fileInfo.created() from QFileInfo are empty, so I cannot do a sort from C++

    I know that there's a way to use the native iOS ImagePicker:

    import Qt.labs.platform 1.0
    // hint: also tried FileDialog from QtQuick.Dialogs 1.2
    // but J-P told me QtQuick.Dialogs FileDialog is a 'Monster' - I should use from labs.platform
    FileDialog {
        fileMode: FileDialog.OpenFiles
        property var standardPicturesLocations: StandardPaths.standardLocations(StandardPaths.PicturesLocation)
        folder: standardPicturesLocations[standardPicturesLocations.length - 1]
    }
    

    but this native Picker only allows us to pick single Photos
    https://bugreports.qt.io/browse/QTBUG-67874

    But I need multi-selection of files, so I created a GridView to preview thumbnails and to select one or more. This works fine but users are complaining that the Photos are not sorted.

    Seems I need som iOS native code to get a sorted Array of Pathes to Photos from assets-library.
    Looked at StackOverFlow and found nothing I really understand with less knowledge on native iOS / Obj-C development.

    Anyone has solved this or any ideas HowTo get the list of Photos from iOS sorted ?

    (will provide the solution together with my nearly ready-to-go QML Camera App for Android / iOS)

    THANKS


  • Lifetime Qt Champion

    Hi,

    Can you also share the stack overflow answers that could be useful ? It might be easier with several pair of eyes to get something up and running.


  • Qt Champions 2016

    @SGaist good idea. will add this later today or tomorrow.


  • Qt Champions 2016

    @SGaist here's what I found in StackOverFlow

    https://stackoverflow.com/questions/7977664/sort-files-by-creation-date-ios#
    don't know if this would work with assets (Photos)

    --
    https://stackoverflow.com/questions/30602830/phfetchresult-get-all-photos-and-sort-by-date-inconsistent/30603715
    seems this does what I want, but how to implement that in a way toget an array of pathes for the Photos

    --
    would be cool if someone has an idea HowTo combine this with Qt C++ to get a sorted list of pathes from "assets-library://"
    and what must be put into .h and what into .mm to call it from Qt

    thanks for any tips and hints


  • Qt Champions 2016

    @ekkescorner anyone ideas ?
    otherwise next week I have to start fighting with Obj-C to make it work ;-)


  • Qt Champions 2016

    figured it out to get iOS Photos sorted for multi-select. will provide src later


  • Lifetime Qt Champion

    Sorry, I lost track of the thread.

    Glad you found out !


  • Qt Champions 2016

    @SGaist here's my solution

    .pro:

    ios {
        LIBS += -framework Photos
    

    cpp: (.mm)

    #import <Photos/Photos.h>
    
    const int MEDIA_PHOTOS = 1;
    const int MEDIA_VIDEOS = 2;
    #pragma unused (MEDIA_VIDEOS)
    const QString MEDIA_PHOTO_SUFFIX = "JPG";
    const QString MEDIA_VIDEO_SUFFIX = "MP4";
    ...
    QVariantMap IosUtil::fetchAssets(const int mediaType)
    {
        QVariantMap albumsWithSortedAssetsMap;
        QMap<QDateTime, QString> assetsMap;
        // get the smart albums
        PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
        for (NSUInteger i = 0; i < smartAlbums.count; i++) {
            PHAssetCollection *assetCollection = smartAlbums[i];
            // the smart album name
            QString theAlbum = QString::fromNSString(assetCollection.localizedTitle);
    
            // get photo collections for this album
            PHFetchResult *assetsFetchResult = [PHAsset fetchAssetsInAssetCollection:assetCollection options:nil];
    
            // to get it sorted by modificationDate we use a Map
            assetsMap.clear();
    
            // get the Assets (Photos or Videos)
            for (NSUInteger x = 0; x < assetsFetchResult.count; x ++) {
                PHAsset *asset = assetsFetchResult[x];
                int mt = asset.mediaType;
                if(mt != mediaType) {
                    continue;
                }
                QString theSuffix;
                if(mediaType == MEDIA_PHOTOS) {
                    theSuffix = MEDIA_PHOTO_SUFFIX;
                } else {
                    theSuffix = MEDIA_VIDEO_SUFFIX;
                }
                QDateTime modificationDate = QDateTime::fromNSDate(asset.modificationDate);
    
                // now constructing the URL
                // https://stackoverflow.com/questions/42579544/ios-phassetcollection-localizedtitle-always-returning-english-name
                // https://stackoverflow.com/questions/28887638/how-to-get-an-alasset-url-from-a-phasset
                // AF3C1B68-222B-43D3-9478-53097429F1B2/L0/001 becomes
                // assets-library://asset/asset.JPG?id=AF3C1B68-222B-43D3-9478-53097429F1B2&ext=JPG
                QString theId = QString::fromNSString(asset.localIdentifier);
                QString theUrl = "assets-library://asset/asset.";
                theUrl.append(theSuffix).append("?id=");
                theUrl.append(theId.split('/').first());
                theUrl.append("&ext=").append(theSuffix);
                // qDebug() << "URL: " << theUrl;
    
                assetsMap.insert(modificationDate, theUrl);
            } // assets in collection
    
            // now we can fill our list of assets-URLs (sorted descendend by modificationDate)
            QStringList sortedAssetsList;
            QMapIterator<QDateTime, QString> assetsIterator(assetsMap);
            assetsIterator.toBack();
            while (assetsIterator.hasPrevious()) {
                assetsIterator.previous();
                sortedAssetsList.append(assetsIterator.value());
            }
    
            // insert sorted list of URLLs into albums map
            albumsWithSortedAssetsMap.insert(theAlbum, sortedAssetsList);
    
        } // media collections in smart album
        // now we have all albums sorted by album name together with sorted collections of assets, where the newest comes first
        return albumsWithSortedAssetsMap;
    }
    

    Good to know: if you fetch the assets, then switch to iOS Camera and create new Photos or delete Photos, go back to your App and again call the same method to fetch assets you’ll get the old content. I had to create a new instance of my IosUtil class to be able to get the newest data from Phto Library.


  • Lifetime Qt Champion

    Thank you very much !


  • Qt Champions 2016

    the code above only fetches smart albums. if you also need albums created manually from user, you must fetch them, too:

    PHFetchResult *userCollections = [PHCollectionList fetchTopLevelUserCollectionsWithOptions:nil];
    

    and if you need sync’d albums:

    PHFetchResult *syncedAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumSyncedAlbum options:nil];
    

    user collections tested, sync’d collections not tested yet because I don’t need them



Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.