Use dialog fragment to select folder/duration

pull/157/head
M66B 6 years ago
parent 0f7f0e1ad3
commit 0d33077b19

@ -3079,55 +3079,21 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
.setNegativeButton(android.R.string.cancel, null) .setNegativeButton(android.R.string.cancel, null)
.show(); .show();
} else } else
properties.move(data.message.id, EntityFolder.TRASH, true); properties.move(data.message.id, EntityFolder.TRASH);
} }
private void onActionMove(final TupleMessageEx message, final boolean copy) { private void onActionMove(final TupleMessageEx message, final boolean copy) {
DialogFolder.show( Bundle args = new Bundle();
context, owner, parentFragment.getView(), args.putString("title", context.getString(copy ? R.string.title_copy_to : R.string.title_move_to_folder));
copy ? R.string.title_copy_to : R.string.title_move_to_folder, args.putLong("account", message.account);
message.account, Arrays.asList(message.folder), args.putLongArray("disabled", new long[]{message.folder});
new DialogFolder.IDialogFolder() { args.putLong("message", message.id);
@Override args.putBoolean("copy", copy);
public void onFolderSelected(TupleFolderEx folder) {
if (copy) {
Bundle args = new Bundle();
args.putLong("id", message.id);
args.putLong("target", folder.id);
new SimpleTask<Void>() {
@Override
protected Void onExecute(Context context, Bundle args) {
long id = args.getLong("id");
long target = args.getLong("target");
DB db = DB.getInstance(context);
try {
db.beginTransaction();
EntityMessage message = db.message().getMessage(id);
if (message == null)
return null;
EntityOperation.queue(context, message, EntityOperation.COPY, target);
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
return null;
}
@Override FragmentSelectFolder fragment = new FragmentSelectFolder();
protected void onException(Bundle args, Throwable ex) { fragment.setArguments(args);
Helper.unexpectedError(context, owner, ex); fragment.setTargetFragment(parentFragment, FragmentMessages.REQUEST_MESSAGE_MOVE);
} fragment.show(parentFragment.getFragmentManager(), "message:move");
}.execute(context, owner, args, "message:copy");
} else
properties.move(message.id, folder.name, false);
}
});
} }
private void onActionMoveOutbox(ActionData data) { private void onActionMoveOutbox(ActionData data) {
@ -3195,11 +3161,11 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
} }
private void onActionArchive(ActionData data) { private void onActionArchive(ActionData data) {
properties.move(data.message.id, EntityFolder.ARCHIVE, true); properties.move(data.message.id, EntityFolder.ARCHIVE);
} }
private void onActionMoveJunk(ActionData data) { private void onActionMoveJunk(ActionData data) {
properties.move(data.message.id, EntityFolder.INBOX, true); properties.move(data.message.id, EntityFolder.INBOX);
} }
private void onActionReplyMenu(final ActionData data) { private void onActionReplyMenu(final ActionData data) {
@ -3837,7 +3803,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
void scrollBy(int dx, int dy); void scrollBy(int dx, int dy);
void move(long id, String target, boolean type); void move(long id, String type);
void finish(); void finish();
} }

@ -1,101 +0,0 @@
package eu.faircode.email;
/*
This file is part of FairEmail.
FairEmail is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
FairEmail is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with FairEmail. If not, see <http://www.gnu.org/licenses/>.
Copyright 2018-2019 by Marcel Bokhorst (M66B)
*/
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import androidx.lifecycle.LifecycleOwner;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
public class DialogFolder {
static void show(
final Context context, final LifecycleOwner owner, View parentView, int title,
long account, final List<Long> disabled,
final IDialogFolder intf) {
final View dview = LayoutInflater.from(context).inflate(R.layout.dialog_folder_select, null);
final RecyclerView rvFolder = dview.findViewById(R.id.rvFolder);
final ContentLoadingProgressBar pbWait = dview.findViewById(R.id.pbWait);
final Dialog dialog = new DialogBuilderLifecycle(context, owner)
.setTitle(title)
.setView(dview)
.create();
rvFolder.setHasFixedSize(false);
LinearLayoutManager llm = new LinearLayoutManager(context);
rvFolder.setLayoutManager(llm);
final AdapterFolder adapter = new AdapterFolder(context, owner, parentView, account, false,
new AdapterFolder.IFolderSelectedListener() {
@Override
public void onFolderSelected(TupleFolderEx folder) {
dialog.dismiss();
intf.onFolderSelected(folder);
}
});
rvFolder.setAdapter(adapter);
rvFolder.setVisibility(View.GONE);
pbWait.setVisibility(View.VISIBLE);
dialog.show();
Bundle args = new Bundle();
args.putLong("account", account);
new SimpleTask<List<TupleFolderEx>>() {
@Override
protected List<TupleFolderEx> onExecute(Context context, Bundle args) {
long account = args.getLong("account");
DB db = DB.getInstance(context);
return db.folder().getFoldersEx(account);
}
@Override
protected void onExecuted(final Bundle args, List<TupleFolderEx> folders) {
if (folders == null)
folders = new ArrayList<>();
adapter.setDisabled(disabled);
adapter.set(folders);
pbWait.setVisibility(View.GONE);
rvFolder.setVisibility(View.VISIBLE);
}
@Override
protected void onException(Bundle args, Throwable ex) {
Helper.unexpectedError(context, owner, ex);
}
}.execute(context, owner, args, "folder:select");
}
interface IDialogFolder {
void onFolderSelected(TupleFolderEx folder);
}
}

@ -214,6 +214,7 @@ public class FragmentCompose extends FragmentBase {
private static final int REQUEST_RECORD_AUDIO = 7; private static final int REQUEST_RECORD_AUDIO = 7;
private static final int REQUEST_ENCRYPT = 8; private static final int REQUEST_ENCRYPT = 8;
private static final int REQUEST_COLOR = 9; private static final int REQUEST_COLOR = 9;
private static final int REQUEST_SEND_AFTER = 10;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
@ -1079,44 +1080,13 @@ public class FragmentCompose extends FragmentBase {
} }
private void onMenuSendAfter() { private void onMenuSendAfter() {
DialogDuration.show(getContext(), getViewLifecycleOwner(), R.string.title_send_at, Bundle args = new Bundle();
new DialogDuration.IDialogDuration() { args.putString("title", getString(R.string.title_send_at));
@Override
public void onDurationSelected(long duration, long time) {
if (!Helper.isPro(getContext())) {
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(getContext());
lbm.sendBroadcast(new Intent(ActivityCompose.ACTION_SHOW_PRO));
return;
}
Bundle args = new Bundle();
args.putLong("id", working);
args.putLong("wakeup", time);
new SimpleTask<Void>() {
@Override
protected Void onExecute(Context context, Bundle args) {
long id = args.getLong("id");
Long wakeup = args.getLong("wakeup");
DB db = DB.getInstance(context);
db.message().setMessageSnoozed(id, wakeup);
return null;
}
@Override
protected void onExecuted(Bundle args, Void data) {
onAction(R.id.action_send);
}
@Override FragmentDuration fragment = new FragmentDuration();
protected void onException(Bundle args, Throwable ex) { fragment.setArguments(args);
Helper.unexpectedError(getContext(), getViewLifecycleOwner(), ex); fragment.setTargetFragment(this, REQUEST_SEND_AFTER);
} fragment.show(getFragmentManager(), "send:after");
}.execute(FragmentCompose.this, args, "compose:send:after");
}
});
} }
private void onActionRecordAudio() { private void onActionRecordAudio() {
@ -1602,12 +1572,52 @@ public class FragmentCompose extends FragmentBase {
etBody.setSelection(end); etBody.setSelection(end);
} }
break; break;
case REQUEST_SEND_AFTER:
if (resultCode == RESULT_OK && data != null) {
Bundle args = data.getBundleExtra("args");
onSendAfter(args.getLong("time"));
}
default: default:
if (resultCode == RESULT_OK && data != null) if (resultCode == RESULT_OK && data != null)
handlePickContact(requestCode, data); handlePickContact(requestCode, data);
} }
} }
private void onSendAfter(long time) {
if (!Helper.isPro(getContext())) {
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(getContext());
lbm.sendBroadcast(new Intent(ActivityCompose.ACTION_SHOW_PRO));
return;
}
Bundle args = new Bundle();
args.putLong("id", working);
args.putLong("wakeup", time);
new SimpleTask<Void>() {
@Override
protected Void onExecute(Context context, Bundle args) {
long id = args.getLong("id");
Long wakeup = args.getLong("wakeup");
DB db = DB.getInstance(context);
db.message().setMessageSnoozed(id, wakeup);
return null;
}
@Override
protected void onExecuted(Bundle args, Void data) {
onAction(R.id.action_send);
}
@Override
protected void onException(Bundle args, Throwable ex) {
Helper.unexpectedError(getContext(), getViewLifecycleOwner(), ex);
}
}.execute(FragmentCompose.this, args, "compose:send:after");
}
private void handlePickContact(int requestCode, Intent data) { private void handlePickContact(int requestCode, Intent data) {
Uri uri = data.getData(); Uri uri = data.getData();
if (uri == null) if (uri == null)

@ -19,37 +19,60 @@ package eu.faircode.email;
Copyright 2018-2019 by Marcel Bokhorst (M66B) Copyright 2018-2019 by Marcel Bokhorst (M66B)
*/ */
import android.content.Context; import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent;
import android.os.Build; import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.widget.DatePicker; import android.widget.DatePicker;
import android.widget.TextView; import android.widget.TextView;
import android.widget.TimePicker; import android.widget.TimePicker;
import androidx.lifecycle.LifecycleOwner; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.Fragment;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
public class DialogDuration { import static android.app.Activity.RESULT_CANCELED;
static void show(Context context, LifecycleOwner owner, int title, final IDialogDuration intf) { import static android.app.Activity.RESULT_OK;
final View dview = LayoutInflater.from(context).inflate(R.layout.dialog_duration, null);
public class FragmentDuration extends DialogFragment {
private Calendar cal = Calendar.getInstance();
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
outState.putLong("fair:time", cal.getTimeInMillis());
super.onSaveInstanceState(outState);
}
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
String title = getArguments().getString("title");
final View dview = LayoutInflater.from(getContext()).inflate(R.layout.dialog_duration, null);
final TextView tvDuration = dview.findViewById(R.id.tvDuration); final TextView tvDuration = dview.findViewById(R.id.tvDuration);
final TimePicker timePicker = dview.findViewById(R.id.timePicker); final TimePicker timePicker = dview.findViewById(R.id.timePicker);
final DatePicker datePicker = dview.findViewById(R.id.datePicker); final DatePicker datePicker = dview.findViewById(R.id.datePicker);
final Calendar cal = Calendar.getInstance(); if (savedInstanceState == null)
cal.setTimeInMillis((new Date().getTime() / (3600 * 1000L) + 1) * (3600 * 1000L)); cal.setTimeInMillis((new Date().getTime() / (3600 * 1000L) + 1) * (3600 * 1000L));
else
cal.setTimeInMillis(savedInstanceState.getLong("fair:time"));
Log.i("Set init=" + new Date(cal.getTimeInMillis())); Log.i("Set init=" + new Date(cal.getTimeInMillis()));
final DateFormat df = SimpleDateFormat.getDateTimeInstance(SimpleDateFormat.FULL, SimpleDateFormat.SHORT); final DateFormat df = SimpleDateFormat.getDateTimeInstance(SimpleDateFormat.FULL, SimpleDateFormat.SHORT);
tvDuration.setText(df.format(cal.getTime())); tvDuration.setText(df.format(cal.getTime()));
timePicker.setIs24HourView(android.text.format.DateFormat.is24HourFormat(context)); timePicker.setIs24HourView(android.text.format.DateFormat.is24HourFormat(getContext()));
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
timePicker.setCurrentHour(cal.get(Calendar.HOUR_OF_DAY)); timePicker.setCurrentHour(cal.get(Calendar.HOUR_OF_DAY));
timePicker.setCurrentMinute(cal.get(Calendar.MINUTE)); timePicker.setCurrentMinute(cal.get(Calendar.MINUTE));
@ -86,7 +109,7 @@ public class DialogDuration {
} }
); );
new DialogBuilderLifecycle(context, owner) return new AlertDialog.Builder(getContext())
.setTitle(title) .setTitle(title)
.setView(dview) .setView(dview)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@ -97,13 +120,28 @@ public class DialogDuration {
if (duration < 0) if (duration < 0)
duration = 0; duration = 0;
Log.i("Set duration=" + duration + " time=" + new Date(cal.getTimeInMillis())); Log.i("Set duration=" + duration + " time=" + new Date(cal.getTimeInMillis()));
intf.onDurationSelected(duration, cal.getTimeInMillis()); sendResult(RESULT_OK, duration, cal.getTimeInMillis());
} }
}) })
.show(); .setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialogInterface) {
sendResult(RESULT_CANCELED, 0, 0);
}
})
.create();
} }
interface IDialogDuration { private void sendResult(int result, long duration, long time) {
void onDurationSelected(long duration, long time); Bundle args = getArguments();
args.putLong("duration", duration);
args.putLong("time", time);
Fragment target = getTargetFragment();
if (target != null) {
Intent data = new Intent();
data.putExtra("args", args);
target.onActivityResult(getTargetRequestCode(), result, data);
}
} }
} }

@ -230,6 +230,11 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
private static final int REQUEST_MOVE_ACROSS = 8; private static final int REQUEST_MOVE_ACROSS = 8;
static final int REQUEST_MESSAGE_COLOR = 9; static final int REQUEST_MESSAGE_COLOR = 9;
private static final int REQUEST_MESSAGES_COLOR = 10; private static final int REQUEST_MESSAGES_COLOR = 10;
private static final int REQUEST_MESSAGE_SNOOZE = 11;
private static final int REQUEST_MESSAGES_SNOOZE = 12;
static final int REQUEST_MESSAGE_MOVE = 13;
private static final int REQUEST_MESSAGES_MOVE = 14;
private static final int REQUEST_SEARCH = 15;
static final String ACTION_STORE_RAW = BuildConfig.APPLICATION_ID + ".STORE_RAW"; static final String ACTION_STORE_RAW = BuildConfig.APPLICATION_ID + ".STORE_RAW";
static final String ACTION_STORE_ATTACHMENT = BuildConfig.APPLICATION_ID + ".STORE_ATTACHMENT"; static final String ACTION_STORE_ATTACHMENT = BuildConfig.APPLICATION_ID + ".STORE_ATTACHMENT";
@ -559,6 +564,78 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
return false; return false;
} }
} }
private void onActionMove(String folderType) {
Bundle args = new Bundle();
args.putLong("account", account);
args.putString("thread", thread);
args.putLong("id", id);
args.putString("type", folderType);
new SimpleTask<ArrayList<MessageTarget>>() {
@Override
protected ArrayList<MessageTarget> onExecute(Context context, Bundle args) {
long aid = args.getLong("account");
String thread = args.getString("thread");
long id = args.getLong("id");
String type = args.getString("type");
ArrayList<MessageTarget> result = new ArrayList<>();
DB db = DB.getInstance(context);
try {
db.beginTransaction();
EntityFolder target = db.folder().getFolderByType(aid, type);
if (target != null) {
EntityAccount account = db.account().getAccount(target.account);
List<EntityMessage> messages = db.message().getMessageByThread(
aid, thread, threading ? null : id, null);
for (EntityMessage threaded : messages) {
EntityFolder folder = db.folder().getFolder(threaded.folder);
if (!target.id.equals(threaded.folder) &&
!EntityFolder.DRAFTS.equals(folder.type) &&
!EntityFolder.OUTBOX.equals(folder.type) &&
(!EntityFolder.SENT.equals(folder.type) || EntityFolder.TRASH.equals(target.type)) &&
!EntityFolder.TRASH.equals(folder.type) &&
!EntityFolder.JUNK.equals(folder.type))
result.add(new MessageTarget(threaded, account, target));
}
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
return result;
}
@Override
protected void onExecuted(Bundle args, ArrayList<MessageTarget> result) {
moveAsk(result);
}
@Override
protected void onException(Bundle args, Throwable ex) {
Helper.unexpectedError(getContext(), getViewLifecycleOwner(), ex);
}
}.execute(FragmentMessages.this, args, "messages:move");
}
private void onActionSnooze() {
Bundle args = new Bundle();
args.putString("title", getString(R.string.title_snooze));
args.putLong("account", account);
args.putString("thread", thread);
args.putLong("id", id);
args.putBoolean("finish", true);
FragmentDuration fragment = new FragmentDuration();
fragment.setArguments(args);
fragment.setTargetFragment(FragmentMessages.this, REQUEST_MESSAGE_SNOOZE);
fragment.show(getFragmentManager(), "message:snooze");
}
}); });
fab.setOnClickListener(new View.OnClickListener() { fab.setOnClickListener(new View.OnClickListener() {
@ -641,21 +718,16 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
if (intent == null) if (intent == null)
return false; return false;
long account = intent.getLongExtra("account", -1); Bundle args = new Bundle();
DialogFolder.show( args.putString("title", getString(R.string.title_move_to_folder));
getContext(), getViewLifecycleOwner(), view, args.putLong("account", intent.getLongExtra("account", -1));
R.string.title_search_in, args.putLongArray("disabled", new long[]{});
account, args.putString("query", query);
new ArrayList<Long>(),
new DialogFolder.IDialogFolder() { FragmentSelectFolder fragment = new FragmentSelectFolder();
@Override fragment.setArguments(args);
public void onFolderSelected(TupleFolderEx folder) { fragment.setTargetFragment(FragmentMessages.this, FragmentMessages.REQUEST_SEARCH);
search( fragment.show(getFragmentManager(), "messages:search");
getContext(), getViewLifecycleOwner(), getFragmentManager(),
folder.id, true, query);
}
}
);
return true; return true;
} }
@ -1035,18 +1107,16 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
} }
@Override @Override
public void move(long id, String name, boolean type) { public void move(long id, String type) {
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putLong("id", id); args.putLong("id", id);
args.putString("name", name); args.putString("type", type);
args.putBoolean("type", type);
new SimpleTask<ArrayList<MessageTarget>>() { new SimpleTask<ArrayList<MessageTarget>>() {
@Override @Override
protected ArrayList<MessageTarget> onExecute(Context context, Bundle args) { protected ArrayList<MessageTarget> onExecute(Context context, Bundle args) {
long id = args.getLong("id"); long id = args.getLong("id");
String name = args.getString("name"); String type = args.getString("type");
boolean type = args.getBoolean("type");
ArrayList<MessageTarget> result = new ArrayList<>(); ArrayList<MessageTarget> result = new ArrayList<>();
@ -1058,10 +1128,7 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
EntityFolder target = null; EntityFolder target = null;
if (message != null) if (message != null)
if (type) target = db.folder().getFolderByType(message.account, type);
target = db.folder().getFolderByType(message.account, name);
else
target = db.folder().getFolderByName(message.account, name);
if (target != null) { if (target != null) {
EntityAccount account = db.account().getAccount(target.account); EntityAccount account = db.account().getAccount(target.account);
@ -1078,10 +1145,7 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
@Override @Override
protected void onExecuted(Bundle args, ArrayList<MessageTarget> result) { protected void onExecuted(Bundle args, ArrayList<MessageTarget> result) {
if (args.getBoolean("type")) moveAsk(result);
moveAsk(result);
else
moveAskConfirmed(result);
} }
@Override @Override
@ -1243,7 +1307,7 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
onActionSeenSelection(false, message.id); onActionSeenSelection(false, message.id);
return true; return true;
case R.string.title_snooze: case R.string.title_snooze:
onActionSnoozeSelection(message.id); onMenuSnooze();
return true; return true;
case R.string.title_flag_color: case R.string.title_flag_color:
onMenuColor(); onMenuColor();
@ -1256,6 +1320,20 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
} }
} }
private void onMenuSnooze() {
Bundle args = new Bundle();
args.putString("title", getString(R.string.title_snooze));
args.putLong("account", message.account);
args.putString("thread", message.thread);
args.putLong("id", message.id);
args.putBoolean("finish", false);
FragmentDuration fragment = new FragmentDuration();
fragment.setArguments(args);
fragment.setTargetFragment(FragmentMessages.this, REQUEST_MESSAGE_SNOOZE);
fragment.show(getFragmentManager(), "message:snooze");
}
private void onMenuColor() { private void onMenuColor() {
int color = (message.color == null ? Color.TRANSPARENT : message.color); int color = (message.color == null ? Color.TRANSPARENT : message.color);
@ -1270,31 +1348,16 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
private void onMenuMove() { private void onMenuMove() {
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putString("title", getString(R.string.title_move_to_folder));
args.putLong("account", message.account); args.putLong("account", message.account);
args.putLongArray("disabled", new long[]{message.folder});
new SimpleTask<List<TupleFolderEx>>() { args.putLong("message", message.id);
@Override args.putBoolean("copy", false);
protected List<TupleFolderEx> onExecute(Context context, Bundle args) {
long account = args.getLong("account"); FragmentSelectFolder fragment = new FragmentSelectFolder();
fragment.setArguments(args);
DB db = DB.getInstance(context); fragment.setTargetFragment(FragmentMessages.this, FragmentMessages.REQUEST_MESSAGE_MOVE);
return db.folder().getFoldersEx(account); fragment.show(getFragmentManager(), "message:move");
}
@Override
protected void onExecuted(Bundle args, List<TupleFolderEx> folders) {
onActionMoveSelectionAccount(
message.account,
folders,
Arrays.asList(new Long[]{message.folder}),
message.id);
}
@Override
protected void onException(Bundle args, Throwable ex) {
Helper.unexpectedError(getContext(), getViewLifecycleOwner(), ex);
}
}.execute(getContext(), getViewLifecycleOwner(), args, "message:move");
} }
}); });
@ -1384,126 +1447,6 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
} }
}; };
private void onActionMove(String folderType) {
Bundle args = new Bundle();
args.putLong("account", account);
args.putString("thread", thread);
args.putLong("id", id);
args.putString("type", folderType);
new SimpleTask<ArrayList<MessageTarget>>() {
@Override
protected ArrayList<MessageTarget> onExecute(Context context, Bundle args) {
long aid = args.getLong("account");
String thread = args.getString("thread");
long id = args.getLong("id");
String type = args.getString("type");
ArrayList<MessageTarget> result = new ArrayList<>();
DB db = DB.getInstance(context);
try {
db.beginTransaction();
EntityFolder target = db.folder().getFolderByType(aid, type);
if (target != null) {
EntityAccount account = db.account().getAccount(target.account);
List<EntityMessage> messages = db.message().getMessageByThread(
aid, thread, threading ? null : id, null);
for (EntityMessage threaded : messages) {
EntityFolder folder = db.folder().getFolder(threaded.folder);
if (!target.id.equals(threaded.folder) &&
!EntityFolder.DRAFTS.equals(folder.type) &&
!EntityFolder.OUTBOX.equals(folder.type) &&
(!EntityFolder.SENT.equals(folder.type) || EntityFolder.TRASH.equals(target.type)) &&
!EntityFolder.TRASH.equals(folder.type) &&
!EntityFolder.JUNK.equals(folder.type))
result.add(new MessageTarget(threaded, account, target));
}
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
return result;
}
@Override
protected void onExecuted(Bundle args, ArrayList<MessageTarget> result) {
moveAsk(result);
}
@Override
protected void onException(Bundle args, Throwable ex) {
Helper.unexpectedError(getContext(), getViewLifecycleOwner(), ex);
}
}.execute(FragmentMessages.this, args, "messages:move");
}
private void onActionSnooze() {
DialogDuration.show(getContext(), getViewLifecycleOwner(), R.string.title_snooze,
new DialogDuration.IDialogDuration() {
@Override
public void onDurationSelected(long duration, long time) {
if (!Helper.isPro(getContext())) {
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(getContext());
lbm.sendBroadcast(new Intent(ActivityView.ACTION_SHOW_PRO));
return;
}
Bundle args = new Bundle();
args.putLong("account", account);
args.putString("thread", thread);
args.putLong("id", id);
args.putLong("wakeup", duration == 0 ? -1 : time);
new SimpleTask<Long>() {
@Override
protected Long onExecute(Context context, Bundle args) {
long account = args.getLong("account");
String thread = args.getString("thread");
long id = args.getLong("id");
Long wakeup = args.getLong("wakeup");
if (wakeup < 0)
wakeup = null;
DB db = DB.getInstance(context);
try {
db.beginTransaction();
List<EntityMessage> messages = db.message().getMessageByThread(
account, thread, threading ? null : id, null);
for (EntityMessage threaded : messages) {
db.message().setMessageSnoozed(threaded.id, wakeup);
EntityMessage.snooze(context, threaded.id, wakeup);
EntityOperation.queue(context, threaded, EntityOperation.SEEN, true);
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
return wakeup;
}
@Override
protected void onExecuted(Bundle args, Long wakeup) {
if (wakeup != null)
finish();
}
@Override
protected void onException(Bundle args, Throwable ex) {
Helper.unexpectedError(getContext(), getViewLifecycleOwner(), ex);
}
}.execute(getContext(), getViewLifecycleOwner(), args, "message:snooze");
}
});
}
private void onMore() { private void onMore() {
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putLongArray("ids", getSelection()); args.putLongArray("ids", getSelection());
@ -1567,9 +1510,6 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
result.accounts = db.account().getSynchronizingAccounts(); result.accounts = db.account().getSynchronizingAccounts();
for (EntityAccount account : result.accounts)
result.targets.put(account.id, db.folder().getFoldersEx(account.id));
return result; return result;
} }
@ -1622,7 +1562,7 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
onActionSeenSelection(false, null); onActionSeenSelection(false, null);
return true; return true;
case R.string.title_snooze: case R.string.title_snooze:
onActionSnoozeSelection(null); onActionSnoozeSelection();
return true; return true;
case R.string.title_flag: case R.string.title_flag:
onActionFlagSelection(true, null); onActionFlagSelection(true, null);
@ -1647,7 +1587,7 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
return true; return true;
case R.string.title_move_to_account: case R.string.title_move_to_account:
long account = target.getIntent().getLongExtra("account", -1); long account = target.getIntent().getLongExtra("account", -1);
onActionMoveSelectionAccount(account, result.targets.get(account), result.folders, null); onActionMoveSelectionAccount(account, result.folders);
return true; return true;
default: default:
return false; return false;
@ -1718,63 +1658,14 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
}.execute(FragmentMessages.this, args, "messages:seen"); }.execute(FragmentMessages.this, args, "messages:seen");
} }
private void onActionSnoozeSelection(final Long id) { private void onActionSnoozeSelection() {
DialogDuration.show(getContext(), getViewLifecycleOwner(), R.string.title_snooze, Bundle args = new Bundle();
new DialogDuration.IDialogDuration() { args.putString("title", getString(R.string.title_snooze));
@Override
public void onDurationSelected(long duration, long time) {
if (!Helper.isPro(getContext())) {
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(getContext());
lbm.sendBroadcast(new Intent(ActivityView.ACTION_SHOW_PRO));
return;
}
Bundle args = new Bundle();
args.putLongArray("ids", id == null ? getSelection() : new long[]{id});
args.putLong("wakeup", duration == 0 ? -1 : time);
selectionTracker.clearSelection();
new SimpleTask<Void>() {
@Override
protected Void onExecute(Context context, Bundle args) {
long[] ids = args.getLongArray("ids");
Long wakeup = args.getLong("wakeup");
if (wakeup < 0)
wakeup = null;
DB db = DB.getInstance(context);
try {
db.beginTransaction();
for (long id : ids) {
EntityMessage message = db.message().getMessage(id);
if (message != null) {
List<EntityMessage> messages = db.message().getMessageByThread(
message.account, message.thread, threading ? null : id, message.folder);
for (EntityMessage threaded : messages) {
db.message().setMessageSnoozed(threaded.id, wakeup);
EntityMessage.snooze(context, threaded.id, wakeup);
EntityOperation.queue(context, threaded, EntityOperation.SEEN, true);
}
}
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
return null;
}
@Override FragmentDuration fragment = new FragmentDuration();
protected void onException(Bundle args, Throwable ex) { fragment.setArguments(args);
Helper.unexpectedError(getContext(), getViewLifecycleOwner(), ex); fragment.setTargetFragment(this, REQUEST_MESSAGES_SNOOZE);
} fragment.show(getFragmentManager(), "messages:snooze");
}.execute(FragmentMessages.this, args, "messages:snooze");
}
});
} }
private void onActionFlagSelection(boolean flagged, Integer color) { private void onActionFlagSelection(boolean flagged, Integer color) {
@ -1947,22 +1838,21 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
}.execute(FragmentMessages.this, args, "messages:move"); }.execute(FragmentMessages.this, args, "messages:move");
} }
private void onActionMoveSelectionAccount(long account, List<TupleFolderEx> folders, List<Long> disabled, final Long id) { private void onActionMoveSelectionAccount(long account, List<Long> disabled) {
DialogFolder.show( Bundle args = new Bundle();
getContext(), getViewLifecycleOwner(), view, args.putString("title", getString(R.string.title_move_to_folder));
R.string.title_move_to_folder, args.putLong("account", account);
account, disabled, args.putLongArray("disabled", Helper.toLongArray(disabled));
new DialogFolder.IDialogFolder() {
@Override FragmentSelectFolder fragment = new FragmentSelectFolder();
public void onFolderSelected(TupleFolderEx folder) { fragment.setArguments(args);
onActionMoveSelection(folder.id, id); fragment.setTargetFragment(FragmentMessages.this, FragmentMessages.REQUEST_MESSAGES_MOVE);
} fragment.show(getFragmentManager(), "messages:move");
});
} }
private void onActionMoveSelection(long target, Long id) { private void onActionMoveSelection(long target) {
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putLongArray("ids", id == null ? getSelection() : new long[]{id}); args.putLongArray("ids", getSelection());
args.putLong("target", target); args.putLong("target", target);
new SimpleTask<ArrayList<MessageTarget>>() { new SimpleTask<ArrayList<MessageTarget>>() {
@ -3688,6 +3578,32 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
onActionFlagSelection(true, color); onActionFlagSelection(true, color);
} }
break; break;
case REQUEST_MESSAGE_SNOOZE:
if (resultCode == RESULT_OK && data != null)
onSnooze(data.getBundleExtra("args"));
break;
case REQUEST_MESSAGES_SNOOZE:
if (resultCode == RESULT_OK && data != null)
onSnoozeSelection(data.getBundleExtra("args"));
break;
case REQUEST_MESSAGE_MOVE:
if (resultCode == RESULT_OK && data != null)
onMove(data.getBundleExtra("args"));
break;
case REQUEST_MESSAGES_MOVE:
if (resultCode == RESULT_OK && data != null) {
Bundle args = data.getBundleExtra("args");
onActionMoveSelection(args.getLong("folder"));
}
break;
case REQUEST_SEARCH:
if (resultCode == RESULT_OK && data != null) {
Bundle args = data.getBundleExtra("args");
search(
getContext(), getViewLifecycleOwner(), getFragmentManager(),
args.getLong("folder"), true, args.getString("query"));
}
break;
} }
} }
@ -3727,6 +3643,150 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
}.execute(FragmentMessages.this, args, "messages:delete:execute"); }.execute(FragmentMessages.this, args, "messages:delete:execute");
} }
private void onSnooze(Bundle args) {
if (!Helper.isPro(getContext())) {
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(getContext());
lbm.sendBroadcast(new Intent(ActivityView.ACTION_SHOW_PRO));
return;
}
long duration = args.getLong("duration");
long time = args.getLong("time");
args.putLong("wakeup", duration == 0 ? -1 : time);
new SimpleTask<Long>() {
@Override
protected Long onExecute(Context context, Bundle args) {
long account = args.getLong("account");
String thread = args.getString("thread");
long id = args.getLong("id");
Long wakeup = args.getLong("wakeup");
if (wakeup < 0)
wakeup = null;
DB db = DB.getInstance(context);
try {
db.beginTransaction();
List<EntityMessage> messages = db.message().getMessageByThread(
account, thread, threading ? null : id, null);
for (EntityMessage threaded : messages) {
db.message().setMessageSnoozed(threaded.id, wakeup);
EntityMessage.snooze(context, threaded.id, wakeup);
EntityOperation.queue(context, threaded, EntityOperation.SEEN, true);
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
return wakeup;
}
@Override
protected void onExecuted(Bundle args, Long wakeup) {
if (wakeup != null && args.getBoolean("finish"))
finish();
}
@Override
protected void onException(Bundle args, Throwable ex) {
Helper.unexpectedError(getContext(), getViewLifecycleOwner(), ex);
}
}.execute(getContext(), getViewLifecycleOwner(), args, "message:snooze");
}
private void onSnoozeSelection(Bundle args) {
if (!Helper.isPro(getContext())) {
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(getContext());
lbm.sendBroadcast(new Intent(ActivityView.ACTION_SHOW_PRO));
return;
}
long duration = args.getLong("duration");
long time = args.getLong("time");
args.putLong("wakeup", duration == 0 ? -1 : time);
args.putLongArray("ids", getSelection());
selectionTracker.clearSelection();
new SimpleTask<Void>() {
@Override
protected Void onExecute(Context context, Bundle args) {
long[] ids = args.getLongArray("ids");
Long wakeup = args.getLong("wakeup");
if (wakeup < 0)
wakeup = null;
DB db = DB.getInstance(context);
try {
db.beginTransaction();
for (long id : ids) {
EntityMessage message = db.message().getMessage(id);
if (message != null) {
List<EntityMessage> messages = db.message().getMessageByThread(
message.account, message.thread, threading ? null : id, message.folder);
for (EntityMessage threaded : messages) {
db.message().setMessageSnoozed(threaded.id, wakeup);
EntityMessage.snooze(context, threaded.id, wakeup);
EntityOperation.queue(context, threaded, EntityOperation.SEEN, true);
}
}
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
return null;
}
@Override
protected void onException(Bundle args, Throwable ex) {
Helper.unexpectedError(getContext(), getViewLifecycleOwner(), ex);
}
}.execute(FragmentMessages.this, args, "messages:snooze");
}
private void onMove(Bundle args) {
new SimpleTask<Void>() {
@Override
protected Void onExecute(Context context, Bundle args) {
long id = args.getLong("message");
boolean copy = args.getBoolean("copy");
long target = args.getLong("folder");
DB db = DB.getInstance(context);
try {
db.beginTransaction();
EntityMessage message = db.message().getMessage(id);
if (message == null)
return null;
if (copy)
EntityOperation.queue(context, message, EntityOperation.COPY, target);
else
EntityOperation.queue(context, message, EntityOperation.MOVE, target);
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
return null;
}
@Override
protected void onException(Bundle args, Throwable ex) {
Helper.unexpectedError(getContext(), getViewLifecycleOwner(), ex);
}
}.execute(getContext(), getViewLifecycleOwner(), args, "message:copy");
}
private void saveRaw(Intent data) { private void saveRaw(Intent data) {
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putLong("id", message); args.putLong("id", message);
@ -4024,7 +4084,6 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
Boolean isDrafts; Boolean isDrafts;
List<Long> folders; List<Long> folders;
List<EntityAccount> accounts; List<EntityAccount> accounts;
Map<Long, List<TupleFolderEx>> targets = new HashMap<>();
} }
private static class MessageTarget implements Parcelable { private static class MessageTarget implements Parcelable {

@ -0,0 +1,142 @@
package eu.faircode.email;
/*
This file is part of FairEmail.
FairEmail is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
FairEmail is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with FairEmail. If not, see <http://www.gnu.org/licenses/>.
Copyright 2018-2019 by Marcel Bokhorst (M66B)
*/
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
import static android.app.Activity.RESULT_CANCELED;
import static android.app.Activity.RESULT_OK;
public class FragmentSelectFolder extends DialogFragment {
private TwoStateOwner owner = new TwoStateOwner("folder:select");
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
String title = getArguments().getString("title");
final View dview = LayoutInflater.from(getContext()).inflate(R.layout.dialog_folder_select, null);
final RecyclerView rvFolder = dview.findViewById(R.id.rvFolder);
final ContentLoadingProgressBar pbWait = dview.findViewById(R.id.pbWait);
rvFolder.setHasFixedSize(false);
LinearLayoutManager llm = new LinearLayoutManager(getContext());
rvFolder.setLayoutManager(llm);
rvFolder.setVisibility(View.GONE);
pbWait.setVisibility(View.VISIBLE);
Bundle args = new Bundle();
args.putLong("account", getArguments().getLong("account"));
new SimpleTask<List<TupleFolderEx>>() {
@Override
protected List<TupleFolderEx> onExecute(Context context, Bundle args) {
long account = args.getLong("account");
DB db = DB.getInstance(context);
return db.folder().getFoldersEx(account);
}
@Override
protected void onExecuted(final Bundle args, List<TupleFolderEx> folders) {
if (folders == null)
folders = new ArrayList<>();
long account = args.getLong("account");
AdapterFolder adapter = new AdapterFolder(getContext(), owner, getView(), account, false,
new AdapterFolder.IFolderSelectedListener() {
@Override
public void onFolderSelected(TupleFolderEx folder) {
dismiss();
sendResult(RESULT_OK, folder.id);
}
});
rvFolder.setAdapter(adapter);
adapter.setDisabled(Helper.fromLongArray(getArguments().getLongArray("disabled")));
adapter.set(folders);
pbWait.setVisibility(View.GONE);
rvFolder.setVisibility(View.VISIBLE);
}
@Override
protected void onException(Bundle args, Throwable ex) {
Helper.unexpectedError(getContext(), owner, ex);
}
}.execute(getContext(), owner, args, "folder:select");
return new AlertDialog.Builder(getContext())
.setTitle(title)
.setView(dview)
.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialogInterface) {
sendResult(RESULT_CANCELED, -1);
}
})
.create();
}
@Override
public void onStart() {
super.onStart();
Log.i("Folder select resume");
owner.resume();
}
@Override
public void onDestroyView() {
Log.i("Folder select destroy");
owner.destroy();
super.onDestroyView();
}
private void sendResult(int result, long folder) {
Bundle args = getArguments();
args.putLong("folder", folder);
Fragment target = getTargetFragment();
if (target != null) {
Intent data = new Intent();
data.putExtra("args", args);
target.onActivityResult(getTargetRequestCode(), result, data);
}
}
}

@ -69,6 +69,10 @@ public class TwoStateOwner implements LifecycleOwner {
registry.setCurrentState(Lifecycle.State.STARTED); registry.setCurrentState(Lifecycle.State.STARTED);
} }
void resume() {
registry.setCurrentState(Lifecycle.State.RESUMED);
}
void stop() { void stop() {
registry.setCurrentState(Lifecycle.State.CREATED); registry.setCurrentState(Lifecycle.State.CREATED);
} }

Loading…
Cancel
Save