Fixes and improvements

- Last loaders/executors have been gone
- Improved debug info
- Fixed multiple draft saves
pull/50/head
M66B 6 years ago
parent 4a43ebaafc
commit d9875de010

@ -2,7 +2,7 @@
"formatVersion": 1, "formatVersion": 1,
"database": { "database": {
"version": 1, "version": 1,
"identityHash": "7814b856d44afe54b8912106df1e673b", "identityHash": "262ca4c3e0dbf6673b00b8b19fc219de",
"entities": [ "entities": [
{ {
"tableName": "identity", "tableName": "identity",
@ -660,7 +660,7 @@
}, },
{ {
"tableName": "operation", "tableName": "operation",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `folder` INTEGER NOT NULL, `message` INTEGER NOT NULL, `name` TEXT NOT NULL, `args` TEXT NOT NULL, `error` TEXT, FOREIGN KEY(`folder`) REFERENCES `folder`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`message`) REFERENCES `message`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `folder` INTEGER NOT NULL, `message` INTEGER NOT NULL, `name` TEXT NOT NULL, `args` TEXT NOT NULL, `created` INTEGER NOT NULL, FOREIGN KEY(`folder`) REFERENCES `folder`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`message`) REFERENCES `message`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [ "fields": [
{ {
"fieldPath": "id", "fieldPath": "id",
@ -693,10 +693,10 @@
"notNull": true "notNull": true
}, },
{ {
"fieldPath": "error", "fieldPath": "created",
"columnName": "error", "columnName": "created",
"affinity": "TEXT", "affinity": "INTEGER",
"notNull": false "notNull": true
} }
], ],
"primaryKey": { "primaryKey": {
@ -751,7 +751,7 @@
], ],
"setupQueries": [ "setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"7814b856d44afe54b8912106df1e673b\")" "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"262ca4c3e0dbf6673b00b8b19fc219de\")"
] ]
} }
} }

@ -24,6 +24,7 @@ import android.content.Intent;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@ -40,18 +41,17 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.core.content.FileProvider; import androidx.core.content.FileProvider;
import androidx.lifecycle.LifecycleOwner;
import androidx.recyclerview.widget.DiffUtil; import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.ListUpdateCallback; import androidx.recyclerview.widget.ListUpdateCallback;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
public class AdapterAttachment extends RecyclerView.Adapter<AdapterAttachment.ViewHolder> { public class AdapterAttachment extends RecyclerView.Adapter<AdapterAttachment.ViewHolder> {
private Context context; private Context context;
private ExecutorService executor = Executors.newCachedThreadPool(); private LifecycleOwner owner;
private List<TupleAttachment> all = new ArrayList<>(); private List<TupleAttachment> all = new ArrayList<>();
private List<TupleAttachment> filtered = new ArrayList<>(); private List<TupleAttachment> filtered = new ArrayList<>();
@ -140,58 +140,84 @@ public class AdapterAttachment extends RecyclerView.Adapter<AdapterAttachment.Vi
return; return;
} }
Bundle args = new Bundle();
args.putLong("id", attachment.id);
args.putSerializable("file", file);
args.putSerializable("dir", dir);
// View // View
executor.submit(new Runnable() { new SimpleTask<Void>() {
@Override @Override
public void run() { protected Void onLoad(Context context, Bundle args) throws Throwable {
try { long id = args.getLong("id");
// Create file File file = (File) args.getSerializable("file");
if (!file.exists()) { File dir = (File) args.getSerializable("dir");
dir.mkdir();
file.createNewFile(); // Create file
if (!file.exists()) {
// Get attachment content dir.mkdir();
byte[] content = DB.getInstance(context).attachment().getContent(attachment.id); file.createNewFile();
// Write attachment content to file // Get attachment content
FileOutputStream fos = null; byte[] content = DB.getInstance(context).attachment().getContent(id);
try {
fos = new FileOutputStream(file); // Write attachment content to file
fos.write(content); FileOutputStream fos = null;
} finally { try {
if (fos != null) fos = new FileOutputStream(file);
fos.close(); fos.write(content);
} } finally {
if (fos != null)
fos.close();
} }
// Start viewer
context.startActivity(intent);
} catch (Throwable ex) {
Log.i(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex));
} }
return null;
} }
});
@Override
protected void onLoaded(Bundle args, Void data) {
context.startActivity(intent);
}
@Override
protected void onException(Bundle args, Throwable ex) {
Toast.makeText(context, ex.toString(), Toast.LENGTH_LONG).show();
}
}.load(context, owner, args);
} else { } else {
if (attachment.progress == null) if (attachment.progress == null) {
// Download Bundle args = new Bundle();
executor.submit(new Runnable() { args.putLong("id", attachment.id);
args.putLong("message", attachment.message);
args.putInt("sequence", attachment.sequence);
new SimpleTask<Void>() {
@Override @Override
public void run() { protected Void onLoad(Context context, Bundle args) {
long id = args.getLong("id");
long message = args.getLong("message");
long sequence = args.getInt("sequence");
// No need for a transaction // No need for a transaction
DB db = DB.getInstance(context); DB db = DB.getInstance(context);
db.attachment().setProgress(attachment.id, 0); db.attachment().setProgress(id, 0);
EntityMessage message = db.message().getMessage(attachment.message); EntityMessage msg = db.message().getMessage(message);
EntityOperation.queue(db, message, EntityOperation.ATTACHMENT, attachment.sequence); EntityOperation.queue(db, msg, EntityOperation.ATTACHMENT, sequence);
EntityOperation.process(context); EntityOperation.process(context);
return null;
} }
}); }.load(context, owner, args);
}
} }
} }
} }
AdapterAttachment(Context context) { AdapterAttachment(Context context, LifecycleOwner owner) {
this.context = context; this.context = context;
this.owner = owner;
setHasStableIds(true); setHasStableIds(true);
} }

@ -31,7 +31,14 @@ import android.widget.ImageView;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.Observer;
import androidx.localbroadcastmanager.content.LocalBroadcastManager; import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import androidx.paging.PagedListAdapter; import androidx.paging.PagedListAdapter;
import androidx.recyclerview.widget.DiffUtil; import androidx.recyclerview.widget.DiffUtil;
@ -39,8 +46,11 @@ import androidx.recyclerview.widget.RecyclerView;
public class AdapterMessage extends PagedListAdapter<TupleMessageEx, AdapterMessage.ViewHolder> { public class AdapterMessage extends PagedListAdapter<TupleMessageEx, AdapterMessage.ViewHolder> {
private Context context; private Context context;
private LifecycleOwner owner;
private ViewType viewType; private ViewType viewType;
private boolean debug; private boolean debug;
private DateFormat df = SimpleDateFormat.getDateTimeInstance(SimpleDateFormat.SHORT, SimpleDateFormat.LONG);
enum ViewType {FOLDER, THREAD} enum ViewType {FOLDER, THREAD}
@ -87,7 +97,7 @@ public class AdapterMessage extends PagedListAdapter<TupleMessageEx, AdapterMess
pbLoading.setVisibility(View.VISIBLE); pbLoading.setVisibility(View.VISIBLE);
} }
private void bindTo(TupleMessageEx message) { private void bindTo(final TupleMessageEx message) {
pbLoading.setVisibility(View.GONE); pbLoading.setVisibility(View.GONE);
if (EntityFolder.DRAFTS.equals(message.folderType) || if (EntityFolder.DRAFTS.equals(message.folderType) ||
@ -111,8 +121,25 @@ public class AdapterMessage extends PagedListAdapter<TupleMessageEx, AdapterMess
tvCount.setVisibility(View.VISIBLE); tvCount.setVisibility(View.VISIBLE);
} }
if (debug) if (debug) {
message.error += (message.ui_hide ? " HIDDEN " : " ") + message.msgid + "/" + message.uid + "/" + message.id; DB db = DB.getInstance(context);
db.operation().getOperationsByMessage(message.id).removeObservers(owner);
db.operation().getOperationsByMessage(message.id).observe(owner, new Observer<List<EntityOperation>>() {
@Override
public void onChanged(List<EntityOperation> operations) {
String text = message.error +
"\n" + message.id + " " + df.format(new Date(message.received)) +
"\n" + (message.ui_hide ? "HIDDEN " : " ") + message.uid + "/" + message.id +
"\n" + message.msgid;
for (EntityOperation op : operations)
text += "\n" + op.name + " " + df.format(new Date(op.created));
tvError.setText(text);
tvError.setVisibility(View.VISIBLE);
}
});
}
tvError.setText(message.error); tvError.setText(message.error);
tvError.setVisibility(message.error == null ? View.GONE : View.VISIBLE); tvError.setVisibility(message.error == null ? View.GONE : View.VISIBLE);
@ -165,9 +192,10 @@ public class AdapterMessage extends PagedListAdapter<TupleMessageEx, AdapterMess
} }
} }
AdapterMessage(Context context, ViewType viewType) { AdapterMessage(Context context, LifecycleOwner owner, ViewType viewType) {
super(DIFF_CALLBACK); super(DIFF_CALLBACK);
this.context = context; this.context = context;
this.owner = owner;
this.viewType = viewType; this.viewType = viewType;
this.debug = PreferenceManager.getDefaultSharedPreferences(context).getBoolean("debug", false); this.debug = PreferenceManager.getDefaultSharedPreferences(context).getBoolean("debug", false);
} }

@ -98,6 +98,7 @@ public interface DaoMessage {
@Query("SELECT uid FROM message WHERE folder = :folder AND received >= :received AND NOT uid IS NULL") @Query("SELECT uid FROM message WHERE folder = :folder AND received >= :received AND NOT uid IS NULL")
List<Long> getUids(long folder, long received); List<Long> getUids(long folder, long received);
// in case of duplicate message IDs
@Insert(onConflict = OnConflictStrategy.REPLACE) @Insert(onConflict = OnConflictStrategy.REPLACE)
long insertMessage(EntityMessage message); long insertMessage(EntityMessage message);

@ -21,15 +21,18 @@ package eu.faircode.email;
import java.util.List; import java.util.List;
import androidx.lifecycle.LiveData;
import androidx.room.Dao; import androidx.room.Dao;
import androidx.room.Insert; import androidx.room.Insert;
import androidx.room.Query; import androidx.room.Query;
import androidx.room.Update;
@Dao @Dao
public interface DaoOperation { public interface DaoOperation {
@Query("SELECT * FROM operation WHERE message = :message ORDER BY id")
LiveData<List<EntityOperation>> getOperationsByMessage(long message);
@Query("SELECT * FROM operation WHERE folder = :folder ORDER BY id") @Query("SELECT * FROM operation WHERE folder = :folder ORDER BY id")
List<EntityOperation> getOperations(long folder); List<EntityOperation> getOperationsByFolder(long folder);
@Query("SELECT COUNT(id) FROM operation WHERE folder = :folder") @Query("SELECT COUNT(id) FROM operation WHERE folder = :folder")
int getOperationCount(long folder); int getOperationCount(long folder);
@ -37,9 +40,6 @@ public interface DaoOperation {
@Insert @Insert
long insertOperation(EntityOperation operation); long insertOperation(EntityOperation operation);
@Update
void updateOperation(EntityOperation operation);
@Query("DELETE FROM operation WHERE id = :id") @Query("DELETE FROM operation WHERE id = :id")
void deleteOperation(long id); void deleteOperation(long id);
} }

@ -26,6 +26,7 @@ import android.util.Log;
import org.json.JSONArray; import org.json.JSONArray;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date;
import java.util.List; import java.util.List;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@ -61,7 +62,8 @@ public class EntityOperation {
public String name; public String name;
@NonNull @NonNull
public String args; public String args;
public String error; @NonNull
public Long created;
public static final String SEEN = "seen"; public static final String SEEN = "seen";
public static final String ADD = "add"; public static final String ADD = "add";
@ -96,6 +98,7 @@ public class EntityOperation {
operation.message = message.id; operation.message = message.id;
operation.name = name; operation.name = name;
operation.args = jsonArray.toString(); operation.args = jsonArray.toString();
operation.created = new Date().getTime();
operation.id = db.operation().insertOperation(operation); operation.id = db.operation().insertOperation(operation);
Intent intent = new Intent(); Intent intent = new Intent();
@ -129,8 +132,7 @@ public class EntityOperation {
return (this.folder.equals(other.folder) && return (this.folder.equals(other.folder) &&
this.message.equals(other.message) && this.message.equals(other.message) &&
this.name.equals(other.name) && this.name.equals(other.name) &&
this.args.equals(other.args) && this.args.equals(other.args));
(this.error == null ? other.error == null : this.error.equals(other.error)));
} else } else
return false; return false;
} }

@ -239,7 +239,7 @@ public class FragmentCompose extends FragmentEx {
LinearLayoutManager llm = new LinearLayoutManager(getContext()); LinearLayoutManager llm = new LinearLayoutManager(getContext());
rvAttachment.setLayoutManager(llm); rvAttachment.setLayoutManager(llm);
adapter = new AdapterAttachment(getContext()); adapter = new AdapterAttachment(getContext(), getViewLifecycleOwner());
rvAttachment.setAdapter(adapter); rvAttachment.setAdapter(adapter);
return view; return view;
@ -757,36 +757,40 @@ public class FragmentCompose extends FragmentEx {
EntityOperation.queue(db, draft, EntityOperation.MOVE, trash.id); EntityOperation.queue(db, draft, EntityOperation.MOVE, trash.id);
} else if (action == R.id.action_save) { } else if (action == R.id.action_save) {
// Save message ID if (draft.uid == null)
String msgid = draft.msgid; db.message().updateMessage(draft);
else {
// Save attachments // Save message ID
List<EntityAttachment> attachments = db.attachment().getAttachments(draft.id); String msgid = draft.msgid;
for (EntityAttachment attachment : attachments)
attachment.content = db.attachment().getContent(attachment.id); // Save attachments
List<EntityAttachment> attachments = db.attachment().getAttachments(draft.id);
// Delete previous draft for (EntityAttachment attachment : attachments)
draft.msgid = null; attachment.content = db.attachment().getContent(attachment.id);
draft.ui_hide = true;
db.message().updateMessage(draft); // Delete previous draft
draft.msgid = null;
EntityOperation.queue(db, draft, EntityOperation.DELETE); draft.ui_hide = true;
db.message().updateMessage(draft);
// Create new draft
draft.id = null; EntityOperation.queue(db, draft, EntityOperation.DELETE);
draft.uid = null;
draft.msgid = msgid; // Create new draft
draft.ui_hide = false; draft.id = null;
draft.id = db.message().insertMessage(draft); draft.uid = null;
draft.msgid = msgid;
draft.ui_hide = false;
draft.id = db.message().insertMessage(draft);
// Restore attachments
for (EntityAttachment attachment : attachments) {
attachment.message = draft.id;
db.attachment().insertAttachment(attachment);
}
// Restore attachments EntityOperation.queue(db, draft, EntityOperation.ADD);
for (EntityAttachment attachment : attachments) {
attachment.message = draft.id;
db.attachment().insertAttachment(attachment);
} }
EntityOperation.queue(db, draft, EntityOperation.ADD);
} else if (action == R.id.action_send) { } else if (action == R.id.action_send) {
// Check data // Check data
if (draft.identity == null) if (draft.identity == null)

@ -66,7 +66,6 @@ import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
public class FragmentMessage extends FragmentEx { public class FragmentMessage extends FragmentEx {
private boolean debug;
private TextView tvFrom; private TextView tvFrom;
private TextView tvTime; private TextView tvTime;
private TextView tvSubject; private TextView tvSubject;
@ -86,6 +85,7 @@ public class FragmentMessage extends FragmentEx {
private AdapterAttachment adapter; private AdapterAttachment adapter;
private boolean debug;
private DateFormat df = SimpleDateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT); private DateFormat df = SimpleDateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
@Override @Override
@ -93,11 +93,10 @@ public class FragmentMessage extends FragmentEx {
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_message, container, false); View view = inflater.inflate(R.layout.fragment_message, container, false);
this.debug = PreferenceManager.getDefaultSharedPreferences(getContext()).getBoolean("debug", false);
// Get arguments // Get arguments
Bundle args = getArguments(); Bundle args = getArguments();
final long id = (args == null ? -1 : args.getLong("id")); final long id = (args == null ? -1 : args.getLong("id"));
debug = PreferenceManager.getDefaultSharedPreferences(getContext()).getBoolean("debug", false);
// Get controls // Get controls
tvFrom = view.findViewById(R.id.tvFrom); tvFrom = view.findViewById(R.id.tvFrom);
@ -226,7 +225,7 @@ public class FragmentMessage extends FragmentEx {
LinearLayoutManager llm = new LinearLayoutManager(getContext()); LinearLayoutManager llm = new LinearLayoutManager(getContext());
rvAttachment.setLayoutManager(llm); rvAttachment.setLayoutManager(llm);
adapter = new AdapterAttachment(getContext()); adapter = new AdapterAttachment(getContext(), getViewLifecycleOwner());
rvAttachment.setAdapter(adapter); rvAttachment.setAdapter(adapter);
return view; return view;
@ -246,21 +245,19 @@ public class FragmentMessage extends FragmentEx {
db.message().liveMessage(id).observe(getViewLifecycleOwner(), new Observer<TupleMessageEx>() { db.message().liveMessage(id).observe(getViewLifecycleOwner(), new Observer<TupleMessageEx>() {
@Override @Override
public void onChanged(@Nullable final TupleMessageEx message) { public void onChanged(@Nullable final TupleMessageEx message) {
if (message == null || message.ui_hide) { if (message == null || (!(debug && BuildConfig.DEBUG) && message.ui_hide)) {
// Message gone (moved, deleted) // Message gone (moved, deleted)
if (FragmentMessage.this.isVisible()) if (FragmentMessage.this.isVisible())
getFragmentManager().popBackStack(); getFragmentManager().popBackStack();
} else { } else {
setSubtitle(Helper.localizeFolderName(getContext(), message.folderName)); setSubtitle(Helper.localizeFolderName(getContext(), message.folderName));
String extra = (debug ? (message.ui_hide ? "HIDDEN " : "") + message.uid + "/" + message.id + " " : "");
tvFrom.setText(message.from == null ? null : MessageHelper.getFormattedAddresses(message.from, true)); tvFrom.setText(message.from == null ? null : MessageHelper.getFormattedAddresses(message.from, true));
tvTime.setText(message.sent == null ? null : df.format(new Date(message.sent))); tvTime.setText(message.sent == null ? null : df.format(new Date(message.sent)));
tvSubject.setText(message.subject); tvSubject.setText(message.subject);
tvCount.setText(extra + Integer.toString(message.count)); tvCount.setText(Integer.toString(message.count));
tvCount.setVisibility(debug || message.count > 1 ? View.VISIBLE : View.GONE); tvCount.setVisibility(message.count > 1 ? View.VISIBLE : View.GONE);
tvTo.setText(message.to == null ? null : MessageHelper.getFormattedAddresses(message.to, true)); tvTo.setText(message.to == null ? null : MessageHelper.getFormattedAddresses(message.to, true));
tvCc.setText(message.cc == null ? null : MessageHelper.getFormattedAddresses(message.cc, true)); tvCc.setText(message.cc == null ? null : MessageHelper.getFormattedAddresses(message.cc, true));
@ -287,9 +284,6 @@ public class FragmentMessage extends FragmentEx {
} }
}); });
if (debug)
message.error += (message.ui_hide ? " HIDDEN " : " ") + message.msgid + "/" + message.uid + "/" + message.id;
tvError.setText(message.error); tvError.setText(message.error);
tvError.setVisibility(message.error == null ? View.GONE : View.VISIBLE); tvError.setVisibility(message.error == null ? View.GONE : View.VISIBLE);
@ -629,12 +623,16 @@ public class FragmentMessage extends FragmentEx {
try { try {
db.beginTransaction(); db.beginTransaction();
EntityMessage message = db.message().getMessage(id); if (debug && BuildConfig.DEBUG)
message.ui_hide = true; db.message().deleteMessage(id);
db.message().updateMessage(message); else {
EntityMessage message = db.message().getMessage(id);
message.ui_hide = true;
db.message().updateMessage(message);
EntityFolder trash = db.folder().getFolderByType(message.account, EntityFolder.TRASH); EntityFolder trash = db.folder().getFolderByType(message.account, EntityFolder.TRASH);
EntityOperation.queue(db, message, EntityOperation.MOVE, trash.id); EntityOperation.queue(db, message, EntityOperation.MOVE, trash.id);
}
db.setTransactionSuccessful(); db.setTransactionSuccessful();
} finally { } finally {

@ -76,7 +76,9 @@ public class FragmentMessages extends FragmentEx {
LinearLayoutManager llm = new LinearLayoutManager(getContext()); LinearLayoutManager llm = new LinearLayoutManager(getContext());
rvMessage.setLayoutManager(llm); rvMessage.setLayoutManager(llm);
adapter = new AdapterMessage(getContext(), adapter = new AdapterMessage(
getContext(),
getViewLifecycleOwner(),
thread < 0 thread < 0
? AdapterMessage.ViewType.FOLDER ? AdapterMessage.ViewType.FOLDER
: AdapterMessage.ViewType.THREAD); : AdapterMessage.ViewType.THREAD);

@ -710,7 +710,7 @@ public class ServiceSynchronize extends LifecycleService {
Log.i(Helper.TAG, folder.name + " start process"); Log.i(Helper.TAG, folder.name + " start process");
DB db = DB.getInstance(this); DB db = DB.getInstance(this);
List<EntityOperation> ops = db.operation().getOperations(folder.id); List<EntityOperation> ops = db.operation().getOperationsByFolder(folder.id);
Log.i(Helper.TAG, folder.name + " pending operations=" + ops.size()); Log.i(Helper.TAG, folder.name + " pending operations=" + ops.size());
for (EntityOperation op : ops) for (EntityOperation op : ops)
try { try {
@ -719,11 +719,12 @@ public class ServiceSynchronize extends LifecycleService {
" msg=" + op.message + " msg=" + op.message +
" args=" + op.args); " args=" + op.args);
EntityMessage message = db.message().getMessage(op.message);
if (message == null)
throw new MessageRemovedException();
try { try {
JSONArray jargs = new JSONArray(op.args); JSONArray jargs = new JSONArray(op.args);
EntityMessage message = db.message().getMessage(op.message);
if (message == null)
throw new MessageRemovedException();
if (EntityOperation.SEEN.equals(op.name)) if (EntityOperation.SEEN.equals(op.name))
doSeen(folder, ifolder, message, jargs); doSeen(folder, ifolder, message, jargs);
@ -735,7 +736,7 @@ public class ServiceSynchronize extends LifecycleService {
doMove(folder, isession, istore, ifolder, message, jargs, db); doMove(folder, isession, istore, ifolder, message, jargs, db);
else if (EntityOperation.DELETE.equals(op.name)) else if (EntityOperation.DELETE.equals(op.name))
doDelete(folder, ifolder, message, db); doDelete(folder, ifolder, message, jargs, db);
else if (EntityOperation.SEND.equals(op.name)) else if (EntityOperation.SEND.equals(op.name))
doSend(db, message); doSend(db, message);
@ -749,8 +750,8 @@ public class ServiceSynchronize extends LifecycleService {
// Operation succeeded // Operation succeeded
db.operation().deleteOperation(op.id); db.operation().deleteOperation(op.id);
} catch (Throwable ex) { } catch (Throwable ex) {
op.error = Helper.formatThrowable(ex); message.error = Helper.formatThrowable(ex);
db.operation().updateOperation(op); db.message().updateMessage(message);
if (BuildConfig.DEBUG && ex instanceof NullPointerException) { if (BuildConfig.DEBUG && ex instanceof NullPointerException) {
db.operation().deleteOperation(op.id); db.operation().deleteOperation(op.id);
@ -786,9 +787,8 @@ public class ServiceSynchronize extends LifecycleService {
private void doSeen(EntityFolder folder, IMAPFolder ifolder, EntityMessage message, JSONArray jargs) throws MessagingException, JSONException { private void doSeen(EntityFolder folder, IMAPFolder ifolder, EntityMessage message, JSONArray jargs) throws MessagingException, JSONException {
// Mark message (un)seen // Mark message (un)seen
if (message.uid == null) { if (message.uid == null) {
Log.w(Helper.TAG, folder.name + " local op seen id=" + message.id + " uid=" + message.uid); Log.w(Helper.TAG, folder.name + " local op seen id=" + message.id);
return; return;
} }
@ -814,12 +814,8 @@ public class ServiceSynchronize extends LifecycleService {
private void doMove(EntityFolder folder, Session isession, IMAPStore istore, IMAPFolder ifolder, EntityMessage message, JSONArray jargs, DB db) throws JSONException, MessagingException { private void doMove(EntityFolder folder, Session isession, IMAPStore istore, IMAPFolder ifolder, EntityMessage message, JSONArray jargs, DB db) throws JSONException, MessagingException {
// Move message // Move message
if (message.uid == null)
if (BuildConfig.DEBUG && message.uid == null) { throw new IllegalArgumentException("MOVE local id=" + message.id);
Log.w(Helper.TAG, "Move local message id=" + message.id);
db.message().deleteMessage(message.id);
return;
}
long id = jargs.getLong(0); long id = jargs.getLong(0);
EntityFolder target = db.folder().getFolder(id); EntityFolder target = db.folder().getFolder(id);
@ -850,18 +846,17 @@ public class ServiceSynchronize extends LifecycleService {
} }
} }
private void doDelete(EntityFolder folder, IMAPFolder ifolder, EntityMessage message, DB db) throws MessagingException { private void doDelete(EntityFolder folder, IMAPFolder ifolder, EntityMessage message, JSONArray jargs, DB db) throws MessagingException, JSONException {
// Delete message // Delete message
if (message.uid == null) if (message.uid == null)
Log.w(Helper.TAG, folder.name + " Delete local message id=" + message.id); throw new IllegalArgumentException("DELETE local id=" + message.id);
else {
Message imessage = ifolder.getMessageByUID(message.uid);
if (imessage == null)
throw new MessageRemovedException();
imessage.setFlag(Flags.Flag.DELETED, true); Message imessage = ifolder.getMessageByUID(message.uid);
ifolder.expunge(); if (imessage == null)
} throw new MessageRemovedException();
imessage.setFlag(Flags.Flag.DELETED, true);
ifolder.expunge();
db.message().deleteMessage(message.id); db.message().deleteMessage(message.id);
} }

@ -39,6 +39,10 @@ import androidx.lifecycle.OnLifecycleEvent;
public abstract class SimpleTask<T> implements LifecycleObserver { public abstract class SimpleTask<T> implements LifecycleObserver {
private boolean alive = true; private boolean alive = true;
public void load(Context context, LifecycleOwner owner, Bundle args) {
run(context, owner, args);
}
public void load(AppCompatActivity activity, Bundle args) { public void load(AppCompatActivity activity, Bundle args) {
run(activity, activity, args); run(activity, activity, args);
} }

@ -71,7 +71,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="6dp" android:layout_marginEnd="6dp"
android:layout_marginStart="6dp" android:layout_marginStart="6dp"
android:text="error" android:text="error\ndebug info\noperation 1\n operation 2"
android:textAppearance="@style/TextAppearance.AppCompat.Small" android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textStyle="bold" android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"

Loading…
Cancel
Save