mirror of
https://github.com/rhunk/SnapEnhance.git
synced 2025-06-13 05:37:48 +02:00
feat(send_override): optional override dialog
- fix saveable snap in chat
This commit is contained in:
@ -1059,6 +1059,7 @@
|
|||||||
"abandon_video": "Missed Video Call"
|
"abandon_video": "Missed Video Call"
|
||||||
},
|
},
|
||||||
"gallery_media_send_override": {
|
"gallery_media_send_override": {
|
||||||
|
"always_ask": "Always Ask",
|
||||||
"ORIGINAL": "Original",
|
"ORIGINAL": "Original",
|
||||||
"NOTE": "Audio Note",
|
"NOTE": "Audio Note",
|
||||||
"SNAP": "Snap",
|
"SNAP": "Snap",
|
||||||
|
@ -73,7 +73,7 @@ object DataProcessors {
|
|||||||
val STRING_UNIQUE_SELECTION = PropertyDataProcessor(
|
val STRING_UNIQUE_SELECTION = PropertyDataProcessor(
|
||||||
type = Type.STRING_UNIQUE_SELECTION,
|
type = Type.STRING_UNIQUE_SELECTION,
|
||||||
serialize = { JsonPrimitive(it) },
|
serialize = { JsonPrimitive(it) },
|
||||||
deserialize = { obj -> obj.takeIf { !it.isJsonNull }?.asString }
|
deserialize = { obj -> obj.takeIf { !it.isJsonNull }?.asString?.takeIf { it != "false" && it != "true" } }
|
||||||
)
|
)
|
||||||
|
|
||||||
val MAP_COORDINATES = PropertyDataProcessor(
|
val MAP_COORDINATES = PropertyDataProcessor(
|
||||||
|
@ -94,7 +94,7 @@ class MessagingTweaks : ConfigContainer() {
|
|||||||
customOptionTranslationPath = "features.options.notifications"
|
customOptionTranslationPath = "features.options.notifications"
|
||||||
}
|
}
|
||||||
val messageLogger = container("message_logger", MessageLoggerConfig()) { addNotices(FeatureNotice.UNSTABLE); requireRestart() }
|
val messageLogger = container("message_logger", MessageLoggerConfig()) { addNotices(FeatureNotice.UNSTABLE); requireRestart() }
|
||||||
val galleryMediaSendOverride = boolean("gallery_media_send_override") { nativeHooks() }
|
val galleryMediaSendOverride = unique("gallery_media_send_override", "always_ask", "SNAP", "NOTE", "SAVABLE_SNAP") { requireRestart(); nativeHooks() }
|
||||||
val stripMediaMetadata = multiple("strip_media_metadata", "hide_caption_text", "hide_snap_filters", "hide_extras", "remove_audio_note_duration", "remove_audio_note_transcript_capability") { requireRestart() }
|
val stripMediaMetadata = multiple("strip_media_metadata", "hide_caption_text", "hide_snap_filters", "hide_extras", "remove_audio_note_duration", "remove_audio_note_transcript_capability") { requireRestart() }
|
||||||
val bypassMessageRetentionPolicy = boolean("bypass_message_retention_policy") { addNotices(FeatureNotice.UNSTABLE); requireRestart() }
|
val bypassMessageRetentionPolicy = boolean("bypass_message_retention_policy") { addNotices(FeatureNotice.UNSTABLE); requireRestart() }
|
||||||
val bypassMessageActionRestrictions = boolean("bypass_message_action_restrictions") { requireRestart() }
|
val bypassMessageActionRestrictions = boolean("bypass_message_action_restrictions") { requireRestart() }
|
||||||
|
@ -176,7 +176,7 @@ class MediaFilePicker : Feature("Media File Picker", loadParams = FeatureLoadPar
|
|||||||
|
|
||||||
val isAudio = context.androidContext.contentResolver.getType(event.intent.data!!)!!.startsWith("audio/")
|
val isAudio = context.androidContext.contentResolver.getType(event.intent.data!!)!!.startsWith("audio/")
|
||||||
|
|
||||||
if (isAudio || !context.config.messaging.galleryMediaSendOverride.get()) {
|
if (isAudio || context.config.messaging.galleryMediaSendOverride.getNullable() == null) {
|
||||||
startConversation(isAudio)
|
startConversation(isAudio)
|
||||||
return@subscribe
|
return@subscribe
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package me.rhunk.snapenhance.core.features.impl.messaging
|
package me.rhunk.snapenhance.core.features.impl.messaging
|
||||||
|
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.WarningAmber
|
||||||
import me.rhunk.snapenhance.common.data.ContentType
|
import me.rhunk.snapenhance.common.data.ContentType
|
||||||
import me.rhunk.snapenhance.common.util.protobuf.ProtoEditor
|
import me.rhunk.snapenhance.common.util.protobuf.ProtoEditor
|
||||||
import me.rhunk.snapenhance.common.util.protobuf.ProtoReader
|
import me.rhunk.snapenhance.common.util.protobuf.ProtoReader
|
||||||
@ -15,32 +17,14 @@ import me.rhunk.snapenhance.nativelib.NativeLib
|
|||||||
class SendOverride : Feature("Send Override", loadParams = FeatureLoadParams.INIT_SYNC) {
|
class SendOverride : Feature("Send Override", loadParams = FeatureLoadParams.INIT_SYNC) {
|
||||||
private var isLastSnapSavable = false
|
private var isLastSnapSavable = false
|
||||||
private val typeNames by lazy {
|
private val typeNames by lazy {
|
||||||
mutableListOf(
|
mutableListOf("ORIGINAL", "SNAP", "NOTE").also {
|
||||||
"ORIGINAL",
|
|
||||||
"SNAP",
|
|
||||||
"NOTE"
|
|
||||||
).also {
|
|
||||||
if (NativeLib.initialized) {
|
if (NativeLib.initialized) {
|
||||||
it.add("SAVABLE_SNAP")
|
it.add("SAVABLE_SNAP")
|
||||||
}
|
}
|
||||||
}.associateWith {
|
}.associateWith { it }
|
||||||
it
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun init() {
|
override fun init() {
|
||||||
context.event.subscribe(NativeUnaryCallEvent::class) { event ->
|
|
||||||
if (event.uri != "/messagingcoreservice.MessagingCoreService/CreateContentMessage") return@subscribe
|
|
||||||
if (isLastSnapSavable) {
|
|
||||||
val protoEditor = ProtoEditor(event.buffer)
|
|
||||||
protoEditor.edit(4) {
|
|
||||||
remove(7)
|
|
||||||
addVarInt(7, 3)
|
|
||||||
}
|
|
||||||
event.buffer = protoEditor.toByteArray()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val stripSnapMetadata = context.config.messaging.stripMediaMetadata.get()
|
val stripSnapMetadata = context.config.messaging.stripMediaMetadata.get()
|
||||||
|
|
||||||
context.event.subscribe(SendMessageWithContentEvent::class, {
|
context.event.subscribe(SendMessageWithContentEvent::class, {
|
||||||
@ -90,9 +74,28 @@ class SendOverride : Feature("Send Override", loadParams = FeatureLoadParams.INI
|
|||||||
event.messageContent.content = newMessageContent
|
event.messageContent.content = newMessageContent
|
||||||
}
|
}
|
||||||
|
|
||||||
context.event.subscribe(SendMessageWithContentEvent::class, {
|
val configOverrideType = context.config.messaging.galleryMediaSendOverride.getNullable() ?: return
|
||||||
context.config.messaging.galleryMediaSendOverride.get()
|
|
||||||
}) { event ->
|
context.event.subscribe(NativeUnaryCallEvent::class) { event ->
|
||||||
|
if (event.uri != "/messagingcoreservice.MessagingCoreService/CreateContentMessage") return@subscribe
|
||||||
|
if (isLastSnapSavable) {
|
||||||
|
event.buffer = ProtoEditor(event.buffer).apply {
|
||||||
|
edit {
|
||||||
|
edit(4) {
|
||||||
|
remove(7)
|
||||||
|
addVarInt(7, 3) // savePolicy = VIEW_SESSION
|
||||||
|
}
|
||||||
|
add(6) {
|
||||||
|
from(9) {
|
||||||
|
addVarInt(1, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.toByteArray()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
context.event.subscribe(SendMessageWithContentEvent::class) { event ->
|
||||||
isLastSnapSavable = false
|
isLastSnapSavable = false
|
||||||
if (event.destinations.stories?.isNotEmpty() == true && event.destinations.conversations?.isEmpty() == true) return@subscribe
|
if (event.destinations.stories?.isNotEmpty() == true && event.destinations.conversations?.isEmpty() == true) return@subscribe
|
||||||
val localMessageContent = event.messageContent
|
val localMessageContent = event.messageContent
|
||||||
@ -104,43 +107,51 @@ class SendOverride : Feature("Send Override", loadParams = FeatureLoadParams.INI
|
|||||||
|
|
||||||
event.canceled = true
|
event.canceled = true
|
||||||
|
|
||||||
|
fun sendMedia(overrideType: String): Boolean {
|
||||||
|
if (overrideType != "ORIGINAL" && messageProtoReader.followPath(3)?.getCount(3) != 1) {
|
||||||
|
context.inAppOverlay.showStatusToast(
|
||||||
|
icon = Icons.Default.WarningAmber,
|
||||||
|
context.translation["gallery_media_send_override.multiple_media_toast"]
|
||||||
|
)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
when (overrideType) {
|
||||||
|
"SNAP", "SAVABLE_SNAP" -> {
|
||||||
|
val extras = messageProtoReader.followPath(3, 3, 13)?.getBuffer()
|
||||||
|
|
||||||
|
localMessageContent.contentType = ContentType.SNAP
|
||||||
|
localMessageContent.content = MessageSender.redSnapProto(extras)
|
||||||
|
if (overrideType == "SAVABLE_SNAP") {
|
||||||
|
isLastSnapSavable = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"NOTE" -> {
|
||||||
|
localMessageContent.contentType = ContentType.NOTE
|
||||||
|
localMessageContent.content =
|
||||||
|
MessageSender.audioNoteProto(messageProtoReader.getVarInt(3, 3, 5, 1, 1, 15) ?: context.feature(MediaFilePicker::class).lastMediaDuration ?: 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configOverrideType != "always_ask") {
|
||||||
|
if (sendMedia(configOverrideType)) {
|
||||||
|
event.invokeOriginal()
|
||||||
|
}
|
||||||
|
return@subscribe
|
||||||
|
}
|
||||||
|
|
||||||
context.runOnUiThread {
|
context.runOnUiThread {
|
||||||
ViewAppearanceHelper.newAlertDialogBuilder(context.mainActivity!!)
|
ViewAppearanceHelper.newAlertDialogBuilder(context.mainActivity!!)
|
||||||
.setItems(typeNames.values.map {
|
.setItems(typeNames.values.map {
|
||||||
context.translation["features.options.gallery_media_send_override.$it"]
|
context.translation["features.options.gallery_media_send_override.$it"]
|
||||||
}.toTypedArray()) { dialog, which ->
|
}.toTypedArray()) { dialog, which ->
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
val overrideType = typeNames.keys.toTypedArray()[which]
|
if (sendMedia(typeNames.keys.toTypedArray()[which])) {
|
||||||
|
event.invokeOriginal()
|
||||||
if (overrideType != "ORIGINAL" && messageProtoReader.followPath(3)?.getCount(3) != 1) {
|
|
||||||
context.runOnUiThread {
|
|
||||||
ViewAppearanceHelper.newAlertDialogBuilder(context.mainActivity!!)
|
|
||||||
.setMessage(context.translation["gallery_media_send_override.multiple_media_toast"])
|
|
||||||
.setPositiveButton(context.translation["button.ok"], null)
|
|
||||||
.show()
|
|
||||||
}
|
|
||||||
return@setItems
|
|
||||||
}
|
}
|
||||||
|
|
||||||
when (overrideType) {
|
|
||||||
"SNAP", "SAVABLE_SNAP" -> {
|
|
||||||
val extras = messageProtoReader.followPath(3, 3, 13)?.getBuffer()
|
|
||||||
|
|
||||||
localMessageContent.contentType = ContentType.SNAP
|
|
||||||
localMessageContent.content = MessageSender.redSnapProto(extras)
|
|
||||||
if (overrideType == "SAVABLE_SNAP") {
|
|
||||||
isLastSnapSavable = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"NOTE" -> {
|
|
||||||
localMessageContent.contentType = ContentType.NOTE
|
|
||||||
localMessageContent.content =
|
|
||||||
MessageSender.audioNoteProto(messageProtoReader.getVarInt(3, 3, 5, 1, 1, 15) ?: context.feature(MediaFilePicker::class).lastMediaDuration ?: 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
event.invokeOriginal()
|
|
||||||
}
|
}
|
||||||
.setNegativeButton(context.translation["button.cancel"], null)
|
.setNegativeButton(context.translation["button.cancel"], null)
|
||||||
.show()
|
.show()
|
||||||
|
Reference in New Issue
Block a user