|
|
@ -98,6 +98,7 @@ import androidx.appcompat.app.AlertDialog;
|
|
|
|
import androidx.appcompat.widget.PopupMenu;
|
|
|
|
import androidx.appcompat.widget.PopupMenu;
|
|
|
|
import androidx.constraintlayout.widget.Group;
|
|
|
|
import androidx.constraintlayout.widget.Group;
|
|
|
|
import androidx.core.content.ContextCompat;
|
|
|
|
import androidx.core.content.ContextCompat;
|
|
|
|
|
|
|
|
import androidx.core.content.FileProvider;
|
|
|
|
import androidx.core.graphics.ColorUtils;
|
|
|
|
import androidx.core.graphics.ColorUtils;
|
|
|
|
import androidx.core.view.MenuItemCompat;
|
|
|
|
import androidx.core.view.MenuItemCompat;
|
|
|
|
import androidx.fragment.app.FragmentActivity;
|
|
|
|
import androidx.fragment.app.FragmentActivity;
|
|
|
@ -106,6 +107,7 @@ import androidx.fragment.app.FragmentResultListener;
|
|
|
|
import androidx.fragment.app.FragmentTransaction;
|
|
|
|
import androidx.fragment.app.FragmentTransaction;
|
|
|
|
import androidx.lifecycle.Lifecycle;
|
|
|
|
import androidx.lifecycle.Lifecycle;
|
|
|
|
import androidx.lifecycle.LifecycleOwner;
|
|
|
|
import androidx.lifecycle.LifecycleOwner;
|
|
|
|
|
|
|
|
import androidx.lifecycle.LiveData;
|
|
|
|
import androidx.lifecycle.Observer;
|
|
|
|
import androidx.lifecycle.Observer;
|
|
|
|
import androidx.lifecycle.ViewModelProvider;
|
|
|
|
import androidx.lifecycle.ViewModelProvider;
|
|
|
|
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
|
|
|
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
|
|
@ -2645,6 +2647,11 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
|
|
|
|
if (message == null)
|
|
|
|
if (message == null)
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
result.count++;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (message.raw != null && message.raw)
|
|
|
|
|
|
|
|
result.raw++;
|
|
|
|
|
|
|
|
|
|
|
|
EntityAccount account = accounts.get(message.account);
|
|
|
|
EntityAccount account = accounts.get(message.account);
|
|
|
|
if (account == null) {
|
|
|
|
if (account == null) {
|
|
|
|
account = db.account().getAccount(message.account);
|
|
|
|
account = db.account().getAccount(message.account);
|
|
|
@ -2816,6 +2823,9 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
|
|
|
|
if (result.hasJunk && !result.isJunk && !result.isDrafts) // has junk and not junk/drafts
|
|
|
|
if (result.hasJunk && !result.isJunk && !result.isDrafts) // has junk and not junk/drafts
|
|
|
|
popupMenu.getMenu().add(Menu.NONE, R.string.title_spam, order++, R.string.title_spam);
|
|
|
|
popupMenu.getMenu().add(Menu.NONE, R.string.title_spam, order++, R.string.title_spam);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (result.accounts.size() > 0 /* IMAP */ && BuildConfig.DEBUG)
|
|
|
|
|
|
|
|
popupMenu.getMenu().add(Menu.NONE, R.string.title_raw_send, order++, R.string.title_raw_send);
|
|
|
|
|
|
|
|
|
|
|
|
for (EntityAccount account : result.accounts) {
|
|
|
|
for (EntityAccount account : result.accounts) {
|
|
|
|
String title = getString(R.string.title_move_to_account, account.name);
|
|
|
|
String title = getString(R.string.title_move_to_account, account.name);
|
|
|
|
SpannableString ss = new SpannableString(title);
|
|
|
|
SpannableString ss = new SpannableString(title);
|
|
|
@ -2882,6 +2892,9 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
|
|
|
|
} else if (itemId == R.string.title_spam) {
|
|
|
|
} else if (itemId == R.string.title_spam) {
|
|
|
|
onActionJunkSelection();
|
|
|
|
onActionJunkSelection();
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
|
|
|
|
|
} else if (itemId == R.string.title_raw_send) {
|
|
|
|
|
|
|
|
onActionRaw();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
} else if (itemId == R.string.title_move_to_account) {
|
|
|
|
} else if (itemId == R.string.title_move_to_account) {
|
|
|
|
long account = target.getIntent().getLongExtra("account", -1);
|
|
|
|
long account = target.getIntent().getLongExtra("account", -1);
|
|
|
|
onActionMoveSelectionAccount(account, false, result.folders);
|
|
|
|
onActionMoveSelectionAccount(account, false, result.folders);
|
|
|
@ -3298,6 +3311,105 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
|
|
|
|
}.execute(this, args, "messages:move");
|
|
|
|
}.execute(this, args, "messages:move");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void onActionRaw() {
|
|
|
|
|
|
|
|
Bundle args = new Bundle();
|
|
|
|
|
|
|
|
args.putLongArray("ids", getSelection());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
selectionTracker.clearSelection();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
new SimpleTask<Integer>() {
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
protected Integer onExecute(Context context, Bundle args) {
|
|
|
|
|
|
|
|
long[] ids = args.getLongArray("ids");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int count = 0;
|
|
|
|
|
|
|
|
DB db = DB.getInstance(context);
|
|
|
|
|
|
|
|
for (long id : ids) {
|
|
|
|
|
|
|
|
EntityMessage message = db.message().getMessage(id);
|
|
|
|
|
|
|
|
if (message == null)
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (message.raw == null || !message.raw) {
|
|
|
|
|
|
|
|
count++;
|
|
|
|
|
|
|
|
EntityOperation.queue(context, message, EntityOperation.RAW);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return count;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
protected void onExecuted(Bundle args, Integer count) {
|
|
|
|
|
|
|
|
long[] ids = args.getLongArray("ids");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (count == 0) {
|
|
|
|
|
|
|
|
send(ids);
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
final Context context = getContext();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LayoutInflater inflator = LayoutInflater.from(context);
|
|
|
|
|
|
|
|
View dview = inflator.inflate(R.layout.dialog_forward, null);
|
|
|
|
|
|
|
|
TextView tvMessages = dview.findViewById(R.id.tvMessages);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tvMessages.setText(null);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
final AlertDialog dialog = new AlertDialog.Builder(context)
|
|
|
|
|
|
|
|
.setView(dview)
|
|
|
|
|
|
|
|
.setNegativeButton(android.R.string.cancel, null)
|
|
|
|
|
|
|
|
.show();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DB db = DB.getInstance(context);
|
|
|
|
|
|
|
|
final LiveData<Integer> ld = db.message().liveRaw(ids);
|
|
|
|
|
|
|
|
ld.observe(getViewLifecycleOwner(), new Observer<Integer>() {
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
public void onChanged(Integer remaining) {
|
|
|
|
|
|
|
|
if (remaining == null)
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tvMessages.setText(getResources().getQuantityString(R.plurals.title_moving_messages, remaining, remaining));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (remaining == 0) {
|
|
|
|
|
|
|
|
ld.removeObserver(this);
|
|
|
|
|
|
|
|
dialog.dismiss();
|
|
|
|
|
|
|
|
send(ids);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
protected void onException(Bundle args, Throwable ex) {
|
|
|
|
|
|
|
|
Log.unexpectedError(getParentFragmentManager(), ex);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void send(long[] ids) {
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
final Context context = getContext();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ArrayList<Uri> uris = new ArrayList<>();
|
|
|
|
|
|
|
|
for (long id : ids) {
|
|
|
|
|
|
|
|
File file = EntityMessage.getRawFile(context, id);
|
|
|
|
|
|
|
|
Uri uri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID, file);
|
|
|
|
|
|
|
|
uris.add(uri);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Intent send = new Intent(Intent.ACTION_SEND_MULTIPLE);
|
|
|
|
|
|
|
|
send.setPackage(BuildConfig.APPLICATION_ID);
|
|
|
|
|
|
|
|
send.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
|
|
|
|
|
|
|
|
send.setType("message/rfc822");
|
|
|
|
|
|
|
|
send.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
context.startActivity(send);
|
|
|
|
|
|
|
|
} catch (Throwable ex) {
|
|
|
|
|
|
|
|
// java.lang.IllegalArgumentException: Failed to resolve canonical path for ...
|
|
|
|
|
|
|
|
Log.unexpectedError(getParentFragmentManager(), ex);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}.execute(this, args, "messages:forward");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void onActionMoveSelectionAccount(long account, boolean copy, List<Long> disabled) {
|
|
|
|
private void onActionMoveSelectionAccount(long account, boolean copy, List<Long> disabled) {
|
|
|
|
Bundle args = new Bundle();
|
|
|
|
Bundle args = new Bundle();
|
|
|
|
args.putString("title", getString(copy ? R.string.title_copy_to : R.string.title_move_to_folder));
|
|
|
|
args.putString("title", getString(copy ? R.string.title_copy_to : R.string.title_move_to_folder));
|
|
|
@ -7804,6 +7916,8 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private class MoreResult {
|
|
|
|
private class MoreResult {
|
|
|
|
|
|
|
|
int count;
|
|
|
|
|
|
|
|
int raw;
|
|
|
|
boolean seen;
|
|
|
|
boolean seen;
|
|
|
|
boolean unseen;
|
|
|
|
boolean unseen;
|
|
|
|
boolean visible;
|
|
|
|
boolean visible;
|
|
|
|