diff --git a/app/build.gradle.kts b/app/build.gradle.kts index ff34894f..39458454 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -70,4 +70,5 @@ dependencies { implementation ("com.google.android.material:material:1.10.0") implementation (kotlin("stdlib", version = kotlinVersion)) implementation ("com.github.cachapa:ExpandableLayout:2.9.2") + implementation ("com.squareup.picasso:picasso:2.8") } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 099a1213..e30947b0 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -19,6 +19,9 @@ + diff --git a/app/src/main/kotlin/rasel/lunar/launcher/apps/AlphabetScrollbar.kt b/app/src/main/kotlin/rasel/lunar/launcher/apps/AlphabetScrollbar.kt index 043aab8d..ba8d350c 100644 --- a/app/src/main/kotlin/rasel/lunar/launcher/apps/AlphabetScrollbar.kt +++ b/app/src/main/kotlin/rasel/lunar/launcher/apps/AlphabetScrollbar.kt @@ -1,118 +1,112 @@ -/* - * Lunar Launcher - * Copyright (C) 2022 Md Rasel Hossain - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package rasel.lunar.launcher.apps - -import android.annotation.SuppressLint -import android.content.Context -import android.graphics.Canvas -import android.graphics.Paint -import android.util.AttributeSet -import android.util.TypedValue -import android.view.MotionEvent -import android.view.View -import androidx.core.content.ContextCompat -import rasel.lunar.launcher.apps.AppDrawer.Companion.alphabetList -import rasel.lunar.launcher.apps.AppDrawer.Companion.letterPreview -import rasel.lunar.launcher.apps.AppDrawer.Companion.listenScroll -import rasel.lunar.launcher.apps.AppDrawer.Companion.settingsPrefs -import rasel.lunar.launcher.apps.AppsAdapter.Companion.appsSize -import rasel.lunar.launcher.helpers.Constants - - -internal class AlphabetScrollbar : View { - - private var paint: Paint? = null - private var selectedIndex = -1 - private val alphabet get() = alphabetList.distinct() - - constructor(context: Context?) : super(context) { - init() - } - - constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) { - init() - } - - constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { - init() - } - - @SuppressLint("ResourceType") - private fun init() { - paint = Paint(Paint.ANTI_ALIAS_FLAG).apply { - color = defaultTextColor - textSize = 16f - } - } - - override fun onDraw(canvas: Canvas) { - super.onDraw(canvas) - val width = width - val height = height - val letterHeight: Int = height / alphabet.count() - alphabet.indices.forEach { i: Int -> - val x = width / 2f - paint!!.measureText(alphabet[i]) / 2f - val y = i * letterHeight + letterHeight / 2f - when (i) { - selectedIndex -> paint!!.textSize = 20f - else -> paint!!.textSize = 16f - } - canvas.drawText(alphabet[i], x, y, paint!!) - } - } - - @SuppressLint("ClickableViewAccessibility") - override fun onTouchEvent(event: MotionEvent): Boolean { - when (event.action) { - MotionEvent.ACTION_DOWN, MotionEvent.ACTION_MOVE -> { - val y = event.y - val index = (y / height * alphabet.count()).toInt() - if (index != selectedIndex) { - selectedIndex = index - invalidate() - } - - if (!settingsPrefs!!.getBoolean(Constants.KEY_APPS_COUNT, true)) letterPreview?.visibility = VISIBLE - try { letterPreview?.text = alphabet[selectedIndex] } - catch (exception: Exception) { exception.printStackTrace() } - } - - MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { - when { - selectedIndex < 0 -> listenScroll(alphabet[0]) - selectedIndex > alphabet.count() - 1 -> listenScroll(alphabet[alphabet.count() - 1]) - else -> listenScroll(alphabet[selectedIndex]) - } - - selectedIndex = -1 - invalidate() - if (settingsPrefs!!.getBoolean(Constants.KEY_APPS_COUNT, true)) letterPreview?.text = appsSize.toString() - else letterPreview?.visibility = GONE - } - } - return true - } - - private val defaultTextColor: Int get() { - val resolvedAttr = TypedValue() - context.theme.resolveAttribute(android.R.attr.textColorPrimary, resolvedAttr, true) - val colorRes = resolvedAttr.run { if (resourceId != 0) resourceId else data } - return ContextCompat.getColor(context, colorRes) - } -} \ No newline at end of file +///* +// * Lunar Launcher +// * Copyright (C) 2022 Md Rasel Hossain +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have received a copy of the GNU General Public License +// * along with this program. If not, see . +// */ +// +//package rasel.lunar.launcher.apps +// +//import android.annotation.SuppressLint +//import android.content.Context +//import android.graphics.Canvas +//import android.graphics.Paint +//import android.util.AttributeSet +//import android.util.TypedValue +//import android.view.MotionEvent +//import android.view.View +//import androidx.core.content.ContextCompat +// +// +//internal class AlphabetScrollbar : View { +// +// private var paint: Paint? = null +// private var selectedIndex = -1 +//// private val alphabet get() = alphabetList.distinct() +// +// constructor(context: Context?) : super(context) { +// init() +// } +// +// constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) { +// init() +// } +// +// constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { +// init() +// } +// +// @SuppressLint("ResourceType") +// private fun init() { +// paint = Paint(Paint.ANTI_ALIAS_FLAG).apply { +// color = defaultTextColor +// textSize = 16f +// } +// } +// +// override fun onDraw(canvas: Canvas) { +// super.onDraw(canvas) +// val width = width +// val height = height +// val letterHeight: Int = height / alphabet.count() +// alphabet.indices.forEach { i: Int -> +// val x = width / 2f - paint!!.measureText(alphabet[i]) / 2f +// val y = i * letterHeight + letterHeight / 2f +// when (i) { +// selectedIndex -> paint!!.textSize = 20f +// else -> paint!!.textSize = 16f +// } +// canvas.drawText(alphabet[i], x, y, paint!!) +// } +// } +// +// @SuppressLint("ClickableViewAccessibility") +// override fun onTouchEvent(event: MotionEvent): Boolean { +//// when (event.action) { +//// MotionEvent.ACTION_DOWN, MotionEvent.ACTION_MOVE -> { +//// val y = event.y +//// val index = (y / height * alphabet.count()).toInt() +//// if (index != selectedIndex) { +//// selectedIndex = index +//// invalidate() +//// } +//// +//// if (!settingsPrefs!!.getBoolean(Constants.KEY_APPS_COUNT, true)) letterPreview?.visibility = VISIBLE +//// try { letterPreview?.text = alphabet[selectedIndex] } +//// catch (exception: Exception) { exception.printStackTrace() } +//// } +//// +//// MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { +//// when { +//// selectedIndex < 0 -> listenScroll(alphabet[0]) +//// selectedIndex > alphabet.count() - 1 -> listenScroll(alphabet[alphabet.count() - 1]) +//// else -> listenScroll(alphabet[selectedIndex]) +//// } +//// +//// selectedIndex = -1 +//// invalidate() +//// if (settingsPrefs!!.getBoolean(Constants.KEY_APPS_COUNT, true)) letterPreview?.text = appsSize.toString() +//// else letterPreview?.visibility = GONE +//// } +//// } +// return true +// } +// +// private val defaultTextColor: Int get() { +// val resolvedAttr = TypedValue() +// context.theme.resolveAttribute(android.R.attr.textColorPrimary, resolvedAttr, true) +// val colorRes = resolvedAttr.run { if (resourceId != 0) resourceId else data } +// return ContextCompat.getColor(context, colorRes) +// } +//} \ No newline at end of file diff --git a/app/src/main/kotlin/rasel/lunar/launcher/apps/AppDrawer.kt b/app/src/main/kotlin/rasel/lunar/launcher/apps/AppDrawer.kt index 59024fa1..23b0cc4e 100644 --- a/app/src/main/kotlin/rasel/lunar/launcher/apps/AppDrawer.kt +++ b/app/src/main/kotlin/rasel/lunar/launcher/apps/AppDrawer.kt @@ -27,6 +27,7 @@ import android.content.pm.ResolveInfo import android.graphics.Rect import android.os.Build import android.os.Bundle +import android.provider.Settings.Global import android.view.Gravity import android.view.LayoutInflater import android.view.View @@ -41,6 +42,9 @@ import androidx.fragment.app.Fragment import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.LinearLayoutManager import com.google.android.material.textview.MaterialTextView +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.MainScope +import kotlinx.coroutines.launch import rasel.lunar.launcher.BuildConfig import rasel.lunar.launcher.LauncherActivity.Companion.lActivity import rasel.lunar.launcher.R @@ -75,42 +79,25 @@ internal class AppDrawer : Fragment() { private var appsAdapter: AppsAdapter? = null private var packageInfoList: MutableList = mutableListOf() private var packageList = mutableListOf() - private var packageListClone = mutableListOf() - private val numberPattern = Pattern.compile("[0-9]") - private val alphabetPattern = Pattern.compile("[A-Z]") + + // private val numberPattern = Pattern.compile("[0-9]") +// private val alphabetPattern = Pattern.compile("[A-Z]") @JvmStatic var settingsPrefs: SharedPreferences? = null @JvmStatic var appNamesPrefs: SharedPreferences? = null - @JvmStatic var alphabetList = mutableListOf() + // @JvmStatic var alphabetList = mutableListOf() @JvmStatic var letterPreview: MaterialTextView? = null private fun appName(resolver: ResolveInfo): String { - return appNamesPrefs?.getString(resolver.activityInfo.packageName, resolver.loadLabel(packageManager).toString())!! + if(appNamesPrefs?.contains(resolver.activityInfo.packageName) != null && appNamesPrefs?.getString(resolver.activityInfo.packageName,"")?.length ?: 0 > 0) { + return appNamesPrefs?.getString(resolver.activityInfo.packageName,"") ?: "" + } else { + return resolver.loadLabel(packageManager).toString().apply { + appNamesPrefs?.edit()?.putString(resolver.activityInfo.packageName, this)?.apply() + } + } + } - fun listenScroll(letter: String) { -// packageListClone.clear() -// for (resolver in packageInfoList) { -// when { -// letter == "#" -> { -// if (numberPattern.matcher(appName(resolver).first().uppercase()).matches()) { -// packageListClone.add(Packages(resolver.activityInfo.packageName, appName(resolver))) -// } -// } -// alphabetPattern.matcher(letter).matches() -> { -// if (appName(resolver).first().uppercase() == letter) { -// packageListClone.add(Packages(resolver.activityInfo.packageName, appName(resolver))) -// } -// } -// letter == "⠶" -> { -// if (!numberPattern.matcher(appName(resolver).first().uppercase()).matches() && -// !alphabetPattern.matcher(appName(resolver).first().uppercase()).matches()) { -// packageListClone.add(Packages(resolver.activityInfo.packageName, appName(resolver))) -// } -// } -// } -// } -// appsAdapter?.updateData(packageListClone.sortedBy { it.appName.lowercase() }) - } } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { @@ -126,9 +113,7 @@ internal class AppDrawer : Fragment() { binding.appsCount.visibility = if (settingsPrefs!!.getBoolean(KEY_APPS_COUNT, true)) VISIBLE else GONE setLayout() - fetchApps() - getAlphabetItems() - setKeyboardPadding() + return binding.root } @@ -140,7 +125,7 @@ internal class AppDrawer : Fragment() { binding.reset.setOnClickListener { onResume() } binding.moveDown.setOnClickListener { - binding.appsList.smoothScrollToPosition(packageListClone.size - 1) + binding.appsList.smoothScrollToPosition(packageList.size - 1) } binding.moveUp.setOnClickListener { @@ -163,7 +148,7 @@ internal class AppDrawer : Fragment() { override fun onResume() { super.onResume() fetchApps() - getAlphabetItems() + setKeyboardPadding() binding.appsCount.visibility = if (settingsPrefs!!.getBoolean(KEY_APPS_COUNT, true)) VISIBLE else GONE @@ -186,7 +171,7 @@ internal class AppDrawer : Fragment() { binding.appsList.layoutManager = LinearLayoutManager(requireContext()) appsAdapter!!.updateGravity(settingsPrefs!!.getInt(KEY_DRAW_ALIGN, Gravity.CENTER)) } - 2 -> binding.appsList.layoutManager = GridLayoutManager(requireContext(), settingsPrefs!!.getInt(KEY_GRID_COLUMNS, DEFAULT_GRID_COLUMNS)) + 2 -> binding.appsList.layoutManager = GridLayoutManager(requireContext(), Math.min(settingsPrefs!!.getInt(KEY_GRID_COLUMNS, DEFAULT_GRID_COLUMNS), 4)) } /* initialize apps list adapter */ @@ -195,30 +180,39 @@ internal class AppDrawer : Fragment() { /* update app list with app and package name */ fun fetchApps() { - packageInfoList = (if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - packageManager?.queryIntentActivities( - Intent(Intent.ACTION_MAIN, null).addCategory(Intent.CATEGORY_LAUNCHER), - PackageManager.ResolveInfoFlags.of(0) - ) - } else { - (packageManager?.queryIntentActivities( - Intent(Intent.ACTION_MAIN, null).addCategory(Intent.CATEGORY_LAUNCHER), 0)) - })?.apply { - removeIf { it.activityInfo.packageName.equals(BuildConfig.APPLICATION_ID) } - sortWith(ResolveInfo.DisplayNameComparator(packageManager)) - }!! + GlobalScope.launch { + packageInfoList = (if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + packageManager?.queryIntentActivities( + Intent(Intent.ACTION_MAIN, null).addCategory(Intent.CATEGORY_LAUNCHER), + PackageManager.ResolveInfoFlags.of(0) + ) + } else { + (packageManager?.queryIntentActivities( + Intent(Intent.ACTION_MAIN, null).addCategory(Intent.CATEGORY_LAUNCHER), 0 + )) + })?.apply { + removeIf { it.activityInfo.packageName.equals(BuildConfig.APPLICATION_ID) } + sortedBy { + appName(it) + } + }!! - /* add package and app names to the list */ - packageList.clear() - packageListClone.clear() - for (resolver in packageInfoList) { - packageList.add(Packages(resolver.activityInfo.packageName, appName(resolver))) - packageListClone.add(Packages(resolver.activityInfo.packageName, appName(resolver))) - } + /* add package and app names to the list */ + packageList.clear() + var edit = appNamesPrefs?.edit() + for (resolver in packageInfoList) { + packageList.add(Packages(resolver.activityInfo.packageName, appName(resolver))) + } - when { - packageListClone.size < 1 -> return - else -> appsAdapter?.updateData(packageListClone.sortedBy { it.appName.lowercase() }) +// when { +// packageList.size < 1 -> return +// else -> { + if (packageList.size > 0) { + MainScope().launch { + appsAdapter?.updateData(packageList) + } + } +// } } } @@ -247,43 +241,63 @@ internal class AppDrawer : Fragment() { // } } + var lastSearchStringLength = 0 + var lastSearchString : String = "" private fun filterAppsList(searchString: String) { /* check each app name and add if it matches the search string */ - packageListClone.clear() - for (resolver in packageInfoList) { - appName(resolver).let { - BLog.LOGE("searchString >>> ${searchString} , normalize(it) ${normalize(it)} ${normalize(it).contains(searchString)}") - if (normalize(it).contains(searchString)) { - packageListClone.add(Packages(resolver.activityInfo.packageName, it)) + if (lastSearchStringLength > 0 && (lastSearchStringLength != searchString.length || lastSearchString.equals(searchString) == false)) { + BLog.LOGE("START FILTER") + packageList.clear() + for (resolver in packageInfoList) { + appName(resolver).let { +// BLog.LOGE("searchString >>> ${searchString} , normalize(it) ${normalize(it)} ${normalize(it).contains(normalize(searchString), false)}") + if (normalize(it).contains(normalize(searchString), false)) { + packageList.add(Packages(resolver.activityInfo.packageName, it)) + } else { + + } } } - } - - if (searchString.length > 2 && packageListClone.size == 1 && settingsPrefs!!.getBoolean(KEY_QUICK_LAUNCH, true)) { - var dialog = AlertDialog.Builder(requireContext()) - dialog.setTitle("앱 실행 확인") - dialog.setMessage("${searchString} 검색 결과 '${packageListClone[0].appName}' 준비됨") - dialog.setCancelable(false) - dialog.setOnCancelListener { - binding.searchInput.setText("") - it.dismiss() + BLog.LOGE("MIDDLE FILTER") + if (searchString.length > 2 && packageList.size == 1 && settingsPrefs!!.getBoolean( + KEY_QUICK_LAUNCH, + true + ) + ) { + var dialog = AlertDialog.Builder(requireContext()) + dialog.setTitle("앱 실행 확인") + dialog.setMessage("${searchString} 검색 결과 '${packageList[0].appName}' 준비됨") + dialog.setCancelable(false) + dialog.setNegativeButton("취소") { s,d-> + binding.searchInput.setText("") + s.dismiss() + } + dialog.setPositiveButton("실행") { s, d -> + startActivity(packageManager?.getLaunchIntentForPackage(packageList[0].packageName)) + s.dismiss() + binding.searchInput.setText("") + } + dialog.show() + } else { + appsAdapter?.updateData(packageList) } - dialog.setPositiveButton("실행") { s,d -> - startActivity(packageManager?.getLaunchIntentForPackage(packageListClone[0].packageName)) - s.dismiss() - binding.searchInput.setText("") + BLog.LOGE("END FILTER") + } else if(lastSearchStringLength == 0){ + packageList.clear() + for (resolver in packageInfoList) { + packageList.add(Packages(resolver.activityInfo.packageName, appName(resolver))) } - dialog.show() + appsAdapter?.updateData(packageList) } - else appsAdapter?.updateData(packageListClone.sortedBy { it.appName.lowercase() }) - + lastSearchString = searchString + lastSearchStringLength = searchString.length } private fun normalize(str: String): String { val normalizedString = - Normalizer.normalize(str.replace("\\W".toRegex(), ""), Normalizer.Form.NFD) + Normalizer.normalize(str.replace("\\W".toRegex(), ""), Normalizer.Form.NFC) val pattern = Pattern.compile("\\p{InCombiningDiacriticalMarks}+") - return pattern.matcher(normalizedString).replaceAll("").lowercase() + return pattern.matcher(normalizedString).replaceAll("").toLowerCase() } private fun openSearch() { diff --git a/app/src/main/kotlin/rasel/lunar/launcher/apps/AppsAdapter.kt b/app/src/main/kotlin/rasel/lunar/launcher/apps/AppsAdapter.kt index 9072c000..7da00b1a 100644 --- a/app/src/main/kotlin/rasel/lunar/launcher/apps/AppsAdapter.kt +++ b/app/src/main/kotlin/rasel/lunar/launcher/apps/AppsAdapter.kt @@ -30,6 +30,8 @@ import androidx.fragment.app.FragmentManager import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView import com.google.android.material.textview.MaterialTextView +import kotlinx.coroutines.MainScope +import kotlinx.coroutines.async import rasel.lunar.launcher.LauncherActivity.Companion.lActivity import rasel.lunar.launcher.R import rasel.lunar.launcher.apps.IconPackManager.Companion.getDrawableIconForPackage @@ -75,7 +77,13 @@ internal class AppsAdapter( } 1 -> { appIcon.visibility = View.GONE - appIconTwo.setImageDrawable(getDrawableIconForPackage(item.packageName, packageManager.getApplicationIcon(item.packageName))) + appIconTwo.visibility = View.VISIBLE + + MainScope().async { + getDrawableIconForPackage(item.packageName, packageManager.getApplicationIcon(item.packageName)) { + appIconTwo.post { appIconTwo.setImageDrawable(it) } + } } + childTextview.apply { gravity = appGravity or Gravity.CENTER_VERTICAL setTextSize(TypedValue.COMPLEX_UNIT_PX, lActivity!!.resources.getDimension(R.dimen.twenty)) @@ -85,7 +93,15 @@ internal class AppsAdapter( } 2 -> { appIconTwo.visibility = View.GONE - appIcon.setImageDrawable(getDrawableIconForPackage(item.packageName, packageManager.getApplicationIcon(item.packageName))) + appIcon.visibility = View.VISIBLE + MainScope().async { + getDrawableIconForPackage( + item.packageName, + packageManager.getApplicationIcon(item.packageName) + ) { + appIcon.post { appIcon.setImageDrawable(it) } + } + } childTextview.apply { gravity = Gravity.CENTER setTextSize(TypedValue.COMPLEX_UNIT_PX, lActivity!!.resources.getDimension(R.dimen.twelve)) @@ -125,7 +141,6 @@ internal class AppsAdapter( appsCount.text = it.toString() appsSize = it } - this.notifyDataSetChanged() } /* update text gravity (alignment) */ @@ -138,6 +153,10 @@ internal class AppsAdapter( notifyDataSetChanged() } } + + fun hideItem(idx: Int) { + + } } internal data class Packages ( diff --git a/app/src/main/kotlin/rasel/lunar/launcher/apps/IconPackManager.kt b/app/src/main/kotlin/rasel/lunar/launcher/apps/IconPackManager.kt index d967b4a2..6087eb23 100644 --- a/app/src/main/kotlin/rasel/lunar/launcher/apps/IconPackManager.kt +++ b/app/src/main/kotlin/rasel/lunar/launcher/apps/IconPackManager.kt @@ -25,7 +25,13 @@ import android.graphics.Bitmap import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable import android.util.Log +import androidx.collection.LruCache import androidx.core.content.res.ResourcesCompat +import com.squareup.picasso.Picasso +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.MainScope +import kotlinx.coroutines.async +import kotlinx.coroutines.launch import org.xmlpull.v1.XmlPullParser import org.xmlpull.v1.XmlPullParserException import org.xmlpull.v1.XmlPullParserFactory @@ -47,12 +53,14 @@ internal class IconPackManager { private val packageName = settingsPrefs.getString(KEY_ICON_PACK, DEFAULT_ICON_PACK) private var loaded = false private val packagesDrawables = HashMap() + private val packagesConponentNames = HashMap() private val backImages: MutableList = ArrayList() private var maskImage: Bitmap? = null private var frontImage: Bitmap? = null private var factor = 1.0f private var totalIcons = 0 private var iconPackRes: Resources? = null + private var appPackageIconDrawables : HashMap = hashMapOf() private fun load() { /* load appfilter.xml from the icon pack package */ @@ -62,11 +70,14 @@ internal class IconPackManager { val appFilterId = iconPackRes!!.getIdentifier("appfilter", "xml", packageName) if (appFilterId > 0) { xpp = iconPackRes!!.getXml(appFilterId) + BLog.LOGE("packageName >>> ${packageName}") } else { - /* no resource found, try to open it from assets folder */ try { xpp = XmlPullParserFactory.newInstance().apply { isNamespaceAware = true } - .newPullParser().apply { setInput(iconPackRes!!.assets.open("appfilter.xml"), "utf-8") } + .newPullParser().apply { + BLog.LOGE("packageName >>> ${packageName}") + setInput(iconPackRes!!.assets.open("appfilter.xml"), "utf-8") + } } catch (e: IOException) { e.printStackTrace() BLog.w("", "Couldn't find the appfilter.xml file") @@ -78,36 +89,24 @@ internal class IconPackManager { if (eventType == XmlPullParser.START_TAG) { when (xpp.name) { "iconback" -> { - for (i in 0 until xpp.attributeCount) { - if (xpp.getAttributeName(i).startsWith("img")) { - loadBitmap(xpp.getAttributeValue(i))?.let { backImages.add(it) } - } - } + for (i in 0 until xpp.attributeCount) { if (xpp.getAttributeName(i).startsWith("img")) { loadBitmap(xpp.getAttributeValue(i))?.let { backImages.add(it) }}} } "iconmask" -> { - if (xpp.attributeCount > 0 && xpp.getAttributeName(0) == "img1") { - maskImage = loadBitmap(xpp.getAttributeValue(0)) - } + if (xpp.attributeCount > 0 && xpp.getAttributeName(0) == "img1") { maskImage = loadBitmap(xpp.getAttributeValue(0)) } } "iconupon" -> { - if (xpp.attributeCount > 0 && xpp.getAttributeName(0) == "img1") { - frontImage = loadBitmap(xpp.getAttributeValue(0)) - } + if (xpp.attributeCount > 0 && xpp.getAttributeName(0) == "img1") { frontImage = loadBitmap(xpp.getAttributeValue(0)) } } "scale" -> { - if (xpp.attributeCount > 0 && xpp.getAttributeName(0) == "factor") { - factor = java.lang.Float.valueOf(xpp.getAttributeValue(0)) - } + if (xpp.attributeCount > 0 && xpp.getAttributeName(0) == "factor") { factor = java.lang.Float.valueOf(xpp.getAttributeValue(0)) } } "item" -> { var componentName: String? = null var drawableName: String? = null - for (i in 0 until xpp.attributeCount) { - when (xpp.getAttributeName(i)) { - "component" -> componentName = xpp.getAttributeValue(i) - "drawable" -> drawableName = xpp.getAttributeValue(i) - } - } + for (i in 0 until xpp.attributeCount) { when (xpp.getAttributeName(i)) { + "component" -> componentName = xpp.getAttributeValue(i) + "drawable" -> drawableName = xpp.getAttributeValue(i) + } } if (!packagesDrawables.containsKey(componentName)) { packagesDrawables[componentName] = drawableName totalIcons += 1 @@ -127,12 +126,30 @@ internal class IconPackManager { e.printStackTrace() } } + val maxMemory = (Runtime.getRuntime().maxMemory() / 1024).toInt() + val cacheSize = maxMemory / 8 + val bitmapCache = object : LruCache(cacheSize) { + fun sizeOf(key: String?, value: Bitmap?): Int { + return if(value?.byteCount?.toInt() ?: 0 > 1024) { + value?.byteCount!!.div(1024) + } else { 0 } + } + } private fun loadBitmap(drawableName: String): Bitmap? { + if (packageName != null && packageName.length > 0) { + var bm = bitmapCache.get(packageName) + if (bm != null) return bm + } iconPackRes!!.getIdentifier(drawableName, "drawable", packageName).let { id -> if (id > 0) { ResourcesCompat.getDrawable(iconPackRes!!, id, null).let { - if (it is BitmapDrawable) return it.bitmap + if (it is BitmapDrawable) { + if (packageName != null && packageName.length > 0) { + bitmapCache.put(packageName, it.bitmap) + } + return it.bitmap + } } } } @@ -146,35 +163,69 @@ internal class IconPackManager { } } - fun getDrawableIconForPackage(appPackageName: String?, defaultDrawable: Drawable?): Drawable? { - when (packageName) { - DEFAULT_ICON_PACK -> return defaultDrawable - else -> { - if (!loaded) load() - var componentName: String? = null - if (lActivity!!.packageManager.getLaunchIntentForPackage(appPackageName!!) != null) { - componentName = lActivity!!.packageManager.getLaunchIntentForPackage(appPackageName)!!.component.toString() - } - var drawable = packagesDrawables[componentName] - if (!drawable.isNullOrEmpty()) return loadDrawable(drawable) - else { - /* try to get a resource with the component filename */ - if (!componentName.isNullOrEmpty()) { - val start = componentName.indexOf("{") + 1 - val end = componentName.indexOf("}", start) - if (end > start) { - drawable = componentName.substring(start, end).lowercase(Locale.getDefault()).replace(".", "_").replace("/", "_") - try { - if (iconPackRes!!.getIdentifier(drawable, "drawable", packageName) > 0) return loadDrawable(drawable) - } catch (e: NullPointerException) { - settingsPrefs.edit().putString(KEY_ICON_PACK, DEFAULT_ICON_PACK).apply() + fun putAfterReturn(packages: String, drawable : Drawable?) : Drawable? { + if (drawable != null) { + appPackageIconDrawables.put(packages, drawable) + } + return drawable + } + + fun getDrawableIconForPackage(appPackageName: String?, defaultDrawable: Drawable?, onComplete : (Drawable?)->Unit) { + var ddd = if (appPackageIconDrawables.containsKey(appPackageName)) appPackageIconDrawables.get(appPackageName) else null + if (ddd != null) { + onComplete(ddd) + } else { + when (packageName) { + DEFAULT_ICON_PACK -> onComplete.invoke(defaultDrawable) + else -> { + if (!loaded) load() + var componentName: String? = null + componentName = packagesConponentNames.get(appPackageName!!) + if (componentName == null || componentName.length ?: 0 <= 0 ) { + BLog.LOGE("it's compo ${appPackageName}") + var pkgIntent = + lActivity!!.packageManager.getLaunchIntentForPackage( + appPackageName!! + ) + if (pkgIntent != null) { + componentName = pkgIntent!!.component.toString() + } + } + var drawable = packagesDrawables[componentName] + if (!drawable.isNullOrEmpty()) onComplete.invoke( + putAfterReturn( + appPackageName, + loadDrawable(drawable) + ) + ) + else { + if (!componentName.isNullOrEmpty()) { + val start = componentName.indexOf("{") + 1 + val end = componentName.indexOf("}", start) + if (end > start) { + drawable = componentName.substring(start, end) + .lowercase(Locale.getDefault()).replace(".", "_") + .replace("/", "_") + try { + if (iconPackRes!!.getIdentifier( + drawable, + "drawable", + packageName + ) > 0 + ) onComplete.invoke(putAfterReturn(appPackageName, loadDrawable(drawable))) + } catch (e: NullPointerException) { + settingsPrefs.edit() + .putString(KEY_ICON_PACK, DEFAULT_ICON_PACK).apply() + } } + } else { + onComplete.invoke(defaultDrawable) } } } - return defaultDrawable } } + } } diff --git a/app/src/main/kotlin/rasel/lunar/launcher/feeds/WidgetHost.kt b/app/src/main/kotlin/rasel/lunar/launcher/feeds/WidgetHost.kt index cf9fe9de..402955b9 100644 --- a/app/src/main/kotlin/rasel/lunar/launcher/feeds/WidgetHost.kt +++ b/app/src/main/kotlin/rasel/lunar/launcher/feeds/WidgetHost.kt @@ -32,4 +32,5 @@ internal class WidgetHost(context: Context, hostId: Int) : AppWidgetHost(context clearViews() } + } diff --git a/app/src/main/kotlin/rasel/lunar/launcher/feeds/WidgetHostView.kt b/app/src/main/kotlin/rasel/lunar/launcher/feeds/WidgetHostView.kt index 847f2d69..b71497a4 100644 --- a/app/src/main/kotlin/rasel/lunar/launcher/feeds/WidgetHostView.kt +++ b/app/src/main/kotlin/rasel/lunar/launcher/feeds/WidgetHostView.kt @@ -36,7 +36,6 @@ internal class WidgetHostView(context: Context) : AppWidgetHostView(context) { hasPerformedLongPress = false return true } - // Watch for long press events at this level to make sure // users can always pick up this widget when (ev.action) { diff --git a/app/src/main/kotlin/rasel/lunar/launcher/helpers/UniUtils.kt b/app/src/main/kotlin/rasel/lunar/launcher/helpers/UniUtils.kt index e6d785af..ba1ecf32 100644 --- a/app/src/main/kotlin/rasel/lunar/launcher/helpers/UniUtils.kt +++ b/app/src/main/kotlin/rasel/lunar/launcher/helpers/UniUtils.kt @@ -212,11 +212,11 @@ internal class UniUtils { (iconSize * resources.displayMetrics.density).toInt(), 1F) }.let { sImageView -> context.packageManager.getApplicationIcon(packageName).let { defaultIcon -> - sImageView.setImageDrawable( if (context.getSharedPreferences(PREFS_SETTINGS, 0).getInt(KEY_APPS_LAYOUT, 0) != 0) - getDrawableIconForPackage(packageName, defaultIcon) - else defaultIcon - ) + getDrawableIconForPackage(packageName, defaultIcon) { + sImageView.setImageDrawable(it ?: defaultIcon) + } + else sImageView.setImageDrawable(defaultIcon) } sImageView.setOnClickListener { context.startActivity(context.packageManager.getLaunchIntentForPackage(packageName)) diff --git a/app/src/main/kotlin/rasel/lunar/launcher/home/BatteryReceiver.kt b/app/src/main/kotlin/rasel/lunar/launcher/home/BatteryReceiver.kt index 0ff32f5b..a24b1fa4 100644 --- a/app/src/main/kotlin/rasel/lunar/launcher/home/BatteryReceiver.kt +++ b/app/src/main/kotlin/rasel/lunar/launcher/home/BatteryReceiver.kt @@ -26,6 +26,7 @@ import android.provider.Settings import android.view.animation.AnimationUtils import com.google.android.material.progressindicator.CircularProgressIndicator import rasel.lunar.launcher.R +import rasel.lunar.launcher.utils.BLog internal class BatteryReceiver(private val progressBar: CircularProgressIndicator) : BroadcastReceiver() { @@ -42,7 +43,14 @@ internal class BatteryReceiver(private val progressBar: CircularProgressIndicato override fun onReceive(context: Context?, intent: Intent?) { val animationDuration = try { - Settings.Global.getFloat(context?.contentResolver, Settings.Global.ANIMATOR_DURATION_SCALE) + intent?.extras?.keySet()?.let { + it.iterator().forEach { + BLog.LOGE("intent key >> ${it}") + } + } + BLog.LOGE("intent >> ${intent}") + + Settings.Global.getFloat(context?.contentResolver, Settings.Global.ANIMATOR_DURATION_SCALE, 1.0f) } catch (e: Settings.SettingNotFoundException) { e.printStackTrace() } diff --git a/app/src/main/kotlin/rasel/lunar/launcher/home/LauncherHome.kt b/app/src/main/kotlin/rasel/lunar/launcher/home/LauncherHome.kt index 1d678cd2..d9f838f2 100644 --- a/app/src/main/kotlin/rasel/lunar/launcher/home/LauncherHome.kt +++ b/app/src/main/kotlin/rasel/lunar/launcher/home/LauncherHome.kt @@ -134,12 +134,7 @@ internal class LauncherHome : Fragment() { gestureDistance: Double ): Boolean { when(fingers) { - 1 -> - if (targetView?.equals(binding.batteryProgress) ?: false) { - QuickAccess().show(fragManager, BOTTOM_SHEET_TAG) - } else { - QuickAccess().show(fragManager, BOTTOM_SHEET_TAG) - } + 3 -> QuickAccess().show(fragManager, BOTTOM_SHEET_TAG) 2->{ var startIntene = Intent(Intent.ACTION_MAIN) startIntene.setComponent(ComponentName("com.mime.dualscreenview","com.mime.dualscreenview.activity.Intro")) @@ -215,11 +210,7 @@ internal class LauncherHome : Fragment() { override fun onDoubleTap(targetView: View,fingers: Int): Boolean { when(fingers) { - 1 -> if (targetView?.equals(binding.batteryProgress) ?: false) { - lockMethod(settingsPrefs.getInt(KEY_LOCK_METHOD, 0), requireContext(), binding.favAppsGroup) - } else { - lockMethod(settingsPrefs.getInt(KEY_LOCK_METHOD, 0), requireContext(), binding.favAppsGroup) - } + 1 -> lockMethod(settingsPrefs.getInt(KEY_LOCK_METHOD, 0), requireContext(), binding.favAppsGroup) else -> {} } return false diff --git a/app/src/main/kotlin/rasel/lunar/launcher/home/weather/WeatherExecutor.kt b/app/src/main/kotlin/rasel/lunar/launcher/home/weather/WeatherExecutor.kt index 657fbedc..9e597e9c 100644 --- a/app/src/main/kotlin/rasel/lunar/launcher/home/weather/WeatherExecutor.kt +++ b/app/src/main/kotlin/rasel/lunar/launcher/home/weather/WeatherExecutor.kt @@ -35,6 +35,10 @@ import java.util.concurrent.Executors internal class WeatherExecutor(sharedPreferences: SharedPreferences) { + companion object { + var lastedCheckTime = 0L + } + private val cityName: String private val owmApi: String private val weatherUrl: String @@ -44,10 +48,9 @@ internal class WeatherExecutor(sharedPreferences: SharedPreferences) { @SuppressLint("SetTextI18n") fun generateWeatherString(materialTextView: MaterialTextView) { materialTextView.visibility = View.GONE - /* run the executor if network is available, and city name and owm api values are not empty */ - if (isNetworkAvailable && cityName.isNotEmpty() && owmApi.isNotEmpty()) { + if (System.currentTimeMillis() - lastedCheckTime > (1000 * 60 * 15) && isNetworkAvailable && cityName.isNotEmpty() && owmApi.isNotEmpty()) { try { Executors.newSingleThreadExecutor().execute { var weather: Weather? = null @@ -70,6 +73,7 @@ internal class WeatherExecutor(sharedPreferences: SharedPreferences) { exception.printStackTrace() } } + lastedCheckTime = System.currentTimeMillis() } init { @@ -77,7 +81,7 @@ internal class WeatherExecutor(sharedPreferences: SharedPreferences) { owmApi = sharedPreferences.getString(KEY_OWM_API, "").toString() tempUnit = sharedPreferences.getInt(KEY_TEMP_UNIT, 0) showCity = sharedPreferences.getBoolean(KEY_SHOW_CITY, false) - weatherUrl = URLEncoder.encode("https://api.openweathermap.org/data/2.5/weather?q=$cityName&APPID=$owmApi&units=" + if (tempUnit == 0) "metric" else "imperial","utf-8") + weatherUrl = "https://api.openweathermap.org/data/2.5/weather?q=$cityName&APPID=$owmApi&units=" + if (tempUnit == 0) "metric" else "imperial" } } diff --git a/app/src/main/kotlin/rasel/lunar/launcher/settings/childs/Apps.kt b/app/src/main/kotlin/rasel/lunar/launcher/settings/childs/Apps.kt index 6ffad637..653848db 100644 --- a/app/src/main/kotlin/rasel/lunar/launcher/settings/childs/Apps.kt +++ b/app/src/main/kotlin/rasel/lunar/launcher/settings/childs/Apps.kt @@ -127,7 +127,7 @@ internal class Apps : BottomSheetDialogFragment() { Gravity.RIGHT -> binding.appAlignmentRight.isChecked = true } - binding.columnsCount.value = settingsPrefs!!.getInt(KEY_GRID_COLUMNS, DEFAULT_GRID_COLUMNS).toFloat() + binding.columnsCount.value = Math.min(settingsPrefs!!.getInt(KEY_GRID_COLUMNS, DEFAULT_GRID_COLUMNS).toFloat(), 4f) binding.scrollbarHeight.value = settingsPrefs!!.getInt(KEY_SCROLLBAR_HEIGHT, DEFAULT_SCROLLBAR_HEIGHT).toFloat() return binding.root diff --git a/app/src/main/res/layout/app_drawer.xml b/app/src/main/res/layout/app_drawer.xml index 947afeac..e85e2c93 100644 --- a/app/src/main/res/layout/app_drawer.xml +++ b/app/src/main/res/layout/app_drawer.xml @@ -7,37 +7,39 @@ - + + + + + + + + + + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent"/> diff --git a/app/src/main/res/layout/apps_child.xml b/app/src/main/res/layout/apps_child.xml index dca3e351..25c3e256 100644 --- a/app/src/main/res/layout/apps_child.xml +++ b/app/src/main/res/layout/apps_child.xml @@ -1,30 +1,40 @@ - - + + + android:layout_marginBottom="@dimen/four" + android:layout_height="match_parent" /> - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/settings_apps.xml b/app/src/main/res/layout/settings_apps.xml index bd40b197..435512ef 100644 --- a/app/src/main/res/layout/settings_apps.xml +++ b/app/src/main/res/layout/settings_apps.xml @@ -231,8 +231,8 @@ android:id="@+id/columnsCount" android:layout_width="@dimen/zero" android:layout_height="wrap_content" - android:valueFrom="3" - android:valueTo="7" + android:valueFrom="2" + android:valueTo="5" android:stepSize="1" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent"