diff --git a/app/src/main/java/eu/faircode/email/FragmentDialogDownloadAttachments.java b/app/src/main/java/eu/faircode/email/FragmentDialogDownloadAttachments.java new file mode 100644 index 0000000000..4168b012bc --- /dev/null +++ b/app/src/main/java/eu/faircode/email/FragmentDialogDownloadAttachments.java @@ -0,0 +1,226 @@ +package eu.faircode.email; + +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.net.ConnectivityManager; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkRequest; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.Button; +import android.widget.ProgressBar; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AlertDialog; +import androidx.lifecycle.Lifecycle; +import androidx.lifecycle.Observer; + +import java.text.NumberFormat; +import java.util.ArrayList; +import java.util.List; + +public class FragmentDialogDownloadAttachments extends FragmentDialogBase { + private List remaining; + + @NonNull + @Override + public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { + Bundle args = getArguments(); + long id = args.getLong("id"); + long[] download = args.getLongArray("download"); + Intent intent = args.getParcelable("intent"); + + final Context context = getContext(); + View dview = LayoutInflater.from(context).inflate(R.layout.dialog_download_attachments, null); + TextView tvRemark = dview.findViewById(R.id.tvRemark); + Button btnDownload = dview.findViewById(R.id.btnDownload); + ProgressBar pbDownloaded = dview.findViewById(R.id.pbDownloaded); + TextView tvRemaining = dview.findViewById(R.id.tvRemaining); + + NumberFormat NF = NumberFormat.getNumberInstance(); + + btnDownload.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + new SimpleTask() { + @Override + protected void onPreExecute(Bundle args) { + tvRemark.setVisibility(View.GONE); + btnDownload.setVisibility(View.GONE); + pbDownloaded.setVisibility(View.VISIBLE); + tvRemaining.setVisibility(View.VISIBLE); + } + + @Override + protected Void onExecute(Context context, Bundle args) { + long id = args.getLong("id"); + List download = Helper.fromLongArray(args.getLongArray("download")); + + DB db = DB.getInstance(context); + EntityMessage message = db.message().getMessage(id); + if (message == null) + return null; + + List attachments = db.attachment().getAttachments(message.id); + if (attachments != null) + for (EntityAttachment attachment : attachments) + if (download.contains(attachment.id)) + EntityOperation.queue(context, message, EntityOperation.ATTACHMENT, attachment.id); + + return null; + } + + @Override + protected void onExecuted(Bundle args, Void data) { + long id = args.getLong("id"); + long[] download = args.getLongArray("download"); + + DB db = DB.getInstance(context); + db.attachment().liveAttachments(id).observe(getViewLifecycleOwner(), new Observer>() { + @Override + public void onChanged(List attachments) { + if (attachments != null) + for (EntityAttachment attachment : attachments) + if (attachment.available && remaining.contains(attachment.id)) + remaining.remove(attachment.id); + + pbDownloaded.setProgress(download.length - remaining.size()); + + String of = getString(R.string.title_of, + NF.format(download.length - remaining.size()), + NF.format(download.length)); + tvRemaining.setText(getString(R.string.title_attachments_download, of)); + + updateButton(); + } + }); + } + + @Override + protected void onException(Bundle args, Throwable ex) { + Log.unexpectedError(getParentFragment(), ex); + } + }.execute(FragmentDialogDownloadAttachments.this, args, "download"); + } + }); + + if (savedInstanceState == null) + remaining = Helper.fromLongArray(download); + else { + long[] r = savedInstanceState.getLongArray("fair:remaining"); + remaining = (r == null ? new ArrayList<>() : Helper.fromLongArray(r)); + } + + pbDownloaded.setMax(download.length); + pbDownloaded.setProgress(download.length - remaining.size()); + + String of = getString(R.string.title_of, + NF.format(download.length - remaining.size()), + NF.format(download.length)); + tvRemaining.setText(getString(R.string.title_attachments_download, of)); + + tvRemark.setVisibility(remaining.isEmpty() ? View.GONE : View.VISIBLE); + btnDownload.setVisibility(remaining.isEmpty() ? View.GONE : View.VISIBLE); + pbDownloaded.setVisibility(remaining.isEmpty() ? View.VISIBLE : View.GONE); + tvRemaining.setVisibility(remaining.isEmpty() ? View.VISIBLE : View.GONE); + + return new AlertDialog.Builder(context) + .setView(dview) + .setNegativeButton(R.string.title_dismiss, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + startActivity(intent); + } + }) + .create(); + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + checkInternet.run(); + } + + @Override + public void onStart() { + super.onStart(); + updateButton(); + } + + private void updateButton() { + Button btn = ((AlertDialog) getDialog()).getButton(AlertDialog.BUTTON_NEGATIVE); + if (btn != null) + btn.setText(remaining.isEmpty() ? android.R.string.ok : R.string.title_dismiss); + } + + @Override + public void onResume() { + super.onResume(); + + ConnectivityManager cm = Helper.getSystemService(getContext(), ConnectivityManager.class); + NetworkRequest.Builder builder = new NetworkRequest.Builder(); + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); + cm.registerNetworkCallback(builder.build(), networkCallback); + } + + @Override + public void onPause() { + super.onPause(); + + ConnectivityManager cm = Helper.getSystemService(getContext(), ConnectivityManager.class); + cm.unregisterNetworkCallback(networkCallback); + } + + @Override + public void onSaveInstanceState(@NonNull Bundle outState) { + outState.putLongArray("fair:remaining", Helper.toLongArray(remaining)); + super.onSaveInstanceState(outState); + } + + private final ConnectivityManager.NetworkCallback networkCallback = new ConnectivityManager.NetworkCallback() { + @Override + public void onAvailable(Network network) { + check(); + } + + @Override + public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) { + check(); + } + + @Override + public void onLost(Network network) { + check(); + } + + private void check() { + ApplicationEx.getMainHandler().post(new Runnable() { + @Override + public void run() { + if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) + checkInternet.run(); + } + }); + } + }; + + private final Runnable checkInternet = new Runnable() { + @Override + public void run() { + try { + ConnectionHelper.NetworkState state = + ConnectionHelper.getNetworkState(getContext()); + getDialog().findViewById(R.id.tvNoInternet).setVisibility( + state.isSuitable() ? View.GONE : View.VISIBLE); + } catch (Throwable ex) { + Log.e(ex); + } + } + }; +} diff --git a/app/src/main/java/eu/faircode/email/FragmentMessages.java b/app/src/main/java/eu/faircode/email/FragmentMessages.java index 9e42a4ce8f..99fa7ab4ac 100644 --- a/app/src/main/java/eu/faircode/email/FragmentMessages.java +++ b/app/src/main/java/eu/faircode/email/FragmentMessages.java @@ -4041,15 +4041,64 @@ public class FragmentMessages extends FragmentBase final Context context = getContext(); if (context == null) return; + if (!"reply".equals(action) && !"reply_all".equals(action) && !"list".equals(action)) selected = null; + Intent reply = new Intent(context, ActivityCompose.class) .putExtra("action", action) .putExtra("reference", message.id) .putExtra("selected", selected); - startActivity(reply); + + if ("reply".equals(action) || "reply_all".equals(action) || + "forward".equals(action) || + "resend".equals(action) || + "editasnew".equals(action)) { + Bundle args = new Bundle(); + args.putLong("id", message.id); + + new SimpleTask>() { + @Override + protected List onExecute(Context context, Bundle args) { + long id = args.getLong("id"); + List download = new ArrayList<>(); + + DB db = DB.getInstance(context); + List attachments = db.attachment().getAttachments(id); + if (attachments != null) + for (EntityAttachment attachment : attachments) + if (!attachment.available && + attachment.subsequence == null && + !attachment.isEncryption()) + download.add(attachment.id); + + return download; + } + + @Override + protected void onExecuted(Bundle args, List download) { + if (download.isEmpty()) { + startActivity(reply); + return; + } + + args.putLongArray("download", Helper.toLongArray(download)); + args.putParcelable("intent", reply); + + FragmentDialogDownloadAttachments dialog = new FragmentDialogDownloadAttachments(); + dialog.setArguments(args); + dialog.show(getParentFragmentManager(), "message:attachments"); + } + + @Override + protected void onException(Bundle args, Throwable ex) { + Log.unexpectedError(getParentFragment(), ex); + } + }.execute(this, args, "message:attachments"); + } else + startActivity(reply); } private void onMenuResend(TupleMessageEx message) { diff --git a/app/src/main/res/layout/dialog_download_attachments.xml b/app/src/main/res/layout/dialog_download_attachments.xml new file mode 100644 index 0000000000..eaf9609738 --- /dev/null +++ b/app/src/main/res/layout/dialog_download_attachments.xml @@ -0,0 +1,84 @@ + + + + + + + + + +