mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-30 13:35:18 +00:00
parent
170a4291de
commit
238471b847
BIN
res/drawable-hdpi/ic_save_all_white_24dp.png
Normal file
BIN
res/drawable-hdpi/ic_save_all_white_24dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 404 B |
BIN
res/drawable-mdpi/ic_save_all_white_24dp.png
Normal file
BIN
res/drawable-mdpi/ic_save_all_white_24dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 314 B |
BIN
res/drawable-xhdpi/ic_save_all_white_24dp.png
Normal file
BIN
res/drawable-xhdpi/ic_save_all_white_24dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 472 B |
BIN
res/drawable-xxhdpi/ic_save_all_white_24dp.png
Normal file
BIN
res/drawable-xxhdpi/ic_save_all_white_24dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 647 B |
BIN
res/drawable-xxxhdpi/ic_save_all_white_24dp.png
Normal file
BIN
res/drawable-xxxhdpi/ic_save_all_white_24dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 789 B |
8
res/menu/media_overview.xml
Normal file
8
res/menu/media_overview.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item android:id="@+id/save"
|
||||
android:title="@string/media_overview__save_all"
|
||||
android:icon="@drawable/ic_save_all_white_24dp"
|
||||
app:showAsAction="ifRoom"/>
|
||||
</menu>
|
@ -161,12 +161,25 @@
|
||||
<item quantity="other">This will permanently delete all %1$d selected messages.</item>
|
||||
</plurals>
|
||||
<string name="ConversationFragment_save_to_sd_card">Save to storage?</string>
|
||||
<string name="ConversationFragment_saving_this_media_to_storage_warning">Saving this media to storage will allow any other apps on your device to access it.\n\nContinue?</string>
|
||||
<string name="ConversationFragment_error_while_saving_attachment_to_sd_card">Error while saving attachment to storage!</string>
|
||||
<plurals name="ConversationFragment_saving_n_media_to_storage_warning">
|
||||
<item quantity="one">Saving this media to storage will allow any other apps on your device to access it.\n\nContinue?</item>
|
||||
<item quantity="other">Saving all %1$d media to storage will allow any other apps on your device to access them.\n\nContinue?</item>
|
||||
</plurals>
|
||||
<plurals name="ConversationFragment_error_while_saving_attachments_to_sd_card">
|
||||
<item quantity="one">Error while saving attachment to storage!</item>
|
||||
<item quantity="other">Error while saving attachments to storage!</item>
|
||||
</plurals>
|
||||
<string name="ConversationFragment_success_exclamation">Success!</string>
|
||||
<string name="ConversationFragment_unable_to_write_to_sd_card_exclamation">Unable to write to storage!</string>
|
||||
<string name="ConversationFragment_saving_attachment">Saving attachment</string>
|
||||
<string name="ConversationFragment_saving_attachment_to_sd_card">Saving attachment to storage...</string>
|
||||
<plurals name="ConversationFragment_saving_n_attachments">
|
||||
<item quantity="one">Saving attachment</item>
|
||||
<item quantity="other">Saving %1$d attachments</item>
|
||||
</plurals>
|
||||
<plurals name="ConversationFragment_saving_n_attachments_to_sd_card">
|
||||
<item quantity="one">Saving attachment to storage...</item>
|
||||
<item quantity="other">Saving %1$d attachments to storage...</item>
|
||||
</plurals>
|
||||
<string name="ConversationFragment_collecting_attahments">Collecting attachments...</string>
|
||||
<string name="ConversationFragment_pending">Pending...</string>
|
||||
<string name="ConversationFragment_push">Data (Signal)</string>
|
||||
<string name="ConversationFragment_mms">MMS</string>
|
||||
@ -1165,6 +1178,9 @@
|
||||
<!-- media_preview -->
|
||||
<string name="media_preview__save_title">Save</string>
|
||||
|
||||
<!-- media_overview -->
|
||||
<string name="media_overview__save_all">Save all</string>
|
||||
|
||||
<!-- media_preview_activity -->
|
||||
<string name="media_preview_activity__image_content_description">Image preview</string>
|
||||
|
||||
|
@ -348,7 +348,9 @@ public class ConversationFragment extends Fragment
|
||||
}
|
||||
|
||||
Log.w(TAG, "No slide with attachable media found, failing nicely.");
|
||||
Toast.makeText(getActivity(), R.string.ConversationFragment_error_while_saving_attachment_to_sd_card, Toast.LENGTH_LONG).show();
|
||||
Toast.makeText(getActivity(),
|
||||
getResources().getQuantityString(R.plurals.ConversationFragment_error_while_saving_attachments_to_sd_card, 1),
|
||||
Toast.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ package org.thoughtcrime.securesms;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.res.Configuration;
|
||||
import android.database.Cursor;
|
||||
import android.os.Build.VERSION;
|
||||
@ -29,6 +30,8 @@ import android.support.v4.content.Loader;
|
||||
import android.support.v7.widget.GridLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
@ -37,11 +40,17 @@ import android.widget.TextView;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.ImageDatabase.ImageRecord;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient.RecipientModifiedListener;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||
import org.thoughtcrime.securesms.util.AbstractCursorLoader;
|
||||
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
||||
import org.thoughtcrime.securesms.util.SaveAttachmentTask;
|
||||
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Activity for displaying media attachments in-app
|
||||
@ -137,12 +146,62 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity i
|
||||
}
|
||||
}
|
||||
|
||||
private void saveToDisk() {
|
||||
final Context c = this;
|
||||
|
||||
SaveAttachmentTask.showWarningDialog(this, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
new ProgressDialogAsyncTask<Void, Void, List<SaveAttachmentTask.Attachment>>(c,
|
||||
R.string.ConversationFragment_collecting_attahments,
|
||||
R.string.please_wait) {
|
||||
@Override
|
||||
protected List<SaveAttachmentTask.Attachment> doInBackground(Void... params) {
|
||||
Cursor cursor = DatabaseFactory.getImageDatabase(c).getImagesForThread(threadId);
|
||||
List<SaveAttachmentTask.Attachment> attachments = new ArrayList<>(cursor.getCount());
|
||||
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
ImageRecord record = ImageRecord.from(cursor);
|
||||
attachments.add(new SaveAttachmentTask.Attachment(record.getAttachment().getDataUri(),
|
||||
record.getContentType(),
|
||||
record.getDate()));
|
||||
}
|
||||
|
||||
return attachments;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(List<SaveAttachmentTask.Attachment> attachments) {
|
||||
super.onPostExecute(attachments);
|
||||
|
||||
SaveAttachmentTask saveTask = new SaveAttachmentTask(c, masterSecret, attachments.size());
|
||||
saveTask.execute(attachments.toArray(new SaveAttachmentTask.Attachment[attachments.size()]));
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
}, gridView.getAdapter().getItemCount());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
super.onPrepareOptionsMenu(menu);
|
||||
|
||||
menu.clear();
|
||||
if (gridView.getAdapter() != null && gridView.getAdapter().getItemCount() > 0) {
|
||||
MenuInflater inflater = this.getMenuInflater();
|
||||
inflater.inflate(R.menu.media_overview, menu);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
super.onOptionsItemSelected(item);
|
||||
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home: finish(); return true;
|
||||
case R.id.save: saveToDisk(); return true;
|
||||
case android.R.id.home: finish(); return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -158,6 +217,7 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity i
|
||||
Log.w(TAG, "onLoadFinished()");
|
||||
gridView.setAdapter(new ImageMediaAdapter(this, masterSecret, cursor));
|
||||
noImages.setVisibility(gridView.getAdapter().getItemCount() > 0 ? View.GONE : View.VISIBLE);
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -33,18 +33,26 @@ public class SaveAttachmentTask extends ProgressDialogAsyncTask<SaveAttachmentTa
|
||||
private final WeakReference<Context> contextReference;
|
||||
private final WeakReference<MasterSecret> masterSecretReference;
|
||||
|
||||
private final int attachmentCount;
|
||||
|
||||
public SaveAttachmentTask(Context context, MasterSecret masterSecret) {
|
||||
super(context, R.string.ConversationFragment_saving_attachment, R.string.ConversationFragment_saving_attachment_to_sd_card);
|
||||
this(context, masterSecret, 1);
|
||||
}
|
||||
|
||||
public SaveAttachmentTask(Context context, MasterSecret masterSecret, int count) {
|
||||
super(context,
|
||||
context.getResources().getQuantityString(R.plurals.ConversationFragment_saving_n_attachments, count, count),
|
||||
context.getResources().getQuantityString(R.plurals.ConversationFragment_saving_n_attachments_to_sd_card, count, count));
|
||||
this.contextReference = new WeakReference<>(context);
|
||||
this.masterSecretReference = new WeakReference<>(masterSecret);
|
||||
this.attachmentCount = count;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer doInBackground(SaveAttachmentTask.Attachment... attachments) {
|
||||
if (attachments == null || attachments.length != 1 || attachments[0] == null) {
|
||||
throw new AssertionError("must pass in exactly one attachment");
|
||||
if (attachments == null || attachments.length == 0) {
|
||||
throw new AssertionError("must pass in at least one attachment");
|
||||
}
|
||||
Attachment attachment = attachments[0];
|
||||
|
||||
try {
|
||||
Context context = contextReference.get();
|
||||
@ -58,20 +66,12 @@ public class SaveAttachmentTask extends ProgressDialogAsyncTask<SaveAttachmentTa
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
String contentType = MediaUtil.getCorrectedMimeType(attachment.contentType);
|
||||
File mediaFile = constructOutputFile(contentType, attachment.date);
|
||||
InputStream inputStream = PartAuthority.getAttachmentStream(context, masterSecret, attachment.uri);
|
||||
|
||||
if (inputStream == null) {
|
||||
return FAILURE;
|
||||
for (Attachment attachment : attachments) {
|
||||
if (attachment != null && !saveAttachment(context, masterSecret, attachment)) {
|
||||
return FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
OutputStream outputStream = new FileOutputStream(mediaFile);
|
||||
Util.copy(inputStream, outputStream);
|
||||
|
||||
MediaScannerConnection.scanFile(context, new String[]{mediaFile.getAbsolutePath()},
|
||||
new String[]{contentType}, null);
|
||||
|
||||
return SUCCESS;
|
||||
} catch (IOException ioe) {
|
||||
Log.w(TAG, ioe);
|
||||
@ -79,6 +79,24 @@ public class SaveAttachmentTask extends ProgressDialogAsyncTask<SaveAttachmentTa
|
||||
}
|
||||
}
|
||||
|
||||
private boolean saveAttachment(Context context, MasterSecret masterSecret, Attachment attachment) throws IOException {
|
||||
String contentType = MediaUtil.getCorrectedMimeType(attachment.contentType);
|
||||
File mediaFile = constructOutputFile(contentType, attachment.date);
|
||||
InputStream inputStream = PartAuthority.getAttachmentStream(context, masterSecret, attachment.uri);
|
||||
|
||||
if (inputStream == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
OutputStream outputStream = new FileOutputStream(mediaFile);
|
||||
Util.copy(inputStream, outputStream);
|
||||
|
||||
MediaScannerConnection.scanFile(context, new String[]{mediaFile.getAbsolutePath()},
|
||||
new String[]{contentType}, null);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Integer result) {
|
||||
super.onPostExecute(result);
|
||||
@ -87,8 +105,10 @@ public class SaveAttachmentTask extends ProgressDialogAsyncTask<SaveAttachmentTa
|
||||
|
||||
switch (result) {
|
||||
case FAILURE:
|
||||
Toast.makeText(context, R.string.ConversationFragment_error_while_saving_attachment_to_sd_card,
|
||||
Toast.LENGTH_LONG).show();
|
||||
Toast.makeText(context,
|
||||
context.getResources().getQuantityText(R.plurals.ConversationFragment_error_while_saving_attachments_to_sd_card,
|
||||
attachmentCount),
|
||||
Toast.LENGTH_LONG).show();
|
||||
break;
|
||||
case SUCCESS:
|
||||
Toast.makeText(context, R.string.ConversationFragment_success_exclamation,
|
||||
@ -149,11 +169,16 @@ public class SaveAttachmentTask extends ProgressDialogAsyncTask<SaveAttachmentTa
|
||||
}
|
||||
|
||||
public static void showWarningDialog(Context context, OnClickListener onAcceptListener) {
|
||||
showWarningDialog(context, onAcceptListener, 1);
|
||||
}
|
||||
|
||||
public static void showWarningDialog(Context context, OnClickListener onAcceptListener, int count) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||
builder.setTitle(R.string.ConversationFragment_save_to_sd_card);
|
||||
builder.setIconAttribute(R.attr.dialog_alert_icon);
|
||||
builder.setCancelable(true);
|
||||
builder.setMessage(R.string.ConversationFragment_saving_this_media_to_storage_warning);
|
||||
builder.setMessage(context.getResources().getQuantityString(R.plurals.ConversationFragment_saving_n_media_to_storage_warning,
|
||||
count, count));
|
||||
builder.setPositiveButton(R.string.yes, onAcceptListener);
|
||||
builder.setNegativeButton(R.string.no, null);
|
||||
builder.show();
|
||||
|
Loading…
Reference in New Issue
Block a user