diff --git a/examples/DemoRunner/Builds/iOS/DemoRunner.xcodeproj/project.pbxproj b/examples/DemoRunner/Builds/iOS/DemoRunner.xcodeproj/project.pbxproj index 3cc02f41dd..beea265ee3 100644 --- a/examples/DemoRunner/Builds/iOS/DemoRunner.xcodeproj/project.pbxproj +++ b/examples/DemoRunner/Builds/iOS/DemoRunner.xcodeproj/project.pbxproj @@ -21,6 +21,7 @@ 2F76CA28C8C0EFC7453D0EB8 /* include_juce_data_structures.mm */ = {isa = PBXBuildFile; fileRef = F5F2EA2238973488632FC322; }; 34A4931AF1DD424D3A400EEF /* CoreGraphics.framework */ = {isa = PBXBuildFile; fileRef = 76A157A111866670A4678F04; }; 36E115D98311F12AA06710E6 /* DemoPIPs2.cpp */ = {isa = PBXBuildFile; fileRef = 061AECBF1CC7056F4155812D; }; + 41AE56F8671DFE80720A6A18 /* UniformTypeIdentifiers.framework */ = {isa = PBXBuildFile; fileRef = AAF88452B7774FB605990B31; settings = { ATTRIBUTES = (Weak, ); }; }; 46071CE2B98B562B7BF27CB1 /* CoreMedia.framework */ = {isa = PBXBuildFile; fileRef = 1CFE3935A3B810D5D68A2504; }; 47ED2C78B05B8A6A00E36C46 /* Assets */ = {isa = PBXBuildFile; fileRef = 685A261BE78585293F3EAD36; }; 48CF0B02E1D06E5DA51E6270 /* Accelerate.framework */ = {isa = PBXBuildFile; fileRef = A04E4408525F24F7DCBA000E; }; @@ -130,6 +131,7 @@ A5256778E2EBD206B337B555 /* juce_video */ /* juce_video */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_video; path = ../../../../modules/juce_video; sourceTree = SOURCE_ROOT; }; A6F555BE0DDF01C285BD8BF5 /* juce_dsp */ /* juce_dsp */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_dsp; path = ../../../../modules/juce_dsp; sourceTree = SOURCE_ROOT; }; A9315F8368A5771EC39631CB /* juce_gui_extra */ /* juce_gui_extra */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_gui_extra; path = ../../../../modules/juce_gui_extra; sourceTree = SOURCE_ROOT; }; + AAF88452B7774FB605990B31 /* UniformTypeIdentifiers.framework */ /* UniformTypeIdentifiers.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UniformTypeIdentifiers.framework; path = System/Library/Frameworks/UniformTypeIdentifiers.framework; sourceTree = SDKROOT; }; B28EFB9D1DF0B6D6499A7DEF /* CoreImage.framework */ /* CoreImage.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreImage.framework; path = System/Library/Frameworks/CoreImage.framework; sourceTree = SDKROOT; }; B2BC383CE102EECCF49C7AF7 /* IntroScreen.h */ /* IntroScreen.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IntroScreen.h; path = ../../Source/Demos/IntroScreen.h; sourceTree = SOURCE_ROOT; }; B4389672DA4CC8E0A531062D /* CoreAudioKit.framework */ /* CoreAudioKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudioKit.framework; path = System/Library/Frameworks/CoreAudioKit.framework; sourceTree = SDKROOT; }; @@ -180,6 +182,7 @@ 89AD16514B1F4133FFEA1DF9, EFD00925ED57B2C5EB5412FC, 10D769051F1431A67AD2CB40, + 41AE56F8671DFE80720A6A18, 9641E7E4F0B5C2A1B3E8709A, ); runOnlyForDeploymentPostprocessing = 0; @@ -210,6 +213,7 @@ 96D99A08027CA35D6A4E5CFD, 3644EF58D9EB1AB436A04E77, 2992DB69DCFB7DADDE907385, + AAF88452B7774FB605990B31, 40D006CCDB1D33FF94B6ECAE, ); name = Frameworks; diff --git a/extras/AudioPerformanceTest/Builds/iOS/AudioPerformanceTest.xcodeproj/project.pbxproj b/extras/AudioPerformanceTest/Builds/iOS/AudioPerformanceTest.xcodeproj/project.pbxproj index ea3e5ab75e..134e4837c0 100644 --- a/extras/AudioPerformanceTest/Builds/iOS/AudioPerformanceTest.xcodeproj/project.pbxproj +++ b/extras/AudioPerformanceTest/Builds/iOS/AudioPerformanceTest.xcodeproj/project.pbxproj @@ -18,6 +18,7 @@ 48ADBEF873A610909D727C97 /* include_juce_audio_formats.mm */ = {isa = PBXBuildFile; fileRef = 9E05B63699A307598B66F829; }; 537E779F6008999191B2920A /* WebKit.framework */ = {isa = PBXBuildFile; fileRef = 3058871156B921B9E5946C4F; }; 5482AA8D0FC9214839FD96A4 /* include_juce_graphics_Sheenbidi.c */ = {isa = PBXBuildFile; fileRef = A6DEFD86172F7F8BA64A77CC; }; + 56BEF006A35699533F758612 /* UniformTypeIdentifiers.framework */ = {isa = PBXBuildFile; fileRef = 7ED3F6975B2EBF16EEF12B3B; settings = { ATTRIBUTES = (Weak, ); }; }; 5923A711C0020F2CDD598714 /* CoreMIDI.framework */ = {isa = PBXBuildFile; fileRef = 12C680C68A15B9A590264B18; }; 5AFD011031C266431687C922 /* CoreAudio.framework */ = {isa = PBXBuildFile; fileRef = 9F28F179EF6B90EB9F4DBEE9; }; 65FC2E13B65977FED63BDDE3 /* include_juce_graphics.mm */ = {isa = PBXBuildFile; fileRef = 7E951216B6138C76653B1460; }; @@ -71,6 +72,7 @@ 732FE1B1B951AB410C8153BD /* Metal.framework */ /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; }; 77AA9722BAADD4108205501A /* juce_data_structures */ /* juce_data_structures */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_data_structures; path = ../../../../modules/juce_data_structures; sourceTree = SOURCE_ROOT; }; 7E951216B6138C76653B1460 /* include_juce_graphics.mm */ /* include_juce_graphics.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = include_juce_graphics.mm; path = ../../JuceLibraryCode/include_juce_graphics.mm; sourceTree = SOURCE_ROOT; }; + 7ED3F6975B2EBF16EEF12B3B /* UniformTypeIdentifiers.framework */ /* UniformTypeIdentifiers.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UniformTypeIdentifiers.framework; path = System/Library/Frameworks/UniformTypeIdentifiers.framework; sourceTree = SDKROOT; }; 81017699F857F5BBFCA6E055 /* juce_events */ /* juce_events */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_events; path = ../../../../modules/juce_events; sourceTree = SOURCE_ROOT; }; 8693552B5FA53C2003A66302 /* Images.xcassets */ /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = AudioPerformanceTest/Images.xcassets; sourceTree = SOURCE_ROOT; }; 89B3243200BAA6BD72905DBB /* include_juce_audio_basics.mm */ /* include_juce_audio_basics.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = include_juce_audio_basics.mm; path = ../../JuceLibraryCode/include_juce_audio_basics.mm; sourceTree = SOURCE_ROOT; }; @@ -121,6 +123,7 @@ 537E779F6008999191B2920A, A545463A201EC7C2F79A330A, 0CB3EC8D832F5781D3BD7827, + 56BEF006A35699533F758612, E4CFFE22717FF2B0A12BAB32, ); runOnlyForDeploymentPostprocessing = 0; @@ -147,6 +150,7 @@ 3058871156B921B9E5946C4F, 732FE1B1B951AB410C8153BD, 19CEFCBBBEBC6F0DAE2376BB, + 7ED3F6975B2EBF16EEF12B3B, F454EA288AEBA354CF288214, ); name = Frameworks; diff --git a/extras/AudioPluginHost/Builds/iOS/AudioPluginHost.xcodeproj/project.pbxproj b/extras/AudioPluginHost/Builds/iOS/AudioPluginHost.xcodeproj/project.pbxproj index 082d45b364..0a7417859d 100644 --- a/extras/AudioPluginHost/Builds/iOS/AudioPluginHost.xcodeproj/project.pbxproj +++ b/extras/AudioPluginHost/Builds/iOS/AudioPluginHost.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 0240E0ECC2771B8B854C49C2 /* UniformTypeIdentifiers.framework */ = {isa = PBXBuildFile; fileRef = 8C6CD9119127C4AEBADABA25; settings = { ATTRIBUTES = (Weak, ); }; }; 025B22813EA4E34CE3630B9A /* IOConfigurationWindow.cpp */ = {isa = PBXBuildFile; fileRef = C37B2E77AAB6C9E13729BF99; }; 075C54DDDBDEA5AAD2F60154 /* include_juce_graphics.mm */ = {isa = PBXBuildFile; fileRef = 82800DBA287EF4BAB13B42FB; }; 08E08AEF1DFE00F06F5ED160 /* include_juce_core_CompilationTime.cpp */ = {isa = PBXBuildFile; fileRef = DB6C39B4C628E31A58A28675; }; @@ -104,6 +105,7 @@ 86CA337014D3F67E906FFD28 /* Accelerate.framework */ /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; }; 87A7AAB053051C49EAF4EE88 /* InternalPlugins.cpp */ /* InternalPlugins.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = InternalPlugins.cpp; path = ../../Source/Plugins/InternalPlugins.cpp; sourceTree = SOURCE_ROOT; }; 89309C0C5F3269BD06BE7F27 /* QuartzCore.framework */ /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; + 8C6CD9119127C4AEBADABA25 /* UniformTypeIdentifiers.framework */ /* UniformTypeIdentifiers.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UniformTypeIdentifiers.framework; path = System/Library/Frameworks/UniformTypeIdentifiers.framework; sourceTree = SDKROOT; }; 8D8BBC353637DA442C5575DA /* App */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Plugin Host.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 8FE7B37CDE0818DB27BDDEBD /* include_juce_gui_basics.mm */ /* include_juce_gui_basics.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = include_juce_gui_basics.mm; path = ../../JuceLibraryCode/include_juce_gui_basics.mm; sourceTree = SOURCE_ROOT; }; 9320A145F2A8ACD687D6608E /* juce_dsp */ /* juce_dsp */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_dsp; path = ../../../../modules/juce_dsp; sourceTree = SOURCE_ROOT; }; @@ -166,6 +168,7 @@ 4DB15177DDC357F4503F88CF, 1AD3A3C7CD2D1F6DC4B65205, 8390CF6AEF2090680E4535F7, + 0240E0ECC2771B8B854C49C2, A6A7B686501E826EB999A03C, ); runOnlyForDeploymentPostprocessing = 0; @@ -316,6 +319,7 @@ B457EE687507BF1DEEA7581F, 3E94492697BD64D0F185D60E, 118ABD8E91DF2E400358D8CD, + 8C6CD9119127C4AEBADABA25, 44D9D7F12D565AC038E17E2F, ); name = Frameworks; diff --git a/extras/NetworkGraphicsDemo/Builds/iOS/NetworkGraphicsDemo.xcodeproj/project.pbxproj b/extras/NetworkGraphicsDemo/Builds/iOS/NetworkGraphicsDemo.xcodeproj/project.pbxproj index 35893c94fa..6ff4b02095 100644 --- a/extras/NetworkGraphicsDemo/Builds/iOS/NetworkGraphicsDemo.xcodeproj/project.pbxproj +++ b/extras/NetworkGraphicsDemo/Builds/iOS/NetworkGraphicsDemo.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* Begin PBXBuildFile section */ 006DF460F8DF66EFFA80D968 /* Icon.icns */ = {isa = PBXBuildFile; fileRef = 70F1CAF3C4C561DD81E6AFC1; }; 0977FEC02DAF29438583198A /* include_juce_core.mm */ = {isa = PBXBuildFile; fileRef = 01E0EEF68A11C1CAF180E173; }; + 0E041BED84BAC24200949A78 /* UniformTypeIdentifiers.framework */ = {isa = PBXBuildFile; fileRef = 961965555B4DAA5BE2361933; settings = { ATTRIBUTES = (Weak, ); }; }; 0E39AB2B15DCE39E1055A646 /* include_juce_audio_processors_lv2_libs.cpp */ = {isa = PBXBuildFile; fileRef = AB2DE62887E2F58D821F3217; }; 0FA2A3321630EBE83E439D99 /* include_juce_cryptography.mm */ = {isa = PBXBuildFile; fileRef = AFF729977947528F3E4AAA96; }; 1282A62308CD1AC3F88A5D03 /* Images.xcassets */ = {isa = PBXBuildFile; fileRef = 5273768FBB55D0DD57A5E70C; }; @@ -85,6 +86,7 @@ 9193D2A3C463BEAA07FD424D /* CoreText.framework */ /* CoreText.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreText.framework; path = System/Library/Frameworks/CoreText.framework; sourceTree = SDKROOT; }; 92800676AF753D1A60108F11 /* BinaryData.h */ /* BinaryData.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = BinaryData.h; path = ../../JuceLibraryCode/BinaryData.h; sourceTree = SOURCE_ROOT; }; 935CA85EF98714D3A17AE737 /* QuartzCore.framework */ /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; + 961965555B4DAA5BE2361933 /* UniformTypeIdentifiers.framework */ /* UniformTypeIdentifiers.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UniformTypeIdentifiers.framework; path = System/Library/Frameworks/UniformTypeIdentifiers.framework; sourceTree = SDKROOT; }; 9982F39121710EFFD5FEEAEF /* MasterComponent.h */ /* MasterComponent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = MasterComponent.h; path = ../../Source/MasterComponent.h; sourceTree = SOURCE_ROOT; }; 9C67BD1915C7FD5747C2BA8F /* juce_audio_formats */ /* juce_audio_formats */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_audio_formats; path = ../../../../modules/juce_audio_formats; sourceTree = SOURCE_ROOT; }; 9C689AFBF364CB167C422D29 /* juce_gui_extra */ /* juce_gui_extra */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_gui_extra; path = ../../../../modules/juce_gui_extra; sourceTree = SOURCE_ROOT; }; @@ -142,6 +144,7 @@ 8ECB0767EE340DD83869E37D, AC37CDB417E2D3FE619E5944, 64DEB67F9523F28D899D1821, + 0E041BED84BAC24200949A78, 78CB229C1BA5093078BC6195, ); runOnlyForDeploymentPostprocessing = 0; @@ -192,6 +195,7 @@ EC794872987FEA2E129C589A, B57F11A8AC0C8D3A8BF3BDCF, C8C4E9A4028028FF1F5B76F2, + 961965555B4DAA5BE2361933, E8976208A3585295BF93D50D, ); name = Frameworks; diff --git a/modules/juce_core/native/juce_ObjCHelpers_mac.h b/modules/juce_core/native/juce_ObjCHelpers_mac.h index 62be95219c..b122c755b8 100644 --- a/modules/juce_core/native/juce_ObjCHelpers_mac.h +++ b/modules/juce_core/native/juce_ObjCHelpers_mac.h @@ -564,4 +564,36 @@ private: Class klass = nullptr; }; +#if JUCE_IOS + +// Defines a function that will check the requested version both at +// build time, and, if necessary, at runtime. +// The function's first template argument is a trait type containing +// two static member functions named newFn and oldFn. +// When the deployment target is at least equal to major.minor, +// newFn will be selected at compile time. +// When the build sdk does not support iOS SDK major.minor, +// oldFn will be selected at compile time. +// Otherwise, the OS version will be checked at runtime and newFn +// will be called if the OS version is at least equal to major.minor, +// otherwise oldFn will be called. +#define JUCE_DEFINE_IOS_VERSION_CHECKER_FOR_VERSION(major, minor) \ + template \ + auto ifelse_ ## major ## _ ## minor (Args&&... args) \ + { \ + constexpr auto fullVersion = major * 10'000 + minor * 100; \ + if constexpr (fullVersion <= __IPHONE_OS_VERSION_MIN_REQUIRED) \ + return Trait::newFn (std::forward (args)...); \ + else if constexpr (__IPHONE_OS_VERSION_MAX_ALLOWED < fullVersion) \ + return Trait::oldFn (std::forward (args)...); \ + else if (@available (ios major ## . ## minor, *)) \ + return Trait::newFn (std::forward (args)...); \ + else \ + return Trait::oldFn (std::forward (args)...); \ + } + +JUCE_DEFINE_IOS_VERSION_CHECKER_FOR_VERSION (14, 0) + +#endif + } // namespace juce diff --git a/modules/juce_gui_basics/juce_gui_basics.cpp b/modules/juce_gui_basics/juce_gui_basics.cpp index fb58ef20bd..834455c16a 100644 --- a/modules/juce_gui_basics/juce_gui_basics.cpp +++ b/modules/juce_gui_basics/juce_gui_basics.cpp @@ -79,6 +79,7 @@ #import #endif + #import #import #import diff --git a/modules/juce_gui_basics/juce_gui_basics.h b/modules/juce_gui_basics/juce_gui_basics.h index bd44e2c934..5f9db06325 100644 --- a/modules/juce_gui_basics/juce_gui_basics.h +++ b/modules/juce_gui_basics/juce_gui_basics.h @@ -55,7 +55,7 @@ OSXFrameworks: Cocoa QuartzCore WeakOSXFrameworks: Metal MetalKit iOSFrameworks: CoreServices UIKit - WeakiOSFrameworks: Metal MetalKit + WeakiOSFrameworks: Metal MetalKit UniformTypeIdentifiers END_JUCE_MODULE_DECLARATION diff --git a/modules/juce_gui_basics/native/juce_FileChooser_ios.mm b/modules/juce_gui_basics/native/juce_FileChooser_ios.mm index 787de522eb..b4d038e551 100644 --- a/modules/juce_gui_basics/native/juce_FileChooser_ios.mm +++ b/modules/juce_gui_basics/native/juce_FileChooser_ios.mm @@ -92,8 +92,7 @@ public: //============================================================================== void didPickDocumentsAtURLs (NSArray* urls) { - const auto isWriting = controller.get().documentPickerMode == UIDocumentPickerModeExportToService - || controller.get().documentPickerMode == UIDocumentPickerModeMoveToService; + const auto isWriting = (savedFlags & FileBrowserComponent::saveMode) != 0; const auto accessOptions = isWriting ? 0 : NSFileCoordinatorReadingWithoutChanges; auto* fileCoordinator = [[[NSFileCoordinator alloc] initWithFilePresenter: nil] autorelease]; @@ -165,24 +164,97 @@ public: private: UIViewController* getViewController() const override { return controller.get(); } + struct CreateSaveControllerTrait + { + API_AVAILABLE (ios (14)) + static FileChooserControllerClass* newFn (NSURL* url, const File& currentFileOrDirectory) + { + return [[FileChooserControllerClass alloc] initForExportingURLs: @[url] asCopy: currentFileOrDirectory.existsAsFile()]; + } + + static FileChooserControllerClass* oldFn (NSURL* url, const File& currentFileOrDirectory) + { + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations") + const auto pickerMode = currentFileOrDirectory.existsAsFile() + ? UIDocumentPickerModeExportToService + : UIDocumentPickerModeMoveToService; + return [[FileChooserControllerClass alloc] initWithURL: url inMode: pickerMode]; + JUCE_END_IGNORE_WARNINGS_GCC_LIKE + } + }; + + struct CreateOpenControllerTrait + { + API_AVAILABLE (ios (14)) + static FileChooserControllerClass* newFn (int flags, const StringArray& validExtensions) + { + NSUniquePtr types ([[NSMutableArray alloc] init]); + + if ((flags & FileBrowserComponent::canSelectDirectories) != 0) + { + if (NSUniquePtr ptr {[UTType typeWithIdentifier: @"public.folder"]}) + [types.get() addObject: ptr.get()]; + } + else + { + if (validExtensions.isEmpty()) + if (NSUniquePtr ptr {[UTType typeWithIdentifier: @"public.data"]}) + [types.get() addObject: ptr.get()]; + + for (const auto& extension : validExtensions) + if (NSUniquePtr ptr {[UTType typeWithFilenameExtension: juceStringToNS (extension)]}) + [types.get() addObject: ptr.get()]; + } + + return [[FileChooserControllerClass alloc] initForOpeningContentTypes: types.get()]; + } + + static FileChooserControllerClass* oldFn (int flags, const StringArray& validExtensions) + { + const NSUniquePtr utTypeArray { std::invoke ([&] + { + if ((flags & FileBrowserComponent::canSelectDirectories) != 0) + return @[@"public.folder"]; + + if (validExtensions.isEmpty()) + return @[@"public.data"]; + + StringArray result; + + for (const auto& extension : validExtensions) + { + if (extension.isEmpty()) + continue; + + CFUniquePtr fileExtensionCF (extension.toCFString()); + + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations") + if (CFUniquePtr tag { UTTypeCreatePreferredIdentifierForTag (kUTTagClassFilenameExtension, fileExtensionCF.get(), nullptr) }) + result.add (String::fromCFString (tag.get())); + JUCE_END_IGNORE_WARNINGS_GCC_LIKE + } + + return createNSArrayFromStringArray (result); + }) }; + + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations") + return [[FileChooserControllerClass alloc] initWithDocumentTypes: utTypeArray.get() inMode: UIDocumentPickerModeOpen]; + JUCE_END_IGNORE_WARNINGS_GCC_LIKE + } + }; + Native (FileChooser& fileChooser, int flags) - : owner (fileChooser) + : owner (fileChooser), + savedFlags (flags) { delegate.reset ([[FileChooserDelegateClass alloc] initWithOwner: this]); const auto validExtensions = getValidExtensionsForWildcards (owner.filters); - const auto utTypeArray = (flags & FileBrowserComponent::canSelectDirectories) != 0 - ? @[@"public.folder"] - : createNSArrayFromStringArray (getUTTypesForExtensions (validExtensions)); if ((flags & FileBrowserComponent::saveMode) != 0) { auto currentFileOrDirectory = owner.startingFile; - UIDocumentPickerMode pickerMode = currentFileOrDirectory.existsAsFile() - ? UIDocumentPickerModeExportToService - : UIDocumentPickerModeMoveToService; - if (! currentFileOrDirectory.existsAsFile()) { const auto extension = validExtensions.isEmpty() ? String() @@ -204,15 +276,12 @@ private: } } - auto url = [[NSURL alloc] initFileURLWithPath: juceStringToNS (currentFileOrDirectory.getFullPathName())]; - - controller.reset ([[FileChooserControllerClass alloc] initWithURL: url inMode: pickerMode]); - [url release]; + const NSUniquePtr url { [[NSURL alloc] initFileURLWithPath: juceStringToNS (currentFileOrDirectory.getFullPathName())] }; + controller.reset (ifelse_14_0 (url.get(), currentFileOrDirectory)); } else { - controller.reset ([[FileChooserControllerClass alloc] initWithDocumentTypes: utTypeArray inMode: UIDocumentPickerModeOpen]); - + controller.reset (ifelse_14_0 (flags, validExtensions)); [controller.get() setAllowsMultipleSelection: (flags & FileBrowserComponent::canSelectMultipleItems) != 0]; } @@ -267,27 +336,6 @@ private: return result; } - static StringArray getUTTypesForExtensions (const StringArray& extensions) - { - if (extensions.isEmpty()) - return { "public.data" }; - - StringArray result; - - for (const auto& extension : extensions) - { - if (extension.isEmpty()) - continue; - - CFUniquePtr fileExtensionCF (extension.toCFString()); - - if (const auto tag = CFUniquePtr (UTTypeCreatePreferredIdentifierForTag (kUTTagClassFilenameExtension, fileExtensionCF.get(), nullptr))) - result.add (String::fromCFString (tag.get())); - } - - return result; - } - static String getFilename (const File& path, const String& fallbackExtension) { auto filename = path.getFileNameWithoutExtension(); @@ -309,6 +357,7 @@ private: FileChooser& owner; NSUniquePtr> delegate; NSUniquePtr controller; + int savedFlags = 0; //============================================================================== JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Native)