feat: config & notification filter
This commit is contained in:
@@ -18,7 +18,8 @@
|
||||
"save_folder": "Save Folder",
|
||||
"prevent_read_receipts": "Prevent Read Receipts",
|
||||
"hide_bitmoji_presence": "Hide Bitmoji Presence",
|
||||
"show_message_content": "Show Message Content",
|
||||
"show_message_content_in_notifications": "Show Message Content In Notifications",
|
||||
"notification_filter": "Notification Filter",
|
||||
"message_logger": "Message Logger",
|
||||
"unlimited_snap_view_time": "Unlimited Snap View Time",
|
||||
"auto_download_snaps": "Auto Download Snaps",
|
||||
@@ -49,7 +50,16 @@
|
||||
"new_map_ui": "New Map UI",
|
||||
"use_download_manager": "Use Android Download Manager"
|
||||
},
|
||||
|
||||
|
||||
"option": {
|
||||
"property": {
|
||||
"notification_filter": {
|
||||
"chat": "Chat",
|
||||
"snap": "Snap",
|
||||
"typing": "Typing"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"friend_menu_option": {
|
||||
"preview": "Preview",
|
||||
|
||||
@@ -1,58 +1,58 @@
|
||||
package me.rhunk.snapenhance.config
|
||||
|
||||
open class ConfigAccessor(
|
||||
private val configMap: MutableMap<ConfigProperty, Any?>
|
||||
private val configMap: MutableMap<ConfigProperty, ConfigValue<*>> = mutableMapOf()
|
||||
) {
|
||||
fun bool(key: ConfigProperty): Boolean {
|
||||
return get(key) as Boolean
|
||||
return get(key).value() as Boolean
|
||||
}
|
||||
|
||||
fun int(key: ConfigProperty): Int {
|
||||
return get(key) as Int
|
||||
return get(key).value() as Int
|
||||
}
|
||||
|
||||
fun string(key: ConfigProperty): String {
|
||||
return get(key) as String
|
||||
return get(key).value() as String
|
||||
}
|
||||
|
||||
fun double(key: ConfigProperty): Double {
|
||||
return get(key) as Double
|
||||
return get(key).value() as Double
|
||||
}
|
||||
|
||||
fun float(key: ConfigProperty): Float {
|
||||
return get(key) as Float
|
||||
return get(key).value() as Float
|
||||
}
|
||||
|
||||
fun long(key: ConfigProperty): Long {
|
||||
return get(key) as Long
|
||||
return get(key).value() as Long
|
||||
}
|
||||
|
||||
fun short(key: ConfigProperty): Short {
|
||||
return get(key) as Short
|
||||
return get(key).value() as Short
|
||||
}
|
||||
|
||||
fun byte(key: ConfigProperty): Byte {
|
||||
return get(key) as Byte
|
||||
return get(key).value() as Byte
|
||||
}
|
||||
|
||||
fun char(key: ConfigProperty): Char {
|
||||
return get(key) as Char
|
||||
return get(key).value() as Char
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T> list(key: ConfigProperty): List<T> {
|
||||
return get(key) as List<T>
|
||||
fun options(key: ConfigProperty): Map<String, Boolean> {
|
||||
return get(key).value() as Map<String, Boolean>
|
||||
}
|
||||
|
||||
fun get(key: ConfigProperty): Any? {
|
||||
return configMap[key]
|
||||
fun get(key: ConfigProperty): ConfigValue<*> {
|
||||
return configMap[key]!!
|
||||
}
|
||||
|
||||
fun set(key: ConfigProperty, value: Any?) {
|
||||
fun set(key: ConfigProperty, value: ConfigValue<*>) {
|
||||
configMap[key] = value
|
||||
}
|
||||
|
||||
fun entries(): Set<Map.Entry<ConfigProperty, Any?>> {
|
||||
fun entries(): Set<Map.Entry<ConfigProperty, ConfigValue<*>>> {
|
||||
return configMap.entries
|
||||
}
|
||||
}
|
||||
@@ -1,174 +1,192 @@
|
||||
package me.rhunk.snapenhance.config
|
||||
|
||||
import android.os.Environment
|
||||
import me.rhunk.snapenhance.config.impl.ConfigIntegerValue
|
||||
import me.rhunk.snapenhance.config.impl.ConfigStateListValue
|
||||
import me.rhunk.snapenhance.config.impl.ConfigStateValue
|
||||
import me.rhunk.snapenhance.config.impl.ConfigStringValue
|
||||
import java.io.File
|
||||
|
||||
enum class ConfigProperty(
|
||||
val nameKey: String,
|
||||
val descriptionKey: String,
|
||||
val category: ConfigCategory,
|
||||
val defaultValue: Any
|
||||
val valueContainer: ConfigValue<*>
|
||||
) {
|
||||
SAVE_FOLDER(
|
||||
"property.save_folder", "description.save_folder", ConfigCategory.GENERAL,
|
||||
File(
|
||||
ConfigStringValue(File(
|
||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).absolutePath + "/Snapchat",
|
||||
"SnapEnhance"
|
||||
).absolutePath
|
||||
).absolutePath)
|
||||
),
|
||||
|
||||
PREVENT_READ_RECEIPTS(
|
||||
"property.prevent_read_receipts",
|
||||
"description.prevent_read_receipts",
|
||||
ConfigCategory.SPY,
|
||||
false
|
||||
ConfigStateValue(false)
|
||||
),
|
||||
HIDE_BITMOJI_PRESENCE(
|
||||
"property.hide_bitmoji_presence",
|
||||
"description.hide_bitmoji_presence",
|
||||
ConfigCategory.SPY,
|
||||
false
|
||||
ConfigStateValue(false)
|
||||
),
|
||||
SHOW_MESSAGE_CONTENT(
|
||||
"property.show_message_content",
|
||||
"description.show_message_content",
|
||||
SHOW_MESSAGE_CONTENT_IN_NOTIFICATIONS(
|
||||
"property.show_message_content_in_notifications",
|
||||
"description.show_message_content_in_notifications",
|
||||
ConfigCategory.SPY,
|
||||
false
|
||||
ConfigStateValue(false)
|
||||
),
|
||||
MESSAGE_LOGGER("property.message_logger", "description.message_logger", ConfigCategory.SPY, false),
|
||||
UNLIMITED_SNAP_VIEW_TIME("property.unlimited_snap_view_time", "description.unlimited_snap_view_time", ConfigCategory.SPY, false),
|
||||
NOTIFICATION_FILTER(
|
||||
"property.notification_filter",
|
||||
"description.notification_filter",
|
||||
ConfigCategory.SPY,
|
||||
ConfigStateListValue(
|
||||
listOf("snap", "chat", "typing"),
|
||||
mutableMapOf(
|
||||
"snap" to true,
|
||||
"chat" to true,
|
||||
"typing" to true
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
MESSAGE_LOGGER("property.message_logger", "description.message_logger", ConfigCategory.SPY, ConfigStateValue(false)),
|
||||
UNLIMITED_SNAP_VIEW_TIME("property.unlimited_snap_view_time", "description.unlimited_snap_view_time", ConfigCategory.SPY, ConfigStateValue(false)),
|
||||
|
||||
AUTO_DOWNLOAD_SNAPS(
|
||||
"property.auto_download_snaps",
|
||||
"description.auto_download_snaps",
|
||||
ConfigCategory.MEDIA_DOWNLOADER,
|
||||
true
|
||||
ConfigStateValue(false)
|
||||
),
|
||||
AUTO_DOWNLOAD_STORIES(
|
||||
"property.auto_download_stories",
|
||||
"description.auto_download_stories",
|
||||
ConfigCategory.MEDIA_DOWNLOADER,
|
||||
false
|
||||
ConfigStateValue(false)
|
||||
),
|
||||
AUTO_DOWNLOAD_PUBLIC_STORIES(
|
||||
"property.auto_download_public_stories",
|
||||
"description.auto_download_public_stories",
|
||||
ConfigCategory.MEDIA_DOWNLOADER,
|
||||
false
|
||||
ConfigStateValue(false)
|
||||
),
|
||||
AUTO_DOWNLOAD_SPOTLIGHT(
|
||||
"property.auto_download_spotlight",
|
||||
"description.auto_download_spotlight",
|
||||
ConfigCategory.MEDIA_DOWNLOADER,
|
||||
false
|
||||
ConfigStateValue(false)
|
||||
),
|
||||
OVERLAY_MERGE(
|
||||
"property.overlay_merge",
|
||||
"description.overlay_merge",
|
||||
ConfigCategory.MEDIA_DOWNLOADER,
|
||||
true
|
||||
ConfigStateValue(false)
|
||||
),
|
||||
DOWNLOAD_INCHAT_SNAPS(
|
||||
"property.download_inchat_snaps",
|
||||
"description.download_inchat_snaps",
|
||||
ConfigCategory.MEDIA_DOWNLOADER,
|
||||
true
|
||||
ConfigStateValue(false)
|
||||
),
|
||||
ANTI_DOWNLOAD_BUTTON(
|
||||
"property.anti_auto_download_button",
|
||||
"description.anti_auto_download_button",
|
||||
ConfigCategory.MEDIA_DOWNLOADER,
|
||||
false
|
||||
ConfigStateValue(false)
|
||||
),
|
||||
|
||||
DISABLE_METRICS("property.disable_metrics", "description.disable_metrics", ConfigCategory.PRIVACY, true),
|
||||
DISABLE_METRICS("property.disable_metrics", "description.disable_metrics", ConfigCategory.PRIVACY, ConfigStateValue(false)),
|
||||
PREVENT_SCREENSHOT_NOTIFICATIONS(
|
||||
"property.prevent_screenshot_notifications",
|
||||
"description.prevent_screenshot_notifications",
|
||||
ConfigCategory.PRIVACY,
|
||||
true
|
||||
ConfigStateValue(false)
|
||||
),
|
||||
PREVENT_STATUS_NOTIFICATIONS(
|
||||
"property.prevent_status_notifications",
|
||||
"description.prevent_status_notifications",
|
||||
ConfigCategory.PRIVACY,
|
||||
true
|
||||
ConfigStateValue(false)
|
||||
),
|
||||
ANONYMOUS_STORY_VIEW(
|
||||
"property.anonymous_story_view",
|
||||
"description.anonymous_story_view",
|
||||
ConfigCategory.PRIVACY,
|
||||
false
|
||||
ConfigStateValue(false)
|
||||
),
|
||||
HIDE_TYPING_NOTIFICATION(
|
||||
"property.hide_typing_notification",
|
||||
"description.hide_typing_notification",
|
||||
ConfigCategory.PRIVACY,
|
||||
false
|
||||
ConfigStateValue(false)
|
||||
),
|
||||
|
||||
MENU_SLOT_ID("property.menu_slot_id", "description.menu_slot_id", ConfigCategory.UI, 1),
|
||||
MENU_SLOT_ID("property.menu_slot_id", "description.menu_slot_id", ConfigCategory.UI, ConfigIntegerValue(1)),
|
||||
MESSAGE_PREVIEW_LENGTH(
|
||||
"property.message_preview_length",
|
||||
"description.message_preview_length",
|
||||
ConfigCategory.UI,
|
||||
20
|
||||
ConfigIntegerValue(20)
|
||||
),
|
||||
|
||||
EXTERNAL_MEDIA_AS_SNAP(
|
||||
"property.external_media_as_snap",
|
||||
"description.external_media_as_snap",
|
||||
ConfigCategory.EXTRAS,
|
||||
false
|
||||
ConfigStateValue(false)
|
||||
),
|
||||
AUTO_SAVE("property.auto_save", "description.auto_save", ConfigCategory.EXTRAS, false),
|
||||
ANTI_AUTO_SAVE("property.anti_auto_save", "description.anti_auto_save", ConfigCategory.EXTRAS, false),
|
||||
SNAPCHAT_PLUS("property.snapchat_plus", "description.snapchat_plus", ConfigCategory.EXTRAS, false),
|
||||
AUTO_SAVE("property.auto_save", "description.auto_save", ConfigCategory.EXTRAS, ConfigStateValue(false)),
|
||||
ANTI_AUTO_SAVE("property.anti_auto_save", "description.anti_auto_save", ConfigCategory.EXTRAS, ConfigStateValue(false)),
|
||||
SNAPCHAT_PLUS("property.snapchat_plus", "description.snapchat_plus", ConfigCategory.EXTRAS, ConfigStateValue(false)),
|
||||
|
||||
REMOVE_VOICE_RECORD_BUTTON(
|
||||
"property.remove_voice_record_button",
|
||||
"description.remove_voice_record_button",
|
||||
ConfigCategory.TWEAKS,
|
||||
false
|
||||
ConfigStateValue(false)
|
||||
),
|
||||
REMOVE_STICKERS_BUTTON(
|
||||
"property.remove_stickers_button",
|
||||
"description.remove_stickers_button",
|
||||
ConfigCategory.TWEAKS,
|
||||
false
|
||||
ConfigStateValue(false)
|
||||
),
|
||||
REMOVE_COGNAC_BUTTON(
|
||||
"property.remove_cognac_button",
|
||||
"description.remove_cognac_button",
|
||||
ConfigCategory.TWEAKS,
|
||||
false
|
||||
ConfigStateValue(false)
|
||||
),
|
||||
REMOVE_CALL_BUTTONS(
|
||||
"property.remove_call_buttons",
|
||||
"description.remove_call_buttons",
|
||||
ConfigCategory.TWEAKS,
|
||||
false
|
||||
ConfigStateValue(false)
|
||||
),
|
||||
DISABLE_SNAP_SPLITTING(
|
||||
"property.disable_snap_splitting",
|
||||
"description.disable_snap_splitting",
|
||||
ConfigCategory.TWEAKS,
|
||||
false
|
||||
ConfigStateValue(false)
|
||||
),
|
||||
BLOCK_ADS("property.block_ads", "description.block_ads", ConfigCategory.TWEAKS, false),
|
||||
BLOCK_ADS("property.block_ads", "description.block_ads", ConfigCategory.TWEAKS, ConfigStateValue(false)),
|
||||
STREAK_EXPIRATION_INFO(
|
||||
"property.streak_expiration_info",
|
||||
"description.streakexpirationinfo",
|
||||
ConfigCategory.TWEAKS,
|
||||
false
|
||||
ConfigStateValue(false)
|
||||
),
|
||||
NEW_MAP_UI("property.new_map_ui", "description.new_map_ui", ConfigCategory.TWEAKS, false),
|
||||
NEW_MAP_UI("property.new_map_ui", "description.new_map_ui", ConfigCategory.TWEAKS, ConfigStateValue(false)),
|
||||
|
||||
USE_DOWNLOAD_MANAGER(
|
||||
"property.use_download_manager",
|
||||
"description.use_download_manager",
|
||||
ConfigCategory.EXPERIMENTAL,
|
||||
false
|
||||
ConfigStateValue(false)
|
||||
);
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package me.rhunk.snapenhance.config
|
||||
|
||||
abstract class ConfigValue<T> {
|
||||
abstract fun value(): T
|
||||
abstract fun write(): String
|
||||
abstract fun read(value: String)
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package me.rhunk.snapenhance.config.impl
|
||||
|
||||
import me.rhunk.snapenhance.config.ConfigValue
|
||||
|
||||
class ConfigIntegerValue(
|
||||
var value: Int
|
||||
) : ConfigValue<Int>() {
|
||||
override fun value() = value
|
||||
|
||||
override fun write(): String {
|
||||
return value.toString()
|
||||
}
|
||||
|
||||
override fun read(value: String) {
|
||||
this.value = value.toInt()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package me.rhunk.snapenhance.config.impl
|
||||
|
||||
import me.rhunk.snapenhance.config.ConfigValue
|
||||
|
||||
class ConfigStateListValue(
|
||||
private val keys: List<String>,
|
||||
var states: MutableMap<String, Boolean> = mutableMapOf()
|
||||
) : ConfigValue<Map<String, Boolean>>() {
|
||||
override fun value() = states
|
||||
|
||||
fun value(key: String) = states[key] ?: false
|
||||
|
||||
override fun write(): String {
|
||||
return keys.joinToString("|") { "$it:${states[it]}" }
|
||||
}
|
||||
|
||||
override fun read(value: String) {
|
||||
value.split("|").forEach {
|
||||
val (key, state) = it.split(":")
|
||||
states[key] = state.toBoolean()
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return states.filter { it.value }.keys.joinToString(", ") { it }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package me.rhunk.snapenhance.config.impl
|
||||
|
||||
import me.rhunk.snapenhance.config.ConfigValue
|
||||
|
||||
class ConfigStateValue(
|
||||
var value: Boolean
|
||||
) : ConfigValue<Boolean>() {
|
||||
override fun value() = value
|
||||
|
||||
override fun write(): String {
|
||||
return value.toString()
|
||||
}
|
||||
|
||||
override fun read(value: String) {
|
||||
this.value = value.toBoolean()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package me.rhunk.snapenhance.config.impl
|
||||
|
||||
import me.rhunk.snapenhance.config.ConfigValue
|
||||
|
||||
class ConfigStringValue(
|
||||
var value: String = ""
|
||||
) : ConfigValue<String>() {
|
||||
override fun value() = value
|
||||
|
||||
override fun write(): String {
|
||||
return value
|
||||
}
|
||||
|
||||
override fun read(value: String) {
|
||||
this.value = value
|
||||
}
|
||||
}
|
||||
@@ -154,11 +154,22 @@ class Notifications : Feature("Notifications", loadParams = FeatureLoadParams.IN
|
||||
}.clear()
|
||||
}
|
||||
|
||||
private fun shouldIgnoreNotification(type: String): Boolean {
|
||||
Logger.debug("notification type: $type")
|
||||
val states = context.config.options(ConfigProperty.NOTIFICATION_FILTER)
|
||||
|
||||
states["snap"]?.let { if (type.endsWith("SNAP") && it) return true }
|
||||
states["chat"]?.let { if (type.endsWith("CHAT") && it) return true }
|
||||
states["typing"]?.let { if (type.endsWith("TYPING") && it) return true }
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
override fun init() {
|
||||
val fetchConversationWithMessagesCallback = context.mappings.getMappedClass("callbacks", "FetchConversationWithMessagesCallback")
|
||||
|
||||
Hooker.hook(notifyAsUserMethod, HookStage.BEFORE, { context.config.bool(ConfigProperty.SHOW_MESSAGE_CONTENT) }) {
|
||||
val notificationData = NotificationData(it.argNullable(0), it.arg(1), it.arg(2), it.arg(3))
|
||||
Hooker.hook(notifyAsUserMethod, HookStage.BEFORE) { param ->
|
||||
val notificationData = NotificationData(param.argNullable(0), param.arg(1), param.arg(2), param.arg(3))
|
||||
|
||||
val extras: Bundle = notificationData.notification.extras.getBundle("system_notification_extras")?: return@hook
|
||||
|
||||
@@ -166,6 +177,13 @@ class Notifications : Feature("Notifications", loadParams = FeatureLoadParams.IN
|
||||
val notificationType = extras.getString("notification_type") ?: return@hook
|
||||
val conversationId = extras.getString("conversation_id") ?: return@hook
|
||||
|
||||
if (shouldIgnoreNotification(notificationType)) {
|
||||
param.setResult(null)
|
||||
return@hook
|
||||
}
|
||||
|
||||
if (!context.config.bool(ConfigProperty.SHOW_MESSAGE_CONTENT_IN_NOTIFICATIONS)) return@hook
|
||||
|
||||
if (!notificationType.endsWith("CHAT") && !notificationType.endsWith("SNAP")) return@hook
|
||||
|
||||
val conversationManager: Any = context.feature(Messaging::class).conversationManager
|
||||
@@ -181,7 +199,7 @@ class Notifications : Feature("Notifications", loadParams = FeatureLoadParams.IN
|
||||
}.build()
|
||||
|
||||
fetchConversationWithMessagesMethod.invoke(conversationManager, SnapUUID.fromString(conversationId).instanceNonNull(), callback)
|
||||
it.setResult(null)
|
||||
param.setResult(null)
|
||||
}
|
||||
|
||||
Hooker.hook(cancelAsUserMethod, HookStage.BEFORE) { param ->
|
||||
|
||||
@@ -11,6 +11,10 @@ import android.widget.TextView
|
||||
import me.rhunk.snapenhance.BuildConfig
|
||||
import me.rhunk.snapenhance.Constants
|
||||
import me.rhunk.snapenhance.config.ConfigProperty
|
||||
import me.rhunk.snapenhance.config.impl.ConfigIntegerValue
|
||||
import me.rhunk.snapenhance.config.impl.ConfigStateListValue
|
||||
import me.rhunk.snapenhance.config.impl.ConfigStateValue
|
||||
import me.rhunk.snapenhance.config.impl.ConfigStringValue
|
||||
import me.rhunk.snapenhance.features.impl.ui.menus.AbstractMenu
|
||||
import me.rhunk.snapenhance.features.impl.ui.menus.ViewAppearanceHelper
|
||||
|
||||
@@ -35,7 +39,7 @@ class SettingsMenu : AbstractMenu() {
|
||||
|
||||
val input = EditText(viewModel.context)
|
||||
input.inputType = InputType.TYPE_CLASS_TEXT
|
||||
input.setText(context.config.get(property).toString())
|
||||
input.setText(property.valueContainer.value().toString())
|
||||
|
||||
builder.setView(input)
|
||||
builder.setPositiveButton("OK") { _, _ ->
|
||||
@@ -46,34 +50,26 @@ class SettingsMenu : AbstractMenu() {
|
||||
builder.show()
|
||||
}
|
||||
|
||||
val resultView: View = when (property.defaultValue) {
|
||||
is String -> {
|
||||
val resultView: View = when (property.valueContainer) {
|
||||
is ConfigStringValue -> {
|
||||
val textView = TextView(viewModel.context)
|
||||
updateButtonText(textView, context.config.string(property))
|
||||
updateButtonText(textView, property.valueContainer.value)
|
||||
ViewAppearanceHelper.applyTheme(viewModel, textView)
|
||||
textView.setOnClickListener {
|
||||
textEditor { value ->
|
||||
context.config.set(property, value)
|
||||
property.valueContainer.value = value
|
||||
updateButtonText(textView, value)
|
||||
}
|
||||
}
|
||||
textView
|
||||
}
|
||||
is Number -> {
|
||||
is ConfigIntegerValue -> {
|
||||
val button = Button(viewModel.context)
|
||||
updateButtonText(button, context.config.get(property).toString())
|
||||
updateButtonText(button, property.valueContainer.value.toString())
|
||||
button.setOnClickListener {
|
||||
textEditor { value ->
|
||||
runCatching {
|
||||
context.config.set(property, when (property.defaultValue) {
|
||||
is Int -> value.toInt()
|
||||
is Double -> value.toDouble()
|
||||
is Float -> value.toFloat()
|
||||
is Long -> value.toLong()
|
||||
is Short -> value.toShort()
|
||||
is Byte -> value.toByte()
|
||||
else -> throw IllegalArgumentException()
|
||||
})
|
||||
property.valueContainer.value = value.toInt()
|
||||
updateButtonText(button, value)
|
||||
}.onFailure {
|
||||
context.shortToast("Invalid value")
|
||||
@@ -83,16 +79,44 @@ class SettingsMenu : AbstractMenu() {
|
||||
ViewAppearanceHelper.applyTheme(viewModel, button)
|
||||
button
|
||||
}
|
||||
is Boolean -> {
|
||||
is ConfigStateValue -> {
|
||||
val switch = Switch(viewModel.context)
|
||||
switch.text = context.translation.get(property.nameKey)
|
||||
switch.isChecked = context.config.bool(property)
|
||||
switch.isChecked = property.valueContainer.value
|
||||
switch.setOnCheckedChangeListener { _, isChecked ->
|
||||
context.config.set(property, isChecked)
|
||||
property.valueContainer.value = isChecked
|
||||
}
|
||||
ViewAppearanceHelper.applyTheme(viewModel, switch)
|
||||
switch
|
||||
}
|
||||
is ConfigStateListValue -> {
|
||||
val button = Button(viewModel.context)
|
||||
updateButtonText(button, property.valueContainer.toString())
|
||||
|
||||
button.setOnClickListener {_ ->
|
||||
val builder = AlertDialog.Builder(viewModel.context)
|
||||
builder.setTitle(context.translation.get(property.nameKey))
|
||||
|
||||
val sortedStates = property.valueContainer.states.toSortedMap()
|
||||
|
||||
builder.setMultiChoiceItems(
|
||||
sortedStates.toSortedMap().map { context.translation.get("option." + property.nameKey + "." +it.key) }.toTypedArray(),
|
||||
sortedStates.map { it.value }.toBooleanArray()
|
||||
) { _, which, isChecked ->
|
||||
sortedStates.keys.toList()[which].let { key ->
|
||||
property.valueContainer.states[key] = isChecked
|
||||
}
|
||||
}
|
||||
|
||||
builder.setPositiveButton("OK") { _, _ ->
|
||||
updateButtonText(button, property.valueContainer.toString())
|
||||
}
|
||||
|
||||
builder.show()
|
||||
}
|
||||
ViewAppearanceHelper.applyTheme(viewModel, button)
|
||||
button
|
||||
}
|
||||
else -> {
|
||||
TextView(viewModel.context)
|
||||
}
|
||||
|
||||
@@ -10,16 +10,12 @@ import me.rhunk.snapenhance.manager.Manager
|
||||
import java.nio.charset.StandardCharsets
|
||||
|
||||
class ConfigManager(
|
||||
private val context: ModContext,
|
||||
config: MutableMap<ConfigProperty, Any?> = mutableMapOf()
|
||||
) : ConfigAccessor(config), Manager {
|
||||
|
||||
private val propertyList = ConfigProperty.sortedByCategory()
|
||||
private val context: ModContext
|
||||
) : ConfigAccessor(), Manager {
|
||||
|
||||
override fun init() {
|
||||
//generate default config
|
||||
propertyList.forEach { key ->
|
||||
set(key, key.defaultValue)
|
||||
ConfigProperty.sortedByCategory().forEach { key ->
|
||||
set(key, key.valueContainer)
|
||||
}
|
||||
|
||||
if (!context.bridgeClient.isFileExists(BridgeFileType.CONFIG)) {
|
||||
@@ -44,16 +40,15 @@ class ConfigManager(
|
||||
String(configContent, StandardCharsets.UTF_8),
|
||||
JsonObject::class.java
|
||||
)
|
||||
propertyList.forEach { key ->
|
||||
val value = context.gson.fromJson(configObject.get(key.name), key.defaultValue.javaClass) ?: key.defaultValue
|
||||
set(key, value)
|
||||
entries().forEach { (key, value) ->
|
||||
value.read(configObject.get(key.name)?.asString ?: value.write())
|
||||
}
|
||||
}
|
||||
|
||||
fun writeConfig() {
|
||||
val configObject = JsonObject()
|
||||
propertyList.forEach { key ->
|
||||
configObject.add(key.name, context.gson.toJsonTree(get(key)))
|
||||
entries().forEach { (key, value) ->
|
||||
configObject.addProperty(key.name, value.write())
|
||||
}
|
||||
context.bridgeClient.writeFile(
|
||||
BridgeFileType.CONFIG,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package me.rhunk.snapenhance.manager.impl
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonParser
|
||||
import me.rhunk.snapenhance.Logger
|
||||
import me.rhunk.snapenhance.ModContext
|
||||
@@ -22,15 +23,17 @@ class TranslationManager(
|
||||
return
|
||||
}
|
||||
|
||||
translations.asJsonObject.entrySet().forEach {
|
||||
if (it.value.isJsonPrimitive) {
|
||||
translationMap[it.key] = it.value.asString
|
||||
}
|
||||
if (!it.value.isJsonObject) return@forEach
|
||||
it.value.asJsonObject.entrySet().forEach { entry ->
|
||||
translationMap["${it.key}.${entry.key}"] = entry.value.asString
|
||||
fun scanObject(jsonObject: JsonObject, prefix: String = "") {
|
||||
jsonObject.entrySet().forEach {
|
||||
if (it.value.isJsonPrimitive) {
|
||||
translationMap["$prefix${it.key}"] = it.value.asString
|
||||
}
|
||||
if (!it.value.isJsonObject) return@forEach
|
||||
scanObject(it.value.asJsonObject, "$prefix${it.key}.")
|
||||
}
|
||||
}
|
||||
|
||||
scanObject(translations)
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user