mirror of
https://github.com/rhunk/SnapEnhance.git
synced 2025-06-13 05:37:48 +02:00
feat(core): long press to force download
This commit is contained in:
@ -94,6 +94,7 @@ class SnapEnhance {
|
||||
val isMainActivityNotNull = appContext.mainActivity != null
|
||||
appContext.mainActivity = this
|
||||
if (isMainActivityNotNull || !appContext.mappings.isMappingsLoaded) return@hookMainActivity
|
||||
appContext.isMainActivityPaused = false
|
||||
onActivityCreate()
|
||||
jetpackComposeResourceHook()
|
||||
appContext.actionManager.onNewIntent(intent)
|
||||
@ -108,18 +109,13 @@ class SnapEnhance {
|
||||
appContext.actionManager.onNewIntent(param.argNullable(0))
|
||||
}
|
||||
|
||||
var activityWasResumed = false
|
||||
//we need to reload the config when the app is resumed
|
||||
//FIXME: called twice at first launch
|
||||
hookMainActivity("onResume") {
|
||||
appContext.isMainActivityPaused = false
|
||||
if (!activityWasResumed) {
|
||||
activityWasResumed = true
|
||||
return@hookMainActivity
|
||||
if (appContext.isMainActivityPaused.also {
|
||||
appContext.isMainActivityPaused = false
|
||||
}) {
|
||||
appContext.reloadConfig()
|
||||
syncRemote()
|
||||
}
|
||||
|
||||
appContext.reloadConfig()
|
||||
syncRemote()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,10 +75,11 @@ class MediaDownloader : MessagingRuleFeature("MediaDownloader", MessagingRuleTyp
|
||||
mediaAuthor: String,
|
||||
creationTimestamp: Long? = null,
|
||||
downloadSource: MediaDownloadSource,
|
||||
friendInfo: FriendInfo? = null
|
||||
friendInfo: FriendInfo? = null,
|
||||
forceAllowDuplicate: Boolean = false
|
||||
): DownloadManagerClient {
|
||||
val generatedHash = (
|
||||
if (!context.config.downloader.allowDuplicate.get()) mediaIdentifier
|
||||
if (!context.config.downloader.allowDuplicate.get() && !forceAllowDuplicate) mediaIdentifier
|
||||
else UUID.randomUUID().toString()
|
||||
).longHashCode().absoluteValue.toString(16)
|
||||
|
||||
@ -135,10 +136,10 @@ class MediaDownloader : MessagingRuleFeature("MediaDownloader", MessagingRuleTyp
|
||||
/*
|
||||
* Download the last seen media
|
||||
*/
|
||||
fun downloadLastOperaMediaAsync() {
|
||||
fun downloadLastOperaMediaAsync(allowDuplicate: Boolean) {
|
||||
if (lastSeenMapParams == null || lastSeenMediaInfoMap == null) return
|
||||
context.executeAsync {
|
||||
handleOperaMedia(lastSeenMapParams!!, lastSeenMediaInfoMap!!, true)
|
||||
handleOperaMedia(lastSeenMapParams!!, lastSeenMediaInfoMap!!, true, allowDuplicate)
|
||||
}
|
||||
}
|
||||
|
||||
@ -162,9 +163,6 @@ class MediaDownloader : MessagingRuleFeature("MediaDownloader", MessagingRuleTyp
|
||||
setNeutralButton("Copy") { _, _ ->
|
||||
this@MediaDownloader.context.copyToClipboard(mediaInfoText)
|
||||
}
|
||||
setPositiveButton("Download") { _, _ ->
|
||||
downloadLastOperaMediaAsync()
|
||||
}
|
||||
setNegativeButton("Cancel") { dialog, _ -> dialog.dismiss() }
|
||||
}.show()
|
||||
}
|
||||
@ -229,7 +227,8 @@ class MediaDownloader : MessagingRuleFeature("MediaDownloader", MessagingRuleTyp
|
||||
private fun handleOperaMedia(
|
||||
paramMap: ParamMap,
|
||||
mediaInfoMap: Map<SplitMediaAssetType, MediaInfo>,
|
||||
forceDownload: Boolean
|
||||
forceDownload: Boolean,
|
||||
forceAllowDuplicate: Boolean = false
|
||||
) {
|
||||
//messages
|
||||
paramMap["MESSAGE_ID"]?.toString()?.takeIf { forceDownload || canAutoDownload("friend_snaps") }?.let { id ->
|
||||
@ -257,7 +256,8 @@ class MediaDownloader : MessagingRuleFeature("MediaDownloader", MessagingRuleTyp
|
||||
mediaAuthor = authorUsername,
|
||||
creationTimestamp = conversationMessage.creationTimestamp,
|
||||
downloadSource = MediaDownloadSource.CHAT_MEDIA,
|
||||
friendInfo = author
|
||||
friendInfo = author,
|
||||
forceAllowDuplicate = forceAllowDuplicate
|
||||
), mediaInfoMap)
|
||||
|
||||
return
|
||||
@ -301,7 +301,8 @@ class MediaDownloader : MessagingRuleFeature("MediaDownloader", MessagingRuleTyp
|
||||
creationTimestamp = paramMap["PLAYABLE_STORY_SNAP_RECORD"]?.toString()?.substringAfter("timestamp=")
|
||||
?.substringBefore(",")?.toLongOrNull(),
|
||||
downloadSource = MediaDownloadSource.STORY,
|
||||
friendInfo = author
|
||||
friendInfo = author,
|
||||
forceAllowDuplicate = forceAllowDuplicate,
|
||||
), mediaInfoMap)
|
||||
return
|
||||
}
|
||||
@ -331,6 +332,7 @@ class MediaDownloader : MessagingRuleFeature("MediaDownloader", MessagingRuleTyp
|
||||
mediaAuthor = author,
|
||||
downloadSource = MediaDownloadSource.PUBLIC_STORY,
|
||||
creationTimestamp = paramMap["SNAP_TIMESTAMP"]?.toString()?.toLongOrNull(),
|
||||
forceAllowDuplicate = forceAllowDuplicate,
|
||||
), mediaInfoMap)
|
||||
return
|
||||
}
|
||||
@ -342,6 +344,7 @@ class MediaDownloader : MessagingRuleFeature("MediaDownloader", MessagingRuleTyp
|
||||
downloadSource = MediaDownloadSource.SPOTLIGHT,
|
||||
mediaAuthor = paramMap["CREATOR_DISPLAY_NAME"].toString(),
|
||||
creationTimestamp = paramMap["SNAP_TIMESTAMP"]?.toString()?.toLongOrNull(),
|
||||
forceAllowDuplicate = forceAllowDuplicate,
|
||||
), mediaInfoMap)
|
||||
return
|
||||
}
|
||||
@ -435,7 +438,8 @@ class MediaDownloader : MessagingRuleFeature("MediaDownloader", MessagingRuleTyp
|
||||
provideDownloadManagerClient(
|
||||
mediaIdentifier = "${paramMap["STORY_ID"]}-${firstChapter.offset}-${lastChapter.offset}",
|
||||
downloadSource = MediaDownloadSource.PUBLIC_STORY,
|
||||
mediaAuthor = storyName
|
||||
mediaAuthor = storyName,
|
||||
forceAllowDuplicate = forceAllowDuplicate,
|
||||
).downloadDashMedia(
|
||||
playlistUrl,
|
||||
firstChapter.offset.plus(100),
|
||||
@ -505,7 +509,8 @@ class MediaDownloader : MessagingRuleFeature("MediaDownloader", MessagingRuleTyp
|
||||
friendInfo: FriendInfo,
|
||||
message: ConversationMessage,
|
||||
authorName: String,
|
||||
attachments: List<DecodedAttachment>
|
||||
attachments: List<DecodedAttachment>,
|
||||
forceAllowDuplicate: Boolean = false
|
||||
) {
|
||||
//TODO: stickers
|
||||
attachments.forEach { attachment ->
|
||||
@ -514,7 +519,8 @@ class MediaDownloader : MessagingRuleFeature("MediaDownloader", MessagingRuleTyp
|
||||
mediaIdentifier = "${message.clientConversationId}${message.senderId}${message.serverMessageId}${attachment.mediaUniqueId}",
|
||||
downloadSource = MediaDownloadSource.CHAT_MEDIA,
|
||||
mediaAuthor = authorName,
|
||||
friendInfo = friendInfo
|
||||
friendInfo = friendInfo,
|
||||
forceAllowDuplicate = forceAllowDuplicate,
|
||||
).downloadSingleMedia(
|
||||
mediaData = attachment.mediaUrlKey!!,
|
||||
mediaType = DownloadMediaType.PROTO_MEDIA,
|
||||
@ -531,7 +537,7 @@ class MediaDownloader : MessagingRuleFeature("MediaDownloader", MessagingRuleTyp
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
fun downloadMessageId(messageId: Long, isPreview: Boolean = false) {
|
||||
fun downloadMessageId(messageId: Long, forceAllowDuplicate: Boolean = false, isPreview: Boolean = false) {
|
||||
val messageLogger = context.feature(MessageLogger::class)
|
||||
val message = context.database.getConversationMessageFromId(messageId) ?: throw Exception("Message not found in database")
|
||||
|
||||
@ -570,7 +576,8 @@ class MediaDownloader : MessagingRuleFeature("MediaDownloader", MessagingRuleTyp
|
||||
context.mainActivity == null // we can't show alert dialogs when it downloads from a notification, so it downloads the first one
|
||||
) {
|
||||
downloadMessageAttachments(friendInfo, message, authorName,
|
||||
listOf(decodedAttachments.first())
|
||||
listOf(decodedAttachments.first()),
|
||||
forceAllowDuplicate = forceAllowDuplicate
|
||||
)
|
||||
return
|
||||
}
|
||||
@ -595,7 +602,9 @@ class MediaDownloader : MessagingRuleFeature("MediaDownloader", MessagingRuleTyp
|
||||
setTitle(translations["select_attachments_title"])
|
||||
setNegativeButton(this@MediaDownloader.context.translation["button.cancel"]) { dialog, _ -> dialog.dismiss() }
|
||||
setPositiveButton(this@MediaDownloader.context.translation["button.download"]) { _, _ ->
|
||||
downloadMessageAttachments(friendInfo, message, authorName, selectedAttachments.map { decodedAttachments[it] })
|
||||
downloadMessageAttachments(friendInfo, message, authorName, selectedAttachments.map { decodedAttachments[it] },
|
||||
forceAllowDuplicate = forceAllowDuplicate
|
||||
)
|
||||
}
|
||||
}.show()
|
||||
}
|
||||
@ -698,9 +707,12 @@ class MediaDownloader : MessagingRuleFeature("MediaDownloader", MessagingRuleTyp
|
||||
/**
|
||||
* Called when a message is focused in chat
|
||||
*/
|
||||
fun onMessageActionMenu(isPreviewMode: Boolean) {
|
||||
fun onMessageActionMenu(isPreviewMode: Boolean, forceAllowDuplicate: Boolean = false) {
|
||||
val messaging = context.feature(Messaging::class)
|
||||
if (messaging.openedConversationUUID == null) return
|
||||
downloadMessageId(messaging.lastFocusedMessageId, isPreviewMode)
|
||||
|
||||
context.executeAsync {
|
||||
downloadMessageId(messaging.lastFocusedMessageId, forceAllowDuplicate, isPreviewMode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ import me.rhunk.snapenhance.core.ui.triggerCloseTouchEvent
|
||||
import me.rhunk.snapenhance.core.util.hook.HookStage
|
||||
import me.rhunk.snapenhance.core.util.hook.hook
|
||||
import me.rhunk.snapenhance.core.util.ktx.getDimens
|
||||
import me.rhunk.snapenhance.core.util.ktx.vibrateLongPress
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
|
||||
@ -80,7 +81,7 @@ class ChatActionMenu : AbstractMenu() {
|
||||
|
||||
override fun init() {
|
||||
runCatching {
|
||||
if (!context.config.downloader.chatDownloadContextMenu.get() && context.config.messaging.messageLogger.globalState != true && !context.isDeveloper) return
|
||||
if (!context.config.downloader.downloadContextMenu.get() && context.config.messaging.messageLogger.globalState != true && !context.isDeveloper) return
|
||||
context.androidContext.classLoader.loadClass("com.snap.messaging.chat.features.actionmenu.ActionMenuChatItemContainer")
|
||||
.hook("onMeasure", HookStage.BEFORE) { param ->
|
||||
param.setArg(1,
|
||||
@ -130,12 +131,14 @@ class ChatActionMenu : AbstractMenu() {
|
||||
}
|
||||
}
|
||||
|
||||
if (context.config.downloader.chatDownloadContextMenu.get()) {
|
||||
if (context.config.downloader.downloadContextMenu.get()) {
|
||||
val mediaDownloader = context.feature(MediaDownloader::class)
|
||||
|
||||
injectButton(Button(viewGroup.context).apply {
|
||||
text = this@ChatActionMenu.context.translation["chat_action_menu.preview_button"]
|
||||
setOnClickListener {
|
||||
closeActionMenu()
|
||||
this@ChatActionMenu.context.executeAsync { feature(MediaDownloader::class).onMessageActionMenu(true) }
|
||||
mediaDownloader.onMessageActionMenu(true)
|
||||
}
|
||||
})
|
||||
|
||||
@ -143,9 +146,13 @@ class ChatActionMenu : AbstractMenu() {
|
||||
text = this@ChatActionMenu.context.translation["chat_action_menu.download_button"]
|
||||
setOnClickListener {
|
||||
closeActionMenu()
|
||||
this@ChatActionMenu.context.executeAsync {
|
||||
feature(MediaDownloader::class).onMessageActionMenu(false)
|
||||
}
|
||||
mediaDownloader.onMessageActionMenu(false)
|
||||
}
|
||||
setOnLongClickListener {
|
||||
closeActionMenu()
|
||||
context.vibrateLongPress()
|
||||
mediaDownloader.onMessageActionMenu(isPreviewMode = false, forceAllowDuplicate = true)
|
||||
true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import me.rhunk.snapenhance.core.ui.applyTheme
|
||||
import me.rhunk.snapenhance.core.ui.menu.AbstractMenu
|
||||
import me.rhunk.snapenhance.core.ui.triggerCloseTouchEvent
|
||||
import me.rhunk.snapenhance.core.util.ktx.getId
|
||||
import me.rhunk.snapenhance.core.util.ktx.vibrateLongPress
|
||||
import me.rhunk.snapenhance.core.wrapper.impl.ScSize
|
||||
import java.text.DateFormat
|
||||
import java.util.Date
|
||||
@ -128,14 +129,22 @@ class OperaContextActionMenu : AbstractMenu() {
|
||||
}
|
||||
}
|
||||
|
||||
linearLayout.addView(Button(view.context).apply {
|
||||
text = translation["download"]
|
||||
setOnClickListener {
|
||||
mediaDownloader.downloadLastOperaMediaAsync()
|
||||
parentView.triggerCloseTouchEvent()
|
||||
}
|
||||
applyTheme(isAmoled = false)
|
||||
})
|
||||
if (context.config.downloader.downloadContextMenu.get()) {
|
||||
linearLayout.addView(Button(view.context).apply {
|
||||
text = translation["download"]
|
||||
setOnClickListener {
|
||||
mediaDownloader.downloadLastOperaMediaAsync(allowDuplicate = false)
|
||||
parentView.triggerCloseTouchEvent()
|
||||
}
|
||||
setOnLongClickListener {
|
||||
context.vibrateLongPress()
|
||||
mediaDownloader.downloadLastOperaMediaAsync(allowDuplicate = true)
|
||||
parentView.triggerCloseTouchEvent()
|
||||
true
|
||||
}
|
||||
applyTheme(isAmoled = false)
|
||||
})
|
||||
}
|
||||
|
||||
if (context.isDeveloper) {
|
||||
linearLayout.addView(Button(view.context).apply {
|
||||
|
@ -11,6 +11,7 @@ import me.rhunk.snapenhance.core.ui.children
|
||||
import me.rhunk.snapenhance.core.ui.menu.AbstractMenu
|
||||
import me.rhunk.snapenhance.core.util.ktx.getDimens
|
||||
import me.rhunk.snapenhance.core.util.ktx.getDrawable
|
||||
import me.rhunk.snapenhance.core.util.ktx.vibrateLongPress
|
||||
|
||||
class OperaDownloadIconMenu : AbstractMenu() {
|
||||
private val downloadSvgDrawable by lazy { context.resources.getDrawable("svg_download", context.androidContext.theme) }
|
||||
@ -21,6 +22,8 @@ class OperaDownloadIconMenu : AbstractMenu() {
|
||||
override fun inject(parent: ViewGroup, view: View, viewConsumer: (View) -> Unit) {
|
||||
if (!context.config.downloader.operaDownloadButton.get()) return
|
||||
|
||||
val mediaDownloader = context.feature(MediaDownloader::class)
|
||||
|
||||
parent.addView(ImageView(view.context).apply {
|
||||
setImageDrawable(downloadSvgDrawable)
|
||||
setColorFilter(Color.WHITE)
|
||||
@ -33,7 +36,12 @@ class OperaDownloadIconMenu : AbstractMenu() {
|
||||
gravity = Gravity.TOP or Gravity.END
|
||||
}
|
||||
setOnClickListener {
|
||||
this@OperaDownloadIconMenu.context.feature(MediaDownloader::class).downloadLastOperaMediaAsync()
|
||||
mediaDownloader.downloadLastOperaMediaAsync(allowDuplicate = false)
|
||||
}
|
||||
setOnLongClickListener {
|
||||
context.vibrateLongPress()
|
||||
mediaDownloader.downloadLastOperaMediaAsync(allowDuplicate = true)
|
||||
true
|
||||
}
|
||||
addOnAttachStateChangeListener(object: View.OnAttachStateChangeListener {
|
||||
override fun onViewAttachedToWindow(v: View) {
|
||||
|
@ -1,10 +1,13 @@
|
||||
package me.rhunk.snapenhance.core.util.ktx
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.res.Resources
|
||||
import android.content.res.Resources.Theme
|
||||
import android.content.res.TypedArray
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.VibrationEffect
|
||||
import android.os.Vibrator
|
||||
import me.rhunk.snapenhance.common.Constants
|
||||
|
||||
|
||||
@ -31,3 +34,7 @@ fun Resources.getStyledAttributes(name: String, theme: Theme): TypedArray {
|
||||
fun Resources.getDrawable(name: String, theme: Theme): Drawable {
|
||||
return getDrawable(getIdentifier(name, "drawable"), theme)
|
||||
}
|
||||
|
||||
fun Context.vibrateLongPress() {
|
||||
getSystemService(Vibrator::class.java).vibrate(VibrationEffect.createOneShot(50, VibrationEffect.DEFAULT_AMPLITUDE))
|
||||
}
|
Reference in New Issue
Block a user