From b5b82213845a7613f6e62d3cf9ef0611a7f67b73 Mon Sep 17 00:00:00 2001 From: SuperMonster003 Date: Sat, 19 Apr 2025 00:21:33 +0800 Subject: [PATCH] =?UTF-8?q?6.6.3=20-=20Alpha=20-=20=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E5=BC=82=E6=AD=A5=E5=8A=A0=E8=BD=BD=E6=96=B9=E5=BC=8F=E4=B8=80?= =?UTF-8?q?=E5=AE=9A=E7=A8=8B=E5=BA=A6=E6=8F=90=E5=8D=87=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=99=A8=E5=88=97=E8=A1=A8=E6=BB=91=E5=8A=A8?= =?UTF-8?q?=E6=B5=81=E7=95=85=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .changelog/lang_zh-Hans.json | 3 +- .readme/README-zh-Hans.md | 1 + README.md | 1 + .../main/assets-app/doc/CHANGELOG-zh-Hans.md | 1 + app/src/main/assets-app/doc/CHANGELOG.md | 1 + .../autojs/autojs/ui/explorer/ExplorerView.kt | 223 ++++++++++++------ .../autojs/ui/widget/BindableViewHolder.kt | 4 + .../res/drawable/ic_edit_explorer_btn.png | Bin 0 -> 1903 bytes .../res/drawable/ic_info_explorer_btn.png | Bin 0 -> 3434 bytes .../res/drawable/ic_install_explorer_btn.png | Bin 0 -> 3969 bytes .../res/drawable/ic_more_explorer_btn.png | Bin 0 -> 2228 bytes .../main/res/drawable/ic_run_explorer_btn.png | Bin 0 -> 2151 bytes app/src/main/res/layout/explorer_file.xml | 86 +++---- version.properties | 6 +- 14 files changed, 203 insertions(+), 123 deletions(-) create mode 100644 app/src/main/res/drawable/ic_edit_explorer_btn.png create mode 100644 app/src/main/res/drawable/ic_info_explorer_btn.png create mode 100644 app/src/main/res/drawable/ic_install_explorer_btn.png create mode 100644 app/src/main/res/drawable/ic_more_explorer_btn.png create mode 100644 app/src/main/res/drawable/ic_run_explorer_btn.png diff --git a/.changelog/lang_zh-Hans.json b/.changelog/lang_zh-Hans.json index 66be77e6..a6bb8642 100644 --- a/.changelog/lang_zh-Hans.json +++ b/.changelog/lang_zh-Hans.json @@ -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" diff --git a/.readme/README-zh-Hans.md b/.readme/README-zh-Hans.md index b5bb921d..3c7563a2 100644 --- a/.readme/README-zh-Hans.md +++ b/.readme/README-zh-Hans.md @@ -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 diff --git a/README.md b/README.md index b5bb921d..3c7563a2 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/app/src/main/assets-app/doc/CHANGELOG-zh-Hans.md b/app/src/main/assets-app/doc/CHANGELOG-zh-Hans.md index 10bc0c53..1fc990a9 100644 --- a/app/src/main/assets-app/doc/CHANGELOG-zh-Hans.md +++ b/app/src/main/assets-app/doc/CHANGELOG-zh-Hans.md @@ -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 diff --git a/app/src/main/assets-app/doc/CHANGELOG.md b/app/src/main/assets-app/doc/CHANGELOG.md index 10bc0c53..1fc990a9 100644 --- a/app/src/main/assets-app/doc/CHANGELOG.md +++ b/app/src/main/assets-app/doc/CHANGELOG.md @@ -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 diff --git a/app/src/main/java/org/autojs/autojs/ui/explorer/ExplorerView.kt b/app/src/main/java/org/autojs/autojs/ui/explorer/ExplorerView.kt index 33da624a..45992cd7 100644 --- a/app/src/main/java/org/autojs/autojs/ui/explorer/ExplorerView.kt +++ b/app/src/main/java/org/autojs/autojs/ui/explorer/ExplorerView.kt @@ -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) { + 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() diff --git a/app/src/main/java/org/autojs/autojs/ui/widget/BindableViewHolder.kt b/app/src/main/java/org/autojs/autojs/ui/widget/BindableViewHolder.kt index 09e38fa2..9fe5cf90 100644 --- a/app/src/main/java/org/autojs/autojs/ui/widget/BindableViewHolder.kt +++ b/app/src/main/java/org/autojs/autojs/ui/widget/BindableViewHolder.kt @@ -11,4 +11,8 @@ abstract class BindableViewHolder(itemView: View) : RecyclerView.ViewH abstract fun bind(data: DataType, position: Int) + open fun onViewRecycled() { + /* Nothing to do by default. */ + } + } diff --git a/app/src/main/res/drawable/ic_edit_explorer_btn.png b/app/src/main/res/drawable/ic_edit_explorer_btn.png new file mode 100644 index 0000000000000000000000000000000000000000..6d3963ce10775c698ce668ee1dc822e8214f87ac GIT binary patch literal 1903 zcmbVNeQeZZ7%vH;L*~cKf-;tL9U+*}>)T%MtJ{r?-Q+HCV;`psG;wd=zPIak*Os=s zyDfeUrjkXCpmCB(VvG=?hHWMXPBc-Oh8UMP{ln2x{QKgY^sEwSX&T-31@*kn9YRRd@2=BHi>ejoQV+A#G z47VYbxMbyME<^2*6B+*S5ehdj`DsibTbYCGD zxe77~+cqSQ%VaXHjN7G~T^t_>1UMjYg1{04YxQY1%(9wQy}%H{7BW@CR&|Yb7@@59 z+Chd$ozEd<6lpc9P$yC`E(;BgcL67-JWxSJoY8A0^T8Fw;UrFB&9(@ZFJg^^ZtGS; zUxvE)_^JS;w$W%Y#*$i6sbUDrZc39h3I$mbZN>Tw%(Y=l?==x_N)wsYPBwDDi=m5Ulp6JBot&w&Ms9|B(E1i*#{9T`+NfHiHjl&<1%DPI|9+~amzdu7xssA z)ay9w?4R#)MMs3=->9;vAer~_q_Mp|mX}2@3k6YTp$ug&0E8K!1-6~0N?tUWT+HgI zQV648@QYrgAQm7PU}aJCv9gDVbSoa&=jGj44nU`y^9>?}Rf|~HS9m|#@!rBJsnYqL zkRWn;J;)%(WUMfS+v*baxS_~}{h0(Nq}MQiKDwpH?F=+=Ll>#tb(@P@PP_%v*Oq=` zR?cfGN?)!S|Bv)SSx^FMU6@Qxj&YLVoDnl`3in^X^3N8HqXjsban7&Eh<<)d~d-2^5L z{=mVHHk!{rdg;dtKR@=Jh<>OIOM%|D?#$-{m%@!q>5#bLi-U_6r$>gzTaUl}%L`w= zKJ(e83#02>o=wixe;+>f&6xXGB@8}PlB>EnP_ysXBfFLA`%A<_FHH$=cI>IX{k4g) z@Sf@iuMD5P^V^>FsmFi6Jn=xhHTU<4x{pr^&z*jC?vU^aA%wLJ_!)r?iu1wR1Z!Ud8O$^QT nQHP!itt(T*N2?YsVqkV{$=8wEbk$oE&L=U_)EpY!+PVK9f-isa literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/ic_info_explorer_btn.png b/app/src/main/res/drawable/ic_info_explorer_btn.png new file mode 100644 index 0000000000000000000000000000000000000000..d89eba1b322d8eafd060539378cca7bb4f936e99 GIT binary patch literal 3434 zcmcIn2~-p38ja7T1py5pQe{a4$~xHzNiet&ww8bbvWP5`WD+7-$O0i)u@!6sVNvv1 z(1_Mn&?2B%76F0Q0HOk|fXF5_C>3$5?JH2x_a+Fu_ML9$ozt8%nSV0(zxRI2d~=ey zHPF}CaE&1XfiU*>V+6xzjsAFZ3H*(^VAu+u3=;h!WeCJ_GySm$aa3c8KrC(NhepUF zm;p4lScm~RVitr+5hlWD1Y*O+lthr70Lf7-h{qSv(NF7}&?r8Kjt+NY;+TnEP(0r+ zRSJcq28Oaz6WCM^dZQ<5LkbNh5JGYgl_C^~WV94IdX|?4uk}A;(WqI7Jb{khtQSN@ zFt?(-#8L=F#oz!o4u?azQ!#jVJe%Oobwv?y1OgUE!Q#mPodw95xmb zKtf0)m%&*40yZ&TEEmh-#lJ(naQjyRaBi8*1&!bIA`~u2$mHJ1a2Rt5`AxJeRGA22 zgCUtXNy>)2lVO{7`e+hqUQ!5@i>0Arv0%PZTjwpK2qX*+03HwE384fcjYOr9C@wg-e7M(8rkKO$Di@$`0FDG#Hn`Vr*)Yd{ zRmnsmM0BST00@Lg0EI$g15^qT0$6TDmY$E`Ms}ZP3zG8T2MrYbl2z}D12a+~4w-_Z zkO3-*L;*-75(t1eE*BtD30$%}mE}eOS^93CZ4jCtUj~;>Irn^oK$5wYfRCE(2^z@O z_c|TT))yJ#pyz((|3*IklJeYsMLYzP{z36ytINb(xdN0zn|W~V{k3if~NHGA(D<7gfZ&p7>ZVY z3-cKg!PHWC`bHdjVvaz(;p@-X9Gaqetcg~wf-K*+ee4_E7rib?VZf>pB&~AFM`fQ{ z;_vdg`r1~bhO@`c=Q9uPL#Z%EYRnRY%#&ZAo3J1MuGrPf5Lwyt(jZCFZ>vbEN`|_| zw*)?X(V>xz9ar=b+a?Q36=`=SkMVe1UgHlP0qvvl1*w+9+b@a8_=#3i_d_+5 zgkb6WWj#ZVx?8e=FCO{d3TvwMnC|?70}ceq+|+~3(+1xhap=NLID`z{8_vBE$7_%F zXz7~i+*UUZsqo*1al8G9!lCO@5%$7MOw8Spsg}qFYyQ2h2aRPjS4&+T`)}7Pk1zH< z_H6kN4*XaL@0|$;*XCUmxOnwf{d|WwySH`X)^oc4wSV&(Y`9lt+C8%AMlED zQzhhlL+&&Yh4{PRK0bbr)#Gh*CDOFdT$XRcQ#$jP+MKc@?B(@TVLWtP?aaGV*@f!| z5Znt6m93kLdErAPNSB<8?EyPJ=r~yNsQg^k;K~cv9J`JtERMJm!Khk&(eX*Asw87u zk!Gb35#)WwLm{+{C2RM0eKu+)|6*0j+q#V56K;|TJBz{CLHj85=P|vq;AtJ#M{c#} z$fivPoBRwK->jx9PdAl6Z@K)IE3N3kG6uFhw=-^{BN7?jb}|B2^ej0XYhq(kE`Qm> z_1d}ne4Ov8=pY9ZPm}7sz;d0)(57;k*~UY~X71Pr9^-X0>Vo@?1OLu%%JR@^ghmD7 zPCmASEgEjv(Qy1mU85py{&P# z{zcuk$l?uQVfdwzhXmw_xk{I*IVUAI41f@*x13EhB|y@H2O%{yZav_9c;%!jFSR$ z&Uy9`E|pQHLunj%OFFu|DnR7&!~&UD$PK!7MpY8IesVSA@a?R6dtDUsqJy`|2M2uP zoCPh%SAQ?)e&kJ6mIK zp^mt-vgE6%L*HI?0!-YWJYiHYqEMPv^X7vFfip9HD;k zp}J2SlG0zhMcH7lLpHjV$Nk*3D6XP_8W8=^XC0J`do?AS*i-e?dYYk45|ApkWidC8 z43>swD_8e>Wxj~%ww4%c%mx)PPu{C|WQS?-5 zLOqA?8o6;bmlCn|LW->RL~BNc!9C@xYdTj|`pYkMRtf7v2kTVf`HhXK`vt0m+!S$I zcFFpHLE=ushsMz!2Rzp5PK|uGW^}*7H`SOeQ88(Y99(p9;o5ho)ddN=iO;=9j!UZ^ zsg8Aid3DvKW7Er(-g~rrZ*EYUWHdeG`dZz{OK}2%igGh*w2}>`k`Z{0WS(hjaLr6# z`Xi%UGs+%2oqwy@0dGvTrdwd5bSD9y=pyh=am+d)`RS6p=ljRa)u-IA9i>EU3V-Bt zMX=(-W{Z-X6|B?usmP7b3A=SC-yR!bfHc3|&lXFsn%?=g@08NSeB!Ihp}zJPMg#KX z^Pe#G5ofeu?oDrOdiFoM3%wQtu46VfMn36&$(0vw7c{u0EqhGBT2NbV26~;|I2B)4 zamd+Z2f7FZiYwA$~y5>m)yFCEqEYO?G0mL~sp&w+{`YqmF0-ro`9B0Ut` z+0)+2iCtQ1B0+>Gvxl?oG4i6W$ikT_{JjGiDCCAD$RbLpM~M}r zt*wf-$e=~7f}l`wEaes$5RBrufEJ6vC5nKoDM1nD29er1-Ol`(b7t;2IrqEo_k7R$ zyvu!WcC82ru$tyD4FF&j6ewB=00CbTz!VaG3s)XT@Y_^H;0G!Ih$ZG9!MMFE2!P4; zve32awZY2-5E|zuk)lzsTT+|?M+4yLourUJn_x913XYb^h1Bi~l~jsMDx|J)4`u`_ zeBl^bV2To6l@byPrEG%uQmVHX#WP8O6U4!42_-2mR<05x38`be0(@;Y)2Wm(h_D+F|UVq&6OBHImBM$?&mKA+BD(OE1Sj-aWMa4d5ItB66>s452i4eE*QUpT;X8yr00<5#uB#Z9o_ zSJA4_WCcuL39HZqB?S9z#$`I2qfrQam9RvODnn5;_En`;ypl{|aoiY`_twbdQZ!LD z|Fr|KNTP;?RJ>{&8k0$5@LSQaOVhUp4DkX)sf$RRjL zB&6aoyUAoy0bk03m{A^V8jsK6&=3X(p+&hvJR0K8ovCb+BkXz z$7h^*IWb-Fhl%+N%W-NYK7HA=rbv9yM+S)&hbDc|_2cs6;nDV*-bcYlWE+pV_;KXx zj?9AccV#VETwKUm9dqGvRhHEf5&3&Rk>dX09ryfekhZYhK{vDV#OuF)3wlx&xa%kS z%{RBZac-{ljfu@7ZLnqED|9)>KCdz?dh~6h&C_=h4U3#q-Or`Sl`nHHE_1nAT4W@- zltJKVm8B;10O8|lY_L*7@>!q*fjjKM2?mie6ZxOpy!EVU_6jcb-bTu-(s0CZdvf7d zb9d=tD=cV%qE5nh(>e)7kv)CU>G!c{cE9Pv<}hcH*o7M9q@e$J_v8i8*{FLi@Y=Hv z1DQUeSmIm@4_f=jk2DcE$;zO*RRO7QD(3uj_S?4Tlv6L3dgcnEKyBMjYTbN}MjZ==XFdXeslk!^oBzO#SAFi>Yi`+V_W0G1^p?dX#z>N3 zo>+zCq7|Po`-8Bj5gFBKd=J+7t{ZO?uU2r&S}{#>OM(ulyE*#%r-tV3Z3%H?0mn$ssW2%D$X7GkTgeN9{JwUvZL?EcV>tjsS5!9MY`-QVu7zYPkXS{66A zZLlU5yW|YH>ccXzjaR_A5Y&~HPFPEIE?$sPNgx(W{q^~CM*J;(i2izb&d5$nA7_7{ zFdbq8tC`uF>bpczUP(S#VcJp!27F4U@P>s^ASFNWjX5K^Odw?SnJrR~f*dtt8o&zIhrl=iHs%F_u%fMNaCZj-oo8K7*6Wht<@%A>opze#;kK^ua)Rh z<+-k+8Y`?CGw`z$KB#sgA4)%D@C@7U1{x>5%j&;d$i2=biFatrtxY5ayXRoRq4VW4 zu;84bW64Eodvf`mw!19hl?#URt)C7%n(TW{=!Unp6b@t%4t%7|o@9~U?9tlbnmntV z&t866^%bAWsBPQOK3VUBY&&W6e}(}-j$fom>)5JmJGYEl{5XRMIgNb&^rFsU9hzU( zN6>0FX^v^QrLC8~*jDW_DJ}QW`{WWwlUwog(eI3QJ#D&F)z!Z4Ttq>zfDxtYOCR;TH#!Z75L- zx!7LpIlKRK#9XPU+QtX*?+}(g5NdjpEP8qdf-Z+-#+hJHi`ed+68phGmGvkOAKkaD z=45HP^o`%QuM3Db1=NAe>mmAoYE9TW+k-{DkJZ6hnFPDjm$B{S`1hzqUk)~qhgQsGOiJ)*{kH(iw_pA9FqhS$PfW~TRi^Tb6<0Lzc17U5u zpFUoHV_>?tV_=i5V)c=&?h;_>(=|J<{0X6l|MTR2Hn1(xp>i+gyDYMHI8010-fGqH zBK29q!Fs3pKkhoV@KF>fUAV!*>s;SkQqd_3uf_*2>+rK7EA1S_^ z23GHgCU{OSw!Ev;Wk)nM2s_+hi&Y}w zr#ZyDqRY>IdYBe|<6*(#_JORw)>eVzo6y6(%5Jj>&Hg5#*7!afJo&*$E{QIiE~;tK zBsP|}Mv!~oKm0=}T3gm&-W2E+qVRzk`wLF{c-C~D_Pj&7qdI~5*M#U@`{idA5cA+$ z)}CbYIlr2jfY}?VZ^pJ5!n^O2d#^Sm3O~}iI^UatF~#@uJ-jyOk_I^XGZk+PTbEnk zD%BW6h>h%_OI5Ch3Z?P729Nl&Fd^`I19-E)E9&#!LIm%wLwzoPHhO!urvBKyuM6td zp?U5^kX_oUIXHjx>|hX9zjS4GZ)J8vm{nc+YGM(NQYo2EGJnVG<_!Zmd%N2L zYBW(72+PL8)Uly39ZFz{2ocARCPqXMl952>W{{sCpiHwU1_{Kkx7#@ke;U1{?br7C zp7(j*=k1%TFE1<29rNfI1VM5GeqRV)TkYfCyWshFY|=gOlB4^pOa!@atbN>pyuEHb zf{flThbyhh;5<&y6bCPA5#UHEIz%JLtl24@7pj4UMnF_nz1Yv)doffNy;wy-kPPa@ zASV0k3^2d0EG*Pj3#^FEE<|UgI7pxXi$_yRTs66r7fbVUaBV*(Ffhh{_xie*`XqzRhFAp$pRRf|vIs+l*;-~*;$$hswKDrz(G5iMbP zF(`E?2Sv})s%EB6uwq1t*9po&+Bv0xqL9Vu2_v2kE(!#Q0|ls-39(cbtH(4;Gh^Bf zsI#xH2>@#w3}$0oSBs)#Lzq@c4NN0bkn5t&aIFrA5HPibA%Kz^C^OH_M(2tRz+0LT z*0lJrQ{}^wQQGMs(P%Gn5H<2;hgj}P}nmfZ}GPTivlNUhQh;yWrdFdLRX_0nk^$&ti?4028QaW zw2EMm3#g{Ws{#o4yco>cAL@e`IzD_-ED{^LkG6o>&P0SyPZfcU1x=js zy$^1iBo!Zg?af^3KYQSRH-6zn)%HZUvgF5agWa(Mudi?EX{l{`qV&=)hZ|m!+Df*x zUX&A8sgEX?UTSVxw0h4O=kE!1;rYDapj7?wX-`*l&;Gm_yOqt$C(Qb3+xf2Ou7mb% z*PKHO4@JB8jSYWYGx&HXv-#J?n%Y96|F@OBTL(AI)%qrW(5x_Zb?(EH+uslEIJ~j5 zg8A-bV8#`7(V5HNA1`0A_DVxl7xQ6HUrpPA&$lI~kK1yzZ*Be{wGT=-oxh~5^=MsR z)8%z%R$Lu8@`G}y=fc@Jqn7Sg_Tpyynq7XQW%J^~VAa`W(IwCt3 z9NiggakzJWWgI)!yY$$~Q|qVJ&pc-hbTp^Wt7c9=SvL2RH4}Hu?R9PJ9OxL;AIM3D zzHDpOr@q%8=rpI6^ambjAL&VmYMptm`5&@)Q`-xBcJu$2zv-sgi_Ckd;?!I7>z}j# PR|HDRd|RJ>;gvrD%*H51 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/ic_run_explorer_btn.png b/app/src/main/res/drawable/ic_run_explorer_btn.png new file mode 100644 index 0000000000000000000000000000000000000000..e30b8ed04e92a97e9d10ac9d91eea644ad143234 GIT binary patch literal 2151 zcmbVO4NTN#819KO)Zt(*i=vTI7bao7{#=i{b{+~Ga-au{KhbQ=UfVmWcWrkq+#N0k zoSQ(x4E}5x!(@vP42x`0F;1L1m+07{Zs>;MOk6~bI_KtOi5q77dK@=hbdoh``?lZn zJ@51W^i7+J3-jWqB~61MC_dj|F9CO_e#XUu>!qpJJ^{C>ierTeLDOgIrvYkfp9Miv z`o*$Jt6!%2)JQGh_zkfgCeR8r@UGuQ={^NWfm$`Y(IvM#ws zvmrq0SPVWTN-L?6Jb{d1K~}*CBd*632J&1Kr_}hpVdp%D30}b`NSX?;L=>x3%bKiK z%a5RrEe{dSqF(JQO(AM0{n<^ab(UQHCw;%3f*nlfk-#WN@hbrBX8rC8QXyEvA&n#Xbi z)D-ze@S(BZ`&o5WJYXc;R)TetW)x_kQQS?LP&&hEMp=?D6D-YT2)s-0=5T{B4p9ZA z3q`(ld;- zAa{>#F6>d_RkrrOrBAGsW16DUAJvTiM|vbJTs13s1TZ- z8i#`!r<>8~3Lc{KS&#s=A57odnY%AS&?I}lJ*zC(ezWa-%gn5VTsdXZ*@U>yQ>-zm zlRfzPMBH9{A<-MxH>bfld3xf-_=Y%RvT4brhE)Z3N^3Ij5#^cPt6%*z&vEqJ@%M+~ z?=&toT^x9FKNVv zUkw%h)mL%yR(YLm)8TcC$z!vU%SUD=GupI%ew&d?TSvrjRTp0X62u))hmWtwlubvj}-T{ z&apXS_SHDkPV~+({Lvcw!S-c?+xE6xf3GJ`Tzq-i;71fRLcTIMkkRZpkl0~(({y3M zfYfduP6@Pr+hI7;(Y^HKr1=GJG#)&4cQmE5b!+>nA(h>hrsn z{63VUZmCFLd-KEDV(*^8d2N-ap4~k-ub^mX%8^ZdU%dnD=0j>aQvBUoXl8wS1v@ym z_pQ)Np=a8xr|Z7xoUMqlFSi-qbsw3Sc_?Pbr85m@6P`%Ze+BY$3++AGtJePwDqi+? literal 0 HcmV?d00001 diff --git a/app/src/main/res/layout/explorer_file.xml b/app/src/main/res/layout/explorer_file.xml index 315aed6e..ec5fd3d6 100644 --- a/app/src/main/res/layout/explorer_file.xml +++ b/app/src/main/res/layout/explorer_file.xml @@ -23,13 +23,14 @@ android:foreground="?selectableItemBackground" android:orientation="horizontal" android:paddingVertical="9dp" - android:paddingStart="8dp"> + android:paddingStart="8dp" + android:paddingEnd="0dp"> + android:layout_gravity="center_vertical" /> + android:contentDescription="@string/text_install" + android:focusable="true" + android:src="@drawable/ic_install_explorer_btn" + android:visibility="gone" + app:tint="#A9AAAB" + tools:visibility="visible" /> + android:contentDescription="@string/text_run" + android:focusable="true" + android:src="@drawable/ic_run_explorer_btn" + android:visibility="gone" + app:tint="#A9AAAB" + tools:visibility="visible" /> + android:contentDescription="@string/text_edit" + android:focusable="true" + android:src="@drawable/ic_edit_explorer_btn" + android:visibility="gone" + app:tint="#A9AAAB" + tools:visibility="visible" /> - - + app:tint="#A9AAAB" + tools:visibility="visible" /> + +