diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-06-11 12:39:28 +0300 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-06-11 12:39:28 +0300 |
commit | 31f7eafd9c6897cdf0ee7d6eeaade9dcc65cb006 (patch) | |
tree | 415707ca26c04ff1bee461c685e79c4302546cd4 | |
parent | 703d2b41fa299a9f8e24a5f6064c3624c3dedbbb (diff) |
iOS: Opening a file via document picker
Use a native file picker to open files. Declare support for .gmi/.gemini files so they can be opened via Files and share sheets.
-rw-r--r-- | po/en.po | 3 | ||||
-rw-r--r-- | res/iOSBundleInfo.plist.in | 246 | ||||
-rw-r--r-- | res/lang/de.bin | bin | 20949 -> 20976 bytes | |||
-rw-r--r-- | res/lang/en.bin | bin | 19654 -> 19681 bytes | |||
-rw-r--r-- | res/lang/es.bin | bin | 22028 -> 22055 bytes | |||
-rw-r--r-- | res/lang/fi.bin | bin | 22151 -> 22178 bytes | |||
-rw-r--r-- | res/lang/fr.bin | bin | 22561 -> 22588 bytes | |||
-rw-r--r-- | res/lang/ia.bin | bin | 21859 -> 21886 bytes | |||
-rw-r--r-- | res/lang/ie.bin | bin | 21417 -> 21444 bytes | |||
-rw-r--r-- | res/lang/pl.bin | bin | 22665 -> 22692 bytes | |||
-rw-r--r-- | res/lang/ru.bin | bin | 32896 -> 32923 bytes | |||
-rw-r--r-- | res/lang/sr.bin | bin | 32301 -> 32328 bytes | |||
-rw-r--r-- | res/lang/tok.bin | bin | 20042 -> 20069 bytes | |||
-rw-r--r-- | res/lang/zh_Hans.bin | bin | 18818 -> 18845 bytes | |||
-rw-r--r-- | res/lang/zh_Hant.bin | bin | 19003 -> 19030 bytes | |||
-rw-r--r-- | src/app.c | 13 | ||||
-rw-r--r-- | src/ios.h | 1 | ||||
-rw-r--r-- | src/ios.m | 26 | ||||
-rw-r--r-- | src/ui/root.c | 2 |
19 files changed, 182 insertions, 109 deletions
@@ -468,6 +468,9 @@ msgstr "Open in New Tab" | |||
468 | msgid "menu.opentab.background" | 468 | msgid "menu.opentab.background" |
469 | msgstr "Open in Background Tab" | 469 | msgstr "Open in Background Tab" |
470 | 470 | ||
471 | msgid "menu.openfile" | ||
472 | msgstr "Open File…" | ||
473 | |||
471 | msgid "menu.edit" | 474 | msgid "menu.edit" |
472 | msgstr "Edit…" | 475 | msgstr "Edit…" |
473 | 476 | ||
diff --git a/res/iOSBundleInfo.plist.in b/res/iOSBundleInfo.plist.in index 1cf0a303..f47df7cd 100644 --- a/res/iOSBundleInfo.plist.in +++ b/res/iOSBundleInfo.plist.in | |||
@@ -1,116 +1,148 @@ | |||
1 | <?xml version="1.0" encoding="UTF-8"?> | 1 | <?xml version="1.0" encoding="UTF-8"?> |
2 | <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | 2 | <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
3 | <plist version="1.0"> | 3 | <plist version="1.0"> |
4 | <dict> | 4 | <dict> |
5 | <key>CFBundleDevelopmentRegion</key> | 5 | <key>CFBundleDevelopmentRegion</key> |
6 | <string>English</string> | 6 | <string>English</string> |
7 | <key>CFBundleExecutable</key> | 7 | <key>CFBundleExecutable</key> |
8 | <string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string> | 8 | <string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string> |
9 | <key>CFBundleGetInfoString</key> | 9 | <key>CFBundleGetInfoString</key> |
10 | <string>${MACOSX_BUNDLE_INFO_STRING}</string> | 10 | <string>${MACOSX_BUNDLE_INFO_STRING}</string> |
11 | <key>CFBundleIconName</key> | 11 | <key>CFBundleIconName</key> |
12 | <string>${MACOSX_BUNDLE_ICON_FILE}</string> | 12 | <string>${MACOSX_BUNDLE_ICON_FILE}</string> |
13 | <key>CFBundleIdentifier</key> | 13 | <key>CFBundleIdentifier</key> |
14 | <string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string> | 14 | <string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string> |
15 | <key>CFBundleInfoDictionaryVersion</key> | 15 | <key>CFBundleInfoDictionaryVersion</key> |
16 | <string>6.0</string> | 16 | <string>6.0</string> |
17 | <key>CFBundleName</key> | 17 | <key>CFBundleName</key> |
18 | <string>${MACOSX_BUNDLE_BUNDLE_NAME}</string> | 18 | <string>${MACOSX_BUNDLE_BUNDLE_NAME}</string> |
19 | <key>CFBundlePackageType</key> | 19 | <key>CFBundlePackageType</key> |
20 | <string>APPL</string> | 20 | <string>APPL</string> |
21 | <key>CFBundleVersion</key> | 21 | <key>CFBundleVersion</key> |
22 | <string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string> | 22 | <string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string> |
23 | <key>CFBundleShortVersionString</key> | 23 | <key>CFBundleShortVersionString</key> |
24 | <string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string> | 24 | <string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string> |
25 | <key>CFBundleSignature</key> | 25 | <key>CFBundleSignature</key> |
26 | <string>????</string> | 26 | <string>????</string> |
27 | <key>CSResourcesFileMapped</key> | 27 | <key>CSResourcesFileMapped</key> |
28 | <true/> | 28 | <true/> |
29 | <key>NSHumanReadableCopyright</key> | 29 | <key>NSHumanReadableCopyright</key> |
30 | <string>${MACOSX_BUNDLE_COPYRIGHT}</string> | 30 | <string>${MACOSX_BUNDLE_COPYRIGHT}</string> |
31 | <key>NSHighResolutionCapable</key> | 31 | <key>NSHighResolutionCapable</key> |
32 | <true/> | 32 | <true/> |
33 | <key>NSRequiresAquaSystemAppearance</key> | 33 | <key>NSRequiresAquaSystemAppearance</key> |
34 | <false/> | 34 | <false/> |
35 | <key>NSSupportsAutomaticGraphicsSwitching</key> | 35 | <key>NSSupportsAutomaticGraphicsSwitching</key> |
36 | <true/> | 36 | <true/> |
37 | <key>UISupportedInterfaceOrientations</key> | 37 | <key>UISupportedInterfaceOrientations</key> |
38 | <array> | 38 | <array> |
39 | <string>UIInterfaceOrientationPortrait</string> | 39 | <string>UIInterfaceOrientationPortrait</string> |
40 | <string>UIInterfaceOrientationLandscapeLeft</string> | 40 | <string>UIInterfaceOrientationLandscapeLeft</string> |
41 | <string>UIInterfaceOrientationLandscapeRight</string> | 41 | <string>UIInterfaceOrientationLandscapeRight</string> |
42 | </array> | 42 | </array> |
43 | <key>UISupportedInterfaceOrientations~ipad</key> | 43 | <key>UISupportedInterfaceOrientations~ipad</key> |
44 | <array> | 44 | <array> |
45 | <string>UIInterfaceOrientationPortrait</string> | 45 | <string>UIInterfaceOrientationPortrait</string> |
46 | <string>UIInterfaceOrientationPortraitUpsideDown</string> | 46 | <string>UIInterfaceOrientationPortraitUpsideDown</string> |
47 | <string>UIInterfaceOrientationLandscapeLeft</string> | 47 | <string>UIInterfaceOrientationLandscapeLeft</string> |
48 | <string>UIInterfaceOrientationLandscapeRight</string> | 48 | <string>UIInterfaceOrientationLandscapeRight</string> |
49 | </array> | 49 | </array> |
50 | <key>UILaunchStoryboardName</key> | 50 | <key>UILaunchStoryboardName</key> |
51 | <string>LaunchScreen</string> | 51 | <string>LaunchScreen</string> |
52 | <key>UIBackgroundModes</key> | 52 | <key>UIBackgroundModes</key> |
53 | <array> | 53 | <array> |
54 | <string>audio</string> | 54 | <string>audio</string> |
55 | </array> | 55 | </array> |
56 | <key>ITSAppUsesNonExemptEncryption</key> | 56 | <key>ITSAppUsesNonExemptEncryption</key> |
57 | <false/> | 57 | <false/> |
58 | <key>LSSupportsOpeningDocumentsInPlace</key> | 58 | <key>LSSupportsOpeningDocumentsInPlace</key> |
59 | <false/> | 59 | <false/> |
60 | <key>CFBundleDocumentTypes</key> | 60 | <key>CFBundleDocumentTypes</key> |
61 | <array> | 61 | <array> |
62 | <dict> | 62 | <dict> |
63 | <key>CFBundleTypeExtensions</key> | 63 | <key>LSItemContentTypes</key> |
64 | <array> | 64 | <array> |
65 | <string>gmi</string> | 65 | <string>fi.skyjake.lagrange.gemini</string> |
66 | <string>gemini</string> | 66 | <string>public.plain-text</string> |
67 | </array> | 67 | </array> |
68 | <key>CFBundleTypeIconFile</key> | 68 | </dict> |
69 | <string>text-gemini.icns</string> | 69 | <dict> |
70 | <key>CFBundleTypeName</key> | 70 | <key>CFBundleTypeExtensions</key> |
71 | <string>Gemini Text File</string> | 71 | <array> |
72 | <key>CFBundleTypeRole</key> | 72 | <string>gmi</string> |
73 | <string>Viewer</string> | 73 | <string>gemini</string> |
74 | <key>LSHandlerRank</key> | 74 | </array> |
75 | <string>Default</string> | 75 | <key>CFBundleTypeIconFile</key> |
76 | <key>LSTypeIsPackage</key> | 76 | <string>text-gemini.icns</string> |
77 | <false/> | 77 | <key>CFBundleTypeName</key> |
78 | </dict> | 78 | <string>Gemini Text File</string> |
79 | <dict> | 79 | <key>CFBundleTypeRole</key> |
80 | <key>CFBundleTypeExtensions</key> | 80 | <string>Viewer</string> |
81 | <array> | 81 | <key>LSHandlerRank</key> |
82 | <string>gpub</string> | 82 | <string>Default</string> |
83 | </array> | 83 | <key>LSTypeIsPackage</key> |
84 | <key>CFBundleTypeIconFile</key> | 84 | <false/> |
85 | <string>gempub.icns</string> | 85 | </dict> |
86 | <key>CFBundleTypeName</key> | 86 | <dict> |
87 | <string>Gempub Book</string> | 87 | <key>CFBundleTypeExtensions</key> |
88 | <key>CFBundleTypeRole</key> | 88 | <array> |
89 | <string>Viewer</string> | 89 | <string>gpub</string> |
90 | <key>LSHandlerRank</key> | 90 | </array> |
91 | <string>Default</string> | 91 | <key>CFBundleTypeIconFile</key> |
92 | <key>LSTypeIsPackage</key> | 92 | <string>gempub.icns</string> |
93 | <false/> | 93 | <key>CFBundleTypeName</key> |
94 | </dict> | 94 | <string>Gempub Book</string> |
95 | </array> | 95 | <key>CFBundleTypeRole</key> |
96 | <key>CFBundleURLTypes</key> | 96 | <string>Viewer</string> |
97 | <array> | 97 | <key>LSHandlerRank</key> |
98 | <dict> | 98 | <string>Default</string> |
99 | <key>CFBundleURLName</key> | 99 | <key>LSTypeIsPackage</key> |
100 | <string>Gemini</string> | 100 | <false/> |
101 | <key>CFBundleURLSchemes</key> | 101 | </dict> |
102 | <array> | 102 | </array> |
103 | <string>gemini</string> | 103 | <key>CFBundleURLTypes</key> |
104 | </array> | 104 | <array> |
105 | </dict> | 105 | <dict> |
106 | <dict> | 106 | <key>CFBundleURLName</key> |
107 | <key>CFBundleURLName</key> | 107 | <string>Gemini</string> |
108 | <string>Gopher</string> | 108 | <key>CFBundleURLSchemes</key> |
109 | <key>CFBundleURLSchemes</key> | 109 | <array> |
110 | <array> | 110 | <string>gemini</string> |
111 | <string>gopher</string> | 111 | </array> |
112 | </array> | 112 | </dict> |
113 | </dict> | 113 | <dict> |
114 | </array> | 114 | <key>CFBundleURLName</key> |
115 | </dict> | 115 | <string>Gopher</string> |
116 | <key>CFBundleURLSchemes</key> | ||
117 | <array> | ||
118 | <string>gopher</string> | ||
119 | </array> | ||
120 | </dict> | ||
121 | </array> | ||
122 | <key>UTExportedTypeDeclarations</key> | ||
123 | <array> | ||
124 | <dict> | ||
125 | <key>UTTypeIdentifier</key> | ||
126 | <string>fi.skyjake.lagrange.gemini</string> | ||
127 | <key>UTTypeReferenceURL</key> | ||
128 | <string>https://gemini.circumlunar.space/docs/specification.gmi</string> | ||
129 | <key>UTTypeDescription</key> | ||
130 | <string>Gemini Text Document</string> | ||
131 | <key>UTTypeConformsTo</key> | ||
132 | <array> | ||
133 | <string>public.plain-text</string> | ||
134 | </array> | ||
135 | <key>UTTypeTagSpecification</key> | ||
136 | <dict> | ||
137 | <key>public.filename-extension</key> | ||
138 | <array> | ||
139 | <string>gmi</string> | ||
140 | <string>gemini</string> | ||
141 | </array> | ||
142 | <key>public.mime-type</key> | ||
143 | <string>text/gemini</string> | ||
144 | </dict> | ||
145 | </dict> | ||
146 | </array> | ||
147 | </dict> | ||
116 | </plist> | 148 | </plist> |
diff --git a/res/lang/de.bin b/res/lang/de.bin index ad41666e..1738f4a7 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 a107cec4..54bb4867 100644 --- a/res/lang/en.bin +++ b/res/lang/en.bin | |||
Binary files differ | |||
diff --git a/res/lang/es.bin b/res/lang/es.bin index 5ad57bc6..5e0ec4d0 100644 --- a/res/lang/es.bin +++ b/res/lang/es.bin | |||
Binary files differ | |||
diff --git a/res/lang/fi.bin b/res/lang/fi.bin index 5167bea1..a000d152 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 dfa5f097..db440d19 100644 --- a/res/lang/fr.bin +++ b/res/lang/fr.bin | |||
Binary files differ | |||
diff --git a/res/lang/ia.bin b/res/lang/ia.bin index 91e5336c..c0fb91d9 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 d1cdb189..96f5f2cb 100644 --- a/res/lang/ie.bin +++ b/res/lang/ie.bin | |||
Binary files differ | |||
diff --git a/res/lang/pl.bin b/res/lang/pl.bin index b65a2b52..99b6f1c4 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 d962ec59..aec21b35 100644 --- a/res/lang/ru.bin +++ b/res/lang/ru.bin | |||
Binary files differ | |||
diff --git a/res/lang/sr.bin b/res/lang/sr.bin index bcd10900..ac4223ac 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 8d4963bd..760b3044 100644 --- a/res/lang/tok.bin +++ b/res/lang/tok.bin | |||
Binary files differ | |||
diff --git a/res/lang/zh_Hans.bin b/res/lang/zh_Hans.bin index 0a5bab01..cc8543b2 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 53b05911..2ef3b8a9 100644 --- a/res/lang/zh_Hant.bin +++ b/res/lang/zh_Hant.bin | |||
Binary files differ | |||
@@ -2303,6 +2303,19 @@ iBool handleCommand_App(const char *cmd) { | |||
2303 | } | 2303 | } |
2304 | setCurrent_Root(oldRoot); | 2304 | setCurrent_Root(oldRoot); |
2305 | } | 2305 | } |
2306 | else if (equal_Command(cmd, "file.open")) { | ||
2307 | const char *path = suffixPtr_Command(cmd, "path"); | ||
2308 | if (path) { | ||
2309 | postCommandf_App("open temp:%d url:%s", | ||
2310 | argLabel_Command(cmd, "temp"), | ||
2311 | makeFileUrl_CStr(path)); | ||
2312 | return iTrue; | ||
2313 | } | ||
2314 | #if defined (iPlatformAppleMobile) | ||
2315 | pickFileForOpening_iOS(); | ||
2316 | #endif | ||
2317 | return iTrue; | ||
2318 | } | ||
2306 | else if (equal_Command(cmd, "file.delete")) { | 2319 | else if (equal_Command(cmd, "file.delete")) { |
2307 | const char *path = suffixPtr_Command(cmd, "path"); | 2320 | const char *path = suffixPtr_Command(cmd, "path"); |
2308 | if (argLabel_Command(cmd, "confirm")) { | 2321 | if (argLabel_Command(cmd, "confirm")) { |
@@ -35,6 +35,7 @@ void setupWindow_iOS (iWindow *window); | |||
35 | iBool processEvent_iOS (const SDL_Event *); | 35 | iBool processEvent_iOS (const SDL_Event *); |
36 | void playHapticEffect_iOS (enum iHapticEffect effect); | 36 | void playHapticEffect_iOS (enum iHapticEffect effect); |
37 | void exportDownloadedFile_iOS(const iString *path); | 37 | void exportDownloadedFile_iOS(const iString *path); |
38 | void pickFileForOpening_iOS (void); | ||
38 | 39 | ||
39 | iBool isPhone_iOS (void); | 40 | iBool isPhone_iOS (void); |
40 | void safeAreaInsets_iOS (float *left, float *top, float *right, float *bottom); | 41 | void safeAreaInsets_iOS (float *left, float *top, float *right, float *bottom); |
@@ -181,11 +181,22 @@ static AppState *appState_; | |||
181 | 181 | ||
182 | - (void)documentPicker:(UIDocumentPickerViewController *)controller | 182 | - (void)documentPicker:(UIDocumentPickerViewController *)controller |
183 | didPickDocumentsAtURLs:(NSArray<NSURL *> *)urls { | 183 | didPickDocumentsAtURLs:(NSArray<NSURL *> *)urls { |
184 | [self removeSavedFile]; | 184 | if (fileBeingSaved) { |
185 | [self removeSavedFile]; | ||
186 | } | ||
187 | else { | ||
188 | /* A file is being opened. */ | ||
189 | NSURL *url = [urls firstObject]; | ||
190 | iString *path = localFilePathFromUrl_String(collectNewCStr_String([[url absoluteString] | ||
191 | UTF8String])); | ||
192 | postCommandf_App("file.open temp:1 path:%s", cstrCollect_String(path)); | ||
193 | } | ||
185 | } | 194 | } |
186 | 195 | ||
187 | - (void)documentPickerWasCancelled:(UIDocumentPickerViewController *)controller { | 196 | - (void)documentPickerWasCancelled:(UIDocumentPickerViewController *)controller { |
188 | [self removeSavedFile]; | 197 | if (fileBeingSaved) { |
198 | [self removeSavedFile]; | ||
199 | } | ||
189 | } | 200 | } |
190 | 201 | ||
191 | -(void)keyboardOnScreen:(NSNotification *)notification { | 202 | -(void)keyboardOnScreen:(NSNotification *)notification { |
@@ -335,6 +346,17 @@ void exportDownloadedFile_iOS(const iString *path) { | |||
335 | [viewController_(get_Window()) presentViewController:picker animated:YES completion:nil]; | 346 | [viewController_(get_Window()) presentViewController:picker animated:YES completion:nil]; |
336 | } | 347 | } |
337 | 348 | ||
349 | void pickFileForOpening_iOS(void) { | ||
350 | UIDocumentPickerViewController *picker = [[UIDocumentPickerViewController alloc] | ||
351 | initWithDocumentTypes:@[@"fi.skyjake.lagrange.gemini", | ||
352 | @"public.text", | ||
353 | @"public.image", | ||
354 | @"public.audio"] | ||
355 | inMode:UIDocumentPickerModeImport]; | ||
356 | picker.delegate = appState_; | ||
357 | [viewController_(get_Window()) presentViewController:picker animated:YES completion:nil]; | ||
358 | } | ||
359 | |||
338 | /*----------------------------------------------------------------------------------------------*/ | 360 | /*----------------------------------------------------------------------------------------------*/ |
339 | 361 | ||
340 | enum iAVFAudioPlayerState { | 362 | enum iAVFAudioPlayerState { |
diff --git a/src/ui/root.c b/src/ui/root.c index 52b6829c..0ab969bf 100644 --- a/src/ui/root.c +++ b/src/ui/root.c | |||
@@ -90,6 +90,7 @@ static const iMenuItem navMenuItems_[] = { | |||
90 | #if defined (iPlatformAppleMobile) | 90 | #if defined (iPlatformAppleMobile) |
91 | /* Tablet menu. */ | 91 | /* Tablet menu. */ |
92 | static const iMenuItem tabletNavMenuItems_[] = { | 92 | static const iMenuItem tabletNavMenuItems_[] = { |
93 | { folder_Icon " ${menu.openfile}", SDLK_o, KMOD_PRIMARY, "file.open" }, | ||
93 | { add_Icon " ${menu.newtab}", 't', KMOD_PRIMARY, "tabs.new" }, | 94 | { add_Icon " ${menu.newtab}", 't', KMOD_PRIMARY, "tabs.new" }, |
94 | { close_Icon " ${menu.closetab}", 'w', KMOD_PRIMARY, "tabs.close" }, | 95 | { close_Icon " ${menu.closetab}", 'w', KMOD_PRIMARY, "tabs.close" }, |
95 | { "---", 0, 0, NULL }, | 96 | { "---", 0, 0, NULL }, |
@@ -110,6 +111,7 @@ static const iMenuItem tabletNavMenuItems_[] = { | |||
110 | 111 | ||
111 | /* Phone menu. */ | 112 | /* Phone menu. */ |
112 | static const iMenuItem phoneNavMenuItems_[] = { | 113 | static const iMenuItem phoneNavMenuItems_[] = { |
114 | { folder_Icon " ${menu.openfile}", SDLK_o, KMOD_PRIMARY, "file.open" }, | ||
113 | { add_Icon " ${menu.newtab}", 't', KMOD_PRIMARY, "tabs.new" }, | 115 | { add_Icon " ${menu.newtab}", 't', KMOD_PRIMARY, "tabs.new" }, |
114 | { close_Icon " ${menu.closetab}", 'w', KMOD_PRIMARY, "tabs.close" }, | 116 | { close_Icon " ${menu.closetab}", 'w', KMOD_PRIMARY, "tabs.close" }, |
115 | { "---", 0, 0, NULL }, | 117 | { "---", 0, 0, NULL }, |