mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 18:59:06 +01:00
Show placeholders for missing attachments in ImageActivity
and display attachments as they arrive while ImageActivity is open.
This commit is contained in:
@@ -24,6 +24,7 @@ import org.briarproject.briar.android.conversation.glide.GlideApp;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
@@ -33,14 +34,19 @@ import static android.os.Build.VERSION.SDK_INT;
|
||||
import static android.widget.ImageView.ScaleType.FIT_START;
|
||||
import static com.bumptech.glide.load.engine.DiskCacheStrategy.NONE;
|
||||
import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull;
|
||||
import static org.briarproject.briar.android.attachment.AttachmentItem.State.AVAILABLE;
|
||||
import static org.briarproject.briar.android.attachment.AttachmentItem.State.ERROR;
|
||||
import static org.briarproject.briar.android.conversation.ImageActivity.ATTACHMENT_POSITION;
|
||||
import static org.briarproject.briar.android.conversation.ImageActivity.ITEM_ID;
|
||||
|
||||
@MethodsNotNullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
public class ImageFragment extends Fragment {
|
||||
public class ImageFragment extends Fragment
|
||||
implements RequestListener<Drawable> {
|
||||
|
||||
private final static String IS_FIRST = "isFirst";
|
||||
@DrawableRes
|
||||
private static final int ERROR_RES = R.drawable.ic_image_broken;
|
||||
|
||||
@Inject
|
||||
ViewModelProvider.Factory viewModelFactory;
|
||||
@@ -89,55 +95,72 @@ public class ImageFragment extends Fragment {
|
||||
|
||||
viewModel = ViewModelProviders.of(requireNonNull(getActivity()),
|
||||
viewModelFactory).get(ImageViewModel.class);
|
||||
viewModel.getOnAttachmentLoaded()
|
||||
.observeEvent(this, this::onAttachmentLoaded);
|
||||
|
||||
photoView = v.findViewById(R.id.photoView);
|
||||
photoView.setScaleLevels(1, 2, 4);
|
||||
photoView.setOnClickListener(view -> viewModel.clickImage());
|
||||
|
||||
// Request Listener
|
||||
RequestListener<Drawable> listener = new RequestListener<Drawable>() {
|
||||
|
||||
@Override
|
||||
public boolean onLoadFailed(@Nullable GlideException e,
|
||||
Object model, Target<Drawable> target,
|
||||
boolean isFirstResource) {
|
||||
if (getActivity() != null && isFirst)
|
||||
getActivity().supportStartPostponedEnterTransition();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onResourceReady(Drawable resource, Object model,
|
||||
Target<Drawable> target, DataSource dataSource,
|
||||
boolean isFirstResource) {
|
||||
if (SDK_INT >= 21 && !(resource instanceof Animatable)) {
|
||||
// set transition name only when not animatable,
|
||||
// because the animation won't start otherwise
|
||||
photoView.setTransitionName(
|
||||
attachment.getTransitionName(conversationItemId));
|
||||
}
|
||||
// Move image to the top if overlapping toolbar
|
||||
if (viewModel.isOverlappingToolbar(photoView, resource)) {
|
||||
photoView.setScaleType(FIT_START);
|
||||
}
|
||||
if (getActivity() != null && isFirst) {
|
||||
getActivity().supportStartPostponedEnterTransition();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Load Image
|
||||
GlideApp.with(this)
|
||||
.load(attachment)
|
||||
// TODO allow if size < maxTextureSize ?
|
||||
// .override(SIZE_ORIGINAL)
|
||||
.diskCacheStrategy(NONE)
|
||||
.error(R.drawable.ic_image_broken)
|
||||
.addListener(listener)
|
||||
.into(photoView);
|
||||
if (attachment.getState() == AVAILABLE) {
|
||||
loadImage();
|
||||
// postponed transition will be started when Image was loaded
|
||||
} else if (attachment.getState() == ERROR) {
|
||||
photoView.setImageResource(ERROR_RES);
|
||||
startPostponedTransition();
|
||||
} else {
|
||||
photoView.setImageResource(R.drawable.ic_image_missing);
|
||||
startPostponedTransition();
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
private void loadImage() {
|
||||
GlideApp.with(this)
|
||||
.load(attachment)
|
||||
// TODO allow if size < maxTextureSize ?
|
||||
// .override(SIZE_ORIGINAL)
|
||||
.diskCacheStrategy(NONE)
|
||||
.error(ERROR_RES)
|
||||
.addListener(this)
|
||||
.into(photoView);
|
||||
}
|
||||
|
||||
private void onAttachmentLoaded(MessageId messageId) {
|
||||
if (attachment.getMessageId().equals(messageId)) loadImage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onLoadFailed(@Nullable GlideException e,
|
||||
Object model, Target<Drawable> target,
|
||||
boolean isFirstResource) {
|
||||
startPostponedTransition();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onResourceReady(Drawable resource, Object model,
|
||||
Target<Drawable> target, DataSource dataSource,
|
||||
boolean isFirstResource) {
|
||||
if (SDK_INT >= 21 && !(resource instanceof Animatable)) {
|
||||
// set transition name only when not animatable,
|
||||
// because the animation won't start otherwise
|
||||
photoView.setTransitionName(
|
||||
attachment.getTransitionName(conversationItemId));
|
||||
}
|
||||
// Move image to the top if overlapping toolbar
|
||||
if (viewModel.isOverlappingToolbar(photoView, resource)) {
|
||||
photoView.setScaleType(FIT_START);
|
||||
}
|
||||
startPostponedTransition();
|
||||
return false;
|
||||
}
|
||||
|
||||
private void startPostponedTransition() {
|
||||
if (getActivity() != null && isFirst) {
|
||||
getActivity().supportStartPostponedEnterTransition();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -56,12 +56,12 @@ class ImageViewHolder extends ViewHolder {
|
||||
imageView.setScaleType(FIT_CENTER);
|
||||
} else {
|
||||
loadImage(attachment, r);
|
||||
if (SDK_INT >= 21) {
|
||||
imageView.setTransitionName(
|
||||
attachment.getTransitionName(conversationItemId));
|
||||
}
|
||||
imageView.setScaleType(CENTER_CROP);
|
||||
}
|
||||
if (SDK_INT >= 21) {
|
||||
imageView.setTransitionName(
|
||||
attachment.getTransitionName(conversationItemId));
|
||||
}
|
||||
}
|
||||
|
||||
private void setImageViewDimensions(AttachmentItem a, boolean single,
|
||||
|
||||
@@ -7,13 +7,18 @@ import android.view.View;
|
||||
|
||||
import org.briarproject.bramble.api.db.DatabaseExecutor;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.event.Event;
|
||||
import org.briarproject.bramble.api.event.EventBus;
|
||||
import org.briarproject.bramble.api.event.EventListener;
|
||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.briar.android.attachment.AttachmentItem;
|
||||
import org.briarproject.briar.android.viewmodel.LiveEvent;
|
||||
import org.briarproject.briar.android.viewmodel.MutableLiveEvent;
|
||||
import org.briarproject.briar.api.messaging.Attachment;
|
||||
import org.briarproject.briar.api.messaging.MessagingManager;
|
||||
import org.briarproject.briar.api.messaging.event.AttachmentReceivedEvent;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
@@ -41,16 +46,19 @@ import static org.briarproject.bramble.util.IoUtils.copyAndClose;
|
||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||
|
||||
@NotNullByDefault
|
||||
public class ImageViewModel extends AndroidViewModel {
|
||||
public class ImageViewModel extends AndroidViewModel implements EventListener {
|
||||
|
||||
private static Logger LOG = getLogger(ImageViewModel.class.getName());
|
||||
|
||||
private final MessagingManager messagingManager;
|
||||
private final EventBus eventBus;
|
||||
@DatabaseExecutor
|
||||
private final Executor dbExecutor;
|
||||
@IoExecutor
|
||||
private final Executor ioExecutor;
|
||||
|
||||
private final MutableLiveEvent<MessageId> attachmentLoaded =
|
||||
new MutableLiveEvent<>();
|
||||
/**
|
||||
* true means there was an error saving the image, false if image was saved.
|
||||
*/
|
||||
@@ -62,13 +70,34 @@ public class ImageViewModel extends AndroidViewModel {
|
||||
|
||||
@Inject
|
||||
ImageViewModel(Application application,
|
||||
MessagingManager messagingManager,
|
||||
MessagingManager messagingManager, EventBus eventBus,
|
||||
@DatabaseExecutor Executor dbExecutor,
|
||||
@IoExecutor Executor ioExecutor) {
|
||||
super(application);
|
||||
this.messagingManager = messagingManager;
|
||||
this.eventBus = eventBus;
|
||||
this.dbExecutor = dbExecutor;
|
||||
this.ioExecutor = ioExecutor;
|
||||
|
||||
eventBus.addListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCleared() {
|
||||
super.onCleared();
|
||||
eventBus.removeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eventOccurred(Event e) {
|
||||
if (e instanceof AttachmentReceivedEvent) {
|
||||
attachmentLoaded
|
||||
.postEvent(((AttachmentReceivedEvent) e).getMessageId());
|
||||
}
|
||||
}
|
||||
|
||||
LiveEvent<MessageId> getOnAttachmentLoaded() {
|
||||
return attachmentLoaded;
|
||||
}
|
||||
|
||||
void clickImage() {
|
||||
|
||||
Reference in New Issue
Block a user