summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2021-12-28 07:52:25 +0200
committerJaakko Keränen <jaakko.keranen@iki.fi>2021-12-28 07:52:30 +0200
commit336b9d7272ed8b1a9dccee27dec20e3377ee0c74 (patch)
treee789b1406574de3e72b15a4d060890548096f4fa
parenta0111b0560c96fcc25758d2384f6ee53171ccd69 (diff)
Viewing unsupported files in another app
After receiving content of unsupported type, show a footer action button to open it in another app. IssueID #135
-rw-r--r--CMakeLists.txt1
-rw-r--r--po/en.po3
-rw-r--r--res/lang/cs.binbin31510 -> 31549 bytes
-rw-r--r--res/lang/de.binbin30517 -> 30556 bytes
-rw-r--r--res/lang/en.binbin26603 -> 26642 bytes
-rw-r--r--res/lang/eo.binbin25567 -> 25606 bytes
-rw-r--r--res/lang/es.binbin30341 -> 30380 bytes
-rw-r--r--res/lang/es_MX.binbin27673 -> 27712 bytes
-rw-r--r--res/lang/fi.binbin30174 -> 30213 bytes
-rw-r--r--res/lang/fr.binbin31321 -> 31360 bytes
-rw-r--r--res/lang/gl.binbin29526 -> 29565 bytes
-rw-r--r--res/lang/hu.binbin31346 -> 31385 bytes
-rw-r--r--res/lang/ia.binbin28673 -> 28712 bytes
-rw-r--r--res/lang/ie.binbin29261 -> 29300 bytes
-rw-r--r--res/lang/isv.binbin25324 -> 25363 bytes
-rw-r--r--res/lang/pl.binbin29949 -> 29988 bytes
-rw-r--r--res/lang/ru.binbin44709 -> 44748 bytes
-rw-r--r--res/lang/sk.binbin25660 -> 25699 bytes
-rw-r--r--res/lang/sr.binbin44135 -> 44174 bytes
-rw-r--r--res/lang/tok.binbin27383 -> 27422 bytes
-rw-r--r--res/lang/tr.binbin29567 -> 29606 bytes
-rw-r--r--res/lang/uk.binbin44054 -> 44093 bytes
-rw-r--r--res/lang/zh_Hans.binbin25568 -> 25607 bytes
-rw-r--r--res/lang/zh_Hant.binbin25766 -> 25805 bytes
-rw-r--r--src/app.c19
-rw-r--r--src/app.h1
-rw-r--r--src/ui/documentwidget.c74
27 files changed, 68 insertions, 30 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 94b70ea0..37afe9d2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -330,6 +330,7 @@ target_include_directories (app PUBLIC
330target_compile_options (app PUBLIC 330target_compile_options (app PUBLIC
331 -Werror=implicit-function-declaration 331 -Werror=implicit-function-declaration
332 -Werror=incompatible-pointer-types 332 -Werror=incompatible-pointer-types
333 -Wno-deprecated-declarations
333 ${SDL2_CFLAGS} 334 ${SDL2_CFLAGS}
334 -DSTB_VORBIS_NO_STDIO=1 335 -DSTB_VORBIS_NO_STDIO=1
335 -DSTB_VORBIS_NO_INTEGER_CONVERSION=1 336 -DSTB_VORBIS_NO_INTEGER_CONVERSION=1
diff --git a/po/en.po b/po/en.po
index 04b6ac19..61d7d3f7 100644
--- a/po/en.po
+++ b/po/en.po
@@ -196,6 +196,9 @@ msgstr "Find on Page"
196msgid "macos.menu.find" 196msgid "macos.menu.find"
197msgstr "Find" 197msgstr "Find"
198 198
199msgid "menu.open.external"
200msgstr "Open in Another App"
201
199# Used on iOS. "Files" refers to Apple's iOS app where you can pick an iCloud folder. 202# Used on iOS. "Files" refers to Apple's iOS app where you can pick an iCloud folder.
200msgid "menu.save.files" 203msgid "menu.save.files"
201msgstr "Save to Files" 204msgstr "Save to Files"
diff --git a/res/lang/cs.bin b/res/lang/cs.bin
index 97197051..ec75dc3a 100644
--- a/res/lang/cs.bin
+++ b/res/lang/cs.bin
Binary files differ
diff --git a/res/lang/de.bin b/res/lang/de.bin
index d2dceda6..96fd003f 100644
--- a/res/lang/de.bin
+++ b/res/lang/de.bin
Binary files differ
diff --git a/res/lang/en.bin b/res/lang/en.bin
index 942dfdc2..26e3c36a 100644
--- a/res/lang/en.bin
+++ b/res/lang/en.bin
Binary files differ
diff --git a/res/lang/eo.bin b/res/lang/eo.bin
index 513c3a0b..2df0e6b8 100644
--- a/res/lang/eo.bin
+++ b/res/lang/eo.bin
Binary files differ
diff --git a/res/lang/es.bin b/res/lang/es.bin
index 92037aea..be919a78 100644
--- a/res/lang/es.bin
+++ b/res/lang/es.bin
Binary files differ
diff --git a/res/lang/es_MX.bin b/res/lang/es_MX.bin
index 7b7e1219..d88b3386 100644
--- a/res/lang/es_MX.bin
+++ b/res/lang/es_MX.bin
Binary files differ
diff --git a/res/lang/fi.bin b/res/lang/fi.bin
index 243e9740..5dba618c 100644
--- a/res/lang/fi.bin
+++ b/res/lang/fi.bin
Binary files differ
diff --git a/res/lang/fr.bin b/res/lang/fr.bin
index 507cbb4c..830bbc72 100644
--- a/res/lang/fr.bin
+++ b/res/lang/fr.bin
Binary files differ
diff --git a/res/lang/gl.bin b/res/lang/gl.bin
index 447ed72d..4df0c57c 100644
--- a/res/lang/gl.bin
+++ b/res/lang/gl.bin
Binary files differ
diff --git a/res/lang/hu.bin b/res/lang/hu.bin
index c2a085ec..f4c826c8 100644
--- a/res/lang/hu.bin
+++ b/res/lang/hu.bin
Binary files differ
diff --git a/res/lang/ia.bin b/res/lang/ia.bin
index 5305304c..6a18bd7d 100644
--- a/res/lang/ia.bin
+++ b/res/lang/ia.bin
Binary files differ
diff --git a/res/lang/ie.bin b/res/lang/ie.bin
index 69ac42d4..84cc2cd7 100644
--- a/res/lang/ie.bin
+++ b/res/lang/ie.bin
Binary files differ
diff --git a/res/lang/isv.bin b/res/lang/isv.bin
index 26c23dc5..1a31a1f7 100644
--- a/res/lang/isv.bin
+++ b/res/lang/isv.bin
Binary files differ
diff --git a/res/lang/pl.bin b/res/lang/pl.bin
index 1ad99e5d..a003ce03 100644
--- a/res/lang/pl.bin
+++ b/res/lang/pl.bin
Binary files differ
diff --git a/res/lang/ru.bin b/res/lang/ru.bin
index 03092acf..807e032d 100644
--- a/res/lang/ru.bin
+++ b/res/lang/ru.bin
Binary files differ
diff --git a/res/lang/sk.bin b/res/lang/sk.bin
index 4d91e8a6..33c83c09 100644
--- a/res/lang/sk.bin
+++ b/res/lang/sk.bin
Binary files differ
diff --git a/res/lang/sr.bin b/res/lang/sr.bin
index 823818e2..7c4c8de1 100644
--- a/res/lang/sr.bin
+++ b/res/lang/sr.bin
Binary files differ
diff --git a/res/lang/tok.bin b/res/lang/tok.bin
index 50743783..601b07f3 100644
--- a/res/lang/tok.bin
+++ b/res/lang/tok.bin
Binary files differ
diff --git a/res/lang/tr.bin b/res/lang/tr.bin
index 543739cd..8cbaa556 100644
--- a/res/lang/tr.bin
+++ b/res/lang/tr.bin
Binary files differ
diff --git a/res/lang/uk.bin b/res/lang/uk.bin
index f866f86f..48adc59b 100644
--- a/res/lang/uk.bin
+++ b/res/lang/uk.bin
Binary files differ
diff --git a/res/lang/zh_Hans.bin b/res/lang/zh_Hans.bin
index 179d87db..759e618a 100644
--- a/res/lang/zh_Hans.bin
+++ b/res/lang/zh_Hans.bin
Binary files differ
diff --git a/res/lang/zh_Hant.bin b/res/lang/zh_Hant.bin
index aad28410..2bfc817b 100644
--- a/res/lang/zh_Hant.bin
+++ b/res/lang/zh_Hant.bin
Binary files differ
diff --git a/src/app.c b/src/app.c
index b04b6388..b0b36783 100644
--- a/src/app.c
+++ b/src/app.c
@@ -1021,7 +1021,7 @@ const iString *downloadDir_App(void) {
1021 return collect_String(cleaned_Path(&app_.prefs.strings[downloadDir_PrefsString])); 1021 return collect_String(cleaned_Path(&app_.prefs.strings[downloadDir_PrefsString]));
1022} 1022}
1023 1023
1024const iString *downloadPathForUrl_App(const iString *url, const iString *mime) { 1024const iString *fileNameForUrl_App(const iString *url, const iString *mime) {
1025 /* Figure out a file name from the URL. */ 1025 /* Figure out a file name from the URL. */
1026 iUrl parts; 1026 iUrl parts;
1027 init_Url(&parts, url); 1027 init_Url(&parts, url);
@@ -1047,22 +1047,27 @@ const iString *downloadPathForUrl_App(const iString *url, const iString *mime) {
1047 } 1047 }
1048 } 1048 }
1049 if (startsWith_String(name, "~")) { 1049 if (startsWith_String(name, "~")) {
1050 /* This would be interpreted as a reference to a home directory. */ 1050 /* This might be interpreted as a reference to a home directory. */
1051 remove_Block(&name->chars, 0, 1); 1051 remove_Block(&name->chars, 0, 1);
1052 } 1052 }
1053 iString *savePath = concat_Path(downloadDir_App(), name); 1053 if (lastIndexOfCStr_String(name, ".") == iInvalidPos) {
1054 if (lastIndexOfCStr_String(savePath, ".") == iInvalidPos) { 1054 /* TODO: Needs the inverse of `mediaTypeFromFileExtension_String()`. */
1055 /* No extension specified in URL. */ 1055 /* No extension specified in URL. */
1056 if (startsWith_String(mime, "text/gemini")) { 1056 if (startsWith_String(mime, "text/gemini")) {
1057 appendCStr_String(savePath, ".gmi"); 1057 appendCStr_String(name, ".gmi");
1058 } 1058 }
1059 else if (startsWith_String(mime, "text/")) { 1059 else if (startsWith_String(mime, "text/")) {
1060 appendCStr_String(savePath, ".txt"); 1060 appendCStr_String(name, ".txt");
1061 } 1061 }
1062 else if (startsWith_String(mime, "image/")) { 1062 else if (startsWith_String(mime, "image/")) {
1063 appendCStr_String(savePath, cstr_String(mime) + 6); 1063 appendCStr_String(name, cstr_String(mime) + 6);
1064 } 1064 }
1065 } 1065 }
1066 return name;
1067}
1068
1069const iString *downloadPathForUrl_App(const iString *url, const iString *mime) {
1070 iString *savePath = concat_Path(downloadDir_App(), fileNameForUrl_App(url, mime));
1066 if (fileExists_FileInfo(savePath)) { 1071 if (fileExists_FileInfo(savePath)) {
1067 /* Make it unique. */ 1072 /* Make it unique. */
1068 iDate now; 1073 iDate now;
diff --git a/src/app.h b/src/app.h
index 50d3ac6b..0c336e65 100644
--- a/src/app.h
+++ b/src/app.h
@@ -110,6 +110,7 @@ enum iColorTheme colorTheme_App (void);
110const iString * schemeProxy_App (iRangecc scheme); 110const iString * schemeProxy_App (iRangecc scheme);
111iBool willUseProxy_App (const iRangecc scheme); 111iBool willUseProxy_App (const iRangecc scheme);
112const iString * searchQueryUrl_App (const iString *queryStringUnescaped); 112const iString * searchQueryUrl_App (const iString *queryStringUnescaped);
113const iString * fileNameForUrl_App (const iString *url, const iString *mime);
113const iString * downloadPathForUrl_App(const iString *url, const iString *mime); 114const iString * downloadPathForUrl_App(const iString *url, const iString *mime);
114 115
115typedef void (*iTickerFunc)(iAny *); 116typedef void (*iTickerFunc)(iAny *);
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index 04257a1c..3771dd6c 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -2260,6 +2260,11 @@ static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode
2260 0, 2260 0,
2261 format_CStr("document.setmediatype mime:%s", mtype) }); 2261 format_CStr("document.setmediatype mime:%s", mtype) });
2262 } 2262 }
2263 pushBack_Array(&items,
2264 &(iMenuItem){ export_Icon " ${menu.open.external}",
2265 SDLK_RETURN,
2266 KMOD_PRIMARY,
2267 "document.save extview:1" });
2263 pushBack_Array( 2268 pushBack_Array(
2264 &items, 2269 &items,
2265 &(iMenuItem){ translateCStr_Lang(download_Icon " " saveToDownloads_Label), 2270 &(iMenuItem){ translateCStr_Lang(download_Icon " " saveToDownloads_Label),
@@ -3337,9 +3342,8 @@ static iBool fetchNextUnfetchedImage_DocumentWidget_(iDocumentWidget *d) {
3337 return iFalse; 3342 return iFalse;
3338} 3343}
3339 3344
3340static const iString *saveToDownloads_(const iString *url, const iString *mime, const iBlock *content, 3345static iBool saveToFile_(const iString *savePath, const iBlock *content, iBool showDialog) {
3341 iBool showDialog) { 3346 iBool ok = iFalse;
3342 const iString *savePath = downloadPathForUrl_App(url, mime);
3343 /* Write the file. */ { 3347 /* Write the file. */ {
3344 iFile *f = new_File(savePath); 3348 iFile *f = new_File(savePath);
3345 if (open_File(f, writeOnly_FileMode)) { 3349 if (open_File(f, writeOnly_FileMode)) {
@@ -3351,21 +3355,21 @@ static const iString *saveToDownloads_(const iString *url, const iString *mime,
3351 exportDownloadedFile_iOS(savePath); 3355 exportDownloadedFile_iOS(savePath);
3352#else 3356#else
3353 if (showDialog) { 3357 if (showDialog) {
3354 const iMenuItem items[2] = { 3358 const iMenuItem items[2] = {
3355 { "${dlg.save.opendownload}", 0, 0, 3359 { "${dlg.save.opendownload}", 0, 0,
3356 format_CStr("!open url:%s", cstrCollect_String(makeFileUrl_String(savePath))) }, 3360 format_CStr("!open url:%s", cstrCollect_String(makeFileUrl_String(savePath))) },
3357 { "${dlg.message.ok}", 0, 0, "message.ok" }, 3361 { "${dlg.message.ok}", 0, 0, "message.ok" },
3358 }; 3362 };
3359 makeMessage_Widget(uiHeading_ColorEscape "${heading.save}", 3363 makeMessage_Widget(uiHeading_ColorEscape "${heading.save}",
3360 format_CStr("%s\n${dlg.save.size} %.3f %s", 3364 format_CStr("%s\n${dlg.save.size} %.3f %s",
3361 cstr_String(path_File(f)), 3365 cstr_String(path_File(f)),
3362 isMega ? size / 1.0e6f : (size / 1.0e3f), 3366 isMega ? size / 1.0e6f : (size / 1.0e3f),
3363 isMega ? "${mb}" : "${kb}"), 3367 isMega ? "${mb}" : "${kb}"),
3364 items, 3368 items,
3365 iElemCount(items)); 3369 iElemCount(items));
3366 } 3370 }
3367#endif 3371#endif
3368 return savePath; 3372 ok = iTrue;
3369 } 3373 }
3370 else { 3374 else {
3371 makeSimpleMessage_Widget(uiTextCaution_ColorEscape "${heading.save.error}", 3375 makeSimpleMessage_Widget(uiTextCaution_ColorEscape "${heading.save.error}",
@@ -3373,7 +3377,16 @@ static const iString *saveToDownloads_(const iString *url, const iString *mime,
3373 } 3377 }
3374 iRelease(f); 3378 iRelease(f);
3375 } 3379 }
3376 return collectNew_String(); 3380 return ok;
3381}
3382
3383static const iString *saveToDownloads_(const iString *url, const iString *mime, const iBlock *content,
3384 iBool showDialog) {
3385 const iString *savePath = downloadPathForUrl_App(url, mime);
3386 if (!saveToFile_(savePath, content, showDialog)) {
3387 return collectNew_String();
3388 }
3389 return savePath;
3377} 3390}
3378 3391
3379static void addAllLinks_(void *context, const iGmRun *run) { 3392static void addAllLinks_(void *context, const iGmRun *run) {
@@ -4111,12 +4124,27 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)
4111 "${dlg.save.incomplete}"); 4124 "${dlg.save.incomplete}");
4112 } 4125 }
4113 else if (!isEmpty_Block(&d->sourceContent)) { 4126 else if (!isEmpty_Block(&d->sourceContent)) {
4114 const iBool doOpen = argLabel_Command(cmd, "open"); 4127 if (argLabel_Command(cmd, "extview")) {
4115 const iString *savePath = saveToDownloads_(d->mod.url, &d->sourceMime, 4128 iString *tmpPath = collectNewCStr_String(tmpnam(NULL));
4116 &d->sourceContent, !doOpen); 4129 const iRangecc tmpDir = dirName_Path(tmpPath);
4117 if (!isEmpty_String(savePath) && doOpen) { 4130 set_String(
4118 postCommandf_Root( 4131 tmpPath,
4119 w->root, "!open url:%s", cstrCollect_String(makeFileUrl_String(savePath))); 4132 collect_String(concat_Path(collectNewRange_String(tmpDir),
4133 fileNameForUrl_App(d->mod.url, &d->sourceMime))));
4134 if (saveToFile_(tmpPath, &d->sourceContent, iFalse)) {
4135 /* TODO: Remember this temporary path and delete it when quitting the app. */
4136 postCommandf_Root(w->root, "!open default:1 url:%s",
4137 cstrCollect_String(makeFileUrl_String(tmpPath)));
4138 }
4139 }
4140 else {
4141 const iBool doOpen = argLabel_Command(cmd, "open");
4142 const iString *savePath = saveToDownloads_(d->mod.url, &d->sourceMime,
4143 &d->sourceContent, !doOpen);
4144 if (!isEmpty_String(savePath) && doOpen) {
4145 postCommandf_Root(
4146 w->root, "!open url:%s", cstrCollect_String(makeFileUrl_String(savePath)));
4147 }
4120 } 4148 }
4121 } 4149 }
4122 return iTrue; 4150 return iTrue;