perf: ui improvements

This commit is contained in:
rhunk
2023-06-04 15:02:06 +02:00
parent 85335dafa8
commit fc94117029
3 changed files with 38 additions and 66 deletions

View File

@@ -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
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
friendFeedInfoMenu.inject(viewGroup, originalAddView)
}
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
friendFeedInfoMenu.inject(viewGroup, originalAddView)
childView.setTag(VIEW_DRAWER, null)
}
}

View File

@@ -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(

View File

@@ -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)