diff --git a/res/drawable-hdpi/ic_download_32.png b/res/drawable-hdpi/ic_download_32.png
new file mode 100644
index 0000000000..38e7786c2b
Binary files /dev/null and b/res/drawable-hdpi/ic_download_32.png differ
diff --git a/res/drawable-mdpi/ic_download_32.png b/res/drawable-mdpi/ic_download_32.png
new file mode 100644
index 0000000000..072e14daa4
Binary files /dev/null and b/res/drawable-mdpi/ic_download_32.png differ
diff --git a/res/drawable-xhdpi/ic_download_32.png b/res/drawable-xhdpi/ic_download_32.png
new file mode 100644
index 0000000000..7013c3149e
Binary files /dev/null and b/res/drawable-xhdpi/ic_download_32.png differ
diff --git a/res/drawable-xxhdpi/ic_download_32.png b/res/drawable-xxhdpi/ic_download_32.png
new file mode 100644
index 0000000000..c5c64063db
Binary files /dev/null and b/res/drawable-xxhdpi/ic_download_32.png differ
diff --git a/res/drawable-xxxhdpi/ic_download_32.png b/res/drawable-xxxhdpi/ic_download_32.png
new file mode 100644
index 0000000000..d6972b48a8
Binary files /dev/null and b/res/drawable-xxxhdpi/ic_download_32.png differ
diff --git a/res/layout/image_editor_hud.xml b/res/layout/image_editor_hud.xml
index d78afa6686..4ebafacaca 100644
--- a/res/layout/image_editor_hud.xml
+++ b/res/layout/image_editor_hud.xml
@@ -22,6 +22,7 @@
android:layout_marginTop="8dp"
android:layout_marginEnd="10dp"
android:orientation="horizontal"
+ android:gravity="center_vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent">
@@ -41,6 +42,14 @@
android:padding="8dp"
android:src="@drawable/ic_undo_32" />
+
+
{
dialog = new AlertDialog.Builder(new ContextThemeWrapper(MediaSendActivity.this, R.style.TextSecure_MediaSendProgressDialog))
- .setView(R.layout.progress_dialog)
- .setCancelable(false)
- .create();
+ .setView(R.layout.progress_dialog)
+ .setCancelable(false)
+ .create();
dialog.show();
dialog.getWindow().setLayout(getResources().getDimensionPixelSize(R.dimen.mediasend_progress_dialog_size),
- getResources().getDimensionPixelSize(R.dimen.mediasend_progress_dialog_size));
+ getResources().getDimensionPixelSize(R.dimen.mediasend_progress_dialog_size));
};
Util.runOnMainDelayed(progressTimer, 250);
}
diff --git a/src/org/thoughtcrime/securesms/scribbles/ImageEditorFragment.java b/src/org/thoughtcrime/securesms/scribbles/ImageEditorFragment.java
index fe7cb36d80..50ab3041ad 100644
--- a/src/org/thoughtcrime/securesms/scribbles/ImageEditorFragment.java
+++ b/src/org/thoughtcrime/securesms/scribbles/ImageEditorFragment.java
@@ -1,6 +1,8 @@
package org.thoughtcrime.securesms.scribbles;
+import android.Manifest;
import android.content.Intent;
+import android.graphics.Bitmap;
import android.graphics.Paint;
import android.net.Uri;
import android.os.Bundle;
@@ -10,6 +12,7 @@ import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.Toast;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.imageeditor.ColorableRenderer;
@@ -22,9 +25,18 @@ import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.mediasend.MediaSendPageFragment;
import org.thoughtcrime.securesms.mms.MediaConstraints;
import org.thoughtcrime.securesms.mms.PushMediaConstraints;
+import org.thoughtcrime.securesms.permissions.Permissions;
+import org.thoughtcrime.securesms.providers.BlobProvider;
import org.thoughtcrime.securesms.scribbles.widget.VerticalSlideColorPicker;
+import org.thoughtcrime.securesms.util.MediaUtil;
import org.thoughtcrime.securesms.util.ParcelUtil;
+import org.thoughtcrime.securesms.util.SaveAttachmentTask;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
+import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
+import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
import static android.app.Activity.RESULT_OK;
@@ -287,6 +299,36 @@ public final class ImageEditorFragment extends Fragment implements ImageEditorHu
refreshUniqueColors();
}
+ @Override
+ public void onSave() {
+ SaveAttachmentTask.showWarningDialog(requireContext(), (dialogInterface, i) -> {
+ Permissions.with(this)
+ .request(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE)
+ .ifNecessary()
+ .withPermanentDenialDialog(getString(R.string.MediaPreviewActivity_signal_needs_the_storage_permission_in_order_to_write_to_external_storage_but_it_has_been_permanently_denied))
+ .onAnyDenied(() -> Toast.makeText(requireContext(), R.string.MediaPreviewActivity_unable_to_write_to_external_storage_without_permission, Toast.LENGTH_LONG).show())
+ .onAllGranted(() -> {
+ SimpleTask.run(() -> {
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ Bitmap image = imageEditorView.getModel().render(requireContext());
+
+ image.compress(Bitmap.CompressFormat.JPEG, 80, outputStream);
+
+ return BlobProvider.getInstance()
+ .forData(outputStream.toByteArray())
+ .withMimeType(MediaUtil.IMAGE_JPEG)
+ .createForSingleUseInMemory();
+
+ }, uri -> {
+ SaveAttachmentTask saveTask = new SaveAttachmentTask(requireContext());
+ SaveAttachmentTask.Attachment attachment = new SaveAttachmentTask.Attachment(uri, MediaUtil.IMAGE_JPEG, System.currentTimeMillis(), null);
+ saveTask.executeOnExecutor(SignalExecutors.BOUNDED, attachment);
+ });
+ })
+ .execute();
+ });
+ }
+
@Override
public void onFlipHorizontal() {
imageEditorView.getModel().flipHorizontal();
diff --git a/src/org/thoughtcrime/securesms/scribbles/ImageEditorHud.java b/src/org/thoughtcrime/securesms/scribbles/ImageEditorHud.java
index 85ada5c0a1..efc062b14d 100644
--- a/src/org/thoughtcrime/securesms/scribbles/ImageEditorHud.java
+++ b/src/org/thoughtcrime/securesms/scribbles/ImageEditorHud.java
@@ -36,6 +36,7 @@ public final class ImageEditorHud extends LinearLayout {
private View textButton;
private View stickerButton;
private View undoButton;
+ private View saveButton;
private View deleteButton;
private View confirmButton;
private VerticalSlideColorPicker colorPicker;
@@ -81,6 +82,7 @@ public final class ImageEditorHud extends LinearLayout {
textButton = findViewById(R.id.scribble_text_button);
stickerButton = findViewById(R.id.scribble_sticker_button);
undoButton = findViewById(R.id.scribble_undo_button);
+ saveButton = findViewById(R.id.scribble_save_button);
deleteButton = findViewById(R.id.scribble_delete_button);
confirmButton = findViewById(R.id.scribble_confirm_button);
colorPicker = findViewById(R.id.scribble_color_picker);
@@ -100,7 +102,7 @@ public final class ImageEditorHud extends LinearLayout {
}
private void initializeVisibilityMap() {
- setVisibleViewsWhenInMode(Mode.NONE, drawButton, highlightButton, textButton, stickerButton, cropButton, undoButton);
+ setVisibleViewsWhenInMode(Mode.NONE, drawButton, highlightButton, textButton, stickerButton, cropButton, undoButton, saveButton);
setVisibleViewsWhenInMode(Mode.DRAW, confirmButton, undoButton, colorPicker, colorPalette);
@@ -145,6 +147,7 @@ public final class ImageEditorHud extends LinearLayout {
highlightButton.setOnClickListener(v -> setMode(Mode.HIGHLIGHT));
textButton.setOnClickListener(v -> setMode(Mode.TEXT));
stickerButton.setOnClickListener(v -> setMode(Mode.MOVE_DELETE));
+ saveButton.setOnClickListener(v -> eventListener.onSave());
}
public void setColorPalette(@NonNull Set colors) {
@@ -241,6 +244,7 @@ public final class ImageEditorHud extends LinearLayout {
void onColorChange(int color);
void onUndo();
void onDelete();
+ void onSave();
void onFlipHorizontal();
void onRotate90AntiClockwise();
void onCropAspectLock(boolean locked);
@@ -266,6 +270,10 @@ public final class ImageEditorHud extends LinearLayout {
public void onDelete() {
}
+ @Override
+ public void onSave() {
+ }
+
@Override
public void onFlipHorizontal() {
}