diff options
author | Jorge Ruesga <jorge@ruesga.com> | 2013-11-02 02:20:56 +0100 |
---|---|---|
committer | Jorge Ruesga <jorge@ruesga.com> | 2013-11-02 02:20:56 +0100 |
commit | 4effddfe30fd045834232f6bb66070edf079578d (patch) | |
tree | 2e57f74d55685891a49b02ec069c118cf5b15110 /src/org | |
parent | ca2f0060cc367ac8174a27a3124cd0124e49c627 (diff) | |
download | android_packages_wallpapers_PhotoPhase-4effddfe30fd045834232f6bb66070edf079578d.tar.gz android_packages_wallpapers_PhotoPhase-4effddfe30fd045834232f6bb66070edf079578d.tar.bz2 android_packages_wallpapers_PhotoPhase-4effddfe30fd045834232f6bb66070edf079578d.zip |
Multiples fixes
- Fully rewrite the album selection preference
- Fix multiple style
- Fix lints
- Resources cleanup
Signed-off-by: Jorge Ruesga <jorge@ruesga.com>
Diffstat (limited to 'src/org')
22 files changed, 1510 insertions, 1051 deletions
diff --git a/src/org/cyanogenmod/wallpapers/photophase/MediaPictureDiscoverer.java b/src/org/cyanogenmod/wallpapers/photophase/MediaPictureDiscoverer.java index 4228abf..f45dcd6 100644 --- a/src/org/cyanogenmod/wallpapers/photophase/MediaPictureDiscoverer.java +++ b/src/org/cyanogenmod/wallpapers/photophase/MediaPictureDiscoverer.java @@ -264,7 +264,7 @@ public class MediaPictureDiscoverer { } } - /*package*/ final Context mContext; + final Context mContext; private final OnMediaPictureDiscoveredListener mCallback; private AsyncDiscoverTask mTask; diff --git a/src/org/cyanogenmod/wallpapers/photophase/PhotoPhaseRenderer.java b/src/org/cyanogenmod/wallpapers/photophase/PhotoPhaseRenderer.java index f57d53b..c307023 100644 --- a/src/org/cyanogenmod/wallpapers/photophase/PhotoPhaseRenderer.java +++ b/src/org/cyanogenmod/wallpapers/photophase/PhotoPhaseRenderer.java @@ -62,25 +62,25 @@ public class PhotoPhaseRenderer implements GLSurfaceView.Renderer { private final long mInstance; private static long sInstances; - /*package*/ final Context mContext; - /*package*/ EffectContext mEffectContext; + final Context mContext; + EffectContext mEffectContext; private final Handler mHandler; - /*package*/ final GLESSurfaceDispatcher mDispatcher; - /*package*/ TextureManager mTextureManager; + final GLESSurfaceDispatcher mDispatcher; + TextureManager mTextureManager; - /*package*/ PhotoPhaseWallpaperWorld mWorld; - /*package*/ ColorShape mOverlay; - /*package*/ OopsShape mOopsShape; + PhotoPhaseWallpaperWorld mWorld; + ColorShape mOverlay; + OopsShape mOopsShape; - /*package*/ long mLastRunningTransition; + long mLastRunningTransition; private long mLastTouchTime; private static final long TOUCH_BARRIER_TIME = 1000L; - /*package*/ int mWidth = -1; - /*package*/ int mHeight = -1; + int mWidth = -1; + int mHeight = -1; private int mStatusBarHeight = 0; - /*package*/ int mMeasuredHeight = -1; + int mMeasuredHeight = -1; private final float[] mMVPMatrix = new float[16]; private final float[] mProjMatrix = new float[16]; @@ -88,7 +88,7 @@ public class PhotoPhaseRenderer implements GLSurfaceView.Renderer { private final Object mDrawing = new Object(); - /*package*/ final Object mMediaSync = new Object(); + final Object mMediaSync = new Object(); private PendingIntent mMediaScanIntent; private final BroadcastReceiver mSettingsChangedReceiver = new BroadcastReceiver() { @@ -383,13 +383,13 @@ public class PhotoPhaseRenderer implements GLSurfaceView.Renderer { /** * Method that deselect the current transition */ - /*package*/ synchronized void deselectCurrentTransition() { + synchronized void deselectCurrentTransition() { mHandler.removeCallbacks(mTransitionThread); mWorld.deselectTransition(mMVPMatrix); mLastRunningTransition = 0; } - /*package*/ void scheduleOrCancelMediaScan() { + void scheduleOrCancelMediaScan() { int interval = Preferences.Media.getRefreshFrecuency(); if (interval != Preferences.Media.MEDIA_RELOAD_DISABLED) { scheduleMediaScan(interval); diff --git a/src/org/cyanogenmod/wallpapers/photophase/PhotoPhaseWallpaper.java b/src/org/cyanogenmod/wallpapers/photophase/PhotoPhaseWallpaper.java index 625212c..5152bc8 100644 --- a/src/org/cyanogenmod/wallpapers/photophase/PhotoPhaseWallpaper.java +++ b/src/org/cyanogenmod/wallpapers/photophase/PhotoPhaseWallpaper.java @@ -96,7 +96,7 @@ public class PhotoPhaseWallpaper class PhotoPhaseWallpaperEngine extends GLES20WallpaperService.GLES20Engine { private final Handler mHandler; - /*package*/ final ActivityManager mActivityManager; + final ActivityManager mActivityManager; /** * Constructor of <code>PhotoPhaseWallpaperEngine<code> diff --git a/src/org/cyanogenmod/wallpapers/photophase/TextureManager.java b/src/org/cyanogenmod/wallpapers/photophase/TextureManager.java index 6c8de05..3731a1b 100644 --- a/src/org/cyanogenmod/wallpapers/photophase/TextureManager.java +++ b/src/org/cyanogenmod/wallpapers/photophase/TextureManager.java @@ -59,8 +59,8 @@ public class TextureManager implements OnMediaPictureDiscoveredListener { BackgroundPictureLoaderThread mBackgroundTask; /*protected*/ final MediaPictureDiscoverer mPictureDiscoverer; - /*package*/ Rect mScreenDimensions; - /*package*/ Rect mDimensions; + Rect mScreenDimensions; + Rect mDimensions; final GLESSurfaceDispatcher mDispatcher; @@ -73,7 +73,7 @@ public class TextureManager implements OnMediaPictureDiscoveredListener { /** * A private runnable that will run in the GLThread */ - /*package*/ class PictureDispatcher implements Runnable { + class PictureDispatcher implements Runnable { File mImage; GLESTextureInfo ti = null; final Object mWait = new Object(); @@ -428,7 +428,7 @@ public class TextureManager implements OnMediaPictureDiscoveredListener { * @param ti The original texture information * @param effect The effect to apply to the destination picture */ - /*package*/ void fixAspectRatio(TextureRequestor requestor, GLESTextureInfo ti) { + void fixAspectRatio(TextureRequestor requestor, GLESTextureInfo ti) { // Check if we have to apply any correction to the image if (Preferences.General.isFixAspectRatio()) { // Transform requestor dimensions to screen dimensions @@ -472,7 +472,7 @@ public class TextureManager implements OnMediaPictureDiscoveredListener { boolean mRun; boolean mTaskPaused; - /*package*/ boolean mEmpty; + boolean mEmpty; private final List<File> mNewImages; private final List<File> mUsedImages; diff --git a/src/org/cyanogenmod/wallpapers/photophase/adapters/AlbumCardUiAdapter.java b/src/org/cyanogenmod/wallpapers/photophase/adapters/AlbumCardUiAdapter.java new file mode 100644 index 0000000..b321b73 --- /dev/null +++ b/src/org/cyanogenmod/wallpapers/photophase/adapters/AlbumCardUiAdapter.java @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2013 The CyanogenMod Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cyanogenmod.wallpapers.photophase.adapters; + +import android.animation.Animator; +import android.animation.AnimatorInflater; +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.Animation; +import android.view.animation.AnimationUtils; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; + +import org.cyanogenmod.wallpapers.photophase.R; +import org.cyanogenmod.wallpapers.photophase.model.Album; +import org.cyanogenmod.wallpapers.photophase.widgets.AlbumInfoView; + +import java.util.ArrayList; +import java.util.List; + +/** + * An implementation of {@link ArrayAdapter} supporting "Google Now Card Layout" like layout + */ +public class AlbumCardUiAdapter extends ArrayAdapter<Album> { + + /** + * A class that conforms with the ViewHolder pattern to performance + * the list view rendering. + */ + private static class ViewHolder { + public ViewHolder() { + super(); + } + AlbumInfoView mAlbumInfoView; + Animation mCardAnimation; + Animator mCardAnimator; + } + + private List<Album> mData = new ArrayList<Album>(); + + private AlbumInfoView.CallbacksListener mAlbumInfoCallback; + + /** + * Constructor of <code>AlbumCardUiAdapter</code>. + * + * @param context The current context + * @param parent The adapter view + * @param data The array with all the album data + * @param callback The album info view callback + */ + public AlbumCardUiAdapter(Context context, AdapterView<?> parent, List<Album> data, + AlbumInfoView.CallbacksListener callback) { + super(context, R.id.album_name, data); + mData = data; + mAlbumInfoCallback = callback; + } + + /** + * Method that dispose the elements of the adapter. + */ + public void dispose() { + clear(); + this.mData = null; + } + + /** + * {@inheritDoc} + */ + @Override + public View getView(int position, View convertView, ViewGroup parent) { + + // Retrieve album + final Album album = this.mData.get(position); + + // Check to reuse view + View v = convertView; + if (v == null) { + //Create the view holder + LayoutInflater li = + (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + v = li.inflate(R.layout.album_info, parent, false); + + // Create the controller for the view + ViewHolder viewHolder = new ViewHolder(); + viewHolder.mAlbumInfoView = (AlbumInfoView)v.findViewById(R.id.album_info); + viewHolder.mAlbumInfoView.setAlbum(album); + viewHolder.mAlbumInfoView.addCallBackListener(mAlbumInfoCallback); + v.setTag(viewHolder); + } + + // Retrieve the view holder + ViewHolder viewHolder = (ViewHolder)v.getTag(); + + // Retrieve the view holder and update the view + viewHolder.mAlbumInfoView.updateView(album); + + // Animate the view? + if (!album.isDisplayed()) { + album.setDisplayed(true); + + // Reset the animation + if (viewHolder.mCardAnimation != null) { + viewHolder.mCardAnimation.cancel(); + } + if (viewHolder.mCardAnimator != null) { + viewHolder.mCardAnimator.cancel(); + } + + // Card Animation + viewHolder.mCardAnimation = AnimationUtils.loadAnimation( + getContext(), R.anim.cards_slide_up); + v.startAnimation(viewHolder.mCardAnimation); + viewHolder.mCardAnimator = AnimatorInflater.loadAnimator(getContext(), + R.animator.cards_rotate_animator); + viewHolder.mCardAnimator.setTarget(v); + viewHolder.mCardAnimator.start(); + } + + // Return the view + return v; + } + +} diff --git a/src/org/cyanogenmod/wallpapers/photophase/adapters/AlbumPictureAdapter.java b/src/org/cyanogenmod/wallpapers/photophase/adapters/AlbumPictureAdapter.java new file mode 100644 index 0000000..addc298 --- /dev/null +++ b/src/org/cyanogenmod/wallpapers/photophase/adapters/AlbumPictureAdapter.java @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2013 The CyanogenMod Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cyanogenmod.wallpapers.photophase.adapters; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; + +import org.cyanogenmod.wallpapers.photophase.R; +import org.cyanogenmod.wallpapers.photophase.model.Picture; +import org.cyanogenmod.wallpapers.photophase.widgets.PictureItemView; + +import java.util.ArrayList; +import java.util.List; + +/** + * An implementation of {@link ArrayAdapter} an album picture + */ +public class AlbumPictureAdapter extends ArrayAdapter<Picture> { + + /** + * A class that conforms with the ViewHolder pattern to performance + * the list view rendering. + */ + private static class ViewHolder { + public ViewHolder() { + super(); + } + PictureItemView mPictureItemView; + } + + private List<Picture> mData = new ArrayList<Picture>(); + private AdapterView<?> mParent; + + /** + * Constructor of <code>AlbumPictureAdapter</code>. + * + * @param context The current context + * @param data The pictures data + */ + public AlbumPictureAdapter(Context context, List<Picture> data, AdapterView<?> parent) { + super(context, R.id.picture_thumbnail, data); + mData = data; + mParent = parent; + } + + /** + * Method that dispose the elements of the adapter. + */ + public void dispose() { + clear(); + this.mData = null; + } + + @Override + public void notifyDataSetChanged() { + int start = mParent.getFirstVisiblePosition(); + int last = mParent.getLastVisiblePosition(); + for (int i = start; i <= last; i++) { + View v = mParent.getChildAt(i); + getView(i, v, mParent, false); + } + } + + /** + * {@inheritDoc} + */ + @Override + public View getView(int position, View convertView, ViewGroup parent) { + return getView(position, convertView, parent, true); + } + + /** + * Method that returns a view for a position + * + * @param position The position + * @param convertView A reusable view or null + * @param parent The parent of the view + * @param refreshIcon If the view should refresh its icon + * @return View The view + */ + private View getView(int position, View convertView, ViewGroup parent, boolean refreshIcon) { + final Picture picture = this.mData.get(position); + + // Check to reuse view + View v = convertView; + if (v == null) { + //Create the view holder + LayoutInflater li = + (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + v = li.inflate(R.layout.picture_item, parent, false); + + // Create the controller for the view + ViewHolder viewHolder = new ViewHolder(); + viewHolder.mPictureItemView = (PictureItemView)v.findViewById(R.id.picture); + viewHolder.mPictureItemView.setPicture(picture); + v.setTag(viewHolder); + } + + // Retrieve the view holder + ViewHolder viewHolder = (ViewHolder)v.getTag(); + + // Retrieve the view holder and update the view + viewHolder.mPictureItemView.updateView(picture, refreshIcon); + + // Return the view + return v; + } + +} diff --git a/src/org/cyanogenmod/wallpapers/photophase/animations/AlbumsFlip3dAnimationController.java b/src/org/cyanogenmod/wallpapers/photophase/animations/Flip3dAnimationController.java index 228f827..69f023d 100644 --- a/src/org/cyanogenmod/wallpapers/photophase/animations/AlbumsFlip3dAnimationController.java +++ b/src/org/cyanogenmod/wallpapers/photophase/animations/Flip3dAnimationController.java @@ -16,20 +16,14 @@ package org.cyanogenmod.wallpapers.photophase.animations; import android.view.View; -import android.view.View.OnClickListener; import android.view.animation.AccelerateInterpolator; import android.view.animation.Animation; import android.view.animation.Animation.AnimationListener; -import org.cyanogenmod.wallpapers.photophase.model.Album; -import org.cyanogenmod.wallpapers.photophase.widgets.AlbumInfo; -import org.cyanogenmod.wallpapers.photophase.widgets.AlbumPictures; -import org.cyanogenmod.wallpapers.photophase.widgets.AlbumPictures.CallbacksListener; - /** - * A class that manages a flip 3d effect of an album + * A class that manages a flip 3d effect of two views */ -public class AlbumsFlip3dAnimationController { +public class Flip3dAnimationController { private static final int DURATION = 200; @@ -37,13 +31,15 @@ public class AlbumsFlip3dAnimationController { View mBack; boolean mFrontFace; + final Object mLock = new Object(); + /** - * Constructor of <code>AlbumsFlip3dAnimationController</code> + * Constructor of <code>Flip3dAnimationController</code> * * @param front The front view * @param back The back view */ - public AlbumsFlip3dAnimationController(AlbumInfo front, AlbumPictures back) { + public Flip3dAnimationController(View front, View back) { super(); mFront = front; mBack = back; @@ -51,45 +47,48 @@ public class AlbumsFlip3dAnimationController { mFrontFace = true; } + public boolean isFrontFace() { + return mFrontFace; + } + /** - * Method that register the controller + * Method that reset the controller */ - public void register() { - getFrontView().setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - getBackView().setVisibility(View.INVISIBLE); - applyAnimation(false); - } - }); - ((AlbumPictures)getBackView()).addCallBackListener(new CallbacksListener() { - @Override - public void onBackButtonClick(View v) { - getBackView().setVisibility(View.INVISIBLE); - applyAnimation(true); - } - - @Override - public void onSelectionChanged(Album album) { - // Ignore - } - }); + public void reset() { + changeToFrontFace(true); } /** - * Method that unregister the controller + * Method that change the view to the front face + * + * @param animate Do with animation */ - public void unregister() { - getFrontView().setOnClickListener(null); - getBackView().setOnClickListener(null); + public void changeToFrontFace(boolean animate) { + if (!mFrontFace) { + if (animate) { + applyAnimation(true); + } else { + mBack.setVisibility(View.GONE); + mFront.setVisibility(View.VISIBLE); + mFrontFace = true; + } + } } /** - * Method that reset the controller + * Method that change the view to the back face + * + * @param animate Do with animation */ - public void reset() { - if (!mFrontFace) { - applyAnimation(true); + public void changeToBackFace(boolean animate) { + if (mFrontFace) { + if (animate) { + applyAnimation(true); + } else { + mFront.setVisibility(View.GONE); + mBack.setVisibility(View.VISIBLE); + mFrontFace = false; + } } } @@ -98,11 +97,11 @@ public class AlbumsFlip3dAnimationController { * * @param inverse Applies the inverse animation */ - /*package*/ void applyAnimation(boolean inverse) { + void applyAnimation(boolean inverse) { applyTransformation(getFrontView(), 0, 90 * (inverse ? -1 : 1), true); } - /*package*/ void applyTransformation(final View v, float start, float end, final boolean step1) { + void applyTransformation(final View v, float start, float end, final boolean step1) { final float centerX = v.getWidth() / 2.0f; final float centerY = v.getHeight() / 2.0f; @@ -117,8 +116,6 @@ public class AlbumsFlip3dAnimationController { if (!step1) { getBackView().setVisibility(View.VISIBLE); } - getFrontView().setOnClickListener(null); - getBackView().setOnClickListener(null); } @Override @@ -128,24 +125,16 @@ public class AlbumsFlip3dAnimationController { @Override public void onAnimationEnd(Animation animation) { - getFrontView().setAnimation(null); - getBackView().setAnimation(null); - if (step1) { - getFrontView().setVisibility(View.INVISIBLE); - applyTransformation(getBackView(), -90 * (!mFrontFace ? -1 : 1), 0, false); - } else { - mFrontFace = !mFrontFace; - getBackView().setVisibility(View.GONE); - if (mFrontFace) { - getFrontView().setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - getBackView().setVisibility(View.INVISIBLE); - applyAnimation(false); - } - }); + synchronized (mLock) { + getFrontView().setAnimation(null); + getBackView().setAnimation(null); + if (step1) { + getFrontView().setVisibility(View.INVISIBLE); + applyTransformation(getBackView(), + -90 * (!mFrontFace ? -1 : 1), 0, false); } else { - ((AlbumPictures)getFrontView()).onShow(); + mFrontFace = !mFrontFace; + getBackView().setVisibility(View.GONE); } } } @@ -153,11 +142,11 @@ public class AlbumsFlip3dAnimationController { v.startAnimation(anim); } - /*package*/ View getFrontView() { + View getFrontView() { return mFrontFace ? mFront : mBack; } - /*package*/ View getBackView() { + View getBackView() { return !mFrontFace ? mFront : mBack; } } diff --git a/src/org/cyanogenmod/wallpapers/photophase/animations/Rotate3dAnimation.java b/src/org/cyanogenmod/wallpapers/photophase/animations/Rotate3dAnimation.java new file mode 100644 index 0000000..814ef0f --- /dev/null +++ b/src/org/cyanogenmod/wallpapers/photophase/animations/Rotate3dAnimation.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cyanogenmod.wallpapers.photophase.animations; + +import android.view.animation.Animation; +import android.view.animation.Transformation; +import android.graphics.Camera; +import android.graphics.Matrix; + +/** + * An animation that rotates the view on the Y axis between two specified angles. + * This animation also adds a translation on the Z axis (depth) to improve the effect. + */ +public class Rotate3dAnimation extends Animation { + private final float mFromDegrees; + private final float mToDegrees; + private final float mCenterX; + private final float mCenterY; + private final float mDepthZ; + private final boolean mReverse; + private Camera mCamera; + + /** + * Creates a new 3D rotation on the Y axis. The rotation is defined by its + * start angle and its end angle. Both angles are in degrees. The rotation + * is performed around a center point on the 2D space, definied by a pair + * of X and Y coordinates, called centerX and centerY. When the animation + * starts, a translation on the Z axis (depth) is performed. The length + * of the translation can be specified, as well as whether the translation + * should be reversed in time. + * + * @param fromDegrees the start angle of the 3D rotation + * @param toDegrees the end angle of the 3D rotation + * @param centerX the X center of the 3D rotation + * @param centerY the Y center of the 3D rotation + * @param reverse true if the translation should be reversed, false otherwise + */ + public Rotate3dAnimation(float fromDegrees, float toDegrees, + float centerX, float centerY, float depthZ, boolean reverse) { + mFromDegrees = fromDegrees; + mToDegrees = toDegrees; + mCenterX = centerX; + mCenterY = centerY; + mDepthZ = depthZ; + mReverse = reverse; + } + + @Override + public void initialize(int width, int height, int parentWidth, int parentHeight) { + super.initialize(width, height, parentWidth, parentHeight); + mCamera = new Camera(); + } + + @Override + protected void applyTransformation(float interpolatedTime, Transformation t) { + final float fromDegrees = mFromDegrees; + float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime); + + final float centerX = mCenterX; + final float centerY = mCenterY; + final Camera camera = mCamera; + + final Matrix matrix = t.getMatrix(); + + camera.save(); + if (mReverse) { + camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime); + } else { + camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime)); + } + camera.rotateY(degrees); + camera.getMatrix(matrix); + camera.restore(); + + matrix.preTranslate(-centerX, -centerY); + matrix.postTranslate(centerX, centerY); + } +} + diff --git a/src/org/cyanogenmod/wallpapers/photophase/model/Album.java b/src/org/cyanogenmod/wallpapers/photophase/model/Album.java index 83f067d..0c1c2a2 100644 --- a/src/org/cyanogenmod/wallpapers/photophase/model/Album.java +++ b/src/org/cyanogenmod/wallpapers/photophase/model/Album.java @@ -24,16 +24,20 @@ import java.util.List; /** * A class that represents an album */ -public class Album implements Comparable<Album>, Cloneable { +public class Album implements Comparable<Album>, Cloneable { private Drawable mIcon; private String mPath; private String mName; private String mDate; private boolean mSelected; - private List<String> mItems; + private List<Picture> mItems; + // We have this array for performance access. Do not forget to sync with Picture#selected private List<String> mSelectedItems; + // Ui properties + private boolean mDisplayed = false; + public Drawable getIcon() { return mIcon; } @@ -74,11 +78,11 @@ public class Album implements Comparable<Album>, Cloneable { this.mSelected = selected; } - public List<String> getItems() { + public List<Picture> getItems() { return mItems; } - public void setItems(List<String> items) { + public void setItems(List<Picture> items) { this.mItems = items; } @@ -90,6 +94,14 @@ public class Album implements Comparable<Album>, Cloneable { this.mSelectedItems = selectedItems; } + public boolean isDisplayed() { + return mDisplayed; + } + + public void setDisplayed(boolean mDisplayed) { + this.mDisplayed = mDisplayed; + } + @Override public int compareTo(Album another) { return mPath.compareTo(another.mPath); @@ -102,9 +114,10 @@ public class Album implements Comparable<Album>, Cloneable { album.mPath = mPath; album.mName = mName; album.mDate = mDate; - album.mItems = new ArrayList<String>(mItems); + album.mItems = new ArrayList<Picture>(mItems); album.mSelectedItems = new ArrayList<String>(mSelectedItems); album.mSelected = mSelected; + album.mDisplayed = mDisplayed; return album; } } diff --git a/src/org/cyanogenmod/wallpapers/photophase/model/Picture.java b/src/org/cyanogenmod/wallpapers/photophase/model/Picture.java new file mode 100644 index 0000000..76b1bb6 --- /dev/null +++ b/src/org/cyanogenmod/wallpapers/photophase/model/Picture.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2013 The CyanogenMod Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cyanogenmod.wallpapers.photophase.model; + +import java.io.File; + +/** + * A class that represents a picture + */ +public class Picture implements Comparable<Picture>, Cloneable { + + private String mPath; + private boolean mSelected; + + public Picture(String path, boolean selected) { + super(); + this.mPath = path; + this.mSelected = selected; + } + + public String getPath() { + return mPath; + } + + public void setPath(String path) { + this.mPath = path; + } + + public boolean isSelected() { + return mSelected; + } + + public void setSelected(boolean selected) { + this.mSelected = selected; + } + + public String getName() { + return new File(mPath).getName(); + } + + @Override + public int compareTo(Picture another) { + return mPath.compareTo(another.mPath); + } + + @Override + public Object clone() { + return new Picture(mPath, mSelected); + } +} diff --git a/src/org/cyanogenmod/wallpapers/photophase/preferences/ChoosePicturesFragment.java b/src/org/cyanogenmod/wallpapers/photophase/preferences/ChoosePicturesFragment.java index 6e41308..00d75a6 100644 --- a/src/org/cyanogenmod/wallpapers/photophase/preferences/ChoosePicturesFragment.java +++ b/src/org/cyanogenmod/wallpapers/photophase/preferences/ChoosePicturesFragment.java @@ -16,7 +16,9 @@ package org.cyanogenmod.wallpapers.photophase.preferences; -import android.content.ContentResolver; +import android.animation.Animator; +import android.animation.Animator.AnimatorListener; +import android.animation.ObjectAnimator; import android.content.Context; import android.content.Intent; import android.content.res.Resources; @@ -24,6 +26,8 @@ import android.database.Cursor; import android.os.AsyncTask; import android.os.AsyncTask.Status; import android.os.Bundle; +import android.os.Handler; +import android.os.Message; import android.preference.PreferenceFragment; import android.provider.MediaStore; import android.util.Log; @@ -32,19 +36,30 @@ import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; +import android.view.View.OnClickListener; import android.view.ViewGroup; +import android.view.animation.AccelerateDecelerateInterpolator; +import android.view.animation.AlphaAnimation; +import android.view.animation.Animation; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.FrameLayout; +import android.widget.GridView; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.TextView; import org.cyanogenmod.wallpapers.photophase.R; -import org.cyanogenmod.wallpapers.photophase.animations.AlbumsFlip3dAnimationController; +import org.cyanogenmod.wallpapers.photophase.adapters.AlbumCardUiAdapter; +import org.cyanogenmod.wallpapers.photophase.adapters.AlbumPictureAdapter; import org.cyanogenmod.wallpapers.photophase.model.Album; +import org.cyanogenmod.wallpapers.photophase.model.Picture; import org.cyanogenmod.wallpapers.photophase.preferences.PreferencesProvider.Preferences; -import org.cyanogenmod.wallpapers.photophase.widgets.AlbumInfo; -import org.cyanogenmod.wallpapers.photophase.widgets.AlbumPictures; -import org.cyanogenmod.wallpapers.photophase.widgets.CardLayout; -import org.cyanogenmod.wallpapers.photophase.widgets.VerticalEndlessScroller; -import org.cyanogenmod.wallpapers.photophase.widgets.VerticalEndlessScroller.OnEndScrollListener; +import org.cyanogenmod.wallpapers.photophase.widgets.AlbumInfoView; +import org.cyanogenmod.wallpapers.photophase.widgets.PictureItemView; import java.io.File; +import java.io.IOException; import java.text.DateFormat; import java.util.ArrayList; import java.util.Date; @@ -56,25 +71,28 @@ import java.util.Set; /** * A fragment class for select the picture that will be displayed on the wallpaper */ -public class ChoosePicturesFragment extends PreferenceFragment implements OnEndScrollListener { +public class ChoosePicturesFragment extends PreferenceFragment + implements AlbumInfoView.CallbacksListener, OnClickListener { private static final String TAG = "ChoosePicturesFragment"; private static final boolean DEBUG = false; - private static final int AMOUNT_OF_ADDED_STEPS = 5; + private static final int PROGRESS_STEPS = 5; + + // The album loader task + private final AsyncTask<Void, Album, Void> mTask = new AsyncTask<Void, Album, Void>() { + + private DateFormat mDateFormat; - private final AsyncTask<Void, Album, Void> mAlbumsLoaderTask = new AsyncTask<Void, Album, Void>() { /** * {@inheritDoc} */ @Override protected Void doInBackground(Void... params) { // Query all the external content and classify the pictures in albums and load the cards - DateFormat df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT); - Album album = null; - unregister(); - Cursor c = mContentResolver.query( + mDateFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT); + Cursor c = getActivity().getContentResolver().query( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new String[]{ MediaStore.MediaColumns.DATA }, null, @@ -84,40 +102,31 @@ public class ChoosePicturesFragment extends PreferenceFragment implements OnEndS try { long start = System.currentTimeMillis(); if (DEBUG) Log.v(TAG, "Media library:"); + int count = 0; + List<Album> pending = new ArrayList<Album>(); + List<Album> all = new ArrayList<Album>(); + Album album = null; while (c.moveToNext()) { - // Only valid files (those i can read) - String p = c.getString(0); - if (DEBUG) Log.v(TAG, "\t" + p); - if (p != null) { - File f = new File(p); - if (f.isFile() && f.canRead()) { - File path = f.getParentFile(); - String name = path.getName(); - if (album == null || album.getPath().compareTo(path.getAbsolutePath()) != 0) { - if (album != null) { - mAlbums.add(album); - mOriginalAlbums.add((Album)album.clone()); - } - album = new Album(); - album.setPath(path.getAbsolutePath()); - album.setName(name); - album.setDate(df.format(new Date(path.lastModified()))); - album.setSelected(isSelectedItem(album.getPath())); - album.setItems(new ArrayList<String>()); - album.setSelectedItems(new ArrayList<String>()); - } - album.getItems().add(f.getAbsolutePath()); - if (isSelectedItem(f.getAbsolutePath())) { - album.getSelectedItems().add(f.getAbsolutePath()); - } - } + album = processPath(all, pending, album, c.getString(0)); + count++; + if (count % PROGRESS_STEPS == 0) { + // Notify and clean + publishProgress(pending.toArray(new Album[pending.size()])); + pending.clear(); } } - // Add the last album + // Add the last albums if (album != null) { - mAlbums.add(album); + // Add to global structures + all.add(album); mOriginalAlbums.add((Album)album.clone()); + + // Add to local structures and notify + pending.add(album); + + // Notify + publishProgress(pending.toArray(new Album[pending.size()])); } long end = System.currentTimeMillis(); if (DEBUG) Log.v(TAG, "Library loaded in " + (end - start) + " miliseconds"); @@ -133,43 +142,139 @@ public class ChoosePicturesFragment extends PreferenceFragment implements OnEndS * {@inheritDoc} */ @Override + protected void onProgressUpdate(Album... albums) { + for(Album album : albums) { + mAlbums.add(album); + } + mAlbumAdapter.notifyDataSetChanged(); + } + + /** + * {@inheritDoc} + */ + @Override protected void onPostExecute(Void result) { - Resources res = getActivity().getResources(); - int size = (int)(res.getDimension(R.dimen.album_size) + - res.getDimension(R.dimen.small_margin)); - mScroller.setEndPadding(size * AMOUNT_OF_ADDED_STEPS); - int height = mScroller.getMeasuredHeight(); - int steps = (height / size) + AMOUNT_OF_ADDED_STEPS; - - // Create the views an force a redraw the items - mAlbumViews = new ArrayList<View>(mAlbums.size()); - for (Album item : mAlbums) { - mAlbumViews.add(createAlbumView(item)); + mAlbumAdapter.notifyDataSetChanged(); + } + + /** + * Method that process a album path + * + * @param all All the albums + * @param pending Pending albums to notify + * @param data The current album data + * @param path The path to analyze + * @return Album The new current album + */ + private Album processPath(List<Album> all, List<Album> pending, Album data, String path) { + // Only valid files (those i can read) + if (DEBUG) Log.v(TAG, "\t" + path); + Album album = data; + if (path != null) { + File f = new File(path); + if (f.isFile() && f.canRead()) { + File p = f.getParentFile(); + String name = p.getName(); + if (album == null || album.getPath().compareTo(p.getAbsolutePath()) != 0) { + if (album != null) { + // Add to global structures + all.add(album); + mOriginalAlbums.add((Album)album.clone()); + + // Add to local structures and notify + pending.add(album); + } + album = new Album(); + album.setPath(p.getAbsolutePath()); + album.setName(name); + album.setDate(mDateFormat.format(new Date(p.lastModified()))); + album.setSelected(isSelectedItem(album.getPath())); + album.setItems(new ArrayList<Picture>()); + album.setSelectedItems(new ArrayList<String>()); + } + boolean selected = isSelectedItem(f.getAbsolutePath()); + album.getItems().add(new Picture(f.getAbsolutePath(), selected)); + if (selected) { + album.getSelectedItems().add(f.getAbsolutePath()); + } + } } - doEndScroll(steps, true); + return album; + } - // We not need Hardware acceleration anymore (no more animations) - // Disable drawing cache - mScroller.setLayerType(View.LAYER_TYPE_SOFTWARE, null); - mScroller.setDrawingCacheEnabled(false); - mScroller.setSmoothScrollingEnabled(true); + /** + * Method that checks if an item is selected + * + * @param item The item + * @return boolean if an item is selected + */ + private boolean isSelectedItem(String item) { + Iterator<String> it = mSelectedAlbums.iterator(); + while (it.hasNext()) { + String albumPath = it.next(); + if (item.compareTo(albumPath) == 0) { + return true; + } + } + return false; } }; - /*package*/ ContentResolver mContentResolver; + private final Handler.Callback mCallback = new Handler.Callback() { + @Override + public boolean handleMessage(Message msg) { + if (msg.what == MSG_LOAD_PICTURES) { + loadPictures((Album)msg.obj); + return true; + } + return false; + } + }; - /*package*/ List<Album> mAlbums; - /*package*/ List<View> mAlbumViews; - /*package*/ List<Album> mOriginalAlbums; - /*package*/ List<AlbumsFlip3dAnimationController> mAnimationControllers; + OnItemClickListener mOnItemClickListener = new OnItemClickListener() { + @Override + public void onItemClick(AdapterView<?> parent, View view, int position, long id) { + if (mShowingAlbums) { + onHeaderPressed(parent, view, position); + } else { + onPicturePressed(view); + } + } + }; + + private static final int MSG_LOAD_PICTURES = 1; - /*package*/ Set<String> mSelectedAlbums; + List<Album> mAlbums; + List<Album> mOriginalAlbums; + + Set<String> mSelectedAlbums; private Set<String> mOriginalSelectedAlbums; - /*package*/ VerticalEndlessScroller mScroller; - private CardLayout mAlbumsPanel; + ViewGroup mContainer; + + ListView mAlbumsPanel; + AlbumCardUiAdapter mAlbumAdapter; - /*package*/ boolean mSelectionChanged; + GridView mPicturesPanel; + AlbumPictureAdapter mPictureAdapter; + + private boolean mSelectionChanged; + + // Animation references + ViewGroup mSrcParent; + View mSrcView; + ViewGroup mDstParent; + View mDstView; + + Album mAlbum; + + private int mPicturesAnimDurationIn; + private int mPicturesAnimDurationOut; + + Handler mHandler; + LayoutInflater mInflater; + + boolean mShowingAlbums; /** * {@inheritDoc} @@ -177,22 +282,26 @@ public class ChoosePicturesFragment extends PreferenceFragment implements OnEndS @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mContentResolver = getActivity().getContentResolver(); + mHandler = new Handler(mCallback); + mShowingAlbums = true; // Create an empty album mAlbums = new ArrayList<Album>(); mOriginalAlbums = new ArrayList<Album>(); - mAnimationControllers = new ArrayList<AlbumsFlip3dAnimationController>(); // Change the preference manager getPreferenceManager().setSharedPreferencesName(PreferencesProvider.PREFERENCES_FILE); getPreferenceManager().setSharedPreferencesMode(Context.MODE_PRIVATE); // Load the albums user selection - mOriginalSelectedAlbums = Preferences.Media.getSelectedMedia(); + mOriginalSelectedAlbums = removeObsoleteAlbumsData(Preferences.Media.getSelectedMedia()); mSelectedAlbums = new HashSet<String>(mOriginalSelectedAlbums); mSelectionChanged = false; + Resources res = getActivity().getResources(); + mPicturesAnimDurationIn = res.getInteger(R.integer.pictures_anim_in); + mPicturesAnimDurationOut = res.getInteger(R.integer.pictures_anim_out); + setHasOptionsMenu(true); } @@ -202,12 +311,19 @@ public class ChoosePicturesFragment extends PreferenceFragment implements OnEndS @Override public void onDestroy() { super.onDestroy(); - if (mAlbumsLoaderTask.getStatus().compareTo(Status.PENDING) == 0) { - mAlbumsLoaderTask.cancel(true); + if (mTask.getStatus().compareTo(Status.PENDING) == 0) { + mTask.cancel(true); } unbindDrawables(mAlbumsPanel); unregister(); + if (!mShowingAlbums) { + mPicturesPanel.setVisibility(View.GONE); + mDstView.setVisibility(View.GONE); + mDstParent.removeView(mPicturesPanel); + mDstParent.removeView(mDstView); + } + // Notify that the settings was changed Intent intent = new Intent(PreferencesProvider.ACTION_SETTINGS_CHANGED); if (mSelectionChanged) { @@ -218,10 +334,9 @@ public class ChoosePicturesFragment extends PreferenceFragment implements OnEndS getActivity().sendBroadcast(intent); } - /*package*/ void unregister() { + private void unregister() { mAlbums.clear(); mOriginalAlbums.clear(); - mAnimationControllers.clear(); } /** @@ -229,7 +344,7 @@ public class ChoosePicturesFragment extends PreferenceFragment implements OnEndS * * @param view The root view */ - private void unbindDrawables(View view) { + void unbindDrawables(View view) { if (view.getBackground() != null) { view.getBackground().setCallback(null); } @@ -237,7 +352,6 @@ public class ChoosePicturesFragment extends PreferenceFragment implements OnEndS for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) { unbindDrawables(((ViewGroup) view).getChildAt(i)); } - ((ViewGroup) view).removeAllViews(); } } @@ -245,26 +359,43 @@ public class ChoosePicturesFragment extends PreferenceFragment implements OnEndS * {@inheritDoc} */ @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + public View onCreateView(final LayoutInflater inflater, final ViewGroup container, + Bundle savedInstanceState) { + + mContainer = container; + mInflater = inflater; + // Inflate the layout for this fragment - mScroller = - (VerticalEndlessScroller)inflater.inflate( + FrameLayout root = + (FrameLayout)mInflater.inflate( R.layout.choose_picture_fragment, container, false); - mScroller.setCallback(this); - mAlbumsPanel = (CardLayout)mScroller.findViewById(R.id.albums_panel); + mAlbumsPanel = (ListView)root.findViewById(R.id.albums_panel); + mAlbumsPanel.setSmoothScrollbarEnabled(true); + mAlbumAdapter = new AlbumCardUiAdapter(getActivity(), mAlbumsPanel, mAlbums, this); + mAlbumsPanel.setAdapter(mAlbumAdapter); + mAlbumsPanel.setOnItemClickListener(mOnItemClickListener); // Force Hardware acceleration - if (!mScroller.isHardwareAccelerated()) { - mScroller.setLayerType(View.LAYER_TYPE_HARDWARE, null); + if (!root.isHardwareAccelerated()) { + root.setLayerType(View.LAYER_TYPE_HARDWARE, null); } if (!mAlbumsPanel.isHardwareAccelerated()) { mAlbumsPanel.setLayerType(View.LAYER_TYPE_HARDWARE, null); } // Load the albums - mAlbumsLoaderTask.execute(); + unregister(); + mTask.execute(); + + return root; + } - return mScroller; + @Override + public void onClick(View v) { + // Hide the albums picture with animation + if (v.equals(mDstView)) { + hideAlbumPictures(mDstParent, mDstView, mSrcParent, mSrcView); + } } /** @@ -287,8 +418,12 @@ public class ChoosePicturesFragment extends PreferenceFragment implements OnEndS case R.id.mnu_restore: restoreData(); return true; - case R.id.mnu_invert_all: - invertAll(); + case R.id.mnu_invert: + if (mShowingAlbums) { + invertAll(); + } else { + invertAlbum(mAlbum); + } return true; default: return super.onOptionsItemSelected(item); @@ -301,14 +436,25 @@ public class ChoosePicturesFragment extends PreferenceFragment implements OnEndS private void restoreData() { // Restore and the albums the selection mSelectedAlbums = new HashSet<String>(mOriginalSelectedAlbums); - mAlbums.clear(); - for (Album album : mOriginalAlbums) { - mAlbums.add((Album)album.clone()); + int count = mAlbums.size(); + for (int i = 0; i < count ; i++) { + Album album = mAlbums.get(i); + Album originalAlbum = mOriginalAlbums.get(i); + + // Update selected status + album.setSelected(originalAlbum.isSelected()); + album.setItems(new ArrayList<Picture>(originalAlbum.getItems())); + album.setSelectedItems(new ArrayList<String>(originalAlbum.getSelectedItems())); } + mAlbumAdapter.notifyDataSetChanged(); - // Update all the views + // Update settings Preferences.Media.setSelectedMedia(getActivity(), mSelectedAlbums); - updateAll(); + mSelectionChanged = true; + + if (!mShowingAlbums) { + hideAlbumPictures(mDstParent, mDstView, mSrcParent, mSrcView); + } } /** @@ -325,172 +471,431 @@ public class ChoosePicturesFragment extends PreferenceFragment implements OnEndS } else { mSelectedAlbums.addAll(album.getSelectedItems()); } + for (Picture picture : album.getItems()) { + picture.setSelected(false); + } } + mAlbumAdapter.notifyDataSetChanged(); - // Update all the views + // Update settings Preferences.Media.setSelectedMedia(getActivity(), mSelectedAlbums); - updateAll(); + mSelectionChanged = true; } /** - * Method that updates the current state of all the albums + * Method that inverts the selection of an album + * + * @param album The album which to invert its selection */ - private void updateAll() { - // Update every view (albums and views should have the same size) - int count = mAlbumsPanel.getChildCount(); - for (int i = 0; i < count; i++) { - Album album = mAlbums.get(i); - View v = mAlbumsPanel.getChildAt(i); - AlbumInfo albumInfo = (AlbumInfo)v.findViewById(R.id.album_info); - AlbumPictures albumPictures = (AlbumPictures)v.findViewById(R.id.album_pictures); - albumInfo.updateView(album); - albumPictures.updateView(album, true); + private void invertAlbum(Album album) { + // Remove all pictures of the album + removeAlbumItems(album); + List<String> origSelectedItems = new ArrayList<String>(album.getSelectedItems()); + List<String> selectedItems = album.getSelectedItems(); + album.getSelectedItems().clear(); + for (Picture picture : album.getItems()) { + boolean selected = !origSelectedItems.contains(picture.getPath()); + if (selected) { + selectedItems.add(picture.getPath()); + } + picture.setSelected(selected); } - // Restore the preference + // Notify pictures dataset changed + mPictureAdapter.notifyDataSetChanged(); + updateAlbumInfo(mDstView, album); + + mSelectedAlbums.addAll(album.getSelectedItems()); Preferences.Media.setSelectedMedia(getActivity(), mSelectedAlbums); mSelectionChanged = true; + } + + /** + * {@inheritDoc} + */ + @Override + public void onAlbumSelected(Album album) { + updateAlbumSelection(album, true); + } + + /** + * {@inheritDoc} + */ + @Override + public void onAlbumDeselected(Album album) { + updateAlbumSelection(album, false); + } + + /** + * {@inheritDoc} + */ + @Override + public void onAllPicturesSelected(Album album) { + updateAllPicturesSelection(album, true); + } - // Restore all the animations states - for (AlbumsFlip3dAnimationController controller : mAnimationControllers) { - controller.reset(); + /** + * {@inheritDoc} + */ + @Override + public void onAllPicturesDeselected(Album album) { + updateAllPicturesSelection(album, false); + } + + /** + * Method that update the album selection + * + * @param album The album to update + * @param selected If the album is selected + */ + private void updateAlbumSelection(Album album, boolean selected) { + // Remove all pictures of the album + removeAlbumItems(album); + album.setSelected(selected); + album.getSelectedItems().clear(); + for (Picture picture : album.getItems()) { + picture.setSelected(false); + } + if (selected) { + mSelectedAlbums.add(album.getPath()); } + + if (!mShowingAlbums) { + // Notify pictures dataset changed + updateAlbumInfo(mDstView, album); + mPictureAdapter.notifyDataSetChanged(); + } + updateAlbumInfo(mSrcView, album); + + Preferences.Media.setSelectedMedia(getActivity(), mSelectedAlbums); + mSelectionChanged = true; } /** - * Method that creates a new album to the card layout + * Method that update the whole picture selection * - * @param album The album to create - * @return View The view create + * @param album The album to update + * @param selected If all the picture were selected */ - View createAlbumView(final Album album) { - LayoutInflater li = (LayoutInflater)getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); - final View albumView = li.inflate(R.layout.album, mAlbumsPanel, false); - final AlbumInfo albumInfo = (AlbumInfo)albumView.findViewById(R.id.album_info); - final AlbumPictures albumPictures = (AlbumPictures)albumView.findViewById(R.id.album_pictures); - - // Load the album info - albumInfo.post(new Runnable() { - @Override - public void run() { - albumInfo.updateView(album); + private void updateAllPicturesSelection(Album album, boolean selected) { + // Remove all pictures of the album + removeAlbumItems(album); + List<String> selectedItems = album.getSelectedItems(); + selectedItems.clear(); + for (Picture picture : album.getItems()) { + if (selected) { + selectedItems.add(picture.getPath()); + } + picture.setSelected(selected); + } + album.setSelected(false); + + // Notify pictures dataset changed + mPictureAdapter.notifyDataSetChanged(); + updateAlbumInfo(mDstView, album); + + mSelectedAlbums.addAll(album.getSelectedItems()); + Preferences.Media.setSelectedMedia(getActivity(), mSelectedAlbums); + mSelectionChanged = true; + } + + /** + * Method that removes the reference to all the items and itself + * + * @param ref The album + */ + private void removeAlbumItems(Album ref) { + Iterator<String> it = mSelectedAlbums.iterator(); + while (it.hasNext()) { + String item = it.next(); + String parent = new File(item).getParent(); + if (parent.compareTo(ref.getPath()) == 0) { + it.remove(); + } else if (item.compareTo(ref.getPath()) == 0) { + it.remove(); } - }); - if (album.isSelected()) { - albumInfo.setSelected(true); } - albumInfo.addCallBackListener(new AlbumInfo.CallbacksListener() { + } + + /** + * Method that shows the album pictures while animating the view + * + * @param srcParent The source parent view + * @param srcView The source view + * @param dstParent The destination parent view + * @param dstView The destination view + */ + void showAlbumPictures(final ViewGroup srcParent, final View srcView, + final ViewGroup dstParent, final View dstView) { + + // Hide the source view + srcView.setAlpha(0.0f); + + // Animation from bottom to top + ObjectAnimator anim1 = ObjectAnimator.ofFloat(dstView, "translationY", + srcView.getY(), srcParent.getPaddingTop()); + anim1.setDuration(mPicturesAnimDurationIn); + anim1.setInterpolator(new AccelerateDecelerateInterpolator()); + anim1.addListener(new AnimatorListener() { @Override - public void onAlbumSelected(Album ref) { - // Remove all pictures of the album and add the album reference - removeAlbumItems(ref); - mSelectedAlbums.add(ref.getPath()); - ref.setSelected(true); - albumPictures.updateView(ref, true); - - Preferences.Media.setSelectedMedia(getActivity(), mSelectedAlbums); - mSelectionChanged = true; + public void onAnimationStart(Animator animation) { + // Ignore } @Override - public void onAlbumDeselected(Album ref) { - // Remove all pictures of the album - removeAlbumItems(ref); - ref.setSelected(false); - albumPictures.updateView(ref, true); - - Preferences.Media.setSelectedMedia(getActivity(), mSelectedAlbums); - mSelectionChanged = true; + public void onAnimationRepeat(Animator animation) { + // Ignore } + @Override + public void onAnimationEnd(Animator animation) { + // Re-layout the view in its new position + dstView.setOnClickListener(ChoosePicturesFragment.this); + + // And now finally show the new album pictures layout + // and fill it + mPicturesPanel.setVisibility(View.VISIBLE); + mHandler.sendMessage(mHandler.obtainMessage(MSG_LOAD_PICTURES, mAlbum)); + mShowingAlbums = false; + } + @Override + public void onAnimationCancel(Animator animation) { + // Ignore + } }); + anim1.start(); + + // Hide the parent view + AlphaAnimation anim2 = new AlphaAnimation(1.0f, 0.0f); + anim2.setDuration(mPicturesAnimDurationIn); + anim2.setFillAfter(true); + anim2.setZAdjustment(Animation.ZORDER_BOTTOM); + anim2.setInterpolator(new AccelerateDecelerateInterpolator()); + srcParent.setEnabled(false); + srcParent.startAnimation(anim2); + + // Save the references + mSrcParent = srcParent; + mSrcView = srcView; + mDstParent = dstParent; + mDstView = dstView; + } + + /** + * Method that hides the album pictures while animating the view + * + * @param srcParent The source parent view + * @param srcView The source view + * @param dstParent The destination parent view + * @param dstView The destination view + */ + void hideAlbumPictures(final ViewGroup srcParent, final View srcView, + final ViewGroup dstParent, final View dstView) { + + mPicturesPanel.setVisibility(View.INVISIBLE); + + // Animation from top to bottom + ObjectAnimator anim1 = ObjectAnimator.ofFloat(srcView, "translationY", + dstParent.getPaddingTop(), dstView.getY()); + anim1.setDuration(mPicturesAnimDurationOut); + anim1.setInterpolator(new AccelerateDecelerateInterpolator()); + anim1.addListener(new AnimatorListener() { + @Override + public void onAnimationStart(Animator animation) { + // Ignore + } - // Load the album picture data - albumPictures.updateView(album, false); - albumPictures.addCallBackListener(new AlbumPictures.CallbacksListener() { @Override - public void onBackButtonClick(View v) { - // Ignored + public void onAnimationRepeat(Animator animation) { + // Ignore } @Override - public void onSelectionChanged(Album ref) { - // Remove, add, and persist the selection - removeAlbumItems(ref); - mSelectedAlbums.addAll(ref.getSelectedItems()); - ref.setSelected(false); - albumInfo.updateView(ref); - - Preferences.Media.setSelectedMedia(getActivity(), mSelectedAlbums); - mSelectionChanged = true; + public void onAnimationEnd(Animator animation) { + // Remove the source view and show the destination view + srcParent.removeView(srcView); + dstView.setAlpha(1.0f); + dstParent.setEnabled(true); + unbindDrawables(mPicturesPanel); + srcParent.removeView(mPicturesPanel); + + mShowingAlbums = true; + } + + @Override + public void onAnimationCancel(Animator animation) { + // Ignore } }); + anim1.start(); + + // Hide the parent view + AlphaAnimation anim2 = new AlphaAnimation(0.0f, 1.0f); + anim2.setDuration(mPicturesAnimDurationOut); + anim2.setFillAfter(true); + anim2.setZAdjustment(Animation.ZORDER_BOTTOM); + anim2.setInterpolator(new AccelerateDecelerateInterpolator()); + dstParent.startAnimation(anim2); + } + + /** + * Method that updates an album info + * + * @param v The header view + * @param album The album data + */ + void updateAlbumInfo(View v, Album album) { + Resources res = getActivity().getResources(); + + AlbumInfoView info = (AlbumInfoView)v.findViewById(R.id.album_info); + info.setAlbum(album); - // Register the animation controller - AlbumsFlip3dAnimationController controller = new AlbumsFlip3dAnimationController(albumInfo, albumPictures); - controller.register(); - mAnimationControllers.add(controller); + ImageView icon = (ImageView)info.findViewById(R.id.album_thumbnail); + TextView name = (TextView)info.findViewById(R.id.album_name); + TextView items = (TextView)info.findViewById(R.id.album_items); + TextView selectedItems = (TextView)info.findViewById(R.id.album_selected_items); - return albumView; + icon.setImageDrawable(album.getIcon()); + name.setText(album.getName()); + + int size = album.getItems().size(); + items.setText(String.format(res.getQuantityText( + R.plurals.album_number_of_pictures, size).toString(), Integer.valueOf(size))); + + int selected = album.getSelectedItems().size(); + String count = String.valueOf(selected); + if (selected > 99) { + count = "99+"; + } + selectedItems.setText(count); + selectedItems.setVisibility(!album.isSelected() ? View.VISIBLE : View.INVISIBLE); + info.setSelected(album.isSelected()); } /** - * Method that checks if an item is selected + * Method that load all the pictures of the album * - * @param item The item - * @return boolean if an item is selected + * @param album */ - /*package*/ boolean isSelectedItem(String item) { - Iterator<String> it = mSelectedAlbums.iterator(); - while (it.hasNext()) { - String albumPath = it.next(); - if (item.compareTo(albumPath) == 0) { - return true; - } + void loadPictures(Album album) { + List<Picture> items = album.getItems(); + + // Calculate the grid dimensions + Resources res = getActivity().getResources(); + int pictureWidth = (int)res.getDimension(R.dimen.picture_size); + int gridWidth = mPicturesPanel.getWidth(); + int columns = gridWidth / pictureWidth; + int space = (gridWidth / pictureWidth) / (columns - 1); + if (columns < items.size()) { + space = (int)res.getDimension(R.dimen.small_padding); } - return false; + mPicturesPanel.setHorizontalSpacing(space); + mPicturesPanel.setVerticalSpacing(space); + mPicturesPanel.setStretchMode(GridView.STRETCH_SPACING); + mPicturesPanel.setColumnWidth(pictureWidth); + mPicturesPanel.setNumColumns(columns); + + mPictureAdapter = new AlbumPictureAdapter(getActivity(), items, mPicturesPanel); + mPicturesPanel.setAdapter(mPictureAdapter); } /** - * Method that removes the reference to all the items and itself + * Method invoked when an album header was pressed * - * @param ref The album + * @param parent The parent view + * @param view The header view + * @param position The position */ - /*package*/ void removeAlbumItems(Album ref) { - Iterator<String> it = mSelectedAlbums.iterator(); - while (it.hasNext()) { - String item = it.next(); - String parent = new File(item).getParent(); - if (parent.compareTo(ref.getPath()) == 0) { - it.remove(); - } else if (item.compareTo(ref.getPath()) == 0) { - it.remove(); - } + void onHeaderPressed(AdapterView<?> parent, View view, int position) { + mAlbum = mAlbumAdapter.getItem(position); + + // Header view + View header = mInflater.inflate(R.layout.album_info, null); + header.setTranslationY(view.getY() + parent.getPaddingTop()); + header.setLayoutParams(new ViewGroup.LayoutParams(view.getWidth(), view.getHeight())); + + // Pictures view + mPicturesPanel = (GridView) mInflater.inflate(R.layout.pictures_view, null); + if (!mPicturesPanel.isHardwareAccelerated()) { + mPicturesPanel.setLayerType(View.LAYER_TYPE_HARDWARE, null); } + mPicturesPanel.setY(view.getHeight()); + mPicturesPanel.setLayoutParams(new ViewGroup.LayoutParams(view.getWidth(), + parent.getHeight() - view.getHeight() - + parent.getPaddingTop() - parent.getPaddingBottom())); + mPicturesPanel.setVisibility(View.INVISIBLE); + mPicturesPanel.setOnItemClickListener(mOnItemClickListener); + + // Add to the container + mContainer.addView(mPicturesPanel); + mContainer.addView(header); + + // Update and display the album pictures view + AlbumInfoView info = (AlbumInfoView)header.findViewById(R.id.album_info); + info.addCallBackListener(ChoosePicturesFragment.this); + info.setAlbumMode(false); + updateAlbumInfo(header, mAlbum); + showAlbumPictures(parent, view, mContainer, header); } /** - * {@inheritDoc} + * Method invoked when a picture view was pressed + * + * @param view The picture view */ - @Override - public void onEndScroll() { - doEndScroll(AMOUNT_OF_ADDED_STEPS, false); + void onPicturePressed(View view) { + PictureItemView pictureView = (PictureItemView)view.findViewById(R.id.picture); + if (pictureView != null) { + Picture picture = pictureView.getPicture(); + removeAlbumItems(mAlbum); + List<String> selectedItems = mAlbum.getSelectedItems(); + if (selectedItems.contains(picture.getPath())) { + selectedItems.remove(picture.getPath()); + picture.setSelected(false); + } else { + selectedItems.add(picture.getPath()); + picture.setSelected(true); + mAlbum.setSelected(false); + } + + // Notify all the views + pictureView.updateView(picture, false); + updateAlbumInfo(mDstView, mAlbum); + mAlbumAdapter.notifyDataSetChanged(); + + // Update settings + mSelectedAlbums.addAll(mAlbum.getSelectedItems()); + Preferences.Media.setSelectedMedia(getActivity(), mSelectedAlbums); + mSelectionChanged = true; + } } /** - * Method that performs a scroll creating new items + * Method that removes all the inexistent albums and pictures * - * @param amount The amount of items to create - * @param animate If the add should be animated + * @param data The data to filter + * @return Set<String> The data filtered */ - /*package*/ synchronized void doEndScroll(int amount, boolean animate) { - for (int i = 0; i < amount; i++) { - //Add to the panel of cards - if (mAlbumViews == null || mAlbumViews.isEmpty()) { - break; + private Set<String> removeObsoleteAlbumsData(Set<String> data) { + Set<String> validDataList = new HashSet<String>(); + Iterator<String> it = data.iterator(); + while (it.hasNext()) { + File f = new File(it.next()); + if (f.exists()) { + try { + validDataList.add(f.getCanonicalPath()); + } catch (IOException ioex) { + // Ignore + } } - mAlbumsPanel.addCard(mAlbumViews.remove(0), animate); } + if (data.size() != validDataList.size()) { + // Obsolete entries were removed + data.clear(); + data.addAll(validDataList); + Preferences.Media.setSelectedMedia(getActivity(), mOriginalSelectedAlbums); + } + return data; } } diff --git a/src/org/cyanogenmod/wallpapers/photophase/preferences/DispositionFragment.java b/src/org/cyanogenmod/wallpapers/photophase/preferences/DispositionFragment.java index b0204c3..7071e76 100644 --- a/src/org/cyanogenmod/wallpapers/photophase/preferences/DispositionFragment.java +++ b/src/org/cyanogenmod/wallpapers/photophase/preferences/DispositionFragment.java @@ -53,7 +53,7 @@ public abstract class DispositionFragment } }; - /*package*/ DispositionView mDispositionView; + DispositionView mDispositionView; private MenuItem mDeleteMenu; diff --git a/src/org/cyanogenmod/wallpapers/photophase/preferences/PhotoPhasePreferences.java b/src/org/cyanogenmod/wallpapers/photophase/preferences/PhotoPhasePreferences.java index 4e8c46e..b5c0d83 100644 --- a/src/org/cyanogenmod/wallpapers/photophase/preferences/PhotoPhasePreferences.java +++ b/src/org/cyanogenmod/wallpapers/photophase/preferences/PhotoPhasePreferences.java @@ -47,7 +47,8 @@ public class PhotoPhasePreferences extends PreferenceActivity { private void initTitleActionBar() { //Configure the action bar options getActionBar().setDisplayOptions( - ActionBar.DISPLAY_SHOW_CUSTOM | ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_SHOW_TITLE); + ActionBar.DISPLAY_SHOW_CUSTOM | ActionBar.DISPLAY_SHOW_HOME | + ActionBar.DISPLAY_SHOW_TITLE); getActionBar().setDisplayHomeAsUpEnabled(true); } diff --git a/src/org/cyanogenmod/wallpapers/photophase/preferences/PreferencesProvider.java b/src/org/cyanogenmod/wallpapers/photophase/preferences/PreferencesProvider.java index 1bf8359..0edc8b7 100644 --- a/src/org/cyanogenmod/wallpapers/photophase/preferences/PreferencesProvider.java +++ b/src/org/cyanogenmod/wallpapers/photophase/preferences/PreferencesProvider.java @@ -96,7 +96,7 @@ public final class PreferencesProvider { /** * @hide */ - /*package*/ static int[] TRANSITIONS_INTERVALS; + static int[] TRANSITIONS_INTERVALS; /** * Method that loads the all the preferences of the application @@ -350,7 +350,12 @@ public final class PreferencesProvider { * @return Set<String> The list of albums and pictures to be displayed */ public static Set<String> getLastDiscorevedAlbums() { - return getStringSet("media_last_disvored_albums", new HashSet<String>()); + // FIXME Typo. Remove when version 1005 is obsolete and unused + Set<String> oldKey = getStringSet("media_last_disvored_albums", new HashSet<String>()); + if (oldKey.size() > 0) { + return oldKey; + } + return getStringSet("media_last_discovered_albums", new HashSet<String>()); } /** @@ -364,7 +369,9 @@ public final class PreferencesProvider { SharedPreferences preferences = context.getSharedPreferences(PREFERENCES_FILE, Context.MODE_PRIVATE); Editor editor = preferences.edit(); - editor.putStringSet("media_last_disvored_albums", albums); + // FIXME Typo. Remove when version 1005 is obsolete and unused + editor.remove("media_last_disvored_albums"); + editor.putStringSet("media_last_discovered_albums", albums); editor.commit(); reload(context); } diff --git a/src/org/cyanogenmod/wallpapers/photophase/tasks/AsyncPictureLoaderTask.java b/src/org/cyanogenmod/wallpapers/photophase/tasks/AsyncPictureLoaderTask.java index bc07b17..3ea1885 100644 --- a/src/org/cyanogenmod/wallpapers/photophase/tasks/AsyncPictureLoaderTask.java +++ b/src/org/cyanogenmod/wallpapers/photophase/tasks/AsyncPictureLoaderTask.java @@ -32,8 +32,34 @@ import java.io.File; */ public class AsyncPictureLoaderTask extends AsyncTask<File, Void, Drawable> { + /** + * Notify whether the picture was loaded + */ + public static abstract class OnPictureLoaded { + Object[] mRefs; + + /** + * Constructor of <code>OnPictureLoaded</code> + * + * @param refs References to notify + */ + public OnPictureLoaded(Object...refs) { + super(); + mRefs = refs; + } + + /** + * Invoked when a picture is loaded + * + * @param o The original object reference + * @param drawable The drawable + */ + public abstract void onPictureLoaded(Object o, Drawable drawable); + } + private final Context mContext; private final ImageView mView; + private final OnPictureLoaded mCallback; /** * Constructor of <code>AsyncPictureLoaderTask</code> @@ -42,9 +68,21 @@ public class AsyncPictureLoaderTask extends AsyncTask<File, Void, Drawable> { * @param v The associated view */ public AsyncPictureLoaderTask(Context context, ImageView v) { + this(context, v, null); + } + + /** + * Constructor of <code>AsyncPictureLoaderTask</code> + * + * @param context The current context + * @param v The associated view + * @param callback A callback to notify when the picture was loaded + */ + public AsyncPictureLoaderTask(Context context, ImageView v, OnPictureLoaded callback) { super(); mContext = context; mView = v; + mCallback = callback; } /** @@ -56,7 +94,15 @@ public class AsyncPictureLoaderTask extends AsyncTask<File, Void, Drawable> { int height = mView.getMeasuredHeight(); Bitmap bitmap = BitmapUtils.decodeBitmap(params[0], width, height); if (bitmap != null) { - return new BitmapDrawable(mContext.getResources(), bitmap); + Drawable dw = new BitmapDrawable(mContext.getResources(), bitmap); + if (mCallback != null) { + for (Object o : mCallback.mRefs) { + if (!isCancelled()) { + mCallback.onPictureLoaded(o, dw); + } + } + } + return dw; } return null; } @@ -66,6 +112,8 @@ public class AsyncPictureLoaderTask extends AsyncTask<File, Void, Drawable> { */ @Override protected void onPostExecute(Drawable result) { - mView.setImageDrawable(result); + if (!isCancelled()) { + mView.setImageDrawable(result); + } } } diff --git a/src/org/cyanogenmod/wallpapers/photophase/widgets/AlbumInfo.java b/src/org/cyanogenmod/wallpapers/photophase/widgets/AlbumInfoView.java index 8e335c3..3cfe4d3 100644 --- a/src/org/cyanogenmod/wallpapers/photophase/widgets/AlbumInfo.java +++ b/src/org/cyanogenmod/wallpapers/photophase/widgets/AlbumInfoView.java @@ -18,6 +18,8 @@ package org.cyanogenmod.wallpapers.photophase.widgets; import android.content.Context; import android.content.res.Resources; +import android.graphics.drawable.Drawable; +import android.os.AsyncTask; import android.os.AsyncTask.Status; import android.util.AttributeSet; import android.view.Menu; @@ -40,10 +42,10 @@ import java.util.ArrayList; import java.util.List; /** - * A view that contains the info about an album + * A view that contains the view of the info of an album */ -public class AlbumInfo extends RelativeLayout - implements OnClickListener, OnMenuItemClickListener { +public class AlbumInfoView extends RelativeLayout + implements OnClickListener, OnMenuItemClickListener { /** * A convenient listener for receive events of the AlbumPictures class @@ -63,43 +65,70 @@ public class AlbumInfo extends RelativeLayout * @param album The album */ void onAlbumDeselected(Album album); + + /** + * Invoked when an all of the picture of the album were selected + * + * @param album The album + */ + void onAllPicturesSelected(Album album); + + /** + * Invoked when an all of the picture of the album were deselected + * + * @param album The album + */ + void onAllPicturesDeselected(Album album); + } + + private class OnPictureLoaded extends AsyncPictureLoaderTask.OnPictureLoaded { + public OnPictureLoaded(Album album) { + super(new Object[]{album}); + } + + @Override + public void onPictureLoaded(Object o, Drawable drawable) { + ((Album)o).setIcon(drawable); + } } private List<CallbacksListener> mCallbacks; - /*package*/ Album mAlbum; + private Album mAlbum; - /*package*/ AsyncPictureLoaderTask mTask; + private AsyncPictureLoaderTask mTask; - /*package*/ ImageView mIcon; + private ImageView mIcon; private TextView mSelectedItems; private TextView mName; private TextView mItems; private View mOverflowButton; + private boolean mAlbumMode; + /** - * Constructor of <code>AlbumInfo</code>. + * Constructor of <code>AlbumInfoView</code>. * * @param context The current context */ - public AlbumInfo(Context context) { + public AlbumInfoView(Context context) { super(context); init(); } /** - * Constructor of <code>AlbumInfo</code>. + * Constructor of <code>AlbumInfoView</code>. * * @param context The current context * @param attrs The attributes of the XML tag that is inflating the view. */ - public AlbumInfo(Context context, AttributeSet attrs) { + public AlbumInfoView(Context context, AttributeSet attrs) { super(context, attrs); init(); } /** - * Constructor of <code>AlbumInfo</code>. + * Constructor of <code>AlbumInfoView</code>. * * @param context The current context * @param attrs The attributes of the XML tag that is inflating the view. @@ -108,7 +137,7 @@ public class AlbumInfo extends RelativeLayout * either be an attribute resource, whose value will be retrieved * from the current theme, or an explicit style resource. */ - public AlbumInfo(Context context, AttributeSet attrs, int defStyle) { + public AlbumInfoView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } @@ -117,7 +146,17 @@ public class AlbumInfo extends RelativeLayout * Method that initializes the internal references */ private void init() { - mCallbacks = new ArrayList<AlbumInfo.CallbacksListener>(); + mCallbacks = new ArrayList<AlbumInfoView.CallbacksListener>(); + mAlbumMode = true; + } + + /** + * Method that set the album mode + * + * @param albumMode The album mode + */ + public void setAlbumMode(boolean albumMode) { + this.mAlbumMode = albumMode; } /** @@ -145,13 +184,6 @@ public class AlbumInfo extends RelativeLayout protected void onAttachedToWindow() { super.onAttachedToWindow(); - mIcon = (ImageView)findViewById(R.id.album_thumbnail); - mSelectedItems = (TextView)findViewById(R.id.album_selected_items); - mName = (TextView)findViewById(R.id.album_name); - mItems = (TextView)findViewById(R.id.album_items); - mOverflowButton = findViewById(R.id.overflow); - mOverflowButton.setOnClickListener(this); - updateView(mAlbum); } @@ -180,7 +212,6 @@ public class AlbumInfo extends RelativeLayout onPreparePopupMenu(popup.getMenu()); popup.setOnMenuItemClickListener(this); popup.show(); - return; } } @@ -195,6 +226,10 @@ public class AlbumInfo extends RelativeLayout } else { popup.findItem(R.id.mnu_deselect_album).setVisible(false); } + if (mAlbumMode) { + popup.findItem(R.id.mnu_select_all).setVisible(false); + popup.findItem(R.id.mnu_deselect_all).setVisible(false); + } } /** @@ -211,6 +246,14 @@ public class AlbumInfo extends RelativeLayout doSelection(false); break; + case R.id.mnu_select_all: + notifyPictureSelectionChanged(true); + break; + + case R.id.mnu_deselect_all: + notifyPictureSelectionChanged(false); + break; + default: return false; } @@ -226,8 +269,8 @@ public class AlbumInfo extends RelativeLayout setSelected(selected); mAlbum.setSelected(selected); mAlbum.setSelectedItems(new ArrayList<String>()); - updateView(mAlbum); notifySelectionChanged(); + updateView(mAlbum); } /** @@ -245,40 +288,80 @@ public class AlbumInfo extends RelativeLayout } /** + * Method that notifies to all the registered callbacks that the selection + * was changed + */ + private void notifyPictureSelectionChanged(boolean selected) { + for (CallbacksListener callback : mCallbacks) { + if (selected) { + callback.onAllPicturesSelected(mAlbum); + } else { + callback.onAllPicturesDeselected(mAlbum); + } + } + } + + /** + * Method that sets the album + * + * @param album The album + */ + public void setAlbum(Album album) { + mAlbum = album; + } + + /** * Method that updates the view * * @param album The album data */ @SuppressWarnings("boxing") public void updateView(Album album) { - mAlbum = album; + // Destroy the update drawable task + if (mTask != null && (mTask.getStatus() == AsyncTask.Status.RUNNING || + mTask.getStatus() == AsyncTask.Status.PENDING)) { + mTask.cancel(true); + } + + // Retrieve the views references + if (mIcon == null) { + mIcon = (ImageView)findViewById(R.id.album_thumbnail); + mSelectedItems = (TextView)findViewById(R.id.album_selected_items); + mName = (TextView)findViewById(R.id.album_name); + mItems = (TextView)findViewById(R.id.album_items); + mOverflowButton = findViewById(R.id.overflow_button); + mOverflowButton.setOnClickListener(this); + } - if (mAlbum != null && mIcon != null) { + // Update the views + if (album != null) { Resources res = getContext().getResources(); - int selectedItems = mAlbum.getSelectedItems().size(); + setAlbum(album); + + int selectedItems = album.getSelectedItems().size(); String count = String.valueOf(selectedItems); if (selectedItems > 99) { - count += "+"; + count = "99+"; } mSelectedItems.setText(count); - mSelectedItems.setVisibility(mAlbum.isSelected() ? View.INVISIBLE : View.VISIBLE); - mName.setText(mAlbum.getName()); - int items = mAlbum.getItems().size(); + mSelectedItems.setVisibility(album.isSelected() ? View.INVISIBLE : View.VISIBLE); + mName.setText(album.getName()); + int items = album.getItems().size(); mItems.setText(String.format(res.getQuantityText( R.plurals.album_number_of_pictures, items).toString(), items)); setSelected(album.isSelected()); - if (mTask == null) { - post(new Runnable() { - @Override - public void run() { - // Show as icon, the first picture - mTask = new AsyncPictureLoaderTask(getContext(), mIcon); - mTask.execute(new File(mAlbum.getItems().get(0))); - } - }); + Drawable dw = album.getIcon(); + mIcon.setImageDrawable(dw); + if (dw == null) { + mIcon.setImageDrawable(null); + + // Show as icon, the first picture + mTask = new AsyncPictureLoaderTask(getContext(), mIcon, new OnPictureLoaded(album)); + mTask.execute(new File(album.getItems().get(0).getPath())); } } } + } diff --git a/src/org/cyanogenmod/wallpapers/photophase/widgets/AlbumPictures.java b/src/org/cyanogenmod/wallpapers/photophase/widgets/AlbumPictures.java deleted file mode 100644 index 5d0c60f..0000000 --- a/src/org/cyanogenmod/wallpapers/photophase/widgets/AlbumPictures.java +++ /dev/null @@ -1,345 +0,0 @@ -/* - * Copyright (C) 2013 The CyanogenMod Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.cyanogenmod.wallpapers.photophase.widgets; - -import android.content.Context; -import android.os.Handler; -import android.util.AttributeSet; -import android.view.LayoutInflater; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.LinearLayout; -import android.widget.PopupMenu; -import android.widget.PopupMenu.OnMenuItemClickListener; -import android.widget.RelativeLayout; -import android.widget.TextView; - -import org.cyanogenmod.wallpapers.photophase.R; -import org.cyanogenmod.wallpapers.photophase.model.Album; - -import java.util.ArrayList; -import java.util.List; - -/** - * A view that contains the pictures of an album - */ -public class AlbumPictures extends RelativeLayout - implements OnClickListener, OnMenuItemClickListener { - - private static final int SELECTION_SELECT_ALL = 1; - private static final int SELECTION_DESELECT_ALL = 2; - private static final int SELECTION_INVERT = 3; - - /** - * A convenient listener for receive events of the AlbumPictures class - * - */ - public interface CallbacksListener { - /** - * Invoked when the user pressed the back button - */ - void onBackButtonClick(View v); - - /** - * Invoked when the selection was changed - * - * @param album The album - */ - void onSelectionChanged(Album album); - } - - private List<CallbacksListener> mCallbacks; - - private Handler mHandler; - - /*package*/ PicturesView mScroller; - /*package*/ LinearLayout mHolder; - private View mBackButton; - private View mOverflowButton; - - private boolean mInitialized; - - /*package*/ Album mAlbum; - - /** - * Constructor of <code>AlbumPictures</code>. - * - * @param context The current context - */ - public AlbumPictures(Context context) { - super(context); - init(); - } - - /** - * Constructor of <code>AlbumPictures</code>. - * - * @param context The current context - * @param attrs The attributes of the XML tag that is inflating the view. - */ - public AlbumPictures(Context context, AttributeSet attrs) { - super(context, attrs); - init(); - } - - /** - * Constructor of <code>AlbumPictures</code>. - * - * @param context The current context - * @param attrs The attributes of the XML tag that is inflating the view. - * @param defStyle The default style to apply to this view. If 0, no style - * will be applied (beyond what is included in the theme). This may - * either be an attribute resource, whose value will be retrieved - * from the current theme, or an explicit style resource. - */ - public AlbumPictures(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - init(); - } - - /** - * Method that initializes the internal references - */ - private void init() { - mCallbacks = new ArrayList<AlbumPictures.CallbacksListener>(); - mHandler = new Handler(); - mInitialized = false; - } - - /** - * {@inheritDoc} - */ - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - mScroller = (PicturesView)findViewById(R.id.album_pictures_scroller); - mHolder = (LinearLayout)findViewById(R.id.album_pictures_holder); - mBackButton = findViewById(R.id.back); - mBackButton.setOnClickListener(this); - mOverflowButton = findViewById(R.id.overflow); - mOverflowButton.setOnClickListener(this); - TextView title = (TextView)findViewById(R.id.album_pictures_title); - title.setText(mAlbum.getName()); - - updateView(mAlbum, false); - } - - /** - * Method that adds the class that will be listen for events of this class - * - * @param callback The callback class - */ - public void addCallBackListener(CallbacksListener callback) { - this.mCallbacks.add(callback); - } - - /** - * Method that removes the class from the current callbacks - * - * @param callback The callback class - */ - public void removeCallBackListener(CallbacksListener callback) { - this.mCallbacks.remove(callback); - } - - /** - * Method that set the data of the view - * - * @param album The album data - * @param recreate If the view should be recreated - */ - public void updateView(Album album, boolean recreate) { - mAlbum = album; - recreateView(false); - } - - /** - * Method that recreates the the view - * - * @param propagateShow If should propagate the show event - */ - private void recreateView(final boolean propagateShow) { - if (mHolder != null) { - mHandler.post(new Runnable() { - @Override - public void run() { - int pictures = mHolder.getChildCount(); - if (pictures != mAlbum.getItems().size()) { - // Recreate the pictures - final LayoutInflater inflater = (LayoutInflater) getContext(). - getSystemService(Context.LAYOUT_INFLATER_SERVICE); - mScroller.cancelTasks(); - mHolder.removeAllViews(); - for (final String picture : mAlbum.getItems()) { - View v = createPicture(inflater, picture, isPictureSelected(picture)); - mHolder.addView(v); - } - } else { - int i = 0; - for (final String picture : mAlbum.getItems()) { - View v = mHolder.getChildAt(i); - v.setSelected(isPictureSelected(picture)); - i++; - } - } - if (propagateShow) { - mScroller.onShow(); - } - } - }); - } - } - - /** - * {@inheritDoc} - */ - @Override - public void onClick(View v) { - // Check which is the view pressed - if (v.equals(mBackButton)) { - for (CallbacksListener callback : mCallbacks) { - callback.onBackButtonClick(v); - } - return; - } - if (v.equals(mOverflowButton)) { - PopupMenu popup = new PopupMenu(getContext(), v); - MenuInflater inflater = popup.getMenuInflater(); - inflater.inflate(R.menu.pictures_actions, popup.getMenu()); - popup.setOnMenuItemClickListener(this); - popup.show(); - return; - } - - // A picture view - v.setSelected(!v.isSelected()); - notifySelectionChanged(); - } - - /** - * Method that notifies to all the registered callbacks that the selection - * was changed - */ - private void notifySelectionChanged() { - List<String> selection = new ArrayList<String>(); - int count = mHolder.getChildCount(); - for (int i = 0; i < count; i++) { - View v = mHolder.getChildAt(i); - if (v.isSelected()) { - selection.add((String)v.getTag()); - } - } - mAlbum.setSelectedItems(selection); - mAlbum.setSelected(false); - - for (CallbacksListener callback : mCallbacks) { - callback.onSelectionChanged(mAlbum); - } - } - - /** - * {@inheritDoc} - */ - @Override - public boolean onMenuItemClick(MenuItem item) { - switch (item.getItemId()) { - case R.id.mnu_select_all: - doSelection(SELECTION_SELECT_ALL); - break; - - case R.id.mnu_deselect_all: - doSelection(SELECTION_DESELECT_ALL); - break; - - case R.id.mnu_invert_selection: - doSelection(SELECTION_INVERT); - break; - - default: - return false; - } - return true; - } - - /** - * Operate over the selection of the pictures of this album. - * - * @param action Takes the next values: - * <ul> - * <li>SELECTION_SELECT_ALL: select all</li> - * <li>SELECTION_DESELECT_ALL: deselect all</li> - * <li>SELECTION_INVERT: invert selection</li> - * </ul> - */ - private void doSelection(int action) { - int count = mHolder.getChildCount(); - for (int i = 0; i < count; i++) { - View v = mHolder.getChildAt(i); - - boolean selected = true; - if (action == SELECTION_DESELECT_ALL) { - selected = false; - } else if (action == SELECTION_INVERT) { - selected = !v.isSelected(); - } - v.setSelected(selected); - } - notifySelectionChanged(); - } - - /** - * Method invoked when the view is displayed - */ - public void onShow() { - if (!mInitialized) { - mInitialized = true; - recreateView(true); - } - } - - /** - * Method that creates a new picture view - * - * @param inflater The inflater of the parent view - * @param picture The path of the picture - * @param selected If the picture is selected - */ - /*package*/ View createPicture(LayoutInflater inflater, String picture, boolean selected) { - final View v = inflater.inflate(R.layout.picture_item, mHolder, false); - v.setTag(picture); - v.setSelected(selected); - v.setOnClickListener(this); - return v; - } - - /** - * Method that check if a picture is selected - * - * @param picture The picture to check - * @return boolean whether the picture is selected - */ - /*package*/ boolean isPictureSelected(String picture) { - for (String item : mAlbum.getSelectedItems()) { - if (item.compareTo(picture) == 0) { - return true; - } - } - return false; - } -} diff --git a/src/org/cyanogenmod/wallpapers/photophase/widgets/CardLayout.java b/src/org/cyanogenmod/wallpapers/photophase/widgets/CardLayout.java deleted file mode 100644 index e1953cd..0000000 --- a/src/org/cyanogenmod/wallpapers/photophase/widgets/CardLayout.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2013 The CyanogenMod Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.cyanogenmod.wallpapers.photophase.widgets; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.View; -import android.view.animation.AnimationUtils; -import android.widget.LinearLayout; - -import org.cyanogenmod.wallpapers.photophase.R; - -/** - * A "Google Now Card Layout" like layout - */ -public class CardLayout extends LinearLayout { - - boolean inverted = false; - - /** - * Constructor of <code>CardLayout</code>. - * - * @param context The current context - */ - public CardLayout(Context context) { - super(context); - } - - /** - * Constructor of <code>CardLayout</code>. - * - * @param context The current context - * @param attrs The attributes of the XML tag that is inflating the view. - */ - public CardLayout(Context context, AttributeSet attrs) { - super(context, attrs); - } - - /** - * Constructor of <code>CardLayout</code>. - * - * @param context The current context - * @param attrs The attributes of the XML tag that is inflating the view. - * @param defStyle The default style to apply to this view. If 0, no style - * will be applied (beyond what is included in the theme). This may - * either be an attribute resource, whose value will be retrieved - * from the current theme, or an explicit style resource. - */ - public CardLayout(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } - - /** - * Add a new card to the layout - * - * @param card The card view to add - * @param animate If the add should be animated - */ - public void addCard(final View card, final boolean animate) { - post(new Runnable() { - @Override - public void run() { - addView(card); - if (animate) { - if (inverted) { - card.startAnimation(AnimationUtils.loadAnimation( - getContext(), R.anim.cards_animation_up_right)); - } else { - card.startAnimation(AnimationUtils.loadAnimation( - getContext(), R.anim.cards_animation_up_left)); - } - inverted = !inverted; - } - } - }); - } -} diff --git a/src/org/cyanogenmod/wallpapers/photophase/widgets/DispositionView.java b/src/org/cyanogenmod/wallpapers/photophase/widgets/DispositionView.java index 22d00a6..0bc462f 100644 --- a/src/org/cyanogenmod/wallpapers/photophase/widgets/DispositionView.java +++ b/src/org/cyanogenmod/wallpapers/photophase/widgets/DispositionView.java @@ -74,7 +74,7 @@ public class DispositionView extends RelativeLayout implements OnLongClickListen private int mCols; private int mRows; - /*package*/ View mTarget; + View mTarget; private ResizeFrame mResizeFrame; private int mInternalPadding; private Rect mOldResizeFrameLocation; @@ -323,7 +323,7 @@ public class DispositionView extends RelativeLayout implements OnLongClickListen * * @param target The disposition target */ - /*package*/ void finishDeleteAnimation(Disposition target) { + void finishDeleteAnimation(Disposition target) { removeView(mTarget); mDispositions.remove(target); Collections.sort(mDispositions); @@ -514,7 +514,7 @@ public class DispositionView extends RelativeLayout implements OnLongClickListen * * @return The target view */ - /*package*/ View findTargetFromResizeFrame() { + View findTargetFromResizeFrame() { int count = getChildCount(); for (int i = 0; i < count; i++) { View v = getChildAt(i); @@ -552,7 +552,7 @@ public class DispositionView extends RelativeLayout implements OnLongClickListen * * @param v The target view */ - /*package*/ boolean selectTarget(View v) { + boolean selectTarget(View v) { //Do not do long click if we do not have a target if (mTarget != null && v.equals(mTarget)) return false; diff --git a/src/org/cyanogenmod/wallpapers/photophase/widgets/PictureItemView.java b/src/org/cyanogenmod/wallpapers/photophase/widgets/PictureItemView.java new file mode 100644 index 0000000..aac7e24 --- /dev/null +++ b/src/org/cyanogenmod/wallpapers/photophase/widgets/PictureItemView.java @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2013 The CyanogenMod Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cyanogenmod.wallpapers.photophase.widgets; + +import android.content.Context; +import android.os.AsyncTask; +import android.os.AsyncTask.Status; +import android.util.AttributeSet; +import android.widget.FrameLayout; +import android.widget.ImageView; + +import org.cyanogenmod.wallpapers.photophase.R; +import org.cyanogenmod.wallpapers.photophase.model.Picture; +import org.cyanogenmod.wallpapers.photophase.tasks.AsyncPictureLoaderTask; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +/** + * A view that contains the view of the picture of an abbum + */ +public class PictureItemView extends FrameLayout { + + /** + * A convenient listener for receive events of the PictureItemView class + * + */ + public interface CallbacksListener { + /** + * Invoked when an Picture was selected + * + * @param Picture The Picture + */ + void onPictureSelected(Picture Picture); + + /** + * Invoked when an Picture was deselected + * + * @param Picture The Picture + */ + void onPictureDeselected(Picture Picture); + } + + private List<CallbacksListener> mCallbacks; + + private Picture mPicture; + + private AsyncPictureLoaderTask mTask; + + private ImageView mIcon; + + /** + * Constructor of <code>PictureItemView</code>. + * + * @param context The current context + */ + public PictureItemView(Context context) { + super(context); + init(); + } + + /** + * Constructor of <code>PictureItemView</code>. + * + * @param context The current context + * @param attrs The attributes of the XML tag that is inflating the view. + */ + public PictureItemView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + /** + * Constructor of <code>PictureItemView</code>. + * + * @param context The current context + * @param attrs The attributes of the XML tag that is inflating the view. + * @param defStyle The default style to apply to this view. If 0, no style + * will be applied (beyond what is included in the theme). This may + * either be an attribute resource, whose value will be retrieved + * from the current theme, or an explicit style resource. + */ + public PictureItemView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(); + } + + /** + * Method that initializes the internal references + */ + private void init() { + mCallbacks = new ArrayList<PictureItemView.CallbacksListener>(); + } + + /** + * Method that adds the class that will be listen for events of this class + * + * @param callback The callback class + */ + public void addCallBackListener(CallbacksListener callback) { + this.mCallbacks.add(callback); + } + + /** + * Method that removes the class from the current callbacks + * + * @param callback The callback class + */ + public void removeCallBackListener(CallbacksListener callback) { + this.mCallbacks.remove(callback); + } + + /** + * {@inheritDoc} + */ + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + + updateView(mPicture, true); + } + + /** + * {@inheritDoc} + */ + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + + // Cancel pending tasks + if (mTask != null && mTask.getStatus().compareTo(Status.PENDING) == 0) { + mTask.cancel(true); + } + } + + /** + * Method that returns the picture + * + * @return Picture The picture + */ + public Picture getPicture() { + return mPicture; + } + + /** + * Method that sets the picture + * + * @param picture The picture + */ + public void setPicture(Picture picture) { + mPicture = picture; + } + + /** + * Method that updates the view + * + * @param picture The picture data + */ + public void updateView(Picture picture, boolean refreshIcon) { + // Destroy the update drawable task + if (mTask != null && (mTask.getStatus() == AsyncTask.Status.RUNNING || + mTask.getStatus() == AsyncTask.Status.PENDING)) { + mTask.cancel(true); + } + + // Retrieve the views references + if (mIcon == null) { + mIcon = (ImageView)findViewById(R.id.picture_thumbnail); + } + + // Update the views + if (picture != null) { + setPicture(picture); + + setSelected(picture.isSelected()); + + // Do no try to cache the images (this generates a lot of memory an we want + // to have a low memory footprint) + if (refreshIcon) { + mIcon.setImageDrawable(null); + + // Show as icon, the first picture + mTask = new AsyncPictureLoaderTask(getContext(), mIcon); + mTask.execute(new File(picture.getPath())); + } + } + } + +} diff --git a/src/org/cyanogenmod/wallpapers/photophase/widgets/PicturesView.java b/src/org/cyanogenmod/wallpapers/photophase/widgets/PicturesView.java deleted file mode 100644 index 0744751..0000000 --- a/src/org/cyanogenmod/wallpapers/photophase/widgets/PicturesView.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (C) 2013 The CyanogenMod Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.cyanogenmod.wallpapers.photophase.widgets; - -import android.content.Context; -import android.graphics.Rect; -import android.os.AsyncTask.Status; -import android.os.Handler; -import android.util.AttributeSet; -import android.view.ViewGroup; -import android.widget.HorizontalScrollView; -import android.widget.ImageView; - -import org.cyanogenmod.wallpapers.photophase.R; -import org.cyanogenmod.wallpapers.photophase.tasks.AsyncPictureLoaderTask; - -import java.io.File; -import java.util.HashMap; -import java.util.Iterator; - -/** - * A view that contains all the pictures of an album - */ -public class PicturesView extends HorizontalScrollView { - - private HashMap<File, AsyncPictureLoaderTask> mTasks; - private Handler mHandler; - - /** - * Constructor of <code>PicturesView</code>. - * - * @param context The current context - */ - public PicturesView(Context context) { - super(context); - init(); - } - - /** - * Constructor of <code>PicturesView</code>. - * - * @param context The current context - * @param attrs The attributes of the XML tag that is inflating the view. - */ - public PicturesView(Context context, AttributeSet attrs) { - super(context, attrs); - init(); - } - - /** - * Constructor of <code>PicturesView</code>. - * - * @param context The current context - * @param attrs The attributes of the XML tag that is inflating the view. - * @param defStyle The default style to apply to this view. If 0, no style - * will be applied (beyond what is included in the theme). This may - * either be an attribute resource, whose value will be retrieved - * from the current theme, or an explicit style resource. - */ - public PicturesView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - init(); - } - - /** - * Method that initializes the structures of this class - */ - private void init() { - mTasks = new HashMap<File, AsyncPictureLoaderTask>(); - mHandler = new Handler(); - } - - /** - * {@inheritDoc} - */ - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - cancelTasks(); - } - - /** - * Method that removes all tasks - */ - public void cancelTasks() { - // Cancel all the pending task - Iterator<AsyncPictureLoaderTask> it = mTasks.values().iterator(); - while (it.hasNext()) { - AsyncPictureLoaderTask task = it.next(); - if (task.getStatus().compareTo(Status.PENDING) == 0) { - task.cancel(true); - } - } - mTasks.clear(); - } - - /** - * {@inheritDoc} - */ - @Override - protected void onScrollChanged(int l, int t, int oldl, int oldt) { - super.onScrollChanged(l, t, oldl, oldt); - // Estimated velocity (in some moment we must obtain some scrolling with an estimated - // velocity below of 3) - int velocity = Math.abs(l - oldl); - if (velocity <= 3) { - mHandler.post(new Runnable() { - @Override - public void run() { - requestLoadOfPendingPictures(); - } - }); - } - } - - /** - * Method invoked when the view is displayed - */ - public void onShow() { - mHandler.post(new Runnable() { - @Override - public void run() { - requestLoadOfPendingPictures(); - } - }); - } - - /** - * Method that load in background all visible and pending pictures - */ - /*package*/ void requestLoadOfPendingPictures() { - // Get the visible rect - Rect r = new Rect(); - getHitRect(r); - - // Get all the image views - ViewGroup vg = (ViewGroup)getChildAt(0); - int count = vg.getChildCount(); - for (int i = 0; i < count; i++) { - ViewGroup picView = (ViewGroup)vg.getChildAt(i); - File image = new File((String)picView.getTag()); - if (picView.getLocalVisibleRect(r) && !mTasks.containsKey(image)) { - ImageView iv = (ImageView)picView.findViewById(R.id.picture_thumbnail); - AsyncPictureLoaderTask task = new AsyncPictureLoaderTask(getContext(), iv); - task.execute(image); - mTasks.put(image, task); - } - } - } -} diff --git a/src/org/cyanogenmod/wallpapers/photophase/widgets/VerticalEndlessScroller.java b/src/org/cyanogenmod/wallpapers/photophase/widgets/VerticalEndlessScroller.java deleted file mode 100644 index 67a1f17..0000000 --- a/src/org/cyanogenmod/wallpapers/photophase/widgets/VerticalEndlessScroller.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2013 The CyanogenMod Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.cyanogenmod.wallpapers.photophase.widgets; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.View; -import android.widget.ScrollView; - -/** - * A scroll view that notifies the end of the scroll to create new views - * dynamically. - */ -public class VerticalEndlessScroller extends ScrollView { - - /** - * Interface to communicate end-scroll events - */ - public interface OnEndScrollListener { - /** - * Called when the scroll reachs the end of the scroll - */ - void onEndScroll(); - } - - private OnEndScrollListener mCallback; - private int mEndPadding = 0; - private boolean mSwitch = false; - - /** - * Constructor of <code>VerticalEndlessScroller</code>. - * - * @param context The current context - */ - public VerticalEndlessScroller(Context context) { - super(context); - } - - /** - * Constructor of <code>VerticalEndlessScroller</code>. - * - * @param context The current context - * @param attrs The attributes of the XML tag that is inflating the view. - */ - public VerticalEndlessScroller(Context context, AttributeSet attrs) { - super(context, attrs); - } - - /** - * Constructor of <code>VerticalEndlessScroller</code>. - * - * @param context The current context - * @param attrs The attributes of the XML tag that is inflating the view. - * @param defStyle The default style to apply to this view. If 0, no style - * will be applied (beyond what is included in the theme). This may - * either be an attribute resource, whose value will be retrieved - * from the current theme, or an explicit style resource. - */ - public VerticalEndlessScroller(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } - - /** - * Method that set the callback for notify end-scroll events - * - * @param callback The callback - */ - public void setCallback(OnEndScrollListener callback) { - mCallback = callback; - } - - /** - * Method that set the end padding for fired the event - * - * @param endPadding The end padding - */ - public void setEndPadding(int endPadding) { - this.mEndPadding = endPadding; - } - - /** - * {@inheritDoc} - */ - @Override - protected void onScrollChanged(int l, int t, int oldl, int oldt) { - // We take the last child in the scrollview - View view = getChildAt(getChildCount() - 1); - int diff = (view.getBottom() - (getHeight() + getScrollY())); - if ((!mSwitch && diff <= mEndPadding)) { - if (mCallback != null) { - mCallback.onEndScroll(); - mSwitch = true; - return; - } - } else if (diff > mEndPadding) { - mSwitch = false; - } - } - -} |