From bdb6a57a55c86e7cce1f442294d3e4154196334d Mon Sep 17 00:00:00 2001 From: lunaticbum <> Date: Thu, 22 Aug 2024 11:54:56 +0900 Subject: [PATCH] ... --- .../rasel/lunar/launcher/apps/AppDrawer.kt | 210 ++++++++++-------- .../lunar/launcher/apps/ContactAdapter.kt | 2 +- .../rasel/lunar/launcher/apps/ContactMenu.kt | 81 ++----- app/src/main/res/drawable/coupang.png | Bin 0 -> 12642 bytes app/src/main/res/layout/app_drawer.xml | 14 +- app/src/main/res/layout/contact_menu.xml | 144 ++++++++++++ 6 files changed, 294 insertions(+), 157 deletions(-) create mode 100644 app/src/main/res/drawable/coupang.png create mode 100644 app/src/main/res/layout/contact_menu.xml 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 95707404..8f149af2 100644 --- a/app/src/main/kotlin/rasel/lunar/launcher/apps/AppDrawer.kt +++ b/app/src/main/kotlin/rasel/lunar/launcher/apps/AppDrawer.kt @@ -28,6 +28,8 @@ import android.content.pm.ResolveInfo import android.net.Uri import android.os.Build import android.os.Bundle +import android.os.Handler +import android.os.Looper import android.provider.ContactsContract import android.util.Log import android.view.Gravity @@ -148,6 +150,12 @@ internal class AppDrawer : Fragment() { binding.searchTranslate.setOnClickListener { openSearchApps("https://translate.google.com/?hl=ko&sl=ko&tl=en&text=${getInputText()}&op=translate","com.android.chrome") } + + binding.searchCoupang.setOnClickListener { + openSearchApps("coupang://search?q=${getInputText()}","com.coupang.mobile") + } + + setLayout() return binding.root @@ -223,13 +231,65 @@ internal class AppDrawer : Fragment() { // false -> openSearch() // } // } - + binding.searchInput.setOnKeyListener { v, keyCode, event -> + BLog.LOGE("v == ${v}, keyCode == ${keyCode}, event == ${event}") + if (keyCode==66) { checkResult() } + return@setOnKeyListener true + } binding.searchInput.doOnTextChanged { inputText, _, _, _ -> binding.searchInput.text?.let { binding.searchInput.setSelection(it.length) } filterAppsList(inputText.toString()) } } + fun checkResult() { + if (lastSearchString.length > 0 && packageList.size == 1) { + var dialog = AlertDialog.Builder(requireContext()) + dialog.setTitle("앱 실행 확인") + dialog.setMessage("${lastSearchString} 검색 결과 '${packageList[0].appName}' 준비됨") + dialog.setCancelable(false) + dialog.setNegativeButton("취소") { s,d-> + s.dismiss() + } + dialog.setPositiveButton("실행") { s, d -> + startActivity(packageManager?.getLaunchIntentForPackage(packageList[0].packageName)) + s.dismiss() + } + dialog.show() + } else if (packageList.size == 0 && contactList.size == 1) { + var dialog = AlertDialog.Builder(requireContext()) + dialog.setTitle("연락처 실행 확인") + dialog.setMessage("${lastSearchString} 검색 결과 '${contactList[0].name}' 준비됨") + dialog.setCancelable(false) + dialog.setNegativeButton("취소") { s,d-> + s.dismiss() + } + dialog.setPositiveButton("실행") { s, d -> + ContactMenu().show(childFragmentManager, contactList[0].id.toString()) + s.dismiss() + } + dialog.show() + } else { + var dialog = AlertDialog.Builder(requireContext()) + dialog.setTitle("검색 실행 확인") + dialog.setMessage("${lastSearchString} 검색 준비됨") + dialog.setCancelable(true) + dialog.setNegativeButton("네이버 지도 검색") { s,d-> + s.dismiss() + binding.searchNmap.performClick() + } + dialog.setNeutralButton("쿠팡 검색") { s,d-> + s.dismiss() + binding.searchCoupang.performClick() + } + dialog.setPositiveButton("구글 검색") { s, d -> + s.dismiss() + binding.searchGoogle.performClick() + + } + dialog.show() + } + } override fun onResume() { super.onResume() @@ -246,7 +306,18 @@ internal class AppDrawer : Fragment() { contactAdapter?.updateData(contactList) /* pop up the keyboard */ - if (settingsPrefs!!.getBoolean(KEY_KEYBOARD_SEARCH, false)) openSearch() + openSearch() + + + chechHandler.postDelayed(cancelSearch, 3000L) + } + + val chechHandler = Handler(Looper.getMainLooper()) + val cancelSearch = Runnable { timerCheck() } + + private fun timerCheck() { + + lActivity?.onBackPressed() } override fun onPause() { @@ -271,62 +342,30 @@ internal class AppDrawer : Fragment() { /* update app list with app and package name */ fun fetchApps() { - if (oringinPackageList.size > 0) { - packageList.clear() - for(pkg in oringinPackageList) { - packageList.add(pkg) - } - } else { - packageList.clear() - oringinPackageList.clear() - 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) } - - forEach { - oringinPackageList.add( - Packages( - it.activityInfo.packageName, - appName(it), - getCategory(it.activityInfo.applicationInfo.category) - ) - ) - packageList.add( - Packages( - it.activityInfo.packageName, - appName(it), - getCategory(it.activityInfo.applicationInfo.category) - ) - ) - } - }!! - } - /* add package and app names to the list */ - -// var edit = appNamesPrefs?.edit() -// for (resolver in packageInfoList) { -// packageList.add(Packages(resolver.activityInfo.packageName, appName(resolver))) -// } + packageList.clear() + oringinPackageList.clear() + 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) } + forEach { oringinPackageList.add(Packages(it.activityInfo.packageName, normalize(appName(it)), getCategory(it.activityInfo.applicationInfo.category))) } + oringinPackageList.sortBy { it.appName } + packageList.addAll( + oringinPackageList + ) + binding.appsList.post { if (packageList.size > 0) { + appsAdapter?.updateData(packageList) + } } + }!! } -// when { -// packageList.size < 1 -> return -// else -> { - if (packageList.size > 0) { - MainScope().launch { - appsAdapter?.updateData(packageList) - } - } -// } - } private fun getAlphabetItems() { @@ -357,8 +396,9 @@ internal class AppDrawer : Fragment() { var lastSearchStringLength = 0 var lastSearchString : String = "" private fun filterAppsList(searchString: String) { + chechHandler.removeCallbacks(cancelSearch) /* check each app name and add if it matches the search string */ - if (lastSearchStringLength > 0 && (lastSearchStringLength != searchString.length || lastSearchString.equals(searchString) == false)) { + if (searchString.length > 0 && (lastSearchStringLength != searchString.length || lastSearchString.equals(searchString) == false)) { BLog.LOGE("START FILTER") packageList.clear() for (pkg in oringinPackageList) { @@ -367,51 +407,41 @@ internal class AppDrawer : Fragment() { packageList.add(pkg) } } + packageList.sortBy { it.appName } 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) - } + contactList.clear() for (item in originContactList) { if (item.name.contains(searchString) || item.phoneNumber.contains(searchString)) { contactList.add(item) } } + contactList.sortBy { it.name } contactAdapter?.updateData(contactList) BLog.LOGE("END FILTER") - } else if(lastSearchStringLength == 0){ - contactList.clear() - for (item in originContactList) { - contactList.add(item) - } - packageList.clear() - for (resolver in oringinPackageList) { - packageList.add(resolver) - } - appsAdapter?.updateData(packageList) - contactAdapter?.updateData(contactList) + } else { + afterClearSearch() } lastSearchString = searchString lastSearchStringLength = searchString.length + chechHandler.postDelayed(cancelSearch, 3000L) + } + + private fun afterClearSearch() { + contactList.clear() + packageList.clear() + for (item in originContactList) { + contactList.add(item) + } + for (resolver in oringinPackageList) { + packageList.add(resolver) + } + packageList.sortBy { it.appName } + contactList.sortBy { it.name } + appsAdapter?.updateData(packageList) + contactAdapter?.updateData(contactList) } private fun normalize(str: String): String { diff --git a/app/src/main/kotlin/rasel/lunar/launcher/apps/ContactAdapter.kt b/app/src/main/kotlin/rasel/lunar/launcher/apps/ContactAdapter.kt index ba93ddcd..37ac76c5 100644 --- a/app/src/main/kotlin/rasel/lunar/launcher/apps/ContactAdapter.kt +++ b/app/src/main/kotlin/rasel/lunar/launcher/apps/ContactAdapter.kt @@ -70,7 +70,7 @@ internal class ContactAdapter ( holder.view.root.apply { /* on click - open app */ setOnClickListener { - context.startActivity(Intent(Intent.ACTION_DIAL, Uri.parse("tel://${item.phoneNumber}"))) + ContactMenu().show(fragmentManager, item.id.toString()) } /* on long click - open app menu */ diff --git a/app/src/main/kotlin/rasel/lunar/launcher/apps/ContactMenu.kt b/app/src/main/kotlin/rasel/lunar/launcher/apps/ContactMenu.kt index 233f46fd..8fd934a4 100644 --- a/app/src/main/kotlin/rasel/lunar/launcher/apps/ContactMenu.kt +++ b/app/src/main/kotlin/rasel/lunar/launcher/apps/ContactMenu.kt @@ -58,6 +58,7 @@ import rasel.lunar.launcher.apps.AppDrawer.Companion.appNamesPrefs import rasel.lunar.launcher.databinding.ActivityBrowserDialogBinding import rasel.lunar.launcher.databinding.AppInfoDialogBinding import rasel.lunar.launcher.databinding.AppMenuBinding +import rasel.lunar.launcher.databinding.ContactMenuBinding import rasel.lunar.launcher.helpers.Constants.Companion.KEY_APP_NO_ import rasel.lunar.launcher.helpers.Constants.Companion.MAX_FAVORITE_APPS import rasel.lunar.launcher.helpers.Constants.Companion.PREFS_FAVORITE_APPS @@ -74,14 +75,15 @@ import java.util.* internal class ContactMenu : BottomSheetDialogFragment() { - private lateinit var binding: AppMenuBinding + private lateinit var binding: ContactMenuBinding private lateinit var packageName: String private lateinit var packageManager: PackageManager private lateinit var appInfo: ApplicationInfo private lateinit var defAppName: String - + var contactName : String = "" + var contactPhoneNumber : String = "" override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { - binding = AppMenuBinding.inflate(inflater, container, false) + binding = ContactMenuBinding.inflate(inflater, container, false) /* get package name from fragment's tag */ packageName = tag.toString() @@ -96,14 +98,12 @@ internal class ContactMenu : BottomSheetDialogFragment() { val cursor = resolver.query(phoneUri, projection, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = " + packageName, null , null) if (cursor != null) { while (cursor.moveToNext()) { -// val idx =cursor.getColumnIndex(projection[0]) val nameIndex = cursor.getColumnIndex(projection[0]) val numberIndex = cursor.getColumnIndex(projection[1]) -// var contactId = cursor.getInt(idx) - val name = cursor.getString(nameIndex) + contactName = cursor.getString(nameIndex) var number = cursor.getString(numberIndex) - number = number.replace("-", "") - BLog.LOGE("GetContact", "이름 : $name 번호 : $number ") + contactPhoneNumber = number.replace("-", "") + BLog.LOGE("GetContact", "이름 : $contactName 번호 : $contactPhoneNumber ") } } // 데이터 계열은 반드시 닫아줘야 한다. @@ -124,8 +124,8 @@ internal class ContactMenu : BottomSheetDialogFragment() { // copyToClipboard(requireContext(), packageName) // } // -// appName() -// binding.detailedInfo.setOnClickListener { detailedInfo() } + appName() + binding.detailedInfo.setOnClickListener { detailedInfo() } // binding.activityBrowser.setOnClickListener { activityBrowser() } // binding.appStore.setOnClickListener { appStore() } // binding.appFreeform.setOnClickListener { freeform() } @@ -165,7 +165,7 @@ internal class ContactMenu : BottomSheetDialogFragment() { /* listen on clicks */ binding.favGroup.addOnButtonCheckedListener { _: MaterialButtonToggleGroup?, - checkedId: Int, isChecked: Boolean -> + checkedId: Int, isChecked: Boolean -> try { if (checkedId == button.id) { if (isChecked) { @@ -186,66 +186,17 @@ internal class ContactMenu : BottomSheetDialogFragment() { } private fun appName() { - binding.appName.setOnFocusChangeListener { _, hasFocus -> - if (hasFocus) binding.appName.minWidth = resources.getDimensionPixelOffset(R.dimen.twoSeventySix) - else { - (requireContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager) - .hideSoftInputFromWindow(binding.appName.windowToken, 0) - - binding.appName.apply { - minWidth = resources.getDimensionPixelOffset(R.dimen.zero) - - if (text!!.isBlank()) setText(defAppName) - else setText(text!!.trim()) - - if (text.toString() == defAppName) appNamesPrefs?.edit()!!.remove(packageName).apply() - else appNamesPrefs?.edit()!!.putString(packageName, text.toString()).apply() - - (requireParentFragment() as AppDrawer).fetchApps() - } - } - } - - binding.appName.setOnKeyListener { _, keyCode, event -> - if (event.action == KeyEvent.ACTION_DOWN) { - if (keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_BACK) { - binding.appName.clearFocus() - return@setOnKeyListener true - } - } - false - } + binding.appName.text = contactName + binding.phoneNumber.text = contactPhoneNumber } /* detailed info dialog */ @SuppressLint("SetTextI18n") private fun detailedInfo() { - val dialogBinding = AppInfoDialogBinding.inflate(lActivity!!.layoutInflater) - MaterialAlertDialogBuilder(lActivity!!) - .setView(dialogBinding.root) - .setPositiveButton(android.R.string.cancel, null) - .show() + var intent = Intent(Intent.ACTION_VIEW); + intent.setData(Uri.parse(ContactsContract.Contacts.CONTENT_URI.toString() + "/" + packageName)); + startActivity(intent); - /* show app name */ - dialogBinding.appName.text = packageManager.getApplicationLabel(appInfo) - - /* get package info */ - val packageInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - packageManager.getPackageInfo(packageName, PackageManager.PackageInfoFlags.of(0)) - } else { - packageManager.getPackageInfo(packageName, 0) - } - - /* show infos */ - dialogBinding.mixed.text = - "${resources.getString(R.string.version)}: ${packageInfo.versionName} (${PackageInfoCompat.getLongVersionCode(packageInfo).toInt()})\n" + - "${resources.getString(R.string.sdk)}: ${appInfo.minSdkVersion} ~ ${appInfo.targetSdkVersion}\n" + - "${resources.getString(R.string.uid)}: ${appInfo.uid}\n" + - "${resources.getString(R.string.first_install)}: ${dateTimeFormat(packageInfo.firstInstallTime)}\n" + - "${resources.getString(R.string.last_update)}: ${dateTimeFormat(packageInfo.lastUpdateTime)}" - - /* show permissions */ - dialogBinding.permissions.text = permissionsList } /* activity browser dialog */ diff --git a/app/src/main/res/drawable/coupang.png b/app/src/main/res/drawable/coupang.png new file mode 100644 index 0000000000000000000000000000000000000000..3ca44f429bd7dd777622f0145408f32464bea30f GIT binary patch literal 12642 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file