Skip to content
Open
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
1 change: 1 addition & 0 deletions app/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,7 @@ endif ()
if (IOS)
target_link_libraries(
MerginMaps PUBLIC AppleFrameworks::CoreLocation AppleFrameworks::CoreHaptics
AppleFrameworks::PhotosUI
)
# TODO is this needed? this change requires cmake 3.28+
# qt_add_ios_ffmpeg_libraries(MerginMaps) # Qt Multimedia
Expand Down
1 change: 0 additions & 1 deletion app/ios/iosimagepicker.mm
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
#include <QCoreApplication>
#include <UIKit/UIKit.h>
#include <QPointer>
#include <QtCore>
#include <QImage>

#include "iosinterface.h"
Expand Down
49 changes: 24 additions & 25 deletions app/ios/iosinterface.mm
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
#import <ImageIO/ImageIO.h>
#import "ios/iosinterface.h"
#include "iosviewdelegate.h"
#include "inpututils.h"
#import <MobileCoreServices/MobileCoreServices.h>
#include "position/positionkit.h"
#include "compass.h"
Expand Down Expand Up @@ -177,7 +176,26 @@ +( void )showImagePicker:( int )sourceType : ( IOSImagePicker * )handler
UIWindow *rootWindow = app.windows[0];
UIViewController *rootViewController = rootWindow.rootViewController;

if ( ![UIImagePickerController isSourceTypeAvailable:( UIImagePickerControllerSourceType ) sourceType] )
bool isCamera = ( UIImagePickerControllerSourceType ) sourceType == UIImagePickerControllerSourceTypeCamera;

if ( !isCamera )
{
// Gallery: use PHPickerViewController
PHPickerConfiguration *config = [[PHPickerConfiguration alloc] init];
config.filter = [PHPickerFilter imagesFilter];
config.selectionLimit = 1;

PHPickerViewController *picker = [[PHPickerViewController alloc] initWithConfiguration:config];
static IOSGalleryPickerDelegate *galleryDelegate = nullptr;
galleryDelegate = [[IOSGalleryPickerDelegate alloc] initWithHandler:handler];
picker.delegate = galleryDelegate;

[rootViewController presentViewController:picker animated:YES completion:nil];
return;
}

// Camera: use UIImagePickerController
if ( ![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera] )
{
NSString *alertTitle = @"Image picker";
NSString *alertMessage = @"The functionality is not available";
Expand All @@ -188,15 +206,15 @@ +( void )showImagePicker:( int )sourceType : ( IOSImagePicker * )handler
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *actionOk = [UIAlertAction actionWithTitle:alertOkButtonText
style:UIAlertActionStyleDefault
handler:nil]; //You can use a block here to handle a press on this button
handler:nil];
[alertController addAction:actionOk];
[rootViewController presentViewController:alertController animated:YES completion:nil];
}
else
{
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
imagePickerController = picker;
picker.sourceType = ( UIImagePickerControllerSourceType ) sourceType;
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
static IOSViewDelegate *delegate = nullptr;
delegate = [[IOSViewDelegate alloc] initWithHandler:handler];

Expand All @@ -218,32 +236,13 @@ +( void )showImagePicker:( int )sourceType : ( IOSImagePicker * )handler
delegate->processingPicture = YES;

NSString *imagePath = generateImagePath( delegate->handler->targetDir().toNSString() );
QString err;

bool isCameraPhoto = picker.sourceType == UIImagePickerControllerSourceType::UIImagePickerControllerSourceTypeCamera;
if ( isCameraPhoto )
{
// Camera handling
err = [IOSInterface handleCameraPhoto:info:imagePath];
}
else
{
// Gallery handling
// Copy an image with metadata from imageURL to targetPath
NSURL *infoImageUrl = info[UIImagePickerControllerImageURL];
if ( !InputUtils::copyFile( QString::fromNSString( infoImageUrl.absoluteString ), QString::fromNSString( imagePath ) ) )
{
err = QStringLiteral( "Copying image from a gallery failed." );
}
infoImageUrl = nil;
}
QString err = [IOSInterface handleCameraPhoto:info:imagePath];

[picker dismissViewControllerAnimated:YES completion:nil];
if ( delegate->handler )
{
QVariantMap data;
QString imagePathData( [imagePath UTF8String] );
data["imagePath"] = imagePathData;
data["imagePath"] = QString( [imagePath UTF8String] );
data["error"] = err;
QMetaObject::invokeMethod( delegate->handler, "onImagePickerFinished", Qt::DirectConnection,
Q_ARG( bool, err.isEmpty() ),
Expand Down
8 changes: 8 additions & 0 deletions app/ios/iosviewdelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#define IOSVIEWDELEGATE_H

#include <UIKit/UIKit.h>
#import <PhotosUI/PhotosUI.h>

#include "iosimagepicker.h"
/**
Expand All @@ -36,4 +37,11 @@ UINavigationControllerDelegate>
- ( id ) initWithHandler:( IOSImagePicker * )handler;
@end

/**
* we use PHPickerViewController delegate for gallery image selection, which keeps GPS metadata
*/
@interface IOSGalleryPickerDelegate : NSObject <PHPickerViewControllerDelegate>
- ( instancetype ) initWithHandler:( IOSImagePicker * )handler;
@end

#endif // IOSVIEWDELEGATE_H
70 changes: 66 additions & 4 deletions app/ios/iosviewdelegate.mm
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,9 @@
***************************************************************************/

#include <QtCore>
#include <QPointer>
#import "iosviewdelegate.h"

@interface IOSViewDelegate()

@end

@implementation IOSViewDelegate

-( id ) initWithHandler:( IOSImagePicker * )handler
Expand Down Expand Up @@ -50,3 +47,68 @@ - ( void )imagePickerControllerDidCancel:( UIImagePickerController * )picker
}

@end

@implementation IOSGalleryPickerDelegate
{
QPointer<IOSImagePicker> _handler;
}

- ( instancetype ) initWithHandler:( IOSImagePicker * )handler
{
self = [super init];
if ( self )
{
_handler = handler;
}
return self;
}

- ( void )picker:( PHPickerViewController * )picker didFinishPicking:( NSArray<PHPickerResult *> * )results
{
[picker dismissViewControllerAnimated:YES completion:nil];

if ( results.count == 0 )
{
return; // user cancelled
}

if ( !_handler )
{
return;
}

PHPickerResult *result = results.firstObject;

NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setDateFormat:@"yyyyMMdd_HHmmss"];
NSString *fileName = [[df stringFromDate:[NSDate date]] stringByAppendingString:@".jpg"];
NSString *imagePath = [_handler->targetDir().toNSString() stringByAppendingPathComponent:fileName];

[result.itemProvider loadDataRepresentationForTypeIdentifier:@"public.jpeg"
completionHandler: ^ ( NSData * data, NSError * error )
{
BOOL writeSuccess = data && !error && [data writeToFile:imagePath atomically:YES];
if ( !writeSuccess )
{
qWarning() << "Gallery Picker: failed to write image data to" << QString::fromNSString( imagePath );
}

dispatch_async( dispatch_get_main_queue(), ^
{
if ( _handler )
{
QVariantMap resultData;
resultData["imagePath"] = QString::fromNSString( imagePath );
if ( !writeSuccess )
{
resultData["error"] = QStringLiteral( "Copying image from gallery failed." );
}
QMetaObject::invokeMethod( _handler, "onImagePickerFinished", Qt::DirectConnection,
Q_ARG( bool, writeSuccess ),
Q_ARG( const QVariantMap, resultData ) );
}
} );
}];
}

@end
1 change: 1 addition & 0 deletions cmake/FindAppleFrameworks.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ set(APPLE_FRAMEWORKS
SystemConfiguration
CoreLocation
CoreHaptics
PhotosUI
)

foreach (framework ${APPLE_FRAMEWORKS})
Expand Down
Loading