diff options
author | Sunny Goyal <sunnygoyal@google.com> | 2015-03-10 13:14:47 -0700 |
---|---|---|
committer | Sunny Goyal <sunnygoyal@google.com> | 2015-03-17 14:49:38 -0700 |
commit | 5d85c44fd873c740dc191b28424c2ee367d730a2 (patch) | |
tree | 293001622c1888852f148a138b542563c6131dd4 /src/com/android/launcher3/FolderPagedView.java | |
parent | ce53e6dd12f5fa9e16ea77fbdafed3f8c2f448ac (diff) | |
download | android_packages_apps_Trebuchet-5d85c44fd873c740dc191b28424c2ee367d730a2.tar.gz android_packages_apps_Trebuchet-5d85c44fd873c740dc191b28424c2ee367d730a2.tar.bz2 android_packages_apps_Trebuchet-5d85c44fd873c740dc191b28424c2ee367d730a2.zip |
Adding sort switch in FolderPagedView
> Adding options column in DB to store generation purpose flags
> Storing isSorted flag in FolderInfo
> Adding a switch for A-Z sorting (only visible if pageCount > 1)
> When in sorted mode, spring-load snaps to the target location for 1.5 seconds
Change-Id: I8c7c778d2cc3ccbd35a2890a1a705e1c1a7e9a66
Diffstat (limited to 'src/com/android/launcher3/FolderPagedView.java')
-rw-r--r-- | src/com/android/launcher3/FolderPagedView.java | 228 |
1 files changed, 216 insertions, 12 deletions
diff --git a/src/com/android/launcher3/FolderPagedView.java b/src/com/android/launcher3/FolderPagedView.java index b4a7a7546..529064444 100644 --- a/src/com/android/launcher3/FolderPagedView.java +++ b/src/com/android/launcher3/FolderPagedView.java @@ -20,15 +20,22 @@ import android.annotation.SuppressLint; import android.content.Context; import android.util.AttributeSet; import android.util.Log; +import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.animation.DecelerateInterpolator; +import android.view.animation.Interpolator; +import android.view.animation.OvershootInterpolator; +import android.widget.Switch; import com.android.launcher3.FocusHelper.PagedFolderKeyEventListener; import com.android.launcher3.PageIndicator.PageMarkerResources; import com.android.launcher3.Workspace.ItemOperator; +import java.text.Collator; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.Map; @@ -40,14 +47,19 @@ public class FolderPagedView extends PagedView implements Folder.FolderContent { private static final int REORDER_ANIMATION_DURATION = 230; private static final int START_VIEW_REORDER_DELAY = 30; private static final float VIEW_REORDER_DELAY_FACTOR = 0.9f; + + private static final int SPAN_TO_PAGE_DURATION = 350; + private static final int SORT_ANIM_HIDE_DURATION = 130; + private static final int SORT_ANIM_SHOW_DURATION = 160; + private static final int[] sTempPosArray = new int[2]; // TODO: Remove this restriction - private static final int MAX_ITEMS_PER_PAGE = 3; + private static final int MAX_ITEMS_PER_PAGE = 4; private final LayoutInflater mInflater; private final IconCache mIconCache; - private final HashMap<View, Runnable> mPageChangingViews = new HashMap<>(); + private final HashMap<View, Runnable> mPendingAnimations = new HashMap<>(); private final int mMaxCountX; private final int mMaxCountY; @@ -61,6 +73,13 @@ public class FolderPagedView extends PagedView implements Folder.FolderContent { private FocusIndicatorView mFocusIndicatorView; private PagedFolderKeyEventListener mKeyListener; + private View mSortButton; + private Switch mSortSwitch; + private View mPageIndicator; + + private boolean mSortOperationPending; + boolean mIsSorted; + public FolderPagedView(Context context, AttributeSet attrs) { super(context, attrs); LauncherAppState app = LauncherAppState.getInstance(); @@ -80,6 +99,134 @@ public class FolderPagedView extends PagedView implements Folder.FolderContent { mFolder = folder; mFocusIndicatorView = (FocusIndicatorView) folder.findViewById(R.id.focus_indicator); mKeyListener = new PagedFolderKeyEventListener(folder); + + mSortButton = folder.findViewById(R.id.folder_sort); + mSortButton.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + onSortClicked(); + } + }); + mPageIndicator = folder.findViewById(R.id.folder_page_indicator); + mSortSwitch = (Switch) folder.findViewById(R.id.folder_sort_switch); + } + + private void onSortClicked() { + if (mSortOperationPending) { + return; + } + if (mIsSorted) { + setIsSorted(false, true); + } else { + mSortOperationPending = true; + doSort(); + } + } + + private void setIsSorted(boolean isSorted, boolean saveChanges) { + mIsSorted = isSorted; + mSortSwitch.setChecked(isSorted); + mFolder.mInfo.setOption(FolderInfo.FLAG_ITEMS_SORTED, isSorted, + saveChanges ? mFolder.mLauncher : null); + } + + /** + * Sorts the contents of the folder and animates the icons on the first page to reflect + * the changes. + * Steps: + * 1. Scroll to first page + * 2. Sort all icons in one go + * 3. Re-apply the old IconInfos on the first page (so that there is no instant change) + * 4. Animate each view individually to reflect the new icon. + */ + private void doSort() { + if (!mSortOperationPending) { + return; + } + if (getNextPage() != 0) { + snapToPage(0, SPAN_TO_PAGE_DURATION, new DecelerateInterpolator()); + return; + } + + mSortOperationPending = false; + ShortcutInfo[][] oldItems = new ShortcutInfo[mGridCountX][mGridCountY]; + CellLayout currentPage = getCurrentCellLayout(); + for (int x = 0; x < mGridCountX; x++) { + for (int y = 0; y < mGridCountY; y++) { + View v = currentPage.getChildAt(x, y); + if (v != null) { + oldItems[x][y] = (ShortcutInfo) v.getTag(); + } + } + } + + ArrayList<View> views = new ArrayList<View>(mFolder.getItemsInReadingOrder()); + Collections.sort(views, new ViewComparator()); + arrangeChildren(views, views.size()); + + int delay = 0; + float delayAmount = START_VIEW_REORDER_DELAY; + final Interpolator hideInterpolator = new DecelerateInterpolator(2); + final Interpolator showInterpolator = new OvershootInterpolator(0.8f); + + currentPage = getCurrentCellLayout(); + for (int x = 0; x < mGridCountX; x++) { + for (int y = 0; y < mGridCountY; y++) { + final BubbleTextView v = (BubbleTextView) currentPage.getChildAt(x, y); + if (v != null) { + final ShortcutInfo info = (ShortcutInfo) v.getTag(); + final Runnable clearPending = new Runnable() { + + @Override + public void run() { + mPendingAnimations.remove(v); + v.setScaleX(1); + v.setScaleY(1); + } + }; + if (oldItems[x][y] == null) { + v.setScaleX(0); + v.setScaleY(0); + v.animate().setDuration(SORT_ANIM_SHOW_DURATION) + .setStartDelay(SORT_ANIM_HIDE_DURATION + delay) + .scaleX(1).scaleY(1).setInterpolator(showInterpolator) + .withEndAction(clearPending); + mPendingAnimations.put(v, clearPending); + } else { + // Apply the old iconInfo so that there is no sudden change. + v.applyFromShortcutInfo(oldItems[x][y], mIconCache, false); + v.animate().setStartDelay(delay).setDuration(SORT_ANIM_HIDE_DURATION) + .scaleX(0).scaleY(0) + .setInterpolator(hideInterpolator) + .withEndAction(new Runnable() { + + @Override + public void run() { + // Apply the new iconInfo as part of the animation. + v.applyFromShortcutInfo(info, mIconCache, false); + v.animate().scaleX(1).scaleY(1) + .setDuration(SORT_ANIM_SHOW_DURATION).setStartDelay(0) + .setInterpolator(showInterpolator) + .withEndAction(clearPending); + } + }); + mPendingAnimations.put(v, new Runnable() { + + @Override + public void run() { + clearPending.run(); + v.applyFromShortcutInfo(info, mIconCache, false); + } + }); + } + delay += delayAmount; + delayAmount *= VIEW_REORDER_DELAY_FACTOR; + } + } + } + + setIsSorted(true, true); } /** @@ -125,6 +272,7 @@ public class FolderPagedView extends PagedView implements Folder.FolderContent { @Override public ArrayList<ShortcutInfo> bindItems(ArrayList<ShortcutInfo> items) { + mIsSorted = mFolder.mInfo.hasOption(FolderInfo.FLAG_ITEMS_SORTED); ArrayList<View> icons = new ArrayList<View>(); for (ShortcutInfo item : items) { icons.add(createNewView(item)); @@ -138,20 +286,33 @@ public class FolderPagedView extends PagedView implements Folder.FolderContent { * Also sets the current page to the last page. */ @Override - public int allocateNewLastItemRank() { + public int allocateRankForNewItem(ShortcutInfo info) { int rank = getItemCount(); - int total = rank + 1; - // Rearrange the items as the grid size might change. - mFolder.rearrangeChildren(total); + ArrayList<View> views = new ArrayList<View>(mFolder.getItemsInReadingOrder()); + if (mIsSorted) { + View tmp = new View(getContext()); + tmp.setTag(info); + int index = Collections.binarySearch(views, tmp, new ViewComparator()); + if (index < 0) { + rank = -index - 1; + } else { + // Item with same name already exists. + // We will just insert it before that item. + rank = index; + } + + } - setCurrentPage(getChildCount() - 1); + views.add(rank, null); + arrangeChildren(views, views.size(), false); + setCurrentPage(rank / mMaxItemsPerPage); return rank; } @Override public View createAndAddViewForRank(ShortcutInfo item, int rank) { View icon = createNewView(item); - addViewForRank(createNewView(item), item, rank); + addViewForRank(icon, item, rank); return icon; } @@ -259,6 +420,10 @@ public class FolderPagedView extends PagedView implements Folder.FolderContent { int position = 0; int newX, newY, rank; + boolean isSorted = mIsSorted; + + ViewComparator comparator = new ViewComparator(); + View lastView = null; rank = 0; for (int i = 0; i < itemCount; i++) { View v = list.size() > i ? list.get(i) : null; @@ -273,6 +438,10 @@ public class FolderPagedView extends PagedView implements Folder.FolderContent { } if (v != null) { + if (lastView != null) { + isSorted &= comparator.compare(lastView, v) <= 0; + } + CellLayout.LayoutParams lp = (CellLayout.LayoutParams) v.getLayoutParams(); newX = position % mGridCountX; newY = position / mGridCountX; @@ -292,6 +461,7 @@ public class FolderPagedView extends PagedView implements Folder.FolderContent { v, -1, mFolder.mLauncher.getViewIdForItem(info), lp, true); } + lastView = v; rank ++; position++; } @@ -305,6 +475,19 @@ public class FolderPagedView extends PagedView implements Folder.FolderContent { if (removed) { setCurrentPage(0); } + + setIsSorted(isSorted, saveChanges); + + // Update footer + if (getPageCount() > 1) { + mPageIndicator.setVisibility(View.VISIBLE); + mSortButton.setVisibility(View.VISIBLE); + mFolder.mFolderName.setGravity(Gravity.START); + } else { + mPageIndicator.setVisibility(View.GONE); + mSortButton.setVisibility(View.GONE); + mFolder.mFolderName.setGravity(Gravity.CENTER_HORIZONTAL); + } } @Override @@ -407,6 +590,17 @@ public class FolderPagedView extends PagedView implements Folder.FolderContent { if (mFolder != null) { mFolder.updateTextViewFocus(); } + if (mSortOperationPending && getNextPage() == 0) { + post(new Runnable() { + + @Override + public void run() { + if (mSortOperationPending) { + doSort(); + } + } + }); + } } /** @@ -433,8 +627,8 @@ public class FolderPagedView extends PagedView implements Folder.FolderContent { * Finish animation all the views which are animating across pages */ public void completePendingPageChanges() { - if (!mPageChangingViews.isEmpty()) { - HashMap<View, Runnable> pendingViews = new HashMap<>(mPageChangingViews); + if (!mPendingAnimations.isEmpty()) { + HashMap<View, Runnable> pendingViews = new HashMap<>(mPendingAnimations); for (Map.Entry<View, Runnable> e : pendingViews.entrySet()) { e.getKey().animate().cancel(); e.getValue().run(); @@ -533,7 +727,7 @@ public class FolderPagedView extends PagedView implements Folder.FolderContent { @Override public void run() { - mPageChangingViews.remove(v); + mPendingAnimations.remove(v); v.setTranslationX(oldTranslateX); ((CellLayout) v.getParent().getParent()).removeView(v); addViewForRank(v, (ShortcutInfo) v.getTag(), newRank); @@ -544,7 +738,7 @@ public class FolderPagedView extends PagedView implements Folder.FolderContent { .setDuration(REORDER_ANIMATION_DURATION) .setStartDelay(0) .withEndAction(endAction); - mPageChangingViews.put(v, endAction); + mPendingAnimations.put(v, endAction); } } moveStart = rankToMove; @@ -569,4 +763,14 @@ public class FolderPagedView extends PagedView implements Folder.FolderContent { } } } + + private static class ViewComparator implements Comparator<View> { + private final Collator mCollator = Collator.getInstance(); + + @Override + public int compare(View lhs, View rhs) { + return mCollator.compare( ((ShortcutInfo) lhs.getTag()).title.toString(), + ((ShortcutInfo) rhs.getTag()).title.toString()); + } + } } |