From b0ca17cea2f0ed4d7951714267cfecb0826c8c26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ensar=20Saraj=C4=8Di=C4=87?= Date: Tue, 18 Jul 2023 17:34:16 +0200 Subject: [PATCH] Implement multiple panes for home screen grid This closes #47 --- .../launcher/activities/MainActivity.kt | 37 ++++++++--- .../launcher/databases/AppsDatabase.kt | 9 ++- .../launcher/fragments/AllAppsFragment.kt | 1 + .../launcher/fragments/WidgetsFragment.kt | 1 + .../launcher/interfaces/FlingListener.kt | 4 ++ .../interfaces/HomeScreenGridItemsDao.kt | 4 +- .../launcher/models/HomeScreenGridItem.kt | 3 +- .../launcher/views/HomeScreenGrid.kt | 63 +++++++++++++++++-- 8 files changed, 103 insertions(+), 19 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/launcher/activities/MainActivity.kt b/app/src/main/kotlin/com/simplemobiletools/launcher/activities/MainActivity.kt index 0dadc51..c3e9e5b 100644 --- a/app/src/main/kotlin/com/simplemobiletools/launcher/activities/MainActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/launcher/activities/MainActivity.kt @@ -50,6 +50,7 @@ import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.activity_main.view.* import kotlinx.android.synthetic.main.all_apps_fragment.view.* import kotlinx.android.synthetic.main.widgets_fragment.view.* +import kotlin.math.abs class MainActivity : SimpleActivity(), FlingListener { private val ANIMATION_DURATION = 150L @@ -118,6 +119,7 @@ class MainActivity : SimpleActivity(), FlingListener { rect.top, rect.right, rect.bottom, + 0, item.shortcutInfo!!.`package`, "", label, @@ -641,11 +643,20 @@ class MainActivity : SimpleActivity(), FlingListener { return true } - if (velocityY > 0) { - flingListener.onFlingDown() - } else { - flingListener.onFlingUp() + if (abs(velocityY) > abs(velocityX)) { + if (velocityY > 0) { + flingListener.onFlingDown() + } else { + flingListener.onFlingUp() + } + } else if (abs(velocityX) > abs(velocityY)) { + if (velocityX > 0) { + flingListener.onFlingRight() + } else { + flingListener.onFlingLeft() + } } + return true } @@ -676,6 +687,14 @@ class MainActivity : SimpleActivity(), FlingListener { } } + override fun onFlingRight() { + home_screen_grid.prevPage(redraw = true) + } + + override fun onFlingLeft() { + home_screen_grid.nextPage(redraw = true) + } + @SuppressLint("WrongConstant") fun getAllAppLaunchers(): ArrayList { val hiddenIcons = hiddenIconsDB.getHiddenIcons().map { @@ -722,7 +741,7 @@ class MainActivity : SimpleActivity(), FlingListener { val defaultDialerPackage = (getSystemService(Context.TELECOM_SERVICE) as TelecomManager).defaultDialerPackage appLaunchers.firstOrNull { it.packageName == defaultDialerPackage }?.apply { val dialerIcon = - HomeScreenGridItem(null, 0, ROW_COUNT - 1, 0, ROW_COUNT - 1, defaultDialerPackage, "", title, ITEM_TYPE_ICON, "", -1, "", "", null) + HomeScreenGridItem(null, 0, ROW_COUNT - 1, 0, ROW_COUNT - 1, 0, defaultDialerPackage, "", title, ITEM_TYPE_ICON, "", -1, "", "", null) homeScreenGridItems.add(dialerIcon) } } catch (e: Exception) { @@ -732,7 +751,7 @@ class MainActivity : SimpleActivity(), FlingListener { val defaultSMSMessengerPackage = Telephony.Sms.getDefaultSmsPackage(this) appLaunchers.firstOrNull { it.packageName == defaultSMSMessengerPackage }?.apply { val SMSMessengerIcon = - HomeScreenGridItem(null, 1, ROW_COUNT - 1, 1, ROW_COUNT - 1, defaultSMSMessengerPackage, "", title, ITEM_TYPE_ICON, "", -1, "", "", null) + HomeScreenGridItem(null, 1, ROW_COUNT - 1, 1, ROW_COUNT - 1, 0, defaultSMSMessengerPackage, "", title, ITEM_TYPE_ICON, "", -1, "", "", null) homeScreenGridItems.add(SMSMessengerIcon) } } catch (e: Exception) { @@ -744,7 +763,7 @@ class MainActivity : SimpleActivity(), FlingListener { val defaultBrowserPackage = resolveInfo!!.activityInfo.packageName appLaunchers.firstOrNull { it.packageName == defaultBrowserPackage }?.apply { val browserIcon = - HomeScreenGridItem(null, 2, ROW_COUNT - 1, 2, ROW_COUNT - 1, defaultBrowserPackage, "", title, ITEM_TYPE_ICON, "", -1, "", "", null) + HomeScreenGridItem(null, 2, ROW_COUNT - 1, 2, ROW_COUNT - 1, 0, defaultBrowserPackage, "", title, ITEM_TYPE_ICON, "", -1, "", "", null) homeScreenGridItems.add(browserIcon) } } catch (e: Exception) { @@ -755,7 +774,7 @@ class MainActivity : SimpleActivity(), FlingListener { val storePackage = potentialStores.firstOrNull { isPackageInstalled(it) && appLaunchers.map { it.packageName }.contains(it) } if (storePackage != null) { appLaunchers.firstOrNull { it.packageName == storePackage }?.apply { - val storeIcon = HomeScreenGridItem(null, 3, ROW_COUNT - 1, 3, ROW_COUNT - 1, storePackage, "", title, ITEM_TYPE_ICON, "", -1, "", "", null) + val storeIcon = HomeScreenGridItem(null, 3, ROW_COUNT - 1, 3, ROW_COUNT - 1, 0, storePackage, "", title, ITEM_TYPE_ICON, "", -1, "", "", null) homeScreenGridItems.add(storeIcon) } } @@ -768,7 +787,7 @@ class MainActivity : SimpleActivity(), FlingListener { val defaultCameraPackage = resolveInfo!!.activityInfo.packageName appLaunchers.firstOrNull { it.packageName == defaultCameraPackage }?.apply { val cameraIcon = - HomeScreenGridItem(null, 4, ROW_COUNT - 1, 4, ROW_COUNT - 1, defaultCameraPackage, "", title, ITEM_TYPE_ICON, "", -1, "", "", null) + HomeScreenGridItem(null, 4, ROW_COUNT - 1, 4, ROW_COUNT - 1, 0, defaultCameraPackage, "", title, ITEM_TYPE_ICON, "", -1, "", "", null) homeScreenGridItems.add(cameraIcon) } } catch (e: Exception) { diff --git a/app/src/main/kotlin/com/simplemobiletools/launcher/databases/AppsDatabase.kt b/app/src/main/kotlin/com/simplemobiletools/launcher/databases/AppsDatabase.kt index de46cc2..f6e85d9 100644 --- a/app/src/main/kotlin/com/simplemobiletools/launcher/databases/AppsDatabase.kt +++ b/app/src/main/kotlin/com/simplemobiletools/launcher/databases/AppsDatabase.kt @@ -15,7 +15,7 @@ import com.simplemobiletools.launcher.models.AppLauncher import com.simplemobiletools.launcher.models.HiddenIcon import com.simplemobiletools.launcher.models.HomeScreenGridItem -@Database(entities = [AppLauncher::class, HomeScreenGridItem::class, HiddenIcon::class], version = 4) +@Database(entities = [AppLauncher::class, HomeScreenGridItem::class, HiddenIcon::class], version = 5) @TypeConverters(Converters::class) abstract class AppsDatabase : RoomDatabase() { @@ -36,6 +36,7 @@ abstract class AppsDatabase : RoomDatabase() { .addMigrations(MIGRATION_1_2) .addMigrations(MIGRATION_2_3) .addMigrations(MIGRATION_3_4) + .addMigrations(MIGRATION_4_5) .build() } } @@ -64,5 +65,11 @@ abstract class AppsDatabase : RoomDatabase() { database.execSQL("CREATE UNIQUE INDEX `index_hidden_icons_id` ON `hidden_icons` (`id`)") } } + + private val MIGRATION_4_5 = object : Migration(4, 5) { + override fun migrate(database: SupportSQLiteDatabase) { + database.execSQL("ALTER TABLE home_screen_grid_items ADD COLUMN page INTEGER NOT NULL DEFAULT 0") + } + } } } diff --git a/app/src/main/kotlin/com/simplemobiletools/launcher/fragments/AllAppsFragment.kt b/app/src/main/kotlin/com/simplemobiletools/launcher/fragments/AllAppsFragment.kt index fe4a5d5..d4b4214 100644 --- a/app/src/main/kotlin/com/simplemobiletools/launcher/fragments/AllAppsFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/launcher/fragments/AllAppsFragment.kt @@ -198,6 +198,7 @@ class AllAppsFragment(context: Context, attributeSet: AttributeSet) : MyFragment -1, -1, -1, + 0, appLauncher.packageName, appLauncher.activityName, appLauncher.title, diff --git a/app/src/main/kotlin/com/simplemobiletools/launcher/fragments/WidgetsFragment.kt b/app/src/main/kotlin/com/simplemobiletools/launcher/fragments/WidgetsFragment.kt index 189906a..eb6c8ba 100644 --- a/app/src/main/kotlin/com/simplemobiletools/launcher/fragments/WidgetsFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/launcher/fragments/WidgetsFragment.kt @@ -250,6 +250,7 @@ class WidgetsFragment(context: Context, attributeSet: AttributeSet) : MyFragment -1, -1, -1, + 0, appWidget.appPackageName, "", "", diff --git a/app/src/main/kotlin/com/simplemobiletools/launcher/interfaces/FlingListener.kt b/app/src/main/kotlin/com/simplemobiletools/launcher/interfaces/FlingListener.kt index 3b5dd09..b9dd60e 100644 --- a/app/src/main/kotlin/com/simplemobiletools/launcher/interfaces/FlingListener.kt +++ b/app/src/main/kotlin/com/simplemobiletools/launcher/interfaces/FlingListener.kt @@ -4,4 +4,8 @@ interface FlingListener { fun onFlingUp() fun onFlingDown() + + fun onFlingRight() + + fun onFlingLeft() } diff --git a/app/src/main/kotlin/com/simplemobiletools/launcher/interfaces/HomeScreenGridItemsDao.kt b/app/src/main/kotlin/com/simplemobiletools/launcher/interfaces/HomeScreenGridItemsDao.kt index 1eda528..7abd805 100644 --- a/app/src/main/kotlin/com/simplemobiletools/launcher/interfaces/HomeScreenGridItemsDao.kt +++ b/app/src/main/kotlin/com/simplemobiletools/launcher/interfaces/HomeScreenGridItemsDao.kt @@ -23,8 +23,8 @@ interface HomeScreenGridItemsDao { @Query("UPDATE home_screen_grid_items SET title = :title WHERE id = :id") fun updateItemTitle(title: String, id: Long): Int - @Query("UPDATE home_screen_grid_items SET `left` = :left, `top` = :top, `right` = :right, `bottom` = :bottom WHERE id = :id") - fun updateItemPosition(left: Int, top: Int, right: Int, bottom: Int, id: Long) + @Query("UPDATE home_screen_grid_items SET `left` = :left, `top` = :top, `right` = :right, `bottom` = :bottom, `page` = :page WHERE id = :id") + fun updateItemPosition(left: Int, top: Int, right: Int, bottom: Int, page: Int, id: Long) @Query("DELETE FROM home_screen_grid_items WHERE id = :id") fun deleteById(id: Long) diff --git a/app/src/main/kotlin/com/simplemobiletools/launcher/models/HomeScreenGridItem.kt b/app/src/main/kotlin/com/simplemobiletools/launcher/models/HomeScreenGridItem.kt index 935f1ed..0d4b38c 100644 --- a/app/src/main/kotlin/com/simplemobiletools/launcher/models/HomeScreenGridItem.kt +++ b/app/src/main/kotlin/com/simplemobiletools/launcher/models/HomeScreenGridItem.kt @@ -15,6 +15,7 @@ data class HomeScreenGridItem( @ColumnInfo(name = "top") var top: Int, @ColumnInfo(name = "right") var right: Int, @ColumnInfo(name = "bottom") var bottom: Int, + @ColumnInfo(name = "page") var page: Int, @ColumnInfo(name = "package_name") var packageName: String, @ColumnInfo(name = "activity_name") var activityName: String, // needed at apps that create multiple icons at install, not just the launcher @ColumnInfo(name = "title") var title: String, @@ -31,7 +32,7 @@ data class HomeScreenGridItem( @Ignore var widthCells: Int = 1, @Ignore var heightCells: Int = 1 ) { - constructor() : this(null, -1, -1, -1, -1, "", "", "", ITEM_TYPE_ICON, "", -1, "", "", null, null, null, null, 1, 1) + constructor() : this(null, -1, -1, -1, -1, 0, "", "", "", ITEM_TYPE_ICON, "", -1, "", "", null, null, null, null, 1, 1) fun getWidthInCells() = if (right == -1 || left == -1) { widthCells diff --git a/app/src/main/kotlin/com/simplemobiletools/launcher/views/HomeScreenGrid.kt b/app/src/main/kotlin/com/simplemobiletools/launcher/views/HomeScreenGrid.kt index d87a4fd..b98196d 100644 --- a/app/src/main/kotlin/com/simplemobiletools/launcher/views/HomeScreenGrid.kt +++ b/app/src/main/kotlin/com/simplemobiletools/launcher/views/HomeScreenGrid.kt @@ -13,6 +13,7 @@ import android.text.StaticLayout import android.text.TextPaint import android.text.TextUtils import android.util.AttributeSet +import android.util.Log import android.util.Size import android.util.SizeF import android.view.View @@ -51,6 +52,9 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel var cellWidth = 0 var cellHeight = 0 + private var currentPage = 0 + private var pageChangeEnabled = true + // apply fake margins at the home screen. Real ones would cause the icons be cut at dragging at screen sides var sideMargins = Rect() @@ -165,6 +169,11 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel } draggedItemCurrentCoords = Pair(x, y) + if (x > right - sideMargins.right) { + nextOrAdditionalPage() + } else if (x < left + 2 * sideMargins.left) { + prevPage() + } redrawGrid() } @@ -210,7 +219,7 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel item.bottom = cellsRect.bottom updateWidgetPositionAndSize(widgetView, item) ensureBackgroundThread { - context.homeScreenGridItemsDB.updateItemPosition(cellsRect.left, cellsRect.top, cellsRect.right, cellsRect.bottom, item.id!!) + context.homeScreenGridItemsDB.updateItemPosition(cellsRect.left, cellsRect.top, cellsRect.right, cellsRect.bottom, item.page, item.id!!) } } @@ -249,7 +258,7 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel // check if the destination cell is empty var areAllCellsEmpty = true val wantedCell = Pair(xIndex, yIndex) - gridItems.forEach { item -> + gridItems.filter { it.page == currentPage }.forEach { item -> for (xCell in item.left..item.right) { for (yCell in item.top..item.bottom) { val cell = Pair(xCell, yCell) @@ -272,9 +281,10 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel top = yIndex right = xIndex bottom = yIndex + page = currentPage ensureBackgroundThread { - context.homeScreenGridItemsDB.updateItemPosition(left, top, right, bottom, id!!) + context.homeScreenGridItemsDB.updateItemPosition(left, top, right, bottom, page, id!!) } } redrawIcons = true @@ -286,6 +296,7 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel yIndex, xIndex, yIndex, + currentPage, draggedItem!!.packageName, draggedItem!!.activityName, draggedItem!!.title, @@ -372,6 +383,7 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel top = widgetRect.top right = widgetRect.right bottom = widgetRect.bottom + page = currentPage } ensureBackgroundThread { @@ -383,7 +395,14 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel bindWidget(widgetItem, false) } } else { - context.homeScreenGridItemsDB.updateItemPosition(widgetItem.left, widgetItem.top, widgetItem.right, widgetItem.bottom, widgetItem.id!!) + context.homeScreenGridItemsDB.updateItemPosition( + widgetItem.left, + widgetItem.top, + widgetItem.right, + widgetItem.bottom, + currentPage, + widgetItem.id!! + ) val widgetView = widgetViews.firstOrNull { it.tag == widgetItem.widgetId } if (widgetView != null) { post { @@ -398,6 +417,7 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel right = widgetItem.right top = widgetItem.top bottom = widgetItem.bottom + page = widgetItem.page } } } @@ -529,7 +549,7 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel fillCellSizes() } - gridItems.filter { it.drawable != null && it.type == ITEM_TYPE_ICON || it.type == ITEM_TYPE_SHORTCUT }.forEach { item -> + gridItems.filter { (it.drawable != null && it.type == ITEM_TYPE_ICON || it.type == ITEM_TYPE_SHORTCUT) && it.page == currentPage }.forEach { item -> if (item.id != draggedItem?.id) { val drawableX = cellXCoords[item.left] + iconMargin + sideMargins.left @@ -563,7 +583,7 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel } if (isFirstDraw) { - gridItems.filter { it.type == ITEM_TYPE_WIDGET }.forEach { item -> + gridItems.filter { it.type == ITEM_TYPE_WIDGET && it.page == currentPage }.forEach { item -> bindWidget(item, true) } } @@ -771,4 +791,35 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel } } + + private fun getMaxPage() = gridItems.map { it.page }.max() + + private fun nextOrAdditionalPage(redraw: Boolean = false) { + if (currentPage < getMaxPage() + 1 && pageChangeEnabled) { + currentPage++ + handlePageChange(redraw) + } + } + + fun nextPage(redraw: Boolean = false) { + if (currentPage < getMaxPage() && pageChangeEnabled) { + currentPage++ + handlePageChange(redraw) + } + } + + fun prevPage(redraw: Boolean = false) { + if (currentPage > 0 && pageChangeEnabled) { + currentPage-- + handlePageChange(redraw) + } + } + + private fun handlePageChange(redraw: Boolean = false) { + pageChangeEnabled = false + if (redraw) { + redrawGrid() + } + postDelayed({ pageChangeEnabled = true }, 700L) + } }