Implement the "download as" functionality properly in the iOS app
We need to catch the downloadas message already in -[DocumentViewController userContentController:didReceiveScriptMessage:] and use an UIDocumentPickerViewController to let the user choose where to download (or export) the document. The iOS-specific code in ChildSession::downloadAs() can go away. Change-Id: I626b9986ec6156f7e83bda02b04e65f7819f8017 Reviewed-on: https://gerrit.libreoffice.org/c/online/+/92112 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com> Reviewed-by: Tor Lillqvist <tml@collabora.com>
This commit is contained in:
parent
34c27a6b9b
commit
909734e261
2 changed files with 52 additions and 51 deletions
|
@ -28,8 +28,9 @@
|
|||
|
||||
static DocumentViewController* theSingleton = nil;
|
||||
|
||||
@interface DocumentViewController() <WKNavigationDelegate, WKUIDelegate, WKScriptMessageHandler, UIScrollViewDelegate> {
|
||||
@interface DocumentViewController() <WKNavigationDelegate, WKUIDelegate, WKScriptMessageHandler, UIScrollViewDelegate, UIDocumentPickerDelegate> {
|
||||
int closeNotificationPipeForForwardingThread[2];
|
||||
NSURL *downloadAsTmpURL;
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -449,6 +450,46 @@ static IMP standardImpOfInputAccessoryView = nil;
|
|||
[application openURL:url options:@{} completionHandler:nil];
|
||||
return;
|
||||
}
|
||||
} else if ([message.body hasPrefix:@"downloadas "]) {
|
||||
NSArray<NSString*> *messageBodyItems = [message.body componentsSeparatedByString:@" "];
|
||||
NSString *format = nil;
|
||||
if ([messageBodyItems count] >= 2) {
|
||||
for (int i = 1; i < [messageBodyItems count]; i++) {
|
||||
if ([messageBodyItems[i] hasPrefix:@"format="])
|
||||
format = [messageBodyItems[i] substringFromIndex:[@"format=" length]];
|
||||
}
|
||||
|
||||
if (format == nil)
|
||||
return; // Warn?
|
||||
|
||||
// First save it in the requested format to a temporary location. First remove any
|
||||
// leftover identically named temporary file.
|
||||
|
||||
NSString *tmpFileName = [[[self.document->copyFileURL lastPathComponent] stringByDeletingPathExtension] stringByAppendingString:[@"." stringByAppendingString:format]];
|
||||
downloadAsTmpURL = [[NSFileManager.defaultManager temporaryDirectory] URLByAppendingPathComponent:tmpFileName];
|
||||
|
||||
std::remove([[downloadAsTmpURL path] UTF8String]);
|
||||
|
||||
lok_document->saveAs([[downloadAsTmpURL absoluteString] UTF8String], [format UTF8String], nullptr);
|
||||
|
||||
// Then verify that it indeed was saved, and then use an
|
||||
// UIDocumentPickerViewController to ask the user where to store the exported
|
||||
// document.
|
||||
|
||||
struct stat statBuf;
|
||||
if (stat([[downloadAsTmpURL path] UTF8String], &statBuf) == -1) {
|
||||
LOG_ERR("Could apparently not save to '" << [[downloadAsTmpURL path] UTF8String] << "'");
|
||||
} else {
|
||||
UIDocumentPickerViewController *picker =
|
||||
[[UIDocumentPickerViewController alloc] initWithURL:downloadAsTmpURL
|
||||
inMode:UIDocumentPickerModeExportToService];
|
||||
picker.delegate = self;
|
||||
[self presentViewController:picker
|
||||
animated:YES
|
||||
completion:nil];
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const char *buf = [message.body UTF8String];
|
||||
|
@ -461,6 +502,14 @@ static IMP standardImpOfInputAccessoryView = nil;
|
|||
}
|
||||
}
|
||||
|
||||
- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentsAtURLs:(NSArray<NSURL *> *)urls {
|
||||
std::remove([[downloadAsTmpURL path] UTF8String]);
|
||||
}
|
||||
|
||||
- (void)documentPickerWasCancelled:(UIDocumentPickerViewController *)controller {
|
||||
std::remove([[downloadAsTmpURL path] UTF8String]);
|
||||
}
|
||||
|
||||
- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view {
|
||||
scrollView.pinchGestureRecognizer.enabled = NO;
|
||||
}
|
||||
|
|
|
@ -921,56 +921,8 @@ bool ChildSession::downloadAs(const char* /*buffer*/, int /*length*/, const Stri
|
|||
}
|
||||
|
||||
#ifdef IOS
|
||||
NSURL *docURL = [NSURL URLWithString:[NSString stringWithUTF8String:getDocURL().c_str()]];
|
||||
|
||||
#if 0
|
||||
// Experimentation
|
||||
|
||||
// Check if we can figure out the name of the file provider service the document is on. (No, the
|
||||
// services dictionary passed to the completion handler is always empty, except for On My iPad
|
||||
// and iCloud Drive.)
|
||||
[NSFileManager.defaultManager
|
||||
getFileProviderServicesForItemAtURL:docURL
|
||||
completionHandler:^(NSDictionary<NSFileProviderServiceName,NSFileProviderService *> *services,
|
||||
NSError *error) {
|
||||
if (services == nil) {
|
||||
std::cerr << "Could not get file provider services for " << [[docURL absoluteString] UTF8String] << "\n";
|
||||
} else if ([services count] == 0) {
|
||||
std::cerr << "No file provider services returned for " << [[docURL absoluteString] UTF8String] << "\n";
|
||||
} else {
|
||||
std::cerr << "File provider services for " << [[docURL absoluteString] UTF8String] << ":\n";
|
||||
for (auto key in [services allKeys]) {
|
||||
std::cerr << " " << [(NSString*)key UTF8String] << "\n";
|
||||
}
|
||||
}
|
||||
}];
|
||||
|
||||
// Check if we can figure out the "ubiquitous item container" name, which apparently means the file provider extension name.
|
||||
// Alas, this seems to work only for documents on iCloud Drive.
|
||||
NSError *error;
|
||||
auto resources = [docURL promisedItemResourceValuesForKeys:@[NSURLUbiquitousItemContainerDisplayNameKey] error:&error];
|
||||
if (resources == nil) {
|
||||
std::cerr << "Could not get ubiquitous container names for " << [[docURL absoluteString] UTF8String] << "\n";
|
||||
} else if ([resources count] == 0) {
|
||||
std::cerr << "No ubiquitous container names for " << [[docURL absoluteString] UTF8String] << "\n";
|
||||
} else {
|
||||
std::cerr << "Ubiquitous container names for " << [[docURL absoluteString] UTF8String] << ":\n";
|
||||
for (auto name in [resources allValues]) {
|
||||
std::cerr << " " << [(NSString*)name UTF8String] << "\n";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
NSArray<NSString *> *pathComponents = [docURL pathComponents];
|
||||
NSString *baseName = [[pathComponents lastObject] stringByDeletingPathExtension];
|
||||
NSURL *documentDirectory = [NSFileManager.defaultManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask][0];
|
||||
NSString *dotFormat = [@"." stringByAppendingString:[NSString stringWithUTF8String:format.c_str()]];
|
||||
NSURL *exportedURL = [documentDirectory URLByAppendingPathComponent:[baseName stringByAppendingString:dotFormat]];
|
||||
LOG_TRC("Exporting as " << [[exportedURL absoluteString] UTF8String]);
|
||||
|
||||
getLOKitDocument()->saveAs([[exportedURL absoluteString] UTF8String],
|
||||
format.empty() ? nullptr : format.c_str(),
|
||||
filterOptions.empty() ? nullptr : filterOptions.c_str());
|
||||
NSLog(@"We should never come here, aborting");
|
||||
std::abort();
|
||||
#else
|
||||
// Prevent user inputting anything funny here.
|
||||
// A "name" should always be a name, not a path
|
||||
|
|
Loading…
Reference in a new issue