commit fc941170294a627b5d3666da517287d82fe0c423
parent 85335dafa81e59af9a35c65a8cdcdf9463350984
Author: rhunk <101876869+rhunk@users.noreply.github.com>
Date: Sun, 4 Jun 2023 15:02:06 +0200
perf: ui improvements
Diffstat:
3 files changed, 38 insertions(+), 66 deletions(-)
diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/features/impl/ui/menus/MenuViewInjector.kt b/app/src/main/kotlin/me/rhunk/snapenhance/features/impl/ui/menus/MenuViewInjector.kt
@@ -1,15 +1,12 @@
package me.rhunk.snapenhance.features.impl.ui.menus
import android.annotation.SuppressLint
-import android.content.Context
-import android.util.AttributeSet
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.LinearLayout
import de.robv.android.xposed.XposedBridge
-import me.rhunk.snapenhance.Constants.VIEW_DRAWER
-import me.rhunk.snapenhance.Constants.VIEW_INJECTED_CODE
+import me.rhunk.snapenhance.Constants
import me.rhunk.snapenhance.config.ConfigProperty
import me.rhunk.snapenhance.features.Feature
import me.rhunk.snapenhance.features.FeatureLoadParams
@@ -20,19 +17,17 @@ import me.rhunk.snapenhance.features.impl.ui.menus.impl.OperaContextActionMenu
import me.rhunk.snapenhance.features.impl.ui.menus.impl.SettingsMenu
import me.rhunk.snapenhance.hook.HookStage
import me.rhunk.snapenhance.hook.Hooker
-import java.lang.reflect.Field
import java.lang.reflect.Modifier
+@SuppressLint("DiscouragedApi")
class MenuViewInjector : Feature("MenuViewInjector", loadParams = FeatureLoadParams.ACTIVITY_CREATE_ASYNC) {
private val friendFeedInfoMenu = FriendFeedInfoMenu()
private val operaContextActionMenu = OperaContextActionMenu()
private val chatActionMenu = ChatActionMenu()
private val settingMenu = SettingsMenu()
- private fun wasInjectedView(view: View): Boolean {
- if (view.getTag(VIEW_INJECTED_CODE) != null) return true
- view.setTag(VIEW_INJECTED_CODE, true)
- return false
+ private val newChatString by lazy {
+ context.resources.getString(context.resources.getIdentifier("new_chat", "string", Constants.SNAPCHAT_PACKAGE_NAME))
}
@SuppressLint("ResourceType")
@@ -42,6 +37,7 @@ class MenuViewInjector : Feature("MenuViewInjector", loadParams = FeatureLoadPar
chatActionMenu.context = context
settingMenu.context = context
+ val actionSheetItemsContainerLayoutId = context.resources.getIdentifier("action_sheet_items_container", "id", Constants.SNAPCHAT_PACKAGE_NAME)
val addViewMethod = ViewGroup::class.java.getMethod(
"addView",
View::class.java,
@@ -49,22 +45,6 @@ class MenuViewInjector : Feature("MenuViewInjector", loadParams = FeatureLoadPar
ViewGroup.LayoutParams::class.java
)
- //catch the card view instance in the action drawer
- Hooker.hook(
- LinearLayout::class.java.getConstructor(
- Context::class.java,
- AttributeSet::class.java,
- Int::class.javaPrimitiveType
- ), HookStage.AFTER
- ) { param ->
- val viewGroup: LinearLayout = param.thisObject()
- val attribute: Int = param.arg(2)
- if (attribute == 0) return@hook
- val resourceName = viewGroup.resources.getResourceName(attribute)
- if (!resourceName.endsWith("snapCardContentLayoutStyle")) return@hook
- viewGroup.setTag(VIEW_DRAWER, Any())
- }
-
Hooker.hook(addViewMethod, HookStage.BEFORE) { param ->
val viewGroup: ViewGroup = param.thisObject()
val originalAddView: (View) -> Unit = { view: View ->
@@ -87,52 +67,43 @@ class MenuViewInjector : Feature("MenuViewInjector", loadParams = FeatureLoadPar
//download in chat snaps and notes from the chat action menu
if (viewGroup.javaClass.name.endsWith("ActionMenuChatItemContainer")) {
- if (viewGroup.parent == null || viewGroup.parent
- .parent == null
- ) return@hook
+ if (viewGroup.parent == null || viewGroup.parent.parent == null) return@hook
chatActionMenu.inject(viewGroup)
return@hook
}
//TODO : preview group chats
- if (viewGroup !is LinearLayout) return@hook
- if (viewGroup.getTag(VIEW_DRAWER) == null) return@hook
- val itemStringInterface =childView.javaClass.declaredFields.filter { field: Field ->
- !field.type.isPrimitive && Modifier.isAbstract(
- field.type.modifiers
- )
- }
- .map { field: Field ->
- try {
- field.isAccessible = true
- return@map field[childView]
- } catch (e: IllegalAccessException) {
- e.printStackTrace()
- }
- null
+ 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
- //FIXME: better way to detect the 3 dot button
- if (viewGroup.getChildCount() == 0 && itemStringInterface != null && itemStringInterface.toString().startsWith("Plain(primaryText=")) {
- if (wasInjectedView(viewGroup)) return@hook
+ //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")) {
- settingMenu.inject(viewGroup, originalAddView)
- viewGroup.addOnAttachStateChangeListener(object: View.OnAttachStateChangeListener {
- override fun onViewAttachedToWindow(v: View) {}
- override fun onViewDetachedFromWindow(v: View) {
- context.config.writeConfig()
- }
- })
- return@hook
- }
- if (context.feature(Messaging::class).lastFetchConversationUserUUID == null) return@hook
+ settingMenu.inject(viewGroup, originalAddView)
+ viewGroup.addOnAttachStateChangeListener(object: View.OnAttachStateChangeListener {
+ override fun onViewAttachedToWindow(v: View) {}
+ override fun onViewDetachedFromWindow(v: View) {
+ context.config.writeConfig()
+ }
+ })
+ return@hook
+ }
+ if (context.feature(Messaging::class).lastFetchConversationUserUUID == null) return@hook
- //filter by the slot index
- if (viewGroup.getChildCount() != context.config.int(ConfigProperty.MENU_SLOT_ID)) return@hook
+ //filter by the slot index
+ if (viewGroup.getChildCount() != context.config.int(ConfigProperty.MENU_SLOT_ID)) return@hook
+ friendFeedInfoMenu.inject(viewGroup, originalAddView)
+ }
- friendFeedInfoMenu.inject(viewGroup, originalAddView)
- childView.setTag(VIEW_DRAWER, null)
}
}
diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/features/impl/ui/menus/impl/FriendFeedInfoMenu.kt b/app/src/main/kotlin/me/rhunk/snapenhance/features/impl/ui/menus/impl/FriendFeedInfoMenu.kt
@@ -45,7 +45,7 @@ class FriendFeedInfoMenu : AbstractMenu() {
return SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.ENGLISH).format(Date(timestamp))
}
- fun showProfileInfo(profile: FriendInfo) {
+ private fun showProfileInfo(profile: FriendInfo) {
var icon: Drawable? = null
try {
if (profile.bitmojiSelfieId != null && profile.bitmojiAvatarId != null) {
@@ -90,14 +90,14 @@ class FriendFeedInfoMenu : AbstractMenu() {
}
}
- fun showPreview(userId: String?, conversationId: String, androidCtx: Context?) {
+ private fun showPreview(userId: String?, conversationId: String, androidCtx: Context?) {
//query message
val messages: List<ConversationMessage>? = context.database.getMessagesFromConversationId(
conversationId,
context.config.int(ConfigProperty.MESSAGE_PREVIEW_LENGTH)
)?.reversed()
- if (messages == null || messages.isEmpty()) {
+ if (messages.isNullOrEmpty()) {
Toast.makeText(androidCtx, "No messages found", Toast.LENGTH_SHORT).show()
return
}
@@ -136,8 +136,8 @@ class FriendFeedInfoMenu : AbstractMenu() {
val targetPerson: FriendInfo? =
if (userId == null) null else participants[userId]
- targetPerson?.let {
- val timeSecondDiff = ((it.streakExpirationTimestamp - System.currentTimeMillis()) / 1000 / 60).toInt()
+ targetPerson?.streakExpirationTimestamp?.takeIf { it > 0 }?.let {
+ val timeSecondDiff = ((it - System.currentTimeMillis()) / 1000 / 60).toInt()
messageBuilder.append("\n\n")
.append("\uD83D\uDD25 ") //fire emoji
.append(context.translation.get("conversation_preview.streak_expiration").format(
diff --git a/app/src/main/kotlin/me/rhunk/snapenhance/features/impl/ui/menus/impl/OperaContextActionMenu.kt b/app/src/main/kotlin/me/rhunk/snapenhance/features/impl/ui/menus/impl/OperaContextActionMenu.kt
@@ -13,6 +13,7 @@ import me.rhunk.snapenhance.features.impl.downloader.MediaDownloader
import me.rhunk.snapenhance.features.impl.ui.menus.AbstractMenu
import me.rhunk.snapenhance.features.impl.ui.menus.ViewAppearanceHelper.applyTheme
+@SuppressLint("DiscouragedApi")
class OperaContextActionMenu : AbstractMenu() {
private val contextCardsScrollView by lazy {
context.resources.getIdentifier("context_cards_scroll_view", "id", Constants.SNAPCHAT_PACKAGE_NAME)