diff --git a/modules/juce_gui_basics/native/juce_ios_FileChooser.mm b/modules/juce_gui_basics/native/juce_ios_FileChooser.mm index 95baab1a45..8345251666 100644 --- a/modules/juce_gui_basics/native/juce_ios_FileChooser.mm +++ b/modules/juce_gui_basics/native/juce_ios_FileChooser.mm @@ -26,19 +26,22 @@ namespace juce { -class FileChooser::Native : private Component, - public FileChooser::Pimpl +class FileChooser::Native : public FileChooser::Pimpl, + public Component, + private AsyncUpdater { public: Native (FileChooser& fileChooser, int flags) : owner (fileChooser) { - String firstFileExtension; - - static FileChooserDelegateClass cls; - delegate.reset ([cls.createInstance() init]); + static FileChooserDelegateClass delegateClass; + delegate.reset ([delegateClass.createInstance() init]); FileChooserDelegateClass::setOwner (delegate.get(), this); + static FileChooserControllerClass controllerClass; + auto* controllerClassInstance = controllerClass.createInstance(); + + String firstFileExtension; auto utTypeArray = createNSArrayFromStringArray (getUTTypesForWildcards (owner.filters, firstFileExtension)); if ((flags & FileBrowserComponent::saveMode) != 0) @@ -69,47 +72,51 @@ public: } auto url = [[NSURL alloc] initFileURLWithPath: juceStringToNS (currentFileOrDirectory.getFullPathName())]; - controller.reset ([[UIDocumentPickerViewController alloc] initWithURL: url - inMode: pickerMode]); + + controller.reset ([controllerClassInstance initWithURL: url + inMode: pickerMode]); + [url release]; } else { - controller.reset ([[UIDocumentPickerViewController alloc] initWithDocumentTypes: utTypeArray - inMode: UIDocumentPickerModeOpen]); + controller.reset ([controllerClassInstance initWithDocumentTypes: utTypeArray + inMode: UIDocumentPickerModeOpen]); } + FileChooserControllerClass::setOwner (controller.get(), this); + [controller.get() setDelegate: delegate.get()]; [controller.get() setModalTransitionStyle: UIModalTransitionStyleCrossDissolve]; setOpaque (false); - if (SystemStats::isRunningInAppExtensionSandbox()) + if (fileChooser.parent != nullptr) { - if (fileChooser.parent != nullptr) - { - [controller.get() setModalPresentationStyle:UIModalPresentationFullScreen]; + [controller.get() setModalPresentationStyle: UIModalPresentationFullScreen]; - auto chooserBounds = fileChooser.parent->getBounds(); - setBounds (chooserBounds); + auto chooserBounds = fileChooser.parent->getBounds(); + setBounds (chooserBounds); - setAlwaysOnTop (true); - fileChooser.parent->addAndMakeVisible (this); - } - else + setAlwaysOnTop (true); + fileChooser.parent->addAndMakeVisible (this); + } + else + { + if (SystemStats::isRunningInAppExtensionSandbox()) { // Opening a native top-level window in an AUv3 is not allowed (sandboxing). You need to specify a // parent component (for example your editor) to parent the native file chooser window. To do this // specify a parent component in the FileChooser's constructor! - jassert (fileChooser.parent != nullptr); + jassertfalse; + return; } - } - else - { + auto chooserBounds = Desktop::getInstance().getDisplays().getMainDisplay().userArea; setBounds (chooserBounds); setAlwaysOnTop (true); + setVisible (true); addToDesktop (0); } } @@ -131,8 +138,6 @@ public: #endif } -private: - //============================================================================== void parentHierarchyChanged() override { auto* newPeer = dynamic_cast (getPeer()); @@ -141,11 +146,23 @@ private: { peer = newPeer; - if (auto* parentController = peer->controller) - [parentController showViewController: controller.get() sender: parentController]; + if (peer != nullptr) + { + if (auto* parentController = peer->controller) + [parentController showViewController: controller.get() sender: parentController]; + + peer->toFront (false); + } } } +private: + //============================================================================== + void handleAsyncUpdate() override + { + pickerWasCancelled(); + } + //============================================================================== static StringArray getUTTypesForWildcards (const String& filterWildcards, String& firstExtension) { @@ -182,7 +199,9 @@ private: } } else + { result.add ("public.data"); + } return result; } @@ -207,6 +226,8 @@ private: //============================================================================== void didPickDocumentAtURL (NSURL* url) { + cancelPendingUpdate(); + bool isWriting = controller.get().documentPickerMode == UIDocumentPickerModeExportToService | controller.get().documentPickerMode == UIDocumentPickerModeMoveToService; @@ -267,9 +288,9 @@ private: void pickerWasCancelled() { - Array chooserResults; + cancelPendingUpdate(); - owner.finished (chooserResults); + owner.finished ({}); exitModalState (0); } @@ -294,21 +315,40 @@ private: //============================================================================== static void didPickDocumentAtURL (id self, SEL, UIDocumentPickerViewController*, NSURL* url) { - auto picker = getOwner (self); - - if (picker != nullptr) + if (auto* picker = getOwner (self)) picker->didPickDocumentAtURL (url); } static void documentPickerWasCancelled (id self, SEL, UIDocumentPickerViewController*) { - auto picker = getOwner (self); - - if (picker != nullptr) + if (auto* picker = getOwner (self)) picker->pickerWasCancelled(); } }; + struct FileChooserControllerClass : public ObjCClass + { + FileChooserControllerClass() : ObjCClass ("FileChooserController_") + { + addIvar ("owner"); + addMethod (@selector (viewDidDisappear:), viewDidDisappear, "v@:@c"); + + registerClass(); + } + + static void setOwner (id self, Native* owner) { object_setInstanceVariable (self, "owner", owner); } + static Native* getOwner (id self) { return getIvar (self, "owner"); } + + //============================================================================== + static void viewDidDisappear (id self, SEL, BOOL animated) + { + sendSuperclassMessage (self, @selector (viewDidDisappear:), animated); + + if (auto* picker = getOwner (self)) + picker->triggerAsyncUpdate(); + } + }; + //============================================================================== FileChooser& owner; std::unique_ptr, NSObjectDeleter> delegate; @@ -316,6 +356,7 @@ private: UIViewComponentPeer* peer = nullptr; static FileChooserDelegateClass fileChooserDelegateClass; + static FileChooserControllerClass fileChooserControllerClass; //============================================================================== JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Native)