Added option connect via unmetered only

pull/207/head
M66B 3 years ago
parent 0a92b677b2
commit 7fa99dc0a7

File diff suppressed because it is too large Load Diff

@ -71,7 +71,7 @@ import io.requery.android.database.sqlite.SQLiteDatabase;
// https://developer.android.com/topic/libraries/architecture/room.html // https://developer.android.com/topic/libraries/architecture/room.html
@Database( @Database(
version = 232, version = 233,
entities = { entities = {
EntityIdentity.class, EntityIdentity.class,
EntityAccount.class, EntityAccount.class,
@ -2318,6 +2318,12 @@ public abstract class DB extends RoomDatabase {
logMigration(startVersion, endVersion); logMigration(startVersion, endVersion);
db.execSQL("ALTER TABLE `contact` ADD COLUMN 'identity' INTEGER"); db.execSQL("ALTER TABLE `contact` ADD COLUMN 'identity' INTEGER");
} }
}).addMigrations(new Migration(232, 233) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase db) {
logMigration(startVersion, endVersion);
db.execSQL("ALTER TABLE `account` ADD COLUMN 'conditions' TEXT");
}
}).addMigrations(new Migration(998, 999) { }).addMigrations(new Migration(998, 999) {
@Override @Override
public void migrate(@NonNull SupportSQLiteDatabase db) { public void migrate(@NonNull SupportSQLiteDatabase db) {

@ -143,6 +143,8 @@ public class EntityAccount extends EntityOrder implements Serializable {
public Boolean use_received = false; // Received header public Boolean use_received = false; // Received header
public String prefix; // namespace, obsolete public String prefix; // namespace, obsolete
public String conditions;
public Long quota_usage; public Long quota_usage;
public Long quota_limit; public Long quota_limit;
@ -295,6 +297,7 @@ public class EntityAccount extends EntityOrder implements Serializable {
json.put("ignore_size", ignore_size); json.put("ignore_size", ignore_size);
json.put("use_date", use_date); json.put("use_date", use_date);
json.put("use_received", use_received); json.put("use_received", use_received);
json.put("conditions", conditions);
// not prefix // not prefix
// not created // not created
// not tbd // not tbd
@ -383,6 +386,7 @@ public class EntityAccount extends EntityOrder implements Serializable {
account.ignore_size = json.optBoolean("ignore_size", false); account.ignore_size = json.optBoolean("ignore_size", false);
account.use_date = json.optBoolean("use_date", false); account.use_date = json.optBoolean("use_date", false);
account.use_received = json.optBoolean("use_received", false); account.use_received = json.optBoolean("use_received", false);
account.conditions = json.optString("conditions");
return account; return account;
} }
@ -420,6 +424,7 @@ public class EntityAccount extends EntityOrder implements Serializable {
this.ignore_size == other.ignore_size && this.ignore_size == other.ignore_size &&
this.use_date == other.use_date && this.use_date == other.use_date &&
this.use_received == other.use_received && this.use_received == other.use_received &&
Objects.equals(this.conditions, other.conditions) &&
Objects.equals(this.quota_usage, other.quota_usage) && Objects.equals(this.quota_usage, other.quota_usage) &&
Objects.equals(this.quota_limit, other.quota_limit) && Objects.equals(this.quota_limit, other.quota_limit) &&
Objects.equals(this.created, other.created) && Objects.equals(this.created, other.created) &&

@ -68,6 +68,8 @@ import com.google.android.material.snackbar.Snackbar;
import com.google.android.material.textfield.TextInputLayout; import com.google.android.material.textfield.TextInputLayout;
import com.sun.mail.imap.IMAPFolder; import com.sun.mail.imap.IMAPFolder;
import org.json.JSONObject;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
@ -121,6 +123,7 @@ public class FragmentAccount extends FragmentBase {
private CheckBox cbPartialFetch; private CheckBox cbPartialFetch;
private CheckBox cbIgnoreSize; private CheckBox cbIgnoreSize;
private RadioGroup rgDate; private RadioGroup rgDate;
private CheckBox cbUnmetered;
private Button btnCheck; private Button btnCheck;
private ContentLoadingProgressBar pbCheck; private ContentLoadingProgressBar pbCheck;
@ -228,6 +231,7 @@ public class FragmentAccount extends FragmentBase {
cbPartialFetch = view.findViewById(R.id.cbPartialFetch); cbPartialFetch = view.findViewById(R.id.cbPartialFetch);
cbIgnoreSize = view.findViewById(R.id.cbIgnoreSize); cbIgnoreSize = view.findViewById(R.id.cbIgnoreSize);
rgDate = view.findViewById(R.id.rgDate); rgDate = view.findViewById(R.id.rgDate);
cbUnmetered = view.findViewById(R.id.cbUnmeteredOnly);
btnCheck = view.findViewById(R.id.btnCheck); btnCheck = view.findViewById(R.id.btnCheck);
pbCheck = view.findViewById(R.id.pbCheck); pbCheck = view.findViewById(R.id.pbCheck);
@ -881,6 +885,7 @@ public class FragmentAccount extends FragmentBase {
args.putBoolean("ignore_size", cbIgnoreSize.isChecked()); args.putBoolean("ignore_size", cbIgnoreSize.isChecked());
args.putBoolean("use_date", rgDate.getCheckedRadioButtonId() == R.id.radio_date_header); args.putBoolean("use_date", rgDate.getCheckedRadioButtonId() == R.id.radio_date_header);
args.putBoolean("use_received", rgDate.getCheckedRadioButtonId() == R.id.radio_received_header); args.putBoolean("use_received", rgDate.getCheckedRadioButtonId() == R.id.radio_received_header);
args.putBoolean("unmetered", cbUnmetered.isChecked());
args.putSerializable("drafts", drafts); args.putSerializable("drafts", drafts);
args.putSerializable("sent", sent); args.putSerializable("sent", sent);
@ -950,6 +955,7 @@ public class FragmentAccount extends FragmentBase {
boolean ignore_size = args.getBoolean("ignore_size"); boolean ignore_size = args.getBoolean("ignore_size");
boolean use_date = args.getBoolean("use_date"); boolean use_date = args.getBoolean("use_date");
boolean use_received = args.getBoolean("use_received"); boolean use_received = args.getBoolean("use_received");
boolean unmetered = args.getBoolean("unmetered");
EntityFolder drafts = (EntityFolder) args.getSerializable("drafts"); EntityFolder drafts = (EntityFolder) args.getSerializable("drafts");
EntityFolder sent = (EntityFolder) args.getSerializable("sent"); EntityFolder sent = (EntityFolder) args.getSerializable("sent");
@ -994,6 +1000,14 @@ public class FragmentAccount extends FragmentBase {
DB db = DB.getInstance(context); DB db = DB.getInstance(context);
EntityAccount account = db.account().getAccount(id); EntityAccount account = db.account().getAccount(id);
JSONObject jconditions = new JSONObject();
if (account != null && account.conditions != null)
try {
jconditions = new JSONObject(account.conditions);
} catch (Throwable ex) {
Log.e(ex);
}
if (should) { if (should) {
if (account == null) if (account == null)
return !TextUtils.isEmpty(host) && !TextUtils.isEmpty(user); return !TextUtils.isEmpty(host) && !TextUtils.isEmpty(user);
@ -1046,6 +1060,8 @@ public class FragmentAccount extends FragmentBase {
return true; return true;
if (!Objects.equals(account.use_received, use_received)) if (!Objects.equals(account.use_received, use_received))
return true; return true;
if (unmetered != jconditions.optBoolean("unmetered"))
return true;
if (account.error != null && account.synchronize) if (account.error != null && account.synchronize)
return true; return true;
@ -1184,6 +1200,9 @@ public class FragmentAccount extends FragmentBase {
account.use_date = use_date; account.use_date = use_date;
account.use_received = use_received; account.use_received = use_received;
jconditions.put("unmetered", unmetered);
account.conditions = jconditions.toString();
if (!update) if (!update)
account.created = now; account.created = now;
@ -1530,6 +1549,15 @@ public class FragmentAccount extends FragmentBase {
cbPartialFetch.setChecked(account == null ? true : account.partial_fetch); cbPartialFetch.setChecked(account == null ? true : account.partial_fetch);
cbIgnoreSize.setChecked(account == null ? false : account.ignore_size); cbIgnoreSize.setChecked(account == null ? false : account.ignore_size);
JSONObject jcondition = new JSONObject();
try {
if (account != null && account.conditions != null)
jcondition = new JSONObject(account.conditions);
} catch (Throwable ex) {
Log.e(ex);
}
cbUnmetered.setChecked(jcondition.optBoolean("unmetered"));
if (account != null && account.use_date) if (account != null && account.use_date)
rgDate.check(R.id.radio_date_header); rgDate.check(R.id.radio_date_header);
else if (account != null && account.use_received) else if (account != null && account.use_received)

@ -60,6 +60,8 @@ import androidx.lifecycle.Lifecycle;
import com.google.android.material.snackbar.Snackbar; import com.google.android.material.snackbar.Snackbar;
import com.google.android.material.textfield.TextInputLayout; import com.google.android.material.textfield.TextInputLayout;
import org.json.JSONObject;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@ -94,6 +96,7 @@ public class FragmentPop extends FragmentBase {
private CheckBox cbLeaveDevice; private CheckBox cbLeaveDevice;
private EditText etMax; private EditText etMax;
private EditText etInterval; private EditText etInterval;
private CheckBox cbUnmetered;
private ArrayAdapter<EntityFolder> adapterSwipe; private ArrayAdapter<EntityFolder> adapterSwipe;
private Spinner spLeft; private Spinner spLeft;
@ -159,6 +162,7 @@ public class FragmentPop extends FragmentBase {
cbLeaveDevice = view.findViewById(R.id.cbLeaveDevice); cbLeaveDevice = view.findViewById(R.id.cbLeaveDevice);
etMax = view.findViewById(R.id.etMax); etMax = view.findViewById(R.id.etMax);
etInterval = view.findViewById(R.id.etInterval); etInterval = view.findViewById(R.id.etInterval);
cbUnmetered = view.findViewById(R.id.cbUnmeteredOnly);
spLeft = view.findViewById(R.id.spLeft); spLeft = view.findViewById(R.id.spLeft);
spRight = view.findViewById(R.id.spRight); spRight = view.findViewById(R.id.spRight);
@ -323,6 +327,7 @@ public class FragmentPop extends FragmentBase {
args.putBoolean("leave_device", cbLeaveDevice.isChecked()); args.putBoolean("leave_device", cbLeaveDevice.isChecked());
args.putString("max", etMax.getText().toString()); args.putString("max", etMax.getText().toString());
args.putString("interval", etInterval.getText().toString()); args.putString("interval", etInterval.getText().toString());
args.putBoolean("unmetered", cbUnmetered.isChecked());
args.putLong("left", ((EntityFolder) spLeft.getSelectedItem()).id); args.putLong("left", ((EntityFolder) spLeft.getSelectedItem()).id);
args.putLong("right", ((EntityFolder) spRight.getSelectedItem()).id); args.putLong("right", ((EntityFolder) spRight.getSelectedItem()).id);
@ -373,6 +378,7 @@ public class FragmentPop extends FragmentBase {
boolean leave_device = args.getBoolean("leave_device"); boolean leave_device = args.getBoolean("leave_device");
String max = args.getString("max"); String max = args.getString("max");
String interval = args.getString("interval"); String interval = args.getString("interval");
boolean unmetered = args.getBoolean("unmetered");
long left = args.getLong("left"); long left = args.getLong("left");
long right = args.getLong("right"); long right = args.getLong("right");
@ -411,6 +417,14 @@ public class FragmentPop extends FragmentBase {
DB db = DB.getInstance(context); DB db = DB.getInstance(context);
EntityAccount account = db.account().getAccount(id); EntityAccount account = db.account().getAccount(id);
JSONObject jconditions = new JSONObject();
if (account != null && account.conditions != null)
try {
jconditions = new JSONObject(account.conditions);
} catch (Throwable ex) {
Log.e(ex);
}
if (should) { if (should) {
if (account == null) if (account == null)
return !TextUtils.isEmpty(host) && !TextUtils.isEmpty(user); return !TextUtils.isEmpty(host) && !TextUtils.isEmpty(user);
@ -453,6 +467,8 @@ public class FragmentPop extends FragmentBase {
return true; return true;
if (!Objects.equals(account.poll_interval, poll_interval)) if (!Objects.equals(account.poll_interval, poll_interval))
return true; return true;
if (unmetered != jconditions.optBoolean("unmetered"))
return true;
if (!Objects.equals(account.swipe_left, left)) if (!Objects.equals(account.swipe_left, left))
return true; return true;
@ -530,6 +546,9 @@ public class FragmentPop extends FragmentBase {
account.max_messages = max_messages; account.max_messages = max_messages;
account.poll_interval = poll_interval; account.poll_interval = poll_interval;
jconditions.put("unmetered", unmetered);
account.conditions = jconditions.toString();
account.swipe_left = left; account.swipe_left = left;
account.swipe_right = right; account.swipe_right = right;
@ -713,6 +732,16 @@ public class FragmentPop extends FragmentBase {
? EntityAccount.DEFAULT_MAX_MESSAGES : account.max_messages)); ? EntityAccount.DEFAULT_MAX_MESSAGES : account.max_messages));
etInterval.setText(account == null ? "" : Long.toString(account.poll_interval)); etInterval.setText(account == null ? "" : Long.toString(account.poll_interval));
JSONObject jcondition = new JSONObject();
try {
if (account != null && account.conditions != null)
jcondition = new JSONObject(account.conditions);
} catch (Throwable ex) {
Log.e(ex);
}
cbUnmetered.setChecked(jcondition.optBoolean("unmetered"));
cbIdentity.setChecked(account == null); cbIdentity.setChecked(account == null);
List<EntityFolder> folders = getSwipeActions(); List<EntityFolder> folders = getSwipeActions();

@ -24,6 +24,8 @@ import android.os.Bundle;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import org.json.JSONObject;
public class TupleAccountNetworkState { public class TupleAccountNetworkState {
public boolean enabled; public boolean enabled;
@NonNull @NonNull
@ -33,6 +35,8 @@ public class TupleAccountNetworkState {
@NonNull @NonNull
public TupleAccountState accountState; public TupleAccountState accountState;
private JSONObject jconditions;
public TupleAccountNetworkState( public TupleAccountNetworkState(
boolean enabled, boolean enabled,
@NonNull Bundle command, @NonNull Bundle command,
@ -42,9 +46,21 @@ public class TupleAccountNetworkState {
this.command = command; this.command = command;
this.networkState = networkState; this.networkState = networkState;
this.accountState = accountState; this.accountState = accountState;
this.jconditions = new JSONObject();
if (this.accountState.conditions != null)
try {
jconditions = new JSONObject(this.accountState.conditions);
} catch (Throwable ex) {
Log.e(ex);
}
} }
public boolean canRun() { public boolean canRun() {
boolean unmetered = jconditions.optBoolean("unmetered");
if (unmetered && !this.networkState.isUnmetered())
return false;
return (this.networkState.isSuitable() && this.accountState.shouldRun(enabled)); return (this.networkState.isSuitable() && this.accountState.shouldRun(enabled));
} }

@ -50,6 +50,7 @@ public class TupleAccountState extends EntityAccount {
this.ignore_size.equals(other.ignore_size) && this.ignore_size.equals(other.ignore_size) &&
this.use_date.equals(other.use_date) && this.use_date.equals(other.use_date) &&
this.use_received.equals(other.use_received) && this.use_received.equals(other.use_received) &&
Objects.equals(this.conditions, other.conditions) &&
this.folders == other.folders && this.folders == other.folders &&
Objects.equals(this.tbd, other.tbd)); Objects.equals(this.tbd, other.tbd));
} else } else

@ -653,6 +653,15 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/rgDate" /> app:layout_constraintTop_toBottomOf="@id/rgDate" />
<CheckBox
android:id="@+id/cbUnmeteredOnly"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/title_unmetered_only"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvDateRemark" />
<!-- check --> <!-- check -->
<Button <Button
@ -665,7 +674,7 @@
android:tag="disable" android:tag="disable"
android:text="@string/title_check" android:text="@string/title_check"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvDateRemark" /> app:layout_constraintTop_toBottomOf="@id/cbUnmeteredOnly" />
<eu.faircode.email.ContentLoadingProgressBar <eu.faircode.email.ContentLoadingProgressBar
android:id="@+id/pbCheck" android:id="@+id/pbCheck"
@ -1052,7 +1061,8 @@
cbBrowse,tvBrowseHint, cbBrowse,tvBrowseHint,
cbAutoSeen, cbAutoSeen,
tvInterval,etInterval,tvIntervalRemark, tvInterval,etInterval,tvIntervalRemark,
cbPartialFetch,tvPartialFetchRemark,cbIgnoreSize,rgDate,tvDateRemark" /> cbPartialFetch,tvPartialFetchRemark,cbIgnoreSize,rgDate,tvDateRemark,
cbUnmeteredOnly" />
<androidx.constraintlayout.widget.Group <androidx.constraintlayout.widget.Group
android:id="@+id/grpFolders" android:id="@+id/grpFolders"

@ -464,6 +464,15 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/etInterval" /> app:layout_constraintTop_toBottomOf="@id/etInterval" />
<CheckBox
android:id="@+id/cbUnmeteredOnly"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/title_unmetered_only"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvIntervalRemark" />
<eu.faircode.email.FixedTextView <eu.faircode.email.FixedTextView
android:id="@+id/tvLeft" android:id="@+id/tvLeft"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -472,7 +481,7 @@
android:text="@string/title_account_left" android:text="@string/title_account_left"
android:textAppearance="@style/TextAppearance.AppCompat.Small" android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tvIntervalRemark" /> app:layout_constraintTop_toBottomOf="@+id/cbUnmeteredOnly" />
<Spinner <Spinner
android:id="@+id/spLeft" android:id="@+id/spLeft"

@ -950,6 +950,7 @@
<string name="title_received_header">Use \'Received\' header</string> <string name="title_received_header">Use \'Received\' header</string>
<string name="title_date_header">Use \'Date\' header (sent time)</string> <string name="title_date_header">Use \'Date\' header (sent time)</string>
<string name="title_date_remark">Changes will be applied to new messages only</string> <string name="title_date_remark">Changes will be applied to new messages only</string>
<string name="title_unmetered_only">Connect only via unmetered networks</string>
<string name="title_related_identity">Add related identity (SMTP server)</string> <string name="title_related_identity">Add related identity (SMTP server)</string>
<string name="title_check">Check</string> <string name="title_check">Check</string>
<string name="title_trust">Trust server certificate with fingerprint %1$s</string> <string name="title_trust">Trust server certificate with fingerprint %1$s</string>

Loading…
Cancel
Save