feat: streaks reminder

- add streak indicator in social
- fix dialogs
- fix container global state
This commit is contained in:
rhunk
2023-08-24 02:15:06 +02:00
parent 7703d3f007
commit 3eb8c8f015
29 changed files with 305 additions and 90 deletions

View File

@ -309,6 +309,16 @@
}
}
},
"streaks_reminder": {
"name": "Streaks Reminder",
"description": "Reminds you to keep your streaks",
"properties": {
"interval": {
"name": "Interval",
"description": "The interval between each reminder (in hours)"
}
}
},
"experimental": {
"name": "Experimental",
"description": "Experimental features",

View File

@ -35,14 +35,14 @@ class BridgeClient(
fun start(callback: (Boolean) -> Unit) {
this.future = CompletableFuture()
//TODO: randomize package name
with(context.androidContext) {
//ensure the remote process is running
startActivity(Intent()
.setClassName(BuildConfig.APPLICATION_ID, ForceStartActivity::class.java.name)
.setClassName(BuildConfig.APPLICATION_ID, "me.rhunk.snapenhance.bridge.ForceStartActivity")
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
)
//TODO: randomize package name
val intent = Intent()
.setClassName(BuildConfig.APPLICATION_ID, "me.rhunk.snapenhance.bridge.BridgeService")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {

View File

@ -1,11 +0,0 @@
package me.rhunk.snapenhance.bridge
import android.app.Activity
import android.os.Bundle
class ForceStartActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
finish()
}
}

View File

@ -6,10 +6,11 @@ import kotlin.reflect.KProperty
typealias ConfigParamsBuilder = ConfigParams.() -> Unit
open class ConfigContainer(
var globalState: Boolean? = null
val hasGlobalState: Boolean = false
) {
var parentContainerKey: PropertyKey<*>? = null
val properties = mutableMapOf<PropertyKey<*>, PropertyValue<*>>()
var globalState: Boolean? = null
private inline fun <T> registerProperty(
key: String,

View File

@ -13,6 +13,8 @@ class Global : ConfigContainer() {
val disableGooglePlayDialogs = boolean("disable_google_play_dialogs")
val forceMediaSourceQuality = boolean("force_media_source_quality")
val betterNotifications = multiple("better_notifications", "snap", "chat", "reply_button", "download_button")
val notificationBlacklist = multiple("notification_blacklist", *NotificationType.getIncomingValues().map { it.key }.toTypedArray())
val notificationBlacklist = multiple("notification_blacklist", *NotificationType.getIncomingValues().map { it.key }.toTypedArray()) {
customOptionTranslationPath = "features.options.notifications"
}
val disableSnapSplitting = boolean("disable_snap_splitting") { addNotices(FeatureNotice.MAY_BREAK_INTERNAL_BEHAVIOR) }
}

View File

@ -16,7 +16,9 @@ class MessagingTweaks : ConfigContainer() {
"EXTERNAL_MEDIA",
"STICKER"
)
val preventMessageSending = multiple("prevent_message_sending", *NotificationType.getOutgoingValues().map { it.key }.toTypedArray())
val preventMessageSending = multiple("prevent_message_sending", *NotificationType.getOutgoingValues().map { it.key }.toTypedArray()) {
customOptionTranslationPath = "features.options.notifications"
}
val messageLogger = boolean("message_logger") { addNotices(FeatureNotice.MAY_CAUSE_CRASHES) }
val galleryMediaSendOverride = boolean("gallery_media_send_override")
val messagePreviewLength = integer("message_preview_length", defaultValue = 20)

View File

@ -9,6 +9,7 @@ class RootConfig : ConfigContainer() {
val global = container("global", Global()) { icon = "MiscellaneousServices" }
val rules = container("rules", Rules()) { icon = "Rule" }
val camera = container("camera", Camera()) { icon = "Camera"}
val streaksReminder = container("streaks_reminder", StreaksReminderConfig()) { icon = "Alarm" }
val experimental = container("experimental", Experimental()) { icon = "Science" }
val spoof = container("spoof", Spoof()) { icon = "Fingerprint" }
}

View File

@ -3,13 +3,13 @@ package me.rhunk.snapenhance.core.config.impl
import me.rhunk.snapenhance.core.config.ConfigContainer
class Spoof : ConfigContainer() {
inner class Location : ConfigContainer(globalState = false) {
inner class Location : ConfigContainer(hasGlobalState = true) {
val latitude = float("location_latitude")
val longitude = float("location_longitude")
}
val location = container("location", Location())
inner class Device : ConfigContainer(globalState = false) {
inner class Device : ConfigContainer(hasGlobalState = true) {
val fingerprint = string("device_fingerprint")
val androidId = string("device_android_id")
}

View File

@ -0,0 +1,7 @@
package me.rhunk.snapenhance.core.config.impl
import me.rhunk.snapenhance.core.config.ConfigContainer
class StreaksReminderConfig : ConfigContainer(hasGlobalState = true) {
val interval = integer("interval", 2)
}

View File

@ -1,6 +1,7 @@
package me.rhunk.snapenhance.core.messaging
import me.rhunk.snapenhance.util.SerializableDataObject
import kotlin.time.Duration.Companion.hours
enum class RuleState(
@ -45,8 +46,16 @@ data class FriendStreaks(
val notify: Boolean,
val expirationTimestamp: Long,
val length: Int
) : SerializableDataObject()
) : SerializableDataObject() {
companion object {
//TODO: config
val EXPIRE_THRESHOLD = 12.hours
}
fun hoursLeft() = (expirationTimestamp - System.currentTimeMillis()) / 1000 / 60 / 60
fun isAboutToExpire() = expirationTimestamp - System.currentTimeMillis() < EXPIRE_THRESHOLD.inWholeMilliseconds
}
data class MessagingGroupInfo(
val conversationId: String,

View File

@ -61,11 +61,7 @@ class MediaDownloader : MessagingRuleFeature("MediaDownloader", MessagingRuleTyp
): DownloadManagerClient {
val generatedHash = mediaIdentifier.hashCode().toString(16).replaceFirst("-", "")
val iconUrl = friendInfo?.takeIf {
it.bitmojiAvatarId != null && it.bitmojiSelfieId != null
}?.let {
BitmojiSelfie.getBitmojiSelfie(it.bitmojiSelfieId!!, it.bitmojiAvatarId!!, BitmojiSelfie.BitmojiSelfieType.THREE_D)
}
val iconUrl = BitmojiSelfie.getBitmojiSelfie(friendInfo?.bitmojiSelfieId, friendInfo?.bitmojiAvatarId, BitmojiSelfie.BitmojiSelfieType.THREE_D)
val downloadLogging by context.config.downloader.logging
if (downloadLogging.contains("started")) {

View File

@ -50,7 +50,7 @@ object ViewAppearanceHelper {
}
}
val snapchatFontResId = resources.getIdentifier("avenir_next_medium", "font", "com.snapchat.android")
val snapchatFontResId = resources.getIdentifier("avenir_next_medium", "font", Constants.SNAPCHAT_PACKAGE_NAME)
val scalingFactor = resources.displayMetrics.densityDpi.toDouble() / 400
with(component) {

View File

@ -53,7 +53,7 @@ class FriendFeedInfoMenu : AbstractMenu() {
profile.bitmojiSelfieId.toString(),
profile.bitmojiAvatarId.toString(),
BitmojiSelfie.BitmojiSelfieType.THREE_D
)
)!!
)
}
} catch (e: Throwable) {

View File

@ -6,7 +6,10 @@ object BitmojiSelfie {
THREE_D
}
fun getBitmojiSelfie(selfieId: String, avatarId: String, type: BitmojiSelfieType): String {
fun getBitmojiSelfie(selfieId: String?, avatarId: String?, type: BitmojiSelfieType): String? {
if (selfieId.isNullOrEmpty() || avatarId.isNullOrEmpty()) {
return null
}
return when (type) {
BitmojiSelfieType.STANDARD -> "https://sdk.bitmoji.com/render/panel/$selfieId-$avatarId-v1.webp?transparent=1"
BitmojiSelfieType.THREE_D -> "https://images.bitmoji.com/3d/render/$selfieId-$avatarId-v1.webp?trim=circle"