Handle home screen pages dragging

This commit is contained in:
Ensar Sarajčić 2023-08-23 11:17:45 +02:00
parent 47a92c3b66
commit 95cf8c0384
2 changed files with 131 additions and 45 deletions

View File

@ -60,6 +60,8 @@ class MainActivity : SimpleActivity(), FlingListener {
private var mMoveGestureThreshold = 0 private var mMoveGestureThreshold = 0
private var mIgnoreUpEvent = false private var mIgnoreUpEvent = false
private var mIgnoreMoveEvents = false private var mIgnoreMoveEvents = false
private var mIgnoreXMoveEvents = false
private var mIgnoreYMoveEvents = false
private var mLongPressedIcon: HomeScreenGridItem? = null private var mLongPressedIcon: HomeScreenGridItem? = null
private var mOpenPopupMenu: PopupMenu? = null private var mOpenPopupMenu: PopupMenu? = null
private var mCachedLaunchers = ArrayList<AppLauncher>() private var mCachedLaunchers = ArrayList<AppLauncher>()
@ -362,7 +364,10 @@ class MainActivity : SimpleActivity(), FlingListener {
if (hasFingerMoved && !mIgnoreMoveEvents) { if (hasFingerMoved && !mIgnoreMoveEvents) {
val diffY = mTouchDownY - event.y val diffY = mTouchDownY - event.y
val diffX = mTouchDownX - event.x
if (abs(diffY) > abs(diffX) && !mIgnoreYMoveEvents) {
mIgnoreXMoveEvents = true
if (isWidgetsFragmentExpanded()) { if (isWidgetsFragmentExpanded()) {
val newY = mWidgetsFragmentY - diffY val newY = mWidgetsFragmentY - diffY
binding.widgetsFragment.root.y = Math.min(Math.max(0f, newY), mScreenHeight.toFloat()) binding.widgetsFragment.root.y = Math.min(Math.max(0f, newY), mScreenHeight.toFloat())
@ -370,6 +375,10 @@ class MainActivity : SimpleActivity(), FlingListener {
val newY = mAllAppsFragmentY - diffY val newY = mAllAppsFragmentY - diffY
binding.allAppsFragment.root.y = Math.min(Math.max(0f, newY), mScreenHeight.toFloat()) binding.allAppsFragment.root.y = Math.min(Math.max(0f, newY), mScreenHeight.toFloat())
} }
} else if (abs(diffX) > abs(diffY) && !mIgnoreXMoveEvents) {
mIgnoreYMoveEvents = true
binding.homeScreenGrid.root.setSwipeMovement(diffX)
}
} }
mLastTouchCoords = Pair(event.x, event.y) mLastTouchCoords = Pair(event.x, event.y)
@ -386,6 +395,7 @@ class MainActivity : SimpleActivity(), FlingListener {
binding.homeScreenGrid.root.itemDraggingStopped() binding.homeScreenGrid.root.itemDraggingStopped()
if (!mIgnoreUpEvent) { if (!mIgnoreUpEvent) {
if (!mIgnoreYMoveEvents) {
if (binding.allAppsFragment.root.y < mScreenHeight * 0.5) { if (binding.allAppsFragment.root.y < mScreenHeight * 0.5) {
showFragment(binding.allAppsFragment) showFragment(binding.allAppsFragment)
} else if (isAllAppsFragmentExpanded()) { } else if (isAllAppsFragmentExpanded()) {
@ -398,6 +408,14 @@ class MainActivity : SimpleActivity(), FlingListener {
hideFragment(binding.widgetsFragment) hideFragment(binding.widgetsFragment)
} }
} }
if (!mIgnoreXMoveEvents) {
binding.homeScreenGrid.root.finalizeSwipe()
}
}
mIgnoreXMoveEvents = false
mIgnoreYMoveEvents = false
} }
} }

View File

@ -37,10 +37,7 @@ import com.simplemobiletools.launcher.extensions.getDrawableForPackageName
import com.simplemobiletools.launcher.extensions.homeScreenGridItemsDB import com.simplemobiletools.launcher.extensions.homeScreenGridItemsDB
import com.simplemobiletools.launcher.helpers.* import com.simplemobiletools.launcher.helpers.*
import com.simplemobiletools.launcher.models.HomeScreenGridItem import com.simplemobiletools.launcher.models.HomeScreenGridItem
import kotlin.math.abs import kotlin.math.*
import kotlin.math.floor
import kotlin.math.max
import kotlin.math.min
class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : RelativeLayout(context, attrs, defStyle) { class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : RelativeLayout(context, attrs, defStyle) {
constructor(context: Context, attrs: AttributeSet) : this(context, attrs, 0) constructor(context: Context, attrs: AttributeSet) : this(context, attrs, 0)
@ -77,6 +74,7 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
private var pageChangeAnimLeftPercentage = 0f private var pageChangeAnimLeftPercentage = 0f
private var pageChangeEnabled = true private var pageChangeEnabled = true
private var pageChangeIndicatorsAlpha = 0f private var pageChangeIndicatorsAlpha = 0f
private var pageChangeSwipedPercentage = 0f
// apply fake margins at the home screen. Real ones would cause the icons be cut at dragging at screen sides // apply fake margins at the home screen. Real ones would cause the icons be cut at dragging at screen sides
var sideMargins = Rect() var sideMargins = Rect()
@ -611,21 +609,12 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
private fun updateWidgetPositionAndSize(widgetView: AppWidgetHostView, item: HomeScreenGridItem): Size { private fun updateWidgetPositionAndSize(widgetView: AppWidgetHostView, item: HomeScreenGridItem): Size {
var x = calculateWidgetX(item.left) + width * item.page - width * lastPage var x = calculateWidgetX(item.left) + width * item.page - width * lastPage
if (pageChangeAnimLeftPercentage > 0f && pageChangeAnimLeftPercentage < 1f && (item.page == currentPage || item.page == lastPage)) { if (isBetweenPages() && (item.page == currentPage || item.page == lastPage || (pageChangeSwipedPercentage > 0f && item.page == currentPage - 1) || (pageChangeSwipedPercentage < 0f && item.page == currentPage + 1))) {
val xFactor = if (currentPage > lastPage) { val xFactor = getXFactorForCurrentPage()
pageChangeAnimLeftPercentage val lastXFactor = getXFactorForLastPage()
} else {
-pageChangeAnimLeftPercentage
}
val lastXFactor = if (currentPage > lastPage) {
pageChangeAnimLeftPercentage - 1
} else {
1 - pageChangeAnimLeftPercentage
}
if (item.page == currentPage) { if (item.page == currentPage) {
x += width * xFactor x += width * xFactor
} } else if (item.page == lastPage || (pageChangeSwipedPercentage > 0f && item.page == currentPage - 1) || (pageChangeSwipedPercentage < 0f && item.page == currentPage + 1)) {
if (item.page == lastPage) {
x += width * lastXFactor x += width * lastXFactor
} }
} }
@ -685,16 +674,8 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
fillCellSizes() fillCellSizes()
} }
val currentXFactor = if (currentPage > lastPage) { val currentXFactor = getXFactorForCurrentPage()
pageChangeAnimLeftPercentage val lastXFactor = getXFactorForLastPage()
} else {
-pageChangeAnimLeftPercentage
}
val lastXFactor = if (currentPage > lastPage) {
pageChangeAnimLeftPercentage - 1
} else {
1 - pageChangeAnimLeftPercentage
}
fun handleItemDrawing(item: HomeScreenGridItem, xFactor: Float) { fun handleItemDrawing(item: HomeScreenGridItem, xFactor: Float) {
if (item.id != draggedItem?.id) { if (item.id != draggedItem?.id) {
@ -755,6 +736,20 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
} }
} }
if (abs(pageChangeSwipedPercentage) > 0f) {
gridItems.filter {
(it.drawable != null && it.type == ITEM_TYPE_ICON || it.type == ITEM_TYPE_SHORTCUT)
&& ((pageChangeSwipedPercentage > 0f && it.page == currentPage - 1) || (pageChangeSwipedPercentage < 0f && it.page == currentPage + 1))
&& !it.docked
}.forEach { item ->
if (item.outOfBounds()) {
return@forEach
}
handleItemDrawing(item, lastXFactor)
}
}
if (isFirstDraw) { if (isFirstDraw) {
gridItems.filter { it.type == ITEM_TYPE_WIDGET && !it.outOfBounds() }.forEach { item -> gridItems.filter { it.type == ITEM_TYPE_WIDGET && !it.outOfBounds() }.forEach { item ->
bindWidget(item, true) bindWidget(item, true)
@ -768,7 +763,7 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
} }
// Only draw page indicators when there is a need for it // Only draw page indicators when there is a need for it
if (pageChangeAnimLeftPercentage > 0f || pageChangeIndicatorsAlpha != 0f) { if (pageChangeAnimLeftPercentage > 0f || pageChangeIndicatorsAlpha != 0f || abs(pageChangeSwipedPercentage) > 0f) {
val pageCount = max(getMaxPage(), currentPage) + 1 val pageCount = max(getMaxPage(), currentPage) + 1
val pageIndicatorsRequiredWidth = pageCount * pageIndicatorRadius * 2 + pageCount * (pageIndicatorMargin - 1) val pageIndicatorsRequiredWidth = pageCount * pageIndicatorRadius * 2 + pageCount * (pageIndicatorMargin - 1)
val usableWidth = getFakeWidth() val usableWidth = getFakeWidth()
@ -789,8 +784,22 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
// Draw current page indicator on exact position // Draw current page indicator on exact position
val currentIndicatorRangeStart = pageIndicatorsStart + lastPage * pageIndicatorStep val currentIndicatorRangeStart = pageIndicatorsStart + lastPage * pageIndicatorStep
val currentIndicatorRangeEnd = pageIndicatorsStart + currentPage * pageIndicatorStep val indicatorEndPage = if (abs(pageChangeSwipedPercentage) > 0f) {
val currentIndicatorPosition = MathUtils.lerp(currentIndicatorRangeStart, currentIndicatorRangeEnd, 1 - pageChangeAnimLeftPercentage) if (pageChangeSwipedPercentage > 0f) {
currentPage - 1
} else {
currentPage + 1
}
} else {
currentPage
}
val currentIndicatorRangeEnd = pageIndicatorsStart + indicatorEndPage * pageIndicatorStep
val lerpAmount = if (pageChangeAnimLeftPercentage > 0f) {
1 - pageChangeAnimLeftPercentage
} else {
abs(pageChangeSwipedPercentage)
}
val currentIndicatorPosition = MathUtils.lerp(currentIndicatorRangeStart, currentIndicatorRangeEnd, lerpAmount)
if (pageChangeIndicatorsAlpha != 0f) { if (pageChangeIndicatorsAlpha != 0f) {
currentPageIndicatorPaint.alpha = (pageChangeIndicatorsAlpha * 255.0f).toInt() currentPageIndicatorPaint.alpha = (pageChangeIndicatorsAlpha * 255.0f).toInt()
} else { } else {
@ -1087,11 +1096,13 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
private fun handlePageChange(redraw: Boolean = false) { private fun handlePageChange(redraw: Boolean = false) {
pageChangeEnabled = false pageChangeEnabled = false
pageChangeIndicatorsAlpha = 0f pageChangeIndicatorsAlpha = 0f
val startingAt = 1 - abs(pageChangeSwipedPercentage)
pageChangeSwipedPercentage = 0f
removeCallbacks(startFadingIndicators) removeCallbacks(startFadingIndicators)
if (redraw) { if (redraw) {
redrawGrid() redrawGrid()
} }
ValueAnimator.ofFloat(1f, 0f) ValueAnimator.ofFloat(startingAt, 0f)
.apply { .apply {
addUpdateListener { addUpdateListener {
pageChangeAnimLeftPercentage = it.animatedValue as Float pageChangeAnimLeftPercentage = it.animatedValue as Float
@ -1112,6 +1123,63 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
} }
} }
private fun isBetweenPages() =
(pageChangeSwipedPercentage > 0f && pageChangeSwipedPercentage < 1f) || (pageChangeAnimLeftPercentage > 0f && pageChangeAnimLeftPercentage < 1f)
private fun getXFactorForCurrentPage(): Float {
return if (abs(pageChangeSwipedPercentage) > 0f) {
pageChangeSwipedPercentage
} else {
if (currentPage > lastPage) {
pageChangeAnimLeftPercentage
} else {
-pageChangeAnimLeftPercentage
}
}
}
private fun getXFactorForLastPage(): Float {
return if (abs(pageChangeSwipedPercentage) > 0f) {
(1 - abs(pageChangeSwipedPercentage)) * -sign(pageChangeSwipedPercentage)
} else {
if (currentPage > lastPage) {
pageChangeAnimLeftPercentage - 1
} else {
1 - pageChangeAnimLeftPercentage
}
}
}
fun setSwipeMovement(diffX: Float) {
if (!pageChangeEnabled) {
return
}
if (currentPage < getMaxPage() && diffX > 0f || currentPage > 0 && diffX < 0f) {
pageChangeSwipedPercentage = (-diffX / width.toFloat()).coerceIn(-1f, 1f)
redrawGrid()
}
}
fun finalizeSwipe() {
if (abs(pageChangeSwipedPercentage) > 0.5f) {
lastPage = currentPage
currentPage = if (pageChangeSwipedPercentage > 0f) {
currentPage - 1
} else {
currentPage + 1
}
handlePageChange(true)
} else {
lastPage = if (pageChangeSwipedPercentage > 0f) {
currentPage - 1
} else {
currentPage + 1
}
handlePageChange(true)
}
}
companion object { companion object {
private const val PAGE_CHANGE_HOLD_THRESHOLD = 500L private const val PAGE_CHANGE_HOLD_THRESHOLD = 500L
private const val PAGE_INDICATORS_FADE_DELAY = PAGE_CHANGE_HOLD_THRESHOLD + 300L private const val PAGE_INDICATORS_FADE_DELAY = PAGE_CHANGE_HOLD_THRESHOLD + 300L