6.7.0 - Alpha23 - Fine tuning
This commit is contained in:
@@ -167,13 +167,14 @@
|
||||
|
||||
<uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
|
||||
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
|
||||
|
||||
<uses-permission android:name="android.permission.READ_CALENDAR" />
|
||||
<uses-permission android:name="android.permission.WRITE_CALENDAR" />
|
||||
|
||||
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
|
||||
|
||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
|
||||
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
|
||||
|
||||
@@ -3,34 +3,21 @@ package androidx.recyclerview.widget;
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.EdgeEffect;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.widget.EdgeEffectCompat;
|
||||
import org.autojs.autojs.theme.ThemeColor;
|
||||
import org.autojs.autojs.theme.ThemeColorManager;
|
||||
import org.autojs.autojs.theme.ThemeColorMutable;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
* Created by Stardust on Aug 14, 2016.
|
||||
* Modified by SuperMonster003 as of Dec 1, 2021.
|
||||
* Modified by JetBrains AI Assistant (GPT-5.3-Codex (xhigh)) as of Mar 6, 2026.
|
||||
* Modified by SuperMonster003 as of Mar 6, 2026.
|
||||
*/
|
||||
public class ThemeColorRecyclerView extends RecyclerView implements ThemeColorMutable {
|
||||
|
||||
private int mColorPrimary;
|
||||
|
||||
private Field mLeftGlowField;
|
||||
private Field mTopGlowField;
|
||||
private Field mRightGlowField;
|
||||
private Field mBottomGlowField;
|
||||
|
||||
private Field mEdgeEffectField;
|
||||
|
||||
private boolean hasAppliedThemeColorLeft;
|
||||
private boolean hasAppliedThemeColorTop;
|
||||
private boolean hasAppliedThemeColorRight;
|
||||
private boolean hasAppliedThemeColorBottom;
|
||||
|
||||
public ThemeColorRecyclerView(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
@@ -46,65 +33,17 @@ public class ThemeColorRecyclerView extends RecyclerView implements ThemeColorMu
|
||||
init();
|
||||
}
|
||||
|
||||
private boolean applyThemeColor(Field edgeEffectCompatField) {
|
||||
try {
|
||||
EdgeEffectCompat edgeEffectCompat = (EdgeEffectCompat) edgeEffectCompatField.get(this);
|
||||
if (edgeEffectCompat != null) {
|
||||
return setEdgeEffectColor(edgeEffectCompat, mColorPrimary);
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
/* Ignored. */
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void init() {
|
||||
try {
|
||||
mEdgeEffectField = EdgeEffectCompat.class.getDeclaredField("mEdgeEffect");
|
||||
mEdgeEffectField.setAccessible(true);
|
||||
mLeftGlowField = RecyclerView.class.getDeclaredField("mLeftGlow");
|
||||
mLeftGlowField.setAccessible(true);
|
||||
mRightGlowField = RecyclerView.class.getDeclaredField("mRightGlow");
|
||||
mRightGlowField.setAccessible(true);
|
||||
mTopGlowField = RecyclerView.class.getDeclaredField("mTopGlow");
|
||||
mTopGlowField.setAccessible(true);
|
||||
mBottomGlowField = RecyclerView.class.getDeclaredField("mBottomGlow");
|
||||
mBottomGlowField.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// android:fadeScrollbars="true"
|
||||
// setScrollbarFadingEnabled(true);
|
||||
|
||||
// android:scrollbarDefaultDelayBeforeFade="600"
|
||||
// setScrollBarDefaultDelayBeforeFade(600);
|
||||
|
||||
// android:scrollbarFadeDuration="500"
|
||||
// setScrollBarFadeDuration(500);
|
||||
|
||||
// android:scrollbars="vertical"
|
||||
// setVerticalScrollBarEnabled(true);
|
||||
|
||||
// To ensure scrollbar fading works properly.
|
||||
// setFadingEdgeLength(0);
|
||||
|
||||
ThemeColorManager.add(this);
|
||||
}
|
||||
|
||||
private boolean setEdgeEffectColor(EdgeEffectCompat compat, int color) {
|
||||
if (compat == null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
EdgeEffect edgeEffect = (EdgeEffect) mEdgeEffectField.get(compat);
|
||||
if (edgeEffect != null) {
|
||||
edgeEffect.setColor(color);
|
||||
setEdgeEffectFactory(new EdgeEffectFactory() {
|
||||
@NonNull
|
||||
@Override
|
||||
protected EdgeEffect createEdgeEffect(@NonNull RecyclerView view, int direction) {
|
||||
EdgeEffect edgeEffect = new EdgeEffect(view.getContext());
|
||||
edgeEffect.setColor(mColorPrimary);
|
||||
return edgeEffect;
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
/* Ignored. */
|
||||
}
|
||||
return true;
|
||||
});
|
||||
ThemeColorManager.add(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -113,36 +52,7 @@ public class ThemeColorRecyclerView extends RecyclerView implements ThemeColorMu
|
||||
return;
|
||||
}
|
||||
mColorPrimary = color.colorPrimary;
|
||||
invalidateGlows();
|
||||
}
|
||||
|
||||
void invalidateGlows() {
|
||||
super.invalidateGlows();
|
||||
hasAppliedThemeColorLeft = false;
|
||||
hasAppliedThemeColorTop = false;
|
||||
hasAppliedThemeColorRight = false;
|
||||
hasAppliedThemeColorBottom = false;
|
||||
}
|
||||
|
||||
void ensureLeftGlow() {
|
||||
super.ensureLeftGlow();
|
||||
hasAppliedThemeColorLeft = hasAppliedThemeColorLeft || applyThemeColor(mLeftGlowField);
|
||||
}
|
||||
|
||||
void ensureTopGlow() {
|
||||
super.ensureTopGlow();
|
||||
hasAppliedThemeColorTop = hasAppliedThemeColorTop || applyThemeColor(mTopGlowField);
|
||||
|
||||
}
|
||||
|
||||
void ensureRightGlow() {
|
||||
super.ensureLeftGlow();
|
||||
hasAppliedThemeColorRight = hasAppliedThemeColorRight || applyThemeColor(mRightGlowField);
|
||||
}
|
||||
|
||||
void ensureBottomGlow() {
|
||||
super.ensureBottomGlow();
|
||||
hasAppliedThemeColorBottom = hasAppliedThemeColorBottom || applyThemeColor(mBottomGlowField);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -44,6 +44,6 @@ class ScriptPromiseAdapter {
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val UNSET = Object()
|
||||
private val UNSET = Any()
|
||||
}
|
||||
}
|
||||
@@ -156,7 +156,7 @@ open class RhinoJavaScriptEngine(private val mAndroidContext: android.content.Co
|
||||
|
||||
override fun wrap(cx: Context, scope: Scriptable, obj: Any?, staticType: Class<*>?): Any? {
|
||||
return when {
|
||||
obj is String -> runtime.bridges.toString(obj.toString())
|
||||
obj is String -> runtime.bridges.toString(obj)
|
||||
staticType == UiObjectCollection::class.java -> runtime.bridges.asArray(obj)
|
||||
else -> super.wrap(cx, scope, obj, staticType)
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ class SearchUpTargetAction(action: Int, filter: FilterAction.Filter) : SearchTar
|
||||
|
||||
companion object {
|
||||
|
||||
private val TAG = SearchUpTargetAction::class.java!!.getSimpleName()
|
||||
private val TAG = SearchUpTargetAction::class.java.getSimpleName()
|
||||
private val LOOP_MAX = 20
|
||||
}
|
||||
}
|
||||
|
||||
@@ -863,13 +863,17 @@ open class UiSelector : UiObjectActions, StringReadable {
|
||||
|
||||
internal fun pick(scriptRuntime: ScriptRuntime) = Detector(compass, object : Result(resultType) {
|
||||
|
||||
override fun byOne() = selector?.let { sel ->
|
||||
root?.let { return sel.findOneOf(it) } ?: sel.findOnce()
|
||||
override fun byOne(): UiObject? {
|
||||
return selector?.let { sel ->
|
||||
root?.let { return sel.findOneOf(it) } ?: sel.findOnce()
|
||||
}
|
||||
}
|
||||
|
||||
override fun byAll() = selector?.let { sel ->
|
||||
root?.let { return sel.findOf(it) } ?: sel.find()
|
||||
} ?: EMPTY
|
||||
override fun byAll(): UiObjectCollection {
|
||||
return selector?.let { sel ->
|
||||
root?.let { return sel.findOf(it) } ?: sel.find()
|
||||
} ?: EMPTY
|
||||
}
|
||||
|
||||
}, callback, selector).detect(scriptRuntime)
|
||||
|
||||
|
||||
@@ -41,15 +41,17 @@ class StartForResultActivity : Activity() {
|
||||
}
|
||||
}
|
||||
if (extras == null) {
|
||||
finish().also { return }
|
||||
finish()
|
||||
return
|
||||
}
|
||||
val callback = extras!!.map["callback"]
|
||||
val callback = extras.map["callback"]
|
||||
if (callback is Callback) {
|
||||
mCallback = callback
|
||||
}
|
||||
if (callback == null) {
|
||||
mCallback = null
|
||||
finish().also { return }
|
||||
finish()
|
||||
return
|
||||
}
|
||||
mCallback!!.onActivityCreate(this)
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ enum class Language(@JvmField val languageTag: String, @KeyRes private val keyRe
|
||||
;
|
||||
|
||||
val locale: Locale = when (languageTag.isBlank()) {
|
||||
true -> LocaleUtils.getSystemLocale()
|
||||
true -> LocaleUtils.getPrimarySystemLocale()
|
||||
else -> Locale.forLanguageTag(languageTag)
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ enum class Language(@JvmField val languageTag: String, @KeyRes private val keyRe
|
||||
return languageTag
|
||||
}
|
||||
|
||||
val systemTag = LocaleUtils.getSystemLocale().toLanguageTag()
|
||||
val systemTag = LocaleUtils.getPrimarySystemLocale().toLanguageTag()
|
||||
val availableTags = values().map { it.languageTag }
|
||||
|
||||
if (systemTag in availableTags) {
|
||||
|
||||
@@ -7,10 +7,6 @@ import android.util.Log
|
||||
import android.view.View
|
||||
import org.autojs.autojs.core.ui.ViewExtras
|
||||
import org.autojs.autojs.engine.module.AssetAndUrlModuleSourceProvider
|
||||
import org.autojs.autojs.rhino.extension.AnyExtensions.isJsNullish
|
||||
import org.autojs.autojs.rhino.extension.AnyExtensions.jsBrief
|
||||
import org.autojs.autojs.rhino.extension.ScriptableExtensions.defineProp
|
||||
import org.autojs.autojs.rhino.extension.ScriptableExtensions.prop
|
||||
import org.autojs.autojs.pio.PFiles
|
||||
import org.autojs.autojs.pio.UncheckedIOException
|
||||
import org.autojs.autojs.project.ScriptConfig
|
||||
@@ -18,6 +14,10 @@ import org.autojs.autojs.rhino.AndroidContextFactory
|
||||
import org.autojs.autojs.rhino.AutoJsContext
|
||||
import org.autojs.autojs.rhino.RhinoAndroidHelper
|
||||
import org.autojs.autojs.rhino.TopLevelScope
|
||||
import org.autojs.autojs.rhino.extension.AnyExtensions.isJsNullish
|
||||
import org.autojs.autojs.rhino.extension.AnyExtensions.jsBrief
|
||||
import org.autojs.autojs.rhino.extension.ScriptableExtensions.defineProp
|
||||
import org.autojs.autojs.rhino.extension.ScriptableExtensions.prop
|
||||
import org.autojs.autojs.runtime.ScriptRuntime
|
||||
import org.autojs.autojs.runtime.api.augment.proxy.PaintProxyObject
|
||||
import org.autojs.autojs.script.JavaScriptSource
|
||||
@@ -42,7 +42,7 @@ import java.io.IOException
|
||||
import java.io.InputStreamReader
|
||||
import java.io.Reader
|
||||
import java.net.URI
|
||||
import java.util.*
|
||||
import java.util.Locale
|
||||
|
||||
/**
|
||||
* Created by Stardust on Apr 2, 2017.
|
||||
@@ -215,9 +215,9 @@ open class RhinoJavaScriptEngine(private val androidContext: android.content.Con
|
||||
private inner class WrapFactory : AndroidContextFactory.WrapFactory() {
|
||||
|
||||
override fun wrapAsJavaObject(cx: Context?, scope: Scriptable, javaObject: Any?, staticType: TypeInfo): Scriptable? {
|
||||
return when (javaObject) {
|
||||
is View -> ViewExtras.getNativeView(scope, /* view = */ javaObject, staticType.asClass(), runtime)
|
||||
is Paint if Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q -> {
|
||||
return when {
|
||||
javaObject is View -> ViewExtras.getNativeView(scope, /* view = */ javaObject, staticType.asClass(), runtime)
|
||||
javaObject is Paint && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q -> {
|
||||
// Use composition-based proxy to preserve Paint identity and intercept setColor only.
|
||||
// zh-CN: 使用组合式代理以保持 Paint 身份一致性, 且仅拦截 setColor.
|
||||
val base = super.wrapAsJavaObject(cx, scope, javaObject, staticType) ?: return null
|
||||
@@ -226,11 +226,12 @@ open class RhinoJavaScriptEngine(private val androidContext: android.content.Con
|
||||
else -> super.wrapAsJavaObject(cx, scope, javaObject, staticType)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val TAG = "RhinoJavaScriptEngine"
|
||||
|
||||
const val SOURCE_FILE_INIT = "init.js"
|
||||
const val SOURCE_NAME_INIT = "<init>"
|
||||
const val MODULES_ROOT_PATH = "modules"
|
||||
@@ -238,9 +239,5 @@ open class RhinoJavaScriptEngine(private val androidContext: android.content.Con
|
||||
|
||||
@JvmField
|
||||
val JS_BEAUTIFY_FILE = PFiles.join(JS_BEAUTIFY_PATH, "beautify.js")
|
||||
|
||||
private val TAG = RhinoJavaScriptEngine::class.java.simpleName
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ object ScriptIntents {
|
||||
JavaScriptFileSource(path).let { fss: JavaScriptFileSource ->
|
||||
source = script?.let { SequenceScriptSource(fss.name, StringScriptSource(it), fss) } ?: fss
|
||||
}
|
||||
File(path!!).parent?.let { config.workingDirectory = it }
|
||||
File(path).parent?.let { config.workingDirectory = it }
|
||||
}
|
||||
}
|
||||
source?.let { AutoJs.instance.scriptEngineService.execute(it, config) }
|
||||
|
||||
@@ -2,8 +2,10 @@ package org.autojs.autojs.inrt
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.EdgeEffect
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import org.autojs.autojs.runtime.api.Permissions
|
||||
import org.autojs.autojs.theme.preference.Syncable
|
||||
import org.autojs.autojs.util.ViewUtils.excludePaddingClippableViewFromBottomNavigationBar
|
||||
@@ -67,11 +69,17 @@ class SettingsActivity : AppCompatActivity() {
|
||||
setDivider(null)
|
||||
setDividerHeight(0)
|
||||
|
||||
listView.edgeEffectFactory = object : RecyclerView.EdgeEffectFactory() {
|
||||
override fun createEdgeEffect(recyclerView: RecyclerView, direction: Int): EdgeEffect {
|
||||
return EdgeEffect(recyclerView.context).apply {
|
||||
color = recyclerView.context.getColor(R.color.md_blue_gray_500)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
listView.isHorizontalScrollBarEnabled = false
|
||||
listView.isVerticalScrollBarEnabled = false
|
||||
listView.excludePaddingClippableViewFromBottomNavigationBar()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -61,12 +61,13 @@ class AppUtils(context: Context, @get:ScriptInterface val fileProviderAuthority:
|
||||
* @param o < alias | packageName >
|
||||
*/
|
||||
@ScriptInterface
|
||||
fun launchPackage(o: String?) = runCatching {
|
||||
o ?: return false
|
||||
val nicePackageName = getAppByAlias(alias = o)?.packageName ?: (/* packageName = */ o)
|
||||
val intent = mPackageManager.getLaunchIntentForPackage(nicePackageName) ?: return false
|
||||
intent.start(mContext)
|
||||
}.isSuccess
|
||||
fun launchPackage(o: String?): Boolean =
|
||||
runCatching {
|
||||
o ?: return false
|
||||
val nicePackageName = getAppByAlias(alias = o)?.packageName ?: (/* packageName = */ o)
|
||||
val intent = mPackageManager.getLaunchIntentForPackage(nicePackageName) ?: return false
|
||||
intent.start(mContext)
|
||||
}.isSuccess
|
||||
|
||||
@ScriptInterface
|
||||
@Suppress("unused")
|
||||
|
||||
@@ -122,14 +122,14 @@ class Device(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
|
||||
@JvmStatic
|
||||
@RhinoFunctionBody
|
||||
fun vibrateRhinoWithRuntime(scriptRuntime: ScriptRuntime, o: Any?, p: Any?) {
|
||||
when (o) {
|
||||
is String -> {
|
||||
when {
|
||||
o is String -> {
|
||||
MorseCode.vibrateRhino(o, p)
|
||||
}
|
||||
is Number if p is Number -> {
|
||||
o is Number && p is Number -> {
|
||||
scriptRuntime.device.vibrate(/* off = */ o.toLong(), /* millis = */ p.toLong())
|
||||
}
|
||||
is NativeArray if p is Number -> {
|
||||
o is NativeArray && p is Number -> {
|
||||
val listOff = listOf(p.toLong())
|
||||
val listOthers = o.map { toVibrateTimingElement(it) }
|
||||
val timings = (listOff + listOthers).toLongArray()
|
||||
|
||||
@@ -494,15 +494,16 @@ class Dialogs(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
|
||||
}
|
||||
|
||||
private fun applyDialogProperty(builder: JsDialogBuilder, name: String, value: Any?) {
|
||||
when (val propertySetter = propertySetterMap[name]) {
|
||||
PropertyConverter.COLOR_INT -> {
|
||||
val propertySetter = propertySetterMap[name]
|
||||
when {
|
||||
propertySetter == PropertyConverter.COLOR_INT -> {
|
||||
val colorInt = Colors.toIntRhino(value)
|
||||
invokeJavaMethod(builder, name, arrayOf(colorInt))
|
||||
}
|
||||
PropertyConverter.BOOLEAN if coerceBoolean(value, false) -> {
|
||||
propertySetter == PropertyConverter.BOOLEAN && coerceBoolean(value, false) -> {
|
||||
invokeJavaMethod(builder, name, emptyArray())
|
||||
}
|
||||
is String -> when (propertySetter) {
|
||||
propertySetter is String -> when (propertySetter) {
|
||||
in propertySetterMap -> {
|
||||
applyDialogProperty(builder, propertySetter, value)
|
||||
}
|
||||
|
||||
@@ -1494,7 +1494,7 @@ class Images(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime), AsEmitt
|
||||
val similarityMethod = runCatching {
|
||||
ImageSimilarity::class.java.getDeclaredMethod(metric, OpencvMat::class.java, OpencvMat::class.java)
|
||||
}.getOrElse { throw WrappedIllegalArgumentException("Unknown similarity metric: $metric") }
|
||||
if (similarityMethod.returnType != Double::class.java && similarityMethod.returnType != java.lang.Double::class.java) {
|
||||
if (similarityMethod.returnType != Double::class.java) {
|
||||
throw WrappedIllegalArgumentException("Similarity metric ($metric) method must return Double type. Found: ${similarityMethod.returnType}")
|
||||
}
|
||||
similarityMethod.invoke(ImageSimilarity, matA, matB) as Double
|
||||
|
||||
@@ -587,9 +587,7 @@ object Inspect : Augmentable(), Invokable {
|
||||
|
||||
private fun formatProperty(ctx: Ctx, value: ScriptableObject, recurseTimes: Int?, visibleKeys: NativeObject, key: String, array: Boolean): String {
|
||||
var name: String? = null
|
||||
val desc = js_object_getOwnPropertyDescriptor(value, key) ?: newNativeObject().apply {
|
||||
put("value", this, value.prop(key))
|
||||
}
|
||||
val desc = js_object_getOwnPropertyDescriptor(value, key)
|
||||
val getter = desc.prop(PROXY_GETTER_KEY)
|
||||
val setter = desc.prop(PROXY_SETTER_KEY)
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
package org.autojs.autojs.theme.widget;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.EdgeEffect;
|
||||
import android.widget.HorizontalScrollView;
|
||||
|
||||
import org.autojs.autojs.theme.ThemeColor;
|
||||
import org.autojs.autojs.theme.ThemeColorManager;
|
||||
import org.autojs.autojs.theme.ThemeColorMutable;
|
||||
@@ -60,17 +61,23 @@ public class ThemeColorHorizontalScrollView extends HorizontalScrollView impleme
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@SuppressLint("DiscouragedPrivateApi")
|
||||
private void syncEdgeEffect() {
|
||||
try {
|
||||
Field f1 = HorizontalScrollView.class.getDeclaredField("mEdgeGlowLeft");
|
||||
f1.setAccessible(true);
|
||||
f1.set(this, mEdgeGlowLeft);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
setLeftEdgeEffectColor(mFadingEdgeColor);
|
||||
setRightEdgeEffectColor(mFadingEdgeColor);
|
||||
} else {
|
||||
try {
|
||||
Field f1 = HorizontalScrollView.class.getDeclaredField("mEdgeGlowLeft");
|
||||
f1.setAccessible(true);
|
||||
f1.set(this, mEdgeGlowLeft);
|
||||
|
||||
Field f2 = HorizontalScrollView.class.getDeclaredField("mEdgeGlowRight");
|
||||
f2.setAccessible(true);
|
||||
f2.set(this, mEdgeGlowRight);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Field f2 = HorizontalScrollView.class.getDeclaredField("mEdgeGlowRight");
|
||||
f2.setAccessible(true);
|
||||
f2.set(this, mEdgeGlowRight);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1080,7 +1080,7 @@ public class ScriptOperations {
|
||||
// zh-CN: 删除操作使用不确定进度条即可, 行为更稳定.
|
||||
MaterialDialog.Builder builder = new MaterialDialog.Builder(mContext)
|
||||
.title(titleRes)
|
||||
.content(R.string.text_deleting)
|
||||
.content(mContext.getString(R.string.text_deleting) + mContext.getString(R.string.text_half_ellipsis))
|
||||
.negativeText(R.string.dialog_button_abort)
|
||||
.negativeColorRes(R.color.dialog_button_caution)
|
||||
.onNegative((dialog, which) -> {
|
||||
|
||||
@@ -8,6 +8,7 @@ import android.content.ContextWrapper
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.database.Cursor
|
||||
import android.graphics.Color
|
||||
import android.graphics.Rect
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
@@ -1328,8 +1329,8 @@ class EditorView : LinearLayout, OnHintClickListener, ClickCallback, ToolbarFrag
|
||||
mNormalToolbar.apply {
|
||||
setOnMenuItemClickListener(this@EditorView)
|
||||
setOnMenuItemLongClickListener { id ->
|
||||
when (id) {
|
||||
R.id.run if !mReadOnly -> true.also { debug() }
|
||||
when {
|
||||
id == R.id.run && !mReadOnly -> true.also { debug() }
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
@@ -1338,8 +1339,8 @@ class EditorView : LinearLayout, OnHintClickListener, ClickCallback, ToolbarFrag
|
||||
(existing as? ToolbarFragment<*>)?.apply {
|
||||
setOnMenuItemClickListener(this@EditorView)
|
||||
setOnMenuItemLongClickListener { id ->
|
||||
when (id) {
|
||||
R.id.run if !mReadOnly -> true.also { debug() }
|
||||
when {
|
||||
id == R.id.run && !mReadOnly -> true.also { debug() }
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
@@ -1513,7 +1514,12 @@ class EditorView : LinearLayout, OnHintClickListener, ClickCallback, ToolbarFrag
|
||||
mCodeCompletionBar.setTextColor(textColor)
|
||||
mSymbolBar.setTextColor(textColor)
|
||||
mShowFunctionsButton.setColorFilter(textColor)
|
||||
ViewUtils.setNavigationBarBackgroundColor(activity, imeBarBackgroundColor)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
ViewUtils.setNavigationBarBackgroundColor(activity, imeBarBackgroundColor)
|
||||
} else {
|
||||
val adjustedImageContrastColor = ColorUtils.adjustColorForContrast(Color.WHITE, ColorUtils.applyAlpha(imeBarBackgroundColor, 1.0), 2.3)
|
||||
ViewUtils.setNavigationBarBackgroundColor(activity, adjustedImageContrastColor)
|
||||
}
|
||||
invalidate()
|
||||
}
|
||||
}
|
||||
@@ -2683,7 +2689,7 @@ class EditorView : LinearLayout, OnHintClickListener, ClickCallback, ToolbarFrag
|
||||
private const val MIN_CONFIDENCE_TO_WRITE_FILE = 90
|
||||
private val DEFAULT_CHARSET_TO_WRITE_FILE = StandardCharsets.UTF_8
|
||||
|
||||
private const val LARGE_FILE_MODE_THRESHOLD = JavaScriptHighlighter.MAX_HIGHLIGHT_CHARS
|
||||
private const val LARGE_FILE_MODE_THRESHOLD = JavaScriptHighlighter.MAX_HIGHLIGHT_CHARS
|
||||
|
||||
// Internal storage root (no external SD).
|
||||
// zh-CN: 内部存储根目录 (不访问外置 SD).
|
||||
|
||||
@@ -597,11 +597,14 @@ class CodeEditText : AppCompatEditText {
|
||||
runCatching { event.text.clear() }
|
||||
runCatching { event.contentDescription = null }
|
||||
|
||||
// Also drop selection-changed events entirely in large-text mode.
|
||||
// zh-CN: 大文本模式下直接丢弃 selection-changed 事件.
|
||||
if (event.eventType == AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED) return
|
||||
if (event.eventType == AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED) return
|
||||
if (event.eventType == AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY) return
|
||||
// Also drop selection-changed events entirely in large-text mode to avoid TransactionTooLargeException.
|
||||
// zh-CN: 大文本模式下直接丢弃 selection-changed 事件以避免 TransactionTooLargeException.
|
||||
when (event.eventType) {
|
||||
AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED -> return
|
||||
AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED -> return
|
||||
AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY -> return
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
super.sendAccessibilityEventUnchecked(event)
|
||||
}
|
||||
|
||||
@@ -178,7 +178,7 @@ class CodeEditor : HVScrollView {
|
||||
if (mProcessDialog?.isShowing == true) return@Runnable
|
||||
|
||||
mProcessDialog = MaterialDialog.Builder(context)
|
||||
.content(R.string.text_processing)
|
||||
.content(R.string.text_in_progress)
|
||||
// Text only, no progress spinner.
|
||||
// zh-CN: 仅显示文字, 不使用进度圆圈动画.
|
||||
.cancelable(false)
|
||||
|
||||
@@ -225,7 +225,7 @@ object SymbolsConfigStore {
|
||||
fun getAllDefaultNameAliases(context: Context): Set<String> {
|
||||
val appLang = Language.getPrefLanguageOrNull()
|
||||
val appKey = appLang?.languageTag ?: "null"
|
||||
val sysKey = LocaleUtils.getSystemLocale().toLanguageTag()
|
||||
val sysKey = LocaleUtils.getPrimarySystemLocale().toLanguageTag()
|
||||
val cacheKey = "app=$appKey|sys=$sysKey"
|
||||
|
||||
sDefaultAliasesCache[cacheKey]?.let { return it }
|
||||
|
||||
@@ -184,7 +184,7 @@ class NodeInfoView : RecyclerView {
|
||||
}
|
||||
}
|
||||
return when (NodeInfo::class.java.getDeclaredField(attr).type) {
|
||||
java.lang.String::class.java -> "$attr('$value')"
|
||||
String::class.java -> "$attr('$value')"
|
||||
else -> "$attr($value)"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,10 @@ package org.autojs.autojs.ui.settings
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.EdgeEffect
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import org.autojs.autojs.theme.ThemeColorManager
|
||||
import org.autojs.autojs.util.ViewUtils.excludePaddingClippableViewFromBottomNavigationBar
|
||||
import org.autojs.autojs6.R
|
||||
|
||||
@@ -14,9 +17,15 @@ class PreferencesFragment : PreferenceFragmentCompat() {
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
listView.edgeEffectFactory = object : RecyclerView.EdgeEffectFactory() {
|
||||
override fun createEdgeEffect(recyclerView: RecyclerView, direction: Int): EdgeEffect {
|
||||
return EdgeEffect(recyclerView.context).apply {
|
||||
color = ThemeColorManager.colorPrimary
|
||||
}
|
||||
}
|
||||
}
|
||||
listView.isHorizontalScrollBarEnabled = false
|
||||
listView.isVerticalScrollBarEnabled = false
|
||||
listView.excludePaddingClippableViewFromBottomNavigationBar()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,10 +384,8 @@ object ColorUtils {
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
fun applyAlpha(@ColorInt color: Int, alpha: Double): Int = when (alpha) {
|
||||
1.0 -> color
|
||||
else -> ColorUtils.setAlphaComponent(color, (alpha * 255).roundToInt())
|
||||
}
|
||||
fun applyAlpha(@ColorInt color: Int, alpha: Double): Int =
|
||||
ColorUtils.setAlphaComponent(color, (alpha * 255).roundToInt())
|
||||
|
||||
/**
|
||||
* Calculate the contrast ratio between two colors using the W3C WCAG formula.
|
||||
|
||||
@@ -3091,16 +3091,17 @@ object FileUtils {
|
||||
}.getOrElse { false }
|
||||
|
||||
@JvmStatic
|
||||
fun File.isBinDiscImageLike() = runCatching {
|
||||
this@isBinDiscImageLike.inputStream().use { inputStream ->
|
||||
val header = ByteArray(2048) // Read first sector
|
||||
if (inputStream.read(header) != header.size) return false
|
||||
fun File.isBinDiscImageLike(): Boolean =
|
||||
runCatching {
|
||||
this@isBinDiscImageLike.inputStream().use { inputStream ->
|
||||
val header = ByteArray(2048) // Read first sector
|
||||
if (inputStream.read(header) != header.size) return false
|
||||
|
||||
// Check for very basic ISO 9660 primary volume descriptor
|
||||
val pvdDescriptor = "CD001".toByteArray()
|
||||
header.sliceArray(0x800 until 0x800 + pvdDescriptor.size).contentEquals(pvdDescriptor)
|
||||
}
|
||||
}.getOrElse { false }
|
||||
// Check for very basic ISO 9660 primary volume descriptor
|
||||
val pvdDescriptor = "CD001".toByteArray()
|
||||
header.sliceArray(0x800 until 0x800 + pvdDescriptor.size).contentEquals(pvdDescriptor)
|
||||
}
|
||||
}.getOrElse { false }
|
||||
|
||||
// Determines if a CUE file describes audio tracks
|
||||
@JvmStatic
|
||||
@@ -3168,17 +3169,26 @@ object FileUtils {
|
||||
}.getOrElse { false }
|
||||
|
||||
@JvmStatic
|
||||
fun File.isSegaMDLike() = runCatching {
|
||||
this@isSegaMDLike.inputStream().use { inputStream ->
|
||||
val header = ByteArray(512) // 假设 SEGA 游戏文件有特定的头部
|
||||
if (inputStream.read(header) != header.size) return false
|
||||
fun File.isSegaMDLike(): Boolean =
|
||||
runCatching {
|
||||
this@isSegaMDLike.inputStream().use { inputStream ->
|
||||
// Assume SEGA game files have a specific header.
|
||||
// zh-CN: 假设 SEGA 游戏文件有特定的头部.
|
||||
val header = ByteArray(512)
|
||||
if (inputStream.read(header) != header.size) return false
|
||||
|
||||
// 这里你需要根据 SEGA 文件的具体特征来调整条件
|
||||
// 例如: 找到特定的标识符或者模式
|
||||
val segaIdentifier = byteArrayOf(0x53, 0x45, 0x47, 0x41) // 可能的 "SEGA" 标记
|
||||
header.sliceArray(segaIdentifier.indices).contentEquals(segaIdentifier)
|
||||
}
|
||||
}.getOrElse { false }
|
||||
// Here is the modification needed to adjust the conditions based on specific SEGA file characteristics.
|
||||
// This requires identifying specific identifiers or patterns within the header.
|
||||
// zh-CN:
|
||||
// 这里需要根据 SEGA 文件的具体特征来调整条件.
|
||||
// 例如: 找到特定的标识符或者模式.
|
||||
|
||||
// Possible "SEGA" marker.
|
||||
// zh-CN: 可能的 "SEGA" 标记.
|
||||
val segaIdentifier = byteArrayOf(0x53, 0x45, 0x47, 0x41)
|
||||
header.sliceArray(segaIdentifier.indices).contentEquals(segaIdentifier)
|
||||
}
|
||||
}.getOrElse { false }
|
||||
|
||||
// Function to check if a file is likely a macro based on scripting patterns found in samples
|
||||
@JvmStatic
|
||||
|
||||
@@ -38,18 +38,41 @@ object LocaleUtils {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
context.getSystemService(LocaleManager::class.java).applicationLocales = LocaleList.getEmptyLocaleList()
|
||||
} else {
|
||||
setLocale(context, getSystemLocale())
|
||||
setLocale(context, getPrimarySystemLocale())
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@Deprecated("Use getSystemLocaleList instead", ReplaceWith("getPrimarySystemLocale()"))
|
||||
fun getSystemLocale(): Locale = Resources.getSystem().configuration.locales[0] ?: Locale.getDefault()
|
||||
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun getSystemLocaleList(context: Context? = null): List<Locale> {
|
||||
return when {
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> {
|
||||
val localeManager = (context ?: GlobalAppContext.get()).getSystemService(LocaleManager::class.java)
|
||||
val localeList: LocaleList = localeManager.systemLocales
|
||||
List(localeList.size()) { index -> localeList[index] }
|
||||
}
|
||||
else -> {
|
||||
val localeList = Resources.getSystem().configuration.locales
|
||||
List(localeList.size()) { index -> localeList[index] }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun getPrimarySystemLocale(context: Context? = null): Locale {
|
||||
return getSystemLocaleList(context).firstOrNull() ?: Locale.getDefault()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getResources(desiredLocale: Locale?): Resources {
|
||||
return GlobalAppContext.get().let { context ->
|
||||
context.resources.configuration.let { Configuration(it) }.run {
|
||||
setLocale(desiredLocale ?: getSystemLocale())
|
||||
setLocale(desiredLocale ?: getPrimarySystemLocale())
|
||||
context.createConfigurationContext(this).resources
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,25 @@
|
||||
package org.autojs.autojs.util;
|
||||
package org.autojs.autojs.util
|
||||
|
||||
/**
|
||||
* Created by Stardust on Nov 26, 2017.
|
||||
* Transformed by SuperMonster003 on Mar 5, 2026.
|
||||
* Modified by SuperMonster003 as of Mar 5, 2026.
|
||||
*/
|
||||
public class MathUtils {
|
||||
object MathUtils {
|
||||
|
||||
public static int min(int... ints) {
|
||||
int min = ints[0];
|
||||
for (int i = 1; i < ints.length; i++) {
|
||||
min = Math.min(ints[i], min);
|
||||
}
|
||||
return min;
|
||||
}
|
||||
@JvmStatic
|
||||
fun min(vararg ints: Int): Int =
|
||||
ints.minOrNull() ?: throw NoSuchElementException("Array is empty")
|
||||
|
||||
@JvmStatic
|
||||
fun Int.floorMod(mod: Int): Int =
|
||||
Math.floorMod(this, mod)
|
||||
|
||||
@JvmStatic
|
||||
fun Long.floorMod(mod: Long): Long =
|
||||
Math.floorMod(this, mod)
|
||||
|
||||
@JvmStatic
|
||||
fun Long.floorMod(mod: Int): Int =
|
||||
Math.floorMod(this, mod)
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
<androidx.recyclerview.widget.ThemeColorRecyclerView
|
||||
android:id="@+id/apps"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
<androidx.recyclerview.widget.ThemeColorRecyclerView
|
||||
android:id="@+id/recycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
android:layout_marginTop="6dp"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
<androidx.recyclerview.widget.ThemeColorRecyclerView
|
||||
android:id="@+id/recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
@@ -105,7 +105,7 @@
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
<androidx.recyclerview.widget.ThemeColorRecyclerView
|
||||
android:id="@+id/recycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
tools:visibility="gone"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
<androidx.recyclerview.widget.ThemeColorRecyclerView
|
||||
android:id="@+id/recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
tools:visibility="gone"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
<androidx.recyclerview.widget.ThemeColorRecyclerView
|
||||
android:id="@+id/recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:background="@drawable/little_triangle" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
<androidx.recyclerview.widget.ThemeColorRecyclerView
|
||||
android:id="@+id/list"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
android:animateLayoutChanges="true"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
<androidx.recyclerview.widget.ThemeColorRecyclerView
|
||||
android:id="@+id/log_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
android:animateLayoutChanges="true"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
<androidx.recyclerview.widget.ThemeColorRecyclerView
|
||||
android:id="@+id/log_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
app:tint="@android:color/white" />
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
<androidx.recyclerview.widget.ThemeColorRecyclerView
|
||||
android:id="@+id/variables"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
<androidx.recyclerview.widget.ThemeColorRecyclerView
|
||||
android:id="@+id/result_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="400dp" />
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
<androidx.recyclerview.widget.ThemeColorRecyclerView
|
||||
android:id="@+id/list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
app:cardElevation="0.97dp"
|
||||
app:cardUseCompatPadding="true" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
<androidx.recyclerview.widget.ThemeColorRecyclerView
|
||||
android:id="@+id/explorer_item_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
android:importantForAccessibility="no"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
<androidx.recyclerview.widget.ThemeColorRecyclerView
|
||||
android:id="@+id/drawer_menu"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
android:layout_height="1dp"
|
||||
android:background="@color/divider_functions_keyboard" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
<androidx.recyclerview.widget.ThemeColorRecyclerView
|
||||
android:id="@+id/properties"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
@@ -22,7 +22,7 @@
|
||||
android:layout_height="1dp"
|
||||
android:background="@color/divider_functions_keyboard" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
<androidx.recyclerview.widget.ThemeColorRecyclerView
|
||||
android:id="@+id/module_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="50dp" />
|
||||
|
||||
Reference in New Issue
Block a user