Expand show hidden folders to also cover files (#1059)

* PasswordItem: only strip .gpg suffixes

Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>

* Add preference key and migration for showing all hidden contents

Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>

* Allow showing both hidden files and directories

Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>

* Add tests for hidden folder setting migration

Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>

* Add changelog entry

Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>

* Slightly improve migration logic

Skip migration if old key is not found and always delete the previous key even if its set to false.

Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>

* Tweak wording

Suggested-by: Fabian Henneke <fabian@henneke.me>
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>

* Assert previous key's removal in tests

Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
This commit is contained in:
Harsh Shandilya 2020-08-27 14:27:55 +05:30 committed by GitHub
parent 8ec3320df7
commit 1ce3ef4ea3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 60 additions and 21 deletions

View file

@ -13,6 +13,7 @@ All notable changes to this project will be documented in this file.
- A descriptive error message is shown if no username is specified in the Git server settings
- Remove explicit protocol choice from Git server settings, it is now inferred from your URL
- 'Show hidden folders' is now 'Show hidden files and folders'
### Fixed

View file

@ -4,6 +4,7 @@
*/
@file:Suppress("DEPRECATION")
package com.zeapo.pwdstore
import android.content.Context
@ -13,10 +14,10 @@ import com.zeapo.pwdstore.git.config.Protocol
import com.zeapo.pwdstore.utils.PreferenceKeys
import com.zeapo.pwdstore.utils.getString
import com.zeapo.pwdstore.utils.sharedPrefs
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import org.junit.Test
import org.junit.Assert.*
class MigrationsTest {
private fun checkOldKeysAreRemoved(context: Context) = with(context.sharedPrefs) {
@ -84,4 +85,25 @@ class MigrationsTest {
"https://github.com/Android-Password-Store/pass-test"
)
}
@Test
fun verifyHiddenFoldersMigrationIfDisabled() {
val context = Application.instance.applicationContext
context.sharedPrefs.edit { clear() }
runMigrations(context)
assertEquals(true, context.sharedPrefs.getBoolean(PreferenceKeys.SHOW_HIDDEN_FOLDERS, true))
assertEquals(false, context.sharedPrefs.getBoolean(PreferenceKeys.SHOW_HIDDEN_CONTENTS, false))
}
@Test
fun verifyHiddenFoldersMigrationIfEnabled() {
val context = Application.instance.applicationContext
context.sharedPrefs.edit {
clear()
putBoolean(PreferenceKeys.SHOW_HIDDEN_FOLDERS, true)
}
runMigrations(context)
assertEquals(false, context.sharedPrefs.getBoolean(PreferenceKeys.SHOW_HIDDEN_FOLDERS, false))
assertEquals(true, context.sharedPrefs.getBoolean(PreferenceKeys.SHOW_HIDDEN_CONTENTS, false))
}
}

View file

@ -19,6 +19,7 @@ import java.net.URI
fun runMigrations(context: Context) {
migrateToGitUrlBasedConfig(context)
migrateToHideAll(context)
}
private fun migrateToGitUrlBasedConfig(context: Context) {
@ -84,3 +85,12 @@ private fun migrateToGitUrlBasedConfig(context: Context) {
e { "Failed to migrate to URL-based Git config, generated URL is invalid" }
}
}
private fun migrateToHideAll(context: Context) {
context.sharedPrefs.all[PreferenceKeys.SHOW_HIDDEN_FOLDERS] ?: return
val isHidden = context.sharedPrefs.getBoolean(PreferenceKeys.SHOW_HIDDEN_FOLDERS, false)
context.sharedPrefs.edit {
remove(PreferenceKeys.SHOW_HIDDEN_FOLDERS)
putBoolean(PreferenceKeys.SHOW_HIDDEN_CONTENTS, isHidden)
}
}

View file

@ -94,7 +94,7 @@ private fun PasswordItem.Companion.makeComparator(
PasswordRepository.PasswordSortOrder.FOLDER_FIRST -> compareBy { it.type }
// In order to let INDEPENDENT not distinguish between items based on their type, we simply
// declare them all equal at this stage.
PasswordRepository.PasswordSortOrder.INDEPENDENT -> Comparator<PasswordItem> { _, _ -> 0 }
PasswordRepository.PasswordSortOrder.INDEPENDENT -> Comparator { _, _ -> 0 }
PasswordRepository.PasswordSortOrder.FILE_FIRST -> compareByDescending { it.type }
PasswordRepository.PasswordSortOrder.RECENTLY_USED -> PasswordRepository.PasswordSortOrder.RECENTLY_USED.comparator
}
@ -140,8 +140,8 @@ class SearchableRepositoryViewModel(application: Application) : AndroidViewModel
private val root
get() = PasswordRepository.getRepositoryDirectory()
private val settings by lazy { application.sharedPrefs }
private val showHiddenDirs
get() = settings.getBoolean(PreferenceKeys.SHOW_HIDDEN_FOLDERS, false)
private val showHiddenContents
get() = settings.getBoolean(PreferenceKeys.SHOW_HIDDEN_CONTENTS, false)
private val defaultSearchMode
get() = if (settings.getBoolean(PreferenceKeys.FILTER_RECURSIVELY, true)) {
SearchMode.RecursivelyInSubdirectories
@ -254,8 +254,9 @@ class SearchableRepositoryViewModel(application: Application) : AndroidViewModel
}.asLiveData(Dispatchers.IO)
private fun shouldTake(file: File) = with(file) {
if (showHiddenContents) return true
if (isDirectory) {
!isHidden || showHiddenDirs
!isHidden
} else {
!isHidden && file.extension == "gpg"
}

View file

@ -50,7 +50,7 @@ open class PasswordItemRecyclerAdapter :
fun bind(item: PasswordItem) {
val settings = itemView.context.sharedPrefs
val showHidden = settings.getBoolean(PreferenceKeys.SHOW_HIDDEN_FOLDERS, false)
val showHidden = settings.getBoolean(PreferenceKeys.SHOW_HIDDEN_CONTENTS, false)
val parentPath = item.fullPathToParent.replace("(^/)|(/$)".toRegex(), "")
val source = if (parentPath.isNotEmpty()) {
"$parentPath\n$item"
@ -62,8 +62,8 @@ open class PasswordItemRecyclerAdapter :
name.text = spannable
if (item.type == PasswordItem.TYPE_CATEGORY) {
folderIndicator.visibility = View.VISIBLE
val children = item.file.listFiles { pathname ->
!(!showHidden && (pathname.isDirectory && pathname.isHidden))
val children = with(item.file) {
if (showHidden) listFiles() else listFiles { pathname -> pathname.isDirectory && !pathname.isHidden }
} ?: emptyArray<File>()
val count = children.size
childCount.visibility = if (count > 0) View.VISIBLE else View.GONE

View file

@ -33,7 +33,7 @@ data class PasswordItem(
}
override fun toString(): String {
return name.replace(".gpg", "")
return name.replace("\\.gpg$".toRegex(), "")
}
override fun hashCode(): Int {

View file

@ -226,12 +226,10 @@ open class PasswordRepository protected constructor() {
// We need to recover the passwords then parse the files
val passList = getFilesList(path).also { it.sortBy { f -> f.name } }
val passwordList = ArrayList<PasswordItem>()
val showHiddenDirs = settings.getBoolean(PreferenceKeys.SHOW_HIDDEN_FOLDERS, false)
val showHidden = settings.getBoolean(PreferenceKeys.SHOW_HIDDEN_CONTENTS, false)
if (passList.size == 0) return passwordList
if (showHiddenDirs) {
passList.filter { !(it.isFile && it.isHidden) }.toCollection(passList.apply { clear() })
} else {
if (!showHidden) {
passList.filter { !it.isHidden }.toCollection(passList.apply { clear() })
}
passList.forEach { file ->

View file

@ -28,16 +28,21 @@ object PreferenceKeys {
const val GIT_EXTERNAL = "git_external"
const val GIT_EXTERNAL_REPO = "git_external_repo"
const val GIT_REMOTE_AUTH = "git_remote_auth"
@Deprecated("Use GIT_REMOTE_URL instead")
const val GIT_REMOTE_LOCATION = "git_remote_location"
@Deprecated("Use GIT_REMOTE_URL instead")
const val GIT_REMOTE_PORT = "git_remote_port"
@Deprecated("Use GIT_REMOTE_URL instead")
const val GIT_REMOTE_PROTOCOL = "git_remote_protocol"
const val GIT_DELETE_REPO = "git_delete_repo"
@Deprecated("Use GIT_REMOTE_URL instead")
const val GIT_REMOTE_SERVER = "git_remote_server"
const val GIT_REMOTE_URL = "git_remote_url"
@Deprecated("Use GIT_REMOTE_URL instead")
const val GIT_REMOTE_USERNAME = "git_remote_username"
const val GIT_SERVER_INFO = "git_server_info"
@ -55,7 +60,13 @@ object PreferenceKeys {
const val REPO_CHANGED = "repo_changed"
const val SEARCH_ON_START = "search_on_start"
const val SHOW_EXTRA_CONTENT = "show_extra_content"
@Deprecated(
message = "Use SHOW_HIDDEN_CONTENTS instead",
replaceWith = ReplaceWith("PreferenceKeys.SHOW_HIDDEN_CONTENTS")
)
const val SHOW_HIDDEN_FOLDERS = "show_hidden_folders"
const val SHOW_HIDDEN_CONTENTS = "show_hidden_contents"
const val SORT_ORDER = "sort_order"
const val SHOW_PASSWORD = "show_password"
const val SSH_KEY = "ssh_key"

View file

@ -269,8 +269,6 @@
<string name="access_sdcard_text">O local do armazenamento está em seu cartão SD ou armazenamento interno, mas o aplicativo não tem permissão para acessá-lo.</string>
<string name="your_public_key">Sua chave pública</string>
<string name="error_generate_ssh_key">Erro ao tentar gerar a chave SSH</string>
<string name="pref_show_hidden_title">Mostrar pastas ocultas</string>
<string name="pref_show_hidden_summary">Incluir diretórios ocultos na lista de senhas</string>
<string name="title_create_folder">Criar pasta</string>
<string name="title_rename_folder">Renomear pasta</string>
<string name="message_category_error_empty_field">O nome da categoria não pode ser vazio</string>

View file

@ -251,8 +251,6 @@
<string name="ssh_openkeystore_clear_keyid">Очистить сохраненный SSH Key идентификатор OpenKystortore</string>
<string name="your_public_key">Ваш публичный ключ</string>
<string name="error_generate_ssh_key">Возникла ошибка при попытке генерации ssh ключа</string>
<string name="pref_show_hidden_title">Показать скрытые папки</string>
<string name="pref_show_hidden_summary">Включить скрытые директории в список паролей</string>
<string name="title_create_folder">Создать папку</string>
<string name="button_create">Создать</string>
<string name="pref_search_on_start">Открыть поиск на старте</string>

View file

@ -302,8 +302,8 @@
<string name="access_sdcard_text">The store location is in your SD Card or Internal storage, but the app does not have permission to access it.</string>
<string name="your_public_key">Your public key</string>
<string name="error_generate_ssh_key">Error while trying to generate the ssh-key</string>
<string name="pref_show_hidden_title">Show hidden folders</string>
<string name="pref_show_hidden_summary">Include hidden directories in the password list</string>
<string name="pref_show_hidden_title">Show all files and folders</string>
<string name="pref_show_hidden_summary">Include non-password files and directories in the password list</string>
<string name="title_create_folder">Create folder</string>
<string name="title_rename_folder">Rename folder</string>
<string name="message_category_error_empty_field">Category name can\'t be empty</string>

View file

@ -127,7 +127,7 @@
app:title="@string/pref_search_on_start" />
<CheckBoxPreference
app:defaultValue="false"
app:key="show_hidden_folders"
app:key="show_hidden_contents"
app:persistent="true"
app:summary="@string/pref_show_hidden_summary"
app:title="@string/pref_show_hidden_title" />