[Feature] Implement grid view.

Fixes: #152
This commit is contained in:
Hai Zhang 2023-08-07 03:03:15 -07:00
parent 9fca17bffe
commit 97c0a04aa3
53 changed files with 784 additions and 164 deletions

View File

@ -16,6 +16,7 @@ private const val VERSION_CODE_1_2_0 = 22
private const val VERSION_CODE_1_3_0 = 24
private const val VERSION_CODE_1_4_0 = 26
private const val VERSION_CODE_1_5_0 = 29
private const val VERSION_CODE_1_6_0 = 32
private const val VERSION_CODE_LATEST = BuildConfig.VERSION_CODE
private var lastVersionCode: Int
@ -52,5 +53,8 @@ private fun upgradeAppFrom(lastVersionCode: Int) {
if (lastVersionCode < VERSION_CODE_1_5_0) {
upgradeAppTo1_5_0()
}
if (lastVersionCode < VERSION_CODE_1_6_0) {
upgradeAppTo1_6_0()
}
// Continue with new `if`s on lastVersionCode instead of `else if`.
}

View File

@ -520,3 +520,24 @@ private fun migrateSftpServersSetting1_5_0() {
}
defaultSharedPreferences.edit { putString(key, newBytes?.toBase64()?.value) }
}
internal fun upgradeAppTo1_6_0() {
addViewTypePathSetting1_6_0()
}
private fun addViewTypePathSetting1_6_0() {
val keys = pathSharedPreferences.all.keys.toSet()
val sortOptionsKey = application.getString(R.string.pref_key_file_list_sort_options)
val viewTypeKey = application.getString(R.string.pref_key_file_list_view_type)
val defaultViewType = application.getString(R.string.pref_default_value_file_list_view_type)
for (key in keys) {
if (!key.startsWith(sortOptionsKey)) {
continue
}
val newKey = key.replaceFirst(sortOptionsKey, viewTypeKey)
if (newKey in keys) {
continue
}
pathSharedPreferences.edit { putString(newKey, defaultViewType) }
}
}

View File

@ -0,0 +1,13 @@
/*
* Copyright (c) 2023 Hai Zhang <dreaming.in.code.zh@gmail.com>
* All Rights Reserved.
*/
package me.zhanghai.android.files.compat
import android.view.Menu
import androidx.core.view.MenuCompat
fun Menu.setGroupDividerEnabledCompat(groupDividerEnabled: Boolean) {
MenuCompat.setGroupDividerEnabled(this, groupDividerEnabled)
}

View File

@ -5,9 +5,21 @@
package me.zhanghai.android.files.compat
import android.os.Build
import android.widget.TextView
import androidx.annotation.StyleRes
import androidx.core.widget.TextViewCompat
import me.zhanghai.android.files.util.lazyReflectedMethod
private val isSingleLineMethod by lazyReflectedMethod(TextView::class.java, "isSingleLine")
val TextView.isSingleLineCompat: Boolean
get() =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
isSingleLine
} else {
isSingleLineMethod.invoke(this) as Boolean
}
fun TextView.setTextAppearanceCompat(@StyleRes resId: Int) {
TextViewCompat.setTextAppearance(this, resId)

View File

@ -6,7 +6,11 @@
package me.zhanghai.android.files.filelist
import android.text.TextUtils
import android.view.View
import android.view.ViewGroup
import android.widget.ImageButton
import android.widget.ImageView
import android.widget.TextView
import androidx.appcompat.widget.PopupMenu
import androidx.core.view.isVisible
import androidx.recyclerview.widget.DiffUtil
@ -17,14 +21,18 @@ import java8.nio.file.Path
import me.zhanghai.android.fastscroll.PopupTextProvider
import me.zhanghai.android.files.R
import me.zhanghai.android.files.coil.AppIconPackageName
import me.zhanghai.android.files.databinding.FileItemBinding
import me.zhanghai.android.files.compat.isSingleLineCompat
import me.zhanghai.android.files.databinding.FileItemGridBinding
import me.zhanghai.android.files.databinding.FileItemListBinding
import me.zhanghai.android.files.file.FileItem
import me.zhanghai.android.files.file.fileSize
import me.zhanghai.android.files.file.formatShort
import me.zhanghai.android.files.file.iconRes
import me.zhanghai.android.files.file.isApk
import me.zhanghai.android.files.provider.archive.isArchivePath
import me.zhanghai.android.files.settings.Settings
import me.zhanghai.android.files.ui.AnimatedListAdapter
import me.zhanghai.android.files.ui.CheckableForegroundLinearLayout
import me.zhanghai.android.files.ui.CheckableItemBackground
import me.zhanghai.android.files.util.layoutInflater
import me.zhanghai.android.files.util.valueCompat
@ -35,6 +43,16 @@ class FileListAdapter(
) : AnimatedListAdapter<FileItem, FileListAdapter.ViewHolder>(CALLBACK), PopupTextProvider {
private var isSearching = false
private lateinit var _viewType: FileViewType
var viewType: FileViewType
get() = _viewType
set(value) {
_viewType = value
if (!isSearching) {
super.replace(list, true)
}
}
private lateinit var _comparator: Comparator<FileItem>
var comparator: Comparator<FileItem>
get() = _comparator
@ -144,16 +162,25 @@ class FileListAdapter(
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder =
ViewHolder(
FileItemBinding.inflate(parent.context.layoutInflater, parent, false)
).apply {
binding.itemLayout.background =
CheckableItemBackground.create(binding.itemLayout.context)
popupMenu = PopupMenu(binding.menuButton.context, binding.menuButton)
.apply { inflate(R.menu.file_item) }
binding.menuButton.setOnClickListener { popupMenu.show() }
override fun getItemViewType(position: Int): Int = viewType.ordinal
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val viewType = FileViewType.values()[viewType]
val inflater = parent.context.layoutInflater
val holder = when (viewType) {
FileViewType.LIST -> ViewHolder(FileItemListBinding.inflate(inflater, parent, false))
FileViewType.GRID -> ViewHolder(FileItemGridBinding.inflate(inflater, parent, false))
}
return holder.apply {
itemLayout.background = when (viewType) {
FileViewType.LIST -> CheckableItemBackground.create(0f, 0f, itemLayout.context)
FileViewType.GRID -> CheckableItemBackground.create(4f, 12f, itemLayout.context)
}
popupMenu = PopupMenu(menuButton.context, menuButton)
.apply { inflate(R.menu.file_item) }
menuButton.setOnClickListener { popupMenu.show() }
}
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
throw UnsupportedOperationException()
@ -161,11 +188,10 @@ class FileListAdapter(
override fun onBindViewHolder(holder: ViewHolder, position: Int, payloads: List<Any>) {
val file = getItem(position)
val binding = holder.binding
val isDirectory = file.attributes.isDirectory
val enabled = isFileSelectable(file) || isDirectory
binding.itemLayout.isEnabled = enabled
binding.menuButton.isEnabled = enabled
val isEnabled = isFileSelectable(file) || isDirectory
holder.itemLayout.isEnabled = isEnabled
holder.menuButton.isEnabled = isEnabled
val menu = holder.popupMenu.menu
val path = file.path
val hasPickOptions = pickOptions != null
@ -173,69 +199,102 @@ class FileListAdapter(
menu.findItem(R.id.action_cut).isVisible = !hasPickOptions && !isReadOnly
menu.findItem(R.id.action_copy).isVisible = !hasPickOptions
val checked = file in selectedFiles
binding.itemLayout.isChecked = checked
val nameEllipsize = nameEllipsize
binding.nameText.ellipsize = nameEllipsize
binding.nameText.isSelected = nameEllipsize == TextUtils.TruncateAt.MARQUEE
holder.itemLayout.isChecked = checked
holder.nameText.apply {
if (isSingleLineCompat) {
val nameEllipsize = nameEllipsize
ellipsize = nameEllipsize
isSelected = nameEllipsize == TextUtils.TruncateAt.MARQUEE
}
}
if (payloads.isNotEmpty()) {
return
}
bindViewHolderAnimation(holder)
binding.itemLayout.setOnClickListener {
if (selectedFiles.isEmpty()) {
listener.openFile(file)
} else {
selectFile(file)
holder.itemLayout.apply {
setOnClickListener {
if (selectedFiles.isEmpty()) {
listener.openFile(file)
} else {
selectFile(file)
}
}
setOnLongClickListener {
if (selectedFiles.isEmpty()) {
selectFile(file)
} else {
listener.openFile(file)
}
true
}
}
binding.itemLayout.setOnLongClickListener {
if (selectedFiles.isEmpty()) {
selectFile(file)
} else {
listener.openFile(file)
}
true
holder.iconLayout.setOnClickListener { selectFile(file) }
val iconRes = file.mimeType.iconRes
holder.iconImage.apply {
isVisible = true
setImageResource(iconRes)
}
binding.iconLayout.setOnClickListener { selectFile(file) }
binding.iconImage.setImageResource(file.mimeType.iconRes)
binding.iconImage.isVisible = true
binding.thumbnailImage.dispose()
binding.thumbnailImage.setImageDrawable(null)
holder.directoryThumbnailImage?.isVisible = isDirectory
holder.thumbnailOutlineView?.isVisible = !isDirectory
val supportsThumbnail = file.supportsThumbnail
binding.thumbnailImage.isVisible = supportsThumbnail
val shouldLoadThumbnailIcon = supportsThumbnail && holder.thumbnailIconImage != null &&
file.mimeType.isApk
val attributes = file.attributes
if (supportsThumbnail) {
binding.thumbnailImage.load(path to attributes) {
listener { _, _ -> binding.iconImage.isVisible = false }
holder.thumbnailIconImage?.apply {
dispose()
isVisible = !isDirectory
setImageResource(iconRes)
if (shouldLoadThumbnailIcon) {
load(path to attributes)
}
}
binding.appIconBadgeImage.dispose()
binding.appIconBadgeImage.setImageDrawable(null)
val appDirectoryPackageName = file.appDirectoryPackageName
val hasAppIconBadge = appDirectoryPackageName != null
binding.appIconBadgeImage.isVisible = hasAppIconBadge
if (hasAppIconBadge) {
binding.appIconBadgeImage.load(AppIconPackageName(appDirectoryPackageName!!))
holder.thumbnailImage.apply {
dispose()
setImageDrawable(null)
val shouldLoadThumbnail = supportsThumbnail && !shouldLoadThumbnailIcon
isVisible = shouldLoadThumbnail
if (shouldLoadThumbnail) {
load(path to attributes) {
listener { _, _ ->
val iconImage = holder.thumbnailIconImage ?: holder.iconImage
iconImage.isVisible = false
}
}
}
}
val badgeIconRes = if (file.attributesNoFollowLinks.isSymbolicLink) {
if (file.isSymbolicLinkBroken) {
R.drawable.error_badge_icon_18dp
holder.appIconBadgeImage.apply {
dispose()
setImageDrawable(null)
val appDirectoryPackageName = file.appDirectoryPackageName
val hasAppIconBadge = appDirectoryPackageName != null
isVisible = hasAppIconBadge
if (hasAppIconBadge) {
load(AppIconPackageName(appDirectoryPackageName!!))
}
}
holder.badgeImage.apply {
val badgeIconRes = if (file.attributesNoFollowLinks.isSymbolicLink) {
if (file.isSymbolicLinkBroken) {
R.drawable.error_badge_icon_18dp
} else {
R.drawable.symbolic_link_badge_icon_18dp
}
} else {
R.drawable.symbolic_link_badge_icon_18dp
null
}
val hasBadge = badgeIconRes != null
isVisible = hasBadge
if (hasBadge) {
setImageResource(badgeIconRes!!)
} else {
setImageDrawable(null)
}
} else {
null
}
val hasBadge = badgeIconRes != null
binding.badgeImage.isVisible = hasBadge
if (hasBadge) {
binding.badgeImage.setImageResource(badgeIconRes!!)
}
binding.nameText.text = file.name
binding.descriptionText.text = if (isDirectory) {
holder.nameText.text = file.name
holder.descriptionText?.text = if (isDirectory) {
null
} else {
val context = binding.descriptionText.context
val context = holder.descriptionText!!.context
val lastModificationTime = attributes.lastModifiedTime().toInstant()
.formatShort(context)
val size = attributes.fileSize.formatHumanReadable(context)
@ -325,7 +384,53 @@ class FileListAdapter(
}
}
class ViewHolder(val binding: FileItemBinding) : RecyclerView.ViewHolder(binding.root) {
class ViewHolder private constructor(
root: View,
val itemLayout: CheckableForegroundLinearLayout,
val iconLayout: View,
val iconImage: ImageView,
val directoryThumbnailImage: ImageView?,
val thumbnailOutlineView: View?,
val thumbnailIconImage: ImageView?,
val thumbnailImage: ImageView,
val appIconBadgeImage: ImageView,
val badgeImage: ImageView,
val nameText: TextView,
val descriptionText: TextView?,
val menuButton: ImageButton
) : RecyclerView.ViewHolder(root) {
constructor(binding: FileItemListBinding) : this(
binding.root,
binding.itemLayout,
binding.iconLayout,
binding.iconImage,
null,
null,
null,
binding.thumbnailImage,
binding.appIconBadgeImage,
binding.badgeImage,
binding.nameText,
binding.descriptionText,
binding.menuButton
)
constructor(binding: FileItemGridBinding) : this(
binding.root,
binding.itemLayout,
binding.iconLayout,
binding.iconImage,
binding.directoryThumbnailImage,
binding.thumbnailOutlineView,
binding.thumbnailIconImage,
binding.thumbnailImage,
binding.appIconBadgeImage,
binding.badgeImage,
binding.nameText,
null,
binding.menuButton
)
lateinit var popupMenu: PopupMenu
}

View File

@ -51,6 +51,7 @@ import me.zhanghai.android.files.R
import me.zhanghai.android.files.app.application
import me.zhanghai.android.files.app.clipboardManager
import me.zhanghai.android.files.compat.checkSelfPermissionCompat
import me.zhanghai.android.files.compat.setGroupDividerEnabledCompat
import me.zhanghai.android.files.databinding.FileListFragmentAppBarIncludeBinding
import me.zhanghai.android.files.databinding.FileListFragmentBinding
import me.zhanghai.android.files.databinding.FileListFragmentBottomBarIncludeBinding
@ -149,6 +150,8 @@ class FileListFragment : Fragment(), BreadcrumbLayout.Listener, FileListAdapter.
private lateinit var bottomActionMode: ToolbarActionMode
private lateinit var layoutManager: GridLayoutManager
private lateinit var adapter: FileListAdapter
private val debouncedSearchRunnable = DebouncedRunnable(Handler(Looper.getMainLooper()), 1000) {
@ -210,7 +213,8 @@ class FileListFragment : Fragment(), BreadcrumbLayout.Listener, FileListAdapter.
)
}
binding.swipeRefreshLayout.setOnRefreshListener { this.refresh() }
binding.recyclerView.layoutManager = GridLayoutManager(activity, /* TODO */ 1)
layoutManager = GridLayoutManager(activity, 1)
binding.recyclerView.layoutManager = layoutManager
adapter = FileListAdapter(this)
binding.recyclerView.adapter = adapter
val fastScroller = ThemedFastScroller.create(binding.recyclerView)
@ -293,9 +297,10 @@ class FileListFragment : Fragment(), BreadcrumbLayout.Listener, FileListAdapter.
viewModel.breadcrumbLiveData.observe(viewLifecycleOwner) {
binding.breadcrumbLayout.setData(it)
}
viewModel.viewTypeLiveData.observe(viewLifecycleOwner) { onViewTypeChanged(it) }
viewModel.sortOptionsLiveData.observe(viewLifecycleOwner) { onSortOptionsChanged(it) }
viewModel.sortPathSpecificLiveData.observe(viewLifecycleOwner) {
onSortPathSpecificChanged(it)
viewModel.viewSortPathSpecificLiveData.observe(viewLifecycleOwner) {
onViewSortPathSpecificChanged(it)
}
viewModel.pickOptionsLiveData.observe(viewLifecycleOwner) { onPickOptionsChanged(it) }
viewModel.selectedFilesLiveData.observe(viewLifecycleOwner) { onSelectedFilesChanged(it) }
@ -317,6 +322,7 @@ class FileListFragment : Fragment(), BreadcrumbLayout.Listener, FileListAdapter.
super.onCreateOptionsMenu(menu, inflater)
menuBinding = MenuBinding.inflate(menu, inflater)
menuBinding.viewSortItem.subMenu!!.setGroupDividerEnabledCompat(true)
setUpSearchView()
}
@ -369,7 +375,7 @@ class FileListFragment : Fragment(), BreadcrumbLayout.Listener, FileListAdapter.
override fun onPrepareOptionsMenu(menu: Menu) {
super.onPrepareOptionsMenu(menu)
updateSortMenuItems()
updateViewSortMenuItems()
updateSelectAllMenuItem()
updateShowHiddenFilesMenuItem()
}
@ -385,6 +391,14 @@ class FileListFragment : Fragment(), BreadcrumbLayout.Listener, FileListAdapter.
}
true
}
R.id.action_view_list -> {
viewModel.viewType = FileViewType.LIST
true
}
R.id.action_view_grid -> {
viewModel.viewType = FileViewType.GRID
true
}
R.id.action_sort_by_name -> {
viewModel.setSortBy(By.NAME)
true
@ -415,8 +429,8 @@ class FileListFragment : Fragment(), BreadcrumbLayout.Listener, FileListAdapter.
viewModel.setSortDirectoriesFirst(!menuBinding.sortDirectoriesFirstItem.isChecked)
true
}
R.id.action_sort_path_specific -> {
viewModel.isSortPathSpecific = !menuBinding.sortPathSpecificItem.isChecked
R.id.action_view_sort_path_specific -> {
viewModel.isViewSortPathSpecific = !menuBinding.viewSortPathSpecificItem.isChecked
true
}
R.id.action_new_task -> {
@ -507,7 +521,7 @@ class FileListFragment : Fragment(), BreadcrumbLayout.Listener, FileListAdapter.
}
private fun onSearchViewExpandedChanged(expanded: Boolean) {
updateSortMenuItems()
updateViewSortMenuItems()
}
private fun onFileListChanged(stateful: Stateful<List<FileItem>>) {
@ -540,8 +554,7 @@ class FileListFragment : Fragment(), BreadcrumbLayout.Listener, FileListAdapter.
adapter.clear()
}
if (stateful is Success) {
viewModel.pendingState
?.let { binding.recyclerView.layoutManager!!.onRestoreInstanceState(it) }
viewModel.pendingState?.let { layoutManager.onRestoreInstanceState(it) }
}
}
@ -572,24 +585,39 @@ class FileListFragment : Fragment(), BreadcrumbLayout.Listener, FileListAdapter.
}
}
private fun onViewTypeChanged(viewType: FileViewType) {
layoutManager.spanCount = when (viewType) {
FileViewType.LIST -> 1
FileViewType.GRID -> (resources.configuration.screenWidthDp / 180).coerceAtLeast(2)
}
adapter.viewType = viewType
updateViewSortMenuItems()
}
private fun onSortOptionsChanged(sortOptions: FileSortOptions) {
adapter.comparator = sortOptions.createComparator()
updateSortMenuItems()
updateViewSortMenuItems()
}
private fun onSortPathSpecificChanged(pathSpecific: Boolean) {
updateSortMenuItems()
private fun onViewSortPathSpecificChanged(pathSpecific: Boolean) {
updateViewSortMenuItems()
}
private fun updateSortMenuItems() {
private fun updateViewSortMenuItems() {
if (!this::menuBinding.isInitialized) {
return
}
val searchViewExpanded = viewModel.isSearchViewExpanded
menuBinding.sortItem.isVisible = !searchViewExpanded
menuBinding.viewSortItem.isVisible = !searchViewExpanded
if (searchViewExpanded) {
return
}
val viewType = viewModel.viewType
val checkedViewTypeItem = when (viewType) {
FileViewType.LIST -> menuBinding.viewListItem
FileViewType.GRID -> menuBinding.viewGridItem
}
checkedViewTypeItem.isChecked = true
val sortOptions = viewModel.sortOptions
val checkedSortByItem = when (sortOptions.by) {
By.NAME -> menuBinding.sortByNameItem
@ -600,7 +628,7 @@ class FileListFragment : Fragment(), BreadcrumbLayout.Listener, FileListAdapter.
checkedSortByItem.isChecked = true
menuBinding.sortOrderAscendingItem.isChecked = sortOptions.order == Order.ASCENDING
menuBinding.sortDirectoriesFirstItem.isChecked = sortOptions.isDirectoriesFirst
menuBinding.sortPathSpecificItem.isChecked = viewModel.isSortPathSpecific
menuBinding.viewSortPathSpecificItem.isChecked = viewModel.isViewSortPathSpecific
}
private fun navigateUp() {
@ -664,7 +692,7 @@ class FileListFragment : Fragment(), BreadcrumbLayout.Listener, FileListAdapter.
override fun navigateTo(path: Path) {
collapseSearchView()
val state = binding.recyclerView.layoutManager!!.onSaveInstanceState()
val state = layoutManager.onSaveInstanceState()
viewModel.navigateTo(state!!, path)
}
@ -1408,14 +1436,16 @@ class FileListFragment : Fragment(), BreadcrumbLayout.Listener, FileListAdapter.
private class MenuBinding private constructor(
val menu: Menu,
val searchItem: MenuItem,
val sortItem: MenuItem,
val viewSortItem: MenuItem,
val viewListItem: MenuItem,
val viewGridItem: MenuItem,
val sortByNameItem: MenuItem,
val sortByTypeItem: MenuItem,
val sortBySizeItem: MenuItem,
val sortByLastModifiedItem: MenuItem,
val sortOrderAscendingItem: MenuItem,
val sortDirectoriesFirstItem: MenuItem,
val sortPathSpecificItem: MenuItem,
val viewSortPathSpecificItem: MenuItem,
val selectAllItem: MenuItem,
val showHiddenFilesItem: MenuItem
) {
@ -1423,14 +1453,15 @@ class FileListFragment : Fragment(), BreadcrumbLayout.Listener, FileListAdapter.
fun inflate(menu: Menu, inflater: MenuInflater): MenuBinding {
inflater.inflate(R.menu.file_list, menu)
return MenuBinding(
menu, menu.findItem(R.id.action_search), menu.findItem(R.id.action_sort),
menu, menu.findItem(R.id.action_search), menu.findItem(R.id.action_view_sort),
menu.findItem(R.id.action_view_list), menu.findItem(R.id.action_view_grid),
menu.findItem(R.id.action_sort_by_name),
menu.findItem(R.id.action_sort_by_type),
menu.findItem(R.id.action_sort_by_size),
menu.findItem(R.id.action_sort_by_last_modified),
menu.findItem(R.id.action_sort_order_ascending),
menu.findItem(R.id.action_sort_directories_first),
menu.findItem(R.id.action_sort_path_specific),
menu.findItem(R.id.action_view_sort_path_specific),
menu.findItem(R.id.action_select_all),
menu.findItem(R.id.action_show_hidden_files)
)

View File

@ -103,6 +103,14 @@ class FileListViewModel : ViewModel() {
val breadcrumbLiveData: LiveData<BreadcrumbData> = BreadcrumbLiveData(trailLiveData)
private val _viewTypeLiveData = FileViewTypeLiveData(currentPathLiveData)
val viewTypeLiveData: LiveData<FileViewType> = _viewTypeLiveData
var viewType: FileViewType
get() = _viewTypeLiveData.valueCompat
set(value) {
_viewTypeLiveData.putValue(value)
}
private val _sortOptionsLiveData = FileSortOptionsLiveData(currentPathLiveData)
val sortOptionsLiveData: LiveData<FileSortOptions> = _sortOptionsLiveData
val sortOptions: FileSortOptions
@ -115,13 +123,14 @@ class FileListViewModel : ViewModel() {
fun setSortDirectoriesFirst(isDirectoriesFirst: Boolean) =
_sortOptionsLiveData.putIsDirectoriesFirst(isDirectoriesFirst)
private val _sortPathSpecificLiveData = FileSortPathSpecificLiveData(currentPathLiveData)
val sortPathSpecificLiveData: LiveData<Boolean>
get() = _sortPathSpecificLiveData
var isSortPathSpecific: Boolean
get() = _sortPathSpecificLiveData.valueCompat
private val _viewSortPathSpecificLiveData =
FileViewSortPathSpecificLiveData(currentPathLiveData)
val viewSortPathSpecificLiveData: LiveData<Boolean>
get() = _viewSortPathSpecificLiveData
var isViewSortPathSpecific: Boolean
get() = _viewSortPathSpecificLiveData.valueCompat
set(value) {
_sortPathSpecificLiveData.putValue(value)
_viewSortPathSpecificLiveData.putValue(value)
}
private val _pickOptionsLiveData = MutableLiveData<PickOptions?>()

View File

@ -13,11 +13,12 @@ import me.zhanghai.android.files.settings.SettingLiveData
import me.zhanghai.android.files.settings.Settings
import me.zhanghai.android.files.util.valueCompat
class FileSortPathSpecificLiveData(pathLiveData: LiveData<Path>) : MediatorLiveData<Boolean>() {
class FileViewSortPathSpecificLiveData(pathLiveData: LiveData<Path>) : MediatorLiveData<Boolean>() {
private lateinit var pathViewTypeLiveData: SettingLiveData<FileViewType?>
private lateinit var pathSortOptionsLiveData: SettingLiveData<FileSortOptions?>
private fun loadValue() {
val value = pathSortOptionsLiveData.value != null
val value = pathViewTypeLiveData.value != null || pathSortOptionsLiveData.value != null
if (this.value != value) {
this.value = value
}
@ -25,10 +26,16 @@ class FileSortPathSpecificLiveData(pathLiveData: LiveData<Path>) : MediatorLiveD
fun putValue(value: Boolean) {
if (value) {
if (pathViewTypeLiveData.value == null) {
pathViewTypeLiveData.putValue(Settings.FILE_LIST_VIEW_TYPE.valueCompat)
}
if (pathSortOptionsLiveData.value == null) {
pathSortOptionsLiveData.putValue(Settings.FILE_LIST_SORT_OPTIONS.valueCompat)
}
} else {
if (pathViewTypeLiveData.value != null) {
pathViewTypeLiveData.putValue(null)
}
if (pathSortOptionsLiveData.value != null) {
pathSortOptionsLiveData.putValue(null)
}
@ -37,10 +44,15 @@ class FileSortPathSpecificLiveData(pathLiveData: LiveData<Path>) : MediatorLiveD
init {
addSource(pathLiveData) { path: Path ->
if (this::pathViewTypeLiveData.isInitialized) {
removeSource(pathViewTypeLiveData)
}
if (this::pathSortOptionsLiveData.isInitialized) {
removeSource(pathSortOptionsLiveData)
}
pathViewTypeLiveData = PathSettings.getFileListViewType(path)
pathSortOptionsLiveData = PathSettings.getFileListSortOptions(path)
addSource(pathViewTypeLiveData) { loadValue() }
addSource(pathSortOptionsLiveData) { loadValue() }
}
}

View File

@ -0,0 +1,11 @@
/*
* Copyright (c) 2023 Hai Zhang <dreaming.in.code.zh@gmail.com>
* All Rights Reserved.
*/
package me.zhanghai.android.files.filelist
enum class FileViewType {
LIST,
GRID
}

View File

@ -0,0 +1,48 @@
/*
* Copyright (c) 2023 Hai Zhang <dreaming.in.code.zh@gmail.com>
* All Rights Reserved.
*/
package me.zhanghai.android.files.filelist
import androidx.lifecycle.LiveData
import androidx.lifecycle.MediatorLiveData
import java8.nio.file.Path
import me.zhanghai.android.files.settings.PathSettings
import me.zhanghai.android.files.settings.SettingLiveData
import me.zhanghai.android.files.settings.Settings
import me.zhanghai.android.files.util.valueCompat
class FileViewTypeLiveData(pathLiveData: LiveData<Path>) : MediatorLiveData<FileViewType>() {
private lateinit var pathViewTypeLiveData: SettingLiveData<FileViewType?>
private fun loadValue() {
if (!this::pathViewTypeLiveData.isInitialized) {
// Not yet initialized.
return
}
val value = pathViewTypeLiveData.value ?: Settings.FILE_LIST_VIEW_TYPE.valueCompat
if (this.value != value) {
this.value = value
}
}
fun putValue(value: FileViewType) {
if (pathViewTypeLiveData.value != null) {
pathViewTypeLiveData.putValue(value)
} else {
Settings.FILE_LIST_VIEW_TYPE.putValue(value)
}
}
init {
addSource(Settings.FILE_LIST_VIEW_TYPE) { loadValue() }
addSource(pathLiveData) { path: Path ->
if (this::pathViewTypeLiveData.isInitialized) {
removeSource(pathViewTypeLiveData)
}
pathViewTypeLiveData = PathSettings.getFileListViewType(path)
addSource(pathViewTypeLiveData) { loadValue() }
}
}
}

View File

@ -5,14 +5,22 @@
package me.zhanghai.android.files.settings
import androidx.core.content.res.ResourcesCompat
import java8.nio.file.Path
import me.zhanghai.android.files.R
import me.zhanghai.android.files.filelist.FileSortOptions
import me.zhanghai.android.files.filelist.FileViewType
object PathSettings {
private const val NAME_SUFFIX = "path"
@Suppress("UNCHECKED_CAST")
fun getFileListViewType(path: Path): SettingLiveData<FileViewType?> =
EnumSettingLiveData(
NAME_SUFFIX, R.string.pref_key_file_list_view_type, path.toString(),
ResourcesCompat.ID_NULL, FileViewType::class.java
) as SettingLiveData<FileViewType?>
fun getFileListSortOptions(path: Path): SettingLiveData<FileSortOptions?> =
ParcelValueSettingLiveData(
NAME_SUFFIX, R.string.pref_key_file_list_sort_options, path.toString(), null

View File

@ -14,6 +14,7 @@ import androidx.annotation.DimenRes
import androidx.annotation.IntegerRes
import androidx.annotation.StringRes
import androidx.core.content.edit
import androidx.core.content.res.ResourcesCompat
import me.zhanghai.android.files.app.appClassLoader
import me.zhanghai.android.files.app.application
import me.zhanghai.android.files.util.Base64
@ -196,7 +197,10 @@ class BooleanSettingLiveData(
}
// Use string resource for default value so that we can support ListPreference.
class EnumSettingLiveData<E : Enum<E>>(
// TODO: kotlinc: Type argument is not within its bounds: should be subtype of 'Enum<E>'
// https://youtrack.jetbrains.com/issue/KT-60985
//class EnumSettingLiveData<E : Enum<E>?>(
class EnumSettingLiveData<E : Enum<*>?>(
nameSuffix: String?,
@StringRes keyRes: Int,
keySuffix: String?,
@ -216,7 +220,12 @@ class EnumSettingLiveData<E : Enum<E>>(
}
override fun getDefaultValue(@StringRes defaultValueRes: Int): E =
enumValues[application.getString(defaultValueRes).toInt()]
if (defaultValueRes != ResourcesCompat.ID_NULL) {
enumValues[application.getString(defaultValueRes).toInt()]
} else {
@Suppress("UNCHECKED_CAST")
null as E
}
override fun getValue(
sharedPreferences: SharedPreferences,
@ -228,7 +237,7 @@ class EnumSettingLiveData<E : Enum<E>>(
}
override fun putValue(sharedPreferences: SharedPreferences, key: String, value: E) {
sharedPreferences.edit { putString(key, value.ordinal.toString()) }
sharedPreferences.edit { putString(key, value?.ordinal?.toString()) }
}
}

View File

@ -13,6 +13,7 @@ import me.zhanghai.android.files.R
import me.zhanghai.android.files.app.application
import me.zhanghai.android.files.compat.EnvironmentCompat2
import me.zhanghai.android.files.filelist.FileSortOptions
import me.zhanghai.android.files.filelist.FileViewType
import me.zhanghai.android.files.filelist.OpenApkDefaultAction
import me.zhanghai.android.files.navigation.BookmarkDirectory
import me.zhanghai.android.files.navigation.StandardDirectorySettings
@ -50,6 +51,12 @@ object Settings {
R.bool.pref_default_value_file_list_show_hidden_files
)
val FILE_LIST_VIEW_TYPE: SettingLiveData<FileViewType> =
EnumSettingLiveData(
R.string.pref_key_file_list_view_type, R.string.pref_default_value_file_list_view_type,
FileViewType::class.java
)
val FILE_LIST_SORT_OPTIONS: SettingLiveData<FileSortOptions> =
ParcelValueSettingLiveData(
R.string.pref_key_file_list_sort_options,

View File

@ -0,0 +1,64 @@
/*
* Copyright (c) 2023 Hai Zhang <dreaming.in.code.zh@gmail.com>
* All Rights Reserved.
*/
package me.zhanghai.android.files.ui
import android.annotation.SuppressLint
import android.content.Context
import android.util.AttributeSet
import android.widget.FrameLayout
import androidx.annotation.AttrRes
import androidx.annotation.StyleRes
import me.zhanghai.android.files.R
import me.zhanghai.android.files.compat.obtainStyledAttributesCompat
import me.zhanghai.android.files.compat.use
import kotlin.math.roundToInt
class AspectRatioFrameLayout @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
@AttrRes defStyleAttr: Int = 0,
@StyleRes defStyleRes: Int = 0
) : FrameLayout(context, attrs, defStyleAttr, defStyleRes) {
@SuppressLint("RestrictedApi")
var ratio: Float = context.obtainStyledAttributesCompat(
attrs, R.styleable.AspectRatioFrameLayout, defStyleAttr, defStyleRes
).use { it.getFloat(R.styleable.AspectRatioFrameLayout_aspectRatio, 0f) }
set(value) {
if (field == value) {
return
}
field = value
requestLayout()
invalidate()
}
fun setRatio(width: Float, height: Float) {
ratio = width / height
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val newWidthMeasureSpec: Int
val newHeightMeasureSpec: Int
if (ratio > 0) {
val widthMode = MeasureSpec.getMode(widthMeasureSpec)
if (widthMode == MeasureSpec.EXACTLY) {
val width = MeasureSpec.getSize(widthMeasureSpec)
val height = (width / ratio).roundToInt().coerceAtLeast(minimumHeight)
newWidthMeasureSpec = widthMeasureSpec
newHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
} else {
val height = MeasureSpec.getSize(heightMeasureSpec)
val width = (ratio * height).roundToInt().coerceAtLeast(minimumWidth)
newWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY)
newHeightMeasureSpec = heightMeasureSpec
}
} else {
newWidthMeasureSpec = widthMeasureSpec
newHeightMeasureSpec = heightMeasureSpec
}
super.onMeasure(newWidthMeasureSpec, newHeightMeasureSpec)
}
}

View File

@ -0,0 +1,62 @@
/*
* Copyright (c) 2023 Hai Zhang <dreaming.in.code.zh@gmail.com>
* All Rights Reserved.
*/
package me.zhanghai.android.files.ui
import android.annotation.SuppressLint
import android.content.Context
import android.util.AttributeSet
import androidx.annotation.AttrRes
import com.google.android.material.imageview.ShapeableImageView
import me.zhanghai.android.files.R
import me.zhanghai.android.files.compat.obtainStyledAttributesCompat
import me.zhanghai.android.files.compat.use
import kotlin.math.roundToInt
open class AspectRatioImageView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
@AttrRes defStyleAttr: Int = 0
) : ShapeableImageView(context, attrs, defStyleAttr) {
@SuppressLint("RestrictedApi")
var ratio: Float = context.obtainStyledAttributesCompat(
attrs, R.styleable.AspectRatioFrameLayout, defStyleAttr
).use { it.getFloat(R.styleable.AspectRatioFrameLayout_aspectRatio, 0f) }
set(value) {
if (field == value) {
return
}
field = value
requestLayout()
invalidate()
}
fun setRatio(width: Float, height: Float) {
ratio = width / height
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val newWidthMeasureSpec: Int
val newHeightMeasureSpec: Int
if (ratio > 0) {
val widthMode = MeasureSpec.getMode(widthMeasureSpec)
if (widthMode == MeasureSpec.EXACTLY) {
val width = MeasureSpec.getSize(widthMeasureSpec)
val height = (width / ratio).roundToInt().coerceIn(minimumHeight, maxHeight)
newWidthMeasureSpec = widthMeasureSpec
newHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
} else {
val height = MeasureSpec.getSize(heightMeasureSpec)
val width = (ratio * height).roundToInt().coerceIn(minimumWidth, maxWidth)
newWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY)
newHeightMeasureSpec = heightMeasureSpec
}
} else {
newWidthMeasureSpec = widthMeasureSpec
newHeightMeasureSpec = heightMeasureSpec
}
super.onMeasure(newWidthMeasureSpec, newHeightMeasureSpec)
}
}

View File

@ -10,8 +10,12 @@ import android.content.Context
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import androidx.annotation.Dimension
import androidx.appcompat.graphics.drawable.AnimatedStateListDrawableCompat
import me.zhanghai.android.files.util.asColor
import me.zhanghai.android.files.util.dpToDimension
import me.zhanghai.android.files.util.dpToDimensionPixelOffset
import me.zhanghai.android.files.util.getColorByAttr
import me.zhanghai.android.files.util.shortAnimTime
import me.zhanghai.android.files.util.withModulatedAlpha
@ -24,14 +28,22 @@ object CheckableItemBackground {
// Note that the <selector>s used in Material Components are color resources, so they are
// inflated as ColorStateList instead of StateListDrawable and don't have this problem.
@SuppressLint("RestrictedApi")
fun create(context: Context): Drawable =
fun create(
@Dimension(unit = Dimension.DP) insetDp: Float,
@Dimension(unit = Dimension.DP) cornerSizeDp: Float,
context: Context
): Drawable =
AnimatedStateListDrawableCompat().apply {
val shortAnimTime = context.shortAnimTime
setEnterFadeDuration(shortAnimTime)
setExitFadeDuration(shortAnimTime)
val primaryColor = context.getColorByAttr(androidx.appcompat.R.attr.colorPrimary)
val checkedColor = primaryColor.asColor().withModulatedAlpha(0.12f).value
addState(intArrayOf(android.R.attr.state_checked), ColorDrawable(checkedColor))
val checkedDrawable = GradientDrawable().apply {
cornerRadius = context.dpToDimension(cornerSizeDp)
val primaryColor = context.getColorByAttr(androidx.appcompat.R.attr.colorPrimary)
setColor(primaryColor.asColor().withModulatedAlpha(0.12f).value)
setStroke(2 * context.dpToDimensionPixelOffset(insetDp), Color.TRANSPARENT)
}
addState(intArrayOf(android.R.attr.state_checked), checkedDrawable)
addState(intArrayOf(), ColorDrawable(Color.TRANSPARENT))
}
}

View File

@ -9,7 +9,6 @@ import android.content.Context
import android.graphics.drawable.Drawable
import android.util.AttributeSet
import androidx.annotation.AttrRes
import androidx.appcompat.widget.AppCompatImageView
import me.zhanghai.android.files.util.getFloatByAttr
import kotlin.math.roundToInt
@ -17,7 +16,7 @@ class DisabledAlphaImageView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
@AttrRes defStyleAttr: Int = 0
) : AppCompatImageView(context, attrs, defStyleAttr) {
) : AspectRatioImageView(context, attrs, defStyleAttr) {
override fun setImageDrawable(drawable: Drawable?) {
super.setImageDrawable(drawable)

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2023 Hai Zhang <dreaming.in.code.zh@gmail.com>
~ All Rights Reserved.
-->
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="20dp"
android:height="20dp"
android:viewportWidth="20"
android:viewportHeight="20">
<path
android:fillColor="?colorControlNormal"
android:pathData="M8,2H2C0.9,2 0,2.9 0,4v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6C20,4.9 19.1,4 18,4h-8z" />
</vector>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2023 Hai Zhang <dreaming.in.code.zh@gmail.com>
~ All Rights Reserved.
-->
<ripple
xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?colorControlHighlight">
<item android:id="@android:id/mask">
<shape android:shape="rectangle">
<corners android:radius="12dp" />
<solid android:color="@android:color/white" />
<stroke android:color="@android:color/transparent" android:width="8dp" />
</shape>
</item>
</ripple>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2023 Hai Zhang <dreaming.in.code.zh@gmail.com>
~ All Rights Reserved.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="8dp" />
<stroke
android:color="@color/material_on_surface_stroke"
android:width="1dp" />
</shape>

View File

@ -0,0 +1,141 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2023 Hai Zhang <dreaming.in.code.zh@gmail.com>
~ All Rights Reserved.
-->
<me.zhanghai.android.files.ui.CheckableForegroundLinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/itemLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:foreground="@drawable/file_item_grid_foreground"
android:gravity="center_vertical"
android:orientation="vertical">
<me.zhanghai.android.files.ui.AspectRatioFrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/screen_edge_margin"
android:layout_marginEnd="@dimen/screen_edge_margin"
android:layout_marginTop="@dimen/screen_edge_margin"
android:duplicateParentState="true"
app:aspectRatio="1.78">
<me.zhanghai.android.files.ui.DisabledAlphaImageView
android:id="@+id/directoryThumbnailImage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:duplicateParentState="true"
android:scaleType="fitCenter"
android:src="@drawable/file_directory_thumbnail" />
<me.zhanghai.android.files.ui.DisabledAlphaImageView
android:id="@+id/thumbnailIconImage"
android:layout_width="@dimen/large_icon_size"
android:layout_height="@dimen/large_icon_size"
android:layout_gravity="center"
android:duplicateParentState="true"
android:scaleType="centerCrop" />
<!--
~ Can't use ShapeableImageView stroke support due to
~ https://github.com/material-components/material-components-android/issues/1329
-->
<me.zhanghai.android.files.ui.DisabledAlphaImageView
android:id="@+id/thumbnailImage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:duplicateParentState="true"
android:scaleType="centerCrop"
app:shapeAppearance="?shapeAppearanceMediumComponent" />
<View
android:id="@+id/thumbnailOutlineView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/file_item_grid_thumbnail_outline"
android:duplicateParentState="true" />
</me.zhanghai.android.files.ui.AspectRatioFrameLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="@dimen/single_line_list_item_height"
android:layout_marginBottom="@dimen/screen_edge_margin_minus_8dp"
android:duplicateParentState="true"
android:gravity="center_vertical"
android:orientation="horizontal">
<FrameLayout
android:id="@+id/iconLayout"
android:layout_width="@dimen/touch_target_size"
android:layout_height="@dimen/touch_target_size"
android:layout_marginStart="@dimen/screen_edge_margin_minus_12dp"
android:duplicateParentState="true"
android:padding="@dimen/touch_target_large_icon_padding">
<me.zhanghai.android.files.ui.DisabledAlphaImageView
android:id="@+id/iconImage"
android:layout_width="@dimen/icon_size"
android:layout_height="@dimen/icon_size"
android:layout_gravity="center"
android:duplicateParentState="true"
android:scaleType="centerCrop" />
<me.zhanghai.android.files.ui.DisabledAlphaImageView
android:id="@+id/appIconBadgeImage"
android:layout_width="@dimen/badge_size_plus_1dp"
android:layout_height="@dimen/badge_size_plus_1dp"
android:layout_gravity="end|bottom"
android:layout_marginStart="-0.5dp"
android:layout_marginEnd="-0.5dp"
android:layout_marginTop="-0.5dp"
android:layout_marginBottom="-0.5dp"
android:duplicateParentState="true" />
<me.zhanghai.android.files.ui.DisabledAlphaImageView
android:id="@+id/badgeImage"
android:layout_width="@dimen/badge_size"
android:layout_height="@dimen/badge_size"
android:layout_gravity="end|bottom"
android:background="@drawable/badge_background_18dp"
android:duplicateParentState="true" />
<me.zhanghai.android.files.ui.DisabledAlphaImageView
android:layout_width="@dimen/badge_size"
android:layout_height="@dimen/badge_size"
android:layout_gravity="end|bottom"
android:duplicateParentState="true"
android:src="@drawable/checkable_badge_18dp" />
</FrameLayout>
<TextView
android:id="@+id/nameText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:duplicateParentState="true"
android:ellipsize="end"
android:gravity="center"
android:maxLines="2"
android:textAppearance="?textAppearanceListItemSecondary" />
<!--
~ Cannot use android:duplicateParentState="true" because a button needs to have its own
~ pressed state, etc. Necessary states will be duplicated manually in the adapter
~ implementation.
-->
<me.zhanghai.android.foregroundcompat.ForegroundImageButton
android:id="@+id/menuButton"
android:layout_width="@dimen/touch_target_size"
android:layout_height="@dimen/touch_target_size"
android:layout_marginEnd="@dimen/screen_edge_margin_minus_12dp"
android:padding="@dimen/touch_target_icon_padding"
android:background="@null"
android:foreground="@drawable/selectable_item_background_oval"
android:src="@drawable/more_vertical_icon_white_24dp"
app:tint="?colorControlNormal" />
</LinearLayout>
</me.zhanghai.android.files.ui.CheckableForegroundLinearLayout>

View File

@ -61,7 +61,7 @@
android:paddingBottom="@dimen/list_bottom_padding_with_fab"
android:clipToPadding="false"
android:fitsSystemWindows="true"
tools:listitem="@layout/file_item" />
tools:listitem="@layout/file_item_list" />
</androidx.swiperefreshlayout.widget.ThemedSwipeRefreshLayout>
</me.zhanghai.android.files.ui.CoordinatorScrollingFrameLayout>
</merge>

View File

@ -20,13 +20,25 @@
app:showAsAction="always|collapseActionView" />
<item
android:id="@+id/action_sort"
android:id="@+id/action_view_sort"
android:icon="@drawable/sort_icon_control_normal_24dp"
android:orderInCategory="100"
android:title="@string/sort"
android:title="@string/file_list_action_view_sort"
app:showAsAction="always">
<menu>
<group android:checkableBehavior="single">
<group
android:id="@+id/group_view"
android:checkableBehavior="single">
<item
android:id="@+id/action_view_list"
android:title="@string/file_list_action_view_list" />
<item
android:id="@+id/action_view_grid"
android:title="@string/file_list_action_view_grid" />
</group>
<group
android:id="@+id/group_sort"
android:checkableBehavior="single">
<item
android:id="@+id/action_sort_by_name"
android:title="@string/file_list_action_sort_by_name" />
@ -39,19 +51,19 @@
<item
android:id="@+id/action_sort_by_last_modified"
android:title="@string/file_list_action_sort_by_last_modified" />
<item
android:id="@+id/action_sort_order_ascending"
android:checkable="true"
android:title="@string/file_list_action_sort_order_ascending" />
<item
android:id="@+id/action_sort_directories_first"
android:checkable="true"
android:title="@string/file_list_action_sort_directories_first" />
</group>
<item
android:id="@+id/action_sort_order_ascending"
android:id="@+id/action_view_sort_path_specific"
android:checkable="true"
android:title="@string/file_list_action_sort_order_ascending" />
<item
android:id="@+id/action_sort_directories_first"
android:checkable="true"
android:title="@string/file_list_action_sort_directories_first" />
<item
android:id="@+id/action_sort_path_specific"
android:checkable="true"
android:title="@string/file_list_action_sort_path_specific" />
android:title="@string/file_list_action_view_sort_path_specific" />
</menu>
</item>

View File

@ -42,7 +42,6 @@
<string name="share">مشاركة</string>
<string name="show">إظهار</string>
<string name="skip">تخطى</string>
<string name="sort">فرز</string>
<string name="stop">إيقاف</string>
<string name="unknown">غير معروف</string>
<string name="view">عرض</string>
@ -390,7 +389,7 @@
<string name="file_list_action_sort_by_last_modified">آخر تعديل</string>
<string name="file_list_action_sort_order_ascending">تصاعدي</string>
<string name="file_list_action_sort_directories_first">المجلدات أولًا</string>
<string name="file_list_action_sort_path_specific">فقط لهذا المجلد</string>
<string name="file_list_action_view_sort_path_specific">فقط لهذا المجلد</string>
<string name="file_list_action_new_task">نافذة جديدة</string>
<string name="file_list_action_navigate_up">اذهب للأعلى</string>
<string name="file_list_action_navigate_to">اذهب إلى</string>

View File

@ -40,7 +40,6 @@
<string name="share">Споделяне</string>
<string name="show">Показване</string>
<string name="skip">Пропускане</string>
<string name="sort">Подреждане</string>
<string name="stop">Спиране</string>
<string name="unknown">Неизвестно</string>
<string name="view">Изглед</string>
@ -260,7 +259,7 @@
<string name="file_list_action_sort_by_last_modified">Последна промяна</string>
<string name="file_list_action_sort_order_ascending">Възходящ</string>
<string name="file_list_action_sort_directories_first">Първо папките</string>
<string name="file_list_action_sort_path_specific">Само тази папка</string>
<string name="file_list_action_view_sort_path_specific">Само тази папка</string>
<string name="file_list_action_new_task">Нов прозорец</string>
<string name="file_list_action_navigate_up">Нагоре</string>
<string name="file_list_action_show_hidden_files">Показване на скрити файлове</string>

View File

@ -41,7 +41,6 @@
<string name="share">Sdílet</string>
<string name="show">Ukázat</string>
<string name="skip">Přeskočit</string>
<string name="sort">Seřadit</string>
<string name="stop">Zastavit</string>
<string name="unknown">Neznámý</string>
<string name="view">Zobrazení</string>
@ -313,7 +312,7 @@
<string name="file_list_action_sort_by_last_modified">Naposledy změněno</string>
<string name="file_list_action_sort_order_ascending">Vzestupně</string>
<string name="file_list_action_sort_directories_first">Složky jako první</string>
<string name="file_list_action_sort_path_specific">Pouze pro tuto složku</string>
<string name="file_list_action_view_sort_path_specific">Pouze pro tuto složku</string>
<string name="file_list_action_new_task">Nové okno</string>
<string name="file_list_action_navigate_up">Nahoru</string>
<string name="file_list_action_show_hidden_files">Zobrazit skryté soubory</string>

View File

@ -42,7 +42,6 @@
<string name="share">Teilen</string>
<string name="show">Anzeigen</string>
<string name="skip">Überspringen</string>
<string name="sort">Sortieren</string>
<string name="stop">Stopp</string>
<string name="unknown">Unbekannt</string>
<string name="view">Anzeigen</string>
@ -278,7 +277,7 @@
<string name="file_list_action_sort_by_last_modified">Zuletzt geändert</string>
<string name="file_list_action_sort_order_ascending">Aufsteigend</string>
<string name="file_list_action_sort_directories_first">Ordner zuerst</string>
<string name="file_list_action_sort_path_specific">Nur für diesen Ordner</string>
<string name="file_list_action_view_sort_path_specific">Nur für diesen Ordner</string>
<string name="file_list_action_new_task">Neues Fenster</string>
<string name="file_list_action_navigate_up">Gehe hoch</string>
<string name="file_list_action_navigate_to">Gehe zu</string>

View File

@ -41,7 +41,6 @@
<string name="share">Compartir</string>
<string name="show">Mostrar</string>
<string name="skip">Saltar</string>
<string name="sort">Clasificar</string>
<string name="stop">Parar</string>
<string name="unknown">Desconocido</string>
<string name="view">Ver</string>
@ -261,7 +260,7 @@
<string name="file_list_action_sort_by_last_modified">Última modificación</string>
<string name="file_list_action_sort_order_ascending">Ascendente</string>
<string name="file_list_action_sort_directories_first">Carpetas primero</string>
<string name="file_list_action_sort_path_specific">Sólo para esta carpeta</string>
<string name="file_list_action_view_sort_path_specific">Sólo para esta carpeta</string>
<string name="file_list_action_new_task">Nueva ventana</string>
<string name="file_list_action_navigate_up">Subir</string>
<string name="file_list_action_show_hidden_files">Mostrar archivos ocultos</string>

View File

@ -38,7 +38,6 @@
<string name="select_all">Hautatu guztiak</string>
<string name="share">Partekatu</string>
<string name="skip">Saltatu</string>
<string name="sort">Ordenatu</string>
<string name="stop">Gelditu</string>
<string name="unknown">Ezezaguna</string>
<string name="view">Ikusi</string>
@ -256,7 +255,7 @@
<string name="file_list_action_sort_by_last_modified">Azken aldaketa</string>
<string name="file_list_action_sort_order_ascending">Gorantza</string>
<string name="file_list_action_sort_directories_first">Karpetak aurretik</string>
<string name="file_list_action_sort_path_specific">Karpeta honetan bakarrik</string>
<string name="file_list_action_view_sort_path_specific">Karpeta honetan bakarrik</string>
<string name="file_list_action_new_task">Leiho berria</string>
<string name="file_list_action_navigate_up">Joan gora</string>
<string name="file_list_action_show_hidden_files">Erakutsi ezkutatutako fitxategiak</string>

View File

@ -43,7 +43,6 @@
<string name="share">هم‌رسانی</string>
<string name="show">نمایش</string>
<string name="skip">پرش</string>
<string name="sort">چینش</string>
<string name="stop">توقّف</string>
<string name="unknown">ناشناس</string>
<string name="view">دیدن</string>
@ -265,7 +264,7 @@
<string name="file_list_action_sort_by_last_modified">آخرین تغییر</string>
<string name="file_list_action_sort_order_ascending">بالا رونده</string>
<string name="file_list_action_sort_directories_first">ابتدا شاخه‌ها</string>
<string name="file_list_action_sort_path_specific">تنها برای این شاخه</string>
<string name="file_list_action_view_sort_path_specific">تنها برای این شاخه</string>
<string name="file_list_action_new_task">پنجرهٔ جدید</string>
<string name="file_list_action_navigate_up">برو بالا</string>
<string name="file_list_action_show_hidden_files">نمایش پرونده‌های پنهان</string>

View File

@ -44,7 +44,6 @@
<string name="share">Partager</string>
<string name="show">Montrer</string>
<string name="skip">Passer</string>
<string name="sort">Trier</string>
<string name="stop">Arrêter</string>
<string name="unknown">Inconnu</string>
<string name="view">Voir</string>
@ -280,7 +279,7 @@
<string name="file_list_action_sort_by_last_modified">Dernière modification</string>
<string name="file_list_action_sort_order_ascending">Ascendant</string>
<string name="file_list_action_sort_directories_first">Dossiers en premier</string>
<string name="file_list_action_sort_path_specific">Seulement pour ce dossier</string>
<string name="file_list_action_view_sort_path_specific">Seulement pour ce dossier</string>
<string name="file_list_action_new_task">Nouvelle fenêtre</string>
<string name="file_list_action_navigate_up">Aller en haut</string>
<string name="file_list_action_navigate_to">Aller à</string>

View File

@ -41,7 +41,6 @@
<string name="share">Megosztás</string>
<string name="show">Megjelenítés</string>
<string name="skip">Kihagyás</string>
<string name="sort">Rendezés</string>
<string name="stop">Leállítás</string>
<string name="unknown">Ismeretlen</string>
<string name="view">Nézet</string>
@ -261,7 +260,7 @@
<string name="file_list_action_sort_by_last_modified">Utoljára módosítva</string>
<string name="file_list_action_sort_order_ascending">Növekvő</string>
<string name="file_list_action_sort_directories_first">Mappák elöl</string>
<string name="file_list_action_sort_path_specific">Csak ennél a mappánál</string>
<string name="file_list_action_view_sort_path_specific">Csak ennél a mappánál</string>
<string name="file_list_action_new_task">Új ablak</string>
<string name="file_list_action_navigate_up">Ugrás fel</string>
<string name="file_list_action_show_hidden_files">Rejtett fájlok megjelenítése</string>

View File

@ -42,7 +42,6 @@
<string name="share">Bagikan</string>
<string name="show">Tampilkan</string>
<string name="skip">Lewati</string>
<string name="sort">Urutkan</string>
<string name="stop">Setop</string>
<string name="unknown">Tidak diketahui</string>
<string name="view">Lihat</string>
@ -250,7 +249,7 @@
<string name="file_list_action_sort_by_last_modified">Terakhir diubah</string>
<string name="file_list_action_sort_order_ascending">Naik</string>
<string name="file_list_action_sort_directories_first">Folder di atas</string>
<string name="file_list_action_sort_path_specific">Hanya untuk folder ini</string>
<string name="file_list_action_view_sort_path_specific">Hanya untuk folder ini</string>
<string name="file_list_action_new_task">Jendela baru</string>
<string name="file_list_action_navigate_up">Ke atas</string>
<string name="file_list_action_navigate_to">Kunjungi</string>

View File

@ -44,7 +44,6 @@
<string name="share">Deila</string>
<string name="show">Birta</string>
<string name="skip">Sleppa</string>
<string name="sort">Raða</string>
<string name="stop">Stöðva</string>
<string name="unknown">Óþekkt</string>
<string name="view">Skoða</string>
@ -280,7 +279,7 @@
<string name="file_list_action_sort_by_last_modified">Síðast breytt</string>
<string name="file_list_action_sort_order_ascending">Hækkandi</string>
<string name="file_list_action_sort_directories_first">Möppur fyrst</string>
<string name="file_list_action_sort_path_specific">Aðeins í þessari möppu</string>
<string name="file_list_action_view_sort_path_specific">Aðeins í þessari möppu</string>
<string name="file_list_action_new_task">Nýr gluggi</string>
<string name="file_list_action_navigate_up">Fara upp</string>
<string name="file_list_action_navigate_to">Fara í</string>

View File

@ -42,7 +42,6 @@
<string name="share">Condividi</string>
<string name="show">Mostra</string>
<string name="skip">Salta</string>
<string name="sort">Ordina</string>
<string name="stop">Ferma</string>
<string name="unknown">Sconosciuto</string>
<string name="view">Visualizza</string>
@ -278,7 +277,7 @@
<string name="file_list_action_sort_by_last_modified">Ultima modifica</string>
<string name="file_list_action_sort_order_ascending">Crescente</string>
<string name="file_list_action_sort_directories_first">Prima le cartelle</string>
<string name="file_list_action_sort_path_specific">Solo per questa cartella</string>
<string name="file_list_action_view_sort_path_specific">Solo per questa cartella</string>
<string name="file_list_action_new_task">Nuova finestra</string>
<string name="file_list_action_navigate_up">Cartella superiore</string>
<string name="file_list_action_navigate_to">Vai in</string>

View File

@ -42,7 +42,6 @@
<string name="share">שיתוף</string>
<string name="show">הצגה</string>
<string name="skip">דילוג</string>
<string name="sort">מיון</string>
<string name="stop">עצירה</string>
<string name="unknown">לא ידוע</string>
<string name="view">הצגה</string>
@ -334,7 +333,7 @@
<string name="file_list_action_sort_by_last_modified">השתנה לאחרונה</string>
<string name="file_list_action_sort_order_ascending">עולה</string>
<string name="file_list_action_sort_directories_first">תיקיות תחילה</string>
<string name="file_list_action_sort_path_specific">לתיקייה זו בלבד</string>
<string name="file_list_action_view_sort_path_specific">לתיקייה זו בלבד</string>
<string name="file_list_action_new_task">חלון חדש</string>
<string name="file_list_action_navigate_up">עלה</string>
<string name="file_list_action_navigate_to">מעבר אל</string>

View File

@ -42,7 +42,6 @@
<string name="share">共有</string>
<string name="show">示す</string>
<string name="skip">スキップ</string>
<string name="sort">並び替え</string>
<string name="stop">停止</string>
<string name="unknown">不明</string>
<string name="view">表示</string>
@ -250,7 +249,7 @@
<string name="file_list_action_sort_by_last_modified">更新日時</string>
<string name="file_list_action_sort_order_ascending">昇順</string>
<string name="file_list_action_sort_directories_first">フォルダを先頭に表示</string>
<string name="file_list_action_sort_path_specific">このフォルダのみに適用</string>
<string name="file_list_action_view_sort_path_specific">このフォルダのみに適用</string>
<string name="file_list_action_new_task">新しい画面</string>
<string name="file_list_action_navigate_up">上へ移動</string>
<string name="file_list_action_navigate_to">ここへ移動</string>

View File

@ -42,7 +42,6 @@
<string name="share">공유</string>
<string name="show">표시</string>
<string name="skip">건너 뛰기</string>
<string name="sort">정렬</string>
<string name="stop">중지</string>
<string name="unknown">알 수 없음</string>
<string name="view">보기</string>
@ -250,7 +249,7 @@
<string name="file_list_action_sort_by_last_modified">수정된 날짜</string>
<string name="file_list_action_sort_order_ascending">오름차순</string>
<string name="file_list_action_sort_directories_first">폴더를 먼저 표시</string>
<string name="file_list_action_sort_path_specific">이 폴더에만 적용</string>
<string name="file_list_action_view_sort_path_specific">이 폴더에만 적용</string>
<string name="file_list_action_new_task">새 창</string>
<string name="file_list_action_navigate_up">상위 폴더로</string>
<string name="file_list_action_navigate_to">이동</string>

View File

@ -42,7 +42,6 @@
<string name="share">Delen</string>
<string name="show">Tonen</string>
<string name="skip">Overslaan</string>
<string name="sort">Sorteren</string>
<string name="stop">Stoppen</string>
<string name="unknown">Onbekend</string>
<string name="view">Bekijken</string>
@ -278,7 +277,7 @@
<string name="file_list_action_sort_by_last_modified">Aangepast op</string>
<string name="file_list_action_sort_order_ascending">Oplopend</string>
<string name="file_list_action_sort_directories_first">Mappen vóór bestanden</string>
<string name="file_list_action_sort_path_specific">Alleen in deze map</string>
<string name="file_list_action_view_sort_path_specific">Alleen in deze map</string>
<string name="file_list_action_new_task">Nieuw venster</string>
<string name="file_list_action_navigate_up">Ga omhoog</string>
<string name="file_list_action_navigate_to">Ga naar</string>

View File

@ -42,7 +42,6 @@
<string name="share">Udostępnij </string>
<string name="show">Pokaż</string>
<string name="skip">Pomiń</string>
<string name="sort">Sortowanie</string>
<string name="stop">Zatrzymaj</string>
<string name="unknown">Nieznany</string>
<string name="view">Podgląd</string>
@ -334,7 +333,7 @@
<string name="file_list_action_sort_by_last_modified">Ostatnia modyfikacja</string>
<string name="file_list_action_sort_order_ascending">Rosnąco</string>
<string name="file_list_action_sort_directories_first">Najpierw katalogi</string>
<string name="file_list_action_sort_path_specific">Tylko dla tego katalogu</string>
<string name="file_list_action_view_sort_path_specific">Tylko dla tego katalogu</string>
<string name="file_list_action_new_task">Nowe okno</string>
<string name="file_list_action_navigate_up">Idź w górę</string>
<string name="file_list_action_navigate_to">Idź do</string>

View File

@ -43,7 +43,6 @@
<string name="share">Compartilhar</string>
<string name="show">Mostrar</string>
<string name="skip">Próximo</string>
<string name="sort">Classificar</string>
<string name="stop">Parar</string>
<string name="unknown">Desconhecido</string>
<string name="view">Visualizar</string>
@ -263,7 +262,7 @@
<string name="file_list_action_sort_by_last_modified">Última modificação</string>
<string name="file_list_action_sort_order_ascending">Crescente</string>
<string name="file_list_action_sort_directories_first">Pastas primeiro</string>
<string name="file_list_action_sort_path_specific">Somente para esta pasta</string>
<string name="file_list_action_view_sort_path_specific">Somente para esta pasta</string>
<string name="file_list_action_new_task">Nova janela</string>
<string name="file_list_action_navigate_up">Subir</string>
<string name="file_list_action_show_hidden_files">Mostrar arquivos ocultos</string>

View File

@ -42,7 +42,6 @@
<string name="share">Partilhar</string>
<string name="show">Mostrar</string>
<string name="skip">Ignorar</string>
<string name="sort">Ordenar</string>
<string name="stop">Parar</string>
<string name="unknown">Desconhecido</string>
<string name="view">Ver</string>
@ -262,7 +261,7 @@
<string name="file_list_action_sort_by_last_modified">Última modificação</string>
<string name="file_list_action_sort_order_ascending">Ascendente</string>
<string name="file_list_action_sort_directories_first">Pastas primeiro</string>
<string name="file_list_action_sort_path_specific">Apenas para esta pasta</string>
<string name="file_list_action_view_sort_path_specific">Apenas para esta pasta</string>
<string name="file_list_action_new_task">Nova janela</string>
<string name="file_list_action_navigate_up">Subir</string>
<string name="file_list_action_show_hidden_files">Mostrar ficheiros ocultos</string>

View File

@ -42,7 +42,6 @@
<string name="share">Partajează</string>
<string name="show">Arată</string>
<string name="skip">Omite</string>
<string name="sort">Sortează</string>
<string name="stop">Oprire</string>
<string name="unknown">Necunoscut</string>
<string name="view">Vizualizează</string>
@ -306,7 +305,7 @@
<string name="file_list_action_sort_by_last_modified">Ultima modificare</string>
<string name="file_list_action_sort_order_ascending">Crescător</string>
<string name="file_list_action_sort_directories_first">Mai întâi dosarele</string>
<string name="file_list_action_sort_path_specific">Doar pentru acest dosar</string>
<string name="file_list_action_view_sort_path_specific">Doar pentru acest dosar</string>
<string name="file_list_action_new_task">Fereastră nouă</string>
<string name="file_list_action_navigate_up">Dute sus</string>
<string name="file_list_action_navigate_to">Sari la</string>

View File

@ -44,7 +44,6 @@
<string name="share">Поделиться</string>
<string name="show">Показать</string>
<string name="skip">Пропустить</string>
<string name="sort">Сортировка</string>
<string name="stop">Остановить</string>
<string name="unknown">Неизвестно</string>
<string name="view">Просмотр</string>
@ -336,7 +335,7 @@
<string name="file_list_action_sort_by_last_modified">Последнее изменение</string>
<string name="file_list_action_sort_order_ascending">По возрастанию</string>
<string name="file_list_action_sort_directories_first">Папки первые</string>
<string name="file_list_action_sort_path_specific">Только для этой папки</string>
<string name="file_list_action_view_sort_path_specific">Только для этой папки</string>
<string name="file_list_action_new_task">Новое окно</string>
<string name="file_list_action_navigate_up">Вверх</string>
<string name="file_list_action_navigate_to">Перейти к</string>

View File

@ -41,7 +41,6 @@
<string name="share">Paylaş</string>
<string name="show">Göster</string>
<string name="skip">Atla</string>
<string name="sort">Sırala</string>
<string name="stop">Durdur</string>
<string name="unknown">Bilinmiyor</string>
<string name="view">Görüntüle</string>
@ -263,7 +262,7 @@
<string name="file_list_action_sort_by_last_modified">Son düzenleme</string>
<string name="file_list_action_sort_order_ascending">Artan</string>
<string name="file_list_action_sort_directories_first">Önce klasörler</string>
<string name="file_list_action_sort_path_specific">Sadece bu klasör için</string>
<string name="file_list_action_view_sort_path_specific">Sadece bu klasör için</string>
<string name="file_list_action_new_task">Yeni pencere</string>
<string name="file_list_action_navigate_up">Yukarı git</string>
<string name="file_list_action_show_hidden_files">Gizli dosyaları göster</string>

View File

@ -42,7 +42,6 @@
<string name="share">Chia sẻ</string>
<string name="show">Hiện</string>
<string name="skip">Bỏ qua</string>
<string name="sort">Sắp xếp</string>
<string name="stop">Dừng</string>
<string name="unknown">Không rõ</string>
<string name="view">Xem</string>
@ -250,7 +249,7 @@
<string name="file_list_action_sort_by_last_modified">Thay đổi lần cuối</string>
<string name="file_list_action_sort_order_ascending">Tăng dần</string>
<string name="file_list_action_sort_directories_first">Thư mục lên trước</string>
<string name="file_list_action_sort_path_specific">Chỉ đối với thư mục này</string>
<string name="file_list_action_view_sort_path_specific">Chỉ đối với thư mục này</string>
<string name="file_list_action_new_task">Cửa sổ mới</string>
<string name="file_list_action_navigate_up">Đi lên</string>
<string name="file_list_action_navigate_to">Đi đến</string>

View File

@ -42,7 +42,6 @@
<string name="share">分享</string>
<string name="show">显示</string>
<string name="skip">跳过</string>
<string name="sort">排序</string>
<string name="stop">停止</string>
<string name="unknown">未知</string>
<string name="view">查看</string>
@ -244,13 +243,16 @@
<string name="file_list_subtitle_separator"></string>
<string name="file_list_path_error_empty">路径不能为空</string>
<string name="file_list_path_error_invalid">无效路径</string>
<string name="file_list_action_view_sort">视图和排序</string>
<string name="file_list_action_view_list">列表</string>
<string name="file_list_action_view_grid">网格</string>
<string name="file_list_action_sort_by_name">名称</string>
<string name="file_list_action_sort_by_type">类型</string>
<string name="file_list_action_sort_by_size">大小</string>
<string name="file_list_action_sort_by_last_modified">最后修改</string>
<string name="file_list_action_sort_order_ascending">升序</string>
<string name="file_list_action_sort_directories_first">文件夹优先</string>
<string name="file_list_action_sort_path_specific">仅用于此文件夹</string>
<string name="file_list_action_view_sort_path_specific">仅用于此文件夹</string>
<string name="file_list_action_new_task">新建窗口</string>
<string name="file_list_action_navigate_up">向上</string>
<string name="file_list_action_navigate_to">转到</string>

View File

@ -42,7 +42,6 @@
<string name="share">分享</string>
<string name="show">顯示</string>
<string name="skip">跳過</string>
<string name="sort">排序</string>
<string name="stop">停止</string>
<string name="unknown">不明</string>
<string name="view">查看</string>
@ -244,13 +243,16 @@
<string name="file_list_subtitle_separator"></string>
<string name="file_list_path_error_empty">路徑不能為空</string>
<string name="file_list_path_error_invalid">無效的路徑</string>
<string name="file_list_action_view_sort">檢視和排序</string>
<string name="file_list_action_view_list">清單</string>
<string name="file_list_action_view_grid">網格</string>
<string name="file_list_action_sort_by_name">名稱</string>
<string name="file_list_action_sort_by_type">類型</string>
<string name="file_list_action_sort_by_size">大小</string>
<string name="file_list_action_sort_by_last_modified">最後修改</string>
<string name="file_list_action_sort_order_ascending">升序</string>
<string name="file_list_action_sort_directories_first">資料夾優先</string>
<string name="file_list_action_sort_path_specific">僅用於此資料夾</string>
<string name="file_list_action_view_sort_path_specific">僅用於此資料夾</string>
<string name="file_list_action_new_task">開新視窗</string>
<string name="file_list_action_navigate_up">向上</string>
<string name="file_list_action_navigate_to">移至</string>

View File

@ -9,6 +9,10 @@
<attr name="colorAppBarSurface" format="color" />
<declare-styleable name="AspectRatioFrameLayout">
<attr name="aspectRatio" format="float" />
</declare-styleable>
<declare-styleable name="NavigationViewExtra">
<attr name="itemSubtitleTextAppearance" format="reference" />
<attr name="itemSubtitleTextColor" format="color" />

View File

@ -31,6 +31,7 @@
<dimen name="list_vertical_padding">8dp</dimen>
<dimen name="list_bottom_padding_with_fab">88dp</dimen>
<dimen name="dense_single_line_list_item_height">40dp</dimen>
<dimen name="single_line_list_item_height">56dp</dimen>
<dimen name="two_line_list_item_height">72dp</dimen>
<dimen name="list_item_vertical_padding">16dp</dimen>
<dimen name="horizontal_divider_height">1dp</dimen>

View File

@ -15,6 +15,8 @@
<bool name="pref_default_value_file_list_persistent_drawer_open">true</bool>
<string name="pref_key_file_list_show_hidden_files">key_file_list_show_hidden_files</string>
<bool name="pref_default_value_file_list_show_hidden_files">false</bool>
<string name="pref_key_file_list_view_type">key_file_list_view_type</string>
<string name="pref_default_value_file_list_view_type">0</string>
<string name="pref_key_file_list_sort_options">key_file_list_sort_options</string>
<string name="pref_key_create_archive_type">key_create_archive_type</string>

View File

@ -43,7 +43,6 @@
<string name="share">Share</string>
<string name="show">Show</string>
<string name="skip">Skip</string>
<string name="sort">Sort</string>
<string name="stop">Stop</string>
<string name="unknown">Unknown</string>
<string name="view">View</string>
@ -275,13 +274,16 @@
<string name="file_list_subtitle_separator">,\u0020</string>
<string name="file_list_path_error_empty">Path cannot be empty</string>
<string name="file_list_path_error_invalid">Invalid path</string>
<string name="file_list_action_view_sort">View and sort</string>
<string name="file_list_action_view_list">List</string>
<string name="file_list_action_view_grid">Grid</string>
<string name="file_list_action_sort_by_name">Name</string>
<string name="file_list_action_sort_by_type">Type</string>
<string name="file_list_action_sort_by_size">Size</string>
<string name="file_list_action_sort_by_last_modified">Last modified</string>
<string name="file_list_action_sort_order_ascending">Ascending</string>
<string name="file_list_action_sort_directories_first">Folders first</string>
<string name="file_list_action_sort_path_specific">Only for this folder</string>
<string name="file_list_action_view_sort_path_specific">Only for this folder</string>
<string name="file_list_action_new_task">New window</string>
<string name="file_list_action_navigate_up">Go up</string>
<string name="file_list_action_navigate_to">Go to</string>