Fine grained operations delete

pull/187/head
M66B 5 years ago
parent 963a35800b
commit 59564ed14a

@ -489,7 +489,7 @@ class Core {
db.beginTransaction(); db.beginTransaction();
// Cleanup operation // Cleanup operation
op.cleanup(context); op.cleanup(context, true);
// There is no use in repeating // There is no use in repeating
db.operation().deleteOperation(op.id); db.operation().deleteOperation(op.id);

@ -441,7 +441,7 @@ public class EntityOperation {
Log.i("Queued subscribe=" + subscribe + " folder=" + folder); Log.i("Queued subscribe=" + subscribe + " folder=" + folder);
} }
void cleanup(Context context) { void cleanup(Context context, boolean fetch) {
DB db = DB.getInstance(context); DB db = DB.getInstance(context);
if (message != null) if (message != null)
@ -473,7 +473,7 @@ public class EntityOperation {
if (EntityOperation.SYNC.equals(name)) if (EntityOperation.SYNC.equals(name))
db.folder().setFolderSyncState(folder, null); db.folder().setFolderSyncState(folder, null);
if (message != null) { if (fetch && message != null) {
EntityMessage m = db.message().getMessage(message); EntityMessage m = db.message().getMessage(message);
if (m == null || m.uid == null) if (m == null || m.uid == null)
return; return;

@ -29,6 +29,7 @@ import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@ -130,23 +131,80 @@ public class FragmentOperations extends FragmentBase {
@NonNull @NonNull
@Override @Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
final View dview = LayoutInflater.from(getContext()).inflate(R.layout.dialog_delete_operations, null);
final CheckBox cbError = dview.findViewById(R.id.cbError);
final CheckBox cbFetch = dview.findViewById(R.id.cbFetch);
final CheckBox cbMove = dview.findViewById(R.id.cbMove);
final CheckBox cbFlag = dview.findViewById(R.id.cbFlag);
final CheckBox cbDelete = dview.findViewById(R.id.cbDelete);
return new AlertDialog.Builder(getContext()) return new AlertDialog.Builder(getContext())
.setMessage(R.string.title_delete_operation) .setView(dview)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
Bundle args = new Bundle();
args.putBoolean("error", cbError.isChecked());
args.putBoolean("fetch", cbFetch.isChecked());
args.putBoolean("move", cbMove.isChecked());
args.putBoolean("flag", cbFlag.isChecked());
args.putBoolean("delete", cbDelete.isChecked());
new SimpleTask<Void>() { new SimpleTask<Void>() {
@Override @Override
protected Void onExecute(Context context, Bundle args) { protected Void onExecute(Context context, Bundle args) {
boolean error = args.getBoolean("error");
boolean fetch = args.getBoolean("fetch");
boolean move = args.getBoolean("move");
boolean flag = args.getBoolean("flag");
boolean delete = args.getBoolean("delete");
DB db = DB.getInstance(context); DB db = DB.getInstance(context);
List<EntityOperation> ops = db.operation().getOperationsError(); try {
Log.i("Operations with error count=" + ops.size()); db.beginTransaction();
for (EntityOperation op : ops) {
Log.w("Deleting operation=" + op.id + " error=" + op.error); List<EntityOperation> ops = new ArrayList<>();
if (op.message != null)
db.message().setMessageUiHide(op.message, false); if (error)
db.operation().deleteOperation(op.id); addAll(ops, db.operation().getOperationsError());
if (fetch) {
addAll(ops, db.operation().getOperations(EntityOperation.FETCH));
addAll(ops, db.operation().getOperations(EntityOperation.BODY));
addAll(ops, db.operation().getOperations(EntityOperation.ATTACHMENT));
addAll(ops, db.operation().getOperations(EntityOperation.HEADERS));
addAll(ops, db.operation().getOperations(EntityOperation.SYNC));
}
if (move) {
addAll(ops, db.operation().getOperations(EntityOperation.MOVE));
addAll(ops, db.operation().getOperations(EntityOperation.COPY));
}
if (flag) {
addAll(ops, db.operation().getOperations(EntityOperation.SEEN));
addAll(ops, db.operation().getOperations(EntityOperation.ANSWERED));
addAll(ops, db.operation().getOperations(EntityOperation.FLAG));
addAll(ops, db.operation().getOperations(EntityOperation.KEYWORD));
addAll(ops, db.operation().getOperations(EntityOperation.LABEL));
}
if (delete) {
addAll(ops, db.operation().getOperations(EntityOperation.DELETE));
addAll(ops, db.operation().getOperations(EntityOperation.PURGE));
}
for (EntityOperation op : ops) {
EntityLog.log(context, "Deleting operation=" + op.id + ":" + op.name + " error=" + op.error);
if (db.operation().deleteOperation(op.id) > 0)
op.cleanup(context, false);
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
} }
return null; return null;
} }
@ -154,6 +212,11 @@ public class FragmentOperations extends FragmentBase {
protected void onException(Bundle args, Throwable ex) { protected void onException(Bundle args, Throwable ex) {
Log.unexpectedError(getParentFragmentManager(), ex); Log.unexpectedError(getParentFragmentManager(), ex);
} }
private void addAll(List<EntityOperation> list, List<EntityOperation> sublist) {
if (sublist != null)
list.addAll(sublist);
}
}.execute(getContext(), getActivity(), new Bundle(), "operations:delete"); }.execute(getContext(), getActivity(), new Bundle(), "operations:delete");
} }
}) })

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="24dp">
<eu.faircode.email.FixedTextView
android:id="@+id/tvAddImage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/title_delete_operation_title"
android:textAppearance="@style/TextAppearance.AppCompat.Large"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<CheckBox
android:id="@+id/cbError"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:checked="true"
android:text="@string/title_delete_operation_error"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvAddImage" />
<CheckBox
android:id="@+id/cbFetch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/title_delete_operation_fetch"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/cbError" />
<CheckBox
android:id="@+id/cbMove"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/title_delete_operation_move"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/cbFetch" />
<CheckBox
android:id="@+id/cbFlag"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/title_delete_operation_flag"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/cbMove" />
<CheckBox
android:id="@+id/cbDelete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/title_delete_operation_delete"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/cbFlag" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -737,7 +737,12 @@
<string name="title_empty_trash_all_ask">Delete all trashed messages of all accounts permanently?</string> <string name="title_empty_trash_all_ask">Delete all trashed messages of all accounts permanently?</string>
<string name="title_empty_spam_all_ask">Delete all spam messages of all accounts permanently?</string> <string name="title_empty_spam_all_ask">Delete all spam messages of all accounts permanently?</string>
<string name="title_empty_all">This will delete all messages both from the device and the server</string> <string name="title_empty_all">This will delete all messages both from the device and the server</string>
<string name="title_delete_operation">Delete operations with an error message?</string> <string name="title_delete_operation_title">Delete operations</string>
<string name="title_delete_operation_error">With an error message</string>
<string name="title_delete_operation_fetch">Fetch operations</string>
<string name="title_delete_operation_move">Move operations</string>
<string name="title_delete_operation_flag">Flag operations</string>
<string name="title_delete_operation_delete">Delete operations</string>
<string name="title_delete_contacts">Delete all local contacts?</string> <string name="title_delete_contacts">Delete all local contacts?</string>
<string name="title_no_operations">No pending operations</string> <string name="title_no_operations">No pending operations</string>
<string name="title_hint_operations">Deleting operations can result in disappearing messages and synchronization problems</string> <string name="title_hint_operations">Deleting operations can result in disappearing messages and synchronization problems</string>

Loading…
Cancel
Save