Allow subscribing to folders

This commit is contained in:
M66B 2019-04-25 18:47:52 +02:00
parent ffb64cd8ba
commit d38027eabe
7 changed files with 79 additions and 5 deletions

1
FAQ.md
View File

@ -223,6 +223,7 @@ The low priority status bar notification shows the number of pending operations,
* *body*: download message text * *body*: download message text
* *attachment*: download attachment * *attachment*: download attachment
* *sync*: synchronize local and remote messages * *sync*: synchronize local and remote messages
* *subscribe*: subscribe to remote folder
Operations are processed only when there is a connection to the email server or when manually synchronizing. Operations are processed only when there is a connection to the email server or when manually synchronizing.
See also [this FAQ](#user-content-faq16). See also [this FAQ](#user-content-faq16).

View File

@ -132,7 +132,9 @@ class Core {
JSONArray jargs = new JSONArray(op.args); JSONArray jargs = new JSONArray(op.args);
try { try {
if (message == null && !EntityOperation.SYNC.equals(op.name)) if (message == null &&
!EntityOperation.SYNC.equals(op.name) &&
!EntityOperation.SUBSCRIBE.equals(op.name))
throw new MessageRemovedException(); throw new MessageRemovedException();
db.operation().setOperationError(op.id, null); db.operation().setOperationError(op.id, null);
@ -144,7 +146,7 @@ class Core {
EntityOperation.DELETE.equals(op.name) || EntityOperation.DELETE.equals(op.name) ||
EntityOperation.SEND.equals(op.name) || EntityOperation.SEND.equals(op.name) ||
EntityOperation.SYNC.equals(op.name) || EntityOperation.SYNC.equals(op.name) ||
EntityOperation.WAIT.equals(op.name))) EntityOperation.SUBSCRIBE.equals(op.name)))
throw new IllegalArgumentException(op.name + " without uid " + op.args); throw new IllegalArgumentException(op.name + " without uid " + op.args);
// Operations should use database transaction when needed // Operations should use database transaction when needed
@ -217,7 +219,8 @@ class Core {
onSynchronizeMessages(context, jargs, account, folder, (IMAPFolder) ifolder, state); onSynchronizeMessages(context, jargs, account, folder, (IMAPFolder) ifolder, state);
break; break;
case EntityOperation.WAIT: case EntityOperation.SUBSCRIBE:
onSubscribeFolder(context, jargs, folder, (IMAPFolder) ifolder);
break; break;
default: default:
@ -792,6 +795,17 @@ class Core {
} }
} }
private static void onSubscribeFolder(Context context, JSONArray jargs, EntityFolder folder, IMAPFolder ifolder)
throws JSONException, MessagingException {
boolean subscribe = jargs.getBoolean(0);
ifolder.setSubscribed(subscribe);
DB db = DB.getInstance(context);
db.folder().setFolderSubscribed(folder.id, subscribe);
Log.i(folder.name + " subscribed=" + subscribe);
}
private static void onSynchronizeMessages( private static void onSynchronizeMessages(
Context context, JSONArray jargs, Context context, JSONArray jargs,
EntityAccount account, final EntityFolder folder, EntityAccount account, final EntityFolder folder,

View File

@ -553,7 +553,7 @@ public abstract class DB extends RoomDatabase {
@Override @Override
public void migrate(SupportSQLiteDatabase db) { public void migrate(SupportSQLiteDatabase db) {
Log.i("DB migration from version " + startVersion + " to " + endVersion); Log.i("DB migration from version " + startVersion + " to " + endVersion);
db.execSQL("DELETE FROM operation WHERE name = '" + EntityOperation.WAIT + "'"); db.execSQL("DELETE FROM operation WHERE name = 'wait'");
} }
}) })
.addMigrations(new Migration(51, 52) { .addMigrations(new Migration(51, 52) {

View File

@ -83,7 +83,7 @@ public class EntityOperation {
static final String BODY = "body"; static final String BODY = "body";
static final String ATTACHMENT = "attachment"; static final String ATTACHMENT = "attachment";
static final String SYNC = "sync"; static final String SYNC = "sync";
static final String WAIT = "wait"; static final String SUBSCRIBE = "subscribe";
static void queue(Context context, DB db, EntityMessage message, String name, Object... values) { static void queue(Context context, DB db, EntityMessage message, String name, Object... values) {
JSONArray jargs = new JSONArray(); JSONArray jargs = new JSONArray();
@ -256,6 +256,26 @@ public class EntityOperation {
ServiceSynchronize.process(context); ServiceSynchronize.process(context);
} }
static void subscribe(Context context, long fid, boolean subscribe) {
DB db = DB.getInstance(context);
EntityFolder folder = db.folder().getFolder(fid);
JSONArray jargs = new JSONArray();
jargs.put(subscribe);
EntityOperation operation = new EntityOperation();
operation.account = folder.account;
operation.folder = folder.id;
operation.message = null;
operation.name = SUBSCRIBE;
operation.args = jargs.toString();
operation.created = new Date().getTime();
operation.id = db.operation().insertOperation(operation);
Log.i("Queued subscribe=" + subscribe + " folder=" + folder);
}
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (obj instanceof EntityOperation) { if (obj instanceof EntityOperation) {

View File

@ -61,6 +61,7 @@ public class FragmentFolder extends FragmentBase {
private long id = -1; private long id = -1;
private long account = -1; private long account = -1;
private Boolean subscribed = null;
private boolean saving = false; private boolean saving = false;
private boolean deletable = false; private boolean deletable = false;
@ -289,6 +290,8 @@ public class FragmentFolder extends FragmentBase {
@Override @Override
public void onPrepareOptionsMenu(Menu menu) { public void onPrepareOptionsMenu(Menu menu) {
menu.findItem(R.id.menu_subscribe).setChecked(subscribed != null && subscribed);
menu.findItem(R.id.menu_subscribe).setVisible(id > 0 && subscribed != null);
menu.findItem(R.id.menu_delete).setVisible(id > 0 && !saving && deletable); menu.findItem(R.id.menu_delete).setVisible(id > 0 && !saving && deletable);
super.onPrepareOptionsMenu(menu); super.onPrepareOptionsMenu(menu);
} }
@ -296,6 +299,11 @@ public class FragmentFolder extends FragmentBase {
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.menu_subscribe:
subscribed = !item.isChecked();
item.setChecked(subscribed);
onMenuSubscribe();
return true;
case R.id.menu_delete: case R.id.menu_delete:
onMenuDelete(); onMenuDelete();
return true; return true;
@ -304,6 +312,29 @@ public class FragmentFolder extends FragmentBase {
} }
} }
private void onMenuSubscribe() {
Bundle args = new Bundle();
args.putLong("id", id);
args.putBoolean("subscribed", subscribed);
new SimpleTask<Void>() {
@Override
protected Void onExecute(Context context, Bundle args) {
long id = args.getLong("id");
boolean subscribed = args.getBoolean("subscribed");
EntityOperation.subscribe(context, id, subscribed);
return null;
}
@Override
protected void onException(Bundle args, Throwable ex) {
Helper.unexpectedError(getContext(), getViewLifecycleOwner(), ex);
}
}.execute(getContext(), getViewLifecycleOwner(), args, "folder:subscribe");
}
private void onMenuDelete() { private void onMenuDelete() {
new DialogBuilderLifecycle(getContext(), getViewLifecycleOwner()) new DialogBuilderLifecycle(getContext(), getViewLifecycleOwner())
.setMessage(R.string.title_folder_delete) .setMessage(R.string.title_folder_delete)
@ -399,6 +430,7 @@ public class FragmentFolder extends FragmentBase {
cbDownload.setEnabled(cbSynchronize.isChecked()); cbDownload.setEnabled(cbSynchronize.isChecked());
btnSave.setEnabled(true); btnSave.setEnabled(true);
subscribed = (folder == null ? null : folder.subscribed != null && folder.subscribed);
deletable = (folder != null && EntityFolder.USER.equals(folder.type)); deletable = (folder != null && EntityFolder.USER.equals(folder.type));
getActivity().invalidateOptionsMenu(); getActivity().invalidateOptionsMenu();
} }

View File

@ -1,6 +1,12 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" <menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"> xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_subscribe"
android:checkable="true"
android:title="@string/title_subscribe"
app:showAsAction="never" />
<item <item
android:id="@+id/menu_delete" android:id="@+id/menu_delete"
android:title="@string/title_delete" android:title="@string/title_delete"

View File

@ -365,6 +365,7 @@
<string name="title_trash">Trash</string> <string name="title_trash">Trash</string>
<string name="title_copy">Copy &#8230;</string> <string name="title_copy">Copy &#8230;</string>
<string name="title_subscribe">Subscribe</string>
<string name="title_delete">Delete</string> <string name="title_delete">Delete</string>
<string name="title_more">More</string> <string name="title_more">More</string>
<string name="title_spam">Spam</string> <string name="title_spam">Spam</string>