I am working on a app launcher and I am trying to achieve is when you drag a app ontop of another those 2 app icons are removed from the home screen and a folder icon show up instead when you open the folder the 2 app that were on the home screen are there. now the drag and drop part is working but the grouping of said icons into a folder I listed above is not working
here is my code for my home screen: package org.cpsk12.cpshome
import android.app.Activity
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.res.Configuration
import android.net.Uri
import android.os.Bundle
import android.preference.PreferenceManager
import android.provider.Settings
import android.text.Editable
import android.text.TextWatcher
import android.util.Log
import android.view.MotionEvent
import android.view.View
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import android.widget.LinearLayout
import org.cpsk12.cpshome.HomeActivity.Companion.appsAdapter
import org.cpsk12.cpshome.databinding.ActivityAppsListBinding
class MyReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
when (intent!!.action) {
"android.intent.action.PACKAGE_ADDED", "android.intent.action.PACKAGE_REMOVED" -> {
Log.d(javaClass.name, "Received")
appsAdapter.resetFilter()
appsAdapter.notifyDataSetChanged()
}
}
}
}
class HomeActivity : Activity() {
private lateinit var binding: ActivityAppsListBinding
private lateinit var searchBox: EditText
private lateinit var searchLayout: LinearLayout
private var isSearchActive = false
companion object {
lateinit var appsAdapter: FolderAppsAdapter
}
private val isPortrait
get() = resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT
private val myReceiver = MyReceiver()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityAppsListBinding.inflate(layoutInflater)
setContentView(binding.root)
val appDetails = AppRepository(this, getString(R.string.app_name)).findAll()
appsAdapter = FolderAppsAdapter(this, AppRepository(this, getString(R.string.app_name)))
binding.appsList.adapter = appsAdapter
binding.appsList.setOnItemClickListener { _, _, position, _ -> startActivity(appsAdapter.getItem(position)?.intent) }
binding.appsList.setOnItemLongClickListener { _, _, position, _ ->
startActivity(Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData(Uri.fromParts("package", appsAdapter.getItem(position)?.packageName, null)))
return@setOnItemLongClickListener true
}
searchBox = findViewById(R.id.searchBox)
searchLayout = findViewById(R.id.searchLayout)
searchBox.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
override fun afterTextChanged(s: Editable?) {
if (s.isNullOrEmpty()) {
isSearchActive = false
appsAdapter.resetFilter()
} else {
isSearchActive = true
appsAdapter.filter.filter(s.toString())
}
}
})
searchBox.setOnClickListener {
val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.showSoftInput(searchBox, InputMethodManager.SHOW_IMPLICIT)
}
registerReceiver(myReceiver, IntentFilter().apply {
addAction("android.intent.action.PACKAGE_ADDED")
addAction("android.intent.action.PACKAGE_REMOVED")
})
}
override fun onResume() {
super.onResume()
if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean("needsReload", false)) {
PreferenceManager.getDefaultSharedPreferences(this).edit().putBoolean("needsReload", false).apply()
recreate()
}
}
override fun onBackPressed() {}
override fun dispatchTouchEvent(event: MotionEvent): Boolean {
val view = currentFocus
val ret = super.dispatchTouchEvent(event)
if (view is EditText) {
val w = currentFocus
val scrcoords = IntArray(2)
w?.getLocationOnScreen(scrcoords)
val x = event.rawX + w!!.left - scrcoords[0]
val y = event.rawY + w.top - scrcoords[1]
if (event.action == MotionEvent.ACTION_UP && (x < 0 || x >= w.width || y < 0 || y >= w.height)) {
val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(window.decorView.windowToken, 0)
searchLayout.requestFocus()
}
}
return ret
}
override fun onDestroy() {
super.onDestroy()
unregisterReceiver(myReceiver)
}
}
here is my FolderAppsAdapter code
package org.cpsk12.cpshome
import android.content.ClipData
import android.content.Context
import android.graphics.drawable.Drawable
import android.view.DragEvent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.Filter
import android.widget.Filterable
import android.widget.ImageView
import android.widget.TextView
import androidx.core.content.ContextCompat
import java.util.*
open class FolderAppsAdapter(private val context: Context, private val appRepository: AppRepository) : BaseAdapter(), Filterable {
private val appsByFolder: MutableMap<String, MutableList<App>> = mutableMapOf()
init {
updateAppsByFolder()
}
private fun updateAppsByFolder() {
appRepository.getFolders().forEach { folder ->
val appsInFolder = appRepository.findAll().filter { it.folderName == folder }.toMutableList()
appsByFolder[folder] = appsInFolder
}
}
var filteredApps: List<App> = appRepository.findAll()
fun resetFilter() {
filteredApps = appRepository.findAll()
notifyDataSetChanged()
}
override fun getCount(): Int {
return filteredApps.size
}
override fun getItem(position: Int): App? {
return filteredApps.getOrNull(position)
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
var convertView = convertView
val app = getItem(position)
val holder: ViewHolder
if (convertView != null) {
holder = convertView.tag as ViewHolder
} else {
convertView = LayoutInflater.from(context).inflate(R.layout.list_item, parent, false)
holder = ViewHolder(
appIcon = convertView!!.findViewById(R.id.item_app_icon) as ImageView,
appLabel = convertView.findViewById(R.id.item_app_label) as TextView
)
convertView.tag = holder
}
app?.let {
holder.appIcon!!.setImageDrawable(it.icon)
holder.appLabel!!.text = it.name
// Handle click for the app
convertView?.setOnClickListener { view ->
// Implement your logic for clicking on an app
// You can launch the app or perform any other action
val clickedApp = getItem(position)
// Example: Launch the app
clickedApp?.intent?.let { intent ->
context.startActivity(intent)
}
}
}
// Handle drag-and-drop for the folder
convertView?.setOnDragListener { _, event ->
when (event.action) {
DragEvent.ACTION_DROP -> {
val draggedItem = event.localState as App
val folder = appRepository.getFolders().find { folderName ->
event.y > convertView.top && event.y < convertView.bottom
}
folder?.let {
// Update the folder for the dragged item
draggedItem.folderName = folder
// Check if the folder already exists
if (!appsByFolder.containsKey(folder)) {
appsByFolder[folder] = mutableListOf(draggedItem)
} else {
appsByFolder[folder]?.add(draggedItem)
}
// Update the adapter and refresh the view
updateAppsByFolder()
notifyDataSetChanged()
}
}
}
true
}
// Enable dragging
convertView?.setOnLongClickListener {
val clipData = ClipData.newPlainText("", "")
val shadowBuilder = View.DragShadowBuilder(it)
it.startDrag(clipData, shadowBuilder, app, 0)
true
}
return convertView!!
}
override fun getFilter(): Filter {
return object : Filter() {
override fun performFiltering(constraint: CharSequence?): FilterResults {
val filterResults = FilterResults()
val filteredList = mutableListOf<App>()
if (constraint.isNullOrBlank()) {
filteredList.addAll(appRepository.findAll())
} else {
val filterPattern = constraint.toString().toLowerCase(Locale.getDefault()).trim()
filteredList.addAll(appRepository.findAll().filter {
it.name.toLowerCase(Locale.getDefault()).contains(filterPattern)
})
}
filterResults.values = filteredList
filterResults.count = filteredList.size
return filterResults
}
override fun publishResults(constraint: CharSequence?, results: FilterResults?) {
if (results != null) {
filteredApps = results.values as List<App>
notifyDataSetChanged()
}
}
}
}
fun updateFolders() {
updateAppsByFolder()
notifyDataSetChanged()
}
private data class ViewHolder(
internal val appIcon: ImageView? = null,
internal val appLabel: TextView? = null
)
}
the app class:
package org.cpsk12.cpshome
import android.content.Intent
import android.graphics.drawable.Drawable
data class App(
val name: String,
val packageName: String,
var folderName: String,
val icon: Drawable?,
val intent: Intent? = null,
var position: Int = -1
)
and the AppRepository
package org.cpsk12.cpshome
import android.content.pm.ActivityInfo
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
import android.content.Context
import android.content.Intent
class AppRepository(private val context: Context, private val appName: String) {
private val packageManager: PackageManager = context.packageManager
private val applicationInfo: ApplicationInfo = context.applicationInfo
// Example settings app
private val settingsApp = App(
name = "$appName settings",
packageName = context.packageName,
folderName = "Uncategorized",
icon = packageManager.getApplicationIcon(applicationInfo),
intent = null
)
// Add folder-related methods
private val folders = mutableSetOf<String>()
fun addFolder(folderName: String) {
folders.add(folderName)
}
fun getFolders(): Set<String> {
return folders
}
fun findAll(): List<App> {
val i = Intent(Intent.ACTION_MAIN, null).addCategory(Intent.CATEGORY_LAUNCHER)
return packageManager.queryIntentActivities(i, 0).map {
App(
name = it.loadLabel(packageManager).toString(),
packageName = it.activityInfo.packageName,
folderName = "Uncategorized", // Default folder
icon = it.activityInfo.loadIcon(packageManager),
intent = loadIntent(it.activityInfo, packageManager)
)
}.filterNot {
it.packageName in setOf(
"com.android.vending",
"com.android.settings",
"org.cpsk12.cpshome",
"com.android.mms",
"com.android.contacts",
"com.android.dialer",
"com.android.chrome",
"com.google.android.dialer",
"com.google.android.apps.messaging"
)
}.plus(settingsApp).sortedBy { it.name }
}
private fun loadIntent(activityInfo: ActivityInfo, packageManager: PackageManager): Intent? {
val launchIntent = packageManager.getLaunchIntentForPackage(activityInfo.packageName)
return launchIntent?.let {
it.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
Intent(it)
}
}
}
any help would be absolutely incredible!!!!