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:
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