diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-03-16 22:13:50 +0200 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-03-16 22:13:50 +0200 |
commit | 9c6da385be908d454ead2056de9b9c31546411ef (patch) | |
tree | 607871ff9ece3cf9fb53b291e5bdb1b3f0e4b3fe | |
parent | 5d3567bd26ad1031e4ec08ccd2c36f5f1f646ca7 (diff) |
Translation: Remember last used languages
-rw-r--r-- | src/app.c | 6 | ||||
-rw-r--r-- | src/prefs.c | 2 | ||||
-rw-r--r-- | src/prefs.h | 2 | ||||
-rw-r--r-- | src/ui/translation.c | 56 | ||||
-rw-r--r-- | src/ui/util.c | 67 | ||||
-rw-r--r-- | src/ui/util.h | 1 |
6 files changed, 80 insertions, 54 deletions
@@ -232,6 +232,7 @@ static iString *serializePrefs_App_(const iApp *d) { | |||
232 | appendFormat_String(str, "proxy.http address:%s\n", cstr_String(&d->prefs.httpProxy)); | 232 | appendFormat_String(str, "proxy.http address:%s\n", cstr_String(&d->prefs.httpProxy)); |
233 | appendFormat_String(str, "downloads path:%s\n", cstr_String(&d->prefs.downloadDir)); | 233 | appendFormat_String(str, "downloads path:%s\n", cstr_String(&d->prefs.downloadDir)); |
234 | appendFormat_String(str, "searchurl address:%s\n", cstr_String(&d->prefs.searchUrl)); | 234 | appendFormat_String(str, "searchurl address:%s\n", cstr_String(&d->prefs.searchUrl)); |
235 | appendFormat_String(str, "translation.languages from:%d to:%d\n", d->prefs.langFrom, d->prefs.langTo); | ||
235 | return str; | 236 | return str; |
236 | } | 237 | } |
237 | 238 | ||
@@ -1455,6 +1456,11 @@ iBool handleCommand_App(const char *cmd) { | |||
1455 | d->prefs.dialogTab = arg_Command(cmd); | 1456 | d->prefs.dialogTab = arg_Command(cmd); |
1456 | return iTrue; | 1457 | return iTrue; |
1457 | } | 1458 | } |
1459 | else if (equal_Command(cmd, "translation.languages")) { | ||
1460 | d->prefs.langFrom = argLabel_Command(cmd, "from"); | ||
1461 | d->prefs.langTo = argLabel_Command(cmd, "to"); | ||
1462 | return iTrue; | ||
1463 | } | ||
1458 | else if (equal_Command(cmd, "window.retain")) { | 1464 | else if (equal_Command(cmd, "window.retain")) { |
1459 | d->prefs.retainWindowSize = arg_Command(cmd); | 1465 | d->prefs.retainWindowSize = arg_Command(cmd); |
1460 | return iTrue; | 1466 | return iTrue; |
diff --git a/src/prefs.c b/src/prefs.c index 5aba8359..b9b59836 100644 --- a/src/prefs.c +++ b/src/prefs.c | |||
@@ -26,6 +26,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
26 | 26 | ||
27 | void init_Prefs(iPrefs *d) { | 27 | void init_Prefs(iPrefs *d) { |
28 | d->dialogTab = 0; | 28 | d->dialogTab = 0; |
29 | d->langFrom = 3; /* fr */ | ||
30 | d->langTo = 2; /* en */ | ||
29 | d->useSystemTheme = iTrue; | 31 | d->useSystemTheme = iTrue; |
30 | d->theme = dark_ColorTheme; | 32 | d->theme = dark_ColorTheme; |
31 | d->accent = cyan_ColorAccent; | 33 | d->accent = cyan_ColorAccent; |
diff --git a/src/prefs.h b/src/prefs.h index 50dd1969..13b91568 100644 --- a/src/prefs.h +++ b/src/prefs.h | |||
@@ -35,6 +35,8 @@ iDeclareType(Prefs) | |||
35 | struct Impl_Prefs { | 35 | struct Impl_Prefs { |
36 | /* UI state */ | 36 | /* UI state */ |
37 | int dialogTab; | 37 | int dialogTab; |
38 | int langFrom; | ||
39 | int langTo; | ||
38 | /* Window */ | 40 | /* Window */ |
39 | iBool useSystemTheme; | 41 | iBool useSystemTheme; |
40 | enum iColorTheme theme; | 42 | enum iColorTheme theme; |
diff --git a/src/ui/translation.c b/src/ui/translation.c index e5059f38..bbc1763e 100644 --- a/src/ui/translation.c +++ b/src/ui/translation.c | |||
@@ -151,13 +151,6 @@ iDefineTypeConstructionArgs(Translation, (iDocumentWidget *doc), doc) | |||
151 | static const char * translationServiceHost = "xlt.skyjake.fi"; | 151 | static const char * translationServiceHost = "xlt.skyjake.fi"; |
152 | static const uint16_t translationServicePort = 443; | 152 | static const uint16_t translationServicePort = 443; |
153 | 153 | ||
154 | //static const char *doubleArrowSymbol = "\U0001f192"; //"\u20e2"; /* prevent getting mangled */ | ||
155 | //static const char *tripleBacktickSymbol = "\U0001f1a9"; //\u20e3"; | ||
156 | //static const char *h1Symbol = "\U0001f19d"; | ||
157 | //static const char *h2Symbol = "\U0001f19e"; | ||
158 | //static const char *h3Symbol = "\U0001f19f"; | ||
159 | //static const char *bulletSymbol = "\n\U0001f196"; | ||
160 | |||
161 | static iString *quote_String_(const iString *d) { | 154 | static iString *quote_String_(const iString *d) { |
162 | iString *quot = new_String(); | 155 | iString *quot = new_String(); |
163 | iConstForEach(String, i, d) { | 156 | iConstForEach(String, i, d) { |
@@ -292,13 +285,19 @@ static uint32_t animate_Translation_(uint32_t interval, iAny *ptr) { | |||
292 | } | 285 | } |
293 | 286 | ||
294 | void submit_Translation(iTranslation *d) { | 287 | void submit_Translation(iTranslation *d) { |
288 | iAssert(status_TlsRequest(d->request) != submitted_TlsRequestStatus); | ||
295 | /* Check the selected languages from the dialog. */ | 289 | /* Check the selected languages from the dialog. */ |
296 | const char *idFrom = languageId_String(text_LabelWidget(findChild_Widget(d->dlg, "xlt.from"))); | 290 | const char *idFrom = languageId_String(text_LabelWidget(findChild_Widget(d->dlg, "xlt.from"))); |
297 | const char *idTo = languageId_String(text_LabelWidget(findChild_Widget(d->dlg, "xlt.to"))); | 291 | const char *idTo = languageId_String(text_LabelWidget(findChild_Widget(d->dlg, "xlt.to"))); |
298 | iAssert(status_TlsRequest(d->request) != submitted_TlsRequestStatus); | 292 | /* Remember these in Preferences. */ |
299 | iBlock *json = collect_Block(new_Block(0)); | 293 | postCommandf_App("translation.languages from:%d to:%d", |
294 | languageIndex_CStr(idFrom), | ||
295 | languageIndex_CStr(idTo)); | ||
296 | iBlock * json = collect_Block(new_Block(0)); | ||
300 | iString *docSrc = collectNew_String(); | 297 | iString *docSrc = collectNew_String(); |
301 | /* TODO: Strip all markup and remember it. These are reapplied when reading response. */ { | 298 | /* The translation engine doesn't preserve Gemtext markup so we'll strip all of it and |
299 | remember each line's type. These are reapplied when reading the response. Newlines seem | ||
300 | to be preserved pretty well. */ { | ||
302 | iRangecc line = iNullRange; | 301 | iRangecc line = iNullRange; |
303 | while (nextSplit_Rangecc( | 302 | while (nextSplit_Rangecc( |
304 | range_String(source_GmDocument(document_DocumentWidget(d->doc))), "\n", &line)) { | 303 | range_String(source_GmDocument(document_DocumentWidget(d->doc))), "\n", &line)) { |
@@ -317,28 +316,25 @@ void submit_Translation(iTranslation *d) { | |||
317 | appendRange_String(docSrc, cleanLine); | 316 | appendRange_String(docSrc, cleanLine); |
318 | } | 317 | } |
319 | } | 318 | } |
320 | // replace_String(docSrc, "=>", doubleArrowSymbol); | ||
321 | // replace_String(docSrc, "```", tripleBacktickSymbol); | ||
322 | // replace_String(docSrc, "###", h3Symbol); | ||
323 | // replace_String(docSrc, "##", h2Symbol); | ||
324 | // replace_String(docSrc, "#", h1Symbol); | ||
325 | // replace_String(docSrc, "\n*", bulletSymbol); | ||
326 | printf_Block(json, | 319 | printf_Block(json, |
327 | "{\"q\":\"%s\",\"source\":\"%s\",\"target\":\"%s\"}", | 320 | "{\"q\":\"%s\",\"source\":\"%s\",\"target\":\"%s\"}", |
328 | cstrCollect_String(quote_String_(docSrc)), | 321 | cstrCollect_String(quote_String_(docSrc)), |
329 | idFrom, | 322 | idFrom, |
330 | idTo); | 323 | idTo); |
331 | iBlock *msg = collect_Block(new_Block(0)); | 324 | iBlock *msg = collect_Block(new_Block(0)); |
332 | printf_Block(msg, "POST /translate HTTP/1.1\r\n" | 325 | printf_Block(msg, |
333 | "Host: xlt.skyjake.fi\r\n" | 326 | "POST /translate HTTP/1.1\r\n" |
334 | "Connection: close\r\n" | 327 | "Host: %s\r\n" |
335 | "Content-Type: application/json; charset=utf-8\r\n" | 328 | "Connection: close\r\n" |
336 | "Content-Length: %zu\r\n\r\n", size_Block(json)); | 329 | "Content-Type: application/json; charset=utf-8\r\n" |
330 | "Content-Length: %zu\r\n\r\n", | ||
331 | translationServiceHost, | ||
332 | size_Block(json)); | ||
337 | append_Block(msg, json); | 333 | append_Block(msg, json); |
338 | setContent_TlsRequest(d->request, msg); | 334 | setContent_TlsRequest(d->request, msg); |
339 | submit_TlsRequest(d->request); | 335 | submit_TlsRequest(d->request); |
340 | d->startTime = SDL_GetTicks(); | 336 | d->startTime = SDL_GetTicks(); |
341 | d->timer = SDL_AddTimer(1000 / 30, animate_Translation_, d); | 337 | d->timer = SDL_AddTimer(1000 / 30, animate_Translation_, d); |
342 | } | 338 | } |
343 | 339 | ||
344 | static void setFailed_Translation_(iTranslation *d, const char *msg) { | 340 | static void setFailed_Translation_(iTranslation *d, const char *msg) { |
@@ -356,8 +352,8 @@ static iBool processResult_Translation_(iTranslation *d) { | |||
356 | return iFalse; | 352 | return iFalse; |
357 | } | 353 | } |
358 | iBlock *resultData = collect_Block(readAll_TlsRequest(d->request)); | 354 | iBlock *resultData = collect_Block(readAll_TlsRequest(d->request)); |
359 | printf("result(%zu):\n%s\n", size_Block(resultData), cstr_Block(resultData)); | 355 | // printf("result(%zu):\n%s\n", size_Block(resultData), cstr_Block(resultData)); |
360 | fflush(stdout); | 356 | // fflush(stdout); |
361 | iRegExp *pattern = iClob(new_RegExp(".*translatedText\":\"(.*)\"\\}", caseSensitive_RegExpOption)); | 357 | iRegExp *pattern = iClob(new_RegExp(".*translatedText\":\"(.*)\"\\}", caseSensitive_RegExpOption)); |
362 | iRegExpMatch m; | 358 | iRegExpMatch m; |
363 | init_RegExpMatch(&m); | 359 | init_RegExpMatch(&m); |
@@ -401,12 +397,6 @@ static iBool processResult_Translation_(iTranslation *d) { | |||
401 | appendRange_String(marked, cleanLine); | 397 | appendRange_String(marked, cleanLine); |
402 | lineIndex++; | 398 | lineIndex++; |
403 | } | 399 | } |
404 | // replace_String(translation, tripleBacktickSymbol, "```"); | ||
405 | // replace_String(translation, doubleArrowSymbol, "=>"); | ||
406 | // replace_String(translation, h3Symbol, "### "); | ||
407 | // replace_String(translation, h2Symbol, "## "); | ||
408 | // replace_String(translation, h1Symbol, "# "); | ||
409 | // replace_String(translation, bulletSymbol, "\n* "); | ||
410 | setSource_DocumentWidget(d->doc, marked); | 400 | setSource_DocumentWidget(d->doc, marked); |
411 | postCommand_App("sidebar.update"); | 401 | postCommand_App("sidebar.update"); |
412 | delete_String(translation); | 402 | delete_String(translation); |
@@ -419,7 +409,11 @@ static iBool processResult_Translation_(iTranslation *d) { | |||
419 | } | 409 | } |
420 | 410 | ||
421 | static iLabelWidget *acceptButton_Translation_(const iTranslation *d) { | 411 | static iLabelWidget *acceptButton_Translation_(const iTranslation *d) { |
422 | return (iLabelWidget *) lastChild_Widget(findChild_Widget(d->dlg, "dialogbuttons")); | 412 | iWidget *buttonParent = findChild_Widget(d->dlg, "dialogbuttons"); |
413 | // if (!buttonParent) { | ||
414 | // buttonParent = findChild_Widget(d->dlg, "panel.back"); | ||
415 | // } | ||
416 | return (iLabelWidget *) lastChild_Widget(buttonParent); | ||
423 | } | 417 | } |
424 | 418 | ||
425 | iBool handleCommand_Translation(iTranslation *d, const char *cmd) { | 419 | iBool handleCommand_Translation(iTranslation *d, const char *cmd) { |
diff --git a/src/ui/util.c b/src/ui/util.c index c1e27751..400e65d4 100644 --- a/src/ui/util.c +++ b/src/ui/util.c | |||
@@ -1078,6 +1078,12 @@ static iWidget *makeValuePadding_(iWidget *value) { | |||
1078 | } | 1078 | } |
1079 | 1079 | ||
1080 | void finalizeSheet_Widget(iWidget *sheet) { | 1080 | void finalizeSheet_Widget(iWidget *sheet) { |
1081 | /* The sheet contents are completely rearranged and restyled on a phone. | ||
1082 | We'll set up a linear fullscreen arrangement of the widgets. Sheets are already | ||
1083 | scrollable so they can be taller than the display. In hindsight, it may have been | ||
1084 | easier to create phone versions of each dialog, but at least this works with any | ||
1085 | future changes to the UI (..."works"). At least this way it is possible to enforce | ||
1086 | a consistent styling. */ | ||
1081 | if (deviceType_App() == phone_AppDeviceType && parent_Widget(sheet) == get_Window()->root) { | 1087 | if (deviceType_App() == phone_AppDeviceType && parent_Widget(sheet) == get_Window()->root) { |
1082 | if (~flags_Widget(sheet) & keepOnTop_WidgetFlag) { | 1088 | if (~flags_Widget(sheet) & keepOnTop_WidgetFlag) { |
1083 | /* Already finalized. */ | 1089 | /* Already finalized. */ |
@@ -1085,11 +1091,6 @@ void finalizeSheet_Widget(iWidget *sheet) { | |||
1085 | postRefresh_App(); | 1091 | postRefresh_App(); |
1086 | return; | 1092 | return; |
1087 | } | 1093 | } |
1088 | /* The sheet contents are completely rearranged on a phone. We'll set up a linear | ||
1089 | fullscreen arrangement of the widgets. Sheets are already scrollable so they | ||
1090 | can be taller than the display. In hindsight, it may have been easier to | ||
1091 | create phone versions of each dialog, but at least this works with any future | ||
1092 | changes to the UI (..."works"). */ | ||
1093 | setFlags_Widget(sheet, | 1094 | setFlags_Widget(sheet, |
1094 | keepOnTop_WidgetFlag | | 1095 | keepOnTop_WidgetFlag | |
1095 | parentCannotResize_WidgetFlag | | 1096 | parentCannotResize_WidgetFlag | |
@@ -1366,6 +1367,9 @@ void finalizeSheet_Widget(iWidget *sheet) { | |||
1366 | /* Pick up the dialog buttons for the navbar. */ | 1367 | /* Pick up the dialog buttons for the navbar. */ |
1367 | iWidget *buttons = findChild_Widget(sheet, "dialogbuttons"); | 1368 | iWidget *buttons = findChild_Widget(sheet, "dialogbuttons"); |
1368 | iLabelWidget *cancel = findMenuItem_Widget(buttons, "cancel"); | 1369 | iLabelWidget *cancel = findMenuItem_Widget(buttons, "cancel"); |
1370 | // if (!cancel) { | ||
1371 | // cancel = findMenuItem_Widget(buttons, "translation.cancel"); | ||
1372 | // } | ||
1369 | if (cancel) { | 1373 | if (cancel) { |
1370 | updateText_LabelWidget(back, text_LabelWidget(cancel)); | 1374 | updateText_LabelWidget(back, text_LabelWidget(cancel)); |
1371 | setCommand_LabelWidget(back, command_LabelWidget(cancel)); | 1375 | setCommand_LabelWidget(back, command_LabelWidget(cancel)); |
@@ -2223,6 +2227,7 @@ static const iMenuItem languages[] = { | |||
2223 | }; | 2227 | }; |
2224 | 2228 | ||
2225 | static iBool translationHandler_(iWidget *dlg, const char *cmd) { | 2229 | static iBool translationHandler_(iWidget *dlg, const char *cmd) { |
2230 | iUnused(dlg); | ||
2226 | if (equal_Command(cmd, "xlt.lang")) { | 2231 | if (equal_Command(cmd, "xlt.lang")) { |
2227 | iLabelWidget *menuItem = pointer_Command(cmd); | 2232 | iLabelWidget *menuItem = pointer_Command(cmd); |
2228 | iWidget *button = parent_Widget(parent_Widget(menuItem)); | 2233 | iWidget *button = parent_Widget(parent_Widget(menuItem)); |
@@ -2242,6 +2247,15 @@ const char *languageId_String(const iString *menuItemLabel) { | |||
2242 | return ""; | 2247 | return ""; |
2243 | } | 2248 | } |
2244 | 2249 | ||
2250 | int languageIndex_CStr(const char *langId) { | ||
2251 | iForIndices(i, languages) { | ||
2252 | if (equal_Rangecc(range_Command(languages[i].command, "id"), langId)) { | ||
2253 | return i; | ||
2254 | } | ||
2255 | } | ||
2256 | return -1; | ||
2257 | } | ||
2258 | |||
2245 | iWidget *makeTranslation_Widget(iWidget *parent) { | 2259 | iWidget *makeTranslation_Widget(iWidget *parent) { |
2246 | iWidget *dlg = makeSheet_Widget("xlt"); | 2260 | iWidget *dlg = makeSheet_Widget("xlt"); |
2247 | setFlags_Widget(dlg, keepOnTop_WidgetFlag, iFalse); | 2261 | setFlags_Widget(dlg, keepOnTop_WidgetFlag, iFalse); |
@@ -2254,25 +2268,32 @@ iWidget *makeTranslation_Widget(iWidget *parent) { | |||
2254 | iWidget *page; | 2268 | iWidget *page; |
2255 | addChild_Widget(dlg, iClob(page = makeTwoColumnWidget_(&headings, &values))); | 2269 | addChild_Widget(dlg, iClob(page = makeTwoColumnWidget_(&headings, &values))); |
2256 | setId_Widget(page, "xlt.langs"); | 2270 | setId_Widget(page, "xlt.langs"); |
2257 | addChild_Widget(headings, iClob(makeHeading_Widget("From:"))); | ||
2258 | iLabelWidget *fromLang, *toLang; | 2271 | iLabelWidget *fromLang, *toLang; |
2259 | setId_Widget(addChildFlags_Widget(values, | 2272 | /* Source language. */ { |
2260 | iClob(fromLang = makeMenuButton_LabelWidget( | 2273 | addChild_Widget(headings, iClob(makeHeading_Widget("From:"))); |
2261 | "Portuguese", languages, iElemCount(languages))), | 2274 | setId_Widget( |
2262 | alignLeft_WidgetFlag), | 2275 | addChildFlags_Widget(values, |
2263 | "xlt.from"); | 2276 | iClob(fromLang = makeMenuButton_LabelWidget( |
2264 | updateTextCStr_LabelWidget(fromLang, "French"); /* TODO: Check source media type; remember last use. */ | 2277 | "Portuguese", languages, iElemCount(languages))), |
2265 | setBackgroundColor_Widget(findChild_Widget(as_Widget(fromLang), "menu"), | 2278 | alignLeft_WidgetFlag), |
2266 | uiBackgroundMenu_ColorId); | 2279 | "xlt.from"); |
2267 | addChild_Widget(headings, iClob(makeHeading_Widget("To:"))); | 2280 | iWidget *langMenu = findChild_Widget(as_Widget(fromLang), "menu"); |
2268 | setId_Widget(addChildFlags_Widget(values, | 2281 | updateText_LabelWidget(fromLang, |
2269 | iClob(toLang = makeMenuButton_LabelWidget( | 2282 | text_LabelWidget(child_Widget(langMenu, prefs_App()->langFrom))); |
2270 | "Portuguese", languages, iElemCount(languages))), | 2283 | setBackgroundColor_Widget(langMenu, uiBackgroundMenu_ColorId); |
2271 | alignLeft_WidgetFlag), | 2284 | } |
2272 | "xlt.to"); | 2285 | /* Target language. */ { |
2273 | setBackgroundColor_Widget(findChild_Widget(as_Widget(toLang), "menu"), | 2286 | addChild_Widget(headings, iClob(makeHeading_Widget("To:"))); |
2274 | uiBackgroundMenu_ColorId); | 2287 | setId_Widget(addChildFlags_Widget(values, |
2275 | updateTextCStr_LabelWidget(toLang, "English"); /* TODO: User preference. */ | 2288 | iClob(toLang = makeMenuButton_LabelWidget( |
2289 | "Portuguese", languages, iElemCount(languages))), | ||
2290 | alignLeft_WidgetFlag), | ||
2291 | "xlt.to"); | ||
2292 | iWidget *langMenu = findChild_Widget(as_Widget(toLang), "menu"); | ||
2293 | setBackgroundColor_Widget(langMenu, uiBackgroundMenu_ColorId); | ||
2294 | updateText_LabelWidget(toLang, | ||
2295 | text_LabelWidget(child_Widget(langMenu, prefs_App()->langTo))); | ||
2296 | } | ||
2276 | addChild_Widget(dlg, iClob(makePadding_Widget(lineHeight_Text(uiLabel_FontId)))); | 2297 | addChild_Widget(dlg, iClob(makePadding_Widget(lineHeight_Text(uiLabel_FontId)))); |
2277 | addChild_Widget( | 2298 | addChild_Widget( |
2278 | dlg, | 2299 | dlg, |
diff --git a/src/ui/util.h b/src/ui/util.h index 251683f5..35e10c6f 100644 --- a/src/ui/util.h +++ b/src/ui/util.h | |||
@@ -226,3 +226,4 @@ iWidget * makeFeedSettings_Widget (uint32_t bookmarkId); | |||
226 | iWidget * makeTranslation_Widget (iWidget *parent); | 226 | iWidget * makeTranslation_Widget (iWidget *parent); |
227 | 227 | ||
228 | const char * languageId_String (const iString *menuItemLabel); | 228 | const char * languageId_String (const iString *menuItemLabel); |
229 | int languageIndex_CStr (const char *langId); | ||