From fb9c2f751fff58b38d1ad65fd9afbf0fe2dfc766 Mon Sep 17 00:00:00 2001 From: SuperMonster003 Date: Tue, 27 May 2025 01:23:09 +0800 Subject: [PATCH] =?UTF-8?q?6.6.3=20-=20Alpha5=20-=20=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E7=BC=96=E8=BE=91=E5=99=A8=E6=94=AF=E6=8C=81=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E8=AF=A6=E7=BB=86=E4=BF=A1=E6=81=AF=20(issue?= =?UTF-8?q?=20#395)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .changelog/lang_zh-Hans.json | 6 +- app/build.gradle.kts | 3 + .../extension/MaterialDialogExtensions.kt | 14 +- .../autojs/autojs/extension/ViewExtensions.kt | 43 ++ .../org/autojs/autojs/model/script/Scripts.kt | 3 +- .../DisplayOverOtherAppsPermission.kt | 2 +- .../theme/app/ColorInfoDialogManager.kt | 6 +- .../autojs/theme/app/ColorItemsActivity.kt | 7 +- .../theme/app/ColorLibrariesActivity.kt | 5 +- .../preference/MaterialListPreference.kt | 4 +- .../autojs/ui/common/ScriptOperations.java | 6 +- .../org/autojs/autojs/ui/edit/EditActivity.kt | 59 +- .../org/autojs/autojs/ui/edit/EditorMenu.java | 35 +- .../org/autojs/autojs/ui/edit/EditorView.kt | 73 ++- .../ui/edit/FindOrReplaceDialogBuilder.kt | 4 +- .../ui/edit/TextSizeSettingDialogBuilder.java | 2 +- .../ui/edit/toolbar/DebugToolbarFragment.java | 2 +- .../org/autojs/autojs/ui/main/MainActivity.kt | 3 +- .../ui/main/scripts/ApkInfoDialogManager.kt | 36 +- .../ui/main/scripts/ApkSignatureDetector.kt | 2 +- .../scripts/EditableFileInfoDialogManager.kt | 185 +++++++ .../ui/main/scripts/MediaInfoDialogManager.kt | 14 +- .../autojs/ui/project/BuildActivity.java | 2 +- .../ui/shortcut/ShortcutCreateActivity.java | 2 +- .../org/autojs/autojs/util/StringUtils.kt | 74 +++ .../res/drawable-night/ic_edit_smaller.png | Bin 0 -> 2603 bytes app/src/main/res/drawable/ic_edit_smaller.png | Bin 0 -> 2934 bytes .../editable_file_info_dialog_list_item.xml | 517 ++++++++++++++++++ app/src/main/res/menu/menu_editor.xml | 4 +- app/src/main/res/values-ar/strings.xml | 28 +- app/src/main/res/values-en/strings.xml | 28 +- app/src/main/res/values-es/strings.xml | 28 +- app/src/main/res/values-fr/strings.xml | 28 +- app/src/main/res/values-ja/strings.xml | 28 +- app/src/main/res/values-ko/strings.xml | 28 +- app/src/main/res/values-ru/strings.xml | 28 +- app/src/main/res/values-zh-rHK/strings.xml | 28 +- app/src/main/res/values-zh-rTW/strings.xml | 28 +- app/src/main/res/values-zh/strings.xml | 28 +- app/src/main/res/values/strings.xml | 28 +- version.properties | 6 +- 41 files changed, 1209 insertions(+), 218 deletions(-) create mode 100644 app/src/main/java/org/autojs/autojs/ui/main/scripts/EditableFileInfoDialogManager.kt create mode 100644 app/src/main/res/drawable-night/ic_edit_smaller.png create mode 100644 app/src/main/res/drawable/ic_edit_smaller.png create mode 100644 app/src/main/res/layout/editable_file_info_dialog_list_item.xml diff --git a/.changelog/lang_zh-Hans.json b/.changelog/lang_zh-Hans.json index 2997c656..e077e640 100644 --- a/.changelog/lang_zh-Hans.json +++ b/.changelog/lang_zh-Hans.json @@ -1,7 +1,7 @@ { "$data": { "v6.6.3": { - "released_date": "2025/05/25", + "released_date": "2025/05/27", "feature": [ "版本历史功能, 可查看发行版本历史更新记录 (多语言) 与统计数据", "timers.keepAlive 方法 (已全局化), 用于保持脚本活跃状态", @@ -16,6 +16,7 @@ ], "fix": [ "主页文档标签及文档活动页面显示在线文档时部分内容被系统导航栏遮挡的问题", + "部分页面 Toolbar 点击按钮时可能导致标题点击事件误触发的问题", "部分设备代码编辑器空行显示方框字符的问题", "主题色设置页面调色盘对话框可能无限叠加的问题", "无障碍服务关闭时音量加键停止所有脚本功能失效的问题", @@ -47,6 +48,8 @@ "设置页面对话框相关设置支持 \"使用默认值\" 菜单选项", "文件管理器浮动按钮展开后点击其他区域可自动隐藏", "代码编辑器格式化代码支持 `??`, `?.`, `??=` 等运算符", + "代码编辑器支持 GB18030 / UTF-16 (LE/BE) / Shift_JIS 等编码的文件读写", + "代码编辑器支持显示文件详细信息 (路径/编码/换行符/字节及字符总数等) _[`issue #395`](http://issues.autojs6.com/395)_", "意图相关操作 (编辑/查看/安装/发送/播放等) 增加操作异常提示", "webview 元素的 url 属性支持相对路径", "ImageWrapper#saveTo 方法的路径参数支持相对路径", @@ -65,6 +68,7 @@ "本地化 Material Date Time Picker 版本 4.2.3", "本地化 libimagequant 版本 2.17.0", "本地化 libpng 版本 1.6.49", + "附加 ICU4J 版本 77.1", "附加 Jsoup 版本 1.19.1", "附加 Material Progressbar 版本 1.4.2", "附加 Flexmark Java HTML to Markdown 版本 0.64.8", diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 42161dca..50f4277f 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -237,6 +237,9 @@ dependencies /* Unclassified */ { // Material Date Time Picker implementation(project(":modules:material-date-time-picker")) + + // ICU4J + implementation("com.ibm.icu:icu4j:77.1") } dependencies /* MIME */ { diff --git a/app/src/main/java/org/autojs/autojs/extension/MaterialDialogExtensions.kt b/app/src/main/java/org/autojs/autojs/extension/MaterialDialogExtensions.kt index 838bf872..8590ad33 100644 --- a/app/src/main/java/org/autojs/autojs/extension/MaterialDialogExtensions.kt +++ b/app/src/main/java/org/autojs/autojs/extension/MaterialDialogExtensions.kt @@ -40,18 +40,26 @@ object MaterialDialogExtensions { } } - fun MaterialDialog.setCopyableTextIfAbsent(textView: TextView, textValue: String?) { + fun MaterialDialog.setCopyableTextIfAbsent(textView: TextView, textValuePair: Pair) { + setCopyableTextIfAbsent(textView, textValuePair.first, textValuePair.second) + } + + fun MaterialDialog.setCopyableTextIfAbsent(textView: TextView, textValue: String?, suffix: String? = null) { if (textView.text == context.getString(R.string.ellipsis_six)) { - textView.text = textValue.takeUnless { it.isNullOrBlank() } ?: context.getString(R.string.text_unknown) + textView.text = textValue.takeUnless { it.isNullOrBlank() }?.let { it + (suffix ?: "") } ?: context.getString(R.string.text_unknown) } this.makeTextCopyable(textView, textValue) } fun MaterialDialog.setCopyableTextIfAbsent(textView: TextView, scope: CoroutineScope, f: () -> String?) { + setCopyableTextIfAbsent(textView, scope, f, suffix = null) + } + + fun MaterialDialog.setCopyableTextIfAbsent(textView: TextView, scope: CoroutineScope, f: () -> String?, suffix: String?) { scope.launch(Dispatchers.IO) { val textValue = f.invoke() withContext(Dispatchers.Main) { - setCopyableTextIfAbsent(textView, textValue) + setCopyableTextIfAbsent(textView, textValue, suffix) } } } diff --git a/app/src/main/java/org/autojs/autojs/extension/ViewExtensions.kt b/app/src/main/java/org/autojs/autojs/extension/ViewExtensions.kt index dbd8407a..8885394c 100644 --- a/app/src/main/java/org/autojs/autojs/extension/ViewExtensions.kt +++ b/app/src/main/java/org/autojs/autojs/extension/ViewExtensions.kt @@ -2,7 +2,11 @@ package org.autojs.autojs.extension import android.annotation.SuppressLint import android.os.Build +import android.view.View import android.widget.PopupMenu +import android.widget.TextView +import androidx.appcompat.widget.Toolbar +import org.autojs.autojs.util.ViewUtils.onceGlobalLayout /** * Created by SuperMonster003 on May 7, 2025. @@ -26,4 +30,43 @@ object ViewExtensions { } } + val Toolbar.titleView: TextView? + get() = this.findViewById(com.google.android.material.R.id.action_bar_title) + ?: Toolbar::class.java.getDeclaredField("mTitleTextView").apply { isAccessible = true }.get(this@titleView) as TextView? + + val Toolbar.subtitleView: TextView? + get() = this.findViewById(com.google.android.material.R.id.action_bar_subtitle) + ?: Toolbar::class.java.getDeclaredField("mSubtitleTextView").apply { isAccessible = true }.get(this@subtitleView) as TextView? + + @JvmStatic + fun Toolbar.setOnTitleViewClickListener(l: View.OnClickListener?) { + this.setOnTitleViewClickListener(l, withFallback = true) + } + + @JvmStatic + fun Toolbar.setOnTitleViewClickListener(l: View.OnClickListener?, withFallback: Boolean) { + this.onceGlobalLayout { + this.titleView?.setOnClickListener(l) ?: run { if (withFallback) this.setOnClickListener(l) } + } + } + + @JvmStatic + fun Toolbar.setOnSubtitleViewClickListener(l: View.OnClickListener?) { + this.onceGlobalLayout { + this.subtitleView?.setOnClickListener(l) + } + } + + @JvmStatic + fun Toolbar.setOnTitleViewLongClickListener(l: View.OnLongClickListener?) { + this.setOnTitleViewLongClickListener(l, withFallback = true) + } + + @JvmStatic + fun Toolbar.setOnTitleViewLongClickListener(l: View.OnLongClickListener?, withFallback: Boolean) { + this.onceGlobalLayout { + this.titleView?.setOnLongClickListener(l) ?: run { if (withFallback) this.setOnLongClickListener(l) } + } + } + } diff --git a/app/src/main/java/org/autojs/autojs/model/script/Scripts.kt b/app/src/main/java/org/autojs/autojs/model/script/Scripts.kt index 8e8fc101..7eaa9ccb 100644 --- a/app/src/main/java/org/autojs/autojs/model/script/Scripts.kt +++ b/app/src/main/java/org/autojs/autojs/model/script/Scripts.kt @@ -12,6 +12,7 @@ import org.autojs.autojs.external.ScriptIntents import org.autojs.autojs.external.fileprovider.AppFileProvider import org.autojs.autojs.external.shortcut.Shortcut import org.autojs.autojs.external.shortcut.ShortcutActivity +import org.autojs.autojs.runtime.api.Mime import org.autojs.autojs.runtime.exception.ScriptInterruptedException import org.autojs.autojs.script.ScriptSource import org.autojs.autojs.ui.edit.EditActivity @@ -81,7 +82,7 @@ object Scripts { IntentUtils.viewFile( globalAppContext, uri, - "text/plain", + Mime.TEXT_PLAIN, AppFileProvider.AUTHORITY, ToastExceptionHolder(globalAppContext), ) diff --git a/app/src/main/java/org/autojs/autojs/permission/DisplayOverOtherAppsPermission.kt b/app/src/main/java/org/autojs/autojs/permission/DisplayOverOtherAppsPermission.kt index 55aed61c..a72f1616 100644 --- a/app/src/main/java/org/autojs/autojs/permission/DisplayOverOtherAppsPermission.kt +++ b/app/src/main/java/org/autojs/autojs/permission/DisplayOverOtherAppsPermission.kt @@ -69,7 +69,7 @@ class DisplayOverOtherAppsPermission(override val context: Context) : Permission .negativeText(R.string.text_cancel) .negativeColorRes(R.color.dialog_button_default) .onNegative { dialog, _ -> dialog.dismiss() } - .positiveText(R.string.text_ok) + .positiveText(R.string.dialog_button_confirm) .positiveColorRes(R.color.dialog_button_attraction) .onPositive { dialog, _ -> dialog.dismiss().also { config() } } .cancelable(false) diff --git a/app/src/main/java/org/autojs/autojs/theme/app/ColorInfoDialogManager.kt b/app/src/main/java/org/autojs/autojs/theme/app/ColorInfoDialogManager.kt index 6d80b1dd..90f21ab7 100644 --- a/app/src/main/java/org/autojs/autojs/theme/app/ColorInfoDialogManager.kt +++ b/app/src/main/java/org/autojs/autojs/theme/app/ColorInfoDialogManager.kt @@ -68,10 +68,8 @@ object ColorInfoDialogManager { Colors.toHsvStringRhino(colorWithoutAlpha).let { binding.colorHsvValue.bindWith(dialog, it) } ColorUtils.toInt(colorWithoutAlpha).let { binding.colorIntValue.bindWith(dialog, it.toString()) } } - withContext(Dispatchers.Main) { - restoreEssentialViews(binding) - updateGuidelines(binding) - } + restoreEssentialViews(binding) + updateGuidelines(binding) } } diff --git a/app/src/main/java/org/autojs/autojs/theme/app/ColorItemsActivity.kt b/app/src/main/java/org/autojs/autojs/theme/app/ColorItemsActivity.kt index f85256cb..0daeff49 100644 --- a/app/src/main/java/org/autojs/autojs/theme/app/ColorItemsActivity.kt +++ b/app/src/main/java/org/autojs/autojs/theme/app/ColorItemsActivity.kt @@ -23,6 +23,8 @@ import androidx.recyclerview.widget.RecyclerView.VERTICAL import androidx.recyclerview.widget.ThemeColorRecyclerView import org.autojs.autojs.core.image.ColorItems import org.autojs.autojs.core.pref.Pref +import org.autojs.autojs.extension.ViewExtensions.setOnSubtitleViewClickListener +import org.autojs.autojs.extension.ViewExtensions.setOnTitleViewClickListener import org.autojs.autojs.theme.ThemeChangeNotifier import org.autojs.autojs.theme.ThemeColorManager import org.autojs.autojs.theme.app.ColorLibrariesActivity.Companion.COLOR_LIBRARY_ID_DEFAULT @@ -105,7 +107,10 @@ class ColorItemsActivity : ColorSelectBaseActivity() { showColorDetails(ThemeColorManager.colorPrimary, getSubtitle(false)) } else -> null - }.let { toolbar.setOnClickListener(it) } + }.let { + toolbar.setOnTitleViewClickListener(it) + toolbar.setOnSubtitleViewClickListener(it) + } } override fun getSubtitle(withHexSuffix: Boolean): String? = when (mLibrary.id) { diff --git a/app/src/main/java/org/autojs/autojs/theme/app/ColorLibrariesActivity.kt b/app/src/main/java/org/autojs/autojs/theme/app/ColorLibrariesActivity.kt index d09b7011..5c5a8e42 100644 --- a/app/src/main/java/org/autojs/autojs/theme/app/ColorLibrariesActivity.kt +++ b/app/src/main/java/org/autojs/autojs/theme/app/ColorLibrariesActivity.kt @@ -12,6 +12,8 @@ import androidx.recyclerview.widget.RecyclerView.VERTICAL import androidx.recyclerview.widget.ThemeColorRecyclerView import org.autojs.autojs.core.image.ColorItems import org.autojs.autojs.core.pref.Pref +import org.autojs.autojs.extension.ViewExtensions.setOnSubtitleViewClickListener +import org.autojs.autojs.extension.ViewExtensions.setOnTitleViewClickListener import org.autojs.autojs.theme.ThemeChangeNotifier import org.autojs.autojs.theme.ThemeColorManager import org.autojs.autojs.util.ViewUtils @@ -52,7 +54,8 @@ class ColorLibrariesActivity : ColorSelectBaseActivity() { setUpAppBar(it.appBar, it.appBarContainer) it.toolbar.let { toolbar -> setUpToolbar(toolbar) - toolbar.setOnClickListener { true.also { showThemeColorDetails() } } + toolbar.setOnTitleViewClickListener { showThemeColorDetails() } + toolbar.setOnSubtitleViewClickListener { showThemeColorDetails() } toolbar.setOnLongClickListener { true.also { /* toggleFabVisibility() */ } } } } diff --git a/app/src/main/java/org/autojs/autojs/theme/preference/MaterialListPreference.kt b/app/src/main/java/org/autojs/autojs/theme/preference/MaterialListPreference.kt index 9e8848b8..d6bdfce8 100644 --- a/app/src/main/java/org/autojs/autojs/theme/preference/MaterialListPreference.kt +++ b/app/src/main/java/org/autojs/autojs/theme/preference/MaterialListPreference.kt @@ -123,8 +123,8 @@ open class MaterialListPreference : MaterialDialogPreference { .title(R.string.text_prompt) .content(content) .widgetThemeColor() - .positiveText(R.string.dialog_button_dismiss) - .positiveColorRes(R.color.dialog_button_default) + .positiveText(R.string.dialog_button_confirm) + .positiveColorRes(R.color.dialog_button_hint) .dismissListener { onChangeConfirmed(getDialog()) } .show() } diff --git a/app/src/main/java/org/autojs/autojs/ui/common/ScriptOperations.java b/app/src/main/java/org/autojs/autojs/ui/common/ScriptOperations.java index 5b874181..c7cdd347 100644 --- a/app/src/main/java/org/autojs/autojs/ui/common/ScriptOperations.java +++ b/app/src/main/java/org/autojs/autojs/ui/common/ScriptOperations.java @@ -392,7 +392,7 @@ public class ScriptOperations { .title(mContext.getString(R.string.text_confirm_to_delete)) .content(scriptFile.getName()) .negativeText(R.string.text_cancel) - .positiveText(R.string.text_ok) + .positiveText(R.string.dialog_button_confirm) .positiveColorRes(R.color.dialog_button_caution) .onPositive((dialog, which) -> deleteWithoutConfirm(scriptFile)) .build() @@ -413,7 +413,7 @@ public class ScriptOperations { .content(content) .negativeText(R.string.text_cancel) .negativeColorRes(R.color.dialog_button_default) - .positiveText(R.string.text_ok) + .positiveText(R.string.dialog_button_confirm) .positiveColorRes(R.color.dialog_button_warn) .onPositive((dialog, which) -> setAsWorkingDirNow(scriptFile)) .build() @@ -491,7 +491,7 @@ public class ScriptOperations { .justScriptFile() .singleChoice(file -> importFile(file.getPath()).subscribe()) .title(R.string.text_select_file_to_import) - .positiveText(R.string.text_ok) + .positiveText(R.string.dialog_button_confirm) .positiveColorRes(R.color.dialog_button_attraction) .show(); } diff --git a/app/src/main/java/org/autojs/autojs/ui/edit/EditActivity.kt b/app/src/main/java/org/autojs/autojs/ui/edit/EditActivity.kt index d4dc2f3b..d12a208d 100644 --- a/app/src/main/java/org/autojs/autojs/ui/edit/EditActivity.kt +++ b/app/src/main/java/org/autojs/autojs/ui/edit/EditActivity.kt @@ -16,7 +16,6 @@ import android.view.ActionMode import android.view.Menu import android.view.MenuItem import android.widget.TextView -import androidx.appcompat.widget.Toolbar import com.afollestad.materialdialogs.MaterialDialog import io.reactivex.Observable import io.reactivex.android.schedulers.AndroidSchedulers @@ -26,11 +25,14 @@ import org.autojs.autojs.app.OnActivityResultDelegate.DelegateHost import org.autojs.autojs.core.permission.OnRequestPermissionsResultCallback import org.autojs.autojs.core.permission.PermissionRequestProxyActivity import org.autojs.autojs.core.permission.RequestPermissionCallbacks +import org.autojs.autojs.extension.ViewExtensions.setOnTitleViewClickListener +import org.autojs.autojs.extension.ViewExtensions.titleView import org.autojs.autojs.pio.PFiles import org.autojs.autojs.storage.file.TmpScriptFiles import org.autojs.autojs.theme.widget.ThemeColorToolbar import org.autojs.autojs.ui.BaseActivity import org.autojs.autojs.ui.main.MainActivity +import org.autojs.autojs.ui.main.scripts.EditableFileInfoDialogManager import org.autojs.autojs.util.Observers import org.autojs.autojs.util.ViewUtils.onceGlobalLayout import org.autojs.autojs.util.ViewUtils.setMenuIconsColorByThemeColorLuminance @@ -38,6 +40,8 @@ import org.autojs.autojs6.R import org.autojs.autojs6.databinding.ActivityEditBinding import java.io.File import java.io.IOException +import androidx.core.view.get +import androidx.core.view.size /** * Created by Stardust on Jan 29, 2017. @@ -61,6 +65,11 @@ open class EditActivity : BaseActivity(), DelegateHost, PermissionRequestProxyAc val binding = ActivityEditBinding.inflate(layoutInflater).also { setContentView(it.root) } mToolbar = findViewById(R.id.toolbar).apply { setTitleTextAppearance(this@EditActivity, R.style.TextAppearanceEditorTitle) + setOnTitleViewClickListener { + EditableFileInfoDialogManager.showEditableFileInfoDialog(this@EditActivity, mEditorView.uri.path?.let { File(it) }) { + mEditorView.editor.text + } + } } mEditorView = binding.editorView.apply { handleIntent(intent) @@ -91,27 +100,24 @@ open class EditActivity : BaseActivity(), DelegateHost, PermissionRequestProxyAc menuInflater.inflate(R.menu.menu_editor, menu) mToolbar?.let { toolbar -> toolbar.setMenuIconsColorByThemeColorLuminance(this) - toolbar.onceGlobalLayout { - val titleView = toolbar.findViewById(com.google.android.material.R.id.action_bar_title) ?: run { - Toolbar::class.java.getDeclaredField("mTitleTextView").apply { isAccessible = true }.get(toolbar) as TextView? - } - titleView?.adjustTitleTextView() - } + toolbar.onceGlobalLayout { toolbar.titleView?.adjustTitleTextView() } } return true } private fun TextView.adjustTitleTextView() = this.post { - ValueAnimator.ofFloat(this.textSize, calculatedTextSize(this) ?: return@post).let { - it.duration = 120L - it.addUpdateListener { this.setTextSize(TypedValue.COMPLEX_UNIT_PX, it.animatedValue as Float) } - it.start() + ValueAnimator.ofFloat(this.textSize, calculatedTextSize(this) ?: return@post).let { animator -> + animator.duration = 120L + animator.addUpdateListener { this.setTextSize(TypedValue.COMPLEX_UNIT_PX, it.animatedValue as Float) } + animator.start() } } // @Created by JetBrains AI Assistant on Mar 24, 2025. private fun calculatedTextSize(textView: TextView): Float? { - // 可用宽度, 排除内边距 + + // Available width excluding padding. + // zh-CN: 可用宽度, 排除内边距. val availableWidth = textView.width - textView.paddingLeft - textView.paddingRight if (availableWidth <= 0) return null @@ -120,7 +126,8 @@ open class EditActivity : BaseActivity(), DelegateHost, PermissionRequestProxyAc val paint: TextPaint = textView.paint val step = resources.getDimension(R.dimen.editor_title_text_size_step) - /* ---------- 尝试一行显示 (单行) ---------- */ + /* Try single line display. + * zh-CN: 尝试一行显示 (单行). */ textView.isSingleLine = true textView.maxLines = 1 @@ -128,27 +135,32 @@ open class EditActivity : BaseActivity(), DelegateHost, PermissionRequestProxyAc var oneLineTextSizePx = textView.textSize val minOneLineSizePx = resources.getDimension(R.dimen.editor_title_min_text_size_single_line) - // 测量一行文字宽度 + // Measure single line text width. + // zh-CN: 测量一行文字宽度. paint.textSize = oneLineTextSizePx var measuredWidth = paint.measureText(textStr) - // 当文字宽度超出可用宽度并且字号还高于下限的时候逐步降低字号 + // Gradually decrease text size when width exceeds and size is above minimum. + // zh-CN: 当文字宽度超出可用宽度并且字号还高于下限的时候逐步降低字号. while (measuredWidth > availableWidth && oneLineTextSizePx > minOneLineSizePx) { oneLineTextSizePx -= step paint.textSize = oneLineTextSizePx measuredWidth = paint.measureText(textStr) } - // 如果一行能够显示文字, 则直接应用修改 + // If text fits in one line, apply changes directly. + // zh-CN: 如果一行能够显示文字, 则直接应用修改. if (measuredWidth <= availableWidth) { return oneLineTextSizePx } - /* ---------- 切换为两行显示 ---------- */ + /* Switch to double line display. + * zh-CN: 切换为两行显示. */ textView.isSingleLine = false textView.maxLines = 2 - // 重置字号 + // Reset text size. + // zh-CN: 重置字号. var twoLineTextSize = when (isNonAscii) { true -> resources.getDimension(R.dimen.editor_title_text_size_double_line_non_ascii) else -> resources.getDimension(R.dimen.editor_title_text_size_double_line_ascii) @@ -157,7 +169,8 @@ open class EditActivity : BaseActivity(), DelegateHost, PermissionRequestProxyAc val minTwoLineSize = resources.getDimension(R.dimen.editor_title_min_text_size_double_line) paint.textSize = twoLineTextSize - // 检查两行显示是否足够: 利用 StaticLayout 测量文字显示效果 + // Check if two lines are sufficient using StaticLayout to measure text display. + // zh-CN: 检查两行显示是否足够: 利用 StaticLayout 测量文字显示效果. fun createStaticLayout(textSize: Float): StaticLayout { paint.textSize = textSize return StaticLayout.Builder @@ -168,7 +181,8 @@ open class EditActivity : BaseActivity(), DelegateHost, PermissionRequestProxyAc } var layout = createStaticLayout(twoLineTextSize) - // 当行数超出了两行且字号尚未到达最低要求, 则逐步降低字号 + // When line count exceeds 2 and text size is above minimum, decrease size gradually. + // zh-CN: 当行数超出了两行且字号尚未到达最低要求, 则逐步降低字号. while (layout.lineCount > 2 && twoLineTextSize > minTwoLineSize) { twoLineTextSize -= step layout = createStaticLayout(twoLineTextSize) @@ -177,7 +191,8 @@ open class EditActivity : BaseActivity(), DelegateHost, PermissionRequestProxyAc return twoLineTextSize } - /* ---------- 切换为三行显示 ---------- */ + /* Switch to triple line display. + * zh-CN: 切换为三行显示. */ textView.maxLines = 3 @@ -205,7 +220,7 @@ open class EditActivity : BaseActivity(), DelegateHost, PermissionRequestProxyAc Log.d(LOG_TAG, "onActionModeStarted: $mode") val menu = mode.menu - val item = menu.getItem(menu.size() - 1) + val item = menu[menu.size - 1] addMenuItem(menu, item.groupId, R.id.action_delete_line, 10000, R.string.text_delete_line) { mEditorMenu.deleteLine() } addMenuItem(menu, item.groupId, R.id.action_copy_line, 20000, R.string.text_copy_line) { mEditorMenu.copyLine() } diff --git a/app/src/main/java/org/autojs/autojs/ui/edit/EditorMenu.java b/app/src/main/java/org/autojs/autojs/ui/edit/EditorMenu.java index e4a57492..d57d2936 100644 --- a/app/src/main/java/org/autojs/autojs/ui/edit/EditorMenu.java +++ b/app/src/main/java/org/autojs/autojs/ui/edit/EditorMenu.java @@ -2,23 +2,21 @@ package org.autojs.autojs.ui.edit; import android.annotation.SuppressLint; import android.content.Context; -import android.net.Uri; import android.text.InputType; import android.text.TextUtils; import android.view.MenuItem; import androidx.annotation.Nullable; import com.afollestad.materialdialogs.MaterialDialog; -import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; import org.autojs.autojs.core.pref.Language; import org.autojs.autojs.core.pref.Pref; import org.autojs.autojs.extension.MaterialDialogExtensions; import org.autojs.autojs.model.indices.AndroidClass; import org.autojs.autojs.model.indices.ClassSearchingItem; -import org.autojs.autojs.pio.PFiles; import org.autojs.autojs.script.JavaScriptFileSource; import org.autojs.autojs.ui.common.NotAskAgainDialog; import org.autojs.autojs.ui.edit.editor.CodeEditor; +import org.autojs.autojs.ui.main.scripts.EditableFileInfoDialogManager; import org.autojs.autojs.ui.project.BuildActivity; import org.autojs.autojs.util.ClipboardUtils; import org.autojs.autojs.util.ConsoleUtils; @@ -27,6 +25,7 @@ import org.autojs.autojs.util.IntentUtils.ToastExceptionHolder; import org.autojs.autojs.util.ViewUtils; import org.autojs.autojs6.R; +import java.io.File; import java.util.Arrays; import java.util.List; import java.util.Objects; @@ -138,8 +137,8 @@ public class EditorMenu { if (itemId == R.id.action_open_by_other_apps) { return tryDoing(mEditorView::openByOtherApps); } - if (itemId == R.id.action_info) { - showInfo(); + if (itemId == R.id.action_file_details) { + showFileDetails(); return true; } if (itemId == R.id.action_build_apk) { @@ -209,10 +208,7 @@ public class EditorMenu { } private void startBuildApkActivity() { - Uri uri = mEditorView.uri; - if (uri != null) { - BuildActivity.launch(mContext, uri.getPath()); - } + BuildActivity.launch(mContext, mEditorView.uri.getPath()); } private void setPinchToZoomStrategy() { @@ -338,24 +334,9 @@ public class EditorMenu { builder.show(); } - @SuppressLint("StringFormatMatches") - private void showInfo() { - Observable - .zip(Observable.just(mEditor.getText()), mEditor.getLineCount(), (text, lineCount) -> { - String size = PFiles.getHumanReadableSize(text.length()); - return String.format(Language.getPrefLanguage().getLocale(), mContext.getString(R.string.format_editor_info), - text.length(), lineCount, size); - }) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(this::showInfo); - - } - - private void showInfo(String info) { - new MaterialDialog.Builder(mContext) - .title(R.string.text_info) - .content(info) - .show(); + private void showFileDetails() { + var path = mEditorView.uri.getPath(); + EditableFileInfoDialogManager.showEditableFileInfoDialog(mContext, new File(path), mEditor::getText); } protected boolean copyLine() { diff --git a/app/src/main/java/org/autojs/autojs/ui/edit/EditorView.kt b/app/src/main/java/org/autojs/autojs/ui/edit/EditorView.kt index 7606b315..3f3b9dba 100644 --- a/app/src/main/java/org/autojs/autojs/ui/edit/EditorView.kt +++ b/app/src/main/java/org/autojs/autojs/ui/edit/EditorView.kt @@ -27,10 +27,13 @@ import io.reactivex.Observable import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.schedulers.Schedulers import org.autojs.autojs.AutoJs +import org.autojs.autojs.core.pref.Pref.getEditorTextSize +import org.autojs.autojs.core.pref.Pref.setEditorTextSize import org.autojs.autojs.engine.JavaScriptEngine import org.autojs.autojs.engine.ScriptEngine import org.autojs.autojs.event.BackPressedHandler.HostActivity import org.autojs.autojs.execution.ScriptExecution +import org.autojs.autojs.extension.MaterialDialogExtensions.choiceWidgetThemeColor import org.autojs.autojs.model.autocomplete.AutoCompletion import org.autojs.autojs.model.autocomplete.CodeCompletions import org.autojs.autojs.model.autocomplete.Symbols @@ -44,11 +47,7 @@ import org.autojs.autojs.model.script.Scripts.openByOtherApps import org.autojs.autojs.model.script.Scripts.runWithBroadcastSender import org.autojs.autojs.pio.PFiles.getNameWithoutExtension import org.autojs.autojs.pio.PFiles.move -import org.autojs.autojs.pio.PFiles.read import org.autojs.autojs.pio.PFiles.write -import org.autojs.autojs.core.pref.Pref.getEditorTextSize -import org.autojs.autojs.core.pref.Pref.setEditorTextSize -import org.autojs.autojs.extension.MaterialDialogExtensions.choiceWidgetThemeColor import org.autojs.autojs.storage.file.TmpScriptFiles import org.autojs.autojs.tool.Callback import org.autojs.autojs.ui.doc.ManualDialog @@ -72,11 +71,15 @@ import org.autojs.autojs.ui.widget.SimpleTextWatcher import org.autojs.autojs.util.DisplayUtils.pxToSp import org.autojs.autojs.util.DocsUtils.getUrl import org.autojs.autojs.util.Observers +import org.autojs.autojs.util.StringUtils import org.autojs.autojs.util.ViewUtils.showSnack import org.autojs.autojs.util.ViewUtils.showToast import org.autojs.autojs6.R import org.autojs.autojs6.databinding.EditorViewBinding import java.io.File +import java.io.IOException +import java.nio.charset.Charset +import java.nio.charset.StandardCharsets /** * Created by Stardust on Sep 28, 2017. @@ -94,11 +97,9 @@ class EditorView : LinearLayout, OnHintClickListener, ClickCallback, ToolbarFrag @JvmField val debugBar: DebugBar = binding.debugBar - @JvmField - var name: String? = null + lateinit var name: String - @JvmField - var uri: Uri? = null + lateinit var uri: Uri var scriptExecutionId = 0 private set @@ -126,6 +127,8 @@ class EditorView : LinearLayout, OnHintClickListener, ClickCallback, ToolbarFrag private val mDocsWebView: EWebView = binding.docs private val mDrawerLayout: DrawerLayout = binding.drawerLayout + private var mCurrentCharset: Charset = StandardCharsets.UTF_8 + private var mHadBom = false private var mReadOnly = false private var mAutoCompletion: AutoCompletion? = null private var mEditorTheme: Theme? = null @@ -193,7 +196,7 @@ class EditorView : LinearLayout, OnHintClickListener, ClickCallback, ToolbarFrag } fun handleIntent(intent: Intent): Observable { - name = intent.getStringExtra(EXTRA_NAME) + intent.getStringExtra(EXTRA_NAME)?.let { name = it } return handleText(intent) .observeOn(AndroidSchedulers.mainThread()) .doOnNext { @@ -228,15 +231,28 @@ class EditorView : LinearLayout, OnHintClickListener, ClickCallback, ToolbarFrag } else { Uri.fromFile(File(path)) } - if (name == null) { - name = getNameWithoutExtension(uri!!.path!!) + if (!::name.isInitialized) { + name = getNameWithoutExtension(uri.path!!) } return loadUri(uri) } @SuppressLint("CheckResult") - private fun loadUri(uri: Uri?): Observable { - return Observable.fromCallable { read(context.contentResolver.openInputStream(uri!!)!!) } + private fun loadUri(uri: Uri): Observable { + return Observable + .fromCallable { + val resolver = context.contentResolver + val rawBytes = resolver.openInputStream(uri)?.use { it.readBytes() } ?: ByteArray(0) + + mCurrentCharset = StringUtils.detectCharset(rawBytes).charsetOrDefault() + mHadBom = StringUtils.hasBom(rawBytes, mCurrentCharset) + + val effectiveBytes = if (mHadBom) { + StringUtils.dropBom(rawBytes, mCurrentCharset) + } else rawBytes + + String(effectiveBytes, mCurrentCharset) + } .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .doOnNext { text: String -> setInitialText(text) } @@ -386,7 +402,7 @@ class EditorView : LinearLayout, OnHintClickListener, ClickCallback, ToolbarFrag } @JvmOverloads - fun run(showMessage: Boolean, file: File? = uri!!.path?.let { File(it) }, overriddenFullPath: String? = null): ScriptExecution? { + fun run(showMessage: Boolean, file: File? = uri.path?.let { File(it) }, overriddenFullPath: String? = null): ScriptExecution? { file ?: return null if (showMessage) { showSnack(this, R.string.text_start_running) @@ -394,7 +410,7 @@ class EditorView : LinearLayout, OnHintClickListener, ClickCallback, ToolbarFrag // TODO by Stardust on Oct 24, 2018. val execution = runWithBroadcastSender( file, - workingDirectory = uri!!.path?.let { File(it).parent }, + workingDirectory = uri.path?.let { File(it).parent }, overriddenFullPath, ) ?: return null scriptExecutionId = execution.id @@ -402,8 +418,8 @@ class EditorView : LinearLayout, OnHintClickListener, ClickCallback, ToolbarFrag return execution } - private fun runTmpFile(file: File? = uri!!.path?.let { File(it) }): ScriptExecution? { - return run(true, file, uri!!.path) + private fun runTmpFile(file: File? = uri.path?.let { File(it) }): ScriptExecution? { + return run(true, file, uri.path) } private fun undo() = editor.undo() @@ -411,12 +427,16 @@ class EditorView : LinearLayout, OnHintClickListener, ClickCallback, ToolbarFrag private fun redo() = editor.redo() fun save(): Observable { - val path = uri!!.path + val path = uri.path!! val backPath = "$path.save" - move(path!!, backPath) - return Observable.just(editor.text) + move(path, backPath) + return Observable + .fromCallable { + editor.text.apply { + writeTextWithCharset(uri, this) + } + } .observeOn(Schedulers.io()) - .doOnNext { s: String? -> write(context.contentResolver.openOutputStream(uri!!)!!, s!!) } .observeOn(AndroidSchedulers.mainThread()) .doOnNext { editor.markTextAsSaved() @@ -429,6 +449,13 @@ class EditorView : LinearLayout, OnHintClickListener, ClickCallback, ToolbarFrag } } + private fun writeTextWithCharset(uri: Uri, text: String) { + context.contentResolver.openOutputStream(uri, "rwt")?.use { out -> + if (mHadBom) out.write(StringUtils.bomBytes(mCurrentCharset)) + out.write(text.toByteArray(mCurrentCharset)) + } ?: throw IOException("Cannot open output stream for $uri") + } + fun forceStop() { doWithCurrentEngine { obj: ScriptEngine<*> -> obj.forceStop() } } @@ -468,9 +495,7 @@ class EditorView : LinearLayout, OnHintClickListener, ClickCallback, ToolbarFrag } fun openByOtherApps() { - if (uri != null) { - openByOtherApps(uri!!) - } + openByOtherApps(uri) } fun beautifyCode() { diff --git a/app/src/main/java/org/autojs/autojs/ui/edit/FindOrReplaceDialogBuilder.kt b/app/src/main/java/org/autojs/autojs/ui/edit/FindOrReplaceDialogBuilder.kt index c7a190ef..78b22c0b 100644 --- a/app/src/main/java/org/autojs/autojs/ui/edit/FindOrReplaceDialogBuilder.kt +++ b/app/src/main/java/org/autojs/autojs/ui/edit/FindOrReplaceDialogBuilder.kt @@ -62,8 +62,8 @@ class FindOrReplaceDialogBuilder(context: Context, private val mEditorView: Edit title(R.string.text_find_or_replace) customView(binding.root, true) - positiveText(R.string.text_ok) - negativeText(R.string.text_cancel) + positiveText(R.string.dialog_button_confirm) + negativeText(R.string.dialog_button_cancel) } private fun storeState() { diff --git a/app/src/main/java/org/autojs/autojs/ui/edit/TextSizeSettingDialogBuilder.java b/app/src/main/java/org/autojs/autojs/ui/edit/TextSizeSettingDialogBuilder.java index 23eeb83e..f2d57f15 100644 --- a/app/src/main/java/org/autojs/autojs/ui/edit/TextSizeSettingDialogBuilder.java +++ b/app/src/main/java/org/autojs/autojs/ui/edit/TextSizeSettingDialogBuilder.java @@ -58,7 +58,7 @@ public class TextSizeSettingDialogBuilder extends MaterialDialog.Builder impleme negativeText(R.string.text_cancel); negativeColorRes(R.color.dialog_button_default); onNegative((dialog, which) -> dialog.dismiss()); - positiveText(R.string.text_ok); + positiveText(R.string.dialog_button_confirm); positiveColorRes(R.color.dialog_button_attraction); onPositive((dialog, which) -> dialog.dismiss()); } diff --git a/app/src/main/java/org/autojs/autojs/ui/edit/toolbar/DebugToolbarFragment.java b/app/src/main/java/org/autojs/autojs/ui/edit/toolbar/DebugToolbarFragment.java index 02ece169..0cf908ec 100644 --- a/app/src/main/java/org/autojs/autojs/ui/edit/toolbar/DebugToolbarFragment.java +++ b/app/src/main/java/org/autojs/autojs/ui/edit/toolbar/DebugToolbarFragment.java @@ -93,7 +93,7 @@ public class DebugToolbarFragment extends ToolbarFragment(this)); setInterrupted(false); - mCurrentEditorSourceUrl = mInitialEditorSourceUrl = mEditorView.uri != null ? mEditorView.uri.toString() : null; + mCurrentEditorSourceUrl = mInitialEditorSourceUrl = mEditorView.uri.toString(); mInitialEditorSource = mEditorView.editor.getText(); setupEditor(); ScriptExecution execution = mEditorView.run(false); diff --git a/app/src/main/java/org/autojs/autojs/ui/main/MainActivity.kt b/app/src/main/java/org/autojs/autojs/ui/main/MainActivity.kt index 9da27551..ea6639f7 100644 --- a/app/src/main/java/org/autojs/autojs/ui/main/MainActivity.kt +++ b/app/src/main/java/org/autojs/autojs/ui/main/MainActivity.kt @@ -36,6 +36,7 @@ import org.autojs.autojs.core.pref.Pref import org.autojs.autojs.event.BackPressedHandler import org.autojs.autojs.event.BackPressedHandler.DoublePressExit import org.autojs.autojs.event.BackPressedHandler.HostActivity +import org.autojs.autojs.extension.ViewExtensions.setOnTitleViewLongClickListener import org.autojs.autojs.model.explorer.Explorers import org.autojs.autojs.permission.DisplayOverOtherAppsPermission import org.autojs.autojs.permission.ManageAllFilesPermission @@ -178,7 +179,7 @@ class MainActivity : BaseActivity(), DelegateHost, HostActivity { val toolbar = mToolbar.also { setSupportActionBar(it) it.setTitle(R.string.app_name) - it.setOnLongClickListener { true.also { PreferencesActivity.launch(this) } } + it.setOnTitleViewLongClickListener { true.also { PreferencesActivity.launch(this) } } } mActionBarDrawerToggle = object : ActionBarDrawerToggle( diff --git a/app/src/main/java/org/autojs/autojs/ui/main/scripts/ApkInfoDialogManager.kt b/app/src/main/java/org/autojs/autojs/ui/main/scripts/ApkInfoDialogManager.kt index 8b540788..6ef6a636 100644 --- a/app/src/main/java/org/autojs/autojs/ui/main/scripts/ApkInfoDialogManager.kt +++ b/app/src/main/java/org/autojs/autojs/ui/main/scripts/ApkInfoDialogManager.kt @@ -13,6 +13,7 @@ import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.view.isVisible import com.afollestad.materialdialogs.DialogAction import com.afollestad.materialdialogs.MaterialDialog +import com.android.apksig.ApkVerifier import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob @@ -71,8 +72,8 @@ object ApkInfoDialogManager { .onNegative { materialDialog, _ -> materialDialog.dismiss() } .show() .apply { + makeTextCopyable { titleView } setOnDismissListener { scope.cancel() } - makeTextCopyable { it.titleView } } scope.launch { @@ -226,15 +227,32 @@ object ApkInfoDialogManager { } private fun getApkSignatureInfo(apkFile: File): String? = runCatching { - // ApkVerifier.Builder(apkFile).build().verify().run { - // listOfNotNull( - // "V1".takeIf { isVerifiedUsingV1Scheme || hasV1Signature(apkFile) }, - // "V2".takeIf { isVerifiedUsingV2Scheme }, - // "V3".takeIf { isVerifiedUsingV3Scheme }, - // "V4".takeIf { isVerifiedUsingV4Scheme }, - // ).takeUnless { it.isEmpty() }?.joinToString(" + ") - // } + // @Hint by JetBrains AI Assistant on May 21, 2025. + // ! APK (Zip) has an "APK Signing Block" at the end, + // ! storing pairs for V2/V3/V4 sequentially. + // ! Only need to locate and check for corresponding ID to determine signature data existence. + // ! zh-CN: + // ! APK (Zip) 末尾有一段 "APK Signing Block", 依次存放 V2/V3/V4 的 对. + // ! 只需定位并查看其中是否存在对应 ID, 即可判断是否存在签名数据. ApkSignatureDetector.detectSchemes(apkFile) + }.getOrNull() ?: getApkSignatureInfoLegacy(apkFile) + + private fun getApkSignatureInfoLegacy(apkFile: File): String? = runCatching { + // @Hint by JetBrains AI Assistant on May 21, 2025. + // ! `ApkVerifier.verify()` parses ZIP structure to find V2/V3/V4 Signing Block, + // ! calculates hash values (SHA-256/512) for each signature scheme segment, + // ! requiring re-traversal of files for each signature. + // ! zh-CN: + // ! `ApkVerifier.verify()` 解析 ZIP 结构找到 V2/V3/V4 Signing Block, + // ! 对每一种签名方案逐段计算哈希值 (SHA-256/512), 每种签名都需要重新遍历文件. + ApkVerifier.Builder(apkFile).build().verify().run { + listOfNotNull( + "V1".takeIf { isVerifiedUsingV1Scheme || ApkSignatureDetector.hasV1Signature(apkFile) }, + "V2".takeIf { isVerifiedUsingV2Scheme }, + "V3".takeIf { isVerifiedUsingV3Scheme }, + "V4".takeIf { isVerifiedUsingV4Scheme }, + ).takeUnless { it.isEmpty() }?.joinToString(" + ") + } }.getOrNull() private data class ApkInfo( diff --git a/app/src/main/java/org/autojs/autojs/ui/main/scripts/ApkSignatureDetector.kt b/app/src/main/java/org/autojs/autojs/ui/main/scripts/ApkSignatureDetector.kt index 84fba56e..bbddac30 100644 --- a/app/src/main/java/org/autojs/autojs/ui/main/scripts/ApkSignatureDetector.kt +++ b/app/src/main/java/org/autojs/autojs/ui/main/scripts/ApkSignatureDetector.kt @@ -48,7 +48,7 @@ object ApkSignatureDetector { ApkSigningBlockUtils.findApkSignatureSchemeBlock(buf, id, null) }.isSuccess - private fun hasV1Signature(apkFile: File): Boolean { + fun hasV1Signature(apkFile: File): Boolean { JarFile(apkFile).use { jar -> var hasManifest = false var hasSF = false diff --git a/app/src/main/java/org/autojs/autojs/ui/main/scripts/EditableFileInfoDialogManager.kt b/app/src/main/java/org/autojs/autojs/ui/main/scripts/EditableFileInfoDialogManager.kt new file mode 100644 index 00000000..d49ebff5 --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/ui/main/scripts/EditableFileInfoDialogManager.kt @@ -0,0 +1,185 @@ +package org.autojs.autojs.ui.main.scripts + +import android.annotation.SuppressLint +import android.content.Context +import android.os.Build +import android.view.LayoutInflater +import android.view.View.MeasureSpec.UNSPECIFIED +import androidx.constraintlayout.widget.ConstraintLayout +import com.afollestad.materialdialogs.MaterialDialog +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.cancel +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import org.autojs.autojs.extension.MaterialDialogExtensions.makeTextCopyable +import org.autojs.autojs.extension.MaterialDialogExtensions.setCopyableTextIfAbsent +import org.autojs.autojs.external.fileprovider.AppFileProvider +import org.autojs.autojs.pio.PFiles +import org.autojs.autojs.runtime.api.Mime +import org.autojs.autojs.util.IntentUtils +import org.autojs.autojs.util.IntentUtils.SnackExceptionHolder +import org.autojs.autojs.util.StringUtils +import org.autojs.autojs.util.StringUtils.dropBom +import org.autojs.autojs6.R +import org.autojs.autojs6.databinding.EditableFileInfoDialogListItemBinding +import java.io.File +import java.nio.charset.Charset +import java.nio.file.Files + +object EditableFileInfoDialogManager { + + @JvmStatic + @SuppressLint("SetTextI18n") + fun showEditableFileInfoDialog(context: Context, file: File?, fileContentGetter: (() -> String)? = null) { + if (file == null || !file.canRead()) { + MaterialDialog.Builder(context) + .title(R.string.text_failed) + .content(R.string.file_not_exist_or_readable) + .show() + return + } + val binding = EditableFileInfoDialogListItemBinding.inflate(LayoutInflater.from(context)) + + val textUnknown = context.getString(R.string.text_unknown) + + // Create an independent Scope for the Dialog, bind its lifecycle with the Dialog. + // zh-CN: 针对 Dialog 独立创建一个 Scope, 生命周期与 Dialog 绑定. + val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate) + + val dialog = MaterialDialog.Builder(context) + .title(file.name) + .customView(binding.root, false) + .iconRes(R.drawable.ic_edit_smaller) + .limitIconToDefaultSize() + .positiveText(R.string.dialog_button_dismiss) + .positiveColorRes(R.color.dialog_button_default) + .show() + .apply { + makeTextCopyable { titleView } + setOnDismissListener { scope.cancel() } + iconView?.setOnClickListener { + IntentUtils.viewFile( + context = context, + path = file.path, + mimeType = Mime.TEXT_PLAIN, + fileProviderAuthority = AppFileProvider.AUTHORITY, + exceptionHolder = SnackExceptionHolder(view), + ) + } + } + + scope.launch { + dialog.setCopyableTextIfAbsent(binding.filePathValue, file.absolutePath) + + @Suppress("DEPRECATION") + val bytes: ByteArray? = withContext(Dispatchers.IO) { + runCatching { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + Files.readAllBytes(file.toPath()) + } else { + file.readBytes() + } + }.getOrNull() + } + when (bytes) { + null -> dialog.apply { + setCopyableTextIfAbsent(binding.byteCountValue, textUnknown) + setCopyableTextIfAbsent(binding.fileCharsetValue, textUnknown) + setCopyableTextIfAbsent(binding.lineCountValue, textUnknown) + setCopyableTextIfAbsent(binding.charCountValue, textUnknown) + setCopyableTextIfAbsent(binding.lineBreakValue, textUnknown) + setCopyableTextIfAbsent(binding.fileSizeValue, scope) { PFiles.getHumanReadableSize(file.length()) } + } + else -> dialog.apply { + val charsetMatch = StringUtils.detectCharset(bytes) + val charset = charsetMatch.charsetOrDefault() + val text = withContext(Dispatchers.IO) { + fileContentGetter?.invoke() ?: dropBom(bytes, charset).decodeToString() + } + setCopyableTextIfAbsent( + binding.fileCharsetValue, + charsetMatch.nameOrDefault(textUnknown), + charsetMatch.confidence?.takeUnless { it == 100 }?.let { + " [ ${context.getString(R.string.text_confidence_level)}: $it ]" + }, + ) + setCopyableTextIfAbsent(binding.lineBreakValue, scope) { + val hasLineBreaks = text.indexOf('\n') >= 0 || text.indexOf('\r') >= 0 + if (hasLineBreaks) detectLineBreak(text) else textUnknown + } + setCopyableTextIfAbsent(binding.fileSizeValue, getReadableSizeString(context, charset, bytes, text)) + setCopyableTextIfAbsent(binding.byteCountValue, getByteCountString(context, charset, bytes, text)) + setCopyableTextIfAbsent(binding.charCountValue, scope) { "${text.codePointCount(0, text.length)}" } + setCopyableTextIfAbsent(binding.lineCountValue, scope) { "${text.lineSequence().count()}" } + } + } + updateGuidelines(binding) + } + } + + private fun updateGuidelines(binding: EditableFileInfoDialogListItemBinding) { + val bindings = listOf( + binding.filePathLabel to binding.filePathGuideline, + binding.fileSizeLabel to binding.fileSizeGuideline, + binding.fileCharsetLabel to binding.fileCharsetGuideline, + binding.lineBreakLabel to binding.lineBreakGuideline, + binding.byteCountLabel to binding.byteCountGuideline, + binding.charCountLabel to binding.charCountGuideline, + binding.lineCountLabel to binding.lineCountGuideline, + ) + + @Suppress("DuplicatedCode") + val maxWidth = bindings.maxOfOrNull { it.first.apply { measure(UNSPECIFIED, UNSPECIFIED) }.measuredWidth } ?: return + + bindings.forEach { (_, guideline) -> + guideline.layoutParams = (guideline.layoutParams as ConstraintLayout.LayoutParams).also { + it.guideBegin = maxWidth + } + } + } + + private fun detectLineBreak(text: String): String { + var lf = 0 // \n + var crlf = 0 // \r\n + var cr = 0 // \r + + var i = 0 + while (i < text.length) { + val c = text[i] + if (c == '\r') { + if (i + 1 < text.length && text[i + 1] == '\n') { + crlf++; i++ // 跳过 \n + } else cr++ + } else if (c == '\n') lf++ + i++ + } + return when { + crlf > 0 && lf == 0 && cr == 0 -> "Windows (CRLF)" + lf > 0 && crlf == 0 && cr == 0 -> "Unix (LF)" + cr > 0 && crlf == 0 && lf == 0 -> "Mac (CR)" + else -> "Mixed" + } + } + + private fun getReadableSizeString(context: Context, charset: Charset, bytes: ByteArray, text: String): Pair { + val (size, suffix) = getByteCount(context, charset, bytes, text) + return PFiles.getHumanReadableSize(size) to suffix + } + + private fun getByteCountString(context: Context, charset: Charset, bytes: ByteArray, text: String): Pair { + val (size, suffix) = getByteCount(context, charset, bytes, text) + return "$size" to suffix + } + + private fun getByteCount(context: Context, charset: Charset, bytes: ByteArray, text: String): Pair { + return when (text) { + String(dropBom(bytes, charset), charset) -> { + bytes.size.toLong() to null + } + else -> text.toByteArray(charset).size.toLong() to " [ ${context.getString(R.string.text_estimated)} ]" + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/org/autojs/autojs/ui/main/scripts/MediaInfoDialogManager.kt b/app/src/main/java/org/autojs/autojs/ui/main/scripts/MediaInfoDialogManager.kt index 28458587..ac740063 100644 --- a/app/src/main/java/org/autojs/autojs/ui/main/scripts/MediaInfoDialogManager.kt +++ b/app/src/main/java/org/autojs/autojs/ui/main/scripts/MediaInfoDialogManager.kt @@ -53,7 +53,10 @@ object MediaInfoDialogManager { .neutralText(R.string.ellipsis_six) .neutralColorRes(R.color.dialog_button_unavailable) .show() - .apply { setOnDismissListener { scope.cancel() } } + .apply { + makeTextCopyable { titleView } + setOnDismissListener { scope.cancel() } + } scope.launch { val mediaInfo = MediaInfo() @@ -106,12 +109,9 @@ object MediaInfoDialogManager { } } - withContext(Dispatchers.Main) { - restoreEssentialViews(binding, context) - updateGuidelines(binding) - updateSplitLineVisibility(binding) - dialog.makeTextCopyable { it.titleView } - } + restoreEssentialViews(binding, context) + updateGuidelines(binding) + updateSplitLineVisibility(binding) when (val containerFormat = containerFormatDeferred.await()) { MEDIA_INFO_ERROR_OPENING_FILE -> { diff --git a/app/src/main/java/org/autojs/autojs/ui/project/BuildActivity.java b/app/src/main/java/org/autojs/autojs/ui/project/BuildActivity.java index 3941eb9c..b4f88f2c 100644 --- a/app/src/main/java/org/autojs/autojs/ui/project/BuildActivity.java +++ b/app/src/main/java/org/autojs/autojs/ui/project/BuildActivity.java @@ -420,7 +420,7 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa "- " + getString(R.string.text_download_and_install_autojs6_including_all_abis) + " [" + getString(R.string.text_recommended) + "]\n\n" + getString(R.string.text_download_link_for_autojs6) + ":\n" + getString(R.string.uri_autojs6_download_link)); - builder.positiveText(R.string.text_ok); + builder.positiveText(R.string.dialog_button_dismiss); builder.positiveColorRes(R.color.dialog_button_hint); MaterialDialogExtensions.widgetThemeColor(builder); MaterialDialog dialog = builder.show(); diff --git a/app/src/main/java/org/autojs/autojs/ui/shortcut/ShortcutCreateActivity.java b/app/src/main/java/org/autojs/autojs/ui/shortcut/ShortcutCreateActivity.java index 00aa1c64..297e09a3 100644 --- a/app/src/main/java/org/autojs/autojs/ui/shortcut/ShortcutCreateActivity.java +++ b/app/src/main/java/org/autojs/autojs/ui/shortcut/ShortcutCreateActivity.java @@ -90,7 +90,7 @@ public class ShortcutCreateActivity extends AppCompatActivity { .title(R.string.text_send_shortcut) .negativeText(R.string.dialog_button_cancel) .negativeColorRes(R.color.dialog_button_default) - .positiveText(R.string.text_ok) + .positiveText(R.string.dialog_button_confirm) .positiveColorRes(R.color.dialog_button_attraction) .onPositive((dialog, which) -> { createShortcut(); diff --git a/app/src/main/java/org/autojs/autojs/util/StringUtils.kt b/app/src/main/java/org/autojs/autojs/util/StringUtils.kt index f1a99d84..59e3896e 100644 --- a/app/src/main/java/org/autojs/autojs/util/StringUtils.kt +++ b/app/src/main/java/org/autojs/autojs/util/StringUtils.kt @@ -2,11 +2,15 @@ package org.autojs.autojs.util import android.content.res.Configuration import android.text.TextUtils +import com.ibm.icu.text.CharsetDetector +import com.ibm.icu.text.CharsetMatch import org.autojs.autojs.annotation.LocaleNonRelated import org.autojs.autojs.app.GlobalAppContext import org.autojs.autojs.core.pref.Language import org.autojs.autojs.extension.NumberExtensions.roundToString import org.opencv.core.Point +import java.nio.charset.Charset +import java.nio.charset.StandardCharsets import java.util.Locale import kotlin.math.min import kotlin.math.pow @@ -21,6 +25,14 @@ object StringUtils { private val globalAppContext by lazy { GlobalAppContext.get() } + private val localePref = mapOf( + Language.ZH_HANS.languageTag to listOf("GB18030", "GBK", "Big5"), + Language.ZH_HANT_HK.languageTag to listOf("Big5", "GB18030"), + Language.ZH_HANT_TW.languageTag to listOf("Big5", "GB18030"), + Language.JA.languageTag to listOf("Shift_JIS", "EUC-JP", "ISO-2022-JP"), + Language.KO.languageTag to listOf("EUC-KR") + ) + @JvmStatic fun str(@LocaleNonRelated resId: Int, vararg args: Any): String = globalAppContext.getString(resId, *args) @@ -230,4 +242,66 @@ object StringUtils { return "{${x.roundToString(scale)}, ${y.roundToString(scale)}}" } + @JvmStatic + fun detectCharset(bytes: ByteArray): CharsetMatchWrapper { + val matches = kotlin.runCatching { + CharsetDetector().apply { setText(bytes) }.detectAll() + }.getOrNull() ?: return CharsetMatchWrapper(null) + + matches.firstOrNull { + it.name.startsWith("UTF-", true) && it.confidence >= 30 + }?.let { + return CharsetMatchWrapper(it) + } + + val topScore = matches.maxOfOrNull { it.confidence } ?: -1 + val candidates = matches.filter { it.confidence == topScore } + val localeTag = Language.getPrefLanguage().getLocalCompatibleLanguageTag() + val prefList = localePref[localeTag] ?: emptyList() + val best = candidates.minByOrNull { + prefList.indexOf(it.name).takeIf { i -> i >= 0 } ?: Int.MAX_VALUE + } ?: candidates.first() + + return CharsetMatchWrapper(best) + } + + @JvmStatic + fun hasBom(bytes: ByteArray, charset: Charset): Boolean { + val bom = bomBytes(charset) + return bom.isNotEmpty() && bytes.take(bom.size).toByteArray().contentEquals(bom) + } + + @JvmStatic + fun bomBytes(charset: Charset): ByteArray = when (charset) { + StandardCharsets.UTF_8 -> byteArrayOf(0xEF.toByte(), 0xBB.toByte(), 0xBF.toByte()) + StandardCharsets.UTF_16LE -> byteArrayOf(0xFF.toByte(), 0xFE.toByte()) + StandardCharsets.UTF_16BE -> byteArrayOf(0xFE.toByte(), 0xFF.toByte()) + else -> ByteArray(0) + } + + @JvmStatic + fun dropBom(bytes: ByteArray, charset: Charset): ByteArray { + val bom = bomBytes(charset) + if (bom.isEmpty() || bytes.size < bom.size || !bytes.take(bom.size).toByteArray().contentEquals(bom)) { + return bytes + } + return bytes.copyOfRange(bom.size, bytes.size) + } + + class CharsetMatchWrapper(private val charsetMatch: CharsetMatch?) { + + val name: String? by lazy { charsetMatch?.name } + val confidence: Int? by lazy { charsetMatch?.confidence } + + fun charsetOrNull(): Charset? = runCatching { + name?.let { Charset.forName(it) } + }.getOrNull() + + @JvmOverloads + fun charsetOrDefault(defaultValue: Charset = StandardCharsets.UTF_8): Charset = charsetOrNull() ?: defaultValue + + fun nameOrDefault(defaultValue: String): String = name ?: defaultValue + + } + } \ No newline at end of file diff --git a/app/src/main/res/drawable-night/ic_edit_smaller.png b/app/src/main/res/drawable-night/ic_edit_smaller.png new file mode 100644 index 0000000000000000000000000000000000000000..efc2e875d3405d0a815f30cad9a4dcca7f1caf2b GIT binary patch literal 2603 zcmcgueNYtV9o_?xuTsWZ6Ezw)t5#Cn+r8!X_I8_7K8^@62b6C|QI_5JJ_>hx+%9l1 za|uE0jFhaK>|Bac+_n#ambw8fcbejc<&n~Fw_rG ziVawTFCdz4%0QDO7eHAxi3=o2q719nFdBhk%xh7Kq$q;a6B-?^(Q_olY2(nD9|ps@ zL^GFZe0nArd@^8GMR9TjQBhH$u831hE(@VyS(YFvf}(JUz~xGZ!n<*YymFSo2xP%! zb1F8;f%+KvBB@LAoO#th(N{S>~rEj1Py#87MSX+}R5Mxd)c6%U%tR$DiG-e7iCtA*~bOIt1$Wob0 z0LkT0=1N~SPActvt$OH#>fr!rX{bpOZRW~3p$tc}UxPx=h`hpoCs-6Xv*fb#FkzdWw*bQFuwZDQ zj9ijbBDr8-s7~WoVKQ;44q4$H0!TF)FqpI2W)nG@0hCD5B+k%!EpFCp0nQ78fb$|F zuzFgfkK={e`9?`7^L5rYf7<1uBtVY;MJ>_`8VxPbIL*Y7I9sHJCpd)DEX!*F$(zj# zKg*WxvcV6HFL{{Nr%Hs3EJKQMI+n%-iq_(Q(b722vPHPS=*$|x#8D(*d~Ws|giEo> zuyvI)-$xcGow+Nqp?*(ryx{Y?0TX;p1|l{yY@4GV-z)OW{0b|8q~Fr~>FBa#Rw{TG zNU*@#eW$sIZxS!_<=-w{CzyF1#R8mS^&$@RS`lY;Iv&?)8MX+(g7SJ;{Ao>dN`Kgl zKScTrw_xQR764aH0{h{~d_Q0Q=*bYi^>W%_#Q&Sm|L&o+6*kg81Q%@IZD6Z_4}r}F zIAEPza4Y!|Us8`C!M{p1CS<#tKil8!_*?wXceHnZdad@+me8dUwej(9y2BD{-NDbT zYG^qa@j^|6>PpWl6ipmk5My&As~Tc54#h<5jCm7FQH^Kl8~%9hxaE@z%j;L3FMa2P z9pR8=txQMqYZL0@ODrqz z?H$uhA;?FiLsJh1?{Ch3_e^=|e+pI49th1@U;5AMNXOt`POh~)(frj<&Mmwh+#B70 zX+_IRH$(2<-J!ho4`fO1#@jc;j+yN{I-{%46z|^m#$|2saBc(M7kqvha(dr;PZVr? zsq*Fx@z!#BJaJ-y>6HWXyDxWSO`J^scpnuRIkM@CL&e9QnOw59D9W;D^b;D{|G6sV z-!*dZn%|G!*%Ng5qtNSDp3mA=nt3IwtKspn6a(_%%cuYKi?k;v*R0805#_m>Gn^ND zVarv0Yr^=x;r5`yuCe~(yYD7#Sbehnwx{lmO_OInOZVz!Pv46*M@g{549!M%1Qto+z54{cthB7=gdF9<-%*!7d34K55lIt#bPOCqsUD`$?R=%)g1#)7K zG2*A>4(}chGTi&?t&*wpOLsb6WxRZNplajh{;ApxJ?stdpDtsRqyFvt7Y{U^-%`-D z4ygKTvT_EFq_cN*eVy$u6!&D_w{MSY;?GX3XgMF2wyW+U6TizgdUEVuWW%2ysn0n( zu@L1~*Jn9D2y!;I5|+^@6yUF}PMuUEAbQu?ThAQvn)81!`JSx~nWoO&|sm(i=pUd+UoJ#Jg zl)~A@so{f372{3L{jWEAIT8E7eNJa^_T$ZMTZl2F@2y`Bsjs~q9OV7#`40zrL%A(SZ$8!?W*-&j j|HjKbP`#Tvw|je@ritpGb#%x0{?4T)ry0G8g*E>L3Kp#q literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/ic_edit_smaller.png b/app/src/main/res/drawable/ic_edit_smaller.png new file mode 100644 index 0000000000000000000000000000000000000000..9ed332918e80cab22670ed5d94eee0494322d092 GIT binary patch literal 2934 zcmbVN2~-o;8lDir3RMuRi0cp#5J@HpfsjB1BrE}gtb$dLFd1SX$%JHBr3m6iMbL_h zilFa+_TgT|2dE^-B5sHZf*=YS)GC5?!=eY?1c77we6Q#Ao|(D--246e|KFSC@8>mH zf0jM~0F!y%+(3Me)V|+Lz`x!*RA&HyI8E&C?$1Rr&`ThefpqEu0I=QxM@ANQJ$t0N zYN1y9`v(VV=4ob{PBkr2rxj*w%h;Qt9cHwOay1Q9Z`RU~3$%+col2*sp08IosMTuu ziq>0oS9WDE)caQX2VcS$(lauutrwIz;@sT^M5232GS6)ikqCcFBxZUCCXCPoEuG-K z-40*JG1HduVmxpRF;ki5h6F^XcxJ6XR8ms19`;EKEL|c;;&?H#)9XbMinIW?w16mH zj6M!-o}!13h&`W-bq8v%JL{SgLySB5MqIAvLf5b@uiUnnxhli~rW@+Cc7p1I>PU5$ z+DN^dt`)b6F43+kSRvW+Wut|jDtcQZJ`>;W(JQtF)#$OjXHXW#T1 zVbd>=@@(F^mxppageTXOKQlSad*t~j)WXK1$0C>49#WvNTcl+r};h8P=hS`+&qhi4Vi>a)zhf7j5|Ox;aop0xUNmah+A zKMdWVn~!a}qv@>kN1y5qi8E` z9Vo&AKHk2yC@XY0yhwTH$=yz;cLRC-MM?PsVZB#|M0+7_#Jto4!^?*{HyZMbmb$10 zE4$WySeCK+$k5p#<)`8Kz+}LX@u2Q(JKiOeIX%&KDe1Fg# zRUjaXLM6jgDivh1C^RMwrZb~$@jj;0A*v%pb0E_k*;G24VF!*560S}mjAjRNJx7({ ze;m>p43o1VC^0dSl4wUk6(WenVzD499ir38ID)K9mSKV;3HK7U-tS8b6>$5kjXj|AL}(SUpvtqe|1WHp?p**j!yn6l*wkW{s6^mMkv4pe+d@C>}XUW72pnwr2-KG z$z>uEI37l}J1RjHxMJKo+L!A*{MJyQ(P9a{@#XC?Vkw``=E;m}C506pq(se~e%FfATL=i1GFl zNdC4QZBuH?hV3m@;t5S2?V2DYZj_RU!I4T~3t(*ra7eH=^@xx(x-988dtdbR7#u$=wB-0Ph5w8nbchT; z-4ysSc7NZ+jR2tYg2#0WPAYi0|C+3s`rW4C;+;!3n?xE)!oUfS-p_H}m^7{SM;(LR zO%=sKuC5zvUw|34Iw3Y8P*k-(E!^yk_vV~CS#yip7UyV&dmlACO`Z32AdA79P zeEPW`f&2gQ^cwGbb@1AU4eqHm@Y_l6P7{lhvQ$P!ZFQY}1Wi80!l^z}MmQD~$Ya*j z^Z^>{-4@3_>38c0+e&%APmJv*zWr_a4s6p$0a4g?xA;JJgdI?rxwLD~lN`e0#;IqO zrzM9b+${TN?&(cRf$WfR_g;tJ4W0E3BGY}1F9k^lPnr>gNx5_H=bhl(Dt>4<5#-Ps zIjeS@IJxK!x|#Uu$#CApa+__#IW}l=&Sab4zYS)e z(%AsW&pozh4VENmlCEml_=rzl=mlFO4hxM@%UJ(6mWbRi&$UXuNxYqcdmkg1}Ro zw;lpC_Ejfy7U~Irx4R1}2WOIw?r(xzE1Q0?&pjREqXKSZ2jyg?_^bmg>yu~guN414 z$e$%LwVG??;#w40U@+H;>FQ_e(z@&=5j2+;3U;;(5VmhG@DdlK5v&`77|=tqt53Ug z(9YN4IzLCucmdzX`p@efG!;GeYPC-fdW;!1nHN^pAMMvmk13c`l4=6vr9EtL4A-%+ zcuHgVB?6|uB5_MPKE5Xm&YXI6ev8U>P`6=Al}a;gH3wikp7XEpA6DXX^Mx0K#PaSA zM=3GYEbrk}eE#G>QI*8C>p3!PRb_Fnb;78Ae(71AEd!JN{hb=AfGyi_qI&n%mVt@> zZ4AF*VE48=%=GxjZwf`v=A9Hy6FMS3l3gk9%TC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/menu_editor.xml b/app/src/main/res/menu/menu_editor.xml index 0886f4b7..ec683392 100644 --- a/app/src/main/res/menu/menu_editor.xml +++ b/app/src/main/res/menu/menu_editor.xml @@ -141,8 +141,8 @@ app:showAsAction="never" /> تفاصيل لون الثيم لا يمكن معالجة الملف لم يتم حفظ المحتوى ، هل أنت متأكد من الخروج؟ + بايت + حروف + ترميز + مسار + حجم + سطر + أسطر اتبع النظام مستندات محلية مستندات عبر الإنترنت @@ -223,6 +230,12 @@ يتم تعطيل خدمة إمكانية الوصول وتوقف البرنامج النصي لم يتم تنشيط خدمة إمكانية الوصول لا توجد خدمة إمكانية الوصول + لا توجد تطبيقات متاحة لاستعراض هذا الرابط + لا توجد تطبيقات متاحة لتحرير هذا الملف + لا توجد تطبيقات متاحة لتثبيت هذا الملف + لا توجد تطبيقات متاحة لتشغيل هذا الملف + لا توجد تطبيقات متاحة لإرسال هذا الملف + لا توجد تطبيقات متاحة لعرض هذا الملف لا يوجد إذن \"عرض عبر التطبيقات الأخرى\" لا يوجد إذن للوصول إلى Shizuku لا يوجد إذن \"نشر الإخطارات\" @@ -265,6 +278,7 @@ نوع نتيجة غير معروف {name: %s ، params: %s} محدد غير معروف {الاسم: %s ، اكتب: %s} نوع غير معروف: %s + لا يمكن ضغط تنسيق WebP-Lossless باستخدام معامل الجودة؛ استخدم JPEG/PNG/WebP-Lossy بدلاً من ذلك الملف غير موجود أو قابلاً للقراءة: %s خدمة مقدمة AutoJs6 انقر لإطلاق AutoJs6 @@ -470,6 +484,7 @@ تم نسخ الأمر إلى الحافظة تعليق التوافق + ثقة تكوين هل أنت متأكد من مسح جميع السجلات؟ هل أنت متأكد من مسح جميع العناصر؟ @@ -560,6 +575,7 @@ خطأ فشل نسخ الملف: %s تقرير الشوائب + تقديري نفذ - اعدم تنفيذ الرمز [%s] انتهى في %s.\n @@ -594,6 +610,7 @@ فشل في إرسال إدخالات السجل فشل في كتابة الملف ملف + تفاصيل الملف ملف موجود بالفعل مستكشف الملفات امتدادات الملف @@ -632,6 +649,8 @@ الملفات والمجلدات المخفية إخفاء زر الإخفاء + إخفاء هذه العقدة + إخفاء العقدة ذات الإطار المماثل التاريخ أيقونة تجاهل تحسينات البطارية @@ -1039,14 +1058,5 @@ اكتب إعدادات الأمان إعدادات النظام الآمنة ، التي تحتوي على تفضيلات النظام التي يمكن أن تقرأها التطبيقات ولكن لا يُسمح لها بالكتابة.\nهذه هي لتفضيلات يجب على المستخدم تعديلها بشكل صريح من خلال واجهة المستخدم لتطبيق النظام.\nمع إذن إعدادات النظام الآمن ، يمكن للتطبيقات العادية تعديل الإعدادات الآمنة مباشرة (مثل خدمة إمكانية الوصول). كتابة إعدادات النظام - إخفاء هذه العقدة - إخفاء العقدة ذات الإطار المماثل - لا توجد تطبيقات متاحة لتحرير هذا الملف - لا توجد تطبيقات متاحة لاستعراض هذا الرابط - لا توجد تطبيقات متاحة لتثبيت هذا الملف - لا توجد تطبيقات متاحة لعرض هذا الملف - لا توجد تطبيقات متاحة لإرسال هذا الملف - لا توجد تطبيقات متاحة لتشغيل هذا الملف - لا يمكن ضغط تنسيق WebP-Lossless باستخدام معامل الجودة؛ استخدم JPEG/PNG/WebP-Lossy بدلاً من ذلك diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml index ebfe355a..934ec7f5 100644 --- a/app/src/main/res/values-en/strings.xml +++ b/app/src/main/res/values-en/strings.xml @@ -116,6 +116,13 @@ Theme color details Cannot process file The content has not been saved, are you sure to exit? + Bytes + Chars + Charset + Path + Size + EOL + Lines Follow system Local docs Online docs @@ -218,6 +225,12 @@ Accessibility service is disabled and the script has stopped Accessibility service is not activated No accessibility service + No applications available for browsing this link + No applications available for editing this file + No applications available for installing this file + No applications available for playing this file + No applications available for sending this file + No applications available for viewing this file No \"display over other apps\" permission No permission to access Shizuku No \"post notifications\" permission @@ -260,6 +273,7 @@ Unknown result type {name: %s, params: %s} Unknown selector {name: %s, type: %s} Unknown type: %s + Format WebP-Lossless cannot be compressed with a quality parameter, use JPEG/PNG/WebP-Lossy instead File does not exist or readable: %s AutoJs6 foreground service Click to launch AutoJs6 @@ -465,6 +479,7 @@ Command copied to clipboard Comment Compatibility + Confidence Config Are you sure to clear all histories? Are you sure to clear all items? @@ -555,6 +570,7 @@ Error Failed to copy file: %s Bug report + Estimated Execute Execute code [%s] finished in %s seconds.\n @@ -589,6 +605,7 @@ Failed to send log entries Failed to write file File + File details File already exists File explorer File extensions @@ -627,6 +644,8 @@ Hidden files and folders Hide Hide button + Hide this node + Hide same frame nodes Histories Icon Ignore battery optimizations @@ -1034,14 +1053,5 @@ Write security settings Secure system settings, containing system preferences that applications can read but are not allowed to write.\nThese are for preferences that the user must explicitly modify through the UI of a system app.\nWith secure system settings permission, normal applications can directly modify the secure settings (such as accessibility service). Write system settings - Hide this node - Hide same frame nodes - No applications available for editing this file - No applications available for browsing this link - No applications available for installing this file - No applications available for viewing this file - No applications available for sending this file - No applications available for playing this file - Format WebP-Lossless cannot be compressed with a quality parameter, use JPEG/PNG/WebP-Lossy instead diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 16e107ba..224d5efe 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -119,6 +119,13 @@ Detalles del color del tema No se puede procesar el archivo El contenido no se ha guardado, ¿está seguro de salir? + Bytes + Caracteres + Charset + Ruta + Tamaño + Salto + Líneas Siga el sistema Documentos locales Documentos en línea @@ -221,6 +228,12 @@ El servicio de accesibilidad está desactivado y el script se ha detenido El servicio de accesibilidad no está activado No hay servicio de accesibilidad + No hay aplicaciones disponibles para abrir este enlace + No hay aplicaciones disponibles para editar este archivo + No hay aplicaciones disponibles para instalar este archivo + No hay aplicaciones disponibles para reproducir este archivo + No hay aplicaciones disponibles para enviar este archivo + No hay aplicaciones disponibles para ver este archivo No hay permiso de \"mostrar sobre otras aplicaciones\". No hay permiso para acceder a Shizuku Sin permiso para \"enviar notificaciones\" @@ -263,6 +276,7 @@ Tipo de resultado desconocido {nombre: %s, parámetro: %s} Selector desconocido {nombre: %s, tipo: %s} Tipo desconocido: %s + El formato WebP-Lossless no se puede comprimir con un parámetro de calidad; usa JPEG/PNG/WebP-Lossy en su lugar El archivo no existe o no se puede leer: %s Servicio de primer plano de AutoJs6 Haga clic para iniciar AutoJs6 @@ -468,6 +482,7 @@ Comando copiado en el portapapeles Comente Compatibilidad + Confianza Configuración ¿Está seguro de borrar todos los historiales? ¿Seguro que desea borrar todos los elementos? @@ -558,6 +573,7 @@ Error No se ha podido copiar el archivo: %s Informe de error + Estimado Ejecutar Ejecutar código [%s] terminó en %s segundos.\n @@ -592,6 +608,7 @@ Error al enviar entradas de registro Fallo al escribir el archivo Archivo + Detalles del archivo El archivo ya existe Explorador de archivos Extensiones de archivo @@ -630,6 +647,8 @@ Archivos y carpetas ocultos Ocultar Botón de ocultar + Ocultar este nodo + Ocultar nodo del mismo marco Historiales Icono Ignorar las optimizaciones de la batería @@ -1037,14 +1056,5 @@ Escribir la configuración de seguridad Ajustes de seguridad del sistema, que contienen preferencias del sistema que las aplicaciones pueden leer pero no pueden escribir.\nSe trata de preferencias que el usuario debe modificar explícitamente a través de la interfaz de usuario de una aplicación del sistema.\nCon el permiso de configuración segura del sistema, las aplicaciones normales pueden modificar directamente la configuración segura (como el servicio de accesibilidad). Escribir la configuración del sistema - Ocultar este nodo - Ocultar nodo del mismo marco - No hay aplicaciones disponibles para editar este archivo - No hay aplicaciones disponibles para abrir este enlace - No hay aplicaciones disponibles para instalar este archivo - No hay aplicaciones disponibles para ver este archivo - No hay aplicaciones disponibles para enviar este archivo - No hay aplicaciones disponibles para reproducir este archivo - El formato WebP-Lossless no se puede comprimir con un parámetro de calidad; usa JPEG/PNG/WebP-Lossy en su lugar diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 68ba01cd..5965e13a 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -119,6 +119,13 @@ Détails de la couleur du thème Cannot process file Le contenu n\'a pas été enregistré, êtes-vous sûr de vouloir quitter ? + Octets + Caractères + Encodage + Chemin + Taille + Saut + Lignes Suivre le système Documents locaux Documents en ligne @@ -221,6 +228,12 @@ Le service d\'accessibilité est désactivé et le script s\'est arrêté. Le service d\'accessibilité n\'est pas activé. No accessibility service + Aucune application disponible pour parcourir ce lien + Aucune application disponible pour modifier ce fichier + Aucune application disponible pour installer ce fichier + Aucune application disponible pour lire ce fichier + Aucune application disponible pour envoyer ce fichier + Aucune application disponible pour afficher ce fichier Aucune permission \"display over other apps\" Pas de permission pour accéder à Shizuku Pas d\'autorisation pour les \"notifications d\'envoi\" @@ -263,6 +276,7 @@ Type de résultat inconnu {nom : %s, params : %s} Sélecteur inconnu {nom : %s, type : %s} Type inconnu : %s + Le format WebP-Lossless ne peut pas être compressé avec un paramètre de qualité ; utilisez plutôt JPEG/PNG/WebP-Lossy Le fichier n\'existe pas ou n\'est pas lisible : %s Service d\'avant-plan AutoJs6 Cliquez pour lancer AutoJs6 @@ -468,6 +482,7 @@ Commande copiée dans le presse-papiers Commentaire Compatibilité + Confiance Configuration Êtes-vous sûr de vouloir effacer tous les historiques ? Voulez-vous vraiment effacer tous les éléments ? @@ -558,6 +573,7 @@ Erreur Failed to copy file : %s Rapport de bug + Estimé Exécuter Exécuter le code [%s] finished in %s seconds.\n @@ -592,6 +608,7 @@ Échec de l\'envoi des entrées de journal Fail to write file Fichier + Détails du fichier Fichier déjà existant Explorateur de fichiers Extensions de fichier @@ -630,6 +647,8 @@ Fichiers et dossiers cachés Cacher Bouton de cacher + Masquer ce nœud + Masquer le nœud du même cadre Histoires Icône Ignorer les optimisations de la batterie. @@ -1037,14 +1056,5 @@ Écrire les paramètres de sécurité. Paramètres de sécurité du système, contenant les préférences du système que les applications peuvent lire mais ne sont pas autorisées à écrire.\nIl s\'agit des préférences que l\'utilisateur doit explicitement modifier par le biais de l\'interface utilisateur d\'une application système.\nAvec l\'autorisation de paramètres de sécurité du système, les applications normales peuvent directement modifier les paramètres de sécurité (comme le service d\'accessibilité). Écrire les paramètres système - Masquer ce nœud - Masquer le nœud du même cadre - Aucune application disponible pour modifier ce fichier - Aucune application disponible pour parcourir ce lien - Aucune application disponible pour installer ce fichier - Aucune application disponible pour afficher ce fichier - Aucune application disponible pour envoyer ce fichier - Aucune application disponible pour lire ce fichier - Le format WebP-Lossless ne peut pas être compressé avec un paramètre de qualité ; utilisez plutôt JPEG/PNG/WebP-Lossy diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 5b8e64d2..7ecb83aa 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -120,6 +120,13 @@ テーマカラー詳細 ファイルを処理できません 内容が保存されていませんので, 本当に終了しますか? + バイト数 + 文字数 + 文字コード + パス + サイズ + 改行 + 行数 システムに従ってください ローカルドキュメント オンラインドキュメント @@ -222,6 +229,12 @@ アクセシビリティサービスが無効で, スクリプトが停止しています アクセシビリティサービスが有効になっていない アクセシビリティ・サービスがありません + このリンクを閲覧できるアプリがありません + このファイルを編集できるアプリがありません + このファイルをインストールできるアプリがありません + このファイルを再生できるアプリがありません + このファイルを送信できるアプリがありません + このファイルを表示できるアプリがありません 他のアプリの上に表示する」権限がない Shizuku にアクセスする権限がありません \"投稿通知\" 許可なし @@ -264,6 +277,7 @@ 不明な結果タイプ {name: %s, params: %s} 不明なセレクタ {name: %s, type: %s} です 不明なタイプ: %s + WebP-Lossless 形式は品質パラメータで圧縮できません, 代わりに JPEG/PNG/WebP-Lossy を使用してください ファイルが存在しないか, 読み取り可能でない: %s AutoJs6 のフォアグラウンド サービス クリックすると, AutoJs6 が起動します @@ -469,6 +483,7 @@ クリップボードにコピーされたコマンド コメント 互換性 + 信頼度 設定 すべての履歴をクリアしてもよろしいですか? すべての項目を削除しますか? @@ -559,6 +574,7 @@ エラー ファイルのコピーに失敗しました. %s バグレポート + 推定 実行 実行コード [%s] は %s 秒で終了しました @@ -593,6 +609,7 @@ ログ・エントリの送信に失敗しました ファイルの書き込みに失敗しました ファイル + ファイルの詳細 ファイルは既に存在しています ファイルエクスプローラー ファイル拡張子 @@ -631,6 +648,8 @@ 隠しファイル・隠しフォルダー 隠す 隠しボタン + このノードを隠す + 同じフレームのノードを隠す ヒストリー アイコン バッテリーの最適化を無視する @@ -1038,14 +1057,5 @@ セキュリティ設定の書き込み アプリケーションが読み取ることはできるが, 書き込むことはできないシステム環境設定を含む, 安全なシステム設定です.\nこれは, ユーザーがシステムアプリの UI を通じて明示的に変更する必要がある環境設定のためのものです.\nセキュアなシステム設定を許可すると, 通常のアプリケーションはセキュアな設定 (アクセシビリティサービスなど) を直接変更できるようになります システム設定の書き込み - このノードを隠す - 同じフレームのノードを隠す - このファイルを編集できるアプリがありません - このリンクを閲覧できるアプリがありません - このファイルをインストールできるアプリがありません - このファイルを表示できるアプリがありません - このファイルを送信できるアプリがありません - このファイルを再生できるアプリがありません - WebP-Lossless 形式は品質パラメータで圧縮できません, 代わりに JPEG/PNG/WebP-Lossy を使用してください diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 93155d74..d20ea9c9 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -121,6 +121,13 @@ 테마 색상 세부정보 파일을 처리 할 수 없습니다 콘텐츠가 저장되지 않았습니다. 나가시겠습니까? + 바이트수 + 문자수 + 문자셋 + 경로 + 크기 + 줄바꿈 + 줄수 시스템을 따르십시오 현지 문서 온라인 문서 @@ -223,6 +230,12 @@ 접근성 서비스가 비활성화되고 스크립트가 중지되었습니다 접근성 서비스는 활성화되지 않습니다 접근성 서비스가 없습니다 + 이 링크를 탐색할 수 있는 앱이 없습니다 + 이 파일을 편집할 수 있는 앱이 없습니다 + 이 파일을 설치할 수 있는 앱이 없습니다 + 이 파일을 재생할 수 있는 앱이 없습니다 + 이 파일을 전송할 수 있는 앱이 없습니다 + 이 파일을 볼 수 있는 앱이 없습니다 \"다른 앱 위에 표시\"권한이 없습니다 Shizuku 에 액세스할 수 있는 권한이 없습니다 \"게시물 알림\" 권한 없음 @@ -265,6 +278,7 @@ 알 수없는 결과 유형 {이름: %s, 매개 변수: %s} 알 수없는 선택기 {이름: %s, 유형: %s} 알 수없는 유형: %s + WebP-Lossless 형식은 품질 파라미터로 압축할 수 없습니다, 대신 JPEG/PNG/WebP-Lossy를 사용하세요 파일이 존재하지 않거나 읽을 수 없습니다: %s AutoJs6 전경 서비스 AutoJs6 을 시작하려면 클릭하십시오 @@ -470,6 +484,7 @@ 클립 보드에 복사 된 명령 논평 호환성 + 신뢰도 구성 모든 기록을 삭제하시겠습니까? 모든 항목을 삭제하시겠습니까? @@ -560,6 +575,7 @@ 오류 파일을 복사하지 못했습니다: %s 버그 보고서 + 추정 실행하다 코드를 실행하십시오 [%s] 는 %s 초 만에 완료되었습니다.\n @@ -594,6 +610,7 @@ 로그 항목을 보내지 못했습니다 파일을 쓰지 못했습니다 파일 + 파일 세부정보 존재하는 파일입니다 파일 탐색기 파일 확장자 @@ -632,6 +649,8 @@ 숨겨진 파일과 폴더 숨기기 버튼 숨기기 + 이 노드를 숨기기 + 동일 프레임의 노드를 숨기기 역사 배터리 최적화를 무시합니다 @@ -1039,14 +1058,5 @@ 보안 설정을 작성하십시오 애플리케이션이 읽을 수 있지만 쓸 수없는 시스템 환경 설정을 포함하는 보안 시스템 설정.\n이들은 사용자가 시스템 앱의 UI 를 통해 명시 적으로 수정 해야하는 선호도입니다.\n보안 시스템 설정 권한을 사용하면 일반 애플리케이션이 보안 설정 (예: 접근성 서비스)을 직접 수정할 수 있습니다. 시스템 설정을 작성하십시오 - 이 노드를 숨기기 - 동일 프레임의 노드를 숨기기 - 이 파일을 편집할 수 있는 앱이 없습니다 - 이 링크를 탐색할 수 있는 앱이 없습니다 - 이 파일을 설치할 수 있는 앱이 없습니다 - 이 파일을 볼 수 있는 앱이 없습니다 - 이 파일을 전송할 수 있는 앱이 없습니다 - 이 파일을 재생할 수 있는 앱이 없습니다 - WebP-Lossless 형식은 품질 파라미터로 압축할 수 없습니다, 대신 JPEG/PNG/WebP-Lossy를 사용하세요 diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 1e7da599..e86ef6d3 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -119,6 +119,13 @@ Детали цвета темы Невозможно обработать файл Содержимое не было сохранено, вы уверены в выходе? + Байты + Символы + Кодировка + Путь + Размер + Перенос + Строки Следовать за системой Локальные документы Онлайн-документы @@ -221,6 +228,12 @@ Служба доступности отключена, и сценарий остановлен Служба доступности не активирована Нет службы доступности + Нет приложений для просмотра этой ссылки + Нет приложений для редактирования этого файла + Нет приложений для установки этого файла + Нет приложений для воспроизведения этого файла + Нет приложений для отправки этого файла + Нет приложений для просмотра этого файла Нет разрешения \"отображать поверх других приложений\" Нет разрешения на доступ к Shizuku Нет разрешения на \"уведомления о сообщениях\" @@ -263,6 +276,7 @@ Неизвестный тип результата {имя: %s, params: %s} Неизвестный селектор {имя: %s, тип: %s} Неизвестный тип: %s + Формат WebP-Lossless нельзя сжать с параметром качества; используйте вместо этого JPEG/PNG/WebP-Lossy \"Файл не существует или не доступен для чтения: %s\". Служба AutoJs6 в фоновом режиме Нажмите для запуска AutoJs6 @@ -468,6 +482,7 @@ Команда скопирована в буфер обмена Комментарий Совместимость + Доверие Конфигурация Вы уверены, что хотите очистить всю историю? Вы уверены, что хотите удалить все элементы? @@ -558,6 +573,7 @@ Ошибка Не удалось скопировать файл: %s Отчет об ошибке + Оценка Выполнить Код выполнения [%s] завершилось через %s секунд.\n @@ -592,6 +608,7 @@ Не удалось отправить записи журнала Не удалось записать файл Файл + Сведения о файле Файл уже существует Проводник файлов Расширения файлов @@ -630,6 +647,8 @@ Скрытые файлы и папки Скрыть Кнопка скрытия + Скрыть этот узел + Скрыть узел того же фрейма Истории Значок Игнорировать оптимизацию батареи @@ -1037,14 +1056,5 @@ Параметры безопасности записи Настройки безопасности системы, содержащие системные предпочтения, которые приложения могут читать, но не имеют права записывать.\nОни предназначены для параметров, которые пользователь должен явно изменить через пользовательский интерфейс системного приложения.\nПри наличии разрешения на безопасные системные настройки обычные приложения могут напрямую изменять безопасные настройки (например, служба доступности). Запись системных настроек - Скрыть этот узел - Скрыть узел того же фрейма - Нет приложений для редактирования этого файла - Нет приложений для просмотра этой ссылки - Нет приложений для установки этого файла - Нет приложений для просмотра этого файла - Нет приложений для отправки этого файла - Нет приложений для воспроизведения этого файла - Формат WebP-Lossless нельзя сжать с параметром качества; используйте вместо этого JPEG/PNG/WebP-Lossy diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index e0f97fdb..6a6e0846 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -117,6 +117,13 @@ 主題色詳情 無法處理文件 內容尚未保存, 確定要退出嗎 + 字節數 + 字符數 + 編碼 + 路徑 + 大小 + 換行 + 總行數 跟隨系統 本地文檔 在線文檔 @@ -219,6 +226,12 @@ 無障礙服務未啓用 無障礙服務未啓用 沒有無障礙服務 + 未找到用於瀏覽該鏈接的應用 + 未找到用於編輯該文件的應用 + 未找到用於安裝該文件的應用 + 未找到用於播放該文件的應用 + 未找到用於發送該文件的應用 + 未找到用於查看該文件的應用 缺少 \"顯示在其他應用上層\" 權限 缺少 Shizuku 訪問權限 缺少 \"發佈通知\" 權限 @@ -261,6 +274,7 @@ 未知結果類型 {名稱: %s, 參數: %s} 未知選擇器 {名稱: %s, 類型: %s} 未知類型: %s + WebP-Lossless 格式無法使用 quality 質量參數進行壓縮, 可改用 JPEG/PNG/WebP-Lossy 文件不存在或不可讀: %s AutoJs6 前台服務 點擊返回 AutoJs6 主界面 @@ -466,6 +480,7 @@ 指令已複製到剪貼板 註釋 兼容性 + 置信度 配置 是否確定清空歷史記錄 是否確定清空全部記錄 @@ -556,6 +571,7 @@ 錯誤 文件複製失敗: %s 錯誤報告 + 預估 執行 執行代碼 [%s] 運行結束 (用時 %s 秒)\n @@ -590,6 +606,7 @@ 日誌條目發送失敗 文件寫入失敗 文件 + 文件詳情 文件已存在 文件管理器 文件擴展名 @@ -628,6 +645,8 @@ 隱藏文件和文件夾 隱藏 隱藏按鈕 + 隱藏此節點 + 隱藏同框節點 歷史記錄 圖標 忽略電池優化 @@ -1035,14 +1054,5 @@ 修改安全設置 安全設置包含應用程序可讀但不可寫入的設置選項, 這些選項只能由 UI 或系統級別應用修改.\n被授予 \"修改安全設置權限\" 後, 普通應用可直接修改上述安全設置 (例如無障礙服務). 修改系統設置 - 隱藏此節點 - 隱藏同框節點 - 未找到用於編輯該文件的應用 - 未找到用於瀏覽該鏈接的應用 - 未找到用於安裝該文件的應用 - 未找到用於查看該文件的應用 - 未找到用於發送該文件的應用 - 未找到用於播放該文件的應用 - WebP-Lossless 格式無法使用 quality 質量參數進行壓縮, 可改用 JPEG/PNG/WebP-Lossy diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 69a08d8b..0ea4a6c7 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -117,6 +117,13 @@ 主題色詳情 無法處理檔案 內容尚未儲存, 確定要退出嗎 + 位元組數 + 字元數 + 編碼 + 路徑 + 大小 + 換行 + 總行數 跟隨系統 本地文件 線上文件 @@ -219,6 +226,12 @@ 無障礙服務未啟用 無障礙服務未啟用 沒有無障礙服務 + 未找到用於瀏覽該連結的應用 + 未找到用於編輯該檔案的應用 + 未找到用於安裝該檔案的應用 + 未找到用於播放該檔案的應用 + 未找到用於傳送該檔案的應用 + 未找到用於檢視該檔案的應用 缺少 \"顯示在其他應用上層\" 許可權 缺少 Shizuku 訪問許可權 缺少 \"釋出通知\" 許可權 @@ -261,6 +274,7 @@ 未知結果型別 {名稱: %s, 引數: %s} 未知選擇器 {名稱: %s, 型別: %s} 未知型別: %s + WebP-Lossless 格式無法使用 quality 質量引數進行壓縮, 可改用 JPEG/PNG/WebP-Lossy 檔案不存在或不可讀: %s AutoJs6 前臺服務 點選返回 AutoJs6 主介面 @@ -466,6 +480,7 @@ 指令已複製到剪貼簿 註釋 相容性 + 置信度 配置 是否確定清空歷史記錄 是否確定清空全部記錄 @@ -556,6 +571,7 @@ 錯誤 檔案複製失敗: %s 錯誤報告 + 預估 執行 執行程式碼 [%s] 執行結束 (用時 %s 秒)\n @@ -590,6 +606,7 @@ 日誌條目傳送失敗 檔案寫入失敗 檔案 + 檔案詳情 檔案已存在 檔案管理器 副檔名 @@ -628,6 +645,8 @@ 隱藏檔案和資料夾 隱藏 隱藏按鈕 + 隱藏此節點 + 隱藏同框節點 歷史記錄 圖示 忽略電池最佳化 @@ -1035,14 +1054,5 @@ 修改安全設定 安全設定包含應用程式可讀但不可寫入的設定選項, 這些選項只能由 UI 或系統級別應用修改.\n被授予 \"修改安全設定許可權\" 後, 普通應用可直接修改上述安全設定 (例如無障礙服務). 修改系統設定 - 隱藏此節點 - 隱藏同框節點 - 未找到用於編輯該檔案的應用 - 未找到用於瀏覽該連結的應用 - 未找到用於安裝該檔案的應用 - 未找到用於檢視該檔案的應用 - 未找到用於傳送該檔案的應用 - 未找到用於播放該檔案的應用 - WebP-Lossless 格式無法使用 quality 質量引數進行壓縮, 可改用 JPEG/PNG/WebP-Lossy diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index 57921b3d..1564de5c 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -117,6 +117,13 @@ 主题色详情 无法处理文件 内容尚未保存, 确定要退出吗 + 字节数 + 字符数 + 编码 + 路径 + 大小 + 换行 + 总行数 跟随系统 本地文档 在线文档 @@ -219,6 +226,12 @@ 无障碍服务未启用 无障碍服务未启用 没有无障碍服务 + 未找到用于浏览该链接的应用 + 未找到用于编辑该文件的应用 + 未找到用于安装该文件的应用 + 未找到用于播放该文件的应用 + 未找到用于发送该文件的应用 + 未找到用于查看该文件的应用 缺少 \"显示在其他应用上层\" 权限 缺少 Shizuku 访问权限 缺少 \"发布通知\" 权限 @@ -261,6 +274,7 @@ 未知结果类型 {名称: %s, 参数: %s} 未知选择器 {名称: %s, 类型: %s} 未知类型: %s + WebP-Lossless 格式无法使用 quality 质量参数进行压缩, 可改用 JPEG/PNG/WebP-Lossy 文件不存在或不可读: %s AutoJs6 前台服务 点击返回 AutoJs6 主界面 @@ -466,6 +480,7 @@ 指令已复制到剪贴板 注释 兼容性 + 置信度 配置 是否确定清空历史记录 是否确定清空全部记录 @@ -556,6 +571,7 @@ 错误 文件复制失败: %s 错误报告 + 预估 执行 执行代码 [%s] 运行结束 (用时 %s 秒)\n @@ -590,6 +606,7 @@ 日志条目发送失败 文件写入失败 文件 + 文件详情 文件已存在 文件管理器 文件扩展名 @@ -628,6 +645,8 @@ 隐藏文件和文件夹 隐藏 隐藏按钮 + 隐藏此节点 + 隐藏同框节点 历史记录 图标 忽略电池优化 @@ -1035,14 +1054,5 @@ 修改安全设置 安全设置包含应用程序可读但不可写入的设置选项, 这些选项只能由 UI 或系统级别应用修改.\n被授予 \"修改安全设置权限\" 后, 普通应用可直接修改上述安全设置 (例如无障碍服务). 修改系统设置 - 隐藏此节点 - 隐藏同框节点 - 未找到用于编辑该文件的应用 - 未找到用于浏览该链接的应用 - 未找到用于安装该文件的应用 - 未找到用于查看该文件的应用 - 未找到用于发送该文件的应用 - 未找到用于播放该文件的应用 - WebP-Lossless 格式无法使用 quality 质量参数进行压缩, 可改用 JPEG/PNG/WebP-Lossy diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9cb6e638..9e986c5e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -347,6 +347,13 @@ Theme color details Cannot process file The content has not been saved, are you sure to exit? + Bytes + Chars + Charset + Path + Size + EOL + Lines Follow system Local docs Online docs @@ -449,6 +456,12 @@ Accessibility service is disabled and the script has stopped Accessibility service is not activated No accessibility service + No applications available for browsing this link + No applications available for editing this file + No applications available for installing this file + No applications available for playing this file + No applications available for sending this file + No applications available for viewing this file No \"display over other apps\" permission No permission to access Shizuku No \"post notifications\" permission @@ -491,6 +504,7 @@ Unknown result type {name: %s, params: %s} Unknown selector {name: %s, type: %s} Unknown type: %s + Format WebP-Lossless cannot be compressed with a quality parameter, use JPEG/PNG/WebP-Lossy instead File does not exist or readable: %s AutoJs6 foreground service Click to launch AutoJs6 @@ -696,6 +710,7 @@ Command copied to clipboard Comment Compatibility + Confidence Config Are you sure to clear all histories? Are you sure to clear all items? @@ -786,6 +801,7 @@ Error Failed to copy file: %s Bug report + Estimated Execute Execute code [%s] finished in %s seconds.\n @@ -820,6 +836,7 @@ Failed to send log entries Failed to write file File + File details File already exists File explorer File extensions @@ -858,6 +875,8 @@ Hidden files and folders Hide Hide button + Hide this node + Hide same frame nodes Histories Icon Ignore battery optimizations @@ -1265,14 +1284,5 @@ Write security settings Secure system settings, containing system preferences that applications can read but are not allowed to write.\nThese are for preferences that the user must explicitly modify through the UI of a system app.\nWith secure system settings permission, normal applications can directly modify the secure settings (such as accessibility service). Write system settings - Hide this node - Hide same frame nodes - No applications available for editing this file - No applications available for browsing this link - No applications available for installing this file - No applications available for viewing this file - No applications available for sending this file - No applications available for playing this file - Format WebP-Lossless cannot be compressed with a quality parameter, use JPEG/PNG/WebP-Lossy instead diff --git a/version.properties b/version.properties index 3f269eab..a3860b21 100644 --- a/version.properties +++ b/version.properties @@ -1,5 +1,5 @@ -#Mon May 26 00:57:45 CST 2025 -BUILD_TIME=1748192265701 +#Tue May 27 01:13:34 CST 2025 +BUILD_TIME=1748279614245 COMPILE_SDK_VERSION=35 IMAGE_QUANT_CMAKE_VERSION=3.22.1 IMAGE_QUANT_NDK_VERSION=26.1.10909125 @@ -19,6 +19,6 @@ RAPID_OCR_OPENCV_MOBILE_LABEL_VERSION=13 RAPID_OCR_OPENCV_MOBILE_VERSION=4.5.3 TARGET_SDK_VERSION=35 TARGET_SDK_VERSION_INRT=29 -VERSION_BUILD=3256 +VERSION_BUILD=3261 VERSION_NAME=6.6.3 Alpha5 VSCODE_EXT_REQUIRED_VERSION=1.0.8