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;
|
static DocumentViewController* theSingleton = nil;
|
||||||
|
|
||||||
@interface DocumentViewController() <WKNavigationDelegate, WKUIDelegate, WKScriptMessageHandler, UIScrollViewDelegate> {
|
@interface DocumentViewController() <WKNavigationDelegate, WKUIDelegate, WKScriptMessageHandler, UIScrollViewDelegate, UIDocumentPickerDelegate> {
|
||||||
int closeNotificationPipeForForwardingThread[2];
|
int closeNotificationPipeForForwardingThread[2];
|
||||||
|
NSURL *downloadAsTmpURL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -449,6 +450,46 @@ static IMP standardImpOfInputAccessoryView = nil;
|
||||||
[application openURL:url options:@{} completionHandler:nil];
|
[application openURL:url options:@{} completionHandler:nil];
|
||||||
return;
|
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];
|
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 {
|
- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view {
|
||||||
scrollView.pinchGestureRecognizer.enabled = NO;
|
scrollView.pinchGestureRecognizer.enabled = NO;
|
||||||
}
|
}
|
||||||
|
|
|
@ -921,56 +921,8 @@ bool ChildSession::downloadAs(const char* /*buffer*/, int /*length*/, const Stri
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef IOS
|
#ifdef IOS
|
||||||
NSURL *docURL = [NSURL URLWithString:[NSString stringWithUTF8String:getDocURL().c_str()]];
|
NSLog(@"We should never come here, aborting");
|
||||||
|
std::abort();
|
||||||
#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());
|
|
||||||
#else
|
#else
|
||||||
// Prevent user inputting anything funny here.
|
// Prevent user inputting anything funny here.
|
||||||
// A "name" should always be a name, not a path
|
// A "name" should always be a name, not a path
|
||||||
|
|
Loading…
Reference in a new issue