6.6.3 - Alpha - 使用异步加载方式一定程度提升文件管理器列表滑动流畅性

This commit is contained in:
SuperMonster003
2025-04-19 00:21:33 +08:00
parent eb0e9141f7
commit b5b8221384
14 changed files with 203 additions and 123 deletions

View File

@@ -8,7 +8,8 @@
"console.setContentTextColor 方法导致日志字体颜色丢失默认值的问题 _[`issue #346`](http://issues.autojs6.com/346)_"
],
"improvement": [
"打包单文件时自动读取并勾选已安装应用的声明权限 _[`issue #362`](http://issues.autojs6.com/362)_"
"打包单文件时自动读取并勾选已安装应用的声明权限 _[`issue #362`](http://issues.autojs6.com/362)_",
"使用异步加载方式一定程度提升文件管理器列表滑动流畅性"
],
"dependency": [
"升级 Gradle 版本 8.14-rc-1 -> 8.14-rc-2"

View File

@@ -163,6 +163,7 @@ AutoJs6 在 Auto.js 最终项目的基础上, 于 `2021/12/01` 进行二次开
* `修复` 部分设备代码编辑器空行显示方框字符的问题
* `修复` console.setContentTextColor 方法导致日志字体颜色丢失默认值的问题 _[`issue #346`](http://issues.autojs6.com/346)_
* `优化` 打包单文件时自动读取并勾选已安装应用的声明权限 _[`issue #362`](http://issues.autojs6.com/362)_
* `优化` 使用异步加载方式一定程度提升文件管理器列表滑动流畅性
* `优化` 部分依赖或本地库版本调整 _[`CHANGELOG.md`](http://project.autojs6.com/blob/master/app/src/main/assets-app/doc/CHANGELOG.md#v663)_
# v6.6.2

View File

@@ -163,6 +163,7 @@ AutoJs6 在 Auto.js 最终项目的基础上, 于 `2021/12/01` 进行二次开
* `修复` 部分设备代码编辑器空行显示方框字符的问题
* `修复` console.setContentTextColor 方法导致日志字体颜色丢失默认值的问题 _[`issue #346`](http://issues.autojs6.com/346)_
* `优化` 打包单文件时自动读取并勾选已安装应用的声明权限 _[`issue #362`](http://issues.autojs6.com/362)_
* `优化` 使用异步加载方式一定程度提升文件管理器列表滑动流畅性
* `优化` 部分依赖或本地库版本调整 _[`CHANGELOG.md`](http://project.autojs6.com/blob/master/app/src/main/assets-app/doc/CHANGELOG.md#v663)_
# v6.6.2

View File

@@ -12,6 +12,7 @@
* `修复` 部分设备代码编辑器空行显示方框字符的问题
* `修复` console.setContentTextColor 方法导致日志字体颜色丢失默认值的问题 _[`issue #346`](http://issues.autojs6.com/346)_
* `优化` 打包单文件时自动读取并勾选已安装应用的声明权限 _[`issue #362`](http://issues.autojs6.com/362)_
* `优化` 使用异步加载方式一定程度提升文件管理器列表滑动流畅性
* `依赖` 升级 Gradle 版本 8.14-rc-1 -> 8.14-rc-2
# v6.6.2

View File

@@ -12,6 +12,7 @@
* `修复` 部分设备代码编辑器空行显示方框字符的问题
* `修复` console.setContentTextColor 方法导致日志字体颜色丢失默认值的问题 _[`issue #346`](http://issues.autojs6.com/346)_
* `优化` 打包单文件时自动读取并勾选已安装应用的声明权限 _[`issue #362`](http://issues.autojs6.com/362)_
* `优化` 使用异步加载方式一定程度提升文件管理器列表滑动流畅性
* `依赖` 升级 Gradle 版本 8.14-rc-1 -> 8.14-rc-2
# v6.6.2

View File

@@ -10,13 +10,13 @@ import android.view.View
import android.view.ViewGroup
import android.widget.PopupMenu
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.LinearSmoothScroller
import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import io.reactivex.Completable
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
@@ -132,32 +132,32 @@ open class ExplorerView : ThemeColorSwipeRefreshLayout, SwipeRefreshLayout.OnRef
}
private fun init() {
Log.d(LOG_TAG, "item bg = " + Integer.toHexString(ContextCompat.getColor(context, R.color.item_background)))
ExplorerViewBinding.inflate(LayoutInflater.from(context), this, true).also { binding ->
this.binding = binding
explorerItemListView = initExplorerItemListView(binding.explorerItemList)
mProjectToolbar = binding.projectToolbar
binding.explorerItemList.also {
this.explorerItemListView = it
it.adapter = mExplorerAdapter
it.setHasFixedSize(true)
it.layoutManager = WrapContentGridLayoutManger(this.context, 2).also { manager ->
manager.setDebugInfo(ExplorerView::class.java.simpleName)
manager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
override fun getSpanSize(position: Int) = when {
position > positionOfCategoryDir && position < positionOfCategoryFile() -> {
mDirectorySpanSize // For directories
}
else -> 2 // For files and category
}
}
}
}
binding.projectToolbar.also {
mProjectToolbar = it
}
}
restoreSortConfig()
setOnRefreshListener(this)
}
private fun initExplorerItemListView(explorerItemListView: RecyclerView) = explorerItemListView.also {
it.adapter = mExplorerAdapter
it.setItemViewCacheSize(4)
it.layoutManager = WrapContentGridLayoutManger(context, 2).also { manager ->
manager.setDebugInfo("ExplorerView")
manager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
override fun getSpanSize(position: Int) = when {
position > positionOfCategoryDir && position < positionOfCategoryFile() -> {
mDirectorySpanSize // For directories
}
else -> 2 // For files and category
}
}
}
}
@Subscribe
fun onExplorerChange(event: ExplorerChangeEvent) {
Log.d(LOG_TAG, "on explorer change: $event")
@@ -589,6 +589,11 @@ open class ExplorerView : ThemeColorSwipeRefreshLayout, SwipeRefreshLayout.OnRef
}
}
override fun onViewRecycled(holder: BindableViewHolder<Any>) {
super.onViewRecycled(holder)
holder.onViewRecycled()
}
override fun getItemViewType(position: Int): Int {
val positionOfCategoryFile = positionOfCategoryFile()
return when {
@@ -639,15 +644,19 @@ open class ExplorerView : ThemeColorSwipeRefreshLayout, SwipeRefreshLayout.OnRef
private val globalAppContext by lazy { GlobalAppContext.get() }
private val mFirstChar: FirstCharView
private val mName: TextView
private val mFileDate: TextView
private val mFileSize: TextView
private val mOptions: View
private val mActionIconContainer: View
private val mInstall: View
private val mRun: View
private val mEdit: View
private val mInfo: View
private val mFirstChar: FirstCharView
private val mOptions: View
private lateinit var mExplorerItem: ExplorerItem
@@ -655,25 +664,20 @@ open class ExplorerView : ThemeColorSwipeRefreshLayout, SwipeRefreshLayout.OnRef
val explorerFileBinding = ExplorerFileBinding.bind(itemView)
val firstCharIconBinding = ExplorerFirstCharIconBinding.bind(itemView)
mFirstChar = firstCharIconBinding.firstChar
mName = explorerFileBinding.name
mFileDate = explorerFileBinding.scriptFileDate
mFileSize = explorerFileBinding.scriptFileSize
mFirstChar = firstCharIconBinding.firstChar
mRun = explorerFileBinding.run
mRun.setOnClickListener { withItemSelected { run() } }
mActionIconContainer = explorerFileBinding.actionIconContainer
mEdit = explorerFileBinding.edit
mEdit.setOnClickListener { withItemSelected { edit() } }
mRun = explorerFileBinding.run.apply { setOnClickListener { withItemSelected { run() } } }
mEdit = explorerFileBinding.edit.apply { setOnClickListener { withItemSelected { edit() } } }
mInfo = explorerFileBinding.info.apply { setOnClickListener { withItemSelected { showInfo() } } }
mInstall = explorerFileBinding.install.apply { setOnClickListener { withItemSelected { install() } } }
mInfo = explorerFileBinding.info
mInfo.setOnClickListener { withItemSelected { showInfo() } }
mInstall = explorerFileBinding.install
mInstall.setOnClickListener { withItemSelected { install() } }
mOptions = explorerFileBinding.more
mOptions.setOnClickListener { withItemSelected { showOptionsMenu() } }
mOptions = explorerFileBinding.more.apply { setOnClickListener { withItemSelected { showOptionsMenu() } } }
explorerFileBinding.item.setOnClickListener { withItemSelected { onItemClick() } }
}
@@ -683,54 +687,117 @@ open class ExplorerView : ThemeColorSwipeRefreshLayout, SwipeRefreshLayout.OnRef
if (item !is ExplorerItem) return
mExplorerItem = item
mName.text = ExplorerViewHelper.getDisplayName(context, item)
mFileDate.text = PFile.getFullDateString(item.lastModified())
mFileSize.text = PFiles.getHumanReadableSize(item.size)
setFirstChar(item)
updateVisibility(mEdit, item.isTextEditable || item.isExternalEditable)
updateVisibility(mRun, item.isExecutable || item.isMediaPlayable)
updateVisibility(mInstall, item.isInstallable)
updateVisibility(mInfo, item.isInstallable || item.isMediaMenu || item.isMediaPlayable)
setTextWith(mName) { ExplorerViewHelper.getDisplayName(context, item) }
setTextWith(mFileDate) { PFile.getFullDateString(item.lastModified()) }
setTextWith(mFileSize) { PFiles.getHumanReadableSize(item.size) }
when /* listOf(mEdit, mRun, mInstall, mInfo).filter { it.isVisible }.size > 2 */ {
listOf(mEdit, mRun, mInfo).all { it.isVisible } -> {
mInfo.isVisible = false
}
listOf(mEdit, mInstall, mInfo).all { it.isVisible } -> {
mInfo.isVisible = false
}
// listOf(mEdit, mRun, mInstall).all { it.isVisible } -> { /* Should not happen. */ }
// listOf(mRun, mInstall, mInfo).all { it.isVisible } -> { /* Should not happen. */ }
// listOf(mEdit, mRun, mInstall, mInfo).all { it.isVisible } -> { /* Should not happen. */ }
Observable.fromCallable {
val shouldEditShow = item.isTextEditable || item.isExternalEditable
val shouldRunShow = item.isExecutable || item.isMediaPlayable
val shouldInstallShow = item.isInstallable
val alreadyHasTwoImportantIcons = shouldEditShow && (shouldRunShow || shouldInstallShow)
val shouldInfoShow = !alreadyHasTwoImportantIcons && (item.isInstallable || item.isMediaMenu || item.isMediaPlayable)
listOf(shouldEditShow, shouldRunShow, shouldInstallShow, shouldInfoShow)
}
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { list ->
val (shouldEditShow, shouldRunShow, shouldInstallShow, shouldInfoShow) = list
if (shouldEditShow || shouldRunShow || shouldInstallShow || shouldInfoShow) {
setVisibilityIf(mEdit, shouldEditShow)
setVisibilityIf(mRun, shouldRunShow)
setVisibilityIf(mInstall, shouldInstallShow)
setVisibilityIf(mInfo, shouldInfoShow)
setVisibilityIf(mActionIconContainer, true)
} else {
setVisibilityIf(mActionIconContainer, false)
}
}
}
private fun updateVisibility(view: View, visible: Boolean) {
val visibility = if (visible) View.VISIBLE else View.GONE
private fun setTextWith(textView: TextView, callable: () -> CharSequence) {
Observable.fromCallable(callable)
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { text -> textView.text = text }
}
private fun setVisibilityWith(view: View, callable: () -> Boolean) {
Observable.fromCallable(callable)
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { isVisible ->
if (view.isVisible != isVisible) {
view.isVisible = isVisible
}
}
}
private fun setVisibilityIf(view: View, visibility: Int) {
if (view.visibility != visibility) {
view.visibility = visibility
}
}
private fun setVisibilityIf(view: View, visible: Boolean) {
setVisibilityIf(view, if (visible) VISIBLE else GONE)
}
private fun setFirstChar(item: ExplorerItem) {
mFirstChar.setIcon(ExplorerViewHelper.getIcon(item))
when (item.type) {
FileUtils.TYPE.JAVASCRIPT, FileUtils.TYPE.AUTO -> {
val themeColorForContrast = ColorUtils.adjustColorForContrast(context.getColor(R.color.item_background_dark), ThemeColorManagerCompat.getColorPrimary(), 1.15)
mFirstChar
.setIconTextColorByThemeColorLuminance()
.setStrokeColor(themeColorForContrast)
.setFillColor(themeColorForContrast)
Observable.fromCallable { ExplorerViewHelper.getIcon(item) }
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { icon ->
mFirstChar.setIcon(icon)
val actions = when (item.type) {
FileUtils.TYPE.JAVASCRIPT, FileUtils.TYPE.AUTO -> {
Observable.fromCallable {
ColorUtils.adjustColorForContrast(
context.getColor(R.color.item_background_dark),
ThemeColorManagerCompat.getColorPrimary(),
1.15
)
}.map { themeColorForContrast ->
listOf(
{ mFirstChar.setIconTextColorByThemeColorLuminance() },
{ mFirstChar.setStrokeColor(themeColorForContrast) },
{ mFirstChar.setFillColor(themeColorForContrast) },
{ mFirstChar.visibility = VISIBLE },
)
}
}
else -> Observable.just(
listOf(
{ mFirstChar.setIconTextColorDayNight() },
{ mFirstChar.setStrokeColorDayNight() },
{ mFirstChar.setFillTransparent() },
{ mFirstChar.visibility = VISIBLE },
)
)
}
actions.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.flatMapCompletable { list ->
Observable.fromIterable(list)
.flatMapCompletable { action -> Completable.fromAction { action.invoke() } }
}
.subscribe()
}
else -> {
mFirstChar
.setIconTextColorDayNight()
.setStrokeColorDayNight()
.setFillTransparent()
}
}
}
override fun onViewRecycled() {
super.onViewRecycled()
mName.text = null
mFileDate.text = null
mFileSize.text = null
setVisibilityIf(mFirstChar, INVISIBLE)
setVisibilityIf(mActionIconContainer, false)
}
private fun onItemClick() {
@@ -848,7 +915,7 @@ open class ExplorerView : ThemeColorSwipeRefreshLayout, SwipeRefreshLayout.OnRef
mName.text = ExplorerViewHelper.getDisplayName(context, data)
mDirDate.text = PFile.getFullDateString(data.lastModified())
mIcon.setImageResource(ExplorerViewHelper.getIconRes(data))
mOptions.visibility = if (data is ExplorerSamplePage) View.GONE else View.VISIBLE
mOptions.visibility = if (data is ExplorerSamplePage) GONE else VISIBLE
mExplorerPage = data
}
@@ -930,14 +997,14 @@ open class ExplorerView : ThemeColorSwipeRefreshLayout, SwipeRefreshLayout.OnRef
val currentSortType = if (mIsDir) explorerItemManager.dirSortType else explorerItemManager.fileSortType
when (currentSortType) {
ExplorerItemManager.SORT_TYPE_DATE -> popupMenu.menu.findItem(R.id.action_sort_by_date).setChecked(true)
ExplorerItemManager.SORT_TYPE_SIZE -> popupMenu.menu.findItem(R.id.action_sort_by_size).setChecked(true)
ExplorerItemManager.SORT_TYPE_TYPE -> popupMenu.menu.findItem(R.id.action_sort_by_type).setChecked(true)
else -> popupMenu.menu.findItem(R.id.action_sort_by_name).setChecked(true)
ExplorerItemManager.SORT_TYPE_DATE -> popupMenu.menu.findItem(R.id.action_sort_by_date).isChecked = true
ExplorerItemManager.SORT_TYPE_SIZE -> popupMenu.menu.findItem(R.id.action_sort_by_size).isChecked = true
ExplorerItemManager.SORT_TYPE_TYPE -> popupMenu.menu.findItem(R.id.action_sort_by_type).isChecked = true
else -> popupMenu.menu.findItem(R.id.action_sort_by_name).isChecked = true
}
popupMenu.setOnMenuItemClickListener { item: MenuItem ->
item.setChecked(true)
item.isChecked = true
when (item.itemId) {
R.id.action_sort_by_name -> {
sort(ExplorerItemManager.SORT_TYPE_NAME, isDirSortMenuShowing, true)
@@ -975,9 +1042,9 @@ open class ExplorerView : ThemeColorSwipeRefreshLayout, SwipeRefreshLayout.OnRef
binding.title.setText(if (isDirCategory) R.string.text_directory else R.string.text_file)
mIsDir = isDirCategory
if (isDirCategory && canGoUp()) {
binding.goUp.visibility = View.VISIBLE
binding.goUp.visibility = VISIBLE
} else {
binding.goUp.visibility = View.GONE
binding.goUp.visibility = GONE
}
if (isDirCategory) {
binding.arrowIcon.rotation = (if (currentPageState.dirsCollapsed) -90 else 0).toFloat()

View File

@@ -11,4 +11,8 @@ abstract class BindableViewHolder<DataType>(itemView: View) : RecyclerView.ViewH
abstract fun bind(data: DataType, position: Int)
open fun onViewRecycled() {
/* Nothing to do by default. */
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -23,13 +23,14 @@
android:foreground="?selectableItemBackground"
android:orientation="horizontal"
android:paddingVertical="9dp"
android:paddingStart="8dp">
android:paddingStart="8dp"
android:paddingEnd="0dp">
<include
layout="@layout/explorer_first_char_icon"
android:layout_gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_width="wrap_content" />
android:layout_gravity="center_vertical" />
<LinearLayout
android:layout_width="0dp"
@@ -59,8 +60,6 @@
android:id="@+id/script_file_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:ellipsize="end"
android:maxLines="1"
android:textColor="?android:textColorSecondary"
@@ -82,8 +81,6 @@
android:id="@+id/script_file_size"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:ellipsize="end"
android:maxLines="1"
android:textColor="?android:textColorSecondary"
@@ -95,71 +92,78 @@
</LinearLayout>
<LinearLayout
android:id="@+id/action_icon_container"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_height="36dp"
android:layout_gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:id="@+id/install"
android:visibility="gone"
tools:visibility="visible"
android:layout_width="36dp"
android:layout_height="match_parent"
android:background="?selectableItemBackgroundBorderless"
android:clickable="true"
android:paddingVertical="11dp"
android:src="@drawable/ic_install"
app:tint="#A9AAAB" />
android:contentDescription="@string/text_install"
android:focusable="true"
android:src="@drawable/ic_install_explorer_btn"
android:visibility="gone"
app:tint="#A9AAAB"
tools:visibility="visible" />
<ImageView
android:id="@+id/run"
android:visibility="gone"
tools:visibility="visible"
android:layout_width="36dp"
android:layout_height="match_parent"
android:background="?selectableItemBackgroundBorderless"
android:clickable="true"
android:paddingVertical="9dp"
android:src="@drawable/ic_run_gray"
app:tint="#A9AAAB" />
android:contentDescription="@string/text_run"
android:focusable="true"
android:src="@drawable/ic_run_explorer_btn"
android:visibility="gone"
app:tint="#A9AAAB"
tools:visibility="visible" />
<ImageView
android:id="@+id/edit"
android:visibility="gone"
tools:visibility="visible"
android:layout_width="36dp"
android:layout_height="match_parent"
android:background="?selectableItemBackgroundBorderless"
android:clickable="true"
android:paddingVertical="9dp"
android:src="@drawable/ic_mode_edit_black_24dp"
app:tint="#A9AAAB" />
android:contentDescription="@string/text_edit"
android:focusable="true"
android:src="@drawable/ic_edit_explorer_btn"
android:visibility="gone"
app:tint="#A9AAAB"
tools:visibility="visible" />
<ImageView
android:id="@+id/info"
android:layout_width="36dp"
android:layout_height="match_parent"
android:background="?selectableItemBackgroundBorderless"
android:clickable="true"
android:contentDescription="@string/text_info"
android:focusable="true"
android:src="@drawable/ic_info_explorer_btn"
android:visibility="gone"
tools:visibility="visible"
android:layout_width="36dp"
android:layout_height="match_parent"
android:background="?selectableItemBackgroundBorderless"
android:clickable="true"
android:paddingVertical="8.5dp"
android:src="@drawable/ic_info_outline_black_48dp"
app:tint="#A9AAAB" />
<ImageView
android:id="@+id/more"
android:layout_width="36dp"
android:layout_height="match_parent"
android:background="?selectableItemBackgroundBorderless"
android:clickable="true"
android:paddingVertical="9dp"
android:src="@drawable/ic_more_vert_black_24dp"
app:tint="#A9AAAB" />
app:tint="#A9AAAB"
tools:visibility="visible" />
</LinearLayout>
<ImageView
android:id="@+id/more"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_gravity="center_vertical"
android:background="?selectableItemBackgroundBorderless"
android:clickable="true"
android:contentDescription="@string/text_more"
android:focusable="true"
android:src="@drawable/ic_more_explorer_btn"
app:tint="#A9AAAB" />
</LinearLayout>
<View

View File

@@ -1,5 +1,5 @@
#Fri Apr 18 14:35:16 CST 2025
BUILD_TIME=1744958116261
#Sat Apr 19 00:16:16 CST 2025
BUILD_TIME=1744992976260
COMPILE_SDK_VERSION=35
JAVA_VERSION=23
JAVA_VERSION_MIN_RADICAL=0
@@ -17,6 +17,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=3147
VERSION_BUILD=3149
VERSION_NAME=6.6.3 Alpha
VSCODE_EXT_REQUIRED_VERSION=1.0.8