1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

FileChooser: Fix deprecation warnings for iOS 14

This commit is contained in:
reuk 2024-10-27 16:50:26 +00:00
parent a901b55b0b
commit a4ba0c1b1c
No known key found for this signature in database
GPG key ID: FCB43929F012EE5C
8 changed files with 136 additions and 38 deletions

View file

@ -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 <typename Trait, typename... Args> \
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> (args)...); \
else if constexpr (__IPHONE_OS_VERSION_MAX_ALLOWED < fullVersion) \
return Trait::oldFn (std::forward<Args> (args)...); \
else if (@available (ios major ## . ## minor, *)) \
return Trait::newFn (std::forward<Args> (args)...); \
else \
return Trait::oldFn (std::forward<Args> (args)...); \
}
JUCE_DEFINE_IOS_VERSION_CHECKER_FOR_VERSION (14, 0)
#endif
} // namespace juce

View file

@ -79,6 +79,7 @@
#import <UserNotifications/UserNotifications.h>
#endif
#import <UniformTypeIdentifiers/UniformTypeIdentifiers.h>
#import <MetalKit/MetalKit.h>
#import <UIKit/UIActivityViewController.h>

View file

@ -55,7 +55,7 @@
OSXFrameworks: Cocoa QuartzCore
WeakOSXFrameworks: Metal MetalKit
iOSFrameworks: CoreServices UIKit
WeakiOSFrameworks: Metal MetalKit
WeakiOSFrameworks: Metal MetalKit UniformTypeIdentifiers
END_JUCE_MODULE_DECLARATION

View file

@ -92,8 +92,7 @@ public:
//==============================================================================
void didPickDocumentsAtURLs (NSArray<NSURL*>* 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<NSMutableArray> types ([[NSMutableArray alloc] init]);
if ((flags & FileBrowserComponent::canSelectDirectories) != 0)
{
if (NSUniquePtr<UTType> ptr {[UTType typeWithIdentifier: @"public.folder"]})
[types.get() addObject: ptr.get()];
}
else
{
if (validExtensions.isEmpty())
if (NSUniquePtr<UTType> ptr {[UTType typeWithIdentifier: @"public.data"]})
[types.get() addObject: ptr.get()];
for (const auto& extension : validExtensions)
if (NSUniquePtr<UTType> 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<NSArray> 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<CFStringRef> fileExtensionCF (extension.toCFString());
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
if (CFUniquePtr<CFStringRef> 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<NSURL> url { [[NSURL alloc] initFileURLWithPath: juceStringToNS (currentFileOrDirectory.getFullPathName())] };
controller.reset (ifelse_14_0<CreateSaveControllerTrait> (url.get(), currentFileOrDirectory));
}
else
{
controller.reset ([[FileChooserControllerClass alloc] initWithDocumentTypes: utTypeArray inMode: UIDocumentPickerModeOpen]);
controller.reset (ifelse_14_0<CreateOpenControllerTrait> (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<CFStringRef> fileExtensionCF (extension.toCFString());
if (const auto tag = CFUniquePtr<CFStringRef> (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<NSObject<UIDocumentPickerDelegate, UIAdaptivePresentationControllerDelegate>> delegate;
NSUniquePtr<FileChooserControllerClass> controller;
int savedFlags = 0;
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Native)