feat: ff menu bar (#59)

fix: amoled dark mode

Co-authored-by: rhunk <101876869+rhunk@users.noreply.github.com>
This commit is contained in:
auth
2023-06-11 01:10:24 +02:00
committed by GitHub
parent bbfc0a8350
commit ab8c4ddb66
9 changed files with 378 additions and 179 deletions

View File

@@ -69,7 +69,10 @@
"picture_resolution": "Override Picture Resolution",
"force_highest_frame_rate": "Force Highest Frame Rate",
"force_camera_source_encoding": "Force Camera Source Encoding",
"amoled_dark_mode": "AMOLED Dark Mode"
"amoled_dark_mode": "AMOLED Dark Mode",
"enable_friend_feed_menu_bar": "Enable New Friend Feed Menu Bar",
"friend_feed_menu_buttons": "Friend Feed Menu Buttons",
"friend_feed_menu_buttons_position": "Friend Feed Buttons Position Index"
},
"option": {
@@ -79,6 +82,12 @@
"snap": "Show medias",
"reply_button": "Add reply button"
},
"friend_feed_menu_buttons": {
"auto_download_blacklist": "\u2B07\uFE0F Auto Download Blacklist",
"anti_auto_save": "\uD83D\uDCAC Anti Auto Save Messages",
"stealth_mode": "\uD83D\uDC7B Stealth Mode",
"conversation_info": "\uD83D\uDC64 Conversation Info"
},
"download_options": {
"format_user_folder": "Create folder for each user",
"format_hash": "Add a unique hash to the file path",
@@ -140,7 +149,7 @@
"friend_menu_option": {
"preview": "Preview",
"stealth_mode": "Stealth Mode",
"anti_auto_download": "Anti Auto Download",
"auto_download_blacklist": "Auto Download Blacklist",
"anti_auto_save": "Anti Auto Save"
},

View File

@@ -141,12 +141,6 @@ enum class ConfigProperty(
ConfigCategory.MEDIA_MANAGEMENT,
ConfigStateValue(false)
),
DOWNLOAD_BLACKLIST(
"property.auto_download_blacklist",
"description.auto_download_blacklist",
ConfigCategory.MEDIA_MANAGEMENT,
ConfigStateValue(false)
),
GALLERY_MEDIA_SEND_OVERRIDE(
"property.gallery_media_send_override",
"description.gallery_media_send_override",
@@ -163,11 +157,6 @@ enum class ConfigProperty(
listOf("CHAT", "SNAP", "NOTE", "EXTERNAL_MEDIA", "STICKER")
)
),
ANTI_AUTO_SAVE("property.anti_auto_save",
"description.anti_auto_save",
ConfigCategory.MEDIA_MANAGEMENT,
ConfigStateValue(false)
),
FORCE_MEDIA_SOURCE_QUALITY(
"property.force_media_source_quality",
@@ -177,6 +166,31 @@ enum class ConfigProperty(
),
//UI AND TWEAKS
ENABLE_FRIEND_FEED_MENU_BAR(
"property.enable_friend_feed_menu_bar",
"description.enable_friend_feed_menu_bar",
ConfigCategory.UI_TWEAKS,
ConfigStateValue(false)
),
FRIEND_FEED_MENU_BUTTONS(
"property.friend_feed_menu_buttons",
"description.friend_feed_menu_buttons",
ConfigCategory.UI_TWEAKS,
ConfigStateListValue(
listOf("auto_download_blacklist", "anti_auto_save", "stealth_mode", "conversation_info"),
mutableMapOf(
"auto_download_blacklist" to false,
"anti_auto_save" to false,
"stealth_mode" to true,
"conversation_info" to true
)
)
),
FRIEND_FEED_MENU_POSITION("property.friend_feed_menu_buttons_position",
"description.friend_feed_menu_buttons_position",
ConfigCategory.UI_TWEAKS,
ConfigIntegerValue(1)
),
CAMERA_DISABLE(
"property.disable_camera",
"description.disable_camera",

View File

@@ -0,0 +1,38 @@
package me.rhunk.snapenhance.data.wrapper.impl
import android.content.Context
import android.graphics.drawable.Drawable
import android.util.AttributeSet
import android.view.View
import me.rhunk.snapenhance.SnapEnhance
import me.rhunk.snapenhance.data.wrapper.AbstractWrapper
class FriendActionButton(
obj: View
) : AbstractWrapper(obj) {
private val iconDrawableContainer by lazy {
instanceNonNull().javaClass.declaredFields.first { it.type != Int::class.javaPrimitiveType }[instanceNonNull()]
}
private val setIconDrawableMethod by lazy {
iconDrawableContainer.javaClass.declaredMethods.first {
it.parameterTypes.size == 1 &&
it.parameterTypes[0] == Drawable::class.java &&
it.name != "invalidateDrawable" &&
it.returnType == Void::class.javaPrimitiveType
}
}
fun setIconDrawable(drawable: Drawable) {
setIconDrawableMethod.invoke(iconDrawableContainer, drawable)
}
companion object {
fun new(context: Context): FriendActionButton {
val instance = SnapEnhance.classLoader.loadClass("com.snap.profile.shared.view.FriendActionButton")
.getConstructor(Context::class.java, AttributeSet::class.java)
.newInstance(context, null) as View
return FriendActionButton(instance)
}
}
}

View File

@@ -36,7 +36,8 @@ class AmoledDarkMode : Feature("Amoled Dark Mode", loadParams = FeatureLoadParam
getAttribute("sigColorTextPrimary") -> {
ephemeralHook("getColor", 0xFFFFFFFF.toInt())
}
getAttribute("sigColorBackgroundMain") -> {
getAttribute("sigColorBackgroundMain"),
getAttribute("sigColorBackgroundSurface") -> {
ephemeralHook("getColor", 0xFF000000.toInt())
}
getAttribute("actionSheetBackgroundDrawable"),

View File

@@ -3,8 +3,11 @@ package me.rhunk.snapenhance.features.impl.ui.menus
import android.annotation.SuppressLint
import android.content.res.ColorStateList
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
import android.graphics.drawable.ShapeDrawable
import android.graphics.drawable.StateListDrawable
import android.view.Gravity
import android.view.MotionEvent
import android.view.View
import android.widget.Switch
import android.widget.TextView
@@ -14,65 +17,77 @@ object ViewAppearanceHelper {
@SuppressLint("UseSwitchCompatOrMaterialCode", "RtlHardcoded", "DiscouragedApi",
"ClickableViewAccessibility"
)
fun applyTheme(viewModel: View, view: TextView) {
val sigColorTextPrimary = viewModel.context.theme.obtainStyledAttributes(
intArrayOf(viewModel.resources.getIdentifier("sigColorTextPrimary", "attr", Constants.SNAPCHAT_PACKAGE_NAME))
).getColor(0, 0)
private var sigColorTextPrimary: Int = 0
private var sigColorBackgroundSurface: Int = 0
val sigColorBackgroundMain = viewModel.context.theme.obtainStyledAttributes(
intArrayOf(viewModel.resources.getIdentifier("sigColorBackgroundMain", "attr", Constants.SNAPCHAT_PACKAGE_NAME))
).getColor(0, 0)
val snapchatFontResId = view.context.resources.getIdentifier("avenir_next_medium", "font", "com.snapchat.android")
//remove the shadow
view.setBackgroundColor(sigColorBackgroundMain)
view.setTextColor(sigColorTextPrimary)
view.setShadowLayer(0F, 0F, 0F, 0)
view.outlineProvider = null
view.gravity = Gravity.LEFT or Gravity.CENTER_VERTICAL
view.width = viewModel.width
//DPI Calculator
val scalingFactor = view.context.resources.displayMetrics.densityDpi.toDouble() / 400
view.height = (150 * scalingFactor).toInt()
view.setPadding((40 * scalingFactor).toInt(), 0, (40 * scalingFactor).toInt(), 0)
view.isAllCaps = false
view.textSize = 16f
view.typeface = view.context.resources.getFont(snapchatFontResId)
//FIXME: wrong color, shouldn't be that much noticeable though
view.setOnTouchListener { _, event ->
when (event.action) {
MotionEvent.ACTION_DOWN -> {
view.setBackgroundColor(0x5395026)
}
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
view.setBackgroundColor(sigColorBackgroundMain)
}
}
false
private fun createRoundedBackground(color: Int, hasRadius: Boolean): Drawable {
if (!hasRadius) return ColorDrawable(color)
//FIXME: hardcoded radius
return ShapeDrawable().apply {
paint.color = color
shape = android.graphics.drawable.shapes.RoundRectShape(
floatArrayOf(20f, 20f, 20f, 20f, 20f, 20f, 20f, 20f),
null,
null
)
}
if (view is Switch) {
with(viewModel.resources) {
view.switchMinWidth = getDimension(getIdentifier("v11_switch_min_width", "dimen", Constants.SNAPCHAT_PACKAGE_NAME)).toInt()
}
@SuppressLint("DiscouragedApi")
fun applyTheme(component: View, componentWidth: Int? = null, hasRadius: Boolean = false) {
val resources = component.context.resources
if (sigColorBackgroundSurface == 0 || sigColorTextPrimary == 0) {
with(component.context.theme) {
sigColorTextPrimary = obtainStyledAttributes(
intArrayOf(resources.getIdentifier("sigColorTextPrimary", "attr", Constants.SNAPCHAT_PACKAGE_NAME))
).getColor(0, 0)
sigColorBackgroundSurface = obtainStyledAttributes(
intArrayOf(resources.getIdentifier("sigColorBackgroundSurface", "attr", Constants.SNAPCHAT_PACKAGE_NAME))
).getColor(0, 0)
}
val colorStateList = ColorStateList(
}
val snapchatFontResId = resources.getIdentifier("avenir_next_medium", "font", "com.snapchat.android")
val scalingFactor = resources.displayMetrics.densityDpi.toDouble() / 400
with(component) {
if (this is TextView) {
setTextColor(sigColorTextPrimary)
setShadowLayer(0F, 0F, 0F, 0)
gravity = Gravity.CENTER_VERTICAL
componentWidth?.let { width = it}
height = (150 * scalingFactor).toInt()
isAllCaps = false
textSize = 16f
typeface = resources.getFont(snapchatFontResId)
outlineProvider = null
setPadding((40 * scalingFactor).toInt(), 0, (40 * scalingFactor).toInt(), 0)
}
background = StateListDrawable().apply {
addState(intArrayOf(), createRoundedBackground(color = sigColorBackgroundSurface, hasRadius))
addState(intArrayOf(android.R.attr.state_pressed), createRoundedBackground(color = 0x5395026, hasRadius))
}
}
if (component is Switch) {
with(resources) {
component.switchMinWidth = getDimension(getIdentifier("v11_switch_min_width", "dimen", Constants.SNAPCHAT_PACKAGE_NAME)).toInt()
}
component.trackTintList = ColorStateList(
arrayOf(intArrayOf(-android.R.attr.state_checked), intArrayOf(android.R.attr.state_checked)
), intArrayOf(
Color.parseColor("#1d1d1d"),
Color.parseColor("#26bd49")
)
)
val thumbStateList = ColorStateList(
component.thumbTintList = ColorStateList(
arrayOf(intArrayOf(-android.R.attr.state_checked), intArrayOf(android.R.attr.state_checked)
), intArrayOf(
Color.parseColor("#F5F5F5"),
Color.parseColor("#26bd49")
)
)
view.trackTintList = colorStateList
view.thumbTintList = thumbStateList
}
}
}

View File

@@ -1,11 +1,7 @@
package me.rhunk.snapenhance.features.impl.ui.menus.impl
import android.annotation.SuppressLint
import android.content.res.Resources
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.SystemClock
import android.util.TypedValue
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
@@ -15,8 +11,8 @@ import me.rhunk.snapenhance.Constants.VIEW_INJECTED_CODE
import me.rhunk.snapenhance.config.ConfigProperty
import me.rhunk.snapenhance.features.impl.Messaging
import me.rhunk.snapenhance.features.impl.downloader.MediaDownloader
import me.rhunk.snapenhance.features.impl.spying.MessageLogger
import me.rhunk.snapenhance.features.impl.ui.menus.AbstractMenu
import me.rhunk.snapenhance.features.impl.ui.menus.ViewAppearanceHelper
class ChatActionMenu : AbstractMenu() {
@@ -26,27 +22,6 @@ class ChatActionMenu : AbstractMenu() {
return false
}
private fun applyButtonTheme(parent: View, button: Button) {
button.background = ColorDrawable(Color.WHITE)
button.setTextColor(Color.BLACK)
button.transformationMethod = null
val margin = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
20f,
Resources.getSystem().displayMetrics
).toInt()
val params = MarginLayoutParams(parent.layoutParams)
params.setMargins(margin, 5, margin, 5)
params.marginEnd = margin
params.marginStart = margin
button.layoutParams = params
button.height = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
50f,
Resources.getSystem().displayMetrics
).toInt()
}
@SuppressLint("SetTextI18n")
fun inject(viewGroup: ViewGroup) {
val parent = viewGroup.parent.parent as ViewGroup
@@ -64,9 +39,23 @@ class ChatActionMenu : AbstractMenu() {
)
)
}
val injectButton = { button: Button ->
ViewAppearanceHelper.applyTheme(button, parent.width, hasRadius = true)
with(button) {
layoutParams = MarginLayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
).apply {
setMargins(40, 0, 40, 15)
}
parent.addView(this)
}
}
if (context.config.bool(ConfigProperty.CHAT_DOWNLOAD_CONTEXT_MENU)) {
parent.addView(Button(viewGroup.context).apply {
applyButtonTheme(parent, this)
injectButton(Button(viewGroup.context).apply {
text = this@ChatActionMenu.context.translation.get("chat_action_menu.preview_button")
setOnClickListener {
closeActionMenu()
@@ -74,8 +63,7 @@ class ChatActionMenu : AbstractMenu() {
}
})
parent.addView(Button(viewGroup.context).apply {
applyButtonTheme(parent, this)
injectButton(Button(viewGroup.context).apply {
text = this@ChatActionMenu.context.translation.get("chat_action_menu.download_button")
setOnClickListener {
closeActionMenu()
@@ -90,18 +78,17 @@ class ChatActionMenu : AbstractMenu() {
//delete logged message button
if (context.config.bool(ConfigProperty.MESSAGE_LOGGER)) {
val downloadButton = Button(viewGroup.context)
applyButtonTheme(parent, downloadButton)
downloadButton.text = context.translation.get("chat_action_menu.delete_logged_message_button")
downloadButton.setOnClickListener {
closeActionMenu()
context.executeAsync {
with(context.feature(Messaging::class)) {
context.feature(MessageLogger::class).deleteMessage(lastOpenedConversationUUID.toString(), lastFocusedMessageId)
injectButton(Button(viewGroup.context).apply {
text = this@ChatActionMenu.context.translation.get("chat_action_menu.delete_logged_message_button")
setOnClickListener {
closeActionMenu()
this@ChatActionMenu.context.executeAsync {
with(this@ChatActionMenu.context.feature(Messaging::class)) {
context.feature(me.rhunk.snapenhance.features.impl.spying.MessageLogger::class).deleteMessage(lastOpenedConversationUUID.toString(), lastFocusedMessageId)
}
}
}
}
parent.addView(downloadButton)
})
}
}
}

View File

@@ -5,26 +5,35 @@ import android.app.AlertDialog
import android.content.Context
import android.content.DialogInterface
import android.content.res.Resources
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.view.Gravity
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.CompoundButton
import android.widget.LinearLayout
import android.widget.Switch
import android.widget.Toast
import me.rhunk.snapenhance.Logger
import me.rhunk.snapenhance.config.ConfigProperty
import me.rhunk.snapenhance.data.ContentType
import me.rhunk.snapenhance.data.wrapper.impl.FriendActionButton
import me.rhunk.snapenhance.database.objects.ConversationMessage
import me.rhunk.snapenhance.database.objects.FriendInfo
import me.rhunk.snapenhance.database.objects.UserConversationLink
import me.rhunk.snapenhance.features.impl.Messaging
import me.rhunk.snapenhance.features.impl.downloader.AntiAutoDownload
import me.rhunk.snapenhance.features.impl.tweaks.AntiAutoSave
import me.rhunk.snapenhance.features.impl.spying.StealthMode
import me.rhunk.snapenhance.features.impl.tweaks.AntiAutoSave
import me.rhunk.snapenhance.features.impl.ui.menus.AbstractMenu
import me.rhunk.snapenhance.features.impl.ui.menus.ViewAppearanceHelper.applyTheme
import me.rhunk.snapenhance.features.impl.ui.menus.ViewAppearanceHelper
import java.net.HttpURLConnection
import java.net.URL
import java.text.DateFormat
@@ -164,77 +173,203 @@ class FriendFeedInfoMenu : AbstractMenu() {
builder.show()
}
private fun createToggleFeature(viewModel: View, viewConsumer: ((View) -> Unit), text: String, isChecked: () -> Boolean, toggle: (Boolean) -> Unit) {
val switch = Switch(viewModel.context)
private fun createEmojiDrawable(text: String, width: Int, height: Int, textSize: Float, disabled: Boolean = false): Drawable {
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
val paint = Paint()
paint.textSize = textSize
paint.color = Color.BLACK
paint.textAlign = Paint.Align.CENTER
canvas.drawText(text, width / 2f, height.toFloat() - paint.descent(), paint)
if (disabled) {
paint.color = Color.RED
paint.strokeWidth = 5f
canvas.drawLine(0f, 0f, width.toFloat(), height.toFloat(), paint)
}
return BitmapDrawable(context.resources, bitmap)
}
private fun getCurrentConversationId(): Pair<String, String?> {
val messaging = context.feature(Messaging::class)
var focusedConversationTargetUser: String? = null
val conversationId = if (messaging.lastFetchConversationUUID == null) {
focusedConversationTargetUser = messaging.lastFetchConversationUserUUID.toString()
val conversation: UserConversationLink = context.database.getDMConversationIdFromUserId(focusedConversationTargetUser) ?: throw IllegalStateException("No conversation found")
conversation.client_conversation_id!!.trim().lowercase()
} else {
messaging.lastFetchConversationUUID.toString()
}
return Pair(conversationId, focusedConversationTargetUser)
}
private fun createToggleFeature(viewConsumer: ((View) -> Unit), text: String, isChecked: () -> Boolean, toggle: (Boolean) -> Unit) {
val switch = Switch(context.androidContext)
switch.text = context.translation.get(text)
switch.isChecked = isChecked()
applyTheme(viewModel, switch)
ViewAppearanceHelper.applyTheme(switch)
switch.setOnCheckedChangeListener { _: CompoundButton?, checked: Boolean ->
toggle(checked)
}
viewConsumer(switch)
}
@SuppressLint("SetTextI18n", "UseSwitchCompatOrMaterialCode", "DefaultLocale")
fun injectOldButtons(viewModel: View, viewConsumer: ((View) -> Unit)) {
}
@SuppressLint("SetTextI18n", "UseSwitchCompatOrMaterialCode", "DefaultLocale", "InflateParams",
"DiscouragedApi", "ClickableViewAccessibility"
)
fun inject(viewModel: View, viewConsumer: ((View) -> Unit)) {
val messaging = context.feature(Messaging::class)
var focusedConversationTargetUser: String? = null
val conversationId: String
if (messaging.lastFetchConversationUserUUID != null) {
focusedConversationTargetUser = messaging.lastFetchConversationUserUUID.toString()
val conversation: UserConversationLink = context.database.getDMConversationIdFromUserId(focusedConversationTargetUser) ?: return
conversationId = conversation.client_conversation_id!!.trim().lowercase()
} else {
conversationId = messaging.lastFetchConversationUUID.toString()
}
val modContext = context
//preview button
val previewButton = Button(viewModel.context)
previewButton.text = context.translation.get("friend_menu_option.preview")
applyTheme(viewModel, previewButton)
val finalFocusedConversationTargetUser = focusedConversationTargetUser
previewButton.setOnClickListener {
showPreview(
finalFocusedConversationTargetUser,
conversationId,
previewButton.context
)
}
val friendFeedMenuOptions = context.config.options(ConfigProperty.FRIEND_FEED_MENU_BUTTONS)
if (friendFeedMenuOptions.none { it.value }) return
//stealth switch
val stealthSwitch = Switch(viewModel.context)
stealthSwitch.text = context.translation.get("friend_menu_option.stealth_mode")
stealthSwitch.isChecked = context.feature(StealthMode::class).isStealth(conversationId)
applyTheme(viewModel, stealthSwitch)
stealthSwitch.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean ->
context.feature(StealthMode::class).setStealth(
conversationId,
isChecked
)
}
val (conversationId, focusedConversationTargetUser) = getCurrentConversationId()
run {
val userId = context.database.getFriendFeedInfoByConversationId(conversationId)?.friendUserId ?: return@run
if (context.config.bool(ConfigProperty.DOWNLOAD_BLACKLIST)) {
createToggleFeature(viewModel,
viewConsumer,
"friend_menu_option.anti_auto_download",
{ context.feature(AntiAutoDownload::class).isUserIgnored(userId) },
{ context.feature(AntiAutoDownload::class).setUserIgnored(userId, it) }
)
if (!context.config.bool(ConfigProperty.ENABLE_FRIEND_FEED_MENU_BAR)) {
//preview button
val previewButton = Button(viewModel.context).apply {
text = modContext.translation.get("friend_menu_option.preview")
ViewAppearanceHelper.applyTheme(this, viewModel.width)
setOnClickListener {
showPreview(
focusedConversationTargetUser,
conversationId,
context
)
}
}
if (context.config.bool(ConfigProperty.ANTI_AUTO_SAVE)) {
createToggleFeature(viewModel,
viewConsumer,
"friend_menu_option.anti_auto_save",
{ context.feature(AntiAutoSave::class).isConversationIgnored(conversationId) },
{ context.feature(AntiAutoSave::class).setConversationIgnored(conversationId, it) }
//stealth switch
val stealthSwitch = Switch(viewModel.context).apply {
text = modContext.translation.get("friend_menu_option.stealth_mode")
isChecked = modContext.feature(StealthMode::class).isStealth(conversationId)
ViewAppearanceHelper.applyTheme(this)
setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean ->
modContext.feature(StealthMode::class).setStealth(
conversationId,
isChecked
)
}
}
run {
val userId = context.database.getFriendFeedInfoByConversationId(conversationId)?.friendUserId ?: return@run
if (friendFeedMenuOptions["auto_download_blacklist"] == true) {
createToggleFeature(viewConsumer,
"friend_menu_option.auto_download_blacklist",
{ context.feature(AntiAutoDownload::class).isUserIgnored(userId) },
{ context.feature(AntiAutoDownload::class).setUserIgnored(userId, it) }
)
}
if (friendFeedMenuOptions["anti_auto_save"] == true) {
createToggleFeature(viewConsumer,
"friend_menu_option.anti_auto_save",
{ context.feature(AntiAutoSave::class).isConversationIgnored(conversationId) },
{ context.feature(AntiAutoSave::class).setConversationIgnored(conversationId, it) }
)
}
}
viewConsumer(stealthSwitch)
viewConsumer(previewButton)
return
}
val menuButtonBar = LinearLayout(viewModel.context).apply {
layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
orientation = LinearLayout.HORIZONTAL
gravity = Gravity.CENTER
}
fun createActionButton(icon: String, isDisabled: Boolean? = null, onClick: (Boolean) -> Unit) {
//FIXME: hardcoded values
menuButtonBar.addView(LinearLayout(viewModel.context).apply {
layoutParams = LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT, 1f)
gravity = Gravity.CENTER
setPadding(0, 20, 0, 20)
isClickable = true
scaleX = 1.1f
scaleY = 1.1f
var isLineThrough = isDisabled ?: false
FriendActionButton.new(viewModel.context).apply {
fun setLineThrough(value: Boolean) {
setIconDrawable(createEmojiDrawable(icon, 60, 60, 50f, if (isDisabled == null) false else value))
}
setLineThrough(isLineThrough)
(instanceNonNull() as View).apply {
layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT).apply {
setMargins(0, 60, 0, 60)
}
setOnTouchListener { _, event ->
if (event.action == MotionEvent.ACTION_UP) {
isLineThrough = !isLineThrough
onClick(isLineThrough)
setLineThrough(isLineThrough)
}
false
}
}
}.also { addView(it.instanceNonNull() as View) }
})
}
if (friendFeedMenuOptions["auto_download_blacklist"] == true) {
run {
val userId =
context.database.getFriendFeedInfoByConversationId(conversationId)?.friendUserId
?: return@run
createActionButton(
"\u2B07\uFE0F",
isDisabled = !context.feature(AntiAutoDownload::class).isUserIgnored(userId)
) {
context.feature(AntiAutoDownload::class).setUserIgnored(userId, !it)
}
}
}
if (friendFeedMenuOptions["anti_auto_save"] == true) {
//diskette
createActionButton("\uD83D\uDCAC",
isDisabled = !context.feature(AntiAutoSave::class)
.isConversationIgnored(conversationId)
) {
context.feature(AntiAutoSave::class).setConversationIgnored(conversationId, !it)
}
}
if (friendFeedMenuOptions["stealth_mode"] == true) {
//eyes
createActionButton(
"\uD83D\uDC7B",
isDisabled = !context.feature(StealthMode::class).isStealth(conversationId)
) { isChecked ->
context.feature(StealthMode::class).setStealth(
conversationId,
!isChecked
)
}
}
viewConsumer(stealthSwitch)
viewConsumer(previewButton)
if (friendFeedMenuOptions["conversation_info"] == true) {
//user
createActionButton("\uD83D\uDC64") {
showPreview(
focusedConversationTargetUser,
conversationId,
viewModel.context
)
}
}
viewConsumer(menuButtonBar)
}
}

View File

@@ -72,7 +72,7 @@ class OperaContextActionMenu : AbstractMenu() {
val button = Button(childView.getContext())
button.text = context.translation.get("opera_context_menu.download")
button.setOnClickListener { context.feature(MediaDownloader::class).downloadLastOperaMediaAsync() }
applyTheme(linearLayout, button)
applyTheme(button)
linearLayout.addView(button)
(childView as ViewGroup).addView(linearLayout, 0)
} catch (e: Throwable) {

View File

@@ -24,10 +24,10 @@ import me.rhunk.snapenhance.features.impl.ui.menus.ViewAppearanceHelper
class SettingsMenu : AbstractMenu() {
@SuppressLint("ClickableViewAccessibility")
private fun createCategoryTitle(viewModel: View, key: String): TextView {
val categoryText = TextView(viewModel.context)
private fun createCategoryTitle(key: String): TextView {
val categoryText = TextView(context.androidContext)
categoryText.text = context.translation.get(key)
ViewAppearanceHelper.applyTheme(viewModel, categoryText)
ViewAppearanceHelper.applyTheme(categoryText)
categoryText.textSize = 20f
categoryText.typeface = categoryText.typeface?.let { Typeface.create(it, Typeface.BOLD) }
categoryText.setOnTouchListener { _, _ -> true }
@@ -35,7 +35,7 @@ class SettingsMenu : AbstractMenu() {
}
@SuppressLint("SetTextI18n")
private fun createPropertyView(viewModel: View, property: ConfigProperty): View {
private fun createPropertyView(property: ConfigProperty): View {
val propertyName = context.translation.get(property.nameKey)
val updateButtonText: (TextView, String) -> Unit = { textView, text ->
textView.text = "$propertyName${if (text.isEmpty()) "" else ": $text"}"
@@ -57,10 +57,10 @@ class SettingsMenu : AbstractMenu() {
}
val textEditor: ((String) -> Unit) -> Unit = { updateValue ->
val builder = AlertDialog.Builder(viewModel.context)
val builder = AlertDialog.Builder(context.mainActivity!!)
builder.setTitle(propertyName)
val input = EditText(viewModel.context)
val input = EditText(context.androidContext)
input.inputType = InputType.TYPE_CLASS_TEXT
input.setText(property.valueContainer.value().toString())
@@ -75,12 +75,12 @@ class SettingsMenu : AbstractMenu() {
val resultView: View = when (property.valueContainer) {
is ConfigStringValue -> {
val textView = TextView(viewModel.context)
val textView = TextView(context.androidContext)
updateButtonText(textView, property.valueContainer.let {
if (it.isHidden) it.hiddenValue()
else it.value()
})
ViewAppearanceHelper.applyTheme(viewModel, textView)
ViewAppearanceHelper.applyTheme(textView)
textView.setOnClickListener {
textEditor { value ->
property.valueContainer.writeFrom(value)
@@ -93,7 +93,7 @@ class SettingsMenu : AbstractMenu() {
textView
}
is ConfigIntegerValue -> {
val button = Button(viewModel.context)
val button = Button(context.androidContext)
updateButtonText(button, property.valueContainer.value().toString())
button.setOnClickListener {
textEditor { value ->
@@ -105,25 +105,25 @@ class SettingsMenu : AbstractMenu() {
}
}
}
ViewAppearanceHelper.applyTheme(viewModel, button)
ViewAppearanceHelper.applyTheme(button)
button
}
is ConfigStateValue -> {
val switch = Switch(viewModel.context)
val switch = Switch(context.androidContext)
switch.text = propertyName
switch.isChecked = property.valueContainer.value()
switch.setOnCheckedChangeListener { _, isChecked ->
property.valueContainer.writeFrom(isChecked.toString())
}
ViewAppearanceHelper.applyTheme(viewModel, switch)
ViewAppearanceHelper.applyTheme(switch)
switch
}
is ConfigStateSelection -> {
val button = Button(viewModel.context)
val button = Button(context.androidContext)
updateLocalizedText(button, property.valueContainer.value())
button.setOnClickListener {_ ->
val builder = AlertDialog.Builder(viewModel.context)
val builder = AlertDialog.Builder(context.mainActivity!!)
builder.setTitle(propertyName)
builder.setSingleChoiceItems(
@@ -142,15 +142,15 @@ class SettingsMenu : AbstractMenu() {
builder.show()
}
ViewAppearanceHelper.applyTheme(viewModel, button)
ViewAppearanceHelper.applyTheme(button)
button
}
is ConfigStateListValue -> {
val button = Button(viewModel.context)
val button = Button(context.androidContext)
updateButtonText(button, "(${property.valueContainer.value().count { it.value }})")
button.setOnClickListener {_ ->
val builder = AlertDialog.Builder(viewModel.context)
val builder = AlertDialog.Builder(context.mainActivity!!)
builder.setTitle(propertyName)
val sortedStates = property.valueContainer.value().toSortedMap()
@@ -173,11 +173,11 @@ class SettingsMenu : AbstractMenu() {
builder.show()
}
ViewAppearanceHelper.applyTheme(viewModel, button)
ViewAppearanceHelper.applyTheme(button)
button
}
else -> {
TextView(viewModel.context)
TextView(context.androidContext)
}
}
return resultView
@@ -203,7 +203,7 @@ class SettingsMenu : AbstractMenu() {
}
val titleText = TextView(viewModel.context)
titleText.text = versionTextBuilder.toString()
ViewAppearanceHelper.applyTheme(viewModel, titleText)
ViewAppearanceHelper.applyTheme(titleText)
titleText.textSize = 18f
titleText.minHeight = 80 * versionTextBuilder.chars().filter { ch: Int -> ch == '\n'.code }
.count().coerceAtLeast(2).toInt()
@@ -216,7 +216,7 @@ class SettingsMenu : AbstractMenu() {
button.setOnClickListener { _ ->
it.run()
}
ViewAppearanceHelper.applyTheme(viewModel, button)
ViewAppearanceHelper.applyTheme(button)
button
}
}
@@ -224,9 +224,9 @@ class SettingsMenu : AbstractMenu() {
context.config.entries().groupBy {
it.key.category
}.forEach { (category, value) ->
addView(createCategoryTitle(viewModel, category.key))
addView(createCategoryTitle(category.key))
value.filter { it.key.shouldAppearInSettings }.forEach { (property, _) ->
addView(createPropertyView(viewModel, property))
addView(createPropertyView(property))
actions.find { pair -> pair.first.dependsOnProperty == property}?.let { pair ->
addView(pair.second())
}