6.6.2 - Alpha4 - 优化部分控件主题色与背景色对比度过低时的视觉体验

This commit is contained in:
SuperMonster003
2025-03-13 17:48:29 +08:00
parent 5c15917abf
commit 17e202a5b1
17 changed files with 335 additions and 129 deletions

View File

@@ -767,7 +767,7 @@ class UI(private val scriptRuntime: ScriptRuntime) : AugmentableProxy(scriptRunt
private fun attrValueConvert(o: Any?): Any? = when (o) {
is String -> o
is ColorNativeObject -> Colors.toHexRhino(o)
is ThemeColor -> o.getColorPrimary()
is ThemeColor -> o.colorPrimary
is NativeWith -> attrValueConvert(o.prototype)
else -> o
}

View File

@@ -17,16 +17,10 @@ import org.autojs.autojs6.R
* Modified by SuperMonster003 as of Mar 30, 2023.
* Transformed by SuperMonster003 on Mar 30, 2023.
*/
class ThemeColor {
class ThemeColor(@JvmField var colorPrimary: Int, @JvmField var colorPrimaryDark: Int, @JvmField var colorAccent: Int) {
@JvmField
var colorPrimary = 0
@JvmField
var colorAccent = 0
@JvmField
var colorPrimaryDark = 0
@JvmOverloads
constructor(color: Int = 0) : this(color, color, color)
@ScriptInterface
fun getColorPrimary() = colorPrimary
@@ -41,16 +35,6 @@ class ThemeColor {
fun isLuminanceDark() = ColorUtils.isLuminanceDark(colorPrimary)
constructor()
constructor(color: Int) : this(color, color, color)
constructor(colorPrimary: Int, colorPrimaryDark: Int, colorAccent: Int) {
this.colorPrimary = colorPrimary
this.colorPrimaryDark = colorPrimaryDark
this.colorAccent = colorAccent
}
fun colorPrimary(colorPrimary: Int) = also { this.colorPrimary = colorPrimary }
fun colorPrimaryDark(colorPrimaryDark: Int) = also { this.colorPrimaryDark = colorPrimaryDark }

View File

@@ -19,6 +19,8 @@ import androidx.appcompat.widget.SwitchCompat;
import androidx.core.graphics.drawable.DrawableCompat;
import org.autojs.autojs.theme.internal.ScrollingViewEdgeGlowColorHelper;
import org.autojs.autojs.util.ColorUtils;
import org.autojs.autojs6.R;
/**
* Created by Stardust on Oct 24, 2016.
@@ -27,8 +29,8 @@ public class ThemeColorHelper {
private static final String TAG = "ThemeColorHelper";
private static final int[][] SWITCH_STATES = new int[][]{
new int[]{-android.R.attr.state_checked},
new int[]{android.R.attr.state_checked},
new int[]{-android.R.attr.state_checked},
};
private static void setColorPrimary(View v, int themeColor) {
@@ -44,36 +46,67 @@ public class ThemeColorHelper {
}
private static void setColorPrimary(ViewGroup viewGroup, int themeColor) {
setColorPrimary(viewGroup, themeColor, false);
}
private static void setColorPrimary(ViewGroup viewGroup, int themeColor, boolean contrastMatters) {
if (contrastMatters) themeColor = ColorUtils.adjustColorForContrast(viewGroup.getContext().getColor(R.color.window_background), themeColor, 2.3);
for (int i = 0; i < viewGroup.getChildCount(); i++) {
setColorPrimary(viewGroup.getChildAt(i), themeColor);
}
}
public static void setColorPrimary(SwitchCompat switchCompat, int color) {
setThumbDrawableTintList(switchCompat.getThumbDrawable(), color);
setTrackDrawableTintList(switchCompat.getTrackDrawable(), color);
setColorPrimary(switchCompat, color, false);
}
public static void setColorPrimary(SwitchCompat switchCompat, int color, boolean contrastMatters) {
int adjustedThumbColor = contrastMatters
? ColorUtils.adjustColorForContrast(switchCompat.getContext().getColor(R.color.window_background), color, 2.3)
: color;
int adjustedTrackColor = contrastMatters
? ColorUtils.adjustColorForContrast(switchCompat.getContext().getColor(R.color.window_background), color, 3.6)
: color;
setThumbDrawableTintList(switchCompat.getThumbDrawable(), adjustedThumbColor);
setTrackDrawableTintList(switchCompat.getTrackDrawable(), adjustedTrackColor, true);
}
public static void setColorPrimary(Switch sw, int color) {
setThumbDrawableTintList(sw.getThumbDrawable(), color);
setTrackDrawableTintList(sw.getTrackDrawable(), color);
setColorPrimary(sw, color, false);
}
public static void setColorPrimary(Switch sw, int color, boolean contrastMatters) {
int adjustedThumbColor = contrastMatters
? ColorUtils.adjustColorForContrast(sw.getContext().getColor(R.color.window_background), color, 2.3)
: color;
int adjustedTrackColor = contrastMatters
? ColorUtils.adjustColorForContrast(sw.getContext().getColor(R.color.window_background), color, 3.6)
: color;
setThumbDrawableTintList(sw.getThumbDrawable(), adjustedThumbColor);
setTrackDrawableTintList(sw.getTrackDrawable(), adjustedTrackColor, false);
}
private static void setThumbDrawableTintList(Drawable drawable, int color) {
int unselectedColor = ColorUtils.isLuminanceLight(color)
? Color.parseColor("#616161") // R.color.md_grey_700
: Color.DKGRAY;
int[] thumbColors = new int[]{
Color.DKGRAY,
color,
unselectedColor,
};
DrawableCompat.setTintList(DrawableCompat.wrap(drawable), new ColorStateList(SWITCH_STATES, thumbColors));
}
private static void setTrackDrawableTintList(Drawable drawable, int color) {
private static void setTrackDrawableTintList(Drawable drawable, int color, boolean isCompat) {
int alpha = isCompat ? 0x29 : 0x66;
int[] trackColors = new int[]{
Color.GRAY,
makeAlpha(0x66, color)
makeAlpha(alpha, color),
makeAlpha(alpha, Color.BLACK),
};
DrawableCompat.setTintList(DrawableCompat.wrap(drawable), new ColorStateList(SWITCH_STATES, trackColors));
DrawableCompat.setTintList(drawable, new ColorStateList(SWITCH_STATES, trackColors));
}
private static int makeAlpha(int alpha, int color) {

View File

@@ -10,6 +10,8 @@ import androidx.preference.PreferenceViewHolder
import org.autojs.autojs.theme.ThemeColor
import org.autojs.autojs.theme.ThemeColorManager
import org.autojs.autojs.theme.ThemeColorMutable
import org.autojs.autojs.util.ColorUtils
import org.autojs.autojs6.R
/**
* Created by Stardust on Aug 8, 2016.
@@ -35,9 +37,9 @@ class ThemeColorPreferenceCategory : PreferenceCategory, ThemeColorMutable {
fun setTitleTextColor(titleTextColor: Int) = setThemeColor(ThemeColor(titleTextColor))
override fun setThemeColor(color: ThemeColor) {
color.colorPrimary.let {
mColor = it
mTitleTextView?.setTextColor(it)
ColorUtils.adjustColorForContrast(context.getColor(R.color.window_background), color.colorPrimary, 3.2).let { contrastColor ->
mColor = contrastColor
mTitleTextView?.setTextColor(contrastColor)
}
}

View File

@@ -1,5 +1,6 @@
package org.autojs.autojs.theme.preference
import android.annotation.SuppressLint
import android.content.Context
import android.content.res.Resources
import android.content.res.TypedArray
@@ -32,6 +33,27 @@ class ThemeColorSwitchPreference : SwitchPreference, ThemeColorMutable, LongClic
override var longClickPromptMore: CharSequence? = null
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {
init(context, attrs, defStyleAttr, defStyleRes)
}
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
init(context, attrs, defStyleAttr, 0)
}
@SuppressLint("RestrictedApi")
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
init(context, attrs, 0, 0)
}
constructor(context: Context) : super(context) {
init(context, null, 0, 0)
}
init {
ThemeColorManager.add(this)
}
private fun init(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) {
obtainStyledAttrs(context, attrs, R.styleable.MaterialPreference, defStyleAttr, defStyleRes)
.let { a ->
getAttrString(a, R.styleable.MaterialPreference_longClickPrompt)?.also { longClickPrompt = it }
@@ -40,20 +62,6 @@ class ThemeColorSwitchPreference : SwitchPreference, ThemeColorMutable, LongClic
}
}
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : this(context, attrs, defStyleAttr, 0)
constructor(context: Context, attrs: AttributeSet?) : this(
context, attrs, TypedArrayUtils.getAttr(
context, androidx.preference.R.attr.switchPreferenceStyle, android.R.attr.switchPreferenceStyle
)
)
constructor(context: Context) : this(context, null)
init {
ThemeColorManager.add(this)
}
override fun onBindViewHolder(holder: PreferenceViewHolder) {
super.onBindViewHolder(holder)
mCheckableView = holder.findViewById(Resources.getSystem().getIdentifier("switch_widget", "id", "android"))
@@ -70,10 +78,10 @@ class ThemeColorSwitchPreference : SwitchPreference, ThemeColorMutable, LongClic
private fun applyColor() {
if (mCheckableView is Switch) {
ThemeColorHelper.setColorPrimary(mCheckableView as Switch?, mColor)
ThemeColorHelper.setColorPrimary(mCheckableView as Switch, mColor, true)
}
if (mCheckableView is SwitchCompat) {
ThemeColorHelper.setColorPrimary(mCheckableView as SwitchCompat?, mColor)
ThemeColorHelper.setColorPrimary(mCheckableView as SwitchCompat, mColor, true)
}
}
@@ -81,6 +89,7 @@ class ThemeColorSwitchPreference : SwitchPreference, ThemeColorMutable, LongClic
return context.obtainStyledAttributes(set, styleableRes, defStyleAttr, defStyleRes)
}
@SuppressLint("RestrictedApi")
private fun getAttrString(a: TypedArray, index: Int): String? = TypedArrayUtils.getString(a, index, index)
}

View File

@@ -39,8 +39,9 @@ public class ThemeColorFloatingActionButton extends FloatingActionButton impleme
@Override
public void setThemeColor(ThemeColor color) {
int colorAccent = color.colorAccent;
setBackgroundTintList(ColorStateList.valueOf(colorAccent));
var tintColorRes = ColorUtils.isLuminanceLight(colorAccent)
int colorForContrast = ColorUtils.adjustColorForContrast(getContext().getColor(R.color.window_background), colorAccent, 1.15);
setBackgroundTintList(ColorStateList.valueOf(colorForContrast));
var tintColorRes = ColorUtils.isLuminanceLight(colorForContrast)
? R.color.fab_tint_dark
: R.color.fab_tint_light;
var tintColor = getResources().getColor(tintColorRes, null);

View File

@@ -72,8 +72,8 @@ abstract class BaseActivity : AppCompatActivity() {
initThemeColors()
if (handleStatusBarThemeColorAutomatically && !BuildConfig.isInrt) {
ThemeColorManager.addActivityStatusBar(this)
setUpStatusBarIconLightByThemeColor()
}
setUpStatusBarIconLightByThemeColor()
}
override fun onResume() {

View File

@@ -44,6 +44,7 @@ import org.autojs.autojs.model.script.Scripts
import org.autojs.autojs.pio.PFile
import org.autojs.autojs.pio.PFiles
import org.autojs.autojs.project.ProjectConfig
import org.autojs.autojs.theme.ThemeColorManagerCompat
import org.autojs.autojs.theme.widget.ThemeColorSwipeRefreshLayout
import org.autojs.autojs.ui.common.ScriptLoopDialog
import org.autojs.autojs.ui.common.ScriptOperations
@@ -54,6 +55,7 @@ import org.autojs.autojs.ui.project.BuildActivity
import org.autojs.autojs.ui.viewmodel.ExplorerItemManager
import org.autojs.autojs.ui.widget.BindableViewHolder
import org.autojs.autojs.ui.widget.FirstCharView
import org.autojs.autojs.util.ColorUtils
import org.autojs.autojs.util.EnvironmentUtils.externalStoragePath
import org.autojs.autojs.util.FileUtils
import org.autojs.autojs.util.IntentUtils
@@ -715,14 +717,19 @@ open class ExplorerView : ThemeColorSwipeRefreshLayout, SwipeRefreshLayout.OnRef
private fun setFirstChar(item: ExplorerItem) {
mFirstChar.setIcon(ExplorerViewHelper.getIcon(item))
when (item.type) {
FileUtils.TYPE.JAVASCRIPT, FileUtils.TYPE.AUTO -> mFirstChar
.setIconTextColorByThemeColorLuminance()
.setStrokeThemeColor()
.setFillThemeColor()
else -> mFirstChar
.setIconTextColorDayNight()
.setStrokeColorDayNight()
.setFillTransparent()
FileUtils.TYPE.JAVASCRIPT, FileUtils.TYPE.AUTO -> {
val themeColorForContrast = ColorUtils.adjustColorForContrast(context.getColor(R.color.item_background_dark), ThemeColorManagerCompat.getColorPrimary(), 1.15)
mFirstChar
.setIconTextColorByThemeColorLuminance()
.setStrokeColor(themeColorForContrast)
.setFillColor(themeColorForContrast)
}
else -> {
mFirstChar
.setIconTextColorDayNight()
.setStrokeColorDayNight()
.setFillTransparent()
}
}
}

View File

@@ -1,13 +1,20 @@
package org.autojs.autojs.ui.filechooser;
import android.content.Context;
import android.content.res.ColorStateList;
import android.view.View;
import androidx.annotation.NonNull;
import org.autojs.autojs.core.ui.widget.JsCheckBox;
import org.autojs.autojs.model.explorer.ExplorerItem;
import org.autojs.autojs.pio.PFile;
import org.autojs.autojs.pio.PFiles;
import org.autojs.autojs.theme.ThemeColorManagerCompat;
import org.autojs.autojs.ui.explorer.ExplorerViewHelper;
import org.autojs.autojs.ui.widget.BindableViewHolder;
import org.autojs.autojs.util.ColorUtils;
import org.autojs.autojs6.R;
import org.autojs.autojs6.databinding.ExplorerFirstCharIconBinding;
import org.autojs.autojs6.databinding.FileChooseListFileBinding;
@@ -33,22 +40,39 @@ class ExplorerItemViewHolder extends BindableViewHolder<Object> {
public void bind(Object item, int position) {
if (!(item instanceof ExplorerItem explorerItem)) return;
mExplorerItem = explorerItem;
listFileBinding.name.setText(ExplorerViewHelper.getDisplayName(fileChooseListView.getContext(), explorerItem));
listFileBinding.item.setOnClickListener(view -> listFileBinding.checkbox.toggle());
listFileBinding.checkbox.setOnCheckedChangeListener((buttonView, isChecked) -> {
if (listFileBinding.checkbox.isChecked()) {
Context context = fileChooseListView.getContext();
JsCheckBox checkbox = listFileBinding.checkbox;
int itemBackgroundDarkColor = context.getColor(R.color.item_background_dark);
int themePrimaryColor = ThemeColorManagerCompat.getColorPrimary();
int checkBoxCheckedThemeColorForContrast = ColorUtils.adjustColorForContrast(itemBackgroundDarkColor, themePrimaryColor, 1.9);
int checkBoxUncheckedCheckedThemeColorForContrast = ColorUtils.adjustColorForContrast(itemBackgroundDarkColor, themePrimaryColor, 1.4);
int itemIconThemeColorForContrast = ColorUtils.adjustColorForContrast(itemBackgroundDarkColor, themePrimaryColor, 1.15);
checkbox.setButtonTintList(new ColorStateList(
new int[][]{new int[]{android.R.attr.state_checked}, new int[]{}},
new int[]{checkBoxCheckedThemeColorForContrast, checkBoxUncheckedCheckedThemeColorForContrast}
));
listFileBinding.name.setText(ExplorerViewHelper.getDisplayName(context, explorerItem));
listFileBinding.item.setOnClickListener(view -> checkbox.toggle());
checkbox.setOnCheckedChangeListener((buttonView, isChecked) -> {
if (checkbox.isChecked()) {
fileChooseListView.check(mExplorerItem.toScriptFile(), getAdapterPosition());
} else {
fileChooseListView.getSelectedFiles().remove(mExplorerItem.toScriptFile());
}
});
listFileBinding.scriptFileSize.setText(PFiles.getHumanReadableSize(explorerItem.getSize()));
listFileBinding.scriptFileDate.setText(PFile.getFullDateString(explorerItem.lastModified()));
switch (explorerItem.getType()) {
case JAVASCRIPT, AUTO -> firstCharIconBinding.firstChar
.setIconTextColorByThemeColorLuminance()
.setStrokeThemeColor()
.setFillColorDayNight();
.setStrokeColor(itemIconThemeColorForContrast)
.setFillColor(itemIconThemeColorForContrast);
default -> firstCharIconBinding.firstChar
.setIconTextColorDayNight()
.setStrokeColorDayNight()
@@ -57,7 +81,7 @@ class ExplorerItemViewHolder extends BindableViewHolder<Object> {
firstCharIconBinding.firstChar.setIcon(ExplorerViewHelper.getIcon(explorerItem));
listFileBinding.checkbox.setChecked(fileChooseListView.getSelectedFiles().containsKey(mExplorerItem.toScriptFile()), false);
checkbox.setChecked(fileChooseListView.getSelectedFiles().containsKey(mExplorerItem.toScriptFile()), false);
}
}

View File

@@ -25,9 +25,12 @@ import org.autojs.autojs.execution.ScriptExecutionListener;
import org.autojs.autojs.execution.SimpleScriptExecutionListener;
import org.autojs.autojs.groundwork.WrapContentLinearLayoutManager;
import org.autojs.autojs.script.AutoFileSource;
import org.autojs.autojs.script.JavaScriptFileSource;
import org.autojs.autojs.storage.database.ModelChange;
import org.autojs.autojs.theme.ThemeColorManagerCompat;
import org.autojs.autojs.timing.TimedTaskManager;
import org.autojs.autojs.ui.timing.TimedTaskSettingActivity;
import org.autojs.autojs.util.ColorUtils;
import org.autojs.autojs.util.FileUtils;
import org.autojs.autojs6.R;
import org.autojs.autojs6.databinding.ExplorerFirstCharIconBinding;
@@ -232,10 +235,19 @@ public class TaskListRecyclerView extends ThemeColorRecyclerView {
public void bind(Task task) {
mTask = task;
int itemIconThemeColorForContrast = ColorUtils.adjustColorForContrast(getContext().getColor(R.color.window_background), ThemeColorManagerCompat.getColorPrimary(), 2.3);
FileUtils.TYPE.Icon icon;
if (JavaScriptFileSource.ENGINE.equals(mTask.getEngineName())) {
icon = FileUtils.TYPE.JAVASCRIPT.icon;
} else if (AutoFileSource.ENGINE.equals(mTask.getEngineName())) {
icon = FileUtils.TYPE.AUTO.icon;
} else {
icon = FileUtils.TYPE.UNKNOWN.icon;
}
firstCharIconBinding.firstChar
.setIcon(AutoFileSource.ENGINE.equals(mTask.getEngineName()) ? FileUtils.TYPE.AUTO.icon : FileUtils.TYPE.JAVASCRIPT.icon)
.setIconTextThemeColor()
.setStrokeThemeColor()
.setIcon(icon)
.setIconTextColor(itemIconThemeColorForContrast)
.setStrokeColor(itemIconThemeColorForContrast)
.setFillTransparent();
itemBinding.name.setText(task.getName());
itemBinding.taskListFilePath.setText(task.getDesc());

View File

@@ -11,6 +11,7 @@ import androidx.annotation.ColorInt
import androidx.annotation.ColorRes
import org.autojs.autojs.theme.ThemeColorManager
import org.autojs.autojs.theme.ThemeColorManagerCompat
import org.autojs.autojs.util.ColorUtils
import org.autojs.autojs.util.FileUtils
import org.autojs.autojs6.R
import kotlin.math.roundToInt
@@ -50,8 +51,6 @@ class FirstCharView : TextView {
return privateBackground!!
}
private fun convertColorResToInt(@ColorRes colorRes: Int) = context.getColor(colorRes)
fun setIconText(text: CharSequence?) = also { setText(text) }
fun setIcon(icon: FileUtils.TYPE.Icon): FirstCharView {
@@ -70,7 +69,7 @@ class FirstCharView : TextView {
fun setIconTextColor(@ColorInt color: Int) = also { setTextColor(color) }
fun setIconTextColorRes(@ColorRes colorRes: Int) = also { setTextColor(convertColorResToInt(colorRes)) }
fun setIconTextColorRes(@ColorRes colorRes: Int) = also { setTextColor(context.getColor(colorRes)) }
fun setIconTextColorByThemeColorLuminance() = also { setIconTextColorRes(ThemeColorManager.getDayOrNightColorResByLuminance()) }
@@ -82,7 +81,7 @@ class FirstCharView : TextView {
fun setStrokeColor(@ColorInt color: Int) = also { background().setStroke(strokeWidth, color) }
fun setStrokeColorRes(@ColorRes colorRes: Int): FirstCharView = setStrokeColor(convertColorResToInt(colorRes))
fun setStrokeColorRes(@ColorRes colorRes: Int): FirstCharView = setStrokeColor(context.getColor(colorRes))
fun setStrokeThemeColor() = setStrokeColor(ThemeColorManagerCompat.getColorPrimary())
@@ -92,7 +91,7 @@ class FirstCharView : TextView {
fun setFillColor(@ColorInt color: Int) = also { background().setColor(color) }
fun setFillColorRes(@ColorRes colorRes: Int) = setFillColor(convertColorResToInt(colorRes))
fun setFillColorRes(@ColorRes colorRes: Int) = setFillColor(context.getColor(colorRes))
fun setFillThemeColor() = setFillColor(ThemeColorManagerCompat.getColorPrimary())

View File

@@ -55,7 +55,7 @@ public class PrefSwitch extends JsSwitch implements SharedPreferences.OnSharedPr
@Override
public void setThemeColor(ThemeColor color) {
ThemeColorHelper.setColorPrimary(this, color.colorPrimary);
ThemeColorHelper.setColorPrimary(this, color.colorPrimary, true);
}
private void readInitialState() {

View File

@@ -632,4 +632,105 @@ object ColorUtils {
@JvmStatic
fun equals(c1: String?, c2: String?) = equals(parseColor(c1), parseColor(c2))
/**
* Adjust the reference color to achieve better contrast on the background color, while remaining as close as possible to the reference color.
*
* zh-CN: 调整参考色, 使其在背景色上具有更好的对比度, 同时尽量接近参考色.
*
* @param background The background color. (zh-CN: 背景颜色.)
* @param reference The reference color. (zh-CN: 参考颜色.)
* @param minimumContrast The minimum contrast ratio, typically between 1.0 and 21.0 (1 being the lowest contrast, 21 being the highest contrast).
* (zh-CN: 最小对比度, 通常值为 1.0 - 21.0 (1 为最低对比度, 21 为最高对比度).)
* - 4.5: Minimum contrast ratio for normal use cases (Standard AA)
* - 7.0: High contrast ratio for better readability (Standard AAA)
* - < 4.5 (e.g. 3.0): Lower contrast ratio (< 4.5, e.g., 3.0) is acceptable for decorative or less significant elements
* - zh-CN:
* - 4.5: 普通场景的最低对比度标准 (AA 标准)
* - 7.0: 高对比度场景标准 (AAA 标准)
* - < 4.5 (如 3.0): 装饰性或次要元素可用的较低标准
* @return The adjusted color. (zh-CN: 调整后的颜色.)
*/
@JvmStatic
fun adjustColorForContrast(
@ColorInt background: Int,
@ColorInt reference: Int,
minimumContrast: Double = 4.5,
): Int {
// 如果已经满足对比度要求, 直接返回参考色
if (calculateContrast(background, reference) >= minimumContrast) {
return reference
}
// 转为 HSL 以便调整亮度
val hsl = FloatArray(3)
ColorUtils.colorToHSL(reference, hsl)
// 提高亮度, 尝试达到目标对比度
val lighterColor = findAdjustableHSLColor(hsl, background, minimumContrast, lighten = true)
if (lighterColor != null) {
return lighterColor
}
// 降低亮度, 尝试达到目标对比度
val darkerColor = findAdjustableHSLColor(hsl, background, minimumContrast, lighten = false)
if (darkerColor != null) {
return darkerColor
}
// 如果两种情况下都无法满足, 返回原始颜色 (极端情况)
return reference
}
/**
* Calculate the contrast ratio between two colors using the W3C WCAG formula.
*
* zh-CN: 计算两种颜色的对比度, 使用 W3C WCAG 公式.
*/
private fun calculateContrast(color1: Int, color2: Int): Double {
return ColorUtils.calculateContrast(color1, color2)
}
/**
* Adjust the lightness of a color in HSL format to meet the minimum contrast ratio.
*
* zh-CN: 调整颜色的亮度, 尝试找到满足最小对比度的颜色.
*
* @param hsl The color value in HSL format, including Hue, Saturation, and Lightness.
* (zh-CN: HSL 格式颜色值, 包括色相 (Hue), 饱和度 (Saturation), 亮度 (Lightness).)
* @param background The background color. (zh-CN: 背景颜色.)
* @param minimumContrast minimum contrast ratio. (zh-CN: 最小对比度值.)
* @param lighten Whether to increase brightness (true) or decrease brightness (false).
* (zh-CN: 是否提高亮度 (true 为提高亮度, false 为降低亮度).)
* @return The adjusted color, or null if no suitable color can be found.
* (zh-CN: 调整后的颜色, 若无法找到满足条件的颜色, 返回 null.)
*/
@ColorInt
private fun findAdjustableHSLColor(
hsl: FloatArray,
@ColorInt background: Int,
minimumContrast: Double,
lighten: Boolean,
): Int? {
val step = 0.02f // 每次调整亮度的步长
val maxSteps = 50 // 最大调整次数 (防止死循环)
val adjustedHSL = hsl.copyOf()
for (i in 0 until maxSteps) {
// 根据 lighten 参数, 增加或减少亮度
adjustedHSL[2] = (adjustedHSL[2] + (if (lighten) step else -step))
.coerceIn(0f, 1f) // 防止超出合法范围 [0, 1]
// 将调整后的 HSL 转回 RGB
val adjustedColor = ColorUtils.HSLToColor(adjustedHSL)
// 重新计算对比度, 如果满足条件即可返回
if (calculateContrast(background, adjustedColor) >= minimumContrast) {
return adjustedColor
}
}
// 无法找到合适的亮度调整
return null
}
}

View File

@@ -17,13 +17,13 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/item_background_dark"
android:baselineAligned="false"
android:clickable="true"
android:focusable="true"
android:foreground="?selectableItemBackground"
android:orientation="horizontal"
android:paddingVertical="9dp"
android:paddingStart="8dp"
android:baselineAligned="false"
android:focusable="true">
android:paddingStart="8dp">
<include
layout="@layout/explorer_first_char_icon"

View File

@@ -1,77 +1,110 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<androidx.appcompat.widget.LinearLayoutCompat
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="?android:divider" />
android:layout_width="match_parent"
android:layout_height="1px"
android:background="?android:divider" />
<LinearLayout
android:id="@+id/item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:foreground="?selectableItemBackground"
android:orientation="horizontal"
android:padding="8dp">
android:id="@+id/item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/item_background_dark"
android:clickable="true"
android:focusable="true"
android:foreground="?selectableItemBackground"
android:orientation="horizontal"
android:paddingVertical="9dp"
android:paddingStart="8dp">
<org.autojs.autojs.core.ui.widget.JsCheckBox
android:id="@+id/checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:gravity="center" />
android:id="@+id/checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:gravity="center" />
<include
layout="@layout/explorer_first_char_icon"
android:layout_gravity="center_vertical"
android:layout_height="wrap_content"
android:layout_width="wrap_content"/>
layout="@layout/explorer_first_char_icon"
android:layout_gravity="center_vertical"
android:layout_height="wrap_content"
android:layout_width="wrap_content" />
<LinearLayout
android:layout_width="0dp"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="10dp"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="10dp"
android:layout_weight="1"
android:orientation="vertical">
android:ellipsize="end"
android:gravity="center_vertical"
android:maxLines="1"
android:textColor="?android:textColorPrimary"
android:textSize="14sp"
tools:text="@string/text_sample_name" />
<TextView
android:id="@+id/name"
android:layout_width="match_parent"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp">
<TextView
android:id="@+id/script_file_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:ellipsize="end"
android:gravity="center_vertical"
android:maxLines="1"
android:textColor="?android:textColorPrimary"
android:textSize="14sp"
tools:text="@string/text_sample_name" />
android:textColor="?android:textColorSecondary"
android:textSize="11sp"
tools:text="@string/text_sample_file_date" />
<TextView
android:id="@+id/script_file_size"
android:layout_width="match_parent"
<TextView
android:paddingHorizontal="3sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginTop="4dp"
android:ellipsize="middle"
android:gravity="center_vertical"
android:layout_gravity="center"
android:gravity="center"
android:ellipsize="end"
android:maxLines="1"
android:textColor="?android:textColorPrimary"
android:textColor="?android:textColorSecondary"
android:textSize="11sp" />
<TextView
android:id="@+id/script_file_size"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:ellipsize="end"
android:maxLines="1"
android:textColor="?android:textColorSecondary"
android:textSize="11sp"
tools:text="@string/text_sample_file_size" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="#EDEEEF" />
android:layout_width="match_parent"
android:layout_height="1px"
android:background="#EDEEEF" />
</androidx.appcompat.widget.LinearLayoutCompat>