commit d79610e29ec623e17880811960995c6b85f07843
parent a42d88c72331837fb1bd7626c935c7338bc8d3e4
Author: rhunk <101876869+rhunk@users.noreply.github.com>
Date:   Sat,  3 Feb 2024 18:31:08 +0100

fix(core/ui): friend feed menu injection
- fix applyTheme dimensions

Diffstat:
Mcommon/src/main/assets/lang/en_US.json | 4----
Mcommon/src/main/kotlin/me/rhunk/snapenhance/common/config/impl/UserInterfaceTweaks.kt | 1-
Mcore/src/main/kotlin/me/rhunk/snapenhance/core/ui/ViewAppearanceHelper.kt | 83++++++++++++++++++++++++++++++++++++-------------------------------------------
Mcore/src/main/kotlin/me/rhunk/snapenhance/core/ui/menu/MenuViewInjector.kt | 67++++++++++++++++++-------------------------------------------------
Mcore/src/main/kotlin/me/rhunk/snapenhance/core/util/ktx/AndroidExt.kt | 5+++++
5 files changed, 61 insertions(+), 99 deletions(-)

diff --git a/common/src/main/assets/lang/en_US.json b/common/src/main/assets/lang/en_US.json @@ -328,10 +328,6 @@ "name": "Vertical Story Viewer", "description": "Enables the vertical story viewer for all stories" }, - "friend_feed_menu_position": { - "name": "Friend Feed Position Index", - "description": "The position of the Friend Feed Menu component" - }, "enable_friend_feed_menu_bar": { "name": "Friend Feed Menu Bar", "description": "Enables the new Friend Feed Menu Bar" diff --git a/common/src/main/kotlin/me/rhunk/snapenhance/common/config/impl/UserInterfaceTweaks.kt b/common/src/main/kotlin/me/rhunk/snapenhance/common/config/impl/UserInterfaceTweaks.kt @@ -23,7 +23,6 @@ class UserInterfaceTweaks : ConfigContainer() { ).apply { set(mutableListOf("conversation_info", MessagingRuleType.STEALTH.key)) } - val friendFeedMenuPosition = integer("friend_feed_menu_position", defaultValue = 1) val amoledDarkMode = boolean("amoled_dark_mode") { addNotices(FeatureNotice.UNSTABLE); requireRestart() } val friendFeedMessagePreview = container("friend_feed_message_preview", FriendFeedMessagePreview()) { requireRestart() } val snapPreview = boolean("snap_preview") { addNotices(FeatureNotice.UNSTABLE); requireRestart() } diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/ui/ViewAppearanceHelper.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/ui/ViewAppearanceHelper.kt @@ -1,6 +1,5 @@ package me.rhunk.snapenhance.core.ui -import android.annotation.SuppressLint import android.app.Activity import android.app.AlertDialog import android.content.Context @@ -21,6 +20,7 @@ import android.view.ViewGroup import android.widget.Switch import android.widget.TextView import me.rhunk.snapenhance.core.util.ktx.getDimens +import me.rhunk.snapenhance.core.util.ktx.getDimensFloat import me.rhunk.snapenhance.core.util.ktx.getIdentifier import kotlin.random.Random @@ -93,73 +93,66 @@ fun View.iterateParent(predicate: (View) -> Boolean) { object ViewAppearanceHelper { - private var sigColorTextPrimary: Int = 0 - private var sigColorBackgroundSurface: Int = 0 - - private fun createRoundedBackground(color: Int, hasRadius: Boolean): Drawable { + private fun createRoundedBackground(color: Int, radius: Float, hasRadius: Boolean): Drawable { if (!hasRadius) return ColorDrawable(color) - //FIXME: hardcoded radius return ShapeDrawable().apply { paint.color = color shape = android.graphics.drawable.shapes.RoundRectShape( - floatArrayOf(20f, 20f, 20f, 20f, 20f, 20f, 20f, 20f), + floatArrayOf(radius, radius, radius, radius, radius, radius, radius, radius), null, null ) } } - @SuppressLint("DiscouragedApi") fun applyTheme(component: View, componentWidth: Int? = null, hasRadius: Boolean = false, isAmoled: Boolean = true) { val resources = component.context.resources - if (sigColorBackgroundSurface == 0 || sigColorTextPrimary == 0) { - with(component.context.theme) { - sigColorTextPrimary = obtainStyledAttributes( - intArrayOf(resources.getIdentifier("sigColorTextPrimary", "attr")) - ).getColor(0, 0) - - sigColorBackgroundSurface = obtainStyledAttributes( - intArrayOf(resources.getIdentifier("sigColorBackgroundSurface", "attr")) - ).getColor(0, 0) - } + val actionSheetCellHorizontalPadding = resources.getDimens("action_sheet_cell_horizontal_padding") + val v11ActionCellVerticalPadding = resources.getDimens("v11_action_cell_vertical_padding") + + val sigColorTextPrimary = component.context.theme.obtainStyledAttributes( + intArrayOf(resources.getIdentifier("sigColorTextPrimary", "attr")) + ).getColor(0, 0) + val sigColorBackgroundSurface = component.context.theme.obtainStyledAttributes( + intArrayOf(resources.getIdentifier("sigColorBackgroundSurface", "attr")) + ).getColor(0, 0) + + val actionSheetDefaultCellHeight = resources.getDimens("action_sheet_default_cell_height") + val actionSheetCornerRadius = resources.getDimensFloat("action_sheet_corner_radius") + val snapchatFontResId = resources.getIdentifier("avenir_next_medium", "font") + + (component as? TextView)?.apply { + setTextColor(sigColorTextPrimary) + setShadowLayer(0F, 0F, 0F, 0) + gravity = Gravity.CENTER_VERTICAL + componentWidth?.let { width = it} + isAllCaps = false + minimumHeight = actionSheetDefaultCellHeight + textSize = 16f + typeface = resources.getFont(snapchatFontResId) + outlineProvider = null + setPadding(actionSheetCellHorizontalPadding, v11ActionCellVerticalPadding, actionSheetCellHorizontalPadding, v11ActionCellVerticalPadding) } - val snapchatFontResId = resources.getIdentifier("avenir_next_medium", "font") - val scalingFactor = resources.displayMetrics.densityDpi.toDouble() / 400 - - with(component) { - if (this is TextView) { - setTextColor(sigColorTextPrimary) - setShadowLayer(0F, 0F, 0F, 0) - gravity = Gravity.CENTER_VERTICAL - componentWidth?.let { width = it} - height = (150 * scalingFactor).toInt() - isAllCaps = false - textSize = 16f - typeface = resources.getFont(snapchatFontResId) - outlineProvider = null - setPadding((40 * scalingFactor).toInt(), 0, (40 * scalingFactor).toInt(), 0) - } - if (isAmoled) { - background = StateListDrawable().apply { - addState(intArrayOf(), createRoundedBackground(color = sigColorBackgroundSurface, hasRadius)) - addState(intArrayOf(android.R.attr.state_pressed), createRoundedBackground(color = 0x5395026, hasRadius)) - } - } else { - setBackgroundColor(0x0) + if (isAmoled) { + component.background = StateListDrawable().apply { + addState(intArrayOf(), createRoundedBackground(color = sigColorBackgroundSurface, radius = actionSheetCornerRadius, hasRadius)) + addState(intArrayOf(android.R.attr.state_pressed), createRoundedBackground(color = 0x5395026, radius = actionSheetCornerRadius, hasRadius)) } + } else { + component.setBackgroundColor(0x0) } - if (component is Switch) { - component.switchMinWidth = resources.getDimens("v11_switch_min_width") - component.trackTintList = ColorStateList( + (component as? Switch)?.apply { + switchMinWidth = resources.getDimens("v11_switch_min_width") + trackTintList = ColorStateList( arrayOf(intArrayOf(-android.R.attr.state_checked), intArrayOf(android.R.attr.state_checked) ), intArrayOf( Color.parseColor("#1d1d1d"), Color.parseColor("#26bd49") ) ) - component.thumbTintList = ColorStateList( + thumbTintList = ColorStateList( arrayOf(intArrayOf(-android.R.attr.state_checked), intArrayOf(android.R.attr.state_checked) ), intArrayOf( Color.parseColor("#F5F5F5"), diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/ui/menu/MenuViewInjector.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/ui/menu/MenuViewInjector.kt @@ -11,40 +11,31 @@ import me.rhunk.snapenhance.core.event.events.impl.AddViewEvent import me.rhunk.snapenhance.core.features.Feature import me.rhunk.snapenhance.core.features.FeatureLoadParams import me.rhunk.snapenhance.core.features.impl.messaging.Messaging -import me.rhunk.snapenhance.core.ui.ViewTagState import me.rhunk.snapenhance.core.ui.menu.impl.* import me.rhunk.snapenhance.core.util.ktx.getIdentifier -import java.lang.reflect.Modifier -import kotlin.reflect.KClass @SuppressLint("DiscouragedApi") class MenuViewInjector : Feature("MenuViewInjector", loadParams = FeatureLoadParams.ACTIVITY_CREATE_ASYNC) { - private val viewTagState = ViewTagState() - - private val menuMap = mutableMapOf<KClass<*>, AbstractMenu>() - private val newChatString by lazy { - context.resources.getString(context.resources.getIdentifier("new_chat", "string")) - } - @SuppressLint("ResourceType") override fun asyncOnActivityCreate() { - arrayOf( + val menuMap = arrayOf( OperaContextActionMenu(), OperaDownloadIconMenu(), SettingsGearInjector(), FriendFeedInfoMenu(), ChatActionMenu(), SettingsMenu() - ).forEach { - menuMap[it::class] = it.also { - it.context = context; it.init() - } + ).associateBy { + it.context = context + it.init() + it::class } val messaging = context.feature(Messaging::class) val actionSheetItemsContainerLayoutId = context.resources.getIdentifier("action_sheet_items_container", "id") val actionSheetContainer = context.resources.getIdentifier("action_sheet_container", "id") + val actionMenuHeaderId = context.resources.getIdentifier("action_menu_header", "id") val actionMenu = context.resources.getIdentifier("action_menu", "id") val componentsHolder = context.resources.getIdentifier("components_holder", "id") val feedNewChat = context.resources.getIdentifier("feed_new_chat", "id") @@ -64,6 +55,17 @@ class MenuViewInjector : Feature("MenuViewInjector", loadParams = FeatureLoadPar val childView: View = event.view menuMap[OperaContextActionMenu::class]!!.inject(viewGroup, childView, originalAddView) + if (event.view.id == actionMenuHeaderId) { + event.parent.post { + val actionSheetItemsContainer = event.parent.findViewById<ViewGroup>(actionSheetItemsContainerLayoutId) ?: return@post + val views = mutableListOf<View>() + menuMap[FriendFeedInfoMenu::class]?.inject(event.parent, actionSheetItemsContainer) { + views.add(it) + } + views.reversed().forEach { actionSheetItemsContainer.addView(it, 0) } + } + } + if (childView.id == contextMenuButtonIconView) { menuMap[OperaDownloadIconMenu::class]!!.inject(viewGroup, childView, originalAddView) } @@ -80,7 +82,6 @@ class MenuViewInjector : Feature("MenuViewInjector", loadParams = FeatureLoadPar return@subscribe } - //TODO: inject in group chat menus if (viewGroup.id == actionSheetContainer && childView.id == actionMenu && messaging.lastFetchGroupConversationUUID != null) { val injectedLayout = LinearLayout(childView.context).apply { orientation = LinearLayout.VERTICAL @@ -95,7 +96,7 @@ class MenuViewInjector : Feature("MenuViewInjector", loadParams = FeatureLoadPar }) } - context.runOnUiThread { + event.parent.post { injectedLayout.addView(ScrollView(injectedLayout.context).apply { layoutParams = LinearLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, @@ -122,38 +123,6 @@ class MenuViewInjector : Feature("MenuViewInjector", loadParams = FeatureLoadPar event.view = injectedLayout } - - if (viewGroup is LinearLayout && viewGroup.id == actionSheetItemsContainerLayoutId) { - val itemStringInterface by lazy { - childView.javaClass.declaredFields.filter { - !it.type.isPrimitive && Modifier.isAbstract(it.type.modifiers) - }.map { - runCatching { - it.isAccessible = true - it[childView] - }.getOrNull() - }.firstOrNull() - } - - //the 3 dot button shows a menu which contains the first item as a Plain object - if (viewGroup.getChildCount() == 0 && itemStringInterface != null && itemStringInterface.toString().startsWith("Plain(primaryText=$newChatString")) { - menuMap[SettingsMenu::class]!!.inject(viewGroup, childView, originalAddView) - viewGroup.addOnAttachStateChangeListener(object: View.OnAttachStateChangeListener { - override fun onViewAttachedToWindow(v: View) {} - override fun onViewDetachedFromWindow(v: View) { - viewTagState.removeState(viewGroup) - } - }) - viewTagState[viewGroup] - return@subscribe - } - if (messaging.lastFetchConversationUUID == null || messaging.lastFetchConversationUserUUID == null) return@subscribe - - //filter by the slot index - if (viewGroup.getChildCount() != context.config.userInterface.friendFeedMenuPosition.get()) return@subscribe - if (viewTagState[viewGroup]) return@subscribe - menuMap[FriendFeedInfoMenu::class]!!.inject(viewGroup, childView, originalAddView) - } } } } \ No newline at end of file diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/util/ktx/AndroidExt.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/util/ktx/AndroidExt.kt @@ -25,6 +25,10 @@ fun Resources.getDimens(name: String): Int { return getDimensionPixelSize(getIdentifier(name, "dimen")) } +fun Resources.getDimensFloat(name: String): Float { + return getDimension(getIdentifier(name, "dimen")) +} + fun Resources.getStyledAttributes(name: String, theme: Theme): TypedArray { return getIdentifier(name, "attr").let { theme.obtainStyledAttributes(intArrayOf(it)) @@ -35,6 +39,7 @@ fun Resources.getDrawable(name: String, theme: Theme): Drawable { return getDrawable(getIdentifier(name, "drawable"), theme) } +@SuppressLint("MissingPermission") fun Context.vibrateLongPress() { getSystemService(Vibrator::class.java).vibrate(VibrationEffect.createOneShot(50, VibrationEffect.DEFAULT_AMPLITUDE)) } \ No newline at end of file