Added download attachments before reply

pull/215/head
M66B 7 months ago
parent 9e83ca7bd8
commit 7704024ba0

@ -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<Long> 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<Void>() {
@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<Long> download = Helper.fromLongArray(args.getLongArray("download"));
DB db = DB.getInstance(context);
EntityMessage message = db.message().getMessage(id);
if (message == null)
return null;
List<EntityAttachment> 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<List<EntityAttachment>>() {
@Override
public void onChanged(List<EntityAttachment> 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);
}
}
};
}

@ -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<List<Long>>() {
@Override
protected List<Long> onExecute(Context context, Bundle args) {
long id = args.getLong("id");
List<Long> download = new ArrayList<>();
DB db = DB.getInstance(context);
List<EntityAttachment> 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<Long> 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) {

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fadeScrollbars="false"
android:padding="24dp"
android:scrollbarStyle="outsideOverlay">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableStart="@drawable/twotone_attachment_24"
android:drawablePadding="6dp"
android:text="@string/title_download_attachments"
android:textAppearance="@style/TextAppearance.AppCompat.Large"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tvRemark"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/title_attachments_missing"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textStyle="italic"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvTitle" />
<Button
android:id="@+id/btnDownload"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:drawableEnd="@drawable/twotone_cloud_download_24"
android:drawablePadding="6dp"
android:text="@string/title_download"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvRemark" />
<ProgressBar
android:id="@+id/pbDownloaded"
style="@android:style/Widget.ProgressBar.Horizontal"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:progress="25"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btnDownload" />
<TextView
android:id="@+id/tvRemaining"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/title_attachments_download"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textColor="?android:attr/textColorPrimary"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/pbDownloaded" />
<TextView
android:id="@+id/tvNoInternet"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:drawableStart="@drawable/twotone_warning_24"
android:drawablePadding="6dp"
android:text="@string/title_no_internet"
android:textAlignment="center"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textColor="?attr/colorWarning"
app:drawableTint="?attr/colorWarning"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvRemaining" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>

@ -1841,6 +1841,8 @@
<string name="title_dsn_reminder">Hard bounces damage the email reputation of the original sender!</string>
<string name="title_size_reminder">Message (%1$s) larger than server limit (%2$s)</string>
<string name="title_attachments_missing">Not all attachments have been downloaded</string>
<string name="title_download_attachments">Download attachments</string>
<string name="title_attachments_download">Attachments downloaded: %1$s</string>
<string name="title_dialog_hint">This dialog can be enabled again via the three-dots menu in the top action bar</string>
<string name="title_draft_deleted">Draft discarded</string>
<string name="title_draft_saved">Draft saved</string>

Loading…
Cancel
Save