Commit 10dac382 authored by Amit Kumar's avatar Amit Kumar 💻
Browse files

Separate folder logic from launcher activity

parent 4bf4103d
Pipeline #151609 passed with stage
in 8 minutes and 20 seconds
...@@ -85,7 +85,7 @@ class ShaderBlurDrawable internal constructor(private val blurWallpaperProvider: ...@@ -85,7 +85,7 @@ class ShaderBlurDrawable internal constructor(private val blurWallpaperProvider:
if (canvasOffset > 0) if (canvasOffset > 0)
canvas.translate(-canvasOffset, 0f) canvas.translate(-canvasOffset, 0f)
} }
override fun setAlpha(alpha: Int) { override fun setAlpha(alpha: Int) {
blurAlpha = alpha blurAlpha = alpha
blurPaint.alpha = alpha blurPaint.alpha = alpha
......
...@@ -62,9 +62,7 @@ class FolderTitleInput @JvmOverloads constructor( ...@@ -62,9 +62,7 @@ class FolderTitleInput @JvmOverloads constructor(
fun dispatchBackKey() { fun dispatchBackKey() {
hideKeyboard() hideKeyboard()
if (mBackKeyListener != null) { mBackKeyListener?.onBackKey()
mBackKeyListener!!.onBackKey()
}
} }
/** /**
......
...@@ -38,9 +38,6 @@ import android.view.animation.AnimationUtils; ...@@ -38,9 +38,6 @@ import android.view.animation.AnimationUtils;
import android.view.animation.OvershootInterpolator; import android.view.animation.OvershootInterpolator;
import android.widget.GridLayout; import android.widget.GridLayout;
import android.widget.Toast; import android.widget.Toast;
import androidx.viewpager.widget.ViewPager;
import foundation.e.blisslauncher.BuildConfig; import foundation.e.blisslauncher.BuildConfig;
import foundation.e.blisslauncher.R; import foundation.e.blisslauncher.R;
import foundation.e.blisslauncher.core.Utilities; import foundation.e.blisslauncher.core.Utilities;
...@@ -57,6 +54,7 @@ import foundation.e.blisslauncher.core.utils.GraphicsUtil; ...@@ -57,6 +54,7 @@ import foundation.e.blisslauncher.core.utils.GraphicsUtil;
import foundation.e.blisslauncher.core.utils.IntSparseArrayMap; import foundation.e.blisslauncher.core.utils.IntSparseArrayMap;
import foundation.e.blisslauncher.core.utils.IntegerArray; import foundation.e.blisslauncher.core.utils.IntegerArray;
import foundation.e.blisslauncher.core.utils.PackageUserKey; import foundation.e.blisslauncher.core.utils.PackageUserKey;
import foundation.e.blisslauncher.features.folder.FolderIcon;
import foundation.e.blisslauncher.features.launcher.Hotseat; import foundation.e.blisslauncher.features.launcher.Hotseat;
import foundation.e.blisslauncher.features.notification.FolderDotInfo; import foundation.e.blisslauncher.features.notification.FolderDotInfo;
import foundation.e.blisslauncher.features.shortcuts.DeepShortcutManager; import foundation.e.blisslauncher.features.shortcuts.DeepShortcutManager;
...@@ -64,7 +62,6 @@ import foundation.e.blisslauncher.features.shortcuts.InstallShortcutReceiver; ...@@ -64,7 +62,6 @@ import foundation.e.blisslauncher.features.shortcuts.InstallShortcutReceiver;
import foundation.e.blisslauncher.features.shortcuts.ShortcutKey; import foundation.e.blisslauncher.features.shortcuts.ShortcutKey;
import foundation.e.blisslauncher.features.test.Alarm; import foundation.e.blisslauncher.features.test.Alarm;
import foundation.e.blisslauncher.features.test.CellLayout; import foundation.e.blisslauncher.features.test.CellLayout;
import foundation.e.blisslauncher.features.test.FolderIconTextView;
import foundation.e.blisslauncher.features.test.IconTextView; import foundation.e.blisslauncher.features.test.IconTextView;
import foundation.e.blisslauncher.features.test.LauncherItemMatcher; import foundation.e.blisslauncher.features.test.LauncherItemMatcher;
import foundation.e.blisslauncher.features.test.LauncherState; import foundation.e.blisslauncher.features.test.LauncherState;
...@@ -84,7 +81,6 @@ import foundation.e.blisslauncher.features.test.dragndrop.DropTarget; ...@@ -84,7 +81,6 @@ import foundation.e.blisslauncher.features.test.dragndrop.DropTarget;
import foundation.e.blisslauncher.features.test.dragndrop.SpringLoadedDragController; import foundation.e.blisslauncher.features.test.dragndrop.SpringLoadedDragController;
import foundation.e.blisslauncher.features.test.graphics.DragPreviewProvider; import foundation.e.blisslauncher.features.test.graphics.DragPreviewProvider;
import foundation.e.blisslauncher.features.test.uninstall.UninstallHelper; import foundation.e.blisslauncher.features.test.uninstall.UninstallHelper;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
...@@ -94,7 +90,6 @@ import java.util.List; ...@@ -94,7 +90,6 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.function.Predicate; import java.util.function.Predicate;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
public class LauncherPagedView extends PagedView<PageIndicatorDots> implements View.OnTouchListener, public class LauncherPagedView extends PagedView<PageIndicatorDots> implements View.OnTouchListener,
...@@ -338,11 +333,8 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V ...@@ -338,11 +333,8 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V
LauncherItem launcherItem = launcherItems.get(i); LauncherItem launcherItem = launcherItems.get(i);
View appView; View appView;
if (launcherItem.itemType == Constants.ITEM_TYPE_FOLDER) { if (launcherItem.itemType == Constants.ITEM_TYPE_FOLDER) {
FolderIconTextView folderIcon = FolderIcon folderIcon = FolderIcon.Companion.fromXml(R.layout.folder_icon, getScreenWithId(launcherItem.screenId), (FolderItem) launcherItem);
(FolderIconTextView) LayoutInflater.from(getContext())
.inflate(R.layout.folder_icon, null, false);
folderIcon.applyFromFolderItem((FolderItem) launcherItem); folderIcon.applyFromFolderItem((FolderItem) launcherItem);
((FolderItem) launcherItem).addListener(folderIcon);
appView = folderIcon; appView = folderIcon;
} else { } else {
IconTextView appIcon = (IconTextView) LayoutInflater.from(getContext()) IconTextView appIcon = (IconTextView) LayoutInflater.from(getContext())
...@@ -537,8 +529,8 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V ...@@ -537,8 +529,8 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V
*/ */
public void removeFolderListeners() { public void removeFolderListeners() {
mapOverItems(false, (info, view, index) -> { mapOverItems(false, (info, view, index) -> {
if (view instanceof FolderIconTextView) { if (view instanceof FolderIcon) {
((FolderIconTextView) view).removeListeners(); ((FolderIcon) view).removeListeners();
} }
return false; return false;
}); });
...@@ -1532,6 +1524,38 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V ...@@ -1532,6 +1524,38 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V
mDragInfo = null; mDragInfo = null;
} }
/**
* Unbinds the view for the specified item, and removes the item and all its children.
*
* @param v the view being removed.
* @param itemInfo the {@link LauncherItem} for this view.
*/
public boolean removeItem(View v, final LauncherItem itemInfo) {
if (itemInfo instanceof ApplicationItem || itemInfo instanceof ShortcutItem) {
// Remove the shortcut from the folder before removing it from launcher
View folderIcon = getHomescreenIconByItemId(String.valueOf(itemInfo.container));
if (folderIcon instanceof FolderIcon) {
((FolderItem) folderIcon.getTag()).remove(itemInfo, true);
} else {
removeWorkspaceItem(v);
}
updateDatabase();
} else if (itemInfo instanceof FolderItem) {
if (v instanceof FolderIcon) {
((FolderIcon) v).removeListeners();
}
removeWorkspaceItem(v);
updateDatabase();
} else {
return false;
}
return true;
}
public View getHomescreenIconByItemId(final String id) {
return getFirstMatch((info, v, idx) -> info != null && info.id == id);
}
/** /**
* For opposite operation. See {@link #addInScreen}. * For opposite operation. See {@link #addInScreen}.
*/ */
...@@ -1898,7 +1922,7 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V ...@@ -1898,7 +1922,7 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V
fi.screenId = screenId; fi.screenId = screenId;
fi.cell = targetCell[1] * mLauncher.getDeviceProfile().getInv() fi.cell = targetCell[1] * mLauncher.getDeviceProfile().getInv()
.getNumColumns() + targetCell[0]; .getNumColumns() + targetCell[0];
FolderIconTextView folderView = (FolderIconTextView) LayoutInflater.from(getContext()) FolderIcon folderView = (FolderIcon) LayoutInflater.from(getContext())
.inflate(R.layout.folder_icon, null, false); .inflate(R.layout.folder_icon, null, false);
folderView.applyFromShortcutItem(fi); folderView.applyFromShortcutItem(fi);
folderView.setOnClickListener(ItemClickHandler.INSTANCE); folderView.setOnClickListener(ItemClickHandler.INSTANCE);
...@@ -2567,6 +2591,18 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V ...@@ -2567,6 +2591,18 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V
); );
} }
public View getFirstMatch(final ItemOperator operator) {
final View[] value = new View[1];
mapOverItems(MAP_NO_RECURSE, (info, v, index) -> {
if (operator.evaluate(info, v, index)) {
value[0] = v;
return true;
}
return false;
});
return value[0];
}
/** /**
* @param cellLayouts List of CellLayouts to scan, in order of preference. * @param cellLayouts List of CellLayouts to scan, in order of preference.
* @param operators List of operators, in order starting from best matching operator. * @param operators List of operators, in order starting from best matching operator.
...@@ -2663,12 +2699,12 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V ...@@ -2663,12 +2699,12 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V
// Update folder icons // Update folder icons
mapOverItems(MAP_NO_RECURSE, (info, v, itemIdx) -> { mapOverItems(MAP_NO_RECURSE, (info, v, itemIdx) -> {
if (info instanceof FolderItem && folderIds.contains(info.id) if (info instanceof FolderItem && folderIds.contains(info.id)
&& v instanceof FolderIconTextView) { && v instanceof FolderIcon) {
FolderDotInfo folderDotInfo = new FolderDotInfo(); FolderDotInfo folderDotInfo = new FolderDotInfo();
for (LauncherItem si : ((FolderItem) info).items) { for (LauncherItem si : ((FolderItem) info).items) {
folderDotInfo.addDotInfo(mLauncher.getDotInfoForItem(si)); folderDotInfo.addDotInfo(mLauncher.getDotInfoForItem(si));
} }
((FolderIconTextView) v).setDotInfo(folderDotInfo); ((FolderIcon) v).setDotInfo(folderDotInfo);
} }
// process all the shortcuts // process all the shortcuts
return false; return false;
...@@ -2831,7 +2867,7 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V ...@@ -2831,7 +2867,7 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V
FolderItem folder = (FolderItem) parent.getTag(); FolderItem folder = (FolderItem) parent.getTag();
parent.clearAnimation(); parent.clearAnimation();
// Close folder before making any changes // Close folder before making any changes
mLauncher.closeFolder(); // mLauncher.closeFolder();
folder.items.remove(itemToRemove); folder.items.remove(itemToRemove);
DatabaseManager.getManager(getContext()).removeItem(itemToRemove.id); DatabaseManager.getManager(getContext()).removeItem(itemToRemove.id);
if (folder.items.size() == 0) { if (folder.items.size() == 0) {
......
package foundation.e.blisslauncher.core.database.model; package foundation.e.blisslauncher.core.database.model;
import org.jetbrains.annotations.NotNull;
import foundation.e.blisslauncher.core.utils.Constants; import foundation.e.blisslauncher.core.utils.Constants;
import java.util.ArrayList; import java.util.ArrayList;
...@@ -34,7 +36,24 @@ public class FolderItem extends LauncherItem { ...@@ -34,7 +36,24 @@ public class FolderItem extends LauncherItem {
listeners.remove(listener); listeners.remove(listener);
} }
public void remove(@NotNull LauncherItem launcherItem, boolean animate) {
items.remove(launcherItem);
for (int i = 0; i < listeners.size(); i++) {
listeners.get(i).onRemove(launcherItem);
}
itemsChanged(animate);
}
public void itemsChanged(boolean animate) {
for (int i = 0; i < listeners.size(); i++) {
listeners.get(i).onItemsChanged(animate);
}
}
public interface FolderListener { public interface FolderListener {
void onAdd(LauncherItem item);
void onTitleChanged(CharSequence title); void onTitleChanged(CharSequence title);
void onRemove(LauncherItem item);
void onItemsChanged(boolean animate);
} }
} }
...@@ -21,10 +21,12 @@ import android.util.Log; ...@@ -21,10 +21,12 @@ import android.util.Log;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import foundation.e.blisslauncher.core.customviews.Folder;
import foundation.e.blisslauncher.core.database.model.ApplicationItem; import foundation.e.blisslauncher.core.database.model.ApplicationItem;
import foundation.e.blisslauncher.core.database.model.FolderItem; import foundation.e.blisslauncher.core.database.model.FolderItem;
import foundation.e.blisslauncher.core.database.model.LauncherItem; import foundation.e.blisslauncher.core.database.model.LauncherItem;
import foundation.e.blisslauncher.core.database.model.ShortcutItem; import foundation.e.blisslauncher.core.database.model.ShortcutItem;
import foundation.e.blisslauncher.features.folder.FolderIcon;
import foundation.e.blisslauncher.features.test.IconTextView; import foundation.e.blisslauncher.features.test.IconTextView;
import foundation.e.blisslauncher.features.test.TestActivity; import foundation.e.blisslauncher.features.test.TestActivity;
...@@ -60,7 +62,7 @@ public class ItemClickHandler { ...@@ -60,7 +62,7 @@ public class ItemClickHandler {
if (tag instanceof ShortcutItem) { if (tag instanceof ShortcutItem) {
onClickAppShortcut(v, (ShortcutItem) tag, launcher); onClickAppShortcut(v, (ShortcutItem) tag, launcher);
} else if (tag instanceof FolderItem) { } else if (tag instanceof FolderItem) {
onClickFolderIcon(v, launcher); onClickFolderIcon(v);
} else if (tag instanceof ApplicationItem) { } else if (tag instanceof ApplicationItem) {
startAppShortcutOrInfoActivity(v, (ApplicationItem) tag, launcher); startAppShortcutOrInfoActivity(v, (ApplicationItem) tag, launcher);
} }
...@@ -70,14 +72,13 @@ public class ItemClickHandler { ...@@ -70,14 +72,13 @@ public class ItemClickHandler {
* Event handler for a folder icon click. * Event handler for a folder icon click.
* *
* @param v The view that was clicked. Must be an instance of {@link IconTextView}. * @param v The view that was clicked. Must be an instance of {@link IconTextView}.
* @param launcher Launcher activity to pass actions.
*/ */
private static void onClickFolderIcon( private static void onClickFolderIcon(View v) {
View v, Folder folder = ((FolderIcon) v).getFolder();
TestActivity launcher if (!folder.isOpen() && !folder.isDestroyed()) {
) { // Open the requested folder
Log.d("ItemClick", "onClickFolderIcon() called with: v = [" + v + "]"); folder.animateOpen();
launcher.openFolder(v); }
} }
/** /**
......
...@@ -20,6 +20,7 @@ import static foundation.e.blisslauncher.features.test.LauncherState.OVERVIEW; ...@@ -20,6 +20,7 @@ import static foundation.e.blisslauncher.features.test.LauncherState.OVERVIEW;
import android.view.View; import android.view.View;
import android.view.View.OnLongClickListener; import android.view.View.OnLongClickListener;
import foundation.e.blisslauncher.core.customviews.Folder;
import foundation.e.blisslauncher.core.database.model.LauncherItem; import foundation.e.blisslauncher.core.database.model.LauncherItem;
import foundation.e.blisslauncher.features.test.CellLayout; import foundation.e.blisslauncher.features.test.CellLayout;
import foundation.e.blisslauncher.features.test.TestActivity; import foundation.e.blisslauncher.features.test.TestActivity;
...@@ -58,7 +59,7 @@ public class ItemLongClickListener { ...@@ -58,7 +59,7 @@ public class ItemLongClickListener {
DragOptions dragOptions DragOptions dragOptions
) { ) {
if (info.container >= 0) { if (info.container >= 0) {
Folder folder = Folder.getOpen(launcher); Folder folder = Folder.Companion.getOpen(launcher);
if (folder != null) { if (folder != null) {
if (!folder.getItemsInReadingOrder().contains(v)) { if (!folder.getItemsInReadingOrder().contains(v)) {
folder.close(true); folder.close(true);
......
/*
* Copyright (C) 2017 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 foundation.e.blisslauncher.features.folder;
import static foundation.e.blisslauncher.features.test.anim.LauncherAnimUtils.SCALE_PROPERTY;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.GradientDrawable;
import android.util.Property;
import android.view.View;
import android.view.animation.AnimationUtils;
import androidx.viewpager.widget.ViewPager;
import foundation.e.blisslauncher.R;
import foundation.e.blisslauncher.core.customviews.Folder;
import foundation.e.blisslauncher.features.test.TestActivity;
import foundation.e.blisslauncher.features.test.dragndrop.DragLayer;
/**
* Manages the opening and closing animations for a {@link Folder}.
* <p>
* All of the animations are done in the Folder.
* ie. When the user taps on the FolderIcon, we immediately hide the FolderIcon and show the Folder
* in its place before starting the animation.
*/
public class FolderAnimationManager {
private Folder mFolder;
private ViewPager mContent;
private GradientDrawable mFolderBackground;
private FolderIcon mFolderIcon;
private Context mContext;
private TestActivity mLauncher;
private final boolean mIsOpening;
private final int mDuration;
private final int mDelay;
private final TimeInterpolator mFolderInterpolator;
public FolderAnimationManager(Folder folder, boolean isOpening) {
mFolder = folder;
mContent = folder.mContent;
mFolderIcon = folder.getFolderIcon();
mContext = folder.getContext();
mLauncher = folder.getLauncher();
mIsOpening = isOpening;
Resources res = mContent.getResources();
mDuration = res.getInteger(R.integer.config_materialFolderExpandDuration);
mDelay = res.getInteger(R.integer.config_folderDelay);
mFolderInterpolator = AnimationUtils.loadInterpolator(
mContext,
R.anim.folder_interpolator
);
}
/**
* Prepares the Folder for animating between open / closed states.
*/
public AnimatorSet getAnimator() {
final DragLayer.LayoutParams lp = (DragLayer.LayoutParams) mFolder.getLayoutParams();
// Match position of the FolderIcon
final Rect folderIconPos = new Rect();
float scaleRelativeToDragLayer = mLauncher.getDragLayer()
.getDescendantRectRelativeToSelf(mFolderIcon, folderIconPos);
// Calculate the starting and ending bounds for the zoomed-in image.
// This step involves lots of math. Yay, math.
Rect dragLayerBounds = new Rect();
Point globalOffset = new Point();
mLauncher.getDragLayer()
.getGlobalVisibleRect(dragLayerBounds, globalOffset);
float startScale = ((float) folderIconPos.width() / dragLayerBounds.width());
float startHeight = startScale * dragLayerBounds.height();
float deltaHeight = (startHeight - folderIconPos.height()) / 2;
folderIconPos.top -= deltaHeight;
folderIconPos.bottom += deltaHeight;
float initialScale = (float) folderIconPos.height() / dragLayerBounds.height();
final float finalScale = 1f;
float scale = mIsOpening ? initialScale : finalScale;
float initialAlpha = 0f;
float finalAlpha = 1f;
mFolder.setScaleX(scale);
mFolder.setScaleY(scale);
mFolder.setPivotX(0);
mFolder.setPivotY(0);
// Create the animators.
AnimatorSet a = new AnimatorSet();
play(
a,
getAnimator(mFolder,
View.X,
folderIconPos.left,
dragLayerBounds.left
)
);
play(a, getAnimator(mFolder, View.Y, folderIconPos.top, dragLayerBounds.top));
play(a, getAnimator(mFolder, SCALE_PROPERTY, initialScale, finalScale));
play(a, getAnimator(mFolder, View.ALPHA, initialAlpha, finalAlpha));
// play(a, getAnimator(mFolderBackground, "color", initialColor, finalColor));
// Animate the elevation midway so that the shadow is not noticeable in the background.
int midDuration = mDuration / 2;
Animator z = getAnimator(mFolder, View.TRANSLATION_Z, -mFolder.getElevation(), 0);
play(a, z, mIsOpening ? midDuration : 0, midDuration);
a.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
mFolder.setVisibility(View.VISIBLE);
mFolder.setPivotX(0f);
mFolder.setPivotY(0f);
}
@Override
public void onAnimationCancel(Animator animation) {
super.onAnimationCancel(animation);
if (mIsOpening) {
mFolder.setVisibility(View.GONE);
}
}
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
mFolder.setScaleX(1f);
mFolder.setScaleY(1f);
if (!mIsOpening) {
mFolder.setVisibility(View.GONE);
}
}
});
return a;
}
private void play(AnimatorSet as, Animator a) {
play(as, a, a.getStartDelay(), mDuration);
}
private void play(AnimatorSet as, Animator a, long startDelay, int duration) {
a.setStartDelay(startDelay);
a.setDuration(duration);
as.play(a);
}
private TimeInterpolator getPreviewItemInterpolator() {
return mFolderInterpolator;
}
private Animator getAnimator(View view, Property property, float v1, float v2) {
return mIsOpening
? ObjectAnimator.ofFloat(view, property, v1, v2)
: ObjectAnimator.ofFloat(view, property, v2, v1);
}