Refactored MainActivity a bunch

This commit is contained in:
ottoptj 2024-08-08 22:21:21 +03:00
commit 4bac8ffee8
11 changed files with 651 additions and 738 deletions

View file

@ -6,6 +6,7 @@ import android.animation.ArgbEvaluator
import android.animation.ObjectAnimator import android.animation.ObjectAnimator
import android.animation.ValueAnimator import android.animation.ValueAnimator
import android.app.Activity import android.app.Activity
import android.content.SharedPreferences
import android.graphics.Color import android.graphics.Color
import android.graphics.drawable.ColorDrawable import android.graphics.drawable.ColorDrawable
import android.view.View import android.view.View
@ -32,7 +33,8 @@ class Animations () {
binding.homeView.fadeOut() 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")) { val newColor: Int = if (originalColor == Color.parseColor("#00000000")) {
Color.parseColor("#3F000000") Color.parseColor("#3F000000")
@ -52,7 +54,8 @@ class Animations () {
backgroundColorAnimator.start() 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")) { val originalColor: Int = if (newColor == Color.parseColor("#00000000")) {
Color.parseColor("#3F000000") Color.parseColor("#3F000000")

View file

@ -125,13 +125,11 @@ class AppActionMenu {
app.second.second app.second.second
) )
CoroutineScope(Dispatchers.Default).launch {
CoroutineScope(Dispatchers.Default).launch { CoroutineScope(Dispatchers.Default).launch {
activity.applySearch() activity.applySearch()
} }
} }
} }
}
actionMenu.findViewById<TextView>(R.id.hide).setOnClickListener { actionMenu.findViewById<TextView>(R.id.hide).setOnClickListener {
editLayout.visibility = View.GONE editLayout.visibility = View.GONE

View file

@ -17,7 +17,7 @@ class AppMenuLinearLayoutManager(private val activity: MainActivity) : LinearLay
val scrollRange = super.scrollVerticallyBy(dy, recycler, state) val scrollRange = super.scrollVerticallyBy(dy, recycler, state)
val overscroll: Int = dy - scrollRange val overscroll: Int = dy - scrollRange
if (overscroll < 0 && firstVisibleItemPosition == 0 && scrollStarted && activity.isJobActive()) { if (overscroll < 0 && firstVisibleItemPosition == 0 && scrollStarted && activity.isJobActive) {
activity.backToHome() activity.backToHome()
} }

View file

@ -1,30 +1,48 @@
package eu.ottop.yamlauncher package eu.ottop.yamlauncher
import android.app.Activity import android.app.Activity
import android.content.Context
import android.content.pm.ApplicationInfo import android.content.pm.ApplicationInfo
import android.content.pm.LauncherActivityInfo import android.content.pm.LauncherActivityInfo
import android.content.pm.LauncherApps import android.content.pm.LauncherApps
import android.os.UserHandle import android.os.UserHandle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.lang.reflect.InvocationTargetException import java.lang.reflect.InvocationTargetException
class AppUtils { class AppUtils {
private val sharedPreferenceManager = SharedPreferenceManager() private val sharedPreferenceManager = SharedPreferenceManager()
fun getInstalledApps(activity: Activity, launcherApps: LauncherApps): List<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>> { suspend fun getInstalledApps(activity: Activity, launcherApps: LauncherApps): List<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>> {
val allApps = mutableListOf<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>() val allApps = mutableListOf<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>()
var sortedApps = listOf<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>()
withContext(Dispatchers.Default) {
for (i in launcherApps.profiles.indices) { for (i in launcherApps.profiles.indices) {
launcherApps.getActivityList(null, launcherApps.profiles[i]).forEach { app -> launcherApps.getActivityList(null, launcherApps.profiles[i]).forEach { app ->
if (!sharedPreferenceManager.isAppHidden(activity, app.applicationInfo.packageName, i) && app.applicationInfo.packageName != activity.applicationInfo.packageName) { if (!sharedPreferenceManager.isAppHidden(
activity,
app.applicationInfo.packageName,
i
) && app.applicationInfo.packageName != activity.applicationInfo.packageName
) {
allApps.add(Pair(app, Pair(launcherApps.profiles[i], i))) allApps.add(Pair(app, Pair(launcherApps.profiles[i], i)))
} }
} }
} }
return allApps.sortedBy {
sharedPreferenceManager.getAppName(activity, it.first.applicationInfo.packageName,it.second.second, it.first.applicationInfo.loadLabel(activity.packageManager)).toString().lowercase() sortedApps = 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) { } catch (_: Exception) {
null 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()
}
} }
} }

View file

@ -88,15 +88,16 @@ class GestureAppsFragment : Fragment(), GestureAppsAdapter.OnItemClickListener {
} }
override fun afterTextChanged(s: Editable?) { override fun afterTextChanged(s: Editable?) {
lifecycleScope.launch {
filterItems(searchView.text.toString()) filterItems(searchView.text.toString())
}
} }
}) })
} }
} }
private fun filterItems(query: String?) { private suspend fun filterItems(query: String?) {
val cleanQuery = stringUtils.cleanString(query) val cleanQuery = stringUtils.cleanString(query)
val newFilteredApps = mutableListOf<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>() val newFilteredApps = mutableListOf<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>()

View file

@ -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<LauncherActivityInfo?, Int?> {
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<out AccessibilityService>): 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()
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,22 +1,41 @@
package eu.ottop.yamlauncher package eu.ottop.yamlauncher
import android.content.SharedPreferences
import android.graphics.BlendMode
import android.graphics.BlendModeColorFilter
import android.graphics.Color import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.view.Gravity
import android.view.View import android.view.View
import android.view.ViewGroup 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 android.widget.TextView
import androidx.core.view.children 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 { when {
view is ViewGroup -> { view is ViewGroup -> {
view.children.forEach { child -> view.children.forEach { child ->
setAllColors(child, color) setTextColors(preferences, child)
} }
} }
hasMethod(view, "setTextColor") -> { hasMethod(view, "setTextColor") -> {
// Check if the method setTextColor exists
(view as? TextView)?.setTextColor(color) (view as? TextView)?.setTextColor(color)
} }
else -> { 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 { private fun hasMethod(view: View, methodName: String): Boolean {
return try { return try {
view.javaClass.getMethod(methodName, Int::class.java) view.javaClass.getMethod(methodName, Int::class.java)
@ -35,18 +53,179 @@ class UIUtils {
} }
} }
private fun setAlpha(color: Int, newAlpha: Int): Int { private fun setAlpha(color: Int, alphaHex: String): Int {
// Extract the RGB components val newAlpha = Integer.parseInt(alphaHex, 16)
val r = Color.red(color) val r = Color.red(color)
val g = Color.green(color) val g = Color.green(color)
val b = Color.blue(color) val b = Color.blue(color)
// Combine the new alpha with the RGB components
return Color.argb(newAlpha, r, g, b) return Color.argb(newAlpha, r, g, b)
} }
fun setAlpha(color: Int, alphaHex: String): Int { fun setSearchColors(preferences: SharedPreferences, searchView: TextInputEditText) {
val newAlpha = Integer.parseInt(alphaHex, 16) // Convert hex alpha to integer val viewTreeObserver = searchView.viewTreeObserver
return setAlpha(color, newAlpha)
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
}
}
}
}

View file

@ -20,7 +20,7 @@
android:id="@+id/textView2" android:id="@+id/textView2"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="YAM Launcher" android:text="@string/app_name"
android:textAlignment="center" android:textAlignment="center"
android:textSize="34sp" android:textSize="34sp"
android:textStyle="bold" android:textStyle="bold"

View file

@ -72,8 +72,8 @@
android:linksClickable="true" android:linksClickable="true"
android:text="Weather data by Open-Meteo.com\n(CC BY 4.0)" android:text="Weather data by Open-Meteo.com\n(CC BY 4.0)"
android:textAlignment="center" android:textAlignment="center"
android:textColor="#A48E8E8E" android:textColor="#B3A5A5A5"
android:textColorLink="#6880CBC4" android:textColorLink="#7F80CBC4"
android:textSize="14sp" android:textSize="14sp"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"

View file

@ -1,63 +1,13 @@
<resources> <resources>
<string name="app_name">YAM Launcher</string> <string name="app_name">YAM Launcher</string>
<string name="action_settings">Settings</string>
<!-- Strings used for fragments for navigation -->
<string name="first_fragment_label">First Fragment</string>
<string name="second_fragment_label">Second Fragment</string>
<string name="next">Next</string>
<string name="previous">Previous</string>
<string name="lorem_ipsum"> <string name="empty"></string>
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.
</string>
<!-- TODO: Remove or change this placeholder text -->
<string name="hello_blank_fragment">Hello blank fragment</string>
<string name="select_an_app">Select an app</string> <string name="select_an_app">Select an app</string>
<string name="search">Search…</string> <string name="search">Search…</string>
<string name="app">App</string> <string name="app">App</string>
<string name="shortcut_default">App</string> <string name="shortcut_default">App</string>
<!-- Preference Titles -->
<string name="messages_header">Messages</string>
<string name="sync_header">Sync</string>
<!-- Messages Preferences -->
<string name="signature_title">Your signature</string>
<string name="reply_title">Default reply action</string>
<!-- Sync Preferences --> <!-- Sync Preferences -->
<string name="sync_title">Sync email periodically</string> <string name="sync_title">Sync email periodically</string>
<string name="attachment_title">Download incoming attachments</string> <string name="attachment_title">Download incoming attachments</string>