Added store media

pull/194/merge
M66B 4 years ago
parent 5da0c60619
commit adf25e05eb

File diff suppressed because it is too large Load Diff

@ -34,6 +34,7 @@ import android.app.RemoteAction;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@ -53,6 +54,7 @@ import android.os.LocaleList;
import android.os.Parcelable;
import android.provider.CalendarContract;
import android.provider.ContactsContract;
import android.provider.MediaStore;
import android.provider.Settings;
import android.text.Html;
import android.text.Spannable;
@ -155,6 +157,7 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
@ -480,6 +483,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
private Button btnCalendarMaybe;
private ContentLoadingProgressBar pbCalendarWait;
private ImageButton ibStoreMedia;
private ImageButton ibShareImages;
private RecyclerView rvImage;
@ -862,6 +866,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
ibSeenBottom = vsBody.findViewById(R.id.ibSeenBottom);
flow = vsBody.findViewById(R.id.flow);
ibStoreMedia = vsBody.findViewById(R.id.ibStoreMedia);
ibShareImages = vsBody.findViewById(R.id.ibShareImages);
rvImage = vsBody.findViewById(R.id.rvImage);
rvImage.setHasFixedSize(false);
@ -1001,6 +1006,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
btnCalendarDecline.setOnLongClickListener(this);
btnCalendarMaybe.setOnLongClickListener(this);
ibStoreMedia.setOnClickListener(this);
ibShareImages.setOnClickListener(this);
}
@ -1106,6 +1112,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
btnCalendarDecline.setOnLongClickListener(null);
btnCalendarMaybe.setOnLongClickListener(null);
ibStoreMedia.setOnClickListener(null);
ibShareImages.setOnClickListener(null);
}
@ -1644,6 +1651,8 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
ibArchiveBottom.setVisibility(View.GONE);
ibMoveBottom.setVisibility(View.GONE);
ibSeenBottom.setVisibility(View.GONE);
ibStoreMedia.setVisibility(View.GONE);
}
private void clearActions() {
@ -3110,6 +3119,9 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
images.add(attachment);
adapterImage.set(images);
grpImages.setVisibility(images.size() > 0 ? View.VISIBLE : View.GONE);
ibStoreMedia.setVisibility(
images.size() > 0 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
? View.VISIBLE : View.GONE);
}
private void bindCalendar(final TupleMessageEx message, EntityAttachment attachment) {
@ -3459,6 +3471,103 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
}.execute(context, owner, args, "message:participation");
}
private void onStoreMedia(TupleMessageEx message) {
Bundle args = new Bundle();
args.putLong("id", message.id);
new SimpleTask<Uri>() {
@Override
@RequiresApi(api = Build.VERSION_CODES.Q)
protected Uri onExecute(Context context, Bundle args) throws IOException {
long id = args.getLong("id");
ContentResolver resolver = context.getContentResolver();
Uri collection = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
String folder = context.getString(R.string.app_name);
DB db = DB.getInstance(context);
List<EntityAttachment> attachments = db.attachment().getAttachments(id);
if (attachments == null || attachments.size() == 0)
return null;
for (EntityAttachment attachment : attachments)
if (attachment.available &&
attachment.isAttachment() && attachment.isImage()) {
// Check is exists
if (attachment.media_uri != null) {
Uri uri = Uri.parse(attachment.media_uri);
try (Cursor cursor = resolver.query(uri, null, null, null, null)) {
if (cursor.moveToFirst())
continue;
}
}
File file = attachment.getFile(context);
String type = attachment.getMimeType();
String title = (attachment.name == null ? file.getName() : attachment.name);
// Fix mime type
if ("image/jpg".equals(type))
type = "image/jpeg";
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/" + folder);
values.put(MediaStore.Images.Media.TITLE, title);
values.put(MediaStore.Images.Media.DISPLAY_NAME, title);
values.put(MediaStore.Images.Media.MIME_TYPE, type);
values.put(MediaStore.Images.Media.IS_PENDING, 1);
Uri uri = resolver.insert(collection, values);
if (uri == null)
return null;
InputStream is = null;
OutputStream os = null;
try {
is = new FileInputStream(file);
os = resolver.openOutputStream(uri);
Helper.copy(is, os);
} finally {
try {
if (is != null)
is.close();
} finally {
if (os != null)
os.close();
}
}
values.clear();
values.put(MediaStore.Images.Media.IS_PENDING, 0);
values.put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis() / 1000);
resolver.update(uri, values, null, null);
db.attachment().setMediaUri(attachment.id, uri.toString());
}
return collection;
}
@Override
@RequiresApi(api = Build.VERSION_CODES.Q)
protected void onExecuted(Bundle args, Uri uri) {
if (uri == null)
return;
Intent view = new Intent(Intent.ACTION_VIEW)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.setDataAndType(uri, "image/*");
context.startActivity(
Intent.createChooser(view, context.getString(R.string.title_select)));
}
@Override
protected void onException(Bundle args, Throwable ex) {
Log.unexpectedError(parentFragment.getParentFragmentManager(), ex);
}
}.execute(context, owner, args, "images:store");
}
private void onShareImages(TupleMessageEx message) {
Bundle args = new Bundle();
args.putLong("id", message.id);
@ -3475,7 +3584,8 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
ArrayList<Uri> result = new ArrayList<>();
for (EntityAttachment attachment : attachments)
if (attachment.isAttachment() && attachment.isImage()) {
if (attachment.available &&
attachment.isAttachment() && attachment.isImage()) {
File file = attachment.getFile(context);
Uri uri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID, file);
result.add(uri);
@ -3501,7 +3611,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
protected void onException(Bundle args, Throwable ex) {
Log.unexpectedError(parentFragment.getParentFragmentManager(), ex);
}
}.execute(context, owner, args, "attachments:share");
}.execute(context, owner, args, "images:share");
}
private boolean isOutgoing(TupleMessageEx message) {
@ -3684,6 +3794,8 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
onMenuSetImportance(message, importance);
} else if (id == R.id.btnCalendarAccept || id == R.id.btnCalendarDecline || id == R.id.btnCalendarMaybe || id == R.id.ibCalendar) {
onActionCalendar(message, view.getId(), false);
} else if (id == R.id.ibStoreMedia) {
onStoreMedia(message);
} else if (id == R.id.ibShareImages) {
onShareImages(message);
} else {

@ -71,7 +71,7 @@ import io.requery.android.database.sqlite.SQLiteDatabase;
// https://developer.android.com/topic/libraries/architecture/room.html
@Database(
version = 223,
version = 224,
entities = {
EntityIdentity.class,
EntityAccount.class,
@ -2260,6 +2260,12 @@ public abstract class DB extends RoomDatabase {
db.execSQL("DROP TRIGGER IF EXISTS `attachment_delete`");
createTriggers(db);
}
}).addMigrations(new Migration(223, 224) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase db) {
logMigration(startVersion, endVersion);
db.execSQL("ALTER TABLE `attachment` ADD COLUMN `media_uri` TEXT");
}
}).addMigrations(new Migration(998, 999) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase db) {

@ -121,6 +121,12 @@ public interface DaoAttachment {
" AND NOT (related IS :related)")
void setCid(long id, String cid, Boolean related);
@Query("UPDATE attachment" +
" SET media_uri = :media_uri" +
" WHERE id = :id" +
" AND NOT (media_uri IS :media_uri)")
void setMediaUri(long id, String media_uri);
@Query("UPDATE attachment" +
" SET available = 0" +
" WHERE NOT (available IS 0)" +

@ -82,6 +82,7 @@ public class EntityAttachment {
public Integer progress;
@NonNull
public Boolean available = false;
public String media_uri;
public String error;
// Gmail sends inline images as attachments with a name and cid

@ -14,6 +14,20 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<eu.faircode.email.FixedImageButton
android:id="@+id/ibStoreMedia"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_marginEnd="12dp"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/title_save_all"
android:padding="6dp"
android:scaleType="fitCenter"
android:tooltipText="@string/title_save_all"
app:layout_constraintEnd_toStartOf="@id/ibShareImages"
app:layout_constraintTop_toBottomOf="@+id/vSeparatorImages"
app:srcCompat="@drawable/twotone_photo_library_24" />
<eu.faircode.email.FixedImageButton
android:id="@+id/ibShareImages"
android:layout_width="36dp"
@ -22,7 +36,7 @@
android:contentDescription="@string/title_share"
android:padding="6dp"
android:scaleType="fitCenter"
android:tooltipText="@string/title_save_all"
android:tooltipText="@string/title_share"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/vSeparatorImages"
app:srcCompat="@drawable/twotone_share_24" />

Loading…
Cancel
Save