mirror of
https://github.com/oxen-io/session-android.git
synced 2025-11-14 13:33:29 +00:00
Implement new media send flow.
Update our media send flow to allow users to send multiple images/videos at once. This change includes: - New in-app media picker flow. - Ability to caption images and videos. - Image editing tools are made more prominent in the flow. - Some fixes to the image editing tools.
This commit is contained in:
@@ -1,100 +0,0 @@
|
||||
package org.thoughtcrime.securesms.mediapreview;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.components.ThumbnailView;
|
||||
import org.thoughtcrime.securesms.database.MediaDatabase.MediaRecord;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class AlbumRailAdapter extends RecyclerView.Adapter<AlbumRailAdapter.AlbumRailViewHolder> {
|
||||
|
||||
private final GlideRequests glideRequests;
|
||||
private final List<MediaRecord> records;
|
||||
private final RailItemClickedListener listener;
|
||||
|
||||
private int activePosition;
|
||||
|
||||
public AlbumRailAdapter(@NonNull GlideRequests glideRequests, @NonNull RailItemClickedListener listener) {
|
||||
this.glideRequests = glideRequests;
|
||||
this.records = new ArrayList<>();
|
||||
this.listener = listener;
|
||||
|
||||
setHasStableIds(true);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public AlbumRailViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
|
||||
return new AlbumRailViewHolder(LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.media_preview_album_rail_item, viewGroup, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull AlbumRailViewHolder albumRailViewHolder, int i) {
|
||||
albumRailViewHolder.bind(records.get(i), i == activePosition, glideRequests, listener, i - activePosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewRecycled(@NonNull AlbumRailViewHolder holder) {
|
||||
holder.recycle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return records.get(position).getAttachment().getAttachmentId().getUniqueId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return records.size();
|
||||
}
|
||||
|
||||
public void setRecords(@NonNull List<MediaRecord> records, int activePosition) {
|
||||
this.activePosition = activePosition;
|
||||
|
||||
this.records.clear();
|
||||
this.records.addAll(records);
|
||||
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
static class AlbumRailViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
private final ThumbnailView image;
|
||||
|
||||
AlbumRailViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
image = (ThumbnailView) itemView;
|
||||
}
|
||||
|
||||
void bind(@NonNull MediaRecord record, boolean isActive, @NonNull GlideRequests glideRequests,
|
||||
@NonNull RailItemClickedListener railItemClickedListener, int distanceFromActive)
|
||||
{
|
||||
if (record.getAttachment().getThumbnailUri() != null) {
|
||||
image.setImageResource(glideRequests, record.getAttachment().getThumbnailUri());
|
||||
} else if (record.getAttachment().getDataUri() != null) {
|
||||
image.setImageResource(glideRequests, record.getAttachment().getDataUri());
|
||||
} else {
|
||||
image.clear(glideRequests);
|
||||
}
|
||||
|
||||
image.setBackgroundResource(isActive ? R.drawable.album_rail_item_background : 0);
|
||||
image.setOnClickListener(v -> railItemClickedListener.onRailItemClicked(distanceFromActive));
|
||||
}
|
||||
|
||||
void recycle() {
|
||||
image.setOnClickListener(null);
|
||||
}
|
||||
}
|
||||
|
||||
public interface RailItemClickedListener {
|
||||
void onRailItemClicked(int distanceFromActive);
|
||||
}
|
||||
}
|
||||
@@ -5,10 +5,13 @@ import android.arch.lifecycle.MutableLiveData;
|
||||
import android.arch.lifecycle.ViewModel;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import org.thoughtcrime.securesms.database.MediaDatabase.MediaRecord;
|
||||
import org.thoughtcrime.securesms.mediasend.Media;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
@@ -22,9 +25,15 @@ public class MediaPreviewViewModel extends ViewModel {
|
||||
|
||||
private @Nullable Cursor cursor;
|
||||
|
||||
public void setCursor(@Nullable Cursor cursor, boolean leftIsRecent) {
|
||||
public void setCursor(@NonNull Context context, @Nullable Cursor cursor, boolean leftIsRecent) {
|
||||
boolean firstLoad = (this.cursor == null) && (cursor != null);
|
||||
|
||||
this.cursor = cursor;
|
||||
this.leftIsRecent = leftIsRecent;
|
||||
|
||||
if (firstLoad) {
|
||||
setActiveAlbumRailItem(context, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public void setActiveAlbumRailItem(@NonNull Context context, int activePosition) {
|
||||
@@ -37,15 +46,17 @@ public class MediaPreviewViewModel extends ViewModel {
|
||||
|
||||
cursor.moveToPosition(activePosition);
|
||||
|
||||
MediaRecord activeRecord = MediaRecord.from(context, cursor);
|
||||
LinkedList<MediaRecord> rail = new LinkedList<>();
|
||||
MediaRecord activeRecord = MediaRecord.from(context, cursor);
|
||||
LinkedList<Media> rail = new LinkedList<>();
|
||||
|
||||
rail.add(activeRecord);
|
||||
Media activeMedia = toMedia(activeRecord);
|
||||
if (activeMedia != null) rail.add(activeMedia);
|
||||
|
||||
while (cursor.moveToPrevious()) {
|
||||
MediaRecord record = MediaRecord.from(context, cursor);
|
||||
if (record.getAttachment().getMmsId() == activeRecord.getAttachment().getMmsId()) {
|
||||
rail.addFirst(record);
|
||||
Media media = toMedia(record);
|
||||
if (media != null) rail.addFirst(media);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@@ -56,7 +67,8 @@ public class MediaPreviewViewModel extends ViewModel {
|
||||
while (cursor.moveToNext()) {
|
||||
MediaRecord record = MediaRecord.from(context, cursor);
|
||||
if (record.getAttachment().getMmsId() == activeRecord.getAttachment().getMmsId()) {
|
||||
rail.addLast(record);
|
||||
Media media = toMedia(record);
|
||||
if (media != null) rail.addLast(media);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@@ -68,7 +80,7 @@ public class MediaPreviewViewModel extends ViewModel {
|
||||
|
||||
previewData.postValue(new PreviewData(rail.size() > 1 ? rail : Collections.emptyList(),
|
||||
activeRecord.getAttachment().getCaption(),
|
||||
rail.indexOf(activeRecord)));
|
||||
rail.indexOf(activeMedia)));
|
||||
}
|
||||
|
||||
private int getCursorPosition(int position) {
|
||||
@@ -80,22 +92,39 @@ public class MediaPreviewViewModel extends ViewModel {
|
||||
else return cursor.getCount() - 1 - position;
|
||||
}
|
||||
|
||||
private @Nullable Media toMedia(@NonNull MediaRecord mediaRecord) {
|
||||
Uri uri = mediaRecord.getAttachment().getThumbnailUri() != null ? mediaRecord.getAttachment().getThumbnailUri()
|
||||
: mediaRecord.getAttachment().getDataUri();
|
||||
|
||||
if (uri == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Media(uri,
|
||||
mediaRecord.getContentType(),
|
||||
mediaRecord.getDate(),
|
||||
mediaRecord.getAttachment().getWidth(),
|
||||
mediaRecord.getAttachment().getHeight(),
|
||||
Optional.absent(),
|
||||
Optional.fromNullable(mediaRecord.getAttachment().getCaption()));
|
||||
}
|
||||
|
||||
public LiveData<PreviewData> getPreviewData() {
|
||||
return previewData;
|
||||
}
|
||||
|
||||
public static class PreviewData {
|
||||
private final List<MediaRecord> albumThumbnails;
|
||||
private final String caption;
|
||||
private final int activePosition;
|
||||
private final List<Media> albumThumbnails;
|
||||
private final String caption;
|
||||
private final int activePosition;
|
||||
|
||||
public PreviewData(@NonNull List<MediaRecord> albumThumbnails, @Nullable String caption, int activePosition) {
|
||||
public PreviewData(@NonNull List<Media> albumThumbnails, @Nullable String caption, int activePosition) {
|
||||
this.albumThumbnails = albumThumbnails;
|
||||
this.caption = caption;
|
||||
this.activePosition = activePosition;
|
||||
}
|
||||
|
||||
public @NonNull List<MediaRecord> getAlbumThumbnails() {
|
||||
public @NonNull List<Media> getAlbumThumbnails() {
|
||||
return albumThumbnails;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
package org.thoughtcrime.securesms.mediapreview;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.components.ThumbnailView;
|
||||
import org.thoughtcrime.securesms.mediasend.Media;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class MediaRailAdapter extends RecyclerView.Adapter<MediaRailAdapter.MediaRailViewHolder> {
|
||||
|
||||
private final GlideRequests glideRequests;
|
||||
private final List<Media> media;
|
||||
private final RailItemListener listener;
|
||||
private final boolean deleteEnabled;
|
||||
|
||||
private int activePosition;
|
||||
|
||||
public MediaRailAdapter(@NonNull GlideRequests glideRequests, @NonNull RailItemListener listener, boolean deleteEnabled) {
|
||||
this.glideRequests = glideRequests;
|
||||
this.media = new ArrayList<>();
|
||||
this.listener = listener;
|
||||
this.deleteEnabled = deleteEnabled;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public MediaRailViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
|
||||
return new MediaRailViewHolder(LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.media_preview_album_rail_item, viewGroup, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull MediaRailViewHolder mediaRailViewHolder, int i) {
|
||||
mediaRailViewHolder.bind(media.get(i), i == activePosition, glideRequests, listener, i - activePosition, deleteEnabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewRecycled(@NonNull MediaRailViewHolder holder) {
|
||||
holder.recycle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return media.size();
|
||||
}
|
||||
|
||||
public void setMedia(@NonNull List<Media> media) {
|
||||
setMedia(media, activePosition);
|
||||
}
|
||||
|
||||
public void setMedia(@NonNull List<Media> records, int activePosition) {
|
||||
this.activePosition = activePosition;
|
||||
|
||||
this.media.clear();
|
||||
this.media.addAll(records);
|
||||
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void setActivePosition(int activePosition) {
|
||||
this.activePosition = activePosition;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
static class MediaRailViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
private final ThumbnailView image;
|
||||
private final View deleteButton;
|
||||
|
||||
MediaRailViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
image = itemView.findViewById(R.id.rail_item_image);
|
||||
deleteButton = itemView.findViewById(R.id.rail_item_delete);
|
||||
}
|
||||
|
||||
void bind(@NonNull Media media, boolean isActive, @NonNull GlideRequests glideRequests,
|
||||
@NonNull RailItemListener railItemListener, int distanceFromActive, boolean deleteEnabled)
|
||||
{
|
||||
image.setImageResource(glideRequests, media.getUri());
|
||||
image.setBackgroundResource(isActive ? R.drawable.media_rail_item_background : 0);
|
||||
image.setOnClickListener(v -> railItemListener.onRailItemClicked(distanceFromActive));
|
||||
|
||||
if (deleteEnabled && isActive) {
|
||||
deleteButton.setVisibility(View.VISIBLE);
|
||||
deleteButton.setOnClickListener(v -> railItemListener.onRailItemDeleteClicked(distanceFromActive));
|
||||
} else {
|
||||
deleteButton.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
void recycle() {
|
||||
image.setOnClickListener(null);
|
||||
deleteButton.setOnClickListener(null);
|
||||
}
|
||||
}
|
||||
|
||||
public interface RailItemListener {
|
||||
void onRailItemClicked(int distanceFromActive);
|
||||
void onRailItemDeleteClicked(int distanceFromActive);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user