Implement bottom row docking

This commit is contained in:
Ensar Sarajčić 2023-07-19 17:26:36 +02:00
parent 1c67a8f097
commit 05c9644037
7 changed files with 71 additions and 24 deletions

View File

@ -148,6 +148,7 @@ class MainActivity : SimpleActivity(), FlingListener {
"", "",
shortcutId, shortcutId,
icon.toBitmap(), icon.toBitmap(),
false,
icon icon
) )
@ -764,7 +765,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, config.homeRowCount - 1, 0, config.homeRowCount - 1, 0, defaultDialerPackage, "", title, ITEM_TYPE_ICON, "", -1, "", "", null) HomeScreenGridItem(null, 0, config.homeRowCount - 1, 0, config.homeRowCount - 1, 0, defaultDialerPackage, "", title, ITEM_TYPE_ICON, "", -1, "", "", null, true)
homeScreenGridItems.add(dialerIcon) homeScreenGridItems.add(dialerIcon)
} }
} catch (e: Exception) { } catch (e: Exception) {
@ -774,7 +775,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, config.homeRowCount - 1, 1, config.homeRowCount - 1, 0, defaultSMSMessengerPackage, "", title, ITEM_TYPE_ICON, "", -1, "", "", null) HomeScreenGridItem(null, 1, config.homeRowCount - 1, 1, config.homeRowCount - 1, 0, defaultSMSMessengerPackage, "", title, ITEM_TYPE_ICON, "", -1, "", "", null, true)
homeScreenGridItems.add(SMSMessengerIcon) homeScreenGridItems.add(SMSMessengerIcon)
} }
} catch (e: Exception) { } catch (e: Exception) {
@ -786,7 +787,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, config.homeRowCount - 1, 2, config.homeRowCount - 1, 0, defaultBrowserPackage, "", title, ITEM_TYPE_ICON, "", -1, "", "", null) HomeScreenGridItem(null, 2, config.homeRowCount - 1, 2, config.homeRowCount - 1, 0, defaultBrowserPackage, "", title, ITEM_TYPE_ICON, "", -1, "", "", null, true)
homeScreenGridItems.add(browserIcon) homeScreenGridItems.add(browserIcon)
} }
} catch (e: Exception) { } catch (e: Exception) {
@ -797,7 +798,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, config.homeRowCount - 1, 3, config.homeRowCount - 1, 0, storePackage, "", title, ITEM_TYPE_ICON, "", -1, "", "", null) val storeIcon = HomeScreenGridItem(null, 3, config.homeRowCount - 1, 3, config.homeRowCount - 1, 0, storePackage, "", title, ITEM_TYPE_ICON, "", -1, "", "", null, true)
homeScreenGridItems.add(storeIcon) homeScreenGridItems.add(storeIcon)
} }
} }
@ -810,7 +811,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, config.homeRowCount - 1, 4, config.homeRowCount - 1, 0, defaultCameraPackage, "", title, ITEM_TYPE_ICON, "", -1, "", "", null) HomeScreenGridItem(null, 4, config.homeRowCount - 1, 4, config.homeRowCount - 1, 0, defaultCameraPackage, "", title, ITEM_TYPE_ICON, "", -1, "", "", null, true)
homeScreenGridItems.add(cameraIcon) homeScreenGridItems.add(cameraIcon)
} }
} catch (e: Exception) { } catch (e: Exception) {

View File

@ -7,6 +7,7 @@ import androidx.room.RoomDatabase
import androidx.room.TypeConverters import androidx.room.TypeConverters
import androidx.room.migration.Migration import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase import androidx.sqlite.db.SupportSQLiteDatabase
import com.simplemobiletools.launcher.extensions.config
import com.simplemobiletools.launcher.helpers.Converters import com.simplemobiletools.launcher.helpers.Converters
import com.simplemobiletools.launcher.interfaces.AppLaunchersDao import com.simplemobiletools.launcher.interfaces.AppLaunchersDao
import com.simplemobiletools.launcher.interfaces.HiddenIconsDao import com.simplemobiletools.launcher.interfaces.HiddenIconsDao
@ -15,7 +16,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 = 5) @Database(entities = [AppLauncher::class, HomeScreenGridItem::class, HiddenIcon::class], version = 6)
@TypeConverters(Converters::class) @TypeConverters(Converters::class)
abstract class AppsDatabase : RoomDatabase() { abstract class AppsDatabase : RoomDatabase() {
@ -37,6 +38,7 @@ abstract class AppsDatabase : RoomDatabase() {
.addMigrations(MIGRATION_2_3) .addMigrations(MIGRATION_2_3)
.addMigrations(MIGRATION_3_4) .addMigrations(MIGRATION_3_4)
.addMigrations(MIGRATION_4_5) .addMigrations(MIGRATION_4_5)
.addMigrations(MIGRATION_5_6.withContext(context))
.build() .build()
} }
} }
@ -71,5 +73,14 @@ abstract class AppsDatabase : RoomDatabase() {
database.execSQL("ALTER TABLE home_screen_grid_items ADD COLUMN page INTEGER NOT NULL DEFAULT 0") database.execSQL("ALTER TABLE home_screen_grid_items ADD COLUMN page INTEGER NOT NULL DEFAULT 0")
} }
} }
private val MIGRATION_5_6 = object {
fun withContext(context: Context) = object : Migration(5, 6) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE home_screen_grid_items ADD COLUMN docked INTEGER NOT NULL DEFAULT 0")
database.execSQL("UPDATE home_screen_grid_items SET docked = 1 WHERE page = 0 AND type != 1 AND top = ?", arrayOf(context.config.homeRowCount - 1))
}
}
}
} }
} }

View File

@ -208,6 +208,7 @@ class AllAppsFragment(context: Context, attributeSet: AttributeSet) : MyFragment
"", "",
"", "",
null, null,
false,
appLauncher.drawable appLauncher.drawable
) )

View File

@ -266,6 +266,7 @@ class WidgetsFragment(context: Context, attributeSet: AttributeSet) : MyFragment
"", "",
"", "",
null, null,
false,
appWidget.widgetPreviewImage, appWidget.widgetPreviewImage,
appWidget.providerInfo, appWidget.providerInfo,
appWidget.activityInfo, appWidget.activityInfo,

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, `page` = :page WHERE id = :id") @Query("UPDATE home_screen_grid_items SET `left` = :left, `top` = :top, `right` = :right, `bottom` = :bottom, `page` = :page, `docked` = :docked WHERE id = :id")
fun updateItemPosition(left: Int, top: Int, right: Int, bottom: Int, page: Int, id: Long) fun updateItemPosition(left: Int, top: Int, right: Int, bottom: Int, page: Int, docked: Boolean, 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

@ -25,6 +25,7 @@ data class HomeScreenGridItem(
@ColumnInfo(name = "intent") var intent: String, // used at static and dynamic shortcuts on click @ColumnInfo(name = "intent") var intent: String, // used at static and dynamic shortcuts on click
@ColumnInfo(name = "shortcut_id") var shortcutId: String, // used at pinned shortcuts at startLauncher call @ColumnInfo(name = "shortcut_id") var shortcutId: String, // used at pinned shortcuts at startLauncher call
@ColumnInfo(name = "icon") var icon: Bitmap? = null, // store images of pinned shortcuts, those cannot be retrieved after creating @ColumnInfo(name = "icon") var icon: Bitmap? = null, // store images of pinned shortcuts, those cannot be retrieved after creating
@ColumnInfo(name = "docked") var docked: Boolean = false, // special flag, meaning that page, top and bottom don't matter for this item, it is always at the bottom of the screen
@Ignore var drawable: Drawable? = null, @Ignore var drawable: Drawable? = null,
@Ignore var providerInfo: AppWidgetProviderInfo? = null, // used at widgets @Ignore var providerInfo: AppWidgetProviderInfo? = null, // used at widgets
@ -32,7 +33,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, 0, "", "", "", ITEM_TYPE_ICON, "", -1, "", "", null, null, null, null, 1, 1) constructor() : this(null, -1, -1, -1, -1, 0, "", "", "", ITEM_TYPE_ICON, "", -1, "", "", null, false, null, null, null, 1, 1)
fun getWidthInCells() = if (right == -1 || left == -1) { fun getWidthInCells() = if (right == -1 || left == -1) {
widthCells widthCells
@ -46,5 +47,21 @@ data class HomeScreenGridItem(
bottom - top + 1 bottom - top + 1
} }
fun getDockAdjustedTop(rowCount: Int): Int {
return if (!docked) {
top
} else {
rowCount - 1
}
}
fun getDockAdjustedBottom(rowCount: Int): Int {
return if (!docked) {
bottom
} else {
rowCount - 1
}
}
fun getItemIdentifier() = "$packageName/$activityName" fun getItemIdentifier() = "$packageName/$activityName"
} }

View File

@ -272,7 +272,7 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
} }
updateWidgetPositionAndSize(widgetView, item) updateWidgetPositionAndSize(widgetView, item)
ensureBackgroundThread { ensureBackgroundThread {
context.homeScreenGridItemsDB.updateItemPosition(item.left, item.top, item.right, item.bottom, item.page, item.id!!) context.homeScreenGridItemsDB.updateItemPosition(item.left, item.top, item.right, item.bottom, item.page, false, item.id!!)
} }
} }
@ -311,9 +311,9 @@ 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.filter { it.page == currentPage }.forEach { item -> gridItems.filter { it.page == currentPage || it.docked }.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.getDockAdjustedTop(rowCount)..item.getDockAdjustedBottom(rowCount)) {
val cell = Pair(xCell, yCell) val cell = Pair(xCell, yCell)
val isAnyCellOccupied = wantedCell == cell val isAnyCellOccupied = wantedCell == cell
if (isAnyCellOccupied) { if (isAnyCellOccupied) {
@ -335,9 +335,10 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
right = xIndex right = xIndex
bottom = yIndex bottom = yIndex
page = currentPage page = currentPage
docked = yIndex == rowCount - 1
ensureBackgroundThread { ensureBackgroundThread {
context.homeScreenGridItemsDB.updateItemPosition(left, top, right, bottom, page, id!!) context.homeScreenGridItemsDB.updateItemPosition(left, top, right, bottom, page, docked, id!!)
} }
} }
redrawIcons = true redrawIcons = true
@ -359,6 +360,7 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
"", "",
"", "",
draggedItem!!.icon, draggedItem!!.icon,
yIndex == rowCount - 1,
draggedItem!!.drawable, draggedItem!!.drawable,
draggedItem!!.providerInfo, draggedItem!!.providerInfo,
draggedItem!!.activityInfo draggedItem!!.activityInfo
@ -416,9 +418,9 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
} }
var areAllCellsEmpty = true var areAllCellsEmpty = true
gridItems.filter { it.id != draggedItem?.id && it.page == currentPage }.forEach { item -> gridItems.filter { it.id != draggedItem?.id && (it.page == currentPage || it.docked) }.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.getDockAdjustedTop(rowCount)..item.getDockAdjustedBottom(rowCount)) {
val cell = Pair(xCell, yCell) val cell = Pair(xCell, yCell)
val isAnyCellOccupied = widgetTargetCells.contains(cell) val isAnyCellOccupied = widgetTargetCells.contains(cell)
if (isAnyCellOccupied) { if (isAnyCellOccupied) {
@ -454,6 +456,7 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
widgetItem.right, widgetItem.right,
widgetItem.bottom, widgetItem.bottom,
currentPage, currentPage,
false,
widgetItem.id!! widgetItem.id!!
) )
val widgetView = widgetViews.firstOrNull { it.tag == widgetItem.widgetId } val widgetView = widgetViews.firstOrNull { it.tag == widgetItem.widgetId }
@ -636,8 +639,8 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
if (item.id != draggedItem?.id) { if (item.id != draggedItem?.id) {
val drawableX = cellXCoords[item.left] + iconMargin + extraXMargin + sideMargins.left + (width * xFactor).toInt() val drawableX = cellXCoords[item.left] + iconMargin + extraXMargin + sideMargins.left + (width * xFactor).toInt()
if (item.top == rowCount - 1) { if (item.docked) {
val drawableY = cellYCoords[item.top] + cellHeight - iconMargin - iconSize + sideMargins.top val drawableY = cellYCoords[rowCount - 1] + cellHeight - iconMargin - iconSize + sideMargins.top
item.drawable!!.setBounds(drawableX, drawableY, drawableX + iconSize, drawableY + iconSize) item.drawable!!.setBounds(drawableX, drawableY, drawableX + iconSize, drawableY + iconSize)
} else { } else {
@ -665,15 +668,26 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
} }
} }
gridItems.filter { (it.drawable != null && it.type == ITEM_TYPE_ICON || it.type == ITEM_TYPE_SHORTCUT) && it.page == currentPage }.forEach { item -> gridItems.filter { (it.drawable != null && it.type == ITEM_TYPE_ICON || it.type == ITEM_TYPE_SHORTCUT) && it.page == currentPage && !it.docked }.forEach { item ->
if (item.outOfBounds()) { if (item.outOfBounds()) {
return@forEach return@forEach
} }
handleDrawing(item, currentXFactor) handleDrawing(item, currentXFactor)
} }
gridItems.filter { (it.drawable != null && it.type == ITEM_TYPE_ICON || it.type == ITEM_TYPE_SHORTCUT) && it.docked }.forEach { item ->
if (item.outOfBounds()) {
return@forEach
}
handleDrawing(item, 0f)
}
if (pageChangeAnimLeftPercentage > 0f && pageChangeAnimLeftPercentage < 1f) { if (pageChangeAnimLeftPercentage > 0f && pageChangeAnimLeftPercentage < 1f) {
gridItems.filter { (it.drawable != null && it.type == ITEM_TYPE_ICON || it.type == ITEM_TYPE_SHORTCUT) && it.page == lastPage }.forEach { item -> gridItems.filter { (it.drawable != null && it.type == ITEM_TYPE_ICON || it.type == ITEM_TYPE_SHORTCUT) && it.page == lastPage && !it.docked }.forEach { item ->
if (item.outOfBounds()) {
return@forEach
}
handleDrawing(item, lastXFactor) handleDrawing(item, lastXFactor)
} }
} }
@ -799,8 +813,8 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
} }
val clickableLeft = cellXCoords[item.left] + sideMargins.left + extraXMargin val clickableLeft = cellXCoords[item.left] + sideMargins.left + extraXMargin
val clickableTop = if (item.top == rowCount - 1) { val clickableTop = if (item.docked) {
cellYCoords[item.top] + cellHeight - iconSize - iconMargin cellYCoords[item.getDockAdjustedTop(rowCount)] + cellHeight - iconSize - iconMargin
} else { } else {
cellYCoords[item.top] - iconMargin + extraYMargin cellYCoords[item.top] - iconMargin + extraYMargin
} + sideMargins.top } + sideMargins.top
@ -833,7 +847,7 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
} }
fun isClickingGridItem(x: Int, y: Int): HomeScreenGridItem? { fun isClickingGridItem(x: Int, y: Int): HomeScreenGridItem? {
for (gridItem in gridItems.filter { it.page == currentPage }) { for (gridItem in gridItems.filter { it.page == currentPage || it.docked }) {
if (gridItem.outOfBounds()) { if (gridItem.outOfBounds()) {
continue continue
} }
@ -867,7 +881,7 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
} }
private fun HomeScreenGridItem.outOfBounds(): Boolean { private fun HomeScreenGridItem.outOfBounds(): Boolean {
return (left >= cellXCoords.size || right >= cellXCoords.size || top >= cellYCoords.size || bottom >= cellYCoords.size) return (left >= cellXCoords.size || right >= cellXCoords.size || (!docked && (top >= cellYCoords.size - 1 || bottom >= cellYCoords.size - 1)))
} }
private inner class HomeScreenGridTouchHelper(host: View) : ExploreByTouchHelper(host) { private inner class HomeScreenGridTouchHelper(host: View) : ExploreByTouchHelper(host) {
@ -882,7 +896,9 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
} }
override fun getVisibleVirtualViews(virtualViewIds: MutableList<Int>?) { override fun getVisibleVirtualViews(virtualViewIds: MutableList<Int>?) {
val sorted = gridItems.sortedBy { it.top * 100 + it.left } val sorted = gridItems.sortedBy {
it.getDockAdjustedTop(rowCount) * 100 + it.left
}
sorted.forEachIndexed { index, homeScreenGridItem -> sorted.forEachIndexed { index, homeScreenGridItem ->
virtualViewIds?.add(index, homeScreenGridItem.id?.toInt() ?: index) virtualViewIds?.add(index, homeScreenGridItem.id?.toInt() ?: index)
} }