GingerCal 1.3: month view, Galician interface, Nginx Proxy Manager bridge option
This commit is contained in:
1 parent
f44ecf4871
commit
42c3d6da91
39 files changed
+1409
-220
No files matched your search
+15
-22
@@ -109,41 +109,34 @@ public class Dav {
|
||||
continue;
|
||||
}
|
||||
if (r.code == 401) {
|
||||
throw new DavException(401, "Login refused (401). Check the user name and use a "
|
||||
+ "Nextcloud app password (Settings > Security > Devices & sessions).");
|
||||
throw new DavException(401, L.t("Login refused (401). Check the user name and use a Nextcloud app password (Settings > Security > Devices & sessions)."));
|
||||
}
|
||||
if (r.code == 403 && body != null && method.equals("PUT")) {
|
||||
throw new DavException(403, "Not allowed to write to this calendar (403). It may be read-only/shared.");
|
||||
throw new DavException(403, L.t("Not allowed to write to this calendar (403). It may be read-only/shared."));
|
||||
}
|
||||
return r;
|
||||
}
|
||||
throw new DavException(DavException.REDIRECT, "Too many redirects from the server.");
|
||||
throw new DavException(DavException.REDIRECT, L.t("Too many redirects from the server."));
|
||||
}
|
||||
|
||||
static void checkRedirect(String from, String to, List<String> visited, int code) throws DavException {
|
||||
String a = originKey(from), b = originKey(to);
|
||||
if (a.startsWith("http:") && b.startsWith("https:")) {
|
||||
throw new DavException(DavException.REDIRECT, "The server redirected http:// to "
|
||||
+ origin(to) + " (Nextcloud forces HTTPS / HSTS). Android 2.3 can't follow that: "
|
||||
+ "use the legacy-TLS bridge address instead (see README, 'Forced HTTPS / HSTS').");
|
||||
throw new DavException(DavException.REDIRECT, L.f("The server redirected http:// to %s (Nextcloud forces HTTPS / HSTS). Android 2.3 can't follow that: use the legacy-TLS bridge address instead (see README, 'Forced HTTPS / HSTS').", origin(to)));
|
||||
}
|
||||
if (!a.equals(b)) {
|
||||
throw new DavException(DavException.REDIRECT, "The server redirected to " + origin(to)
|
||||
+ ", not the address set in the app. Nextcloud is sending its public URL; check the "
|
||||
+ "bridge's proxy_redirect line (README, 'Forced HTTPS / HSTS').");
|
||||
throw new DavException(DavException.REDIRECT, L.f("The server redirected to %s, not the address set in the app. Nextcloud is sending its public URL; check the bridge's proxy_redirect line (README, 'Forced HTTPS / HSTS').", origin(to)));
|
||||
}
|
||||
if (visited.contains(to)) {
|
||||
throw new DavException(DavException.REDIRECT, "Redirect loop (HTTP " + code + " back to the same "
|
||||
+ "address). Nextcloud forces HTTPS but the bridge reaches it over plain HTTP: switch the "
|
||||
+ "bridge to proxy_pass https:// (README, 'Forced HTTPS / HSTS').");
|
||||
throw new DavException(DavException.REDIRECT, L.f("Redirect loop (HTTP %d back to the same address). Nextcloud forces HTTPS but the bridge reaches it over plain HTTP: switch the bridge to proxy_pass https:// (README, 'Forced HTTPS / HSTS').", code));
|
||||
}
|
||||
}
|
||||
|
||||
List<Response> multistatus(String method, String target, String depth, String body) throws IOException {
|
||||
Http.Resp r = send(method, target, depth, body, null);
|
||||
if (r.code != 207) {
|
||||
throw new DavException(r.code, method + " " + URI.create(target).getPath() + " failed: HTTP " + r.code
|
||||
+ (r.code == 404 ? " (not found)" : r.code == 405 ? " (not a WebDAV URL?)" : ""));
|
||||
throw new DavException(r.code, L.f("%s %s failed: HTTP %d%s", method, URI.create(target).getPath(), r.code,
|
||||
r.code == 404 ? L.t(" (not found)") : r.code == 405 ? L.t(" (not a WebDAV URL?)") : ""));
|
||||
}
|
||||
Node ms = Xml.parse(r.body);
|
||||
List<Response> out = new ArrayList<Response>();
|
||||
@@ -206,7 +199,7 @@ public class Dav {
|
||||
}
|
||||
}
|
||||
if (principal == null) {
|
||||
throw last != null ? last : new DavException(0, "Server did not report a CalDAV principal");
|
||||
throw last != null ? last : new DavException(0, L.t("Server did not report a CalDAV principal"));
|
||||
}
|
||||
List<Response> rs = multistatus("PROPFIND", principal, "0", propfind("<c:calendar-home-set/>"));
|
||||
for (Response r : rs) {
|
||||
@@ -326,7 +319,7 @@ public class Dav {
|
||||
/** GET a single object. Returns {ics, etag}. */
|
||||
public String[] get(String href) throws IOException {
|
||||
Http.Resp r = send("GET", href, null, null, null);
|
||||
if (r.code != 200) throw new DavException(r.code, "Could not load event: HTTP " + r.code);
|
||||
if (r.code != 200) throw new DavException(r.code, L.f("Could not load event: HTTP %d", r.code));
|
||||
return new String[] {r.body, r.etag};
|
||||
}
|
||||
|
||||
@@ -334,25 +327,25 @@ public class Dav {
|
||||
String href = abs(calHref.endsWith("/") ? calHref : calHref + "/", uid + ".ics");
|
||||
Http.Resp r = send("PUT", href, null, ics, new String[] {"If-None-Match", "*"});
|
||||
if (r.code != 201 && r.code != 204 && r.code != 200) {
|
||||
throw new DavException(r.code, "Saving failed: HTTP " + r.code);
|
||||
throw new DavException(r.code, L.f("Saving failed: HTTP %d", r.code));
|
||||
}
|
||||
}
|
||||
|
||||
public void update(String href, String etag, String ics) throws IOException {
|
||||
String[] h = etag == null || etag.length() == 0 ? null : new String[] {"If-Match", etag};
|
||||
Http.Resp r = send("PUT", href, null, ics, h);
|
||||
if (r.code == 412) throw new DavException(412, "Event was changed on the server meanwhile. Sync and try again.");
|
||||
if (r.code == 412) throw new DavException(412, L.t("Event was changed on the server meanwhile. Sync and try again."));
|
||||
if (r.code != 201 && r.code != 204 && r.code != 200) {
|
||||
throw new DavException(r.code, "Saving failed: HTTP " + r.code);
|
||||
throw new DavException(r.code, L.f("Saving failed: HTTP %d", r.code));
|
||||
}
|
||||
}
|
||||
|
||||
public void delete(String href, String etag) throws IOException {
|
||||
String[] h = etag == null || etag.length() == 0 ? null : new String[] {"If-Match", etag};
|
||||
Http.Resp r = send("DELETE", href, null, null, h);
|
||||
if (r.code == 412) throw new DavException(412, "Event was changed on the server meanwhile. Sync and try again.");
|
||||
if (r.code == 412) throw new DavException(412, L.t("Event was changed on the server meanwhile. Sync and try again."));
|
||||
if (r.code != 204 && r.code != 200 && r.code != 404) {
|
||||
throw new DavException(r.code, "Delete failed: HTTP " + r.code);
|
||||
throw new DavException(r.code, L.f("Delete failed: HTTP %d", r.code));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@ public class DavException extends IOException {
|
||||
|
||||
public UntrustedCert(String fingerprint, String subject, String issuer, String expires,
|
||||
boolean pinMismatch) {
|
||||
super(pinMismatch ? "Server certificate changed (does not match the pinned fingerprint)"
|
||||
: "Server certificate is not trusted by this phone");
|
||||
super(pinMismatch ? L.t("Server certificate changed (does not match the pinned fingerprint)")
|
||||
: L.t("Server certificate is not trusted by this phone"));
|
||||
this.fingerprint = fingerprint;
|
||||
this.subject = subject;
|
||||
this.issuer = issuer;
|
||||
|
||||
@@ -296,6 +296,13 @@ public class ICal {
|
||||
return c.getTimeInMillis();
|
||||
}
|
||||
|
||||
/** Whether [start, end) covers part of the local day starting at `day`; zero-length counts at its start. */
|
||||
public static boolean onDay(long start, long end, long day) {
|
||||
long next = addDays(day, 1);
|
||||
if (end <= start) return start >= day && start < next;
|
||||
return start < next && end > day;
|
||||
}
|
||||
|
||||
public static long startOfDay(long t) {
|
||||
Calendar c = Calendar.getInstance();
|
||||
c.setTimeInMillis(t);
|
||||
|
||||
@@ -0,0 +1,231 @@
|
||||
package org.gingercal;
|
||||
|
||||
import java.text.DateFormatSymbols;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Interface language. English text is the key; Galician comes from the table below.
|
||||
* Android 2.3 ships no Galician locale data, so month and weekday names live here too.
|
||||
* tools/check_i18n.py checks that every L.t()/L.f() key has a translation with matching
|
||||
* placeholders.
|
||||
*/
|
||||
public final class L {
|
||||
private L() {}
|
||||
|
||||
/** Galician on (the app default); the desktop tests run in English. */
|
||||
public static volatile boolean gl;
|
||||
|
||||
private static final Map<String, String> GL = new HashMap<String, String>();
|
||||
|
||||
public static String t(String en) {
|
||||
if (!gl) return en;
|
||||
String v = GL.get(en);
|
||||
return v == null ? en : v;
|
||||
}
|
||||
|
||||
public static String f(String en, Object... args) {
|
||||
return String.format(Locale.US, t(en), args);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------ dates
|
||||
|
||||
static final String[] GL_MONTHS = {"xaneiro", "febreiro", "marzo", "abril", "maio", "xuño", "xullo",
|
||||
"agosto", "setembro", "outubro", "novembro", "decembro"};
|
||||
static final String[] GL_MONTHS_SHORT = {"xan", "feb", "mar", "abr", "mai", "xuñ", "xul", "ago", "set",
|
||||
"out", "nov", "dec"};
|
||||
static final String[] GL_DAYS = {"", "domingo", "luns", "martes", "mércores", "xoves", "venres", "sábado"};
|
||||
static final String[] GL_DAYS_SHORT = {"", "dom", "lun", "mar", "mér", "xov", "ven", "sáb"};
|
||||
|
||||
public static DateFormatSymbols symbols() {
|
||||
if (!gl) return new DateFormatSymbols(Locale.getDefault());
|
||||
DateFormatSymbols s = new DateFormatSymbols(Locale.US);
|
||||
s.setMonths(GL_MONTHS);
|
||||
s.setShortMonths(GL_MONTHS_SHORT);
|
||||
s.setWeekdays(GL_DAYS);
|
||||
s.setShortWeekdays(GL_DAYS_SHORT);
|
||||
s.setAmPmStrings(new String[] {"a.m.", "p.m."});
|
||||
return s;
|
||||
}
|
||||
|
||||
public static SimpleDateFormat df(String pattern) {
|
||||
return new SimpleDateFormat(pattern, symbols());
|
||||
}
|
||||
|
||||
/** "Outubro de 2026" / "October 2026". */
|
||||
public static String monthTitle(long t) {
|
||||
String s = df(gl ? "MMMM 'de' yyyy" : "MMMM yyyy").format(new Date(t));
|
||||
return s.length() > 0 ? Character.toUpperCase(s.charAt(0)) + s.substring(1) : s;
|
||||
}
|
||||
|
||||
public static int firstDayOfWeek() {
|
||||
return gl ? Calendar.MONDAY : Calendar.getInstance().getFirstDayOfWeek();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------ translations
|
||||
|
||||
private static void put(String en, String gal) {
|
||||
GL.put(en, gal);
|
||||
}
|
||||
|
||||
static {
|
||||
// main screen
|
||||
put("Not set up yet: press Menu > Settings.", "Aínda sen configurar: preme Menú > Configuración.");
|
||||
put("Syncing…", "Sincronizando…");
|
||||
put("Loading %s from the server…", "Cargando %s do servidor…");
|
||||
put("Couldn't load this month: %s", "Non se puido cargar este mes: %s");
|
||||
put("never", "nunca");
|
||||
put("Sync failed: %s\nLast good sync: %s", "Erro de sincronización: %s\nÚltima sincronización correcta: %s");
|
||||
put("Synced %s", "Sincronizado: %s");
|
||||
put("No upcoming events. Menu > New event, or Menu > Sync.", "Non hai eventos próximos. Menú > Novo evento ou Menú > Sincronizar.");
|
||||
put("Nothing on %s. Long-press a day to add an event.", "Non hai nada o %s. Mantén premido un día para engadir un evento.");
|
||||
put("View", "Vista");
|
||||
put("Agenda", "Axenda");
|
||||
put("Month", "Mes");
|
||||
put("New event", "Novo evento");
|
||||
put("Sync", "Sincronizar");
|
||||
put("Today", "Hoxe");
|
||||
put("Calendars", "Calendarios");
|
||||
put("Settings", "Configuración");
|
||||
put("Sync first: no writable calendar yet.", "Sincroniza primeiro: aínda non hai ningún calendario con permiso de escritura.");
|
||||
put("Calendar: %s", "Calendario: %s");
|
||||
put("Repeating event: edit the series in Nextcloud. Delete removes the whole series.", "Evento periódico: edita a serie en Nextcloud. Eliminar borra a serie completa.");
|
||||
put("(no title)", "(sen título)");
|
||||
put("(repeats)", "(repítese)");
|
||||
put("Close", "Pechar");
|
||||
put("Edit", "Editar");
|
||||
put("Delete", "Eliminar");
|
||||
put("Delete event?", "Eliminar o evento?");
|
||||
put("This deletes EVERY occurrence of \"%s\".", "Isto elimina TODAS as repeticións de «%s».");
|
||||
put("\"%s\" will be deleted on the server.", "«%s» eliminarase no servidor.");
|
||||
put("Cancel", "Cancelar");
|
||||
put("Deleting…", "Eliminando…");
|
||||
put("Delete failed", "Non se puido eliminar");
|
||||
put("OK", "Aceptar");
|
||||
|
||||
// dates and times
|
||||
put("Today · %s", "Hoxe · %s");
|
||||
put("Tomorrow · %s", "Mañá · %s");
|
||||
put("All day", "Todo o día");
|
||||
put("All day, until %s", "Todo o día, ata o %s");
|
||||
put("No reminder", "Sen aviso");
|
||||
put("At start time", "Á hora de comezo");
|
||||
put("%d min before", "%d min antes");
|
||||
put("%d h before", "%d h antes");
|
||||
put("%d day before", "%d día antes");
|
||||
|
||||
// event editor
|
||||
put("Edit event", "Editar evento");
|
||||
put("Title", "Título");
|
||||
put("Starts", "Comeza");
|
||||
put("Ends", "Remata");
|
||||
put("Location", "Lugar");
|
||||
put("Notes", "Notas");
|
||||
put("Save", "Gardar");
|
||||
put("Alarm: %s", "Aviso: %s");
|
||||
put("Alarm (saved in the event)", "Aviso (gárdase no evento)");
|
||||
put("Calendar", "Calendario");
|
||||
put("The end is before the start.", "O final é anterior ao comezo.");
|
||||
put("No writable calendar. Sync first.", "Non hai ningún calendario con permiso de escritura. Sincroniza primeiro.");
|
||||
put("Loading…", "Cargando…");
|
||||
put("Can't load event", "Non se puido cargar o evento");
|
||||
put("Repeating event", "Evento periódico");
|
||||
put("Repeating events can't be edited on the phone yet. Edit the series in Nextcloud.", "Os eventos periódicos aínda non se poden editar no teléfono. Edita a serie en Nextcloud.");
|
||||
put("Can't edit", "Non se pode editar");
|
||||
put("The server returned no event data.", "O servidor non devolveu os datos do evento.");
|
||||
put("Saving…", "Gardando…");
|
||||
put("Not saved", "Non se gardou");
|
||||
put("Saved", "Gardado");
|
||||
|
||||
// calendars
|
||||
put("No calendars yet. Set up the account in Settings and sync.", "Aínda non hai calendarios. Configura a conta en Configuración e sincroniza.");
|
||||
put("(read-only)", "(só lectura)");
|
||||
put("first writable", "o primeiro con escritura");
|
||||
put("New events go to: %s", "Os eventos novos gárdanse en: %s");
|
||||
put("Default calendar", "Calendario predeterminado");
|
||||
|
||||
// settings
|
||||
put("GingerCal settings", "Configuración de GingerCal");
|
||||
put("Nextcloud server. Android 2.3 can't speak TLS 1.2, so use either your legacy-TLS bridge (https://cloud.example.com:8443) or http:// to the server on your home Wi-Fi. Use an app password, not your real one.",
|
||||
"Servidor Nextcloud. Android 2.3 non admite TLS 1.2, así que usa a túa ponte TLS antiga (https://cloud.example.com:8443) ou http:// ao servidor na wifi da casa. Usa un contrasinal de aplicación, non o teu contrasinal real.");
|
||||
put("Server address", "Enderezo do servidor");
|
||||
put("User name", "Usuario");
|
||||
put("App password", "Contrasinal de aplicación");
|
||||
put("Pinned certificate SHA-256 (filled in for you)", "SHA-256 do certificado fixado (énchese automaticamente)");
|
||||
put("optional", "opcional");
|
||||
put("Days ahead to sync", "Días futuros que sincronizar");
|
||||
put("Save and test connection", "Gardar e probar a conexión");
|
||||
put("Re-download everything", "Descargar todo de novo");
|
||||
put("Background sync", "Sincronización automática");
|
||||
put("Background sync: %s", "Sincronización automática: %s");
|
||||
put("Manual only", "Só manual");
|
||||
put("Every hour", "Cada hora");
|
||||
put("Every %d hours", "Cada %d horas");
|
||||
put("Phone notification", "Notificación no teléfono");
|
||||
put("Notification: %s", "Notificación: %s");
|
||||
put("Off", "Desactivada");
|
||||
put("off", "desactivada");
|
||||
put("Language: %s", "Lingua: %s");
|
||||
put("Re-downloading in the background", "Descargando todo de novo en segundo plano");
|
||||
put("Server address and user name are required.", "O enderezo do servidor e o usuario son obrigatorios.");
|
||||
put("Unencrypted connection", "Conexión sen cifrar");
|
||||
put("http:// sends your password in clear text over the internet. Use the legacy-TLS bridge instead, or only use http:// to a LAN address.",
|
||||
"Con http:// o contrasinal viaxa sen cifrar por internet. Usa a ponte TLS antiga ou usa http:// só cun enderezo da rede local.");
|
||||
put("Use anyway", "Usar igualmente");
|
||||
put("Connecting…", "Conectando…");
|
||||
put("Connection failed", "Erro de conexión");
|
||||
put("Connected. Calendars found: %d\n", "Conectado. Calendarios atopados: %d\n");
|
||||
put("It works", "Funciona");
|
||||
put("Sync now", "Sincronizar agora");
|
||||
|
||||
// certificate trust
|
||||
put("WARNING: the server certificate changed since you trusted it. That happens when you regenerate the bridge certificate - or when someone is intercepting the connection.\n\n",
|
||||
"AVISO: o certificado do servidor cambiou desde que confiaches nel. Isto pasa se rexeneras o certificado da ponte, ou se alguén está a interceptar a conexión.\n\n");
|
||||
put("This phone doesn't trust the server certificate (normal for the self-signed legacy bridge, or for Let's Encrypt on Android 2.3).\n\n",
|
||||
"Este teléfono non confía no certificado do servidor (é normal coa ponte antiga autoasinada ou con Let's Encrypt en Android 2.3).\n\n");
|
||||
put("Subject: %s\nIssuer: %s\nExpires: %s\n\nSHA-256:\n%s\n\nOnly trust it if this matches the fingerprint printed on your server.",
|
||||
"Suxeito: %s\nEmisor: %s\nCaduca: %s\n\nSHA-256:\n%s\n\nConfía nel só se coincide coa pegada dixital que mostra o teu servidor.");
|
||||
put("Certificate changed!", "O certificado cambiou!");
|
||||
put("Trust this certificate?", "Confiar neste certificado?");
|
||||
put("Trust", "Confiar");
|
||||
put("Server certificate changed (does not match the pinned fingerprint)", "O certificado do servidor cambiou (non coincide coa pegada fixada)");
|
||||
put("Server certificate is not trusted by this phone", "Este teléfono non confía no certificado do servidor");
|
||||
|
||||
// errors
|
||||
put("Can't resolve %s. No connection, or a typo in the server address.", "Non se pode resolver %s. Non hai conexión ou hai un erro no enderezo do servidor.");
|
||||
put("Can't connect to the server (%s). Wrong port, or the bridge is down?", "Non se pode conectar co servidor (%s). Porto incorrecto ou ponte caída?");
|
||||
put("The server took too long to answer.", "O servidor tardou de máis en responder.");
|
||||
put("TLS error: %s", "Erro TLS: %s");
|
||||
put("Network error: %s", "Erro de rede: %s");
|
||||
put("Out of memory. Lower 'Days ahead' in Settings.", "Sen memoria. Reduce «Días futuros» na configuración.");
|
||||
put("Error: %s", "Erro: %s");
|
||||
put("Login refused (401). Check the user name and use a Nextcloud app password (Settings > Security > Devices & sessions).",
|
||||
"Acceso rexeitado (401). Comproba o usuario e usa un contrasinal de aplicación de Nextcloud (Configuración > Seguranza > Dispositivos e sesións).");
|
||||
put("Not allowed to write to this calendar (403). It may be read-only/shared.", "Non tes permiso para escribir neste calendario (403). Pode ser de só lectura ou compartido.");
|
||||
put("Too many redirects from the server.", "O servidor fixo demasiadas redireccións.");
|
||||
put("The server redirected http:// to %s (Nextcloud forces HTTPS / HSTS). Android 2.3 can't follow that: use the legacy-TLS bridge address instead (see README, 'Forced HTTPS / HSTS').",
|
||||
"O servidor redirixiu http:// a %s (Nextcloud obriga a usar HTTPS / HSTS). Android 2.3 non pode seguir esa redirección: usa o enderezo da ponte TLS antiga (consulta o README, «Forced HTTPS / HSTS»).");
|
||||
put("The server redirected to %s, not the address set in the app. Nextcloud is sending its public URL; check the bridge's proxy_redirect line (README, 'Forced HTTPS / HSTS').",
|
||||
"O servidor redirixiu a %s, que non é o enderezo configurado na aplicación. Nextcloud está a enviar o seu URL público; revisa a liña proxy_redirect da ponte (README, «Forced HTTPS / HSTS»).");
|
||||
put("Redirect loop (HTTP %d back to the same address). Nextcloud forces HTTPS but the bridge reaches it over plain HTTP: switch the bridge to proxy_pass https:// (README, 'Forced HTTPS / HSTS').",
|
||||
"Bucle de redirección (HTTP %d ao mesmo enderezo). Nextcloud obriga a usar HTTPS pero a ponte conecta con el por HTTP: cambia a ponte a proxy_pass https:// (README, «Forced HTTPS / HSTS»).");
|
||||
put("%s %s failed: HTTP %d%s", "%s %s fallou: HTTP %d%s");
|
||||
put(" (not found)", " (non atopado)");
|
||||
put(" (not a WebDAV URL?)", " (non é un URL WebDAV?)");
|
||||
put("Server did not report a CalDAV principal", "O servidor non informou de ningún principal CalDAV");
|
||||
put("Could not load event: HTTP %d", "Non se puido cargar o evento: HTTP %d");
|
||||
put("Saving failed: HTTP %d", "Non se puido gardar: HTTP %d");
|
||||
put("Event was changed on the server meanwhile. Sync and try again.", "O evento cambiou no servidor mentres tanto. Sincroniza e téntao de novo.");
|
||||
put("Delete failed: HTTP %d", "Non se puido eliminar: HTTP %d");
|
||||
put("TLS handshake failed before any certificate was sent. The server most likely requires TLS 1.2+, which Android 2.3 cannot do. Point the app at the legacy-TLS bridge (see README) or use http:// on your LAN. (%s)",
|
||||
"A negociación TLS fallou antes de recibir ningún certificado. Seguramente o servidor esixe TLS 1.2 ou superior, que Android 2.3 non admite. Configura a aplicación coa ponte TLS antiga (consulta o README) ou usa http:// na rede local. (%s)");
|
||||
put("Bad XML from server: %s", "XML incorrecto do servidor: %s");
|
||||
put("Empty XML from server", "XML baleiro do servidor");
|
||||
put("%d calendars: %d refreshed (%d events)", "Calendarios: %d, actualizados: %d (eventos: %d)");
|
||||
put(", %d unchanged", ", sen cambios: %d");
|
||||
}
|
||||
}
|
||||
@@ -16,10 +16,12 @@ public class Syncer {
|
||||
|
||||
public static class Result {
|
||||
public int calendars, fetched, skipped, events;
|
||||
/** The time window now cached locally. */
|
||||
public long from, to;
|
||||
|
||||
public String summary() {
|
||||
return calendars + " calendars: " + fetched + " refreshed (" + events + " events)"
|
||||
+ (skipped > 0 ? ", " + skipped + " unchanged" : "");
|
||||
return L.f("%d calendars: %d refreshed (%d events)", calendars, fetched, events)
|
||||
+ (skipped > 0 ? L.f(", %d unchanged", skipped) : "");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +34,8 @@ public class Syncer {
|
||||
Set<String> seen = new HashSet<String>();
|
||||
long from = ICal.addDays(ICal.startOfDay(now), -pastDays);
|
||||
long to = ICal.addDays(ICal.startOfDay(now), futureDays + 1);
|
||||
res.from = from;
|
||||
res.to = to;
|
||||
|
||||
for (Cal r : remote) {
|
||||
seen.add(r.href);
|
||||
|
||||
@@ -101,9 +101,7 @@ public final class Tls {
|
||||
return new DavException.UntrustedCert(seenFp, seenSubject, seenIssuer, seenExpiry, mismatch);
|
||||
}
|
||||
if (e instanceof SSLException && seenFp == null) {
|
||||
return new DavException(0, "TLS handshake failed before any certificate was sent. The server "
|
||||
+ "most likely requires TLS 1.2+, which Android 2.3 cannot do. Point the app at the "
|
||||
+ "legacy-TLS bridge (see README) or use http:// on your LAN. (" + e.getMessage() + ")");
|
||||
return new DavException(0, L.f("TLS handshake failed before any certificate was sent. The server most likely requires TLS 1.2+, which Android 2.3 cannot do. Point the app at the legacy-TLS bridge (see README) or use http:// on your LAN. (%s)", e.getMessage()));
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
@@ -106,9 +106,9 @@ public class Xml {
|
||||
} catch (IOException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new IOException("Bad XML from server: " + e.getMessage());
|
||||
throw new IOException(L.f("Bad XML from server: %s", e.getMessage()));
|
||||
}
|
||||
if (root.kids.isEmpty()) throw new IOException("Empty XML from server");
|
||||
if (root.kids.isEmpty()) throw new IOException(L.t("Empty XML from server"));
|
||||
return root.kids.get(0);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user