mirror of https://github.com/M66B/FairEmail.git
Added notification move action
This commit is contained in:
parent
ee39642758
commit
f262eb3e3e
2
FAQ.md
2
FAQ.md
|
@ -75,8 +75,8 @@ Related questions:
|
|||
* ~~Remind to attach files~~
|
||||
* ~~Select domains to show images for~~ (this will be too complicated to use)
|
||||
* ~~Unified starred messages view~~ (there is already a special search for this)
|
||||
* ~~Notification move action~~
|
||||
* Search for settings
|
||||
* Notification move action
|
||||
|
||||
Anything on this list is in random order and *might* be added in the near future.
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -2768,6 +2768,7 @@ class Core {
|
|||
boolean notify_trash = (prefs.getBoolean("notify_trash", true) || !pro);
|
||||
boolean notify_junk = (prefs.getBoolean("notify_junk", false) && pro);
|
||||
boolean notify_archive = (prefs.getBoolean("notify_archive", true) || !pro);
|
||||
boolean notify_move = (prefs.getBoolean("notify_move", false) && pro);
|
||||
boolean notify_reply = (prefs.getBoolean("notify_reply", false) && pro);
|
||||
boolean notify_reply_direct = (prefs.getBoolean("notify_reply_direct", false) && pro);
|
||||
boolean notify_flag = (prefs.getBoolean("notify_flag", false) && flags && pro);
|
||||
|
@ -2993,6 +2994,27 @@ class Core {
|
|||
wactions.add(actionArchive.build());
|
||||
}
|
||||
|
||||
if (notify_move) {
|
||||
EntityAccount account = db.account().getAccount(message.account);
|
||||
if (account != null && account.move_to != null) {
|
||||
EntityFolder folder = db.folder().getFolder(account.move_to);
|
||||
if (folder != null) {
|
||||
Intent move = new Intent(context, ServiceUI.class)
|
||||
.setAction("move:" + message.id)
|
||||
.putExtra("group", group);
|
||||
PendingIntent piMove = PendingIntent.getService(context, ServiceUI.PI_MOVE, move, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
NotificationCompat.Action.Builder actionMove = new NotificationCompat.Action.Builder(
|
||||
R.drawable.baseline_folder_24,
|
||||
folder.getDisplayName(context),
|
||||
piMove)
|
||||
.setAllowGeneratedReplies(false);
|
||||
mbuilder.addAction(actionMove.build());
|
||||
|
||||
wactions.add(actionMove.build());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (notify_reply && message.content &&
|
||||
db.identity().getComposableIdentities(message.account).size() > 0) {
|
||||
Intent reply = new Intent(context, ActivityCompose.class)
|
||||
|
|
|
@ -56,7 +56,7 @@ import io.requery.android.database.sqlite.RequerySQLiteOpenHelperFactory;
|
|||
// https://developer.android.com/topic/libraries/architecture/room.html
|
||||
|
||||
@Database(
|
||||
version = 111,
|
||||
version = 112,
|
||||
entities = {
|
||||
EntityIdentity.class,
|
||||
EntityAccount.class,
|
||||
|
@ -1079,6 +1079,13 @@ public abstract class DB extends RoomDatabase {
|
|||
db.execSQL("ALTER TABLE `rule` ADD COLUMN `applied` INTEGER NOT NULL DEFAULT 0");
|
||||
}
|
||||
})
|
||||
.addMigrations(new Migration(111, 112) {
|
||||
@Override
|
||||
public void migrate(@NonNull SupportSQLiteDatabase db) {
|
||||
Log.i("DB migration from version " + startVersion + " to " + endVersion);
|
||||
db.execSQL("ALTER TABLE `account` ADD COLUMN `move_to` INTEGER");
|
||||
}
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
|
|
|
@ -92,6 +92,7 @@ public class EntityAccount extends EntityOrder implements Serializable {
|
|||
public Character separator;
|
||||
public Long swipe_left;
|
||||
public Long swipe_right;
|
||||
public Long move_to;
|
||||
@NonNull
|
||||
public Integer poll_interval = DEFAULT_KEEP_ALIVE_INTERVAL; // keep-alive interval
|
||||
@NonNull
|
||||
|
|
|
@ -122,6 +122,8 @@ public class FragmentAccount extends FragmentBase {
|
|||
private Spinner spLeft;
|
||||
private Spinner spRight;
|
||||
|
||||
private Spinner spMove;
|
||||
|
||||
private Button btnSave;
|
||||
private ContentLoadingProgressBar pbSave;
|
||||
private CheckBox cbIdentity;
|
||||
|
@ -217,6 +219,7 @@ public class FragmentAccount extends FragmentBase {
|
|||
spJunk = view.findViewById(R.id.spJunk);
|
||||
spLeft = view.findViewById(R.id.spLeft);
|
||||
spRight = view.findViewById(R.id.spRight);
|
||||
spMove = view.findViewById(R.id.spMove);
|
||||
|
||||
btnSave = view.findViewById(R.id.btnSave);
|
||||
pbSave = view.findViewById(R.id.pbSave);
|
||||
|
@ -406,6 +409,8 @@ public class FragmentAccount extends FragmentBase {
|
|||
spLeft.setAdapter(adapterSwipe);
|
||||
spRight.setAdapter(adapterSwipe);
|
||||
|
||||
spMove.setAdapter(adapter);
|
||||
|
||||
// Initialize
|
||||
Helper.setViewsEnabled(view, false);
|
||||
|
||||
|
@ -668,6 +673,7 @@ public class FragmentAccount extends FragmentBase {
|
|||
EntityFolder junk = (EntityFolder) spJunk.getSelectedItem();
|
||||
EntityFolder left = (EntityFolder) spLeft.getSelectedItem();
|
||||
EntityFolder right = (EntityFolder) spRight.getSelectedItem();
|
||||
EntityFolder move = (EntityFolder) spMove.getSelectedItem();
|
||||
|
||||
if (drafts != null && drafts.id != null && drafts.id == 0L)
|
||||
drafts = null;
|
||||
|
@ -685,6 +691,9 @@ public class FragmentAccount extends FragmentBase {
|
|||
if (right != null && right.id != null && right.id == 0L)
|
||||
right = null;
|
||||
|
||||
if (move != null && move.id != null && move.id == 0L)
|
||||
move = null;
|
||||
|
||||
Bundle args = new Bundle();
|
||||
args.putLong("id", id);
|
||||
|
||||
|
@ -716,6 +725,7 @@ public class FragmentAccount extends FragmentBase {
|
|||
args.putSerializable("junk", junk);
|
||||
args.putSerializable("left", left);
|
||||
args.putSerializable("right", right);
|
||||
args.putSerializable("move", move);
|
||||
|
||||
args.putBoolean("should", should);
|
||||
|
||||
|
@ -772,6 +782,7 @@ public class FragmentAccount extends FragmentBase {
|
|||
EntityFolder junk = (EntityFolder) args.getSerializable("junk");
|
||||
EntityFolder left = (EntityFolder) args.getSerializable("left");
|
||||
EntityFolder right = (EntityFolder) args.getSerializable("right");
|
||||
EntityFolder move = (EntityFolder) args.getSerializable("move");
|
||||
|
||||
boolean pro = ActivityBilling.isPro(context);
|
||||
boolean should = args.getBoolean("should");
|
||||
|
@ -872,6 +883,9 @@ public class FragmentAccount extends FragmentBase {
|
|||
if (!Objects.equals(account.swipe_right, right == null ? null : right.id))
|
||||
return true;
|
||||
|
||||
if (!Objects.equals(account.move_to, move == null ? null : move.id))
|
||||
return true;
|
||||
|
||||
if (account.error != null)
|
||||
return true;
|
||||
|
||||
|
@ -1045,6 +1059,19 @@ public class FragmentAccount extends FragmentBase {
|
|||
}
|
||||
}
|
||||
|
||||
if (move != null && !(move.id != null && move.id < 0)) {
|
||||
boolean found = false;
|
||||
for (EntityFolder folder : folders)
|
||||
if (move.name.equals(folder.name)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
if (!found) {
|
||||
move.type = EntityFolder.USER;
|
||||
folders.add(move);
|
||||
}
|
||||
}
|
||||
|
||||
db.folder().setFoldersUser(account.id);
|
||||
|
||||
for (EntityFolder folder : folders) {
|
||||
|
@ -1061,6 +1088,7 @@ public class FragmentAccount extends FragmentBase {
|
|||
|
||||
account.swipe_left = (left == null ? null : left.id);
|
||||
account.swipe_right = (right == null ? null : right.id);
|
||||
account.move_to = (move == null ? null : move.id);
|
||||
db.account().updateAccount(account);
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
|
@ -1441,6 +1469,10 @@ public class FragmentAccount extends FragmentBase {
|
|||
spTrash.setSelection(pos);
|
||||
else if (EntityFolder.JUNK.equals(folder.type))
|
||||
spJunk.setSelection(pos);
|
||||
|
||||
if (account != null &&
|
||||
account.move_to != null && account.move_to.equals(folder.id))
|
||||
spMove.setSelection(pos);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -60,6 +60,7 @@ public class FragmentOptionsNotifications extends FragmentBase implements Shared
|
|||
private CheckBox cbNotifyActionTrash;
|
||||
private CheckBox cbNotifyActionJunk;
|
||||
private CheckBox cbNotifyActionArchive;
|
||||
private CheckBox cbNotifyActionMove;
|
||||
private CheckBox cbNotifyActionReply;
|
||||
private CheckBox cbNotifyActionReplyDirect;
|
||||
private CheckBox cbNotifyActionFlag;
|
||||
|
@ -81,7 +82,8 @@ public class FragmentOptionsNotifications extends FragmentBase implements Shared
|
|||
private final static String[] RESET_OPTIONS = new String[]{
|
||||
"badge", "unseen_ignored",
|
||||
"notify_summary", "notify_remove", "notify_preview", "wearable_preview",
|
||||
"notify_trash", "notify_junk", "notify_archive", "notify_reply", "notify_reply_direct",
|
||||
"notify_trash", "notify_junk", "notify_archive", "notify_move",
|
||||
"notify_reply", "notify_reply_direct",
|
||||
"notify_flag", "notify_seen", "notify_snooze",
|
||||
"biometrics_notify",
|
||||
"light", "sound", "alert_once"
|
||||
|
@ -106,6 +108,7 @@ public class FragmentOptionsNotifications extends FragmentBase implements Shared
|
|||
cbNotifyActionTrash = view.findViewById(R.id.cbNotifyActionTrash);
|
||||
cbNotifyActionJunk = view.findViewById(R.id.cbNotifyActionJunk);
|
||||
cbNotifyActionArchive = view.findViewById(R.id.cbNotifyActionArchive);
|
||||
cbNotifyActionMove = view.findViewById(R.id.cbNotifyActionMove);
|
||||
cbNotifyActionReply = view.findViewById(R.id.cbNotifyActionReply);
|
||||
cbNotifyActionReplyDirect = view.findViewById(R.id.cbNotifyActionReplyDirect);
|
||||
cbNotifyActionFlag = view.findViewById(R.id.cbNotifyActionFlag);
|
||||
|
@ -198,6 +201,13 @@ public class FragmentOptionsNotifications extends FragmentBase implements Shared
|
|||
}
|
||||
});
|
||||
|
||||
cbNotifyActionMove.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean checked) {
|
||||
prefs.edit().putBoolean("notify_move", checked).apply();
|
||||
}
|
||||
});
|
||||
|
||||
cbNotifyActionReply.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean checked) {
|
||||
|
@ -358,6 +368,7 @@ public class FragmentOptionsNotifications extends FragmentBase implements Shared
|
|||
cbNotifyActionTrash.setChecked(prefs.getBoolean("notify_trash", true) || !pro);
|
||||
cbNotifyActionJunk.setChecked(prefs.getBoolean("notify_junk", false) && pro);
|
||||
cbNotifyActionArchive.setChecked(prefs.getBoolean("notify_archive", true) || !pro);
|
||||
cbNotifyActionMove.setChecked(prefs.getBoolean("notify_move", false) && pro);
|
||||
cbNotifyActionReply.setChecked(prefs.getBoolean("notify_reply", false) && pro);
|
||||
cbNotifyActionReplyDirect.setChecked(prefs.getBoolean("notify_reply_direct", false) && pro);
|
||||
cbNotifyActionFlag.setChecked(prefs.getBoolean("notify_flag", false) && pro);
|
||||
|
@ -375,19 +386,20 @@ public class FragmentOptionsNotifications extends FragmentBase implements Shared
|
|||
|
||||
private void enableOptions() {
|
||||
boolean pro = ActivityBilling.isPro(getContext());
|
||||
boolean checked = swNotifySummary.isChecked();
|
||||
boolean summary = swNotifySummary.isChecked();
|
||||
|
||||
swNotifyPreview.setEnabled(!checked);
|
||||
swWearablePreview.setEnabled(!checked && swNotifyPreview.isChecked());
|
||||
cbNotifyActionTrash.setEnabled(pro && !checked);
|
||||
cbNotifyActionJunk.setEnabled(pro && !checked);
|
||||
cbNotifyActionArchive.setEnabled(pro && !checked);
|
||||
cbNotifyActionReply.setEnabled(pro && !checked);
|
||||
cbNotifyActionReplyDirect.setEnabled(pro && !checked);
|
||||
cbNotifyActionFlag.setEnabled(pro && !checked);
|
||||
cbNotifyActionSeen.setEnabled(pro && !checked);
|
||||
cbNotifyActionSnooze.setEnabled(pro && !checked);
|
||||
swBiometricsNotify.setEnabled(!checked);
|
||||
swNotifyPreview.setEnabled(!summary);
|
||||
swWearablePreview.setEnabled(!summary && swNotifyPreview.isChecked());
|
||||
cbNotifyActionTrash.setEnabled(pro && !summary);
|
||||
cbNotifyActionJunk.setEnabled(pro && !summary);
|
||||
cbNotifyActionArchive.setEnabled(pro && !summary);
|
||||
cbNotifyActionMove.setEnabled(pro && !summary);
|
||||
cbNotifyActionReply.setEnabled(pro && !summary);
|
||||
cbNotifyActionReplyDirect.setEnabled(pro && !summary);
|
||||
cbNotifyActionFlag.setEnabled(pro && !summary);
|
||||
cbNotifyActionSeen.setEnabled(pro && !summary);
|
||||
cbNotifyActionSnooze.setEnabled(pro && !summary);
|
||||
swBiometricsNotify.setEnabled(!summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -44,12 +44,13 @@ public class ServiceUI extends IntentService {
|
|||
static final int PI_TRASH = 2;
|
||||
static final int PI_JUNK = 3;
|
||||
static final int PI_ARCHIVE = 4;
|
||||
static final int PI_REPLY_DIRECT = 5;
|
||||
static final int PI_FLAG = 6;
|
||||
static final int PI_SEEN = 7;
|
||||
static final int PI_SNOOZE = 8;
|
||||
static final int PI_IGNORED = 9;
|
||||
static final int PI_WAKEUP = 10;
|
||||
static final int PI_MOVE = 5;
|
||||
static final int PI_REPLY_DIRECT = 6;
|
||||
static final int PI_FLAG = 7;
|
||||
static final int PI_SEEN = 8;
|
||||
static final int PI_SNOOZE = 9;
|
||||
static final int PI_IGNORED = 10;
|
||||
static final int PI_WAKEUP = 11;
|
||||
|
||||
public ServiceUI() {
|
||||
this(ServiceUI.class.getName());
|
||||
|
@ -111,6 +112,11 @@ public class ServiceUI extends IntentService {
|
|||
onMove(id, EntityFolder.ARCHIVE);
|
||||
break;
|
||||
|
||||
case "move":
|
||||
cancel(group, id);
|
||||
onMove(id);
|
||||
break;
|
||||
|
||||
case "reply":
|
||||
onReplyDirect(id, intent);
|
||||
cancel(group, id);
|
||||
|
@ -173,9 +179,30 @@ public class ServiceUI extends IntentService {
|
|||
if (message == null)
|
||||
return;
|
||||
|
||||
EntityFolder trash = db.folder().getFolderByType(message.account, folderType);
|
||||
if (trash != null)
|
||||
EntityOperation.queue(this, message, EntityOperation.MOVE, trash.id);
|
||||
EntityFolder folder = db.folder().getFolderByType(message.account, folderType);
|
||||
if (folder != null)
|
||||
EntityOperation.queue(this, message, EntityOperation.MOVE, folder.id);
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
private void onMove(long id) {
|
||||
DB db = DB.getInstance(this);
|
||||
try {
|
||||
db.beginTransaction();
|
||||
|
||||
EntityMessage message = db.message().getMessage(id);
|
||||
if (message == null)
|
||||
return;
|
||||
|
||||
EntityAccount account = db.account().getAccount(message.account);
|
||||
if (account == null || account.move_to == null)
|
||||
return;
|
||||
|
||||
EntityOperation.queue(this, message, EntityOperation.MOVE, account.move_to);
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
|
|
|
@ -619,13 +619,23 @@
|
|||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/spRight" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvMove"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/title_account_move"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/spMove"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/spMove" />
|
||||
|
||||
<androidx.constraintlayout.widget.Barrier
|
||||
android:id="@+id/barrier_folders"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="6dp"
|
||||
app:barrierDirection="end"
|
||||
app:constraint_referenced_ids="tvDrafts,tvSent,tvArchive,tvTrash,tvJunk,tvLeft,tvRight" />
|
||||
app:constraint_referenced_ids="tvDrafts,tvSent,tvArchive,tvTrash,tvJunk,tvLeft,tvRight,tvMove" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/spDrafts"
|
||||
|
@ -716,6 +726,25 @@
|
|||
app:layout_constraintStart_toEndOf="@id/barrier_folders"
|
||||
app:layout_constraintTop_toBottomOf="@id/spLeft" />
|
||||
|
||||
<View
|
||||
android:id="@+id/vSeparatorMove"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:background="?attr/colorSeparator"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/spRight" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/spMove"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_marginTop="12dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/barrier_folders"
|
||||
app:layout_constraintTop_toBottomOf="@id/vSeparatorMove" />
|
||||
|
||||
<!-- save -->
|
||||
|
||||
<Button
|
||||
|
@ -726,7 +755,7 @@
|
|||
android:tag="disable"
|
||||
android:text="@string/title_save"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/spRight" />
|
||||
app:layout_constraintTop_toBottomOf="@id/spMove" />
|
||||
|
||||
<eu.faircode.email.ContentLoadingProgressBar
|
||||
android:id="@+id/pbSave"
|
||||
|
@ -845,6 +874,7 @@
|
|||
tvArchive,spArchive,
|
||||
tvTrash,spTrash,
|
||||
tvJunk,spJunk,
|
||||
vSeparatorSwipe,tvLeft,spLeft,tvRight,spRight" />
|
||||
vSeparatorSwipe,tvLeft,spLeft,tvRight,spRight,
|
||||
vSeparatorMove,tvMove,spMove" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</ScrollView>
|
||||
|
|
|
@ -169,6 +169,15 @@
|
|||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/cbNotifyActionJunk" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/cbNotifyActionMove"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="6dp"
|
||||
android:text="@string/title_advanced_notify_action_move"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/cbNotifyActionArchive" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/cbNotifyActionReply"
|
||||
android:layout_width="wrap_content"
|
||||
|
@ -176,7 +185,7 @@
|
|||
android:layout_marginTop="6dp"
|
||||
android:text="@string/title_advanced_notify_action_reply"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/cbNotifyActionArchive" />
|
||||
app:layout_constraintTop_toBottomOf="@id/cbNotifyActionMove" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/cbNotifyActionReplyDirect"
|
||||
|
|
|
@ -304,6 +304,7 @@
|
|||
<string name="title_advanced_notify_action_trash">Trash</string>
|
||||
<string name="title_advanced_notify_action_junk">Spam</string>
|
||||
<string name="title_advanced_notify_action_archive">Archive</string>
|
||||
<string name="title_advanced_notify_action_move">Move</string>
|
||||
<string name="title_advanced_notify_action_reply">Reply</string>
|
||||
<string name="title_advanced_notify_action_reply_direct">Direct reply</string>
|
||||
<string name="title_advanced_notify_action_flag">Star</string>
|
||||
|
@ -406,6 +407,7 @@
|
|||
<string name="title_account_notify">Separate notifications</string>
|
||||
<string name="title_account_left">Swipe left</string>
|
||||
<string name="title_account_right">Swipe right</string>
|
||||
<string name="title_account_move">Default move to</string>
|
||||
<string name="title_domain">Domain name</string>
|
||||
<string name="title_autoconfig">Get settings</string>
|
||||
<string name="title_imap" translatable="false">IMAP</string>
|
||||
|
|
Loading…
Reference in New Issue