Merge pull request #103 from esensar/feature/folders
Add support for folders on home screen
This commit is contained in:
commit
f25738a40f
16 changed files with 1246 additions and 346 deletions
|
@ -5,6 +5,7 @@ import android.content.pm.PackageManager
|
|||
import android.os.Bundle
|
||||
import com.simplemobiletools.commons.extensions.beVisibleIf
|
||||
import com.simplemobiletools.commons.extensions.normalizeString
|
||||
import com.simplemobiletools.commons.extensions.viewBinding
|
||||
import com.simplemobiletools.commons.helpers.NavigationIcon
|
||||
import com.simplemobiletools.commons.helpers.ensureBackgroundThread
|
||||
import com.simplemobiletools.commons.interfaces.RefreshRecyclerViewListener
|
||||
|
@ -17,12 +18,11 @@ import com.simplemobiletools.launcher.extensions.hiddenIconsDB
|
|||
import com.simplemobiletools.launcher.models.HiddenIcon
|
||||
|
||||
class HiddenIconsActivity : SimpleActivity(), RefreshRecyclerViewListener {
|
||||
private lateinit var binding: ActivityHiddenIconsBinding
|
||||
private val binding by viewBinding(ActivityHiddenIconsBinding::inflate)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
isMaterialActivity = true
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = ActivityHiddenIconsBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
updateIcons()
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ import com.simplemobiletools.launcher.extensions.*
|
|||
import com.simplemobiletools.launcher.fragments.MyFragment
|
||||
import com.simplemobiletools.launcher.helpers.*
|
||||
import com.simplemobiletools.launcher.interfaces.FlingListener
|
||||
import com.simplemobiletools.launcher.interfaces.ItemMenuListener
|
||||
import com.simplemobiletools.launcher.models.AppLauncher
|
||||
import com.simplemobiletools.launcher.models.HiddenIcon
|
||||
import com.simplemobiletools.launcher.models.HomeScreenGridItem
|
||||
|
@ -72,7 +73,7 @@ class MainActivity : SimpleActivity(), FlingListener {
|
|||
private var wasJustPaused: Boolean = false
|
||||
|
||||
private lateinit var mDetector: GestureDetectorCompat
|
||||
private lateinit var binding: ActivityMainBinding
|
||||
private val binding by viewBinding(ActivityMainBinding::inflate)
|
||||
|
||||
companion object {
|
||||
private var mLastUpEvent = 0L
|
||||
|
@ -84,7 +85,6 @@ class MainActivity : SimpleActivity(), FlingListener {
|
|||
useDynamicTheme = false
|
||||
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = ActivityMainBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
appLaunched(BuildConfig.APPLICATION_ID)
|
||||
|
||||
|
@ -132,79 +132,6 @@ class MainActivity : SimpleActivity(), FlingListener {
|
|||
}
|
||||
}
|
||||
|
||||
private fun handleIntentAction(intent: Intent) {
|
||||
if (intent.action == LauncherApps.ACTION_CONFIRM_PIN_SHORTCUT) {
|
||||
val launcherApps = applicationContext.getSystemService(Context.LAUNCHER_APPS_SERVICE) as LauncherApps
|
||||
val item = launcherApps.getPinItemRequest(intent)
|
||||
if (item.shortcutInfo == null) {
|
||||
return
|
||||
}
|
||||
|
||||
ensureBackgroundThread {
|
||||
val shortcutId = item.shortcutInfo?.id!!
|
||||
val label = item.shortcutInfo?.shortLabel?.toString() ?: item.shortcutInfo?.longLabel?.toString() ?: ""
|
||||
val icon = launcherApps.getShortcutIconDrawable(item.shortcutInfo!!, resources.displayMetrics.densityDpi)
|
||||
val (page, rect) = findFirstEmptyCell()
|
||||
val gridItem = HomeScreenGridItem(
|
||||
null,
|
||||
rect.left,
|
||||
rect.top,
|
||||
rect.right,
|
||||
rect.bottom,
|
||||
page,
|
||||
item.shortcutInfo!!.`package`,
|
||||
"",
|
||||
label,
|
||||
ITEM_TYPE_SHORTCUT,
|
||||
"",
|
||||
-1,
|
||||
shortcutId,
|
||||
icon.toBitmap(),
|
||||
false,
|
||||
icon
|
||||
)
|
||||
|
||||
runOnUiThread {
|
||||
binding.homeScreenGrid.root.skipToPage(page)
|
||||
}
|
||||
// delay showing the shortcut both to let the user see adding it in realtime and hackily avoid concurrent modification exception at HomeScreenGrid
|
||||
Thread.sleep(2000)
|
||||
|
||||
try {
|
||||
item.accept()
|
||||
binding.homeScreenGrid.root.storeAndShowGridItem(gridItem)
|
||||
} catch (ignored: IllegalStateException) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun findFirstEmptyCell(): Pair<Int, Rect> {
|
||||
val gridItems = homeScreenGridItemsDB.getAllItems() as ArrayList<HomeScreenGridItem>
|
||||
val maxPage = gridItems.map { it.page }.max()
|
||||
val occupiedCells = ArrayList<Triple<Int, Int, Int>>()
|
||||
gridItems.forEach { item ->
|
||||
for (xCell in item.left..item.right) {
|
||||
for (yCell in item.top..item.bottom) {
|
||||
occupiedCells.add(Triple(item.page, xCell, yCell))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (page in 0 until maxPage) {
|
||||
for (checkedYCell in 0 until config.homeColumnCount) {
|
||||
for (checkedXCell in 0 until config.homeRowCount - 1) {
|
||||
val wantedCell = Triple(page, checkedXCell, checkedYCell)
|
||||
if (!occupiedCells.contains(wantedCell)) {
|
||||
return Pair(page, Rect(wantedCell.second, wantedCell.third, wantedCell.second, wantedCell.third))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Pair(maxPage + 1, Rect(0, 0, 0, 0))
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
binding.homeScreenGrid.root.appWidgetHost.startListening()
|
||||
|
@ -256,12 +183,13 @@ class MainActivity : SimpleActivity(), FlingListener {
|
|||
newRowCount = config.homeRowCount,
|
||||
newColumnCount = config.homeColumnCount
|
||||
)
|
||||
binding.homeScreenGrid.root.updateColors()
|
||||
binding.allAppsFragment.root.onResume()
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
binding.homeScreenGrid.root.appWidgetHost?.stopListening()
|
||||
binding.homeScreenGrid.root.appWidgetHost.stopListening()
|
||||
wasJustPaused = false
|
||||
}
|
||||
|
||||
|
@ -351,7 +279,7 @@ class MainActivity : SimpleActivity(), FlingListener {
|
|||
hasFingerMoved(event)
|
||||
}
|
||||
|
||||
if (mLongPressedIcon != null && mOpenPopupMenu != null && hasFingerMoved) {
|
||||
if (mLongPressedIcon != null && (mOpenPopupMenu != null) && hasFingerMoved) {
|
||||
mOpenPopupMenu?.dismiss()
|
||||
mOpenPopupMenu = null
|
||||
binding.homeScreenGrid.root.itemDraggingStarted(mLongPressedIcon!!)
|
||||
|
@ -422,6 +350,80 @@ class MainActivity : SimpleActivity(), FlingListener {
|
|||
return true
|
||||
}
|
||||
|
||||
private fun handleIntentAction(intent: Intent) {
|
||||
if (intent.action == LauncherApps.ACTION_CONFIRM_PIN_SHORTCUT) {
|
||||
val launcherApps = applicationContext.getSystemService(Context.LAUNCHER_APPS_SERVICE) as LauncherApps
|
||||
val item = launcherApps.getPinItemRequest(intent)
|
||||
if (item.shortcutInfo == null) {
|
||||
return
|
||||
}
|
||||
|
||||
ensureBackgroundThread {
|
||||
val shortcutId = item.shortcutInfo?.id!!
|
||||
val label = item.shortcutInfo?.shortLabel?.toString() ?: item.shortcutInfo?.longLabel?.toString() ?: ""
|
||||
val icon = launcherApps.getShortcutIconDrawable(item.shortcutInfo!!, resources.displayMetrics.densityDpi)
|
||||
val (page, rect) = findFirstEmptyCell()
|
||||
val gridItem = HomeScreenGridItem(
|
||||
null,
|
||||
rect.left,
|
||||
rect.top,
|
||||
rect.right,
|
||||
rect.bottom,
|
||||
page,
|
||||
item.shortcutInfo!!.`package`,
|
||||
"",
|
||||
label,
|
||||
ITEM_TYPE_SHORTCUT,
|
||||
"",
|
||||
-1,
|
||||
shortcutId,
|
||||
icon.toBitmap(),
|
||||
false,
|
||||
null,
|
||||
icon
|
||||
)
|
||||
|
||||
runOnUiThread {
|
||||
binding.homeScreenGrid.root.skipToPage(page)
|
||||
}
|
||||
// delay showing the shortcut both to let the user see adding it in realtime and hackily avoid concurrent modification exception at HomeScreenGrid
|
||||
Thread.sleep(2000)
|
||||
|
||||
try {
|
||||
item.accept()
|
||||
binding.homeScreenGrid.root.storeAndShowGridItem(gridItem)
|
||||
} catch (ignored: IllegalStateException) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun findFirstEmptyCell(): Pair<Int, Rect> {
|
||||
val gridItems = homeScreenGridItemsDB.getAllItems() as ArrayList<HomeScreenGridItem>
|
||||
val maxPage = gridItems.map { it.page }.max()
|
||||
val occupiedCells = ArrayList<Triple<Int, Int, Int>>()
|
||||
gridItems.forEach { item ->
|
||||
for (xCell in item.left..item.right) {
|
||||
for (yCell in item.top..item.bottom) {
|
||||
occupiedCells.add(Triple(item.page, xCell, yCell))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (page in 0 until maxPage) {
|
||||
for (checkedYCell in 0 until config.homeColumnCount) {
|
||||
for (checkedXCell in 0 until config.homeRowCount - 1) {
|
||||
val wantedCell = Triple(page, checkedXCell, checkedYCell)
|
||||
if (!occupiedCells.contains(wantedCell)) {
|
||||
return Pair(page, Rect(wantedCell.second, wantedCell.third, wantedCell.second, wantedCell.third))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Pair(maxPage + 1, Rect(0, 0, 0, 0))
|
||||
}
|
||||
|
||||
// some devices ACTION_MOVE keeps triggering for the whole long press duration, but we are interested in real moves only, when coords change
|
||||
private fun hasFingerMoved(event: MotionEvent) = mTouchDownX != -1 && mTouchDownY != -1 &&
|
||||
((Math.abs(mTouchDownX - event.x) > mMoveGestureThreshold) || (Math.abs(mTouchDownY - event.y) > mMoveGestureThreshold))
|
||||
|
@ -524,6 +526,9 @@ class MainActivity : SimpleActivity(), FlingListener {
|
|||
if (clickedGridItem != null) {
|
||||
performItemClick(clickedGridItem)
|
||||
}
|
||||
if (clickedGridItem?.type != ITEM_TYPE_FOLDER) {
|
||||
binding.homeScreenGrid.root.closeFolder(redraw = true)
|
||||
}
|
||||
}
|
||||
|
||||
fun closeAppDrawer(delayed: Boolean = false) {
|
||||
|
@ -559,20 +564,26 @@ class MainActivity : SimpleActivity(), FlingListener {
|
|||
}
|
||||
|
||||
private fun performItemClick(clickedGridItem: HomeScreenGridItem) {
|
||||
if (clickedGridItem.type == ITEM_TYPE_ICON) {
|
||||
launchApp(clickedGridItem.packageName, clickedGridItem.activityName)
|
||||
} else if (clickedGridItem.type == ITEM_TYPE_SHORTCUT) {
|
||||
val id = clickedGridItem.shortcutId
|
||||
val packageName = clickedGridItem.packageName
|
||||
val userHandle = android.os.Process.myUserHandle()
|
||||
val shortcutBounds = binding.homeScreenGrid.root.getClickableRect(clickedGridItem)
|
||||
val launcherApps = applicationContext.getSystemService(Context.LAUNCHER_APPS_SERVICE) as LauncherApps
|
||||
launcherApps.startShortcut(packageName, id, shortcutBounds, null, userHandle)
|
||||
when (clickedGridItem.type) {
|
||||
ITEM_TYPE_ICON -> launchApp(clickedGridItem.packageName, clickedGridItem.activityName)
|
||||
ITEM_TYPE_FOLDER -> openFolder(clickedGridItem)
|
||||
ITEM_TYPE_SHORTCUT -> {
|
||||
val id = clickedGridItem.shortcutId
|
||||
val packageName = clickedGridItem.packageName
|
||||
val userHandle = android.os.Process.myUserHandle()
|
||||
val shortcutBounds = binding.homeScreenGrid.root.getClickableRect(clickedGridItem)
|
||||
val launcherApps = applicationContext.getSystemService(Context.LAUNCHER_APPS_SERVICE) as LauncherApps
|
||||
launcherApps.startShortcut(packageName, id, shortcutBounds, null, userHandle)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun openFolder(folder: HomeScreenGridItem) {
|
||||
binding.homeScreenGrid.root.openFolder(folder)
|
||||
}
|
||||
|
||||
private fun performItemLongClick(x: Float, clickedGridItem: HomeScreenGridItem) {
|
||||
if (clickedGridItem.type == ITEM_TYPE_ICON || clickedGridItem.type == ITEM_TYPE_SHORTCUT) {
|
||||
if (clickedGridItem.type == ITEM_TYPE_ICON || clickedGridItem.type == ITEM_TYPE_SHORTCUT || clickedGridItem.type == ITEM_TYPE_FOLDER) {
|
||||
binding.mainHolder.performHapticFeedback()
|
||||
}
|
||||
|
||||
|
@ -595,7 +606,7 @@ class MainActivity : SimpleActivity(), FlingListener {
|
|||
binding.homeScreenPopupMenuAnchor.y = anchorY
|
||||
|
||||
if (mOpenPopupMenu == null) {
|
||||
mOpenPopupMenu = handleGridItemPopupMenu(binding.homeScreenPopupMenuAnchor, gridItem, isOnAllAppsFragment)
|
||||
mOpenPopupMenu = handleGridItemPopupMenu(binding.homeScreenPopupMenuAnchor, gridItem, isOnAllAppsFragment, menuListener)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -623,52 +634,6 @@ class MainActivity : SimpleActivity(), FlingListener {
|
|||
}
|
||||
}
|
||||
|
||||
private fun handleGridItemPopupMenu(anchorView: View, gridItem: HomeScreenGridItem, isOnAllAppsFragment: Boolean): PopupMenu {
|
||||
|
||||
val contextTheme = ContextThemeWrapper(this, getPopupMenuTheme())
|
||||
return PopupMenu(contextTheme, anchorView, Gravity.TOP or Gravity.END).apply {
|
||||
if (isQPlus()) {
|
||||
setForceShowIcon(true)
|
||||
}
|
||||
|
||||
inflate(R.menu.menu_app_icon)
|
||||
menu.findItem(R.id.rename).isVisible = gridItem.type == ITEM_TYPE_ICON && !isOnAllAppsFragment
|
||||
menu.findItem(R.id.hide_icon).isVisible = gridItem.type == ITEM_TYPE_ICON && isOnAllAppsFragment
|
||||
menu.findItem(R.id.resize).isVisible = gridItem.type == ITEM_TYPE_WIDGET
|
||||
menu.findItem(R.id.app_info).isVisible = gridItem.type == ITEM_TYPE_ICON
|
||||
menu.findItem(R.id.uninstall).isVisible = gridItem.type == ITEM_TYPE_ICON && canAppBeUninstalled(gridItem.packageName)
|
||||
menu.findItem(R.id.remove).isVisible = !isOnAllAppsFragment
|
||||
setOnMenuItemClickListener { item ->
|
||||
resetFragmentTouches()
|
||||
when (item.itemId) {
|
||||
R.id.hide_icon -> hideIcon(gridItem)
|
||||
R.id.rename -> renameItem(gridItem)
|
||||
R.id.resize -> binding.homeScreenGrid.root.widgetLongPressed(gridItem)
|
||||
R.id.app_info -> launchAppInfo(gridItem.packageName)
|
||||
R.id.remove -> binding.homeScreenGrid.root.removeAppIcon(gridItem)
|
||||
R.id.uninstall -> uninstallApp(gridItem.packageName)
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
setOnDismissListener {
|
||||
mOpenPopupMenu = null
|
||||
resetFragmentTouches()
|
||||
}
|
||||
|
||||
var visibleMenuItems = 0
|
||||
for (item in menu.iterator()) {
|
||||
if (item.isVisible) {
|
||||
visibleMenuItems++
|
||||
}
|
||||
}
|
||||
val yOffset = resources.getDimension(R.dimen.long_press_anchor_button_offset_y) * (visibleMenuItems - 1)
|
||||
anchorView.y -= yOffset
|
||||
|
||||
show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun resetFragmentTouches() {
|
||||
binding.widgetsFragment.root.apply {
|
||||
touchDownY = -1
|
||||
|
@ -714,6 +679,53 @@ class MainActivity : SimpleActivity(), FlingListener {
|
|||
}
|
||||
}
|
||||
|
||||
val menuListener: ItemMenuListener = object : ItemMenuListener {
|
||||
override fun onAnyClick() {
|
||||
resetFragmentTouches()
|
||||
}
|
||||
|
||||
override fun hide(gridItem: HomeScreenGridItem) {
|
||||
hideIcon(gridItem)
|
||||
}
|
||||
|
||||
override fun rename(gridItem: HomeScreenGridItem) {
|
||||
renameItem(gridItem)
|
||||
}
|
||||
|
||||
override fun resize(gridItem: HomeScreenGridItem) {
|
||||
binding.homeScreenGrid.root.widgetLongPressed(gridItem)
|
||||
}
|
||||
|
||||
override fun appInfo(gridItem: HomeScreenGridItem) {
|
||||
launchAppInfo(gridItem.packageName)
|
||||
}
|
||||
|
||||
override fun remove(gridItem: HomeScreenGridItem) {
|
||||
binding.homeScreenGrid.root.removeAppIcon(gridItem)
|
||||
}
|
||||
|
||||
override fun uninstall(gridItem: HomeScreenGridItem) {
|
||||
uninstallApp(gridItem.packageName)
|
||||
}
|
||||
|
||||
override fun onDismiss() {
|
||||
mOpenPopupMenu = null
|
||||
resetFragmentTouches()
|
||||
}
|
||||
|
||||
override fun beforeShow(menu: Menu) {
|
||||
var visibleMenuItems = 0
|
||||
for (item in menu.iterator()) {
|
||||
if (item.isVisible) {
|
||||
visibleMenuItems++
|
||||
}
|
||||
}
|
||||
val yOffset = resources.getDimension(R.dimen.long_press_anchor_button_offset_y) * (visibleMenuItems - 1)
|
||||
binding.homeScreenPopupMenuAnchor.y -= yOffset
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class MyGestureListener(private val flingListener: FlingListener) : GestureDetector.SimpleOnGestureListener() {
|
||||
override fun onSingleTapUp(event: MotionEvent): Boolean {
|
||||
(flingListener as MainActivity).homeScreenClicked(event.x, event.y)
|
||||
|
@ -857,7 +869,8 @@ class MainActivity : SimpleActivity(), FlingListener {
|
|||
-1,
|
||||
"",
|
||||
null,
|
||||
true
|
||||
true,
|
||||
null
|
||||
)
|
||||
homeScreenGridItems.add(dialerIcon)
|
||||
}
|
||||
|
@ -883,7 +896,8 @@ class MainActivity : SimpleActivity(), FlingListener {
|
|||
-1,
|
||||
"",
|
||||
null,
|
||||
true
|
||||
true,
|
||||
null
|
||||
)
|
||||
homeScreenGridItems.add(SMSMessengerIcon)
|
||||
}
|
||||
|
@ -911,7 +925,8 @@ class MainActivity : SimpleActivity(), FlingListener {
|
|||
-1,
|
||||
"",
|
||||
null,
|
||||
true
|
||||
true,
|
||||
null
|
||||
)
|
||||
homeScreenGridItems.add(browserIcon)
|
||||
}
|
||||
|
@ -938,7 +953,8 @@ class MainActivity : SimpleActivity(), FlingListener {
|
|||
-1,
|
||||
"",
|
||||
null,
|
||||
true
|
||||
true,
|
||||
null
|
||||
)
|
||||
homeScreenGridItems.add(storeIcon)
|
||||
}
|
||||
|
@ -967,7 +983,8 @@ class MainActivity : SimpleActivity(), FlingListener {
|
|||
-1,
|
||||
"",
|
||||
null,
|
||||
true
|
||||
true,
|
||||
null
|
||||
)
|
||||
homeScreenGridItems.add(cameraIcon)
|
||||
}
|
||||
|
|
|
@ -21,11 +21,10 @@ import kotlin.system.exitProcess
|
|||
|
||||
class SettingsActivity : SimpleActivity() {
|
||||
|
||||
private lateinit var binding: ActivitySettingsBinding
|
||||
private val binding by viewBinding(ActivitySettingsBinding::inflate)
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
isMaterialActivity = true
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = ActivitySettingsBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
updateMaterialActivityViews(binding.settingsCoordinator, binding.settingsHolder, useTransparentNavigation = true, useTopSearchMenu = false)
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
package com.simplemobiletools.launcher.adapters
|
||||
|
||||
import android.view.Menu
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.iterator
|
||||
import com.simplemobiletools.commons.activities.BaseSimpleActivity
|
||||
import com.simplemobiletools.commons.adapters.MyRecyclerViewAdapter
|
||||
import com.simplemobiletools.commons.views.MyRecyclerView
|
||||
import com.simplemobiletools.launcher.R
|
||||
import com.simplemobiletools.launcher.activities.MainActivity
|
||||
import com.simplemobiletools.launcher.databinding.ItemLauncherLabelBinding
|
||||
import com.simplemobiletools.launcher.extensions.handleGridItemPopupMenu
|
||||
import com.simplemobiletools.launcher.interfaces.ItemMenuListenerAdapter
|
||||
import com.simplemobiletools.launcher.models.HomeScreenGridItem
|
||||
|
||||
class FolderIconsAdapter(
|
||||
activity: BaseSimpleActivity, var items: MutableList<HomeScreenGridItem>, private val iconPadding: Int,
|
||||
recyclerView: MyRecyclerView, itemClick: (Any) -> Unit
|
||||
) : MyRecyclerViewAdapter(activity, recyclerView, itemClick) {
|
||||
|
||||
override fun getActionMenuId() = 0
|
||||
|
||||
override fun actionItemPressed(id: Int) {}
|
||||
|
||||
override fun getSelectableItemCount() = itemCount
|
||||
|
||||
override fun getIsItemSelectable(position: Int) = false
|
||||
|
||||
override fun getItemSelectionKey(position: Int) = items.getOrNull(position)?.id?.toInt()
|
||||
|
||||
override fun getItemKeyPosition(key: Int) = items.indexOfFirst { it.id?.toInt() == key }
|
||||
|
||||
override fun onActionModeCreated() {}
|
||||
|
||||
override fun onActionModeDestroyed() {}
|
||||
|
||||
override fun prepareActionMode(menu: Menu) {}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
return createViewHolder(ItemLauncherLabelBinding.inflate(layoutInflater, parent, false).root)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val item = items[position]
|
||||
setupView(holder.itemView, item)
|
||||
bindViewHolder(holder)
|
||||
}
|
||||
|
||||
override fun getItemCount() = items.size
|
||||
|
||||
private fun removeItem(item: HomeScreenGridItem) {
|
||||
val position = items.indexOfFirst { it.id == item.id }
|
||||
items.removeAt(position)
|
||||
notifyItemRemoved(position)
|
||||
}
|
||||
|
||||
private fun setupView(view: View, item: HomeScreenGridItem) {
|
||||
ItemLauncherLabelBinding.bind(view).apply {
|
||||
launcherLabel.text = item.title
|
||||
launcherLabel.setTextColor(textColor)
|
||||
launcherIcon.setPadding(iconPadding, iconPadding, iconPadding, 0)
|
||||
launcherIcon.setImageDrawable(item.drawable)
|
||||
|
||||
val mainListener = (activity as? MainActivity)?.menuListener
|
||||
|
||||
root.setOnClickListener { itemClick(item) }
|
||||
root.setOnLongClickListener {
|
||||
popupAnchor.y = launcherIcon.y
|
||||
activity.handleGridItemPopupMenu(popupAnchor, item, false, object : ItemMenuListenerAdapter() {
|
||||
override fun appInfo(gridItem: HomeScreenGridItem) {
|
||||
mainListener?.appInfo(gridItem)
|
||||
}
|
||||
|
||||
override fun remove(gridItem: HomeScreenGridItem) {
|
||||
mainListener?.remove(gridItem)
|
||||
removeItem(gridItem)
|
||||
}
|
||||
|
||||
override fun uninstall(gridItem: HomeScreenGridItem) {
|
||||
mainListener?.uninstall(gridItem)
|
||||
}
|
||||
|
||||
override fun rename(gridItem: HomeScreenGridItem) {
|
||||
mainListener?.rename(gridItem)
|
||||
}
|
||||
|
||||
override fun beforeShow(menu: Menu) {
|
||||
var visibleMenuItems = 0
|
||||
for (menuItem in menu.iterator()) {
|
||||
if (menuItem.isVisible) {
|
||||
visibleMenuItems++
|
||||
}
|
||||
}
|
||||
val yOffset = resources.getDimension(R.dimen.long_press_anchor_button_offset_y) * (visibleMenuItems - 1)
|
||||
popupAnchor.y -= yOffset
|
||||
}
|
||||
})
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun updateItems(items: List<HomeScreenGridItem>) {
|
||||
this.items.clear()
|
||||
this.items.addAll(items)
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
}
|
|
@ -68,8 +68,8 @@ abstract class AppsDatabase : RoomDatabase() {
|
|||
|
||||
private val MIGRATION_4_5 = object : Migration(4, 5) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("CREATE TABLE `home_screen_grid_items_new` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `left` INTEGER NOT NULL, `top` INTEGER NOT NULL, `right` INTEGER NOT NULL, `bottom` INTEGER NOT NULL, `page` INTEGER NOT NULL, `package_name` TEXT NOT NULL, `activity_name` TEXT NOT NULL, `title` TEXT NOT NULL, `type` INTEGER NOT NULL, `class_name` TEXT NOT NULL, `widget_id` INTEGER NOT NULL, `shortcut_id` TEXT NOT NULL, `icon` BLOB, `docked` INTEGER NOT NULL DEFAULT 0)")
|
||||
database.execSQL("INSERT INTO `home_screen_grid_items_new` (`id`, `left`, `top`, `right`, `bottom`, `page`, `package_name`, `activity_name`, `title`, `type`, `class_name`, `widget_id`, `shortcut_id`, `icon`, `docked`) SELECT `id`, `left`, `top`, `right`, `bottom`, 0 as `page`, `package_name`, `activity_name`, `title`, `type`, `class_name`, `widget_id`, `shortcut_id`, `icon`, CASE WHEN `type` != 1 AND `top` = 5 THEN 1 ELSE 0 END AS `docked` FROM `home_screen_grid_items` WHERE `intent` IS NULL OR `intent` = ''")
|
||||
database.execSQL("CREATE TABLE `home_screen_grid_items_new` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `left` INTEGER NOT NULL, `top` INTEGER NOT NULL, `right` INTEGER NOT NULL, `bottom` INTEGER NOT NULL, `page` INTEGER NOT NULL, `package_name` TEXT NOT NULL, `activity_name` TEXT NOT NULL, `title` TEXT NOT NULL, `type` INTEGER NOT NULL, `class_name` TEXT NOT NULL, `widget_id` INTEGER NOT NULL, `shortcut_id` TEXT NOT NULL, `icon` BLOB, `docked` INTEGER NOT NULL DEFAULT 0, `parent_id` INTEGER)")
|
||||
database.execSQL("INSERT INTO `home_screen_grid_items_new` (`id`, `left`, `top`, `right`, `bottom`, `page`, `package_name`, `activity_name`, `title`, `type`, `class_name`, `widget_id`, `shortcut_id`, `icon`, `docked`, `parent_id`) SELECT `id`, `left`, `top`, `right`, `bottom`, 0 as `page`, `package_name`, `activity_name`, `title`, `type`, `class_name`, `widget_id`, `shortcut_id`, `icon`, CASE WHEN `type` != 1 AND `top` = 5 THEN 1 ELSE 0 END AS `docked`, NULL AS `parent_id` FROM `home_screen_grid_items` WHERE `intent` IS NULL OR `intent` = ''")
|
||||
database.execSQL("DROP TABLE `home_screen_grid_items`")
|
||||
database.execSQL("ALTER TABLE `home_screen_grid_items_new` RENAME TO `home_screen_grid_items`")
|
||||
database.execSQL("CREATE UNIQUE INDEX `index_home_screen_grid_items_id` ON `home_screen_grid_items` (`id`)")
|
||||
|
|
|
@ -6,9 +6,21 @@ import android.content.Intent
|
|||
import android.content.pm.ApplicationInfo
|
||||
import android.net.Uri
|
||||
import android.provider.Settings
|
||||
import android.view.ContextThemeWrapper
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.widget.PopupMenu
|
||||
import com.simplemobiletools.commons.extensions.getPopupMenuTheme
|
||||
import com.simplemobiletools.commons.extensions.showErrorToast
|
||||
import com.simplemobiletools.commons.helpers.isQPlus
|
||||
import com.simplemobiletools.launcher.R
|
||||
import com.simplemobiletools.launcher.activities.SettingsActivity
|
||||
import com.simplemobiletools.launcher.helpers.ITEM_TYPE_FOLDER
|
||||
import com.simplemobiletools.launcher.helpers.ITEM_TYPE_ICON
|
||||
import com.simplemobiletools.launcher.helpers.ITEM_TYPE_WIDGET
|
||||
import com.simplemobiletools.launcher.helpers.UNINSTALL_APP_REQUEST_CODE
|
||||
import com.simplemobiletools.launcher.interfaces.ItemMenuListener
|
||||
import com.simplemobiletools.launcher.models.HomeScreenGridItem
|
||||
|
||||
fun Activity.launchApp(packageName: String, activityName: String) {
|
||||
// if this is true, launch the app settings
|
||||
|
@ -56,3 +68,40 @@ fun Activity.uninstallApp(packageName: String) {
|
|||
startActivityForResult(this, UNINSTALL_APP_REQUEST_CODE)
|
||||
}
|
||||
}
|
||||
|
||||
fun Activity.handleGridItemPopupMenu(anchorView: View, gridItem: HomeScreenGridItem, isOnAllAppsFragment: Boolean, listener: ItemMenuListener): PopupMenu {
|
||||
val contextTheme = ContextThemeWrapper(this, getPopupMenuTheme())
|
||||
return PopupMenu(contextTheme, anchorView, Gravity.TOP or Gravity.END).apply {
|
||||
if (isQPlus()) {
|
||||
setForceShowIcon(true)
|
||||
}
|
||||
|
||||
inflate(R.menu.menu_app_icon)
|
||||
menu.findItem(R.id.rename).isVisible = (gridItem.type == ITEM_TYPE_ICON || gridItem.type == ITEM_TYPE_FOLDER) && !isOnAllAppsFragment
|
||||
menu.findItem(R.id.hide_icon).isVisible = gridItem.type == ITEM_TYPE_ICON && isOnAllAppsFragment
|
||||
menu.findItem(R.id.resize).isVisible = gridItem.type == ITEM_TYPE_WIDGET
|
||||
menu.findItem(R.id.app_info).isVisible = gridItem.type == ITEM_TYPE_ICON
|
||||
menu.findItem(R.id.uninstall).isVisible = gridItem.type == ITEM_TYPE_ICON && canAppBeUninstalled(gridItem.packageName)
|
||||
menu.findItem(R.id.remove).isVisible = !isOnAllAppsFragment
|
||||
setOnMenuItemClickListener { item ->
|
||||
listener.onAnyClick()
|
||||
when (item.itemId) {
|
||||
R.id.hide_icon -> listener.hide(gridItem)
|
||||
R.id.rename -> listener.rename(gridItem)
|
||||
R.id.resize -> listener.resize(gridItem)
|
||||
R.id.app_info -> listener.appInfo(gridItem)
|
||||
R.id.remove -> listener.remove(gridItem)
|
||||
R.id.uninstall -> listener.uninstall(gridItem)
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
setOnDismissListener {
|
||||
listener.onDismiss()
|
||||
}
|
||||
|
||||
listener.beforeShow(menu)
|
||||
|
||||
show()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -207,6 +207,7 @@ class AllAppsFragment(context: Context, attributeSet: AttributeSet) : MyFragment
|
|||
"",
|
||||
null,
|
||||
false,
|
||||
null,
|
||||
appLauncher.drawable
|
||||
)
|
||||
|
||||
|
|
|
@ -267,6 +267,7 @@ class WidgetsFragment(context: Context, attributeSet: AttributeSet) : MyFragment
|
|||
"",
|
||||
null,
|
||||
false,
|
||||
null,
|
||||
appWidget.widgetPreviewImage,
|
||||
appWidget.providerInfo,
|
||||
appWidget.activityInfo,
|
||||
|
|
|
@ -27,6 +27,7 @@ const val REQUEST_CREATE_SHORTCUT = 53
|
|||
const val ITEM_TYPE_ICON = 0
|
||||
const val ITEM_TYPE_WIDGET = 1
|
||||
const val ITEM_TYPE_SHORTCUT = 2
|
||||
const val ITEM_TYPE_FOLDER = 3
|
||||
|
||||
const val WIDGET_HOST_ID = 12345
|
||||
const val MAX_CLICK_DURATION = 150
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
package com.simplemobiletools.launcher.interfaces
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import androidx.room.*
|
||||
import com.simplemobiletools.launcher.models.HomeScreenGridItem
|
||||
|
||||
@Dao
|
||||
|
@ -11,6 +8,9 @@ interface HomeScreenGridItemsDao {
|
|||
@Query("SELECT * FROM home_screen_grid_items")
|
||||
fun getAllItems(): List<HomeScreenGridItem>
|
||||
|
||||
@Query("SELECT * FROM home_screen_grid_items WHERE parent_id = :folderId")
|
||||
fun getFolderItems(folderId: Long): List<HomeScreenGridItem>
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
fun insert(item: HomeScreenGridItem): Long
|
||||
|
||||
|
@ -23,12 +23,33 @@ 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, `page` = :page, `docked` = :docked WHERE id = :id")
|
||||
fun updateItemPosition(left: Int, top: Int, right: Int, bottom: Int, page: Int, docked: Boolean, id: Long)
|
||||
@Query("UPDATE home_screen_grid_items SET `left` = :left, `top` = :top, `right` = :right, `bottom` = :bottom, `page` = :page, `docked` = :docked , `parent_id` = :parentId WHERE id = :id")
|
||||
fun updateItemPosition(left: Int, top: Int, right: Int, bottom: Int, page: Int, docked: Boolean, parentId: Long?, id: Long)
|
||||
|
||||
@Query("DELETE FROM home_screen_grid_items WHERE id = :id")
|
||||
fun deleteById(id: Long)
|
||||
fun deleteItemById(id: Long)
|
||||
|
||||
@Query("DELETE FROM home_screen_grid_items WHERE parent_id = :id")
|
||||
fun deleteItemsWithParentId(id: Long)
|
||||
|
||||
@Transaction
|
||||
fun deleteById(id: Long) {
|
||||
deleteItemById(id)
|
||||
deleteItemsWithParentId(id)
|
||||
}
|
||||
|
||||
@Query("DELETE FROM home_screen_grid_items WHERE package_name = :packageName")
|
||||
fun deleteByPackageName(packageName: String)
|
||||
fun deleteItemByPackageName(packageName: String)
|
||||
|
||||
@Query("DELETE FROM home_screen_grid_items WHERE parent_id IN (SELECT id FROM home_screen_grid_items WHERE package_name = :packageName)")
|
||||
fun deleteItemsByParentPackageName(packageName: String)
|
||||
|
||||
@Query("UPDATE home_screen_grid_items SET `left` = `left` + :shiftBy WHERE parent_id == :folderId AND `left` > :shiftFrom AND id != :excludingId")
|
||||
fun shiftFolderItems(folderId: Long, shiftFrom: Int, shiftBy: Int, excludingId: Long? = null)
|
||||
|
||||
@Transaction
|
||||
fun deleteByPackageName(packageName: String) {
|
||||
deleteItemByPackageName(packageName)
|
||||
deleteItemsByParentPackageName(packageName)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
package com.simplemobiletools.launcher.interfaces
|
||||
|
||||
import android.view.Menu
|
||||
import com.simplemobiletools.launcher.models.HomeScreenGridItem
|
||||
|
||||
interface ItemMenuListener {
|
||||
fun onAnyClick()
|
||||
fun hide(gridItem: HomeScreenGridItem)
|
||||
fun rename(gridItem: HomeScreenGridItem)
|
||||
fun resize(gridItem: HomeScreenGridItem)
|
||||
fun appInfo(gridItem: HomeScreenGridItem)
|
||||
fun remove(gridItem: HomeScreenGridItem)
|
||||
fun uninstall(gridItem: HomeScreenGridItem)
|
||||
fun onDismiss()
|
||||
fun beforeShow(menu: Menu)
|
||||
}
|
||||
|
||||
abstract class ItemMenuListenerAdapter : ItemMenuListener {
|
||||
override fun onAnyClick() = Unit
|
||||
override fun hide(gridItem: HomeScreenGridItem) = Unit
|
||||
override fun rename(gridItem: HomeScreenGridItem) = Unit
|
||||
override fun resize(gridItem: HomeScreenGridItem) = Unit
|
||||
override fun appInfo(gridItem: HomeScreenGridItem) = Unit
|
||||
override fun remove(gridItem: HomeScreenGridItem) = Unit
|
||||
override fun uninstall(gridItem: HomeScreenGridItem) = Unit
|
||||
override fun onDismiss() = Unit
|
||||
override fun beforeShow(menu: Menu) = Unit
|
||||
}
|
|
@ -3,6 +3,7 @@ package com.simplemobiletools.launcher.models
|
|||
import android.appwidget.AppWidgetProviderInfo
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Point
|
||||
import android.graphics.drawable.Drawable
|
||||
import androidx.room.*
|
||||
import com.simplemobiletools.launcher.helpers.ITEM_TYPE_ICON
|
||||
|
@ -25,6 +26,7 @@ data class HomeScreenGridItem(
|
|||
@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 = "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
|
||||
@ColumnInfo(name = "parent_id") var parentId: Long? = null, // id of folder this item is in (if it is in any)
|
||||
|
||||
@Ignore var drawable: Drawable? = null,
|
||||
@Ignore var providerInfo: AppWidgetProviderInfo? = null, // used at widgets
|
||||
|
@ -32,7 +34,11 @@ data class HomeScreenGridItem(
|
|||
@Ignore var widthCells: Int = 1,
|
||||
@Ignore var heightCells: Int = 1
|
||||
) {
|
||||
constructor() : this(null, -1, -1, -1, -1, 0, "", "", "", ITEM_TYPE_ICON, "", -1, "", null, false, null, null, null, 1, 1)
|
||||
companion object {
|
||||
const val FOLDER_MAX_CAPACITY = 16
|
||||
}
|
||||
|
||||
constructor() : this(null, -1, -1, -1, -1, 0, "", "", "", ITEM_TYPE_ICON, "", -1, "", null, false, null, null, null, null, 1, 1)
|
||||
|
||||
fun getWidthInCells() = if (right == -1 || left == -1) {
|
||||
widthCells
|
||||
|
@ -63,4 +69,6 @@ data class HomeScreenGridItem(
|
|||
}
|
||||
|
||||
fun getItemIdentifier() = "$packageName/$activityName"
|
||||
|
||||
fun getTopLeft() = Point(left, top)
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
26
app/src/main/res/layout/dialog_folder_icons.xml
Normal file
26
app/src/main/res/layout/dialog_folder_icons.xml
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/dialog_folder_icons_holder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="@dimen/small_margin"
|
||||
android:layout_marginTop="@dimen/medium_margin"
|
||||
android:layout_marginEnd="@dimen/small_margin"
|
||||
android:minHeight="@dimen/min_folder_view_height"
|
||||
app:layout_constraintHeight_max="@dimen/max_folder_view_height">
|
||||
|
||||
<com.simplemobiletools.commons.views.MyRecyclerView
|
||||
android:id="@+id/dialog_folder_icons_grid"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:itemCount="10"
|
||||
tools:listitem="@layout/item_launcher_label" />
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
</FrameLayout>
|
|
@ -27,4 +27,10 @@
|
|||
android:maxLines="2"
|
||||
android:textSize="@dimen/smaller_text_size" />
|
||||
|
||||
<View
|
||||
android:id="@+id/popup_anchor"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:gravity="center_horizontal|top" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
|
|
@ -9,4 +9,6 @@
|
|||
<dimen name="page_indicator_dot_radius">6dp</dimen>
|
||||
<dimen name="page_indicator_stroke_width">1dp</dimen>
|
||||
<dimen name="page_indicator_margin">6dp</dimen>
|
||||
<dimen name="min_folder_view_height">200dp</dimen>
|
||||
<dimen name="max_folder_view_height">500dp</dimen>
|
||||
</resources>
|
||||
|
|
Loading…
Reference in a new issue