From 4bac8ffee884c9681bfc8af8f70ff38807274e09 Mon Sep 17 00:00:00 2001 From: ottoptj Date: Thu, 8 Aug 2024 22:21:21 +0300 Subject: [PATCH] Refactored MainActivity a bunch --- .../java/eu/ottop/yamlauncher/Animations.kt | 7 +- .../eu/ottop/yamlauncher/AppActionMenu.kt | 4 +- .../yamlauncher/AppMenuLinearLayoutManager.kt | 2 +- .../java/eu/ottop/yamlauncher/AppUtils.kt | 44 +- .../ottop/yamlauncher/GestureAppsFragment.kt | 7 +- .../java/eu/ottop/yamlauncher/GestureUtils.kt | 65 + .../java/eu/ottop/yamlauncher/MainActivity.kt | 1077 ++++++----------- .../main/java/eu/ottop/yamlauncher/UIUtils.kt | 201 ++- app/src/main/res/layout/fragment_about.xml | 2 +- app/src/main/res/layout/fragment_location.xml | 4 +- app/src/main/res/values/strings.xml | 54 +- 11 files changed, 690 insertions(+), 777 deletions(-) create mode 100644 app/src/main/java/eu/ottop/yamlauncher/GestureUtils.kt diff --git a/app/src/main/java/eu/ottop/yamlauncher/Animations.kt b/app/src/main/java/eu/ottop/yamlauncher/Animations.kt index 2b42064..ba1cd6c 100644 --- a/app/src/main/java/eu/ottop/yamlauncher/Animations.kt +++ b/app/src/main/java/eu/ottop/yamlauncher/Animations.kt @@ -6,6 +6,7 @@ import android.animation.ArgbEvaluator import android.animation.ObjectAnimator import android.animation.ValueAnimator import android.app.Activity +import android.content.SharedPreferences import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.view.View @@ -32,7 +33,8 @@ class Animations () { binding.homeView.fadeOut() } - fun backgroundIn(activity: Activity, originalColor: Int, duration: Long = 100) { + fun backgroundIn(activity: Activity, preferences: SharedPreferences, duration: Long = 100) { + val originalColor = Color.parseColor(preferences.getString("bgColor", "#00000000")) val newColor: Int = if (originalColor == Color.parseColor("#00000000")) { Color.parseColor("#3F000000") @@ -52,7 +54,8 @@ class Animations () { backgroundColorAnimator.start() } - fun backgroundOut(activity: Activity, newColor: Int, duration: Long = 100) { + fun backgroundOut(activity: Activity, preferences: SharedPreferences, duration: Long = 100) { + val newColor = Color.parseColor(preferences.getString("bgColor", "#00000000")) val originalColor: Int = if (newColor == Color.parseColor("#00000000")) { Color.parseColor("#3F000000") diff --git a/app/src/main/java/eu/ottop/yamlauncher/AppActionMenu.kt b/app/src/main/java/eu/ottop/yamlauncher/AppActionMenu.kt index 56b21c8..869f080 100644 --- a/app/src/main/java/eu/ottop/yamlauncher/AppActionMenu.kt +++ b/app/src/main/java/eu/ottop/yamlauncher/AppActionMenu.kt @@ -126,9 +126,7 @@ class AppActionMenu { ) CoroutineScope(Dispatchers.Default).launch { - CoroutineScope(Dispatchers.Default).launch { - activity.applySearch() - } + activity.applySearch() } } } diff --git a/app/src/main/java/eu/ottop/yamlauncher/AppMenuLinearLayoutManager.kt b/app/src/main/java/eu/ottop/yamlauncher/AppMenuLinearLayoutManager.kt index 000ab90..61e3d08 100644 --- a/app/src/main/java/eu/ottop/yamlauncher/AppMenuLinearLayoutManager.kt +++ b/app/src/main/java/eu/ottop/yamlauncher/AppMenuLinearLayoutManager.kt @@ -17,7 +17,7 @@ class AppMenuLinearLayoutManager(private val activity: MainActivity) : LinearLay val scrollRange = super.scrollVerticallyBy(dy, recycler, state) val overscroll: Int = dy - scrollRange - if (overscroll < 0 && firstVisibleItemPosition == 0 && scrollStarted && activity.isJobActive()) { + if (overscroll < 0 && firstVisibleItemPosition == 0 && scrollStarted && activity.isJobActive) { activity.backToHome() } diff --git a/app/src/main/java/eu/ottop/yamlauncher/AppUtils.kt b/app/src/main/java/eu/ottop/yamlauncher/AppUtils.kt index eb69186..24c7420 100644 --- a/app/src/main/java/eu/ottop/yamlauncher/AppUtils.kt +++ b/app/src/main/java/eu/ottop/yamlauncher/AppUtils.kt @@ -1,30 +1,48 @@ package eu.ottop.yamlauncher import android.app.Activity +import android.content.Context import android.content.pm.ApplicationInfo import android.content.pm.LauncherActivityInfo import android.content.pm.LauncherApps import android.os.UserHandle +import android.widget.Toast import androidx.appcompat.app.AppCompatActivity +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext import java.lang.reflect.InvocationTargetException class AppUtils { private val sharedPreferenceManager = SharedPreferenceManager() - fun getInstalledApps(activity: Activity, launcherApps: LauncherApps): List>> { + suspend fun getInstalledApps(activity: Activity, launcherApps: LauncherApps): List>> { val allApps = mutableListOf>>() - - for (i in launcherApps.profiles.indices) { - launcherApps.getActivityList(null, launcherApps.profiles[i]).forEach { app -> - if (!sharedPreferenceManager.isAppHidden(activity, app.applicationInfo.packageName, i) && app.applicationInfo.packageName != activity.applicationInfo.packageName) { - allApps.add(Pair(app, Pair(launcherApps.profiles[i], i))) + var sortedApps = listOf>>() + withContext(Dispatchers.Default) { + for (i in launcherApps.profiles.indices) { + launcherApps.getActivityList(null, launcherApps.profiles[i]).forEach { app -> + if (!sharedPreferenceManager.isAppHidden( + activity, + app.applicationInfo.packageName, + i + ) && app.applicationInfo.packageName != activity.applicationInfo.packageName + ) { + allApps.add(Pair(app, Pair(launcherApps.profiles[i], i))) + } } } + + sortedApps = allApps.sortedBy { + sharedPreferenceManager.getAppName( + activity, + it.first.applicationInfo.packageName, + it.second.second, + it.first.applicationInfo.loadLabel(activity.packageManager) + ).toString().lowercase() + } } - return allApps.sortedBy { - sharedPreferenceManager.getAppName(activity, it.first.applicationInfo.packageName,it.second.second, it.first.applicationInfo.loadLabel(activity.packageManager)).toString().lowercase() - } + return sortedApps } @@ -53,6 +71,14 @@ class AppUtils { } catch (_: Exception) { null } + } + fun launchApp(context: Context, launcherApps: LauncherApps, appInfo: LauncherActivityInfo, userHandle: UserHandle) { + val mainActivity = launcherApps.getActivityList(appInfo.applicationInfo.packageName, userHandle).firstOrNull() + if (mainActivity != null) { + launcherApps.startMainActivity(mainActivity.componentName, userHandle, null, null) + } else { + Toast.makeText(context, "Cannot launch app", Toast.LENGTH_SHORT).show() + } } } \ No newline at end of file diff --git a/app/src/main/java/eu/ottop/yamlauncher/GestureAppsFragment.kt b/app/src/main/java/eu/ottop/yamlauncher/GestureAppsFragment.kt index c7b900e..71aa9d4 100644 --- a/app/src/main/java/eu/ottop/yamlauncher/GestureAppsFragment.kt +++ b/app/src/main/java/eu/ottop/yamlauncher/GestureAppsFragment.kt @@ -88,15 +88,16 @@ class GestureAppsFragment : Fragment(), GestureAppsAdapter.OnItemClickListener { } override fun afterTextChanged(s: Editable?) { - - filterItems(searchView.text.toString()) + lifecycleScope.launch { + filterItems(searchView.text.toString()) + } } }) } } - private fun filterItems(query: String?) { + private suspend fun filterItems(query: String?) { val cleanQuery = stringUtils.cleanString(query) val newFilteredApps = mutableListOf>>() diff --git a/app/src/main/java/eu/ottop/yamlauncher/GestureUtils.kt b/app/src/main/java/eu/ottop/yamlauncher/GestureUtils.kt new file mode 100644 index 0000000..4069819 --- /dev/null +++ b/app/src/main/java/eu/ottop/yamlauncher/GestureUtils.kt @@ -0,0 +1,65 @@ +package eu.ottop.yamlauncher + +import android.accessibilityservice.AccessibilityService +import android.accessibilityservice.AccessibilityServiceInfo +import android.app.AlertDialog +import android.content.Context +import android.content.Intent +import android.content.SharedPreferences +import android.content.pm.LauncherActivityInfo +import android.content.pm.LauncherApps +import android.content.pm.ServiceInfo +import android.provider.Settings +import android.view.accessibility.AccessibilityManager +import androidx.appcompat.app.AppCompatActivity.ACCESSIBILITY_SERVICE + +class GestureUtils { + fun getSwipeInfo(preferences: SharedPreferences, launcherApps: LauncherApps, direction: String): Pair { + val app = preferences.getString("${direction}SwipeApp", "")?.split("§splitter§") + + if (app != null) { + if (app.size >= 3) + + return Pair( + launcherApps.getActivityList( + app[1], launcherApps.profiles[app[2] + .toInt()] + ).firstOrNull(), app[2].toInt() + ) + } + return Pair(null, null) + } + + fun isAccessibilityServiceEnabled(context: Context, service: Class): Boolean { + val am = context.getSystemService(ACCESSIBILITY_SERVICE) as AccessibilityManager + val enabledServices = + am.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK) + + for (enabledService in enabledServices) { + val enabledServiceInfo: ServiceInfo = enabledService.resolveInfo.serviceInfo + if (enabledServiceInfo.packageName.equals(context.packageName) && enabledServiceInfo.name.equals( + service.name + ) + ) return true + } + + return false + } + + fun promptEnableAccessibility(context: Context) { + AlertDialog.Builder(context).apply { + setTitle("Confirmation") + setMessage("To lock with double tap, enable YAM Launcher in accessibility settings.") + setPositiveButton("Yes") { _, _ -> + // Perform action on confirmation + val intent = Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS) + intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK + context.startActivity(intent) + } + setNegativeButton("Cancel") { _, _ -> + + } + + }.create().show() + } +} \ No newline at end of file diff --git a/app/src/main/java/eu/ottop/yamlauncher/MainActivity.kt b/app/src/main/java/eu/ottop/yamlauncher/MainActivity.kt index cb9ab7c..f61e79d 100644 --- a/app/src/main/java/eu/ottop/yamlauncher/MainActivity.kt +++ b/app/src/main/java/eu/ottop/yamlauncher/MainActivity.kt @@ -1,38 +1,22 @@ package eu.ottop.yamlauncher -import android.accessibilityservice.AccessibilityService -import android.accessibilityservice.AccessibilityServiceInfo import android.annotation.SuppressLint -import android.app.AlertDialog import android.content.Context import android.content.Intent import android.content.SharedPreferences import android.content.pm.LauncherActivityInfo import android.content.pm.LauncherApps -import android.content.pm.ServiceInfo -import android.graphics.BlendMode -import android.graphics.BlendModeColorFilter -import android.graphics.Color -import android.graphics.drawable.ColorDrawable import android.os.Build import android.os.Bundle import android.os.Handler import android.os.Looper import android.os.UserHandle -import android.provider.Settings import android.text.Editable import android.text.TextWatcher import android.view.GestureDetector import android.view.Gravity import android.view.MotionEvent import android.view.View -import android.view.View.TEXT_ALIGNMENT_CENTER -import android.view.View.TEXT_ALIGNMENT_TEXT_END -import android.view.View.TEXT_ALIGNMENT_TEXT_START -import android.view.ViewTreeObserver -import android.view.WindowInsets -import android.view.WindowInsetsController -import android.view.accessibility.AccessibilityManager import android.view.inputmethod.InputMethodManager import android.widget.LinearLayout import android.widget.TextClock @@ -42,19 +26,15 @@ import androidx.activity.OnBackPressedCallback import androidx.annotation.RequiresApi import androidx.appcompat.app.AppCompatActivity import androidx.core.content.res.ResourcesCompat -import androidx.core.view.children import androidx.core.view.marginLeft import androidx.lifecycle.Lifecycle -import androidx.lifecycle.LifecycleCoroutineScope import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import androidx.preference.PreferenceManager import androidx.recyclerview.widget.RecyclerView import com.google.android.material.textfield.TextInputEditText import eu.ottop.yamlauncher.databinding.ActivityMainBinding -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -73,8 +53,6 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh private lateinit var recyclerView: RecyclerView private lateinit var searchView: TextInputEditText private var adapter: AppMenuAdapter? = null - private var job: Job? = null - private var weatherJob: Job? = null private var batteryReceiver: BatteryReceiver? = null private var appActionMenu = AppActionMenu() @@ -100,50 +78,52 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh private val weatherSystem = WeatherSystem() - private val uiUtils = UIUtils() + private lateinit var uiUtils: UIUtils + private lateinit var gestureUtils: GestureUtils private var isBatteryReceiverRegistered = false private lateinit var leftSwipeActivity: Pair private lateinit var rightSwipeActivity: Pair - private var windowInsetsController: WindowInsetsController? = null + var isJobActive = true - @SuppressLint("ClickableViewAccessibility") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) setSupportActionBar(null) - preferences = PreferenceManager.getDefaultSharedPreferences(this) + setMainVariables() - preferences.registerOnSharedPreferenceChangeListener(this) + setPreferences() + setShortcuts() - window.decorView.setBackgroundColor( - Color.parseColor(preferences.getString("bgColor", "#00000000")) - ) + setHomeListeners() - windowInsetsController = window.insetsController - - windowInsetsController?.let { - if (preferences.getBoolean("barVisibility", false)) { - it.show(WindowInsets.Type.statusBars()) - } - else { - it.hide(WindowInsets.Type.statusBars()) - it.systemBarsBehavior = - WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE + lifecycleScope.launch { + lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { + while (true) { + refreshAppMenu() + delay(5000) + } } } - searchView = findViewById(R.id.searchView) + lifecycleScope.launch(Dispatchers.IO) { + repeatOnLifecycle(Lifecycle.State.STARTED) { + while (true) { + updateWeather() + delay(600000) + } + } + } - launcherApps = getSystemService(Context.LAUNCHER_APPS_SERVICE) as LauncherApps + setupApps() - leftSwipeActivity = getSwipeInfo("left") - rightSwipeActivity = getSwipeInfo("right") + } + private fun setMainVariables() { gestureDetector = GestureDetector(this, GestureListener()) shortcutGestureDetector = GestureDetector(this, TextGestureListener()) @@ -155,36 +135,136 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh dateElements = mutableListOf(dateText.format12Hour.toString(), dateText.format24Hour.toString(), "", "") - setClockAlignment(preferences.getString("clockAlignment", "left")) + searchView = findViewById(R.id.searchView) - setupApps() + launcherApps = getSystemService(Context.LAUNCHER_APPS_SERVICE) as LauncherApps - setShortcutAlignment(preferences.getString("shortcutAlignment", "left"), binding.homeView) + preferences = PreferenceManager.getDefaultSharedPreferences(this) + uiUtils = UIUtils() + gestureUtils = GestureUtils() + } - setSearchAlignment(preferences.getString("searchAlignment", "left")) + private fun setPreferences() { + uiUtils.setBackground(window, preferences) + uiUtils.setTextColors(preferences, binding.homeView) + uiUtils.setSearchColors(preferences, searchView) - setClockSize(preferences.getString("clockSize","medium")) + uiUtils.setClockAlignment(preferences, clock, dateText) + uiUtils.setSearchAlignment(preferences, searchView) - setDateSize(preferences.getString("dateSize", "medium")) + uiUtils.setClockSize(preferences, clock) + uiUtils.setDateSize(preferences, dateText) + uiUtils.setShortcutSize(preferences, binding.homeView) + uiUtils.setSearchSize(preferences, searchView) - setShortcutSize(binding.homeView) + uiUtils.setStatusBar(window, preferences) - setSearchSize(preferences.getString("searchSize", "medium")) + leftSwipeActivity = gestureUtils.getSwipeInfo(preferences, launcherApps, "left") + rightSwipeActivity = gestureUtils.getSwipeInfo(preferences, launcherApps, "right") + } - setSearchColors() + private fun setShortcuts() { + val shortcuts = arrayOf(R.id.app1, R.id.app2, R.id.app3, R.id.app4, R.id.app5, R.id.app6, R.id.app7, R.id.app8) - uiUtils.setAllColors(binding.homeView, Color.parseColor(preferences.getString("textColor", "#FFF3F3F3"))) + for (i in shortcuts.indices) { + val textView = findViewById(shortcuts[i]) + + val shortcutNo = preferences.getString("shortcutNo", "4")?.toInt() + + if (i >= shortcutNo!!) { + textView.visibility = View.GONE + } + + else { + textView.visibility = View.VISIBLE + + unsetShortcutSetup(textView) + + val savedView = sharedPreferenceManager.getShortcut(this, textView) + + if (savedView?.get(1) != "e") { + setShortcutSetup(textView, savedView) + } + + uiUtils.setShortcutAlignment(preferences, binding.homeView) + } + + } + + } + + @SuppressLint("ClickableViewAccessibility") + private fun unsetShortcutSetup(textView: TextView) { + textView.setOnTouchListener {_, event -> + shortcutGestureDetector.onTouchEvent(event) + super.onTouchEvent(event) + } + + textView.setCompoundDrawablesWithIntrinsicBounds(ResourcesCompat.getDrawable(resources, R.drawable.ic_empty, null),null,null,null) + + unsetShortcutListeners(textView) + } + + private fun unsetShortcutListeners(textView: TextView) { + textView.setOnClickListener { + Toast.makeText(this, "Long click to select an app", Toast.LENGTH_SHORT).show() + } + textView.setOnLongClickListener { + adapter?.shortcutTextView = textView + toAppMenu() + + return@setOnLongClickListener true + } + } + + private fun toAppMenu() { + animations.showApps(binding) + animations.backgroundIn(this@MainActivity, preferences) + if (preferences.getBoolean("autoKeyboard", false)) { + val imm = + getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + searchView.requestFocus() + imm.showSoftInput(searchView, InputMethodManager.SHOW_IMPLICIT) + } + } + + private fun setShortcutSetup(textView: TextView, savedView: List?) { + if (savedView?.get(1) != "0") { + textView.setCompoundDrawablesWithIntrinsicBounds(ResourcesCompat.getDrawable(resources, R.drawable.ic_work_app, null),null,null,null) + } + else { + textView.setCompoundDrawablesWithIntrinsicBounds(ResourcesCompat.getDrawable(resources, R.drawable.ic_empty, null),null,null,null) + } + textView.text = savedView?.get(2) + setShortcutListeners(textView, savedView) + } + + private fun setShortcutListeners(textView: TextView, savedView: List?) { + textView.setOnClickListener { + val mainActivity = launcherApps.getActivityList(savedView?.get(0).toString(), launcherApps.profiles[savedView?.get(1)!!.toInt()]).firstOrNull() + if (mainActivity != null) { + launcherApps.startMainActivity(mainActivity.componentName, launcherApps.profiles[savedView[1].toInt()], null, null) + } else { + Toast.makeText(this, "Cannot launch app", Toast.LENGTH_SHORT).show() + } + } + } + + @SuppressLint("ClickableViewAccessibility") + private fun setHomeListeners() { registerBatteryReceiver() if (!preferences.getBoolean("battery_enabled", false)) { unregisterBatteryReceiver() } + preferences.registerOnSharedPreferenceChangeListener(this) + binding.homeView.setOnTouchListener { _, event -> super.onTouchEvent(event) gestureDetector.onTouchEvent(event) - true // Return true if the touch event is handled + true } onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) { @@ -192,136 +272,6 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh backToHome() } }) - - lifecycleScope.launch(Dispatchers.IO) { - repeatOnLifecycle(Lifecycle.State.STARTED) { - while (true) { - updateWeather() - delay(600000) - } - } - } - - } - - private suspend fun updateWeather() { - withContext(Dispatchers.IO) { - if (preferences.getBoolean("weather_enabled", false)) { - if (preferences.getBoolean("gps_location", false)) { - weatherSystem.setGpsLocation(this@MainActivity) - } else { - - updateWeatherText() - } - } - } - } - - fun modifyDate(value: String, index: Int) { - dateElements[index] = value - dateText.format12Hour = "${dateElements[0]}${stringUtils.addStartTextIfNotEmpty(dateElements[2], " | ")}${stringUtils.addStartTextIfNotEmpty(dateElements[3], " | ")}" - dateText.format24Hour = "${dateElements[1]}${stringUtils.addStartTextIfNotEmpty(dateElements[2], " | ")}${stringUtils.addStartTextIfNotEmpty(dateElements[3], " | ")}" - } - - - - suspend fun updateWeatherText() { - val temp = weatherSystem.getTemp(this@MainActivity) - withContext(Dispatchers.Main) { - modifyDate(temp, 2) - } - } - - override fun onSharedPreferenceChanged(preferences: SharedPreferences?, key: String?) { - - when (key) { - "clockAlignment" -> { - setClockAlignment(preferences?.getString(key, "left")) - } - - "shortcutAlignment" -> { - setShortcutAlignment(preferences?.getString(key, "left"), binding.homeView) - } - - "searchAlignment" -> { - setSearchAlignment(preferences?.getString(key, "left")) - } - - "clockSize" -> { - setClockSize(preferences?.getString(key,"medium")) - } - - "dateSize" -> { - setDateSize(preferences?.getString(key, "medium")) - } - - "shortcutSize" -> { - setShortcutSize(binding.homeView) - } - - "searchSize" -> { - setSearchSize(preferences?.getString(key, "medium")) - } - - "bgColor" -> { - window.setBackgroundDrawable(ColorDrawable(Color.parseColor("#00000000"))) - window.decorView.setBackgroundColor( - Color.parseColor(preferences?.getString(key, "#00000000")) - ) - } - - "textColor" -> { - uiUtils.setAllColors(binding.homeView, Color.parseColor(preferences?.getString(key, "#FFF3F3F3"))) - setSearchColors() - } - - "weather_enabled" -> { - if (preferences?.getBoolean(key, false) == true) { - lifecycleScope.launch { - updateWeather() - } - } - else { - weatherJob?.cancel() - modifyDate("", 2) - } - } - - "battery_enabled" -> { - if (preferences?.getBoolean(key, false) == true) { - registerBatteryReceiver() - } - else { - unregisterBatteryReceiver() - modifyDate("", 3) - } - } - - "leftSwipeApp" -> { - leftSwipeActivity = getSwipeInfo("left") - } - - "rightSwipeApp" -> { - rightSwipeActivity = getSwipeInfo("right") - } - - "barVisibility" -> { - windowInsetsController?.let { - if (preferences?.getBoolean("barVisibility", false) == true) { - it.show(WindowInsets.Type.statusBars()) - } - else { - it.hide(WindowInsets.Type.statusBars()) - it.systemBarsBehavior = - WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE - } - } - } - - "shortcutNo" -> { - handleListItems() - } - } } private fun registerBatteryReceiver() { @@ -338,196 +288,172 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh } } - private fun setSearchColors() { - val viewTreeObserver = searchView.viewTreeObserver - val globalLayoutListener = object : ViewTreeObserver.OnGlobalLayoutListener { - override fun onGlobalLayout() { - // Your code here - searchView.setTextColor(Color.parseColor(preferences.getString("textColor", "#FFF3F3F3"))) - searchView.setHintTextColor(uiUtils.setAlpha(Color.parseColor(preferences.getString("textColor", "#FFF3F3F3")), "A9")) - searchView.compoundDrawables[0].mutate().colorFilter = - BlendModeColorFilter(Color.parseColor(preferences.getString("textColor", "#FFF3F3F3")), BlendMode.SRC_ATOP) + override fun onSharedPreferenceChanged(preferences: SharedPreferences?, key: String?) { + if (preferences != null) { + when (key) { + "bgColor" -> { + uiUtils.setBackground(window, preferences) + } - // Remove the listener - if (viewTreeObserver.isAlive) { - viewTreeObserver.removeOnGlobalLayoutListener(this) + "textColor" -> { + uiUtils.setTextColors(preferences, binding.homeView) + uiUtils.setSearchColors(preferences, searchView) + } + + "clockAlignment" -> { + uiUtils.setClockAlignment(preferences, clock, dateText) + } + + "shortcutAlignment" -> { + uiUtils.setShortcutSize(preferences, binding.homeView) + } + + "searchAlignment" -> { + uiUtils.setSearchAlignment(preferences, searchView) + } + + "clockSize" -> { + uiUtils.setClockSize(preferences, clock) + } + + "dateSize" -> { + uiUtils.setDateSize(preferences, dateText) + } + + "shortcutSize" -> { + uiUtils.setShortcutSize(preferences, binding.homeView) + } + + "searchSize" -> { + uiUtils.setSearchSize(preferences, searchView) + } + + "barVisibility" -> { + uiUtils.setStatusBar(window, preferences) + } + + "leftSwipeApp" -> { + leftSwipeActivity = gestureUtils.getSwipeInfo(preferences, launcherApps, "left") + } + + "rightSwipeApp" -> { + rightSwipeActivity = gestureUtils.getSwipeInfo(preferences, launcherApps, "right") + } + + "battery_enabled" -> { + if (preferences.getBoolean(key, false)) { + registerBatteryReceiver() + } else { + unregisterBatteryReceiver() + modifyDate("", 3) + } + } + + "shortcutNo" -> { + setShortcuts() } } } - - if (viewTreeObserver.isAlive) { - viewTreeObserver.addOnGlobalLayoutListener(globalLayoutListener) - } } - override fun onNewIntent(intent: Intent) { - super.onNewIntent(intent) - backToHome() + fun modifyDate(value: String, index: Int) { + dateElements[index] = value + dateText.format12Hour = "${dateElements[0]}${stringUtils.addStartTextIfNotEmpty(dateElements[2], " | ")}${stringUtils.addStartTextIfNotEmpty(dateElements[3], " | ")}" + dateText.format24Hour = "${dateElements[1]}${stringUtils.addStartTextIfNotEmpty(dateElements[2], " | ")}${stringUtils.addStartTextIfNotEmpty(dateElements[3], " | ")}" } - override fun onStop() { - super.onStop() - job?.cancel() - weatherJob?.cancel() - } - - override fun onDestroy() { - super.onDestroy() - job?.cancel() - unregisterBatteryReceiver() - preferences.unregisterOnSharedPreferenceChangeListener(this) - } - - override fun onStart() { - super.onStart() - startTask() - - // Keyboard is sometimes open when going back to the app, so close it. + fun backToHome() { closeKeyboard() - } + animations.showHome(binding) + animations.backgroundOut(this@MainActivity, preferences) + val handler = Handler(Looper.getMainLooper()) + handler.postDelayed({ + try { + binding.menutitle.visibility = View.VISIBLE + searchView.setText(R.string.empty) + } + catch (_: UninitializedPropertyAccessException) { - @SuppressLint("NotifyDataSetChanged") - override fun onResume() { - super.onResume() - adapter?.notifyDataSetChanged() - } + } + }, 100) + handler.postDelayed({ + lifecycleScope.launch { + refreshAppMenu() - open inner class GestureListener : GestureDetector.SimpleOnGestureListener() { - - @RequiresApi(Build.VERSION_CODES.TIRAMISU) - @SuppressLint("WrongConstant") - override fun onFling( - e1: MotionEvent?, - e2: MotionEvent, - velocityX: Float, - velocityY: Float - ): Boolean { - if (e1 != null) { - val deltaY = e2.y - e1.y - val deltaX = e2.x - e1.x - - // Detect swipe up - if (deltaY < -swipeThreshold && abs(velocityY) > swipeVelocityThreshold) { - openAppMenuActivity() - } - - // Detect swipe down - else if (deltaY > swipeThreshold && abs(velocityY) > swipeVelocityThreshold) { - val statusBarService = getSystemService(Context.STATUS_BAR_SERVICE) - val statusBarManager: Class<*> = Class.forName("android.app.StatusBarManager") - val expandMethod: Method = statusBarManager.getMethod("expandNotificationsPanel") - expandMethod.invoke(statusBarService) - } - - // Detect swipe left - else if (deltaX < -swipeThreshold && abs(velocityX) > swipeVelocityThreshold && preferences.getBoolean("leftSwipe", true)){ - - if (leftSwipeActivity.first != null && leftSwipeActivity.second != null) { - launcherApps.startMainActivity(leftSwipeActivity.first!!.componentName, launcherApps.profiles[leftSwipeActivity.second!!], null, null) - } else { - Toast.makeText(this@MainActivity, "Cannot launch app", Toast.LENGTH_SHORT).show() + try { + withContext(Dispatchers.Main) { + recyclerView.scrollToPosition(0) } } + catch (_: UninitializedPropertyAccessException) { + } + }}, 150) - // Detect swipe right - else if (deltaX > -swipeThreshold && abs(velocityX) > swipeVelocityThreshold && preferences.getBoolean("rightSwipe", true)) { - if (rightSwipeActivity.first != null && rightSwipeActivity.second != null) { - launcherApps.startMainActivity(rightSwipeActivity.first!!.componentName, launcherApps.profiles[rightSwipeActivity.second!!], null, null) - } else { - Toast.makeText(this@MainActivity, "Cannot launch app", Toast.LENGTH_SHORT).show() + } + + private fun closeKeyboard() { + val imm = + getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + imm.hideSoftInputFromWindow(binding.root.windowToken, 0) + } + + suspend fun refreshAppMenu() { + try { + if (isJobActive) { + val updatedApps = appUtils.getInstalledApps(this@MainActivity, launcherApps) + if (!listsEqual(installedApps, updatedApps)) { + withContext(Dispatchers.Main) { + updateMenu(updatedApps) } + installedApps = updatedApps } } - return true + } + catch (_: UninitializedPropertyAccessException) { + } + } + + private fun listsEqual(list1: List>>, list2: List>>): Boolean { + if (list1.size != list2.size) return false + + for (i in list1.indices) { + if (list1[i].first.componentName != list2[i].first.componentName || list1[i].second.first != list2[i].second.first) { + return false + } } - override fun onLongPress(e: MotionEvent) { - super.onLongPress(e) - startActivity(Intent(this@MainActivity, SettingsActivity::class.java)) - } + return true + } - override fun onDoubleTap(e: MotionEvent): Boolean { - if (preferences.getBoolean("doubleTap", false)) { - if (isAccessibilityServiceEnabled( - this@MainActivity, - ScreenLockService::class.java - ) - ) { - println("enabled") - val intent = Intent(this@MainActivity, ScreenLockService::class.java) - intent.action = "LOCK_SCREEN" - startService(intent) + private fun updateMenu(updatedApps : List>>) { + adapter?.updateApps(updatedApps) + } + + private suspend fun updateWeather() { + withContext(Dispatchers.IO) { + if (preferences.getBoolean("weather_enabled", false)) { + if (preferences.getBoolean("gps_location", false)) { + weatherSystem.setGpsLocation(this@MainActivity) } else { - promptEnableAccessibility() + updateWeatherText() } } - - return super.onDoubleTap(e) - - } - - } - - inner class TextGestureListener : GestureListener() { - override fun onLongPress(e: MotionEvent) { - - } - } - - - fun isAccessibilityServiceEnabled(context: Context, service: Class): Boolean { - val am = context.getSystemService(ACCESSIBILITY_SERVICE) as AccessibilityManager - val enabledServices = - am.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK) - - for (enabledService in enabledServices) { - val enabledServiceInfo: ServiceInfo = enabledService.resolveInfo.serviceInfo - if (enabledServiceInfo.packageName.equals(context.packageName) && enabledServiceInfo.name.equals( - service.name - ) - ) return true - } - - return false - } - - private fun promptEnableAccessibility() { - AlertDialog.Builder(this@MainActivity).apply { - setTitle("Confirmation") - setMessage("To lock with double tap, enable YAM Launcher in accessibility settings.") - setPositiveButton("Yes") { _, _ -> - // Perform action on confirmation - val intent = Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS) - intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK - startActivity(intent) + else { + modifyDate("", 2) } - setNegativeButton("Cancel") { _, _ -> - - } - - }.create().show() + } } - private fun getSwipeInfo(direction: String): Pair { - val app = preferences.getString("${direction}SwipeApp", "")?.split("§splitter§") - - if (app != null) { - if (app.size >= 3) - - return Pair( - launcherApps.getActivityList( - app[1], launcherApps.profiles[app[2] - .toInt()] - ).firstOrNull(), app[2].toInt() - ) + suspend fun updateWeatherText() { + val temp = weatherSystem.getTemp(this@MainActivity) + withContext(Dispatchers.Main) { + modifyDate(temp, 2) } - return Pair(null, null) } private fun setupApps() { - handleListItems() - CoroutineScope(Dispatchers.Default).launch { + lifecycleScope.launch(Dispatchers.Default) { installedApps = appUtils.getInstalledApps(this@MainActivity, launcherApps) val newApps = installedApps.toMutableList() @@ -538,83 +464,6 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh } - private fun handleListItems() { - val shortcuts = arrayOf(R.id.app1, R.id.app2, R.id.app3, R.id.app4, R.id.app5, R.id.app6, R.id.app7, R.id.app8) - - for (i in shortcuts.indices) { - - val textView = findViewById(shortcuts[i]) - - val shortcutNo = preferences.getString("shortcutNo", "4")?.toInt() - - if (i >= shortcutNo!!) { - textView.visibility = View.GONE - } - - else { - textView.visibility = View.VISIBLE - - unselectedSetup(textView) - - val savedView = sharedPreferenceManager.getShortcut(this, textView) - - if (savedView?.get(1) != "e") { - selectedSetup(textView, savedView) - } - - setShortcutAlignment(preferences.getString("shortcutAlignment", "left"), binding.homeView) - } - - } - - } - - @SuppressLint("ClickableViewAccessibility") - private fun unselectedSetup(textView: TextView) { - textView.setOnTouchListener {_, event -> - shortcutGestureDetector.onTouchEvent(event) - super.onTouchEvent(event) - } - - textView.setCompoundDrawablesWithIntrinsicBounds(ResourcesCompat.getDrawable(resources, R.drawable.ic_empty, null),null,null,null) - - unselectedListeners(textView) - } - - private fun selectedSetup(textView: TextView, savedView: List?) { - if (savedView?.get(1) != "0") { - textView.setCompoundDrawablesWithIntrinsicBounds(ResourcesCompat.getDrawable(resources, R.drawable.ic_work_app, null),null,null,null) - } - else { - textView.setCompoundDrawablesWithIntrinsicBounds(ResourcesCompat.getDrawable(resources, R.drawable.ic_empty, null),null,null,null) - } - textView.text = savedView?.get(2) - selectedListeners(textView, savedView) - } - - private fun unselectedListeners(textView: TextView) { - textView.setOnClickListener { - Toast.makeText(this, "Long click to select an app", Toast.LENGTH_SHORT).show() - } - textView.setOnLongClickListener { - adapter?.shortcutTextView = textView - toAppMenu() - - return@setOnLongClickListener true - } - } - - private fun selectedListeners(textView: TextView, savedView: List?) { - textView.setOnClickListener { - val mainActivity = launcherApps.getActivityList(savedView?.get(0).toString(), launcherApps.profiles[savedView?.get(1)!!.toInt()]).firstOrNull() - if (mainActivity != null) { - launcherApps.startMainActivity(mainActivity.componentName, launcherApps.profiles[savedView[1].toInt()], null, null) - } else { - Toast.makeText(this, "Cannot launch app", Toast.LENGTH_SHORT).show() - } - } - } - private suspend fun setupRecyclerView(newApps: MutableList>>) { adapter = AppMenuAdapter(this@MainActivity, newApps, this@MainActivity, this@MainActivity, this@MainActivity, launcherApps) appMenuLinearLayoutManager.stackFromEnd = true @@ -640,19 +489,11 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh }) } - private fun setupSearch() { + private suspend fun setupSearch() { recyclerView.addOnLayoutChangeListener { _, _, top, _, bottom, _, oldTop, _, oldBottom -> if (bottom - top > oldBottom - oldTop) { - searchView.clearFocus() - - if (searchView.text.isNullOrEmpty()) { - startTask() - } - } - else if (bottom - top < oldBottom - oldTop) { - job?.cancel() } } @@ -666,34 +507,32 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh } override fun afterTextChanged(s: Editable?) { - CoroutineScope(Dispatchers.Default).launch { + lifecycleScope.launch(Dispatchers.Default) { filterItems(searchView.text.toString()) } } }) } - suspend fun applySearch() { - filterItems(searchView.text.toString()) - } - private suspend fun filterItems(query: String?) { - val cleanQuery = stringUtils.cleanString(query) - val newFilteredApps = mutableListOf>>() - val updatedApps = appUtils.getInstalledApps(this@MainActivity, launcherApps) + val cleanQuery = stringUtils.cleanString(query) + val newFilteredApps = mutableListOf>>() + val updatedApps = appUtils.getInstalledApps(this@MainActivity, launcherApps) - getFilteredApps(cleanQuery, newFilteredApps, updatedApps) + getFilteredApps(cleanQuery, newFilteredApps, updatedApps) - applySearch(newFilteredApps) + applySearchFilter(newFilteredApps) } private suspend fun getFilteredApps(cleanQuery: String?, newFilteredApps: MutableList>>, updatedApps: List>>) { if (cleanQuery.isNullOrEmpty()) { + isJobActive = true refreshAppMenu() newFilteredApps.addAll(installedApps) } else { + isJobActive = false updatedApps.forEach { val cleanItemText = stringUtils.cleanString(sharedPreferenceManager.getAppName(this@MainActivity, it.first.applicationInfo.packageName, it.second.second, packageManager.getApplicationLabel(it.first.applicationInfo)).toString()) if (cleanItemText != null) { @@ -705,7 +544,7 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh } } - private suspend fun applySearch(newFilteredApps: MutableList>>) { + private suspend fun applySearchFilter(newFilteredApps: MutableList>>) { if (!listsEqual(installedApps, newFilteredApps)) { withContext(Dispatchers.Main) { updateMenu(newFilteredApps) @@ -714,70 +553,45 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh } } - private fun startTask() { - job?.cancel() - job = CoroutineScope(Dispatchers.Default).launch { - while (true) { - refreshAppMenu() - delay(5000) - } - } + suspend fun applySearch() { + filterItems(searchView.text.toString()) } - fun openAppMenuActivity() { - adapter?.shortcutTextView = null - binding.menutitle.visibility = View.GONE - toAppMenu() + + override fun onNewIntent(intent: Intent) { + super.onNewIntent(intent) + backToHome() } - - fun backToHome() { + + override fun onDestroy() { + super.onDestroy() + + unregisterBatteryReceiver() + preferences.unregisterOnSharedPreferenceChangeListener(this) + } + + override fun onStart() { + super.onStart() + // Keyboard is sometimes open when going back to the app, so close it. closeKeyboard() - animations.showHome(binding) - animations.backgroundOut(this@MainActivity, Color.parseColor(preferences.getString("bgColor", "#00000000"))) - val handler = Handler(Looper.getMainLooper()) - handler.postDelayed({ - try { - binding.menutitle.visibility = View.VISIBLE - searchView.setText("") - } - catch (_: UninitializedPropertyAccessException) { + try { - } - }, 100) - handler.postDelayed({ - CoroutineScope(Dispatchers.Default).launch { - refreshAppMenu() + recyclerView.scrollToPosition(0) - try { - withContext(Dispatchers.Main) { - recyclerView.scrollToPosition(0) - } - } - catch (_: UninitializedPropertyAccessException) { - - } - }}, 150) + } + catch (_: UninitializedPropertyAccessException) { + } } - private fun toAppMenu() { - animations.showApps(binding) - animations.backgroundIn(this@MainActivity, Color.parseColor(preferences.getString("bgColor", "#00000000"))) - if (preferences.getBoolean("autoKeyboard", false)) { - val imm = - getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager - searchView.requestFocus() - imm.showSoftInput(searchView, InputMethodManager.SHOW_IMPLICIT) - } + @SuppressLint("NotifyDataSetChanged") + override fun onResume() { + super.onResume() + adapter?.notifyDataSetChanged() } override fun onItemClick(appInfo: LauncherActivityInfo, userHandle: UserHandle) { - val mainActivity = launcherApps.getActivityList(appInfo.applicationInfo.packageName, userHandle).firstOrNull() - if (mainActivity != null) { - launcherApps.startMainActivity(mainActivity.componentName, userHandle, null, null) - } else { - Toast.makeText(this, "Cannot launch app", Toast.LENGTH_SHORT).show() - } + appUtils.launchApp(this@MainActivity, launcherApps, appInfo, userHandle) } override fun onShortcut( @@ -825,12 +639,7 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh shortcutView.text = textView.text.toString() shortcutView.setOnClickListener { - val mainActivity = launcherApps.getActivityList(appInfo.applicationInfo.packageName, userHandle).firstOrNull() - if (mainActivity != null) { - launcherApps.startMainActivity(mainActivity.componentName, userHandle, null, null) - } else { - Toast.makeText(this, "Cannot launch app", Toast.LENGTH_SHORT).show() - } + appUtils.launchApp(this@MainActivity, launcherApps, appInfo, userHandle) } sharedPreferenceManager.setShortcut(this, shortcutView, appInfo.applicationInfo.packageName, userProfile) backToHome() @@ -866,211 +675,93 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh ) } - suspend fun refreshAppMenu() { - try { - val updatedApps = appUtils.getInstalledApps(this@MainActivity, launcherApps) - println("update running") - if (!listsEqual(installedApps, updatedApps)) { - withContext(Dispatchers.Main) { - updateMenu(updatedApps) - } - installedApps = updatedApps + open inner class GestureListener : GestureDetector.SimpleOnGestureListener() { + + @RequiresApi(Build.VERSION_CODES.TIRAMISU) + @SuppressLint("WrongConstant") + override fun onFling( + e1: MotionEvent?, + e2: MotionEvent, + velocityX: Float, + velocityY: Float + ): Boolean { + if (e1 != null) { + val deltaY = e2.y - e1.y + val deltaX = e2.x - e1.x + + // Detect swipe up + if (deltaY < -swipeThreshold && abs(velocityY) > swipeVelocityThreshold) { + openAppMenu() } - } - catch (_: UninitializedPropertyAccessException) { - } - } + // Detect swipe down + else if (deltaY > swipeThreshold && abs(velocityY) > swipeVelocityThreshold) { + val statusBarService = getSystemService(Context.STATUS_BAR_SERVICE) + val statusBarManager: Class<*> = Class.forName("android.app.StatusBarManager") + val expandMethod: Method = statusBarManager.getMethod("expandNotificationsPanel") + expandMethod.invoke(statusBarService) + } + // Detect swipe left + else if (deltaX < -swipeThreshold && abs(velocityX) > swipeVelocityThreshold && preferences.getBoolean("leftSwipe", true)){ - private fun closeKeyboard() { - val imm = - getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager - imm.hideSoftInputFromWindow(binding.root.windowToken, 0) - } - - private fun updateMenu(updatedApps : List>>) { - adapter?.updateApps(updatedApps) - println("moved") - } - - private fun listsEqual(list1: List>>, list2: List>>): Boolean { - if (list1.size != list2.size) return false - - for (i in list1.indices) { - if (list1[i].first.componentName != list2[i].first.componentName || list1[i].second.first != list2[i].second.first) { - return false - } - } - - return true - } - - private fun setClockAlignment(alignment: String?) { - - when (alignment) { - "left" -> { - clock.textAlignment = TEXT_ALIGNMENT_TEXT_START - dateText.textAlignment = TEXT_ALIGNMENT_TEXT_START - } - "center" -> { - clock.textAlignment = TEXT_ALIGNMENT_CENTER - dateText.textAlignment = TEXT_ALIGNMENT_CENTER - } - "right" -> { - clock.textAlignment = TEXT_ALIGNMENT_TEXT_END - dateText.textAlignment = TEXT_ALIGNMENT_TEXT_END - } - } - } - - private fun setShortcutAlignment(alignment: String?, shortcuts: LinearLayout) { - shortcuts.children.forEach { - - if (it is TextView) { - - try { - when (alignment) { - "left" -> { - it.setCompoundDrawablesWithIntrinsicBounds( - it.compoundDrawables.filterNotNull().first(), null, null, null - ) - it.gravity = Gravity.CENTER_VERTICAL or Gravity.START - } - - "center" -> { - it.setCompoundDrawablesWithIntrinsicBounds( - it.compoundDrawables.filterNotNull().first(), - null, - it.compoundDrawables.filterNotNull().first(), - null - ) - it.gravity = Gravity.CENTER - } - - "right" -> { - it.setCompoundDrawablesWithIntrinsicBounds( - null, - null, - it.compoundDrawables.filterNotNull().first(), - null - ) - it.gravity = Gravity.CENTER_VERTICAL or Gravity.END - } - } - } catch(_: Exception) {} - } - } - } - - private fun setSearchAlignment(alignment: String?) { - - when (alignment) { - "left" -> { - searchView.textAlignment = View.TEXT_ALIGNMENT_VIEW_START - } - "center" -> { - searchView.textAlignment = View.TEXT_ALIGNMENT_CENTER - } - "right" -> { - searchView.textAlignment = View.TEXT_ALIGNMENT_VIEW_END - } - } - } - - private fun setShortcutSize(shortcuts: LinearLayout) { - - val viewTreeObserver = shortcuts.viewTreeObserver - val globalLayoutListener = object : ViewTreeObserver.OnGlobalLayoutListener { - override fun onGlobalLayout() { - - shortcuts.children.forEach { - if (it is TextView) { - - when (preferences.getString("shortcutSize", "medium")) { - "small" -> { - it.setPadding( - it.paddingLeft, - it.height / 4, - it.paddingRight, - it.height / 4 - ) - } - - "medium" -> { - it.setPadding( - it.paddingLeft, - (it.height / 4.5).toInt(), - it.paddingRight, - (it.height / 4.5).toInt() - ) - } - - "large" -> { - it.setPadding(it.paddingLeft, 0, it.paddingRight, 0) - } - } - + if (leftSwipeActivity.first != null && leftSwipeActivity.second != null) { + launcherApps.startMainActivity(leftSwipeActivity.first!!.componentName, launcherApps.profiles[leftSwipeActivity.second!!], null, null) + } else { + Toast.makeText(this@MainActivity, "Cannot launch app", Toast.LENGTH_SHORT).show() } } - if (viewTreeObserver.isAlive) { - viewTreeObserver.removeOnGlobalLayoutListener(this) + + + // Detect swipe right + else if (deltaX > -swipeThreshold && abs(velocityX) > swipeVelocityThreshold && preferences.getBoolean("rightSwipe", true)) { + if (rightSwipeActivity.first != null && rightSwipeActivity.second != null) { + launcherApps.startMainActivity(rightSwipeActivity.first!!.componentName, launcherApps.profiles[rightSwipeActivity.second!!], null, null) + } else { + Toast.makeText(this@MainActivity, "Cannot launch app", Toast.LENGTH_SHORT).show() + } } } + return true } - if (viewTreeObserver.isAlive) { - viewTreeObserver.addOnGlobalLayoutListener(globalLayoutListener) + override fun onLongPress(e: MotionEvent) { + super.onLongPress(e) + startActivity(Intent(this@MainActivity, SettingsActivity::class.java)) + } + + override fun onDoubleTap(e: MotionEvent): Boolean { + if (preferences.getBoolean("doubleTap", false)) { + if (gestureUtils.isAccessibilityServiceEnabled( + this@MainActivity, + ScreenLockService::class.java + ) + ) { + println("enabled") + val intent = Intent(this@MainActivity, ScreenLockService::class.java) + intent.action = "LOCK_SCREEN" + startService(intent) + } else { + gestureUtils.promptEnableAccessibility(this@MainActivity) + } + } + + return super.onDoubleTap(e) + + } + + private fun openAppMenu() { + adapter?.shortcutTextView = null + binding.menutitle.visibility = View.GONE + toAppMenu() + } + + } + + inner class TextGestureListener : GestureListener() { + override fun onLongPress(e: MotionEvent) { + } } - private fun setClockSize(size: String?) { - when (size) { - "small" -> { - clock.textSize = 48F - } - "medium" -> { - clock.textSize = 58F - } - "large" -> { - clock.textSize = 68F - } - } - } - - private fun setDateSize(size: String?) { - when (size) { - "small" -> { - dateText.textSize = 17F - } - "medium" -> { - dateText.textSize = 20F - } - "large" -> { - dateText.textSize = 23F - } - } - } - - private fun setSearchSize(size: String?) { - when (size) { - "small" -> { - searchView.textSize = 21F - } - "medium" -> { - searchView.textSize = 23F - } - "large" -> { - searchView.textSize = 25F - } - } - } - - fun isJobActive(): Boolean { - return if (job != null) { - job!!.isActive - } else { - false - } - } } \ No newline at end of file diff --git a/app/src/main/java/eu/ottop/yamlauncher/UIUtils.kt b/app/src/main/java/eu/ottop/yamlauncher/UIUtils.kt index a271639..dbf7357 100644 --- a/app/src/main/java/eu/ottop/yamlauncher/UIUtils.kt +++ b/app/src/main/java/eu/ottop/yamlauncher/UIUtils.kt @@ -1,22 +1,41 @@ package eu.ottop.yamlauncher +import android.content.SharedPreferences +import android.graphics.BlendMode +import android.graphics.BlendModeColorFilter import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.view.Gravity import android.view.View import android.view.ViewGroup +import android.view.ViewTreeObserver +import android.view.Window +import android.view.WindowInsets +import android.view.WindowInsetsController +import android.widget.LinearLayout +import android.widget.TextClock import android.widget.TextView import androidx.core.view.children +import com.google.android.material.textfield.TextInputEditText -class UIUtils { +class UIUtils() { - fun setAllColors(view: View, color: Int) { + fun setBackground(window: Window, preferences: SharedPreferences) { + window.setBackgroundDrawable(ColorDrawable(Color.parseColor("#00000000"))) + window.decorView.setBackgroundColor( + Color.parseColor(preferences.getString("bgColor", "#00000000")) + ) + } + + fun setTextColors(preferences: SharedPreferences, view: View) { + val color = Color.parseColor(preferences.getString("textColor", "#FFF3F3F3")) when { view is ViewGroup -> { view.children.forEach { child -> - setAllColors(child, color) + setTextColors(preferences, child) } } hasMethod(view, "setTextColor") -> { - // Check if the method setTextColor exists (view as? TextView)?.setTextColor(color) } else -> { @@ -25,7 +44,6 @@ class UIUtils { } } - // Helper function to check if a view has a method private fun hasMethod(view: View, methodName: String): Boolean { return try { view.javaClass.getMethod(methodName, Int::class.java) @@ -35,18 +53,179 @@ class UIUtils { } } - private fun setAlpha(color: Int, newAlpha: Int): Int { - // Extract the RGB components + private fun setAlpha(color: Int, alphaHex: String): Int { + val newAlpha = Integer.parseInt(alphaHex, 16) + val r = Color.red(color) val g = Color.green(color) val b = Color.blue(color) - // Combine the new alpha with the RGB components return Color.argb(newAlpha, r, g, b) } - fun setAlpha(color: Int, alphaHex: String): Int { - val newAlpha = Integer.parseInt(alphaHex, 16) // Convert hex alpha to integer - return setAlpha(color, newAlpha) + fun setSearchColors(preferences: SharedPreferences, searchView: TextInputEditText) { + val viewTreeObserver = searchView.viewTreeObserver + + val globalLayoutListener = object : ViewTreeObserver.OnGlobalLayoutListener { + override fun onGlobalLayout() { + searchView.setTextColor(Color.parseColor(preferences.getString("textColor", "#FFF3F3F3"))) + searchView.setHintTextColor(setAlpha(Color.parseColor(preferences.getString("textColor", "#FFF3F3F3")), "A9")) + searchView.compoundDrawables[0].mutate().colorFilter = + BlendModeColorFilter(Color.parseColor(preferences.getString("textColor", "#FFF3F3F3")), BlendMode.SRC_ATOP) + + if (viewTreeObserver.isAlive) { + viewTreeObserver.removeOnGlobalLayoutListener(this) + } + } + } + + if (viewTreeObserver.isAlive) { + viewTreeObserver.addOnGlobalLayoutListener(globalLayoutListener) + } } + + fun setClockAlignment(preferences: SharedPreferences, clock: TextClock, dateText: TextClock) { + setTextAlignment(clock, preferences.getString("clockAlignment", "left")) + setTextAlignment(dateText, preferences.getString("clockAlignment", "left")) + } + + fun setShortcutAlignment(preferences: SharedPreferences, shortcuts: LinearLayout) { + shortcuts.children.forEach { + + if (it is TextView) { + + try { + when (preferences.getString("shortcutAlignment", "left")) { + "left" -> { + it.setCompoundDrawablesWithIntrinsicBounds( + it.compoundDrawables.filterNotNull().first(), null, null, null + ) + it.gravity = Gravity.CENTER_VERTICAL or Gravity.START + } + + "center" -> { + it.setCompoundDrawablesWithIntrinsicBounds( + it.compoundDrawables.filterNotNull().first(), + null, + it.compoundDrawables.filterNotNull().first(), + null + ) + it.gravity = Gravity.CENTER + } + + "right" -> { + it.setCompoundDrawablesWithIntrinsicBounds( + null, + null, + it.compoundDrawables.filterNotNull().first(), + null + ) + it.gravity = Gravity.CENTER_VERTICAL or Gravity.END + } + } + } catch(_: Exception) {} + } + } + } + + fun setSearchAlignment(preferences: SharedPreferences, searchView: TextInputEditText) { + setTextAlignment(searchView, preferences.getString("searchAlignment", "left")) + } + + private fun setTextAlignment(view: TextView, alignment: String?) { + view.textAlignment = when (alignment) { + "left" -> View.TEXT_ALIGNMENT_VIEW_START + + "center" -> View.TEXT_ALIGNMENT_CENTER + + "right" -> View.TEXT_ALIGNMENT_VIEW_END + + else -> View.TEXT_ALIGNMENT_VIEW_START + } + } + + fun setClockSize(preferences: SharedPreferences, clock: TextClock) { + setTextSize(clock, preferences.getString("clockSize","medium"), 48F, 58F, 68F) + } + + fun setDateSize(preferences: SharedPreferences, dateText: TextClock) { + setTextSize(dateText, preferences.getString("dateSize", "medium"), 17F, 20F, 23F) + } + + fun setShortcutSize(preferences: SharedPreferences, shortcuts: LinearLayout) { + + val viewTreeObserver = shortcuts.viewTreeObserver + val globalLayoutListener = object : ViewTreeObserver.OnGlobalLayoutListener { + override fun onGlobalLayout() { + + shortcuts.children.forEach { + if (it is TextView) { + + when (preferences.getString("shortcutSize", "medium")) { + "small" -> { + it.setPadding( + it.paddingLeft, + it.height / 4, + it.paddingRight, + it.height / 4 + ) + } + + "medium" -> { + it.setPadding( + it.paddingLeft, + (it.height / 4.5).toInt(), + it.paddingRight, + (it.height / 4.5).toInt() + ) + } + + "large" -> { + it.setPadding(it.paddingLeft, 0, it.paddingRight, 0) + } + } + } + } + if (viewTreeObserver.isAlive) { + viewTreeObserver.removeOnGlobalLayoutListener(this) + } + } + } + + if (viewTreeObserver.isAlive) { + viewTreeObserver.addOnGlobalLayoutListener(globalLayoutListener) + } + } + + fun setSearchSize(preferences: SharedPreferences, searchView: TextInputEditText) { + setTextSize(searchView, preferences.getString("searchSize", "medium"), 21F, 23F, 25F) + } + + private fun setTextSize(view: TextView, size: String?, s: Float, m: Float, l: Float) { + view.textSize = when (size) { + "small" -> s + + "medium" -> m + + "large" -> l + + else -> {0F} + } + } + + fun setStatusBar(window: Window, preferences: SharedPreferences) { + val windowInsetsController = window.insetsController + + windowInsetsController?.let { + if (preferences.getBoolean("barVisibility", false)) { + it.show(WindowInsets.Type.statusBars()) + } + else { + it.hide(WindowInsets.Type.statusBars()) + it.systemBarsBehavior = + WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE + } + } + } + } \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_about.xml b/app/src/main/res/layout/fragment_about.xml index 7d68cf9..b9de9df 100644 --- a/app/src/main/res/layout/fragment_about.xml +++ b/app/src/main/res/layout/fragment_about.xml @@ -20,7 +20,7 @@ android:id="@+id/textView2" android:layout_width="0dp" android:layout_height="wrap_content" - android:text="YAM Launcher" + android:text="@string/app_name" android:textAlignment="center" android:textSize="34sp" android:textStyle="bold" diff --git a/app/src/main/res/layout/fragment_location.xml b/app/src/main/res/layout/fragment_location.xml index b5291ba..3dcde4c 100644 --- a/app/src/main/res/layout/fragment_location.xml +++ b/app/src/main/res/layout/fragment_location.xml @@ -72,8 +72,8 @@ android:linksClickable="true" android:text="Weather data by Open-Meteo.com\n(CC BY 4.0)" android:textAlignment="center" - android:textColor="#A48E8E8E" - android:textColorLink="#6880CBC4" + android:textColor="#B3A5A5A5" + android:textColorLink="#7F80CBC4" android:textSize="14sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5dda323..6cf8c90 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,63 +1,13 @@ YAM Launcher - Settings - - First Fragment - Second Fragment - Next - Previous - - Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam in scelerisque sem. Mauris - volutpat, dolor id interdum ullamcorper, risus dolor egestas lectus, sit amet mattis purus - dui nec risus. Maecenas non sodales nisi, vel dictum dolor. Class aptent taciti sociosqu ad - litora torquent per conubia nostra, per inceptos himenaeos. Suspendisse blandit eleifend - diam, vel rutrum tellus vulputate quis. Aliquam eget libero aliquet, imperdiet nisl a, - ornare ex. Sed rhoncus est ut libero porta lobortis. Fusce in dictum tellus.\n\n - Suspendisse interdum ornare ante. Aliquam nec cursus lorem. Morbi id magna felis. Vivamus - egestas, est a condimentum egestas, turpis nisl iaculis ipsum, in dictum tellus dolor sed - neque. Morbi tellus erat, dapibus ut sem a, iaculis tincidunt dui. Interdum et malesuada - fames ac ante ipsum primis in faucibus. Curabitur et eros porttitor, ultricies urna vitae, - molestie nibh. Phasellus at commodo eros, non aliquet metus. Sed maximus nisl nec dolor - bibendum, vel congue leo egestas.\n\n - Sed interdum tortor nibh, in sagittis risus mollis quis. Curabitur mi odio, condimentum sit - amet auctor at, mollis non turpis. Nullam pretium libero vestibulum, finibus orci vel, - molestie quam. Fusce blandit tincidunt nulla, quis sollicitudin libero facilisis et. Integer - interdum nunc ligula, et fermentum metus hendrerit id. Vestibulum lectus felis, dictum at - lacinia sit amet, tristique id quam. Cras eu consequat dui. Suspendisse sodales nunc ligula, - in lobortis sem porta sed. Integer id ultrices magna, in luctus elit. Sed a pellentesque - est.\n\n - Aenean nunc velit, lacinia sed dolor sed, ultrices viverra nulla. Etiam a venenatis nibh. - Morbi laoreet, tortor sed facilisis varius, nibh orci rhoncus nulla, id elementum leo dui - non lorem. Nam mollis ipsum quis auctor varius. Quisque elementum eu libero sed commodo. In - eros nisl, imperdiet vel imperdiet et, scelerisque a mauris. Pellentesque varius ex nunc, - quis imperdiet eros placerat ac. Duis finibus orci et est auctor tincidunt. Sed non viverra - ipsum. Nunc quis augue egestas, cursus lorem at, molestie sem. Morbi a consectetur ipsum, a - placerat diam. Etiam vulputate dignissim convallis. Integer faucibus mauris sit amet finibus - convallis.\n\n - Phasellus in aliquet mi. Pellentesque habitant morbi tristique senectus et netus et - malesuada fames ac turpis egestas. In volutpat arcu ut felis sagittis, in finibus massa - gravida. Pellentesque id tellus orci. Integer dictum, lorem sed efficitur ullamcorper, - libero justo consectetur ipsum, in mollis nisl ex sed nisl. Donec maximus ullamcorper - sodales. Praesent bibendum rhoncus tellus nec feugiat. In a ornare nulla. Donec rhoncus - libero vel nunc consequat, quis tincidunt nisl eleifend. Cras bibendum enim a justo luctus - vestibulum. Fusce dictum libero quis erat maximus, vitae volutpat diam dignissim. - - - Hello blank fragment + + Select an app Search… App App - - Messages - Sync - - - Your signature - Default reply action - Sync email periodically Download incoming attachments