Some imageviewer progress

tempwork
Floens 10 years ago
parent cf7af07382
commit 3d6fe34518
  1. 20
      Clover/app/src/main/java/org/floens/chan/core/model/PostImage.java
  2. 40
      Clover/app/src/main/java/org/floens/chan/core/presenter/ImageViewerPresenter.java
  3. 2
      Clover/app/src/main/java/org/floens/chan/core/presenter/ThreadPresenter.java
  4. 35
      Clover/app/src/main/java/org/floens/chan/ui/adapter/ImageViewerAdapter.java
  5. 72
      Clover/app/src/main/java/org/floens/chan/ui/controller/ImageViewerController.java
  6. 11
      Clover/app/src/main/java/org/floens/chan/ui/controller/ImageViewerNavigationController.java
  7. 7
      Clover/app/src/main/java/org/floens/chan/ui/controller/ThreadController.java
  8. 20
      Clover/app/src/main/java/org/floens/chan/ui/fragment/ImageViewFragment.java
  9. 100
      Clover/app/src/main/java/org/floens/chan/ui/view/MultiImageView.java
  10. 25
      Clover/app/src/main/java/org/floens/chan/ui/view/ViewPagerAdapter.java
  11. 8
      Clover/app/src/main/res/layout/controller_image_viewer.xml
  12. 2
      Clover/app/src/main/res/layout/controller_navigation_image_viewer.xml

@ -1,17 +1,35 @@
package org.floens.chan.core.model;
public class PostImage {
public enum Type {
STATIC, GIF, MOVIE
}
public String thumbnailUrl;
public String imageUrl;
public String filename;
public int imageWidth;
public int imageHeight;
public PostImage(String thumbnailUrl, String imageUrl, String filename, int imageWidth, int imageHeight) {
public Type type;
public PostImage(String thumbnailUrl, String imageUrl, String filename, String extension, int imageWidth, int imageHeight) {
this.thumbnailUrl = thumbnailUrl;
this.imageUrl = imageUrl;
this.filename = filename;
this.imageWidth = imageWidth;
this.imageHeight = imageHeight;
switch (extension) {
case "gif":
type = Type.GIF;
break;
case "webm":
type = Type.MOVIE;
break;
default:
type = Type.STATIC;
break;
}
}
}

@ -0,0 +1,40 @@
package org.floens.chan.core.presenter;
import org.floens.chan.core.model.PostImage;
import java.util.List;
public class ImageViewerPresenter {
private final Callback callback;
private boolean exiting = false;
private List<PostImage> images;
private int selectedIndex;
public ImageViewerPresenter(Callback callback) {
this.callback = callback;
}
public void showImages(List<PostImage> images, int index) {
callback.startPreviewInTransition();
this.images = images;
selectedIndex = index;
}
public void onExit() {
if (exiting) return;
exiting = true;
callback.startPreviewOutTransition();
}
public void onInTransitionEnd() {
PostImage image = images.get(selectedIndex);
}
public interface Callback {
public void startPreviewInTransition();
public void startPreviewOutTransition();
}
}

@ -141,7 +141,7 @@ public class ThreadPresenter implements ChanLoader.ChanLoaderCallback, PostAdapt
for (int i = 0; i < chanLoader.getThread().posts.size(); i++) {
Post item = chanLoader.getThread().posts.get(i);
if (item.hasImage) {
images.add(new PostImage(item.thumbnailUrl, item.imageUrl, item.filename, item.imageWidth, item.imageHeight));
images.add(new PostImage(item.thumbnailUrl, item.imageUrl, item.filename, item.ext, item.imageWidth, item.imageHeight));
if (item.no == post.no) {
index = i;
}

@ -0,0 +1,35 @@
package org.floens.chan.ui.adapter;
import android.content.Context;
import android.view.View;
import org.floens.chan.core.model.PostImage;
import org.floens.chan.ui.view.MultiImageView;
import org.floens.chan.ui.view.ViewPagerAdapter;
import java.util.List;
public class ImageViewerAdapter extends ViewPagerAdapter {
private final Context context;
private final List<PostImage> images;
private final MultiImageView.Callback multiImageViewCallback;
public ImageViewerAdapter(Context context, List<PostImage> images, MultiImageView.Callback multiImageViewCallback) {
this.context = context;
this.images = images;
this.multiImageViewCallback = multiImageViewCallback;
}
@Override
public View getView(int position) {
MultiImageView view = new MultiImageView(context);
view.bindPostImage(images.get(position), multiImageViewCallback);
return view;
}
@Override
public int getCount() {
return images.size();
}
}

@ -11,6 +11,7 @@ import android.graphics.Color;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Build;
import android.support.v4.view.ViewPager;
import android.view.View;
import android.view.Window;
import android.view.animation.DecelerateInterpolator;
@ -18,52 +19,70 @@ import android.widget.ImageView;
import org.floens.chan.R;
import org.floens.chan.controller.Controller;
import org.floens.chan.core.presenter.ImageViewerPresenter;
import org.floens.chan.ui.toolbar.Toolbar;
import org.floens.chan.ui.view.ClippingImageView;
import org.floens.chan.utils.AnimationUtils;
import org.floens.chan.utils.Logger;
import static org.floens.chan.utils.AndroidUtils.dp;
import static org.floens.chan.utils.AnimationUtils.calculateBoundsAnimation;
public class ImageViewerController extends Controller implements View.OnClickListener {
public class ImageViewerController extends Controller implements View.OnClickListener, ImageViewerPresenter.Callback {
private static final int TRANSITION_DURATION = 200; //165;
private static final int TRANSITION_CLIP_DURATION = (int) (TRANSITION_DURATION * 0.5f);
private static final float TRANSITION_FINAL_ALPHA = 0.80f;
private ClippingImageView previewImage;
private Callback callback;
private int statusBarColorPrevious;
private AnimatorSet startPreviewAnimation;
private AnimatorSet endAnimation;
public ImageViewerController(Context context) {
private Callback callback;
private ImageViewerPresenter presenter;
private final Toolbar toolbar;
private ClippingImageView previewImage;
private ViewPager pager;
public ImageViewerController(Context context, Toolbar toolbar) {
super(context);
this.toolbar = toolbar;
presenter = new ImageViewerPresenter(this);
}
@Override
public void onCreate() {
super.onCreate();
navigationItem.title = "Image title here";
view = inflateRes(R.layout.controller_image_viewer);
previewImage = (ClippingImageView) view.findViewById(R.id.image);
view.setOnClickListener(this);
previewImage = (ClippingImageView) view.findViewById(R.id.preview_image);
pager = (ViewPager) view.findViewById(R.id.pager);
}
@Override
public void onClick(View v) {
startPreviewOutTransition();
presenter.onExit();
}
@Override
public boolean onBack() {
startPreviewOutTransition();
presenter.onExit();
return true;
}
public void startPreviewInTransition(Callback callback, final ImageView previewImageView) {
public void setCallback(Callback callback) {
this.callback = callback;
}
public ImageViewerPresenter getPresenter() {
return presenter;
}
public void startPreviewInTransition() {
ImageView previewImageView = callback.getPreviewImageStartView(this);
previewImage.setImageDrawable(previewImageView.getDrawable());
Rect startBounds = getImageViewBounds(previewImageView);
@ -127,6 +146,11 @@ public class ImageViewerController extends Controller implements View.OnClickLis
startPreviewAnimation.setInterpolator(new DecelerateInterpolator());
startPreviewAnimation.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
callback.onPreviewCreate(ImageViewerController.this);
}
@Override
public void onAnimationEnd(Animator animation) {
previewImage.setX(0f);
@ -135,6 +159,7 @@ public class ImageViewerController extends Controller implements View.OnClickLis
previewImage.setScaleY(1f);
previewImage.clip(null);
startPreviewAnimation = null;
presenter.onInTransitionEnd();
}
});
startPreviewAnimation.start();
@ -220,23 +245,27 @@ public class ImageViewerController extends Controller implements View.OnClickLis
}
private void previewOutAnimationEnded() {
setStatusBarColor(statusBarColorPrevious);
setBackgroundAlpha(0f);
callback.onPreviewDestroy(this);
navigationController.stopPresenting(false);
}
private void setBackgroundAlpha(float alpha) {
alpha *= TRANSITION_FINAL_ALPHA;
view.setBackgroundColor(Color.argb((int) (alpha * 255f), 0, 0, 0));
view.setBackgroundColor(Color.argb((int) (alpha * TRANSITION_FINAL_ALPHA * 255f), 0, 0, 0));
if (Build.VERSION.SDK_INT >= 21) {
int r = (int) ((1f - alpha) * Color.red(statusBarColorPrevious));
int g = (int) ((1f - alpha) * Color.green(statusBarColorPrevious));
int b = (int) ((1f - alpha) * Color.blue(statusBarColorPrevious));
setStatusBarColor(Color.argb(255, r, g, b));
if (alpha == 0f) {
setStatusBarColor(statusBarColorPrevious);
} else {
int r = (int) ((1f - alpha) * Color.red(statusBarColorPrevious));
int g = (int) ((1f - alpha) * Color.green(statusBarColorPrevious));
int b = (int) ((1f - alpha) * Color.blue(statusBarColorPrevious));
setStatusBarColor(Color.argb(255, r, g, b));
}
}
setToolbarBackgroundAlpha(alpha);
}
private void setStatusBarColor(int color) {
@ -245,12 +274,15 @@ public class ImageViewerController extends Controller implements View.OnClickLis
}
}
private void setToolbarBackgroundAlpha(float alpha) {
toolbar.setAlpha(alpha);
}
private Rect getImageViewBounds(ImageView image) {
Rect startBounds = new Rect();
if (image.getGlobalVisibleRect(startBounds) && !startBounds.isEmpty()) {
AnimationUtils.adjustImageViewBoundsToDrawableBounds(image, startBounds);
if (!startBounds.isEmpty()) {
Logger.test(startBounds.toShortString());
return startBounds;
} else {
return null;
@ -271,6 +303,8 @@ public class ImageViewerController extends Controller implements View.OnClickLis
public interface Callback {
public ImageView getPreviewImageStartView(ImageViewerController imageViewerController);
public void onPreviewCreate(ImageViewerController imageViewerController);
public void onPreviewDestroy(ImageViewerController imageViewerController);
}
}

@ -3,13 +3,15 @@ package org.floens.chan.ui.controller;
import android.content.Context;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import org.floens.chan.R;
import org.floens.chan.controller.NavigationController;
import org.floens.chan.core.model.PostImage;
import org.floens.chan.ui.toolbar.Toolbar;
import org.floens.chan.utils.AndroidUtils;
import java.util.List;
public class ImageViewerNavigationController extends NavigationController {
private ImageViewerController imageViewerController;
@ -27,15 +29,16 @@ public class ImageViewerNavigationController extends NavigationController {
toolbar.setCallback(this);
imageViewerController = new ImageViewerController(context);
imageViewerController = new ImageViewerController(context, toolbar);
pushController(imageViewerController, false);
}
public void setImage(final ImageViewerController.Callback callback, final ImageView startImageView) {
public void showImages(final List<PostImage> images, final int index, final ImageViewerController.Callback callback) {
AndroidUtils.waitForMeasure(imageViewerController.view, new AndroidUtils.OnMeasuredCallback() {
@Override
public boolean onMeasured(View view) {
imageViewerController.startPreviewInTransition(callback, startImageView);
imageViewerController.setCallback(callback);
imageViewerController.getPresenter().showImages(images, index);
return true;
}
});

@ -25,11 +25,10 @@ public abstract class ThreadController extends Controller implements ThreadLayou
@Override
public void showImages(List<PostImage> images, int index, final ImageView thumbnail) {
presentingImageView = thumbnail;
presentingImageView.setVisibility(View.INVISIBLE);
final ImageViewerNavigationController imageViewerNavigationController = new ImageViewerNavigationController(context);
presentController(imageViewerNavigationController, false);
imageViewerNavigationController.setImage(this, thumbnail);
imageViewerNavigationController.showImages(images, index, this);
}
@Override
@ -37,6 +36,10 @@ public abstract class ThreadController extends Controller implements ThreadLayou
return presentingImageView;
}
public void onPreviewCreate(ImageViewerController imageViewerController) {
presentingImageView.setVisibility(View.INVISIBLE);
}
@Override
public void onPreviewDestroy(ImageViewerController imageViewerController) {
presentingImageView.setVisibility(View.VISIBLE);

@ -40,8 +40,8 @@ import org.floens.chan.core.settings.ChanSettings;
import org.floens.chan.core.model.Post;
import org.floens.chan.ui.activity.ImageViewActivity;
import org.floens.chan.ui.adapter.ImageViewAdapter;
import org.floens.chan.ui.view.ThumbnailImageView;
import org.floens.chan.ui.view.ThumbnailImageView.ThumbnailImageViewCallback;
import org.floens.chan.ui.view.MultiImageView;
import org.floens.chan.ui.view.MultiImageView.Callback;
import org.floens.chan.utils.AndroidUtils;
import org.floens.chan.utils.ImageSaver;
@ -49,11 +49,11 @@ import java.io.File;
import static org.floens.chan.utils.AndroidUtils.dp;
public class ImageViewFragment extends Fragment implements ThumbnailImageViewCallback {
public class ImageViewFragment extends Fragment implements Callback {
private Context context;
private ImageViewActivity activity;
private ThumbnailImageView imageView;
private MultiImageView imageView;
private Post post;
private boolean showProgressBar = true;
@ -83,7 +83,7 @@ public class ImageViewFragment extends Fragment implements ThumbnailImageViewCal
} else {
context = inflater.getContext();
imageView = new ThumbnailImageView(context);
imageView = new MultiImageView(context);
imageView.setCallback(this);
int padding = getResources().getDimensionPixelSize(R.dimen.image_view_padding);
imageView.setPadding(padding, padding, padding, padding);
@ -272,7 +272,7 @@ public class ImageViewFragment extends Fragment implements ThumbnailImageViewCal
context.startActivity(Intent.createChooser(intent, context.getString(R.string.action_share)));
}
public void onVideoError(File video) {
public void onVideoError(MultiImageView view, File video) {
if (ChanSettings.getVideoErrorIgnore()) {
Toast.makeText(context, R.string.image_open_failed, Toast.LENGTH_SHORT).show();
} else {
@ -324,7 +324,7 @@ public class ImageViewFragment extends Fragment implements ThumbnailImageViewCal
}
@Override
public void onTap() {
public void onTap(MultiImageView view) {
if (tapToLoad) {
if (loaded) {
activity.finish();
@ -337,12 +337,12 @@ public class ImageViewFragment extends Fragment implements ThumbnailImageViewCal
}
@Override
public void setProgress(boolean progress) {
public void setProgress(MultiImageView view, boolean progress) {
showProgressBar(progress);
}
@Override
public void setLinearProgress(long current, long total, boolean done) {
public void setLinearProgress(MultiImageView view, long current, long total, boolean done) {
progressCurrent = current;
progressTotal = total;
progressDone = done;
@ -350,7 +350,7 @@ public class ImageViewFragment extends Fragment implements ThumbnailImageViewCal
}
@Override
public void onVideoLoaded() {
public void onVideoLoaded(MultiImageView view) {
videoSetIconToPause = true;
activity.invalidateActionBar();
}

@ -30,13 +30,13 @@ import android.widget.ImageView;
import android.widget.Toast;
import android.widget.VideoView;
import com.android.volley.Request;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.ImageLoader.ImageContainer;
import com.koushikdutta.async.future.Future;
import org.floens.chan.ChanApplication;
import org.floens.chan.R;
import org.floens.chan.core.model.PostImage;
import org.floens.chan.core.settings.ChanSettings;
import org.floens.chan.utils.AndroidUtils;
import org.floens.chan.utils.FileCache;
@ -48,34 +48,28 @@ import java.io.IOException;
import pl.droidsonroids.gif.GifDrawable;
import pl.droidsonroids.gif.GifImageView;
public class ThumbnailImageView extends LoadView implements View.OnClickListener {
private static final String TAG = "ThumbnailImageView";
public class MultiImageView extends LoadView implements View.OnClickListener {
private static final String TAG = "MultiImageView";
private ThumbnailImageViewCallback callback;
/**
* Max amount to scale the image inside the view
*/
private final float maxScale = 3f;
private PostImage postImage;
private Callback callback;
private boolean thumbnailNeeded = true;
private Request<?> imageRequest;
private Future<?> ionRequest;
private Future<?> request;
private VideoView videoView;
private GifDrawable gifDrawable;
public ThumbnailImageView(Context context) {
public MultiImageView(Context context) {
super(context);
init();
}
public ThumbnailImageView(Context context, AttributeSet attrs) {
public MultiImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public ThumbnailImageView(Context context, AttributeSet attrs, int defStyleAttr) {
public MultiImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
@ -84,10 +78,21 @@ public class ThumbnailImageView extends LoadView implements View.OnClickListener
setOnClickListener(this);
}
public void setCallback(ThumbnailImageViewCallback callback) {
public void bindPostImage(PostImage postImage, Callback callback) {
this.postImage = postImage;
this.callback = callback;
}
public void loadLowRes() {
}
public void loadHighRes() {
}
public void setCallback(Callback callback) {
this.callback = callback;
}
public void setThumbnail(String thumbnailUrl) {
if (getWidth() == 0 || getHeight() == 0) {
@ -120,15 +125,15 @@ public class ThumbnailImageView extends LoadView implements View.OnClickListener
return;
}
callback.setProgress(true);
ionRequest = ChanApplication.getFileCache().downloadFile(getContext(), imageUrl, new FileCache.DownloadedCallback() {
callback.setProgress(this, true);
request = ChanApplication.getFileCache().downloadFile(getContext(), imageUrl, new FileCache.DownloadedCallback() {
@Override
public void onProgress(long downloaded, long total, boolean done) {
if (done) {
// callback.setLinearProgress(0, 0, true);
thumbnailNeeded = false;
} else {
callback.setLinearProgress(downloaded, total, false);
callback.setLinearProgress(MultiImageView.this, downloaded, total, false);
}
}
@ -151,7 +156,7 @@ public class ThumbnailImageView extends LoadView implements View.OnClickListener
public void setBigImageFile(File file) {
final CustomScaleImageView image = new CustomScaleImageView(getContext());
image.setImageFile(file.getAbsolutePath());
image.setOnClickListener(ThumbnailImageView.this);
image.setOnClickListener(MultiImageView.this);
addView(image);
@ -160,7 +165,7 @@ public class ThumbnailImageView extends LoadView implements View.OnClickListener
public void onInit() {
removeAllViews();
addView(image);
callback.setProgress(false);
callback.setProgress(MultiImageView.this, false);
}
@Override
@ -176,16 +181,16 @@ public class ThumbnailImageView extends LoadView implements View.OnClickListener
return;
}
callback.setProgress(true);
ionRequest = ChanApplication.getFileCache().downloadFile(getContext(), gifUrl, new FileCache.DownloadedCallback() {
callback.setProgress(this, true);
request = ChanApplication.getFileCache().downloadFile(getContext(), gifUrl, new FileCache.DownloadedCallback() {
@Override
public void onProgress(long downloaded, long total, boolean done) {
if (done) {
callback.setProgress(false);
callback.setLinearProgress(0, 0, true);
callback.setProgress(MultiImageView.this, false);
callback.setLinearProgress(MultiImageView.this, 0, 0, true);
thumbnailNeeded = false;
} else {
callback.setLinearProgress(downloaded, total, false);
callback.setLinearProgress(MultiImageView.this, downloaded, total, false);
}
}
@ -227,16 +232,16 @@ public class ThumbnailImageView extends LoadView implements View.OnClickListener
}
public void setVideo(String videoUrl) {
callback.setProgress(true);
ionRequest = ChanApplication.getFileCache().downloadFile(getContext(), videoUrl, new FileCache.DownloadedCallback() {
callback.setProgress(this, true);
request = ChanApplication.getFileCache().downloadFile(getContext(), videoUrl, new FileCache.DownloadedCallback() {
@Override
public void onProgress(long downloaded, long total, boolean done) {
if (done) {
callback.setProgress(false);
callback.setLinearProgress(0, 0, true);
callback.setProgress(MultiImageView.this, false);
callback.setLinearProgress(MultiImageView.this, 0, 0, true);
thumbnailNeeded = false;
} else {
callback.setLinearProgress(downloaded, total, false);
callback.setLinearProgress(MultiImageView.this, downloaded, total, false);
}
}
@ -282,13 +287,13 @@ public class ThumbnailImageView extends LoadView implements View.OnClickListener
@Override
public void onPrepared(MediaPlayer mp) {
mp.setLooping(true);
callback.onVideoLoaded();
callback.onVideoLoaded(MultiImageView.this);
}
});
videoView.setOnErrorListener(new MediaPlayer.OnErrorListener() {
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
callback.onVideoError(file);
callback.onVideoError(MultiImageView.this, file);
return true;
}
@ -308,45 +313,40 @@ public class ThumbnailImageView extends LoadView implements View.OnClickListener
public void onError() {
Toast.makeText(getContext(), R.string.image_preview_failed, Toast.LENGTH_SHORT).show();
callback.setProgress(false);
callback.setProgress(this, false);
}
public void onNotFoundError() {
Toast.makeText(getContext(), R.string.image_not_found, Toast.LENGTH_LONG).show();
callback.setProgress(false);
callback.setProgress(this, false);
}
public void onOutOfMemoryError() {
Toast.makeText(getContext(), R.string.image_preview_failed_oom, Toast.LENGTH_SHORT).show();
callback.setProgress(false);
callback.setProgress(this, false);
}
public void cancelLoad() {
if (imageRequest != null) {
imageRequest.cancel();
imageRequest = null;
}
if (ionRequest != null) {
ionRequest.cancel(true);
if (request != null) {
request.cancel(true);
}
}
@Override
public void onClick(View v) {
callback.onTap();
callback.onTap(this);
}
public static interface ThumbnailImageViewCallback {
public void onTap();
public static interface Callback {
public void onTap(MultiImageView multiImageView);
public void setProgress(boolean progress);
public void setProgress(MultiImageView multiImageView, boolean progress);
public void setLinearProgress(long current, long total, boolean done);
public void setLinearProgress(MultiImageView multiImageView, long current, long total, boolean done);
public void onVideoLoaded();
public void onVideoLoaded(MultiImageView multiImageView);
public void onVideoError(File video);
public void onVideoError(MultiImageView multiImageView, File video);
}
public static class NoMusicServiceCommandContext extends ContextWrapper {

@ -0,0 +1,25 @@
package org.floens.chan.ui.view;
import android.support.v4.view.PagerAdapter;
import android.view.View;
import android.view.ViewGroup;
import org.floens.chan.utils.AndroidUtils;
public abstract class ViewPagerAdapter extends PagerAdapter {
@Override
public Object instantiateItem(ViewGroup container, int position) {
return getView(position);
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
AndroidUtils.removeFromParentView((View) object);
}
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
public abstract View getView(int position);
}

@ -4,8 +4,14 @@
android:layout_height="match_parent">
<org.floens.chan.ui.view.ClippingImageView
android:id="@+id/image"
android:id="@+id/preview_image"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ViewPager
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>

@ -25,7 +25,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="56dp"
android:background="@color/primary"
android:background="#e9000000"
android:elevation="4dp" />
<FrameLayout

Loading…
Cancel
Save