Refactored ImageViewFragment

The image, gif and webm things got their own view.
Made videos playable and pausable through the actionbar.
captchafix
Florens Douwes 11 years ago
parent 4e28980b33
commit 7e0c024a99
  1. BIN
      Chan/res/drawable-hdpi/ic_action_play.png
  2. BIN
      Chan/res/drawable-mdpi/ic_action_play.png
  3. BIN
      Chan/res/drawable-xhdpi/ic_action_play.png
  4. BIN
      Chan/res/drawable-xxhdpi/ic_action_play.png
  5. 17
      Chan/res/menu/image_view.xml
  6. 4
      Chan/res/values/dimens.xml
  7. 1
      Chan/res/values/strings.xml
  8. 20
      Chan/src/org/floens/chan/core/net/FileRequest.java
  9. 153
      Chan/src/org/floens/chan/ui/activity/ImageViewActivity.java
  10. 7
      Chan/src/org/floens/chan/ui/adapter/ImageViewAdapter.java
  11. 2
      Chan/src/org/floens/chan/ui/adapter/PostAdapter.java
  12. 233
      Chan/src/org/floens/chan/ui/fragment/ImageViewFragment.java
  13. 23
      Chan/src/org/floens/chan/ui/view/CustomNetworkImageView.java
  14. 72
      Chan/src/org/floens/chan/ui/view/LoadView.java
  15. 226
      Chan/src/org/floens/chan/ui/view/ThumbnailImageView.java
  16. 6
      Chan/src/org/floens/chan/utils/Utils.java

Binary file not shown.

After

Width:  |  Height:  |  Size: 437 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 339 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 522 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 702 B

@ -1,9 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="@+id/action_image_play_state"
android:icon="@drawable/ic_action_play"
android:orderInCategory="1"
android:showAsAction="always"
android:title="@string/image_play_state"/>
<item
android:id="@+id/action_image_save"
android:orderInCategory="1"
android:showAsAction="never"
android:title="@string/image_save" />
android:id="@+id/action_image_save"
android:orderInCategory="2"
android:showAsAction="never"
android:title="@string/image_save"/>
</menu>
</menu>

@ -5,12 +5,10 @@
<dimen name="post_comment_padding">11dp</dimen>
<dimen name="post_icon_padding">6dp</dimen>
<dimen name="dp48">48dp</dimen>
<dimen name="thumbnail_size">70dp</dimen>
<dimen name="post_icon_width">24dp</dimen>
<dimen name="post_icon_height">14dp</dimen>
<dimen name="post_max_height">200dp</dimen>
<dimen name="image_popup_padding">8dp</dimen>
<dimen name="image_view_padding">8dp</dimen>
</resources>

@ -29,6 +29,7 @@
<string name="image_save_failed">Saving image failed</string>
<string name="image_save_directory_error">Cannot make save directory</string>
<string name="image_save_not_mounted">Cannot write to storage</string>
<string name="image_play_state">Start / stop playing</string>
<string name="image_preview_failed">Failed to show image</string>
<string name="image_open_failed">Failed to open image</string>

@ -1,16 +1,21 @@
package org.floens.chan.core.net;
import java.io.File;
import org.floens.chan.ChanApplication;
import com.android.volley.NetworkResponse;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.Response.ErrorListener;
import com.android.volley.Response.Listener;
import com.android.volley.toolbox.DiskBasedCache;
import com.android.volley.toolbox.HttpHeaderParser;
public class CachingRequest extends Request<Void> {
protected final Listener<Void> listener;
public class FileRequest extends Request<Void> {
protected final Listener<File> listener;
public CachingRequest(String url, Listener<Void> listener, ErrorListener errorListener) {
public FileRequest(String url, Listener<File> listener, ErrorListener errorListener) {
super(Method.GET, url, errorListener);
this.listener = listener;
@ -24,6 +29,13 @@ public class CachingRequest extends Request<Void> {
@Override
protected void deliverResponse(Void response) {
listener.onResponse(response);
DiskBasedCache cache = (DiskBasedCache) ChanApplication.getVolleyRequestQueue().getCache();
File file = cache.getFileForKey(getCacheKey());
if (file.exists()) {
listener.onResponse(file);
} else {
listener.onResponse(null);
}
}
}

@ -6,6 +6,7 @@ import org.floens.chan.R;
import org.floens.chan.core.model.Post;
import org.floens.chan.ui.adapter.ImageViewAdapter;
import org.floens.chan.ui.adapter.PostAdapter;
import org.floens.chan.ui.fragment.ImageViewFragment;
import org.floens.chan.utils.ImageSaver;
import org.floens.chan.utils.Logger;
@ -18,56 +19,57 @@ import android.view.MenuItem;
import android.view.Window;
/**
* An fragment pager that contains images. Call setPosts first,
* and then start the activity with startActivity()
* An fragment pager that contains images. Call setPosts first, and then start
* the activity with startActivity()
*/
public class ImageViewActivity extends Activity implements ViewPager.OnPageChangeListener {
private static final String TAG = "ImageViewActivity";
private static PostAdapter postAdapter;
private static int selectedId = -1;
private ViewPager viewPager;
private ImageViewAdapter adapter;
private int currentPosition;
private boolean[] progressData;
/**
* Set the posts to show
* @param other the posts to get image data from
* @param selected the no that the user clicked on
*
* @param other
* the posts to get image data from
* @param selected
* the no that the user clicked on
*/
public static void setAdapter(PostAdapter adapter, int selected) {
postAdapter = adapter;
selectedId = selected;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
ActionBar actionBar = getActionBar();
actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE | ActionBar.DISPLAY_HOME_AS_UP);
super.onCreate(savedInstanceState);
if (postAdapter != null) {
// Get the posts with images
ArrayList<Post> imagePosts = new ArrayList<Post>();
for (Post post : postAdapter.getList()) {
if (post.hasImage){
if (post.hasImage) {
imagePosts.add(post);
}
}
// Setup our pages and adapter
setContentView(R.layout.image_pager);
ViewPager viewPager = (ViewPager) findViewById(R.id.image_pager);
viewPager = (ViewPager) findViewById(R.id.image_pager);
adapter = new ImageViewAdapter(getFragmentManager(), this);
adapter.addToList(imagePosts);
adapter.setList(imagePosts);
viewPager.setAdapter(adapter);
viewPager.setOnPageChangeListener(this);
progressData = new boolean[imagePosts.size()];
// Select the right image
for (int i = 0; i < imagePosts.size(); i++) {
if (imagePosts.get(i).no == selectedId) {
@ -77,18 +79,60 @@ public class ImageViewActivity extends Activity implements ViewPager.OnPageChang
}
}
} else {
Logger.e(TAG, "Posts in imageview list was null");
Logger.e(TAG, "Posts in ImageViewActivity was null");
finish();
}
}
@Override
protected void onStop() {
super.onStop();
// Avoid things like out of sync, since this is an activity.
finish();
}
@Override
public void finish() {
super.finish();
overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
postAdapter = null;
}
@Override
public void onPageScrollStateChanged(int state) {
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
currentPosition = position;
ImageViewFragment fragment = getCurrentFragment();
if (fragment != null) {
fragment.onSelected(adapter, position);
}
Post post = adapter.getPost(position);
if (postAdapter != null) {
postAdapter.scrollToPost(post);
}
}
public void invalidateActionBar() {
invalidateOptionsMenu();
}
public void callOnSelect() {
ImageViewFragment fragment = getCurrentFragment();
if (fragment != null) {
fragment.onSelected(adapter, currentPosition);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
@ -97,70 +141,41 @@ public class ImageViewActivity extends Activity implements ViewPager.OnPageChang
} else if (item.getItemId() == R.id.action_image_save) {
Post post = adapter.getPost(currentPosition);
ImageSaver.save(this, post.imageUrl, post.filename, post.ext);
return true;
} else {
ImageViewFragment fragment = getCurrentFragment();
if (fragment != null) {
fragment.customOnOptionsItemSelected(item);
}
return super.onOptionsItemSelected(item);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.image_view, menu);
return true;
}
/**
* Show the progressbar in the actionbar at the specified position.
* @param e
* @param position
*/
public void showProgressBar(boolean e, int position) {
progressData[position] = e;
if (position == currentPosition) {
setProgressBarIndeterminateVisibility(e);
}
}
@Override
protected void onStop() {
super.onStop();
// Avoid things like out of sync, since this is an activity.
finish();
return true;
}
@Override
public void onPageSelected(int position) {
currentPosition = position;
setProgressBarIndeterminateVisibility(progressData[position]);
Post post = adapter.getPost(position);
if (post != null) {
String filename = post.filename + "." + post.ext;
String text = "(" + (position + 1) + "/" + progressData.length + ") " + filename;
getActionBar().setTitle(text);
public boolean onPrepareOptionsMenu(Menu menu) {
ImageViewFragment fragment = getCurrentFragment();
if (fragment != null) {
fragment.onPrepareOptionsMenu(currentPosition, adapter, menu);
}
if (postAdapter != null) {
postAdapter.scrollToPost(post);
}
}
@Override
public void onPageScrollStateChanged(int state) {
return super.onPrepareOptionsMenu(menu);
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
private ImageViewFragment getCurrentFragment() {
Object o = adapter.instantiateItem(viewPager, currentPosition);
if (o instanceof ImageViewFragment) {
return (ImageViewFragment) o;
} else {
return null;
}
}
}

@ -15,7 +15,6 @@ import android.view.View;
public class ImageViewAdapter extends FragmentStatePagerAdapter {
private final ImageViewActivity activity;
private int count = 0;
private final ArrayList<Post> postList = new ArrayList<Post>();
public ImageViewAdapter(FragmentManager fragmentManager, ImageViewActivity activity) {
@ -25,7 +24,7 @@ public class ImageViewAdapter extends FragmentStatePagerAdapter {
@Override
public int getCount() {
return count;
return postList.size();
}
@Override
@ -46,8 +45,8 @@ public class ImageViewAdapter extends FragmentStatePagerAdapter {
view = null;
}
public void addToList(ArrayList<Post> list){
count += list.size();
public void setList(ArrayList<Post> list){
postList.clear();
postList.addAll(list);
notifyDataSetChanged();

@ -92,7 +92,7 @@ public class PostAdapter extends BaseAdapter {
view.init(threadManager, listView, this);
int padding = context.getResources().getDimensionPixelSize(R.dimen.general_padding);
view.setPadding(padding, padding, padding, padding);
int height = context.getResources().getDimensionPixelSize(R.dimen.dp48);
int height = Utils.dp(context, 48f);
view.setHeight(height);
view.setGravity(Gravity.CENTER);
return view;

@ -1,70 +1,41 @@
package org.floens.chan.ui.fragment;
import java.io.File;
import java.io.IOException;
import org.floens.chan.ChanApplication;
import org.floens.chan.R;
import org.floens.chan.core.ChanPreferences;
import org.floens.chan.core.model.Post;
import org.floens.chan.core.net.CachingRequest;
import org.floens.chan.core.net.GIFRequest;
import org.floens.chan.ui.activity.ImageViewActivity;
import org.floens.chan.ui.view.GIFView;
import org.floens.chan.ui.view.NetworkPhotoView;
import org.floens.chan.utils.Logger;
import org.floens.chan.ui.adapter.ImageViewAdapter;
import org.floens.chan.ui.view.ThumbnailImageView;
import org.floens.chan.ui.view.ThumbnailImageView.ThumbnailImageViewCallback;
import uk.co.senab.photoview.PhotoViewAttacher.OnViewTapListener;
import android.app.Fragment;
import android.content.Context;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnPreparedListener;
import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.RelativeLayout;
import android.widget.Toast;
import android.widget.VideoView;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.DiskBasedCache;
public class ImageViewFragment extends Fragment implements View.OnLongClickListener, OnViewTapListener, OnClickListener {
private static final String TAG = "ImageViewFragment";
public class ImageViewFragment extends Fragment implements ThumbnailImageViewCallback {
private Context context;
private RelativeLayout wrapper;
private Post post;
private ImageViewActivity activity;
private int index;
private CachingRequest movieRequest;
private Post post;
private boolean showProgressBar = true;
private ThumbnailImageView imageView;
private boolean isVideo = false;
private boolean videoVisible = false;
private boolean videoSetIconToPause = false;
public static ImageViewFragment newInstance(Post post, ImageViewActivity activity, int index) {
ImageViewFragment imageViewFragment = new ImageViewFragment();
imageViewFragment.post = post;
imageViewFragment.activity = activity;
imageViewFragment.index = index;
return imageViewFragment;
}
@Override
public void onSaveInstanceState(Bundle bundle) {
// https://code.google.com/p/android/issues/detail?id=19917
bundle.putString("bug_19917", "bug_19917");
super.onSaveInstanceState(bundle);
}
public void showProgressBar(boolean e) {
activity.showProgressBar(e, index);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (post == null) {
@ -73,14 +44,13 @@ public class ImageViewFragment extends Fragment implements View.OnLongClickListe
} else {
context = inflater.getContext();
wrapper = new RelativeLayout(context);
int padding = (int) context.getResources().getDimension(R.dimen.image_popup_padding);
wrapper.setPadding(padding, padding, padding, padding);
wrapper.setGravity(Gravity.CENTER);
wrapper.setOnClickListener(this);
imageView = new ThumbnailImageView(context);
imageView.setCallback(this);
int padding = (int) context.getResources().getDimension(R.dimen.image_view_padding);
imageView.setPadding(padding, padding, padding, padding);
return wrapper;
return imageView;
}
}
@ -92,135 +62,92 @@ public class ImageViewFragment extends Fragment implements View.OnLongClickListe
// No restoring
} else {
if (!post.hasImage) {
throw new IllegalArgumentException("No post / post has no image");
throw new IllegalArgumentException("Post has no image");
}
imageView.setThumbnail(post.thumbnailUrl);
if (post.ext.equals("gif")) {
loadGif();
imageView.setGif(post.imageUrl);
} else if (post.ext.equals("webm")) {
if (ChanPreferences.getVideosEnabled()) {
loadMovie();
} else {
loadOtherImage(post.thumbnailUrl);
}
isVideo = true;
activity.invalidateActionBar();
showProgressBar(false);
} else {
loadOtherImage(post.imageUrl);
imageView.setBigImage(post.imageUrl);
}
}
}
private void loadMovie() {
movieRequest = new CachingRequest(post.imageUrl, new Response.Listener<Void>() {
@Override
public void onResponse(Void empty) {
if (movieRequest != null) {
try {
handleMovieResponse(movieRequest);
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(context, R.string.image_preview_failed, Toast.LENGTH_LONG).show();
}
}
showProgressBar(false);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(context, R.string.image_preview_failed, Toast.LENGTH_LONG).show();
showProgressBar(false);
}
});
movieRequest.setShouldCache(true);
ChanApplication.getVolleyRequestQueue().add(movieRequest);
showProgressBar(true);
@Override
public void onSaveInstanceState(Bundle bundle) {
// https://code.google.com/p/android/issues/detail?id=19917
bundle.putString("bug_19917", "bug_19917");
super.onSaveInstanceState(bundle);
}
private void handleMovieResponse(CachingRequest request) throws IOException {
DiskBasedCache cache = (DiskBasedCache) ChanApplication.getVolleyRequestQueue().getCache();
File file = cache.getFileForKey(movieRequest.getCacheKey());
if (file.exists()) {
Logger.test("Showing video from " + file.getAbsolutePath());
final VideoView view = new VideoView(context);
view.setZOrderOnTop(true);
view.setOnLongClickListener(this);
view.setOnClickListener(this);
wrapper.addView(view, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
public void onSelected(ImageViewAdapter adapter, int position) {
activity.setProgressBarIndeterminateVisibility(showProgressBar);
view.setOnPreparedListener(new OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
mp.setLooping(true);
view.start();
}
});
String filename = post.filename + "." + post.ext;
activity.getActionBar().setTitle(filename);
String text = (position + 1) + "/" + adapter.getCount();
activity.getActionBar().setSubtitle(text);
view.setVideoPath(file.getAbsolutePath());
} else {
Logger.e(TAG, "Cache file doesn't exist");
Toast.makeText(context, R.string.image_preview_failed, Toast.LENGTH_LONG).show();
}
activity.invalidateActionBar();
}
private void loadOtherImage(String url) {
NetworkPhotoView imageView = new NetworkPhotoView(context);
imageView.setImageViewFragment(this);
imageView.setFadeIn(100);
imageView.setImageUrl(url, ChanApplication.getImageLoader());
imageView.setMaxScale(3f);
imageView.setOnLongClickListenerToAttacher(this);
imageView.setOnViewTapListenerToAttacher(this);
wrapper.addView(imageView, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
showProgressBar(true);
public void onPrepareOptionsMenu(int position, ImageViewAdapter adapter, Menu menu) {
MenuItem item = menu.findItem(R.id.action_image_play_state);
item.setVisible(isVideo);
item.setEnabled(isVideo);
VideoView view = imageView.getVideoView();
if (view != null) {
item.setIcon((videoSetIconToPause || view.isPlaying()) ? R.drawable.ic_action_pause : R.drawable.ic_action_play);
}
videoSetIconToPause = false;
}
private void loadGif() {
ChanApplication.getVolleyRequestQueue().add(new GIFRequest(post.imageUrl, new Response.Listener<GIFView>() {
@Override
public void onResponse(GIFView view) {
wrapper.addView(view, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
view.setOnLongClickListener(ImageViewFragment.this);
view.setOnClickListener(ImageViewFragment.this);
showProgressBar(false);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(context, R.string.image_preview_failed, Toast.LENGTH_LONG).show();
showProgressBar(false);
public void customOnOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.action_image_play_state) {
if (!videoVisible) {
videoVisible = true;
imageView.setVideo(post.imageUrl);
} else {
VideoView view = imageView.getVideoView();
if (view != null) {
if (!view.isPlaying()) {
view.start();
} else {
view.pause();
}
}
}
}, context));
showProgressBar(true);
activity.invalidateActionBar();
}
}
@Override
/*
* TODO: figure out why adding an onLongClick listener removes the error:
* "ImageView no longer exists. You should not use this PhotoViewAttacher any more."
* ); PhotoViewAttacher line 300
*/
public boolean onLongClick(View v) {
return false;
public void showProgressBar(boolean e) {
showProgressBar = e;
activity.callOnSelect();
}
@Override
public void onViewTap(View view, float x, float y) {
public void onTap() {
activity.finish();
}
@Override
public void setProgress(boolean progress) {
showProgressBar(progress);
}
@Override
public void onClick(View v) {
activity.finish();
public void onVideoLoaded() {
videoSetIconToPause = true;
activity.invalidateActionBar();
}
}

@ -28,7 +28,7 @@ import com.android.volley.toolbox.ImageLoader.ImageListener;
/**
* Custom version of NetworkImageView
*
*
* Handles fetching an image from a URL as well as the life-cycle of the
* associated request.
*/
@ -74,7 +74,7 @@ public class CustomNetworkImageView extends ImageView {
/**
* How larger the inner bitmap is to the defined view size.
*
*
* @param amount
*/
public void setMaxScale(float amount) {
@ -87,7 +87,7 @@ public class CustomNetworkImageView extends ImageView {
/**
* Animate the image fading in.
*
*
* @param duration
* duration of the fade animation in milliseconds
*/
@ -100,12 +100,12 @@ public class CustomNetworkImageView extends ImageView {
* calling this will immediately either set the cached image (if available)
* or the default image specified by
* {@link CustomNetworkImageView#setDefaultImageResId(int)} on the view.
*
*
* NOTE: If applicable,
* {@link CustomNetworkImageView#setDefaultImageResId(int)} and
* {@link CustomNetworkImageView#setErrorImageResId(int)} should be called
* prior to calling this function.
*
*
* @param url
* The URL that should be loaded into this ImageView.
* @param imageLoader
@ -139,7 +139,7 @@ public class CustomNetworkImageView extends ImageView {
/**
* Loads the image for the view if it isn't already loaded.
*
*
* @param isInLayoutPass
* True if this was invoked from a layout pass, false otherwise.
*/
@ -207,12 +207,9 @@ public class CustomNetworkImageView extends ImageView {
@Override
public void onResponse(final ImageContainer response, boolean isImmediate) {
// If this was an immediate response that was delivered inside
// of a layout
// pass do not set the image immediately as it will trigger a
// requestLayout
// inside of a layout. Instead, defer setting the image by
// posting back to
// If this was an immediate response that was delivered inside of a layout
// pass do not set the image immediately as it will trigger a requestLayout
// inside of a layout. Instead, defer setting the image by posting back to
// the main thread.
if (isImmediate && isInLayoutPass) {
post(new Runnable() {
@ -235,7 +232,7 @@ public class CustomNetworkImageView extends ImageView {
setImageResource(mDefaultImageId);
}
}
}, (int)(maxWidth * mMaxScale), (int)(maxHeight * mMaxScale));
}, (int) (maxWidth * mMaxScale), (int) (maxHeight * mMaxScale));
// update the ImageContainer to be the new bitmap container.
mImageContainer = newContainer;

@ -12,70 +12,76 @@ import android.widget.LinearLayout;
import android.widget.ProgressBar;
/**
* Container for a view with an ProgressBar. Toggles between the view and a ProgressBar.
* Container for a view with an ProgressBar. Toggles between the view and a
* ProgressBar.
*/
public class LoadView extends FrameLayout {
public int fadeDuration = 100;
private View currentView;
public LoadView(Context context) {
super(context);
init();
}
public LoadView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public LoadView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
setView(null);
setView(null, false);
}
/**
* Set the content of this container. It will fade the old one out with the new one.
* Set view to null to show the progressbar.
* @param view the view or null for a progressbar.
* Set the content of this container. It will fade the old one out with the
* new one. Set view to null to show the progressbar.
*
* @param view
* the view or null for a progressbar.
*/
public void setView(View view) {
setView(view, true);
}
public void setView(View view, boolean animation) {
if (view == null) {
LinearLayout layout = new LinearLayout(getContext());
layout.setGravity(Gravity.CENTER);
ProgressBar pb = new ProgressBar(getContext());
layout.addView(pb);
view = layout;
}
while (getChildCount() > 2) {
while (getChildCount() > 1) {
removeViewAt(0);
}
View currentView = getChildAt(0);
if (currentView != null) {
final View tempView = currentView;
currentView.animate().setDuration(fadeDuration).alpha(0).setListener(new SimpleAnimatorListener() {
@Override
public void onAnimationEnd(Animator animation) {
removeView(tempView);
}
});
if (animation) {
final View tempView = currentView;
currentView.animate().setDuration(fadeDuration).alpha(0).setListener(new SimpleAnimatorListener() {
@Override
public void onAnimationEnd(Animator animation) {
removeView(tempView);
}
});
} else {
removeView(currentView);
}
}
addView(view);
view.setAlpha(0f);
view.animate().setDuration(fadeDuration).alpha(1f);
currentView = view;
if (animation) {
view.setAlpha(0f);
view.animate().setDuration(fadeDuration).alpha(1f);
}
}
}

@ -0,0 +1,226 @@
package org.floens.chan.ui.view;
import java.io.File;
import org.floens.chan.ChanApplication;
import org.floens.chan.R;
import org.floens.chan.core.net.FileRequest;
import org.floens.chan.core.net.GIFRequest;
import org.floens.chan.utils.Utils;
import uk.co.senab.photoview.PhotoViewAttacher;
import uk.co.senab.photoview.PhotoViewAttacher.OnViewTapListener;
import android.content.Context;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnPreparedListener;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;
import android.widget.VideoView;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.ImageLoader.ImageContainer;
import com.android.volley.toolbox.ImageLoader.ImageListener;
public class ThumbnailImageView extends LoadView implements OnViewTapListener, View.OnClickListener {
private ThumbnailImageViewCallback callback;
/**
* Max amount to scale the image inside the view
*/
private final float maxScale = 3f;
private boolean thumbnailNeeded = true;
private VideoView videoView;
public ThumbnailImageView(Context context) {
super(context);
init();
}
public ThumbnailImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public ThumbnailImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
setOnClickListener(this);
}
public void setCallback(ThumbnailImageViewCallback callback) {
this.callback = callback;
}
public void setThumbnail(String thumbnailUrl) {
ChanApplication.getImageLoader().get(thumbnailUrl, new ImageListener() {
@Override
public void onErrorResponse(VolleyError error) {
onError();
}
@Override
public void onResponse(ImageContainer response, boolean isImmediate) {
if (response.getBitmap() != null && thumbnailNeeded) {
ImageView thumbnail = new ImageView(getContext());
thumbnail.setImageBitmap(response.getBitmap());
thumbnail.setLayoutParams(Utils.MATCH_PARAMS);
setView(thumbnail, false);
}
}
}, getWidth(), getHeight());
}
public void setBigImage(String imageUrl) {
callback.setProgress(true);
ChanApplication.getImageLoader().get(imageUrl, new ImageListener() {
@Override
public void onErrorResponse(VolleyError error) {
onError();
}
@Override
public void onResponse(ImageContainer response, boolean isImmediate) {
if (response.getBitmap() != null) {
CleanupImageView image = new CleanupImageView(getContext());
image.setImageBitmap(response.getBitmap());
PhotoViewAttacher attacher = new PhotoViewAttacher(image);
attacher.setOnViewTapListener(ThumbnailImageView.this);
attacher.setMaximumScale(maxScale);
image.setAttacher(attacher);
setView(image, !isImmediate);
callback.setProgress(false);
thumbnailNeeded = false;
}
}
}, (int) (getWidth() * maxScale), (int) (getHeight() * maxScale));
}
public void setGif(String gifUrl) {
callback.setProgress(true);
ChanApplication.getVolleyRequestQueue().add(new GIFRequest(gifUrl, new Response.Listener<GIFView>() {
@Override
public void onResponse(GIFView view) {
view.setLayoutParams(Utils.MATCH_PARAMS);
setView(view, false);
callback.setProgress(false);
thumbnailNeeded = false;
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
onError();
}
}, getContext()));
}
public void setVideo(String videoUrl) {
callback.setProgress(true);
ChanApplication.getVolleyRequestQueue().add(new FileRequest(videoUrl, new Response.Listener<File>() {
@Override
public void onResponse(File file) {
if (file != null) {
videoView = new VideoView(getContext());
videoView.setZOrderOnTop(true);
videoView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
videoView.setLayoutParams(Utils.MATCH_PARAMS);
LayoutParams par = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
par.gravity = Gravity.CENTER;
videoView.setLayoutParams(par);
videoView.setOnPreparedListener(new OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
mp.setLooping(true);
callback.onVideoLoaded();
}
});
videoView.setVideoPath(file.getAbsolutePath());
videoView.start();
setView(videoView, false);
callback.setProgress(false);
thumbnailNeeded = false;
} else {
onError();
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
onError();
}
}));
}
public VideoView getVideoView() {
return videoView;
}
public void onError() {
Toast.makeText(getContext(), R.string.image_preview_failed, Toast.LENGTH_LONG).show();
callback.setProgress(false);
}
@Override
public void onViewTap(View view, float x, float y) {
callback.onTap();
}
@Override
public void onClick(View v) {
callback.onTap();
}
public static interface ThumbnailImageViewCallback {
public void onTap();
public void setProgress(boolean progress);
public void onVideoLoaded();
}
private static class CleanupImageView extends ImageView {
private PhotoViewAttacher attacher;
public CleanupImageView(Context context) {
super(context);
}
public CleanupImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CleanupImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void setAttacher(PhotoViewAttacher attacher) {
this.attacher = attacher;
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (attacher != null) {
attacher.cleanup();
}
}
}
}

@ -7,8 +7,14 @@ import android.os.Handler;
import android.os.Looper;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
public class Utils {
public final static ViewGroup.LayoutParams MATCH_PARAMS = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
public final static ViewGroup.LayoutParams WRAP_PARAMS = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
public final static ViewGroup.LayoutParams MATCH_WRAP_PARAMS = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
public final static ViewGroup.LayoutParams WRAP_MATCH_PARAMS = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT);
public static int dp(Context context, float dp) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics());
}

Loading…
Cancel
Save