diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index c7a878d98..393c209cf 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -26,6 +26,8 @@ set(launcher_SRCS if(APPLE_IOS) list(APPEND launcher_SRCS ios/launchGame.m + ios/selectdirectory.h + ios/selectdirectory.mm ) endif() @@ -212,6 +214,10 @@ if(ENABLE_INNOEXTRACT) endif() if(APPLE_IOS) + target_link_libraries(vcmilauncher + "-framework UniformTypeIdentifiers" + ) + # TODO: remove after switching prebuilt deps to a newer Conan's Qt recipe if(XCODE_VERSION VERSION_GREATER_EQUAL 14.0) target_link_libraries(vcmilauncher "-framework IOKit") diff --git a/launcher/firstLaunch/firstlaunch_moc.cpp b/launcher/firstLaunch/firstlaunch_moc.cpp index 0efd65760..0e2a84027 100644 --- a/launcher/firstLaunch/firstlaunch_moc.cpp +++ b/launcher/firstLaunch/firstlaunch_moc.cpp @@ -26,7 +26,9 @@ #include "cli/extract.hpp" #endif -#ifdef VCMI_ANDROID +#ifdef VCMI_IOS +#include "ios/selectdirectory.h" +#elif defined(VCMI_ANDROID) #include #include @@ -384,9 +386,16 @@ void FirstLaunchView::extractGogData() void FirstLaunchView::copyHeroesData(const QString & path, bool move) { QDir sourceRoot{path}; - + +#ifdef VCMI_IOS + // TODO: Qt 6.5 can select directories https://codereview.qt-project.org/c/qt/qtbase/+/446449 + SelectDirectory iosDirectorySelector; + if(path.isEmpty()) + sourceRoot.setPath(iosDirectorySelector.getExistingDirectory()); +#else if(path.isEmpty()) sourceRoot.setPath(QFileDialog::getExistingDirectory(this, {}, {}, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks)); +#endif if(!sourceRoot.exists()) return; diff --git a/launcher/ios/selectdirectory.h b/launcher/ios/selectdirectory.h new file mode 100644 index 000000000..2d00a1e4e --- /dev/null +++ b/launcher/ios/selectdirectory.h @@ -0,0 +1,20 @@ +/* + * selectdirectory.h, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ +#pragma once + +#include + +class SelectDirectory final +{ +public: + ~SelectDirectory(); + + QString getExistingDirectory(); +}; diff --git a/launcher/ios/selectdirectory.mm b/launcher/ios/selectdirectory.mm new file mode 100644 index 000000000..6ba064e42 --- /dev/null +++ b/launcher/ios/selectdirectory.mm @@ -0,0 +1,72 @@ +/* + * selectdirectory.mm, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ +#include "selectdirectory.h" + +#include + +#import +#import +#import + + +@interface ObjcDocumentPickerDelegate : NSObject +@property (nonatomic, assign, readonly) QEventLoop & eventLoop; +@property (nonatomic, copy, nullable) NSURL * selectedDirectoryURL; +@end + +@implementation ObjcDocumentPickerDelegate +{ + QEventLoop _eventLoop; +} + +- (QEventLoop &)eventLoop { return _eventLoop; } + +- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentsAtURLs:(NSArray *)urls +{ + self.selectedDirectoryURL = urls.firstObject; + _eventLoop.exit(); +} + +- (void)documentPickerWasCancelled:(UIDocumentPickerViewController *)controller +{ + _eventLoop.exit(); +} + +@end + +static ObjcDocumentPickerDelegate * documentPickerDelegate; + + +SelectDirectory::~SelectDirectory() +{ + [documentPickerDelegate.selectedDirectoryURL stopAccessingSecurityScopedResource]; + documentPickerDelegate = nil; +} + +QString SelectDirectory::getExistingDirectory() +{ + documentPickerDelegate = [ObjcDocumentPickerDelegate new]; + + UIDocumentPickerViewController * documentPickerVc; + if(@available(iOS 14.0, *)) + documentPickerVc = [[UIDocumentPickerViewController alloc] initForOpeningContentTypes:@[UTTypeFolder]]; + else + documentPickerVc = [[UIDocumentPickerViewController alloc] initWithDocumentTypes:@[(__bridge NSString *)kUTTypeFolder] inMode:UIDocumentPickerModeOpen]; + documentPickerVc.allowsMultipleSelection = NO; + documentPickerVc.delegate = documentPickerDelegate; + [UIApplication.sharedApplication.keyWindow.rootViewController presentViewController:documentPickerVc animated:YES completion:nil]; + + documentPickerDelegate.eventLoop.exec(QEventLoop::DialogExec); + if(!documentPickerDelegate.selectedDirectoryURL) + return {}; + + [documentPickerDelegate.selectedDirectoryURL startAccessingSecurityScopedResource]; + return QString::fromNSString(documentPickerDelegate.selectedDirectoryURL.path); +}