244 lines
9.7 KiB
Java
244 lines
9.7 KiB
Java
package org.gingercal;
|
|
|
|
import java.util.List;
|
|
|
|
import android.app.Activity;
|
|
import android.app.AlertDialog;
|
|
import android.app.ProgressDialog;
|
|
import android.content.DialogInterface;
|
|
import android.os.AsyncTask;
|
|
import android.os.Bundle;
|
|
import android.view.View;
|
|
import android.widget.Button;
|
|
import android.widget.EditText;
|
|
import android.widget.LinearLayout;
|
|
import android.widget.ScrollView;
|
|
import android.widget.TextView;
|
|
|
|
import org.gingercal.Model.Cal;
|
|
|
|
/** Account, TLS pin, sync interval and reminder settings. */
|
|
public class SettingsActivity extends Activity {
|
|
EditText url, user, pass, pin, ahead;
|
|
Button intervalBtn, remindBtn;
|
|
int interval, remind;
|
|
|
|
@Override
|
|
protected void onCreate(Bundle b) {
|
|
super.onCreate(b);
|
|
setTitle("GingerCal settings");
|
|
LinearLayout f = App.vbox(this);
|
|
int p = App.dp(this, 8);
|
|
f.setPadding(p, p, p, p);
|
|
f.addView(App.text(this, "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.", 12, 0xFFB0BEC5));
|
|
url = field(f, "Server address", "https://cloud.example.com:8443", 1 | 0x10 /* URI */);
|
|
user = field(f, "User name", "", 1 | 0x80000 /* no suggestions */);
|
|
pass = field(f, "App password", "", 1 | 0x80 /* password */);
|
|
pin = field(f, "Pinned certificate SHA-256 (filled in for you)", "optional", 1 | 0x80000);
|
|
ahead = field(f, "Days ahead to sync", "60", 2 /* number */);
|
|
intervalBtn = new Button(this);
|
|
f.addView(intervalBtn, new LinearLayout.LayoutParams(-1, -2));
|
|
remindBtn = new Button(this);
|
|
f.addView(remindBtn, new LinearLayout.LayoutParams(-1, -2));
|
|
Button test = new Button(this);
|
|
test.setText("Save and test connection");
|
|
f.addView(test, new LinearLayout.LayoutParams(-1, -2));
|
|
Button resync = new Button(this);
|
|
resync.setText("Re-download everything");
|
|
f.addView(resync, new LinearLayout.LayoutParams(-1, -2));
|
|
ScrollView sv = new ScrollView(this);
|
|
sv.addView(f);
|
|
setContentView(sv);
|
|
|
|
url.setText(App.get(this, "url"));
|
|
user.setText(App.get(this, "user"));
|
|
pass.setText(App.get(this, "pass"));
|
|
pin.setText(App.get(this, "pin"));
|
|
ahead.setText(String.valueOf(App.ahead(this)));
|
|
interval = App.interval(this);
|
|
remind = App.remind(this);
|
|
labels();
|
|
|
|
intervalBtn.setOnClickListener(new View.OnClickListener() {
|
|
public void onClick(View v) {
|
|
final String[] l = new String[App.INTERVALS.length];
|
|
for (int i = 0; i < l.length; i++) l[i] = intervalLabel(App.INTERVALS[i]);
|
|
new AlertDialog.Builder(SettingsActivity.this).setTitle("Background sync")
|
|
.setItems(l, new DialogInterface.OnClickListener() {
|
|
public void onClick(DialogInterface d, int w) {
|
|
interval = App.INTERVALS[w];
|
|
labels();
|
|
}
|
|
}).show();
|
|
}
|
|
});
|
|
remindBtn.setOnClickListener(new View.OnClickListener() {
|
|
public void onClick(View v) {
|
|
final int[] opts = {-1, 0, 5, 10, 15, 30, 60};
|
|
String[] l = new String[opts.length];
|
|
for (int i = 0; i < l.length; i++) l[i] = opts[i] < 0 ? "Off" : App.alarmLabel(opts[i]);
|
|
new AlertDialog.Builder(SettingsActivity.this).setTitle("Phone notification")
|
|
.setItems(l, new DialogInterface.OnClickListener() {
|
|
public void onClick(DialogInterface d, int w) {
|
|
remind = opts[w];
|
|
labels();
|
|
}
|
|
}).show();
|
|
}
|
|
});
|
|
test.setOnClickListener(new View.OnClickListener() {
|
|
public void onClick(View v) {
|
|
confirmAndTest();
|
|
}
|
|
});
|
|
resync.setOnClickListener(new View.OnClickListener() {
|
|
public void onClick(View v) {
|
|
save();
|
|
Db.get(SettingsActivity.this).forgetSyncState();
|
|
App.requestSync(SettingsActivity.this, true, true);
|
|
App.toast(SettingsActivity.this, "Re-downloading in the background");
|
|
finish();
|
|
}
|
|
});
|
|
}
|
|
|
|
EditText field(LinearLayout f, String label, String hint, int type) {
|
|
TextView l = App.text(this, label, 13, 0xFFFFFFFF);
|
|
l.setPadding(App.dp(this, 4), App.dp(this, 8), 0, 0);
|
|
f.addView(l);
|
|
EditText e = new EditText(this);
|
|
e.setHint(hint);
|
|
e.setSingleLine(true);
|
|
e.setInputType(type);
|
|
f.addView(e, new LinearLayout.LayoutParams(-1, -2));
|
|
return e;
|
|
}
|
|
|
|
static String intervalLabel(int h) {
|
|
return h == 0 ? "Manual only" : h == 1 ? "Every hour" : "Every " + h + " hours";
|
|
}
|
|
|
|
void labels() {
|
|
intervalBtn.setText("Background sync: " + intervalLabel(interval));
|
|
remindBtn.setText("Notify: " + (remind < 0 ? "off" : App.alarmLabel(remind)));
|
|
}
|
|
|
|
static String txt(TextView t) {
|
|
return t.getText().toString().trim();
|
|
}
|
|
|
|
@Override
|
|
protected void onPause() {
|
|
super.onPause();
|
|
if (txt(url).length() > 0) save();
|
|
}
|
|
|
|
void save() {
|
|
String oldAccount = App.get(this, "url") + "|" + App.get(this, "user");
|
|
int days = 60;
|
|
try {
|
|
days = Math.max(7, Math.min(365, Integer.parseInt(txt(ahead))));
|
|
} catch (NumberFormatException ignored) {
|
|
}
|
|
String u = txt(url);
|
|
if (u.length() > 0) u = Dav.normalize(u);
|
|
App.prefs(this).edit()
|
|
.putString("url", u)
|
|
.putString("user", txt(user))
|
|
.putString("pass", pass.getText().toString())
|
|
.putString("pin", Tls.normPin(txt(pin)).length() == 64 ? txt(pin) : "")
|
|
.putInt("ahead", days)
|
|
.putInt("interval", interval)
|
|
.putInt("remind", remind)
|
|
.commit();
|
|
if (!oldAccount.equals(u + "|" + txt(user))) {
|
|
Db.get(this).clearAll();
|
|
App.prefs(this).edit().putLong("lastsync", 0).putString("status", "").commit();
|
|
}
|
|
App.scheduleSync(this);
|
|
Reminders.schedule(this);
|
|
}
|
|
|
|
void confirmAndTest() {
|
|
String u = txt(url);
|
|
if (u.length() == 0 || txt(user).length() == 0) {
|
|
App.toast(this, "Server address and user name are required.");
|
|
return;
|
|
}
|
|
if (Dav.normalize(u).startsWith("http://") && !App.isLan(u)) {
|
|
new AlertDialog.Builder(this).setTitle("Unencrypted connection")
|
|
.setMessage("http:// sends your password in clear text over the internet. Use the legacy-TLS "
|
|
+ "bridge instead, or only use http:// to a LAN address.")
|
|
.setPositiveButton("Use anyway", new DialogInterface.OnClickListener() {
|
|
public void onClick(DialogInterface d, int w) {
|
|
save();
|
|
new TestTask().execute();
|
|
}
|
|
})
|
|
.setNegativeButton("Cancel", null).show();
|
|
return;
|
|
}
|
|
save();
|
|
new TestTask().execute();
|
|
}
|
|
|
|
class TestTask extends AsyncTask<Void, Void, Object> {
|
|
ProgressDialog pd;
|
|
|
|
@Override
|
|
protected void onPreExecute() {
|
|
pd = ProgressDialog.show(SettingsActivity.this, null, "Connecting…");
|
|
}
|
|
|
|
@Override
|
|
protected Object doInBackground(Void... v) {
|
|
Dav d = null;
|
|
try {
|
|
d = App.dav(SettingsActivity.this);
|
|
return d.calendars(d.calendarHome());
|
|
} catch (Throwable t) {
|
|
return t;
|
|
} finally {
|
|
if (d != null) d.close();
|
|
}
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
@Override
|
|
protected void onPostExecute(Object r) {
|
|
try {
|
|
pd.dismiss();
|
|
} catch (RuntimeException ignored) {
|
|
}
|
|
if (r instanceof DavException.UntrustedCert) {
|
|
App.askTrust(SettingsActivity.this, (DavException.UntrustedCert) r, new App.Trusted() {
|
|
public void trusted(String fp) {
|
|
pin.setText(fp);
|
|
save();
|
|
new TestTask().execute();
|
|
}
|
|
});
|
|
return;
|
|
}
|
|
if (r instanceof Throwable) {
|
|
new AlertDialog.Builder(SettingsActivity.this).setTitle("Connection failed")
|
|
.setMessage(App.describe((Throwable) r)).setPositiveButton("OK", null).show();
|
|
return;
|
|
}
|
|
List<Cal> cals = (List<Cal>) r;
|
|
StringBuilder s = new StringBuilder("Connected. Found " + cals.size() + " calendar(s):\n");
|
|
for (Cal c : cals) s.append("\n• ").append(c.name).append(c.writable ? "" : " (read-only)");
|
|
new AlertDialog.Builder(SettingsActivity.this).setTitle("It works")
|
|
.setMessage(s.toString())
|
|
.setPositiveButton("Sync now", new DialogInterface.OnClickListener() {
|
|
public void onClick(DialogInterface d, int w) {
|
|
App.requestSync(SettingsActivity.this, true, false);
|
|
finish();
|
|
}
|
|
}).show();
|
|
}
|
|
}
|
|
}
|