feat(core): colors (#892)
Co-authored-by: Theonethom <141059521+Theonethom@users.noreply.github.com> Co-authored-by: auth <64337177+authorisation@users.noreply.github.com>
This commit is contained in:
@@ -249,6 +249,7 @@ Thanks to everyone involved including the [third-party libraries](https://github
|
|||||||
- [TheVisual](https://github.com/TheVisual)
|
- [TheVisual](https://github.com/TheVisual)
|
||||||
- [CanerKaraca23](https://github.com/CanerKaraca23)
|
- [CanerKaraca23](https://github.com/CanerKaraca23)
|
||||||
- [bocajthomas](https://github.com/bocajthomas)
|
- [bocajthomas](https://github.com/bocajthomas)
|
||||||
|
|
||||||
## Donate
|
## Donate
|
||||||
- LTC: LbBnT9GxgnFhwy891EdDKqGmpn7XtduBdE
|
- LTC: LbBnT9GxgnFhwy891EdDKqGmpn7XtduBdE
|
||||||
- BCH: qpu57a05kqljjadvpgjc6t894apprvth9slvlj4vpj
|
- BCH: qpu57a05kqljjadvpgjc6t894apprvth9slvlj4vpj
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package me.rhunk.snapenhance.ui.util
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.compose.foundation.ScrollState
|
import androidx.compose.foundation.ScrollState
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
@@ -175,6 +176,7 @@ class AlertDialogs(
|
|||||||
@Composable
|
@Composable
|
||||||
fun KeyboardInputDialog(property: PropertyPair<*>, dismiss: () -> Unit = {}) {
|
fun KeyboardInputDialog(property: PropertyPair<*>, dismiss: () -> Unit = {}) {
|
||||||
val focusRequester = remember { FocusRequester() }
|
val focusRequester = remember { FocusRequester() }
|
||||||
|
val context = LocalContext.current
|
||||||
|
|
||||||
DefaultDialogCard {
|
DefaultDialogCard {
|
||||||
var fieldValue by remember {
|
var fieldValue by remember {
|
||||||
@@ -215,7 +217,7 @@ class AlertDialogs(
|
|||||||
}
|
}
|
||||||
Button(onClick = {
|
Button(onClick = {
|
||||||
if (fieldValue.text.isNotEmpty() && property.key.params.inputCheck?.invoke(fieldValue.text) == false) {
|
if (fieldValue.text.isNotEmpty() && property.key.params.inputCheck?.invoke(fieldValue.text) == false) {
|
||||||
dismiss()
|
Toast.makeText(context, "Invalid input! Make sure you entered a valid value.", Toast.LENGTH_SHORT).show() //TODO: i18n
|
||||||
return@Button
|
return@Button
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -358,9 +358,35 @@
|
|||||||
"name": "Enable App Appearance Settings",
|
"name": "Enable App Appearance Settings",
|
||||||
"description": "Enables the hidden App Appearance Setting\nMay not be required on newer Snapchat versions"
|
"description": "Enables the hidden App Appearance Setting\nMay not be required on newer Snapchat versions"
|
||||||
},
|
},
|
||||||
"amoled_dark_mode": {
|
"customize_ui": {
|
||||||
"name": "AMOLED Dark Mode",
|
"name": "Colors",
|
||||||
"description": "Enables AMOLED dark mode\nMake sure Snapchats Dark mode is enabled"
|
"description": "Customize Snapchats Colors",
|
||||||
|
"properties": {
|
||||||
|
"text_colour": {
|
||||||
|
"name": "Text Color",
|
||||||
|
"description": "Changes Snapchats text color\nInput hex color code"
|
||||||
|
},
|
||||||
|
"chat_colour": {
|
||||||
|
"name": "Sent & Received Color",
|
||||||
|
"description": "Changes Snapchats Sent and Received text color on the friend feed\nInput a hex color code"
|
||||||
|
},
|
||||||
|
"background_colour": {
|
||||||
|
"name": "Background Color",
|
||||||
|
"description": "Changes Snapchats background color\nInput a hex color code"
|
||||||
|
},
|
||||||
|
"background_colour_surface": {
|
||||||
|
"name": "Background Surface Color",
|
||||||
|
"description": "Changes Snapchats background surface color\nInput a hex color code"
|
||||||
|
},
|
||||||
|
"action_menu_background_colour": {
|
||||||
|
"name": "Action Menu Background Color",
|
||||||
|
"description": "Changes Snapchats chat action menu background color\nInput a hex color code"
|
||||||
|
},
|
||||||
|
"action_menu_round_background_colour": {
|
||||||
|
"name": "Action Menu Round Background Color",
|
||||||
|
"description": "Changes Snapchats chat action menu round background color\nInput a hex color code"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"friend_feed_message_preview": {
|
"friend_feed_message_preview": {
|
||||||
"name": "Friend Feed Message Preview",
|
"name": "Friend Feed Message Preview",
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package me.rhunk.snapenhance.common.config.impl
|
package me.rhunk.snapenhance.common.config.impl
|
||||||
|
|
||||||
|
import android.graphics.Color
|
||||||
import me.rhunk.snapenhance.common.config.ConfigContainer
|
import me.rhunk.snapenhance.common.config.ConfigContainer
|
||||||
import me.rhunk.snapenhance.common.config.FeatureNotice
|
import me.rhunk.snapenhance.common.config.FeatureNotice
|
||||||
import me.rhunk.snapenhance.common.data.MessagingRuleType
|
import me.rhunk.snapenhance.common.data.MessagingRuleType
|
||||||
@@ -18,12 +19,24 @@ class UserInterfaceTweaks : ConfigContainer() {
|
|||||||
val amount = integer("amount", defaultValue = 1)
|
val amount = integer("amount", defaultValue = 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inner class CustomizeUIConfig : ConfigContainer(hasGlobalState = true) {
|
||||||
|
private val checkInputColor = { value: String ->
|
||||||
|
value.isEmpty() || runCatching { Color.parseColor(value) }.isSuccess
|
||||||
|
}
|
||||||
|
val textColour = string("text_colour") { inputCheck = checkInputColor }
|
||||||
|
val backgroundColour = string("background_colour") { inputCheck = checkInputColor }
|
||||||
|
val backgroundColourSurface = string("background_colour_surface") { inputCheck = checkInputColor }
|
||||||
|
val actionMenuBackgroundColour = string("action_menu_background_colour") { inputCheck = checkInputColor }
|
||||||
|
val actionMenuRoundBackgroundColour = string("action_menu_round_background_colour") { inputCheck = checkInputColor }
|
||||||
|
val chatColour = string("chat_colour") { inputCheck = checkInputColor }
|
||||||
|
}
|
||||||
|
|
||||||
val friendFeedMenuButtons = multiple(
|
val friendFeedMenuButtons = multiple(
|
||||||
"friend_feed_menu_buttons","conversation_info", "mark_snaps_as_seen", "mark_stories_as_seen_locally", *MessagingRuleType.entries.filter { it.showInFriendMenu }.map { it.key }.toTypedArray()
|
"friend_feed_menu_buttons","conversation_info", "mark_snaps_as_seen", "mark_stories_as_seen_locally", *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 amoledDarkMode = boolean("amoled_dark_mode") { addNotices(FeatureNotice.UNSTABLE); requireRestart() }
|
val customizeUi = container("customize_ui", CustomizeUIConfig()) { addNotices(FeatureNotice.UNSTABLE); requireRestart() }
|
||||||
val friendFeedMessagePreview = container("friend_feed_message_preview", FriendFeedMessagePreview()) { requireRestart() }
|
val friendFeedMessagePreview = container("friend_feed_message_preview", FriendFeedMessagePreview()) { requireRestart() }
|
||||||
val snapPreview = boolean("snap_preview") { addNotices(FeatureNotice.UNSTABLE); requireRestart() }
|
val snapPreview = boolean("snap_preview") { addNotices(FeatureNotice.UNSTABLE); requireRestart() }
|
||||||
val bootstrapOverride = container("bootstrap_override", BootstrapOverride()) { requireRestart() }
|
val bootstrapOverride = container("bootstrap_override", BootstrapOverride()) { requireRestart() }
|
||||||
|
|||||||
@@ -84,7 +84,6 @@ class FeatureManager(
|
|||||||
AppLock(),
|
AppLock(),
|
||||||
CameraTweaks(),
|
CameraTweaks(),
|
||||||
InfiniteStoryBoost(),
|
InfiniteStoryBoost(),
|
||||||
AmoledDarkMode(),
|
|
||||||
PinConversations(),
|
PinConversations(),
|
||||||
DeviceSpooferHook(),
|
DeviceSpooferHook(),
|
||||||
ClientBootstrapOverride(),
|
ClientBootstrapOverride(),
|
||||||
@@ -120,6 +119,7 @@ class FeatureManager(
|
|||||||
AccountSwitcher(),
|
AccountSwitcher(),
|
||||||
RemoveGroupsLockedStatus(),
|
RemoveGroupsLockedStatus(),
|
||||||
BypassMessageActionRestrictions(),
|
BypassMessageActionRestrictions(),
|
||||||
|
CustomizeUI(),
|
||||||
BetterLocation(),
|
BetterLocation(),
|
||||||
MediaFilePicker(),
|
MediaFilePicker(),
|
||||||
HideActiveMusic(),
|
HideActiveMusic(),
|
||||||
@@ -128,7 +128,6 @@ class FeatureManager(
|
|||||||
ComposerHooks(),
|
ComposerHooks(),
|
||||||
DisableCustomTabs(),
|
DisableCustomTabs(),
|
||||||
)
|
)
|
||||||
|
|
||||||
initializeFeatures()
|
initializeFeatures()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,4 +189,4 @@ class FeatureManager(
|
|||||||
context.log.verbose("feature manager onActivityCreate took $it ms")
|
context.log.verbose("feature manager onActivityCreate took $it ms")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,50 +0,0 @@
|
|||||||
package me.rhunk.snapenhance.core.features.impl.experiments
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.content.res.TypedArray
|
|
||||||
import android.graphics.drawable.ColorDrawable
|
|
||||||
import me.rhunk.snapenhance.core.features.Feature
|
|
||||||
import me.rhunk.snapenhance.core.features.FeatureLoadParams
|
|
||||||
import me.rhunk.snapenhance.core.util.hook.HookStage
|
|
||||||
import me.rhunk.snapenhance.core.util.hook.Hooker
|
|
||||||
import me.rhunk.snapenhance.core.util.hook.hook
|
|
||||||
import me.rhunk.snapenhance.core.util.ktx.getIdentifier
|
|
||||||
|
|
||||||
class AmoledDarkMode : Feature("Amoled Dark Mode", loadParams = FeatureLoadParams.ACTIVITY_CREATE_SYNC) {
|
|
||||||
@SuppressLint("DiscouragedApi")
|
|
||||||
override fun onActivityCreate() {
|
|
||||||
if (!context.config.userInterface.amoledDarkMode.get()) return
|
|
||||||
val attributeCache = mutableMapOf<String, Int>()
|
|
||||||
|
|
||||||
fun getAttribute(name: String): Int {
|
|
||||||
if (attributeCache.containsKey(name)) return attributeCache[name]!!
|
|
||||||
return context.resources.getIdentifier(name, "attr").also { attributeCache[name] = it }
|
|
||||||
}
|
|
||||||
|
|
||||||
context.androidContext.theme.javaClass.getMethod("obtainStyledAttributes", IntArray::class.java).hook(
|
|
||||||
HookStage.AFTER) { param ->
|
|
||||||
val array = param.arg<IntArray>(0)
|
|
||||||
val result = param.getResult() as TypedArray
|
|
||||||
|
|
||||||
fun ephemeralHook(methodName: String, content: Any) {
|
|
||||||
Hooker.ephemeralHookObjectMethod(result::class.java, result, methodName, HookStage.BEFORE) {
|
|
||||||
it.setResult(content)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
when (array[0]) {
|
|
||||||
getAttribute("sigColorTextPrimary") -> {
|
|
||||||
ephemeralHook("getColor", 0xFFFFFFFF.toInt())
|
|
||||||
}
|
|
||||||
getAttribute("sigColorBackgroundMain"),
|
|
||||||
getAttribute("sigColorBackgroundSurface") -> {
|
|
||||||
ephemeralHook("getColor", 0xFF000000.toInt())
|
|
||||||
}
|
|
||||||
getAttribute("actionSheetBackgroundDrawable"),
|
|
||||||
getAttribute("actionSheetRoundedBackgroundDrawable") -> {
|
|
||||||
ephemeralHook("getDrawable", ColorDrawable(0xFF000000.toInt()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
package me.rhunk.snapenhance.core.features.impl.ui
|
||||||
|
|
||||||
|
import android.content.res.TypedArray
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.graphics.drawable.ColorDrawable
|
||||||
|
import me.rhunk.snapenhance.core.features.Feature
|
||||||
|
import me.rhunk.snapenhance.core.features.FeatureLoadParams
|
||||||
|
import me.rhunk.snapenhance.core.util.hook.HookStage
|
||||||
|
import me.rhunk.snapenhance.core.util.hook.Hooker
|
||||||
|
import me.rhunk.snapenhance.core.util.hook.hook
|
||||||
|
import me.rhunk.snapenhance.core.util.ktx.getIdentifier
|
||||||
|
|
||||||
|
class CustomizeUI: Feature("Customize UI", loadParams = FeatureLoadParams.ACTIVITY_CREATE_SYNC) {
|
||||||
|
private fun parseColor(color: String): Int? {
|
||||||
|
return color.takeIf { it.isNotEmpty() }?.let {
|
||||||
|
runCatching { Color.parseColor(color) }.getOrNull()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityCreate() {
|
||||||
|
val isAmoledMode = context.config.userInterface.amoledDarkMode.get()
|
||||||
|
val isCustomizeUI = context.config.userInterface.customizeUi.globalState == true
|
||||||
|
|
||||||
|
if (!isAmoledMode && !isCustomizeUI) return
|
||||||
|
|
||||||
|
//TODO: color picker
|
||||||
|
val customizeUIConfig = context.config.userInterface.customizeUi
|
||||||
|
val effectiveTextColour by lazy { parseColor(customizeUIConfig.textColour.get()) }
|
||||||
|
val effectiveBackgroundColour by lazy { parseColor(customizeUIConfig.backgroundColour.get()) }
|
||||||
|
val effectiveBackgroundColourSurface by lazy { parseColor(customizeUIConfig.backgroundColourSurface.get()) }
|
||||||
|
val effectiveActionMenuBackgroundColour by lazy { parseColor(customizeUIConfig.actionMenuBackgroundColour.get()) }
|
||||||
|
val effectiveActionMenuRoundBackgroundColour by lazy { parseColor(customizeUIConfig.actionMenuRoundBackgroundColour.get()) }
|
||||||
|
val effectiveChatColour by lazy { parseColor(customizeUIConfig.chatColour.get()) }
|
||||||
|
|
||||||
|
val attributeCache = mutableMapOf<String, Int>()
|
||||||
|
|
||||||
|
fun getAttribute(name: String): Int {
|
||||||
|
if (attributeCache.containsKey(name)) return attributeCache[name]!!
|
||||||
|
return context.resources.getIdentifier(name, "attr").also { attributeCache[name] = it }
|
||||||
|
}
|
||||||
|
|
||||||
|
context.androidContext.theme.javaClass.getMethod("obtainStyledAttributes", IntArray::class.java).hook(
|
||||||
|
HookStage.AFTER) { param ->
|
||||||
|
val array = param.arg<IntArray>(0)
|
||||||
|
val result = param.getResult() as TypedArray
|
||||||
|
|
||||||
|
fun ephemeralHook(methodName: String, content: Any) {
|
||||||
|
Hooker.ephemeralHookObjectMethod(result::class.java, result, methodName, HookStage.BEFORE) {
|
||||||
|
it.setResult(content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isAmoledMode) {
|
||||||
|
when (array[0]) {
|
||||||
|
getAttribute("sigColorTextPrimary") -> {
|
||||||
|
ephemeralHook("getColor", 0xFFFFFFFF.toInt())
|
||||||
|
}
|
||||||
|
getAttribute("sigColorBackgroundMain"),
|
||||||
|
getAttribute("sigColorBackgroundSurface") -> {
|
||||||
|
ephemeralHook("getColor", 0xFF000000.toInt())
|
||||||
|
}
|
||||||
|
getAttribute("actionSheetBackgroundDrawable"),
|
||||||
|
getAttribute("actionSheetRoundedBackgroundDrawable") -> {
|
||||||
|
ephemeralHook("getDrawable", ColorDrawable(0xFF000000.toInt()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isCustomizeUI) {
|
||||||
|
when (array[0]) {
|
||||||
|
getAttribute("sigColorTextPrimary") -> {
|
||||||
|
ephemeralHook("getColor", effectiveTextColour ?: return@hook)
|
||||||
|
}
|
||||||
|
|
||||||
|
getAttribute("sigColorBackgroundMain") -> {
|
||||||
|
ephemeralHook("getColor", effectiveBackgroundColour ?: return@hook)
|
||||||
|
}
|
||||||
|
|
||||||
|
getAttribute("sigColorBackgroundSurface") -> {
|
||||||
|
ephemeralHook("getColor", effectiveBackgroundColourSurface ?: return@hook)
|
||||||
|
}
|
||||||
|
|
||||||
|
getAttribute("actionSheetBackgroundDrawable") -> {
|
||||||
|
ephemeralHook("getDrawable", ColorDrawable(effectiveActionMenuBackgroundColour ?: return@hook))
|
||||||
|
}
|
||||||
|
|
||||||
|
getAttribute("actionSheetRoundedBackgroundDrawable") -> {
|
||||||
|
ephemeralHook("getDrawable", ColorDrawable(effectiveActionMenuRoundBackgroundColour ?: return@hook))
|
||||||
|
}
|
||||||
|
getAttribute("sigColorChatActivity") -> {
|
||||||
|
ephemeralHook("getColor", effectiveChatColour ?: return@hook)
|
||||||
|
}
|
||||||
|
getAttribute("sigColorChatChat") -> {
|
||||||
|
ephemeralHook("getColor", effectiveChatColour ?: return@hook)
|
||||||
|
}
|
||||||
|
getAttribute("sigColorChatPendingSending") -> {
|
||||||
|
ephemeralHook("getColor", effectiveChatColour ?: return@hook)
|
||||||
|
}
|
||||||
|
getAttribute("sigColorChatSnapWithSound") -> {
|
||||||
|
ephemeralHook("getColor", effectiveChatColour ?: return@hook)
|
||||||
|
}
|
||||||
|
getAttribute("sigColorChatSnapWithoutSound") -> {
|
||||||
|
ephemeralHook("getColor", effectiveChatColour ?: return@hook)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user