feat: bootstrap override

- home tab
- persistent app appearance
This commit is contained in:
rhunk
2023-09-09 10:22:52 +02:00
parent 01476ad820
commit 249569468c
6 changed files with 68 additions and 75 deletions

View File

@ -213,6 +213,20 @@
"name": "AMOLED Dark Mode",
"description": "Enables AMOLED dark mode\nMake sure Snapchats Dark mode is enabled"
},
"bootstrap_override": {
"name": "Bootstrap Override",
"description": "Overrides user interface bootstrap settings",
"properties": {
"app_appearance": {
"name": "App Appearance",
"description": "Sets a persistent App Appearance"
},
"home_tab": {
"name": "Home Tab",
"description": "Overrides the startup tab when opening Snapchat"
}
}
},
"map_friend_nametags": {
"name": "Enhanced Friend Map Nametags",
"description": "Improves the Nametags of friends on the Snapmap"
@ -507,6 +521,10 @@
}
},
"options": {
"app_appearance": {
"always_light": "Always Light",
"always_dark": "Always Dark"
},
"better_notifications": {
"chat": "Show chat messages",
"snap": "Show media",
@ -585,14 +603,12 @@
"hide_following": "Hide following section",
"hide_for_you": "Hide For You section"
},
"startup_tab": {
"OFF": "Off",
"ngs_map_icon_container": "Map",
"ngs_chat_icon_container": "Chat",
"ngs_camera_icon_container": "Camera",
"ngs_community_icon_container": "Community / Stories",
"ngs_spotlight_icon_container": "Spotlight",
"ngs_search_icon_container": "Search"
"home_tab": {
"map": "Map",
"chat": "Chat",
"camera": "Camera",
"discover": "Discover",
"spotlight": "Spotlight"
},
"add_friend_source_spoof": {
"added_by_username": "By Username",

View File

@ -3,9 +3,14 @@ package me.rhunk.snapenhance.core.config.impl
import me.rhunk.snapenhance.core.config.ConfigContainer
import me.rhunk.snapenhance.core.config.FeatureNotice
import me.rhunk.snapenhance.core.messaging.MessagingRuleType
import me.rhunk.snapenhance.features.impl.ui.ClientBootstrapOverride
class UserInterfaceTweaks : ConfigContainer() {
val enableAppAppearance = boolean("enable_app_appearance")
inner class BootstrapOverride : ConfigContainer() {
val appAppearance = unique("app_appearance", "always_light", "always_dark")
val homeTab = unique("home_tab", *ClientBootstrapOverride.tabs) { addNotices(FeatureNotice.UNSTABLE) }
}
val friendFeedMenuButtons = multiple(
"friend_feed_menu_buttons","conversation_info", *MessagingRuleType.values().toList().filter { it.listMode }.map { it.key }.toTypedArray()
).apply {
@ -13,6 +18,7 @@ class UserInterfaceTweaks : ConfigContainer() {
}
val friendFeedMenuPosition = integer("friend_feed_menu_position", defaultValue = 1)
val amoledDarkMode = boolean("amoled_dark_mode") { addNotices(FeatureNotice.UNSTABLE) }
val bootstrapOverride = container("bootstrap_override", BootstrapOverride())
val mapFriendNameTags = boolean("map_friend_nametags")
val streakExpirationInfo = boolean("streak_expiration_info")
val hideStorySections = multiple("hide_story_sections",
@ -26,13 +32,5 @@ class UserInterfaceTweaks : ConfigContainer() {
)
val ddBitmojiSelfie = boolean("2d_bitmoji_selfie")
val disableSpotlight = boolean("disable_spotlight")
val startupTab = unique("startup_tab",
"ngs_map_icon_container",
"ngs_chat_icon_container",
"ngs_camera_icon_container",
"ngs_community_icon_container",
"ngs_spotlight_icon_container",
"ngs_search_icon_container"
) { addNotices(FeatureNotice.INTERNAL_BEHAVIOR) }
val storyViewerOverride = unique("story_viewer_override", "DISCOVER_PLAYBACK_SEEKBAR", "VERTICAL_STORY_VIEWER") { addNotices(FeatureNotice.UNSTABLE) }
val storyViewerOverride = unique("story_viewer_override", "DISCOVER_PLAYBACK_SEEKBAR", "VERTICAL_STORY_VIEWER")
}

View File

@ -26,7 +26,6 @@ class ConfigurationOverride : Feature("Configuration Override", loadParams = Fea
overrideProperty("DF_VOPERA_FOR_STORIES", { state == "VERTICAL_STORY_VIEWER" }, true)
}
overrideProperty("SIG_APP_APPEARANCE_SETTING", { context.config.userInterface.enableAppAppearance.get() }, true)
overrideProperty("SPOTLIGHT_5TH_TAB_ENABLED", { context.config.userInterface.disableSpotlight.get() }, false)
overrideProperty("BYPASS_AD_FEATURE_GATE", { context.config.global.blockAds.get() }, true)

View File

@ -0,0 +1,34 @@
package me.rhunk.snapenhance.features.impl.ui
import me.rhunk.snapenhance.features.Feature
import me.rhunk.snapenhance.features.FeatureLoadParams
import java.io.File
class ClientBootstrapOverride : Feature("ClientBootstrapOverride", loadParams = FeatureLoadParams.ACTIVITY_CREATE_SYNC) {
companion object {
val tabs = arrayOf("map", "chat", "camera", "discover", "spotlight")
}
private val clientBootstrapFolder by lazy { File(context.androidContext.filesDir, "client-bootstrap") }
private val appearanceStartupConfigFile by lazy { File(clientBootstrapFolder, "appearancestartupconfig") }
private val plusFile by lazy { File(clientBootstrapFolder, "plus") }
override fun onActivityCreate() {
val bootstrapOverrideConfig = context.config.userInterface.bootstrapOverride
bootstrapOverrideConfig.appAppearance.getNullable()?.also { appearance ->
val state = when (appearance) {
"always_light" -> 0
"always_dark" -> 1
else -> return@also
}.toByte()
appearanceStartupConfigFile.writeBytes(byteArrayOf(0, 0, 0, state))
}
bootstrapOverrideConfig.homeTab.getNullable()?.also { currentTab ->
plusFile.writeBytes(byteArrayOf(8, (tabs.indexOf(currentTab) + 1).toByte()))
}
}
}

View File

@ -1,54 +0,0 @@
package me.rhunk.snapenhance.features.impl.ui
import android.annotation.SuppressLint
import android.os.Handler
import android.view.View
import android.widget.LinearLayout
import me.rhunk.snapenhance.Constants
import me.rhunk.snapenhance.core.eventbus.events.impl.AddViewEvent
import me.rhunk.snapenhance.features.Feature
import me.rhunk.snapenhance.features.FeatureLoadParams
import me.rhunk.snapenhance.hook.HookStage
import me.rhunk.snapenhance.hook.hook
@SuppressLint("DiscouragedApi")
class StartupPageOverride : Feature("StartupPageOverride", loadParams = FeatureLoadParams.ACTIVITY_CREATE_SYNC) {
private var ngsIcon: View? = null
/*
navbar icons:
ngs_map_icon_container
ngs_chat_icon_container
ngs_camera_icon_container
ngs_community_icon_container
ngs_spotlight_icon_container
ngs_search_icon_container
*/
private fun clickNgsIcon() {
Handler(context.androidContext.mainLooper).postDelayed({
ngsIcon?.callOnClick()
}, 300)
}
override fun onActivityCreate() {
val ngsIconName = context.config.userInterface.startupTab.getNullable() ?: return
context.androidContext.classLoader.loadClass("com.snap.mushroom.MainActivity").apply {
hook("onResume", HookStage.AFTER) { clickNgsIcon() }
}
val ngsIconId = context.androidContext.resources.getIdentifier(ngsIconName, "id", Constants.SNAPCHAT_PACKAGE_NAME)
lateinit var unhook: () -> Unit
context.event.subscribe(AddViewEvent::class) { event ->
if (event.parent !is LinearLayout) return@subscribe
with(event.view) {
if (id == ngsIconId) {
ngsIcon = this
unhook()
}
}
}.also { unhook = it }
}
}

View File

@ -35,7 +35,7 @@ import me.rhunk.snapenhance.features.impl.tweaks.SendOverride
import me.rhunk.snapenhance.features.impl.tweaks.SnapchatPlus
import me.rhunk.snapenhance.features.impl.tweaks.UnlimitedSnapViewTime
import me.rhunk.snapenhance.features.impl.ui.PinConversations
import me.rhunk.snapenhance.features.impl.ui.StartupPageOverride
import me.rhunk.snapenhance.features.impl.ui.ClientBootstrapOverride
import me.rhunk.snapenhance.features.impl.ui.UITweaks
import me.rhunk.snapenhance.manager.Manager
import me.rhunk.snapenhance.ui.menu.impl.MenuViewInjector
@ -90,7 +90,7 @@ class FeatureManager(private val context: ModContext) : Manager {
register(PinConversations::class)
register(UnlimitedMultiSnap::class)
register(DeviceSpooferHook::class)
register(StartupPageOverride::class)
register(ClientBootstrapOverride::class)
register(GooglePlayServicesDialogs::class)
register(NoFriendScoreDelay::class)
register(ProfilePictureDownloader::class)