Implement multiple panes for home screen grid

This closes #47
This commit is contained in:
Ensar Sarajčić 2023-07-18 17:34:16 +02:00
parent c5ea727398
commit b0ca17cea2
8 changed files with 103 additions and 19 deletions

View File

@ -50,6 +50,7 @@ import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.activity_main.view.* import kotlinx.android.synthetic.main.activity_main.view.*
import kotlinx.android.synthetic.main.all_apps_fragment.view.* import kotlinx.android.synthetic.main.all_apps_fragment.view.*
import kotlinx.android.synthetic.main.widgets_fragment.view.* import kotlinx.android.synthetic.main.widgets_fragment.view.*
import kotlin.math.abs
class MainActivity : SimpleActivity(), FlingListener { class MainActivity : SimpleActivity(), FlingListener {
private val ANIMATION_DURATION = 150L private val ANIMATION_DURATION = 150L
@ -118,6 +119,7 @@ class MainActivity : SimpleActivity(), FlingListener {
rect.top, rect.top,
rect.right, rect.right,
rect.bottom, rect.bottom,
0,
item.shortcutInfo!!.`package`, item.shortcutInfo!!.`package`,
"", "",
label, label,
@ -641,11 +643,20 @@ class MainActivity : SimpleActivity(), FlingListener {
return true return true
} }
if (velocityY > 0) { if (abs(velocityY) > abs(velocityX)) {
flingListener.onFlingDown() if (velocityY > 0) {
} else { flingListener.onFlingDown()
flingListener.onFlingUp() } else {
flingListener.onFlingUp()
}
} else if (abs(velocityX) > abs(velocityY)) {
if (velocityX > 0) {
flingListener.onFlingRight()
} else {
flingListener.onFlingLeft()
}
} }
return true 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") @SuppressLint("WrongConstant")
fun getAllAppLaunchers(): ArrayList<AppLauncher> { fun getAllAppLaunchers(): ArrayList<AppLauncher> {
val hiddenIcons = hiddenIconsDB.getHiddenIcons().map { val hiddenIcons = hiddenIconsDB.getHiddenIcons().map {
@ -722,7 +741,7 @@ class MainActivity : SimpleActivity(), FlingListener {
val defaultDialerPackage = (getSystemService(Context.TELECOM_SERVICE) as TelecomManager).defaultDialerPackage val defaultDialerPackage = (getSystemService(Context.TELECOM_SERVICE) as TelecomManager).defaultDialerPackage
appLaunchers.firstOrNull { it.packageName == defaultDialerPackage }?.apply { appLaunchers.firstOrNull { it.packageName == defaultDialerPackage }?.apply {
val dialerIcon = 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) homeScreenGridItems.add(dialerIcon)
} }
} catch (e: Exception) { } catch (e: Exception) {
@ -732,7 +751,7 @@ class MainActivity : SimpleActivity(), FlingListener {
val defaultSMSMessengerPackage = Telephony.Sms.getDefaultSmsPackage(this) val defaultSMSMessengerPackage = Telephony.Sms.getDefaultSmsPackage(this)
appLaunchers.firstOrNull { it.packageName == defaultSMSMessengerPackage }?.apply { appLaunchers.firstOrNull { it.packageName == defaultSMSMessengerPackage }?.apply {
val SMSMessengerIcon = 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) homeScreenGridItems.add(SMSMessengerIcon)
} }
} catch (e: Exception) { } catch (e: Exception) {
@ -744,7 +763,7 @@ class MainActivity : SimpleActivity(), FlingListener {
val defaultBrowserPackage = resolveInfo!!.activityInfo.packageName val defaultBrowserPackage = resolveInfo!!.activityInfo.packageName
appLaunchers.firstOrNull { it.packageName == defaultBrowserPackage }?.apply { appLaunchers.firstOrNull { it.packageName == defaultBrowserPackage }?.apply {
val browserIcon = 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) homeScreenGridItems.add(browserIcon)
} }
} catch (e: Exception) { } catch (e: Exception) {
@ -755,7 +774,7 @@ class MainActivity : SimpleActivity(), FlingListener {
val storePackage = potentialStores.firstOrNull { isPackageInstalled(it) && appLaunchers.map { it.packageName }.contains(it) } val storePackage = potentialStores.firstOrNull { isPackageInstalled(it) && appLaunchers.map { it.packageName }.contains(it) }
if (storePackage != null) { if (storePackage != null) {
appLaunchers.firstOrNull { it.packageName == storePackage }?.apply { 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) homeScreenGridItems.add(storeIcon)
} }
} }
@ -768,7 +787,7 @@ class MainActivity : SimpleActivity(), FlingListener {
val defaultCameraPackage = resolveInfo!!.activityInfo.packageName val defaultCameraPackage = resolveInfo!!.activityInfo.packageName
appLaunchers.firstOrNull { it.packageName == defaultCameraPackage }?.apply { appLaunchers.firstOrNull { it.packageName == defaultCameraPackage }?.apply {
val cameraIcon = 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) homeScreenGridItems.add(cameraIcon)
} }
} catch (e: Exception) { } catch (e: Exception) {

View File

@ -15,7 +15,7 @@ import com.simplemobiletools.launcher.models.AppLauncher
import com.simplemobiletools.launcher.models.HiddenIcon import com.simplemobiletools.launcher.models.HiddenIcon
import com.simplemobiletools.launcher.models.HomeScreenGridItem 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) @TypeConverters(Converters::class)
abstract class AppsDatabase : RoomDatabase() { abstract class AppsDatabase : RoomDatabase() {
@ -36,6 +36,7 @@ abstract class AppsDatabase : RoomDatabase() {
.addMigrations(MIGRATION_1_2) .addMigrations(MIGRATION_1_2)
.addMigrations(MIGRATION_2_3) .addMigrations(MIGRATION_2_3)
.addMigrations(MIGRATION_3_4) .addMigrations(MIGRATION_3_4)
.addMigrations(MIGRATION_4_5)
.build() .build()
} }
} }
@ -64,5 +65,11 @@ abstract class AppsDatabase : RoomDatabase() {
database.execSQL("CREATE UNIQUE INDEX `index_hidden_icons_id` ON `hidden_icons` (`id`)") 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")
}
}
} }
} }

View File

@ -198,6 +198,7 @@ class AllAppsFragment(context: Context, attributeSet: AttributeSet) : MyFragment
-1, -1,
-1, -1,
-1, -1,
0,
appLauncher.packageName, appLauncher.packageName,
appLauncher.activityName, appLauncher.activityName,
appLauncher.title, appLauncher.title,

View File

@ -250,6 +250,7 @@ class WidgetsFragment(context: Context, attributeSet: AttributeSet) : MyFragment
-1, -1,
-1, -1,
-1, -1,
0,
appWidget.appPackageName, appWidget.appPackageName,
"", "",
"", "",

View File

@ -4,4 +4,8 @@ interface FlingListener {
fun onFlingUp() fun onFlingUp()
fun onFlingDown() fun onFlingDown()
fun onFlingRight()
fun onFlingLeft()
} }

View File

@ -23,8 +23,8 @@ interface HomeScreenGridItemsDao {
@Query("UPDATE home_screen_grid_items SET title = :title WHERE id = :id") @Query("UPDATE home_screen_grid_items SET title = :title WHERE id = :id")
fun updateItemTitle(title: String, id: Long): Int 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") @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, id: Long) fun updateItemPosition(left: Int, top: Int, right: Int, bottom: Int, page: Int, id: Long)
@Query("DELETE FROM home_screen_grid_items WHERE id = :id") @Query("DELETE FROM home_screen_grid_items WHERE id = :id")
fun deleteById(id: Long) fun deleteById(id: Long)

View File

@ -15,6 +15,7 @@ data class HomeScreenGridItem(
@ColumnInfo(name = "top") var top: Int, @ColumnInfo(name = "top") var top: Int,
@ColumnInfo(name = "right") var right: Int, @ColumnInfo(name = "right") var right: Int,
@ColumnInfo(name = "bottom") var bottom: Int, @ColumnInfo(name = "bottom") var bottom: Int,
@ColumnInfo(name = "page") var page: Int,
@ColumnInfo(name = "package_name") var packageName: String, @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 = "activity_name") var activityName: String, // needed at apps that create multiple icons at install, not just the launcher
@ColumnInfo(name = "title") var title: String, @ColumnInfo(name = "title") var title: String,
@ -31,7 +32,7 @@ data class HomeScreenGridItem(
@Ignore var widthCells: Int = 1, @Ignore var widthCells: Int = 1,
@Ignore var heightCells: 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) { fun getWidthInCells() = if (right == -1 || left == -1) {
widthCells widthCells

View File

@ -13,6 +13,7 @@ import android.text.StaticLayout
import android.text.TextPaint import android.text.TextPaint
import android.text.TextUtils import android.text.TextUtils
import android.util.AttributeSet import android.util.AttributeSet
import android.util.Log
import android.util.Size import android.util.Size
import android.util.SizeF import android.util.SizeF
import android.view.View import android.view.View
@ -51,6 +52,9 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
var cellWidth = 0 var cellWidth = 0
var cellHeight = 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 // 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()
@ -165,6 +169,11 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
} }
draggedItemCurrentCoords = Pair(x, y) draggedItemCurrentCoords = Pair(x, y)
if (x > right - sideMargins.right) {
nextOrAdditionalPage()
} else if (x < left + 2 * sideMargins.left) {
prevPage()
}
redrawGrid() redrawGrid()
} }
@ -210,7 +219,7 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
item.bottom = cellsRect.bottom item.bottom = cellsRect.bottom
updateWidgetPositionAndSize(widgetView, item) updateWidgetPositionAndSize(widgetView, item)
ensureBackgroundThread { 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 // check if the destination cell is empty
var areAllCellsEmpty = true var areAllCellsEmpty = true
val wantedCell = Pair(xIndex, yIndex) val wantedCell = Pair(xIndex, yIndex)
gridItems.forEach { item -> gridItems.filter { it.page == currentPage }.forEach { item ->
for (xCell in item.left..item.right) { for (xCell in item.left..item.right) {
for (yCell in item.top..item.bottom) { for (yCell in item.top..item.bottom) {
val cell = Pair(xCell, yCell) val cell = Pair(xCell, yCell)
@ -272,9 +281,10 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
top = yIndex top = yIndex
right = xIndex right = xIndex
bottom = yIndex bottom = yIndex
page = currentPage
ensureBackgroundThread { ensureBackgroundThread {
context.homeScreenGridItemsDB.updateItemPosition(left, top, right, bottom, id!!) context.homeScreenGridItemsDB.updateItemPosition(left, top, right, bottom, page, id!!)
} }
} }
redrawIcons = true redrawIcons = true
@ -286,6 +296,7 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
yIndex, yIndex,
xIndex, xIndex,
yIndex, yIndex,
currentPage,
draggedItem!!.packageName, draggedItem!!.packageName,
draggedItem!!.activityName, draggedItem!!.activityName,
draggedItem!!.title, draggedItem!!.title,
@ -372,6 +383,7 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
top = widgetRect.top top = widgetRect.top
right = widgetRect.right right = widgetRect.right
bottom = widgetRect.bottom bottom = widgetRect.bottom
page = currentPage
} }
ensureBackgroundThread { ensureBackgroundThread {
@ -383,7 +395,14 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
bindWidget(widgetItem, false) bindWidget(widgetItem, false)
} }
} else { } 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 } val widgetView = widgetViews.firstOrNull { it.tag == widgetItem.widgetId }
if (widgetView != null) { if (widgetView != null) {
post { post {
@ -398,6 +417,7 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
right = widgetItem.right right = widgetItem.right
top = widgetItem.top top = widgetItem.top
bottom = widgetItem.bottom bottom = widgetItem.bottom
page = widgetItem.page
} }
} }
} }
@ -529,7 +549,7 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
fillCellSizes() 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) { if (item.id != draggedItem?.id) {
val drawableX = cellXCoords[item.left] + iconMargin + sideMargins.left val drawableX = cellXCoords[item.left] + iconMargin + sideMargins.left
@ -563,7 +583,7 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
} }
if (isFirstDraw) { 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) 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)
}
} }