diff --git a/Chan/res/drawable-hdpi/ic_action_play.png b/Chan/res/drawable-hdpi/ic_action_play.png
new file mode 100644
index 00000000..9a2147ec
Binary files /dev/null and b/Chan/res/drawable-hdpi/ic_action_play.png differ
diff --git a/Chan/res/drawable-mdpi/ic_action_play.png b/Chan/res/drawable-mdpi/ic_action_play.png
new file mode 100644
index 00000000..b94fbe6e
Binary files /dev/null and b/Chan/res/drawable-mdpi/ic_action_play.png differ
diff --git a/Chan/res/drawable-xhdpi/ic_action_play.png b/Chan/res/drawable-xhdpi/ic_action_play.png
new file mode 100644
index 00000000..e01a8445
Binary files /dev/null and b/Chan/res/drawable-xhdpi/ic_action_play.png differ
diff --git a/Chan/res/drawable-xxhdpi/ic_action_play.png b/Chan/res/drawable-xxhdpi/ic_action_play.png
new file mode 100644
index 00000000..7f7ca2e0
Binary files /dev/null and b/Chan/res/drawable-xxhdpi/ic_action_play.png differ
diff --git a/Chan/res/menu/image_view.xml b/Chan/res/menu/image_view.xml
index 1994db71..9d30282d 100644
--- a/Chan/res/menu/image_view.xml
+++ b/Chan/res/menu/image_view.xml
@@ -1,9 +1,16 @@
+
\ No newline at end of file
diff --git a/Chan/res/values/dimens.xml b/Chan/res/values/dimens.xml
index b38361f2..b1b42513 100644
--- a/Chan/res/values/dimens.xml
+++ b/Chan/res/values/dimens.xml
@@ -5,12 +5,10 @@
11dp
6dp
- 48dp
-
70dp
24dp
14dp
200dp
- 8dp
+ 8dp
diff --git a/Chan/res/values/strings.xml b/Chan/res/values/strings.xml
index a593c58d..47689e10 100644
--- a/Chan/res/values/strings.xml
+++ b/Chan/res/values/strings.xml
@@ -29,6 +29,7 @@
Saving image failed
Cannot make save directory
Cannot write to storage
+ Start / stop playing
Failed to show image
Failed to open image
diff --git a/Chan/src/org/floens/chan/core/net/CachingRequest.java b/Chan/src/org/floens/chan/core/net/FileRequest.java
similarity index 53%
rename from Chan/src/org/floens/chan/core/net/CachingRequest.java
rename to Chan/src/org/floens/chan/core/net/FileRequest.java
index a2700ce2..172329b5 100644
--- a/Chan/src/org/floens/chan/core/net/CachingRequest.java
+++ b/Chan/src/org/floens/chan/core/net/FileRequest.java
@@ -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 {
- protected final Listener listener;
+public class FileRequest extends Request {
+ protected final Listener listener;
- public CachingRequest(String url, Listener listener, ErrorListener errorListener) {
+ public FileRequest(String url, Listener listener, ErrorListener errorListener) {
super(Method.GET, url, errorListener);
this.listener = listener;
@@ -24,6 +29,13 @@ public class CachingRequest extends Request {
@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);
+ }
}
}
diff --git a/Chan/src/org/floens/chan/ui/activity/ImageViewActivity.java b/Chan/src/org/floens/chan/ui/activity/ImageViewActivity.java
index afcee46b..910e8ceb 100644
--- a/Chan/src/org/floens/chan/ui/activity/ImageViewActivity.java
+++ b/Chan/src/org/floens/chan/ui/activity/ImageViewActivity.java
@@ -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 imagePosts = new ArrayList();
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;
+ }
}
}
-
-
-
-
-
diff --git a/Chan/src/org/floens/chan/ui/adapter/ImageViewAdapter.java b/Chan/src/org/floens/chan/ui/adapter/ImageViewAdapter.java
index aecbf9cb..b5142126 100644
--- a/Chan/src/org/floens/chan/ui/adapter/ImageViewAdapter.java
+++ b/Chan/src/org/floens/chan/ui/adapter/ImageViewAdapter.java
@@ -15,7 +15,6 @@ import android.view.View;
public class ImageViewAdapter extends FragmentStatePagerAdapter {
private final ImageViewActivity activity;
- private int count = 0;
private final ArrayList postList = new ArrayList();
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 list){
- count += list.size();
+ public void setList(ArrayList list){
+ postList.clear();
postList.addAll(list);
notifyDataSetChanged();
diff --git a/Chan/src/org/floens/chan/ui/adapter/PostAdapter.java b/Chan/src/org/floens/chan/ui/adapter/PostAdapter.java
index b2a2f946..6bf0e8f4 100644
--- a/Chan/src/org/floens/chan/ui/adapter/PostAdapter.java
+++ b/Chan/src/org/floens/chan/ui/adapter/PostAdapter.java
@@ -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;
diff --git a/Chan/src/org/floens/chan/ui/fragment/ImageViewFragment.java b/Chan/src/org/floens/chan/ui/fragment/ImageViewFragment.java
index 2beb52c8..2e091c63 100644
--- a/Chan/src/org/floens/chan/ui/fragment/ImageViewFragment.java
+++ b/Chan/src/org/floens/chan/ui/fragment/ImageViewFragment.java
@@ -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() {
- @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() {
- @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();
}
}
diff --git a/Chan/src/org/floens/chan/ui/view/CustomNetworkImageView.java b/Chan/src/org/floens/chan/ui/view/CustomNetworkImageView.java
index 9d606a2f..647c6cdd 100644
--- a/Chan/src/org/floens/chan/ui/view/CustomNetworkImageView.java
+++ b/Chan/src/org/floens/chan/ui/view/CustomNetworkImageView.java
@@ -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;
diff --git a/Chan/src/org/floens/chan/ui/view/LoadView.java b/Chan/src/org/floens/chan/ui/view/LoadView.java
index 74e74392..95b7d36e 100644
--- a/Chan/src/org/floens/chan/ui/view/LoadView.java
+++ b/Chan/src/org/floens/chan/ui/view/LoadView.java
@@ -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);
+ }
}
}
-
-
-
-
-
diff --git a/Chan/src/org/floens/chan/ui/view/ThumbnailImageView.java b/Chan/src/org/floens/chan/ui/view/ThumbnailImageView.java
new file mode 100644
index 00000000..96f7f7d9
--- /dev/null
+++ b/Chan/src/org/floens/chan/ui/view/ThumbnailImageView.java
@@ -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() {
+ @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() {
+ @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();
+ }
+ }
+ }
+}
diff --git a/Chan/src/org/floens/chan/utils/Utils.java b/Chan/src/org/floens/chan/utils/Utils.java
index fe6936ed..c82d0d89 100644
--- a/Chan/src/org/floens/chan/utils/Utils.java
+++ b/Chan/src/org/floens/chan/utils/Utils.java
@@ -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());
}