Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions plugins/AliucordStyleSheets/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import com.android.build.gradle.LibraryExtension

version = "1.0.7"
description = "(A.S.S) Style Aliucord to your liking!"

aliucord {
changelog = """
# 1.0.0
* Initial version
""".trimIndent()

author("RazerTexz", 633565155501801472L)
}

configure<LibraryExtension> {
defaultConfig {
minSdk = 26
}
}
156 changes: 156 additions & 0 deletions plugins/AliucordStyleSheets/src/com/github/razertexz/ASS.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
package com.github.razertexz

import androidx.recyclerview.widget.RecyclerView
import android.content.Context
import android.widget.TextView
import android.widget.ImageView
import android.view.LayoutInflater
import android.view.ViewGroup
import android.view.View
import android.util.SparseArray

import com.aliucord.annotations.AliucordPlugin
import com.aliucord.entities.Plugin

import org.xmlpull.v1.XmlPullParser

import de.robv.android.xposed.XC_MethodHook

@AliucordPlugin(requiresRestart = false)
class ASS : Plugin() {
private val stack = ArrayDeque<View>()

init {
settingsTab = SettingsTab(ASSSettings::class.java).withArgs(settings)
}

override fun start(ctx: Context) {
val currentStyle = settings.getString("currentStyle", "")
if (currentStyle.isEmpty()) return

val rules = ASSLoader.loadStyle(currentStyle)?.rules ?: return
patcher.patch(LayoutInflater::class.java, "inflate", arrayOf(XmlPullParser::class.java, ViewGroup::class.java, Boolean::class.java), object : XC_MethodHook(10000) {
override fun afterHookedMethod(param: XC_MethodHook.MethodHookParam) {
traverse(param.result as View, rules)
}
})

patcher.patch(RecyclerView.Adapter::class.java, "onBindViewHolder", arrayOf(RecyclerView.ViewHolder::class.java, Int::class.java, List::class.java), object : XC_MethodHook(10000) {
override fun afterHookedMethod(param: XC_MethodHook.MethodHookParam) {
traverse((param.args[0] as RecyclerView.ViewHolder).itemView, rules)
}
})
}

override fun stop(ctx: Context) = patcher.unpatchAll()

private fun traverse(view: View, rules: SparseArray<Rule>) {
stack.addFirst(view)

while (stack.isNotEmpty()) {
val current = stack.removeFirst()
if (current.id != View.NO_ID) {
val rule = rules[current.id]
if (rule != null) applyRule(current, rule)
}

if (current is ViewGroup) {
for (i in 0 until current.childCount) {
stack.addFirst(current.getChildAt(i))
}
}
}
}

private fun applyRule(view: View, rule: Rule) {
val lp = view.layoutParams
var lpChanged = false

if (view is TextView) {
if (rule.textSize != null) {
view.textSize = rule.textSize!!
}

if (rule.textColor != null && view.currentTextColor != rule.textColor) {
view.setTextColor(rule.textColor!!)
}

if (rule.typeface != null && view.typeface != rule.typeface) {
view.typeface = rule.typeface
}

if (rule.compoundDrawableTint != null && view.compoundDrawableTintList != rule.compoundDrawableTint) {
view.compoundDrawableTintList = rule.compoundDrawableTint
}
} else if (view is ImageView) {
if (rule.drawableState != null && view.drawable?.constantState != rule.drawableState) {
view.setImageDrawable(rule.drawableState!!.newDrawable().mutate())
}

if (rule.drawableTint != null) {
view.setColorFilter(rule.drawableTint!!)
}
}

if (rule.visibility != null && view.visibility != rule.visibility) {
view.visibility = rule.visibility!!
}

if (rule.bgState != null && view.background?.constantState != rule.bgState) {
view.setBackground(rule.bgState!!.newDrawable(view.resources).mutate())
}

if (rule.bgTint != null && view.backgroundTintList != rule.bgTint) {
view.backgroundTintList = rule.bgTint
}

if (rule.width != null && lp.width != rule.width) {
lp.width = rule.width!!
lpChanged = true
}

if (rule.height != null && lp.height != rule.height) {
lp.height = rule.height!!
lpChanged = true
}

if (lp is ViewGroup.MarginLayoutParams) {
if (rule.leftMargin != null && lp.leftMargin != rule.leftMargin) {
lp.leftMargin = rule.leftMargin!!
lpChanged = true
}

if (rule.topMargin != null && lp.topMargin != rule.topMargin) {
lp.topMargin = rule.topMargin!!
lpChanged = true
}

if (rule.rightMargin != null && lp.rightMargin != rule.rightMargin) {
lp.rightMargin = rule.rightMargin!!
lpChanged = true
}

if (rule.bottomMargin != null && lp.bottomMargin != rule.bottomMargin) {
lp.bottomMargin = rule.bottomMargin!!
lpChanged = true
}
}

if (lpChanged) {
view.layoutParams = lp
}

if (rule.paddingLeft != null || rule.paddingTop != null || rule.paddingRight != null || rule.paddingBottom != null) {
view.setPadding(
rule.paddingLeft ?: view.paddingLeft,
rule.paddingTop ?: view.paddingTop,
rule.paddingRight ?: view.paddingRight,
rule.paddingBottom ?: view.paddingBottom
)
}

for ((paths, value) in rule.customProperties.entries) {
ReflectUtils.setValue(view, paths, value)
}
}
}
166 changes: 166 additions & 0 deletions plugins/AliucordStyleSheets/src/com/github/razertexz/ASSLoader.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
package com.github.razertexz

import androidx.core.graphics.PathParser
import android.content.res.ColorStateList
import android.graphics.drawable.GradientDrawable
import android.graphics.drawable.ColorDrawable
import android.graphics.Typeface
import android.graphics.Color
import android.graphics.Path
import android.util.SparseArray
import android.util.ArrayMap
import android.view.View

import com.aliucord.Constants
import com.aliucord.Logger
import com.aliucord.Utils
import com.aliucord.utils.DimenUtils

import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonWriter
import com.google.gson.TypeAdapter

import java.io.FileReader
import java.io.File

internal object ASSLoader {
private object ASSTypeAdapter : TypeAdapter<Style>() {
private val fontCache = ArrayMap<String, Typeface>()

override fun read(reader: JsonReader): Style {
val manifest = Manifest()
val rules = SparseArray<Rule>()

reader.b()
while (reader.q()) {
val name = reader.C()
if (name == "manifest") {
reader.b()
while (reader.q()) {
when (reader.C()) {
"name" -> manifest.name = reader.J()
"version" -> manifest.version = reader.J()
"author" -> manifest.author = reader.J()
else -> reader.U()
}
}
reader.f()
} else {
val childId = Utils.getResId(name, "id")
if (childId == 0) {
reader.U()
continue
}

var vectorPath: Path? = null
var vectorWidth = 24.0f
var vectorHeight = 24.0f

var gradientColors = ArrayList<Int>()
var gradientType = GradientDrawable.LINEAR_GRADIENT
var gradientOrientation = GradientDrawable.Orientation.LEFT_RIGHT

val rule = Rule()

reader.b()
while (reader.q()) {
val propName = reader.C()
when (propName) {
"visibility" -> {
rule.visibility = when (reader.J()) {
"GONE" -> View.GONE
"INVISIBLE" -> View.INVISIBLE
else -> View.VISIBLE
}
}

"width" -> {
val value = reader.x()
rule.width = if (value < 0) value.toInt() else DimenUtils.dpToPx(value.toFloat())
}

"height" -> {
val value = reader.x()
rule.height = if (value < 0) value.toInt() else DimenUtils.dpToPx(value.toFloat())
}

"leftMargin" -> rule.leftMargin = DimenUtils.dpToPx(reader.x().toFloat())
"topMargin" -> rule.topMargin = DimenUtils.dpToPx(reader.x().toFloat())
"rightMargin" -> rule.rightMargin = DimenUtils.dpToPx(reader.x().toFloat())
"bottomMargin" -> rule.bottomMargin = DimenUtils.dpToPx(reader.x().toFloat())

"paddingLeft" -> rule.paddingLeft = DimenUtils.dpToPx(reader.x().toFloat())
"paddingTop" -> rule.paddingTop = DimenUtils.dpToPx(reader.x().toFloat())
"paddingRight" -> rule.paddingRight = DimenUtils.dpToPx(reader.x().toFloat())
"paddingBottom" -> rule.paddingBottom = DimenUtils.dpToPx(reader.x().toFloat())

"drawableTint" -> rule.drawableTint = Color.parseColor(reader.J())
"bgColor" -> rule.bgState = ColorDrawable(Color.parseColor(reader.J())).constantState
"bgTint" -> rule.bgTint = ColorStateList.valueOf(Color.parseColor(reader.J()))

"textSize" -> rule.textSize = reader.x().toFloat()
"textColor" -> rule.textColor = Color.parseColor(reader.J())
"typeface" -> {
val fontName = reader.J()
rule.typeface = fontCache.getOrPut(fontName) {
Typeface.createFromFile(File("${Constants.BASE_PATH}/styles/$fontName"))
}
}
"compoundDrawableTint" -> rule.compoundDrawableTint = ColorStateList.valueOf(Color.parseColor(reader.J()))

"gradientColors" -> {
reader.a()
while (reader.q()) {
gradientColors += Color.parseColor(reader.J())
}
reader.e()
}
"gradientType" -> {
gradientType = when (reader.J()) {
"RADIAL" -> GradientDrawable.RADIAL_GRADIENT
"SWEEP" -> GradientDrawable.SWEEP_GRADIENT
else -> GradientDrawable.LINEAR_GRADIENT
}
}
"gradientOrientation" -> gradientOrientation = GradientDrawable.Orientation.valueOf(reader.J())

"vectorPath" -> vectorPath = PathParser.createPathFromPathData(reader.J())
"vectorWidth" -> vectorWidth = reader.x().toFloat()
"vectorHeight" -> vectorHeight = reader.x().toFloat()

else -> rule.customProperties[propName.split(".").toTypedArray()] = reader.J()
}
}

if (vectorPath != null) {
rule.drawableState = PathDrawable.State(vectorPath, vectorWidth, vectorHeight)
}

if (gradientColors.isNotEmpty()) {
rule.bgState = GradientDrawable(gradientOrientation, gradientColors.toIntArray()).apply { this.gradientType = gradientType }.constantState
}

rules.put(childId, rule)
reader.f()
}
}
reader.f()

return Style(manifest, rules)
}

override fun write(writer: JsonWriter, value: Style) {}
}

fun loadStyle(fileName: String): Style? {
val reader = JsonReader(FileReader("${Constants.BASE_PATH}/styles/$fileName"))
return try {
ASSTypeAdapter.read(reader)
} catch (e: Exception) {
Logger("AliucordStyleSheets").errorToast("Something went wrong! please check debug logs.", e)
null
} finally {
reader.close()
}
}
}
Loading
Loading