feat: better ff message preview

This commit is contained in:
rhunk 2023-10-08 21:03:39 +02:00
parent 72b0308506
commit e0f6d05676
3 changed files with 69 additions and 35 deletions

View File

@ -220,9 +220,15 @@
"name": "AMOLED Dark Mode", "name": "AMOLED Dark Mode",
"description": "Enables AMOLED dark mode\nMake sure Snapchats Dark mode is enabled" "description": "Enables AMOLED dark mode\nMake sure Snapchats Dark mode is enabled"
}, },
"conversation_preview_in_friend_feed": { "friend_feed_message_preview": {
"name": "Preview in FF", "name": "Friend Feed Message Preview",
"description": "Shows a preview of the last messages in the Friend Feed" "description": "Shows a preview of the last messages in the Friend Feed",
"properties": {
"amount": {
"name": "Amount",
"description": "The amount of messages to get previewed"
}
}
}, },
"bootstrap_override": { "bootstrap_override": {
"name": "Bootstrap Override", "name": "Bootstrap Override",

View File

@ -11,14 +11,18 @@ class UserInterfaceTweaks : ConfigContainer() {
val homeTab = unique("home_tab", *ClientBootstrapOverride.tabs) { addNotices(FeatureNotice.UNSTABLE) } val homeTab = unique("home_tab", *ClientBootstrapOverride.tabs) { addNotices(FeatureNotice.UNSTABLE) }
} }
inner class FriendFeedMessagePreview : ConfigContainer(hasGlobalState = true) {
val amount = integer("amount", defaultValue = 1)
}
val friendFeedMenuButtons = multiple( val friendFeedMenuButtons = multiple(
"friend_feed_menu_buttons","conversation_info", *MessagingRuleType.values().toList().filter { it.showInFriendMenu }.map { it.key }.toTypedArray() "friend_feed_menu_buttons","conversation_info", *MessagingRuleType.entries.filter { it.showInFriendMenu }.map { it.key }.toTypedArray()
).apply { ).apply {
set(mutableListOf("conversation_info", MessagingRuleType.STEALTH.key)) set(mutableListOf("conversation_info", MessagingRuleType.STEALTH.key))
} }
val friendFeedMenuPosition = integer("friend_feed_menu_position", defaultValue = 1) val friendFeedMenuPosition = integer("friend_feed_menu_position", defaultValue = 1)
val amoledDarkMode = boolean("amoled_dark_mode") { addNotices(FeatureNotice.UNSTABLE); requireRestart() } val amoledDarkMode = boolean("amoled_dark_mode") { addNotices(FeatureNotice.UNSTABLE); requireRestart() }
val conversationPreviewInFriendFeed = boolean("conversation_preview_in_friend_feed") { requireRestart() } val friendFeedMessagePreview = container("friend_feed_message_preview", FriendFeedMessagePreview()) { requireRestart() }
val bootstrapOverride = container("bootstrap_override", BootstrapOverride()) { requireRestart() } val bootstrapOverride = container("bootstrap_override", BootstrapOverride()) { requireRestart() }
val mapFriendNameTags = boolean("map_friend_nametags") { requireRestart() } val mapFriendNameTags = boolean("map_friend_nametags") { requireRestart() }
val streakExpirationInfo = boolean("streak_expiration_info") { requireRestart() } val streakExpirationInfo = boolean("streak_expiration_info") { requireRestart() }

View File

@ -3,11 +3,12 @@ package me.rhunk.snapenhance.features.impl.ui
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.graphics.Canvas import android.graphics.Canvas
import android.graphics.Paint import android.graphics.Paint
import android.graphics.Rect
import android.graphics.drawable.ShapeDrawable import android.graphics.drawable.ShapeDrawable
import android.graphics.drawable.shapes.Shape import android.graphics.drawable.shapes.Shape
import android.text.TextPaint
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.FrameLayout
import me.rhunk.snapenhance.Constants import me.rhunk.snapenhance.Constants
import me.rhunk.snapenhance.core.event.events.impl.BindViewEvent import me.rhunk.snapenhance.core.event.events.impl.BindViewEvent
import me.rhunk.snapenhance.core.util.protobuf.ProtoReader import me.rhunk.snapenhance.core.util.protobuf.ProtoReader
@ -16,64 +17,87 @@ import me.rhunk.snapenhance.features.Feature
import me.rhunk.snapenhance.features.FeatureLoadParams import me.rhunk.snapenhance.features.FeatureLoadParams
import me.rhunk.snapenhance.ui.addForegroundDrawable import me.rhunk.snapenhance.ui.addForegroundDrawable
import me.rhunk.snapenhance.ui.removeForegroundDrawable import me.rhunk.snapenhance.ui.removeForegroundDrawable
import kotlin.math.absoluteValue
@SuppressLint("DiscouragedApi")
class FriendFeedMessagePreview : Feature("FriendFeedMessagePreview", loadParams = FeatureLoadParams.ACTIVITY_CREATE_SYNC) { class FriendFeedMessagePreview : Feature("FriendFeedMessagePreview", loadParams = FeatureLoadParams.ACTIVITY_CREATE_SYNC) {
@SuppressLint("SetTextI18n", "DiscouragedApi") private val sigColorTextPrimary by lazy {
context.mainActivity!!.theme.obtainStyledAttributes(
intArrayOf(context.resources.getIdentifier("sigColorTextPrimary", "attr", Constants.SNAPCHAT_PACKAGE_NAME))
).getColor(0, 0)
}
private fun getDimens(name: String) = context.resources.getDimensionPixelSize(context.resources.getIdentifier(name, "dimen", Constants.SNAPCHAT_PACKAGE_NAME))
override fun onActivityCreate() { override fun onActivityCreate() {
if (!context.config.userInterface.conversationPreviewInFriendFeed.get()) return val setting = context.config.userInterface.friendFeedMessagePreview
if (setting.globalState != true) return
val ffItemId = context.resources.getIdentifier("ff_item", "id", Constants.SNAPCHAT_PACKAGE_NAME) val ffItemId = context.resources.getIdentifier("ff_item", "id", Constants.SNAPCHAT_PACKAGE_NAME)
val sigColorTextPrimary by lazy { val secondaryTextSize = getDimens("ff_feed_cell_secondary_text_size").toFloat()
context.mainActivity!!.theme.obtainStyledAttributes( val ffSdlAvatarMargin = getDimens("ff_sdl_avatar_margin")
intArrayOf(context.resources.getIdentifier("sigColorTextPrimary", "attr", Constants.SNAPCHAT_PACKAGE_NAME)) val ffSdlAvatarSize = getDimens("ff_sdl_avatar_size")
).getColor(0, 0) val ffSdlAvatarStartMargin = getDimens("ff_sdl_avatar_start_margin")
} val ffSdlPrimaryTextStartMargin = getDimens("ff_sdl_primary_text_start_margin").toFloat()
val ffSdlAvatarMargin = context.resources.getDimensionPixelSize(context.resources.getIdentifier("ff_sdl_avatar_margin", "dimen", Constants.SNAPCHAT_PACKAGE_NAME)) val feedEntryHeight = ffSdlAvatarSize + ffSdlAvatarMargin * 2 + ffSdlAvatarStartMargin
val ffSdlAvatarSize = context.resources.getDimensionPixelSize(context.resources.getIdentifier("ff_sdl_avatar_size", "dimen", Constants.SNAPCHAT_PACKAGE_NAME)) val separatorHeight = (context.resources.displayMetrics.density * 2).toInt()
val ffSdlAvatarStartMargin = context.resources.getDimensionPixelSize(context.resources.getIdentifier("ff_sdl_avatar_start_margin", "dimen", Constants.SNAPCHAT_PACKAGE_NAME)) val textPaint = TextPaint().apply {
val ffSdlPrimaryTextStartMargin = context.resources.getDimensionPixelSize(context.resources.getIdentifier("ff_sdl_primary_text_start_margin", "dimen", Constants.SNAPCHAT_PACKAGE_NAME)) textSize = secondaryTextSize
}
context.event.subscribe(BindViewEvent::class) { param -> context.event.subscribe(BindViewEvent::class) { param ->
param.friendFeedItem { conversationId -> param.friendFeedItem { conversationId ->
val frameLayout = param.view as FrameLayout val frameLayout = param.view as ViewGroup
val ffItem = frameLayout.findViewById<View>(ffItemId) val ffItem = frameLayout.findViewById<View>(ffItemId)
context.log.verbose("updated $conversationId")
ffItem.layoutParams = ffItem.layoutParams.apply { ffItem.layoutParams = ffItem.layoutParams.apply {
height = ViewGroup.LayoutParams.MATCH_PARENT height = ViewGroup.LayoutParams.MATCH_PARENT
} }
frameLayout.removeForegroundDrawable("ffItem") frameLayout.removeForegroundDrawable("ffItem")
val stringMessages = context.database.getMessagesFromConversationId(conversationId, 5)?.mapNotNull { message -> val stringMessages = context.database.getMessagesFromConversationId(conversationId, setting.amount.get().absoluteValue)?.mapNotNull { message ->
message.messageContent val messageContainer = message.messageContent
?.let { ProtoReader(it) } ?.let { ProtoReader(it) }
?.followPath(4, 4) ?.followPath(4, 4)
?.let { messageContainer -> ?: return@mapNotNull null
messageContainer.getString(2, 1) ?: ContentType.fromMessageContainer(messageContainer)?.name ?: return@mapNotNull null
} val messageString = messageContainer.getString(2, 1)
} ?: return@friendFeedItem ?: ContentType.fromMessageContainer(messageContainer)?.name
?: return@mapNotNull null
val friendName = context.database.getFriendInfo(message.senderId ?: return@mapNotNull null)?.let { it.displayName?: it.mutableUsername } ?: "Unknown"
"$friendName: $messageString"
}?.reversed() ?: return@friendFeedItem
var maxTextHeight = 0
val previewContainerHeight = stringMessages.sumOf { msg ->
val rect = Rect()
textPaint.getTextBounds(msg, 0, msg.length, rect)
rect.height().also {
if (it > maxTextHeight) maxTextHeight = it
}.plus(separatorHeight)
}
ffItem.layoutParams = ffItem.layoutParams.apply {
height = feedEntryHeight + previewContainerHeight + separatorHeight
}
frameLayout.addForegroundDrawable("ffItem", ShapeDrawable(object: Shape() { frameLayout.addForegroundDrawable("ffItem", ShapeDrawable(object: Shape() {
override fun draw(canvas: Canvas, paint: Paint) { override fun draw(canvas: Canvas, paint: Paint) {
val offsetY = canvas.height.toFloat() - (stringMessages.size * 30f) val offsetY = canvas.height.toFloat() - previewContainerHeight
stringMessages.forEachIndexed { index, messageString -> stringMessages.forEachIndexed { index, messageString ->
paint.textSize = 30f paint.textSize = secondaryTextSize
paint.color = sigColorTextPrimary paint.color = sigColorTextPrimary
canvas.drawText(messageString, canvas.drawText(messageString,
ffSdlAvatarStartMargin.toFloat() + ffSdlAvatarMargin * 2 + ffSdlAvatarSize + ffSdlPrimaryTextStartMargin, feedEntryHeight + ffSdlPrimaryTextStartMargin,
offsetY + (index * 30f), offsetY + index * maxTextHeight,
paint paint
) )
} }
ffItem.layoutParams = ffItem.layoutParams.apply {
height = ffSdlAvatarSize + ffSdlAvatarMargin * 2 + ffSdlAvatarStartMargin + (stringMessages.size * 30)
}
} }
})) }))
} }