Refactor uses of applicationContext and startActivityForResult (#997)
* Refactor uses of applicationContext and startActivityForResult This commit applies three types of refactoring: 1. Remove context argument from PasswordRepository companion functions by relying on Application.instance. 2. Introduce a sharedPrefs extension function on Context that returns the default SharedPreferences for the applicationContext. 3. Use OpenDocument() and OpenDocumentTree() contracts. * Drop toPasswordItem argument
This commit is contained in:
parent
14c44bf584
commit
3dace243e4
25 changed files with 159 additions and 191 deletions
|
@ -15,27 +15,25 @@ import com.github.ajalt.timberkt.Timber.DebugTree
|
|||
import com.github.ajalt.timberkt.Timber.plant
|
||||
import com.zeapo.pwdstore.git.config.setUpBouncyCastleForSshj
|
||||
import com.zeapo.pwdstore.utils.PreferenceKeys
|
||||
import com.zeapo.pwdstore.utils.sharedPrefs
|
||||
|
||||
@Suppress("Unused")
|
||||
class Application : android.app.Application(), SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
||||
private var prefs: SharedPreferences? = null
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
instance = this
|
||||
prefs = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
if (BuildConfig.ENABLE_DEBUG_FEATURES || prefs?.getBoolean(PreferenceKeys.ENABLE_DEBUG_LOGGING, false) ==
|
||||
true) {
|
||||
if (BuildConfig.ENABLE_DEBUG_FEATURES ||
|
||||
sharedPrefs.getBoolean(PreferenceKeys.ENABLE_DEBUG_LOGGING, false)) {
|
||||
plant(DebugTree())
|
||||
}
|
||||
prefs?.registerOnSharedPreferenceChangeListener(this)
|
||||
sharedPrefs.registerOnSharedPreferenceChangeListener(this)
|
||||
setNightMode()
|
||||
setUpBouncyCastleForSshj()
|
||||
}
|
||||
|
||||
override fun onTerminate() {
|
||||
prefs?.unregisterOnSharedPreferenceChangeListener(this)
|
||||
sharedPrefs.unregisterOnSharedPreferenceChangeListener(this)
|
||||
super.onTerminate()
|
||||
}
|
||||
|
||||
|
@ -46,7 +44,7 @@ class Application : android.app.Application(), SharedPreferences.OnSharedPrefere
|
|||
}
|
||||
|
||||
private fun setNightMode() {
|
||||
AppCompatDelegate.setDefaultNightMode(when (prefs?.getString(PreferenceKeys.APP_THEME, getString(R.string.app_theme_def))) {
|
||||
AppCompatDelegate.setDefaultNightMode(when (sharedPrefs.getString(PreferenceKeys.APP_THEME, getString(R.string.app_theme_def))) {
|
||||
"light" -> MODE_NIGHT_NO
|
||||
"dark" -> MODE_NIGHT_YES
|
||||
"follow_system" -> MODE_NIGHT_FOLLOW_SYSTEM
|
||||
|
|
|
@ -19,6 +19,7 @@ import androidx.preference.PreferenceManager
|
|||
import com.github.ajalt.timberkt.d
|
||||
import com.zeapo.pwdstore.utils.PreferenceKeys
|
||||
import com.zeapo.pwdstore.utils.clipboard
|
||||
import com.zeapo.pwdstore.utils.sharedPrefs
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
|
@ -31,7 +32,7 @@ import kotlinx.coroutines.withContext
|
|||
class ClipboardService : Service() {
|
||||
|
||||
private val scope = CoroutineScope(Job() + Dispatchers.Main)
|
||||
private val settings: SharedPreferences by lazy { PreferenceManager.getDefaultSharedPreferences(this) }
|
||||
private val settings: SharedPreferences by lazy { sharedPrefs }
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
if (intent != null) {
|
||||
|
|
|
@ -13,12 +13,13 @@ import androidx.preference.PreferenceManager
|
|||
import com.zeapo.pwdstore.crypto.DecryptActivity
|
||||
import com.zeapo.pwdstore.utils.BiometricAuthenticator
|
||||
import com.zeapo.pwdstore.utils.PreferenceKeys
|
||||
import com.zeapo.pwdstore.utils.sharedPrefs
|
||||
|
||||
class LaunchActivity : AppCompatActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
val prefs = sharedPrefs
|
||||
if (prefs.getBoolean(PreferenceKeys.BIOMETRIC_AUTH, false)) {
|
||||
BiometricAuthenticator.authenticate(this) {
|
||||
when (it) {
|
||||
|
|
|
@ -58,7 +58,7 @@ class PasswordExportService : Service() {
|
|||
*/
|
||||
private fun exportPasswords(targetDirectory: DocumentFile) {
|
||||
|
||||
val repositoryDirectory = requireNotNull(PasswordRepository.getRepositoryDirectory(applicationContext))
|
||||
val repositoryDirectory = requireNotNull(PasswordRepository.getRepositoryDirectory())
|
||||
val sourcePassDir = DocumentFile.fromFile(repositoryDirectory)
|
||||
|
||||
d { "Copying ${repositoryDirectory.path} to $targetDirectory" }
|
||||
|
|
|
@ -18,7 +18,6 @@ import androidx.activity.result.contract.ActivityResultContracts.StartActivityFo
|
|||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
|
@ -33,6 +32,7 @@ import com.zeapo.pwdstore.ui.dialogs.ItemCreationBottomSheet
|
|||
import com.zeapo.pwdstore.utils.PasswordItem
|
||||
import com.zeapo.pwdstore.utils.PasswordRepository
|
||||
import com.zeapo.pwdstore.utils.PreferenceKeys
|
||||
import com.zeapo.pwdstore.utils.sharedPrefs
|
||||
import com.zeapo.pwdstore.utils.viewBinding
|
||||
import java.io.File
|
||||
import me.zhanghai.android.fastscroll.FastScrollerBuilder
|
||||
|
@ -59,7 +59,7 @@ class PasswordFragment : Fragment(R.layout.password_recycler_view) {
|
|||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
settings = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
settings = requireContext().sharedPrefs
|
||||
initializePasswordList()
|
||||
binding.fab.setOnClickListener {
|
||||
ItemCreationBottomSheet().show(childFragmentManager, "BOTTOM_SHEET")
|
||||
|
@ -73,7 +73,7 @@ class PasswordFragment : Fragment(R.layout.password_recycler_view) {
|
|||
}
|
||||
|
||||
private fun initializePasswordList() {
|
||||
val gitDir = File(PasswordRepository.getRepositoryDirectory(requireContext()), ".git")
|
||||
val gitDir = File(PasswordRepository.getRepositoryDirectory(), ".git")
|
||||
val hasGitDir = gitDir.exists() && gitDir.isDirectory && (gitDir.listFiles()?.isNotEmpty() == true)
|
||||
binding.swipeRefresher.setOnRefreshListener {
|
||||
if (!hasGitDir) {
|
||||
|
@ -180,7 +180,7 @@ class PasswordFragment : Fragment(R.layout.password_recycler_view) {
|
|||
// may be called multiple times if the mode is invalidated.
|
||||
override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean {
|
||||
menu.findItem(R.id.menu_edit_password).isVisible =
|
||||
recyclerAdapter.getSelectedItems(requireContext())
|
||||
recyclerAdapter.getSelectedItems()
|
||||
.all { it.type == PasswordItem.TYPE_CATEGORY }
|
||||
return true
|
||||
}
|
||||
|
@ -189,17 +189,17 @@ class PasswordFragment : Fragment(R.layout.password_recycler_view) {
|
|||
override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.menu_delete_password -> {
|
||||
requireStore().deletePasswords(recyclerAdapter.getSelectedItems(requireContext()))
|
||||
requireStore().deletePasswords(recyclerAdapter.getSelectedItems())
|
||||
// Action picked, so close the CAB
|
||||
mode.finish()
|
||||
true
|
||||
}
|
||||
R.id.menu_move_password -> {
|
||||
requireStore().movePasswords(recyclerAdapter.getSelectedItems(requireContext()))
|
||||
requireStore().movePasswords(recyclerAdapter.getSelectedItems())
|
||||
false
|
||||
}
|
||||
R.id.menu_edit_password -> {
|
||||
requireStore().renameCategory(recyclerAdapter.getSelectedItems(requireContext()))
|
||||
requireStore().renameCategory(recyclerAdapter.getSelectedItems())
|
||||
mode.finish()
|
||||
false
|
||||
}
|
||||
|
|
|
@ -69,6 +69,7 @@ import com.zeapo.pwdstore.utils.contains
|
|||
import com.zeapo.pwdstore.utils.isInsideRepository
|
||||
import com.zeapo.pwdstore.utils.listFilesRecursively
|
||||
import com.zeapo.pwdstore.utils.requestInputFocusOnView
|
||||
import com.zeapo.pwdstore.utils.sharedPrefs
|
||||
import java.io.File
|
||||
import java.lang.Character.UnicodeBlock
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
@ -83,10 +84,11 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) {
|
|||
private lateinit var activity: PasswordStore
|
||||
private lateinit var searchItem: MenuItem
|
||||
private lateinit var searchView: SearchView
|
||||
private lateinit var settings: SharedPreferences
|
||||
private var plist: PasswordFragment? = null
|
||||
private var shortcutManager: ShortcutManager? = null
|
||||
|
||||
private val settings by lazy { sharedPrefs }
|
||||
|
||||
private val model: SearchableRepositoryViewModel by viewModels {
|
||||
ViewModelProvider.AndroidViewModelFactory(application)
|
||||
}
|
||||
|
@ -119,7 +121,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) {
|
|||
dir.exists() &&
|
||||
dir.isDirectory &&
|
||||
dir.listFilesRecursively().isNotEmpty() &&
|
||||
getPasswords(dir, getRepositoryDirectory(this), sortOrder).isNotEmpty()) {
|
||||
getPasswords(dir, getRepositoryDirectory(), sortOrder).isNotEmpty()) {
|
||||
closeRepository()
|
||||
checkLocalRepository()
|
||||
return@registerForActivityResult
|
||||
|
@ -153,7 +155,6 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) {
|
|||
@SuppressLint("NewApi")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
activity = this
|
||||
settings = PreferenceManager.getDefaultSharedPreferences(this.applicationContext)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
|
||||
shortcutManager = getSystemService()
|
||||
}
|
||||
|
@ -209,7 +210,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) {
|
|||
}
|
||||
|
||||
model.currentDir.observe(this) { dir ->
|
||||
val basePath = getRepositoryDirectory(applicationContext).absoluteFile
|
||||
val basePath = getRepositoryDirectory().absoluteFile
|
||||
supportActionBar!!.apply {
|
||||
if (dir != basePath)
|
||||
title = dir.name
|
||||
|
@ -379,9 +380,9 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) {
|
|||
|
||||
private fun createRepository() {
|
||||
if (!isInitialized) {
|
||||
initialize(this)
|
||||
initialize()
|
||||
}
|
||||
val localDir = getRepositoryDirectory(applicationContext)
|
||||
val localDir = getRepositoryDirectory()
|
||||
try {
|
||||
check(localDir.mkdir()) { "Failed to create directory!" }
|
||||
createRepository(localDir)
|
||||
|
@ -409,7 +410,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) {
|
|||
if (externalRepo && externalRepoPath != null) {
|
||||
val dir = File(externalRepoPath)
|
||||
if (dir.exists() && dir.isDirectory &&
|
||||
getPasswords(dir, getRepositoryDirectory(this), sortOrder).isNotEmpty()) {
|
||||
getPasswords(dir, getRepositoryDirectory(), sortOrder).isNotEmpty()) {
|
||||
closeRepository()
|
||||
checkLocalRepository()
|
||||
return // if not empty, just show me the passwords!
|
||||
|
@ -449,7 +450,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) {
|
|||
}
|
||||
|
||||
private fun checkLocalRepository() {
|
||||
val repo = initialize(this)
|
||||
val repo = initialize()
|
||||
if (repo == null) {
|
||||
val intent = Intent(activity, UserPreference::class.java)
|
||||
intent.putExtra("operation", "git_external")
|
||||
|
@ -459,7 +460,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) {
|
|||
}
|
||||
}.launch(intent)
|
||||
} else {
|
||||
checkLocalRepository(getRepositoryDirectory(applicationContext))
|
||||
checkLocalRepository(getRepositoryDirectory())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -472,7 +473,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) {
|
|||
settings.edit { putBoolean(PreferenceKeys.REPO_CHANGED, false) }
|
||||
plist = PasswordFragment()
|
||||
val args = Bundle()
|
||||
args.putString(REQUEST_ARG_PATH, getRepositoryDirectory(applicationContext).absolutePath)
|
||||
args.putString(REQUEST_ARG_PATH, getRepositoryDirectory().absolutePath)
|
||||
|
||||
// if the activity was started from the autofill settings, the
|
||||
// intent is to match a clicked pwd with app. pass this to fragment
|
||||
|
@ -506,7 +507,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) {
|
|||
}
|
||||
|
||||
private fun getLastChangedTimestamp(fullPath: String): Long {
|
||||
val repoPath = getRepositoryDirectory(this)
|
||||
val repoPath = getRepositoryDirectory()
|
||||
val repository = getRepository(repoPath)
|
||||
if (repository == null) {
|
||||
d { "getLastChangedTimestamp: No git repository" }
|
||||
|
@ -534,7 +535,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) {
|
|||
for (intent in arrayOf(decryptIntent, authDecryptIntent)) {
|
||||
intent.putExtra("NAME", item.toString())
|
||||
intent.putExtra("FILE_PATH", item.file.absolutePath)
|
||||
intent.putExtra("REPO_PATH", getRepositoryDirectory(applicationContext).absolutePath)
|
||||
intent.putExtra("REPO_PATH", getRepositoryDirectory().absolutePath)
|
||||
intent.putExtra("LAST_CHANGED_TIMESTAMP", getLastChangedTimestamp(item.file.absolutePath))
|
||||
}
|
||||
// Needs an action to be a shortcut intent
|
||||
|
@ -577,7 +578,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) {
|
|||
i { "Adding file to : ${currentDir.absolutePath}" }
|
||||
val intent = Intent(this, PasswordCreationActivity::class.java)
|
||||
intent.putExtra("FILE_PATH", currentDir.absolutePath)
|
||||
intent.putExtra("REPO_PATH", getRepositoryDirectory(applicationContext).absolutePath)
|
||||
intent.putExtra("REPO_PATH", getRepositoryDirectory().absolutePath)
|
||||
registerForActivityResult(StartActivityForResult()) { result ->
|
||||
if (result.resultCode == RESULT_OK) {
|
||||
lifecycleScope.launch {
|
||||
|
@ -623,7 +624,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) {
|
|||
refreshPasswordList()
|
||||
AutofillMatcher.updateMatches(applicationContext, delete = filesToDelete)
|
||||
val fmt = selectedItems.joinToString(separator = ", ") { item ->
|
||||
item.file.toRelativeString(getRepositoryDirectory(this@PasswordStore))
|
||||
item.file.toRelativeString(getRepositoryDirectory())
|
||||
}
|
||||
lifecycleScope.launch {
|
||||
commitChange(
|
||||
|
@ -645,7 +646,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) {
|
|||
val intentData = result.data ?: return@registerForActivityResult
|
||||
val filesToMove = requireNotNull(intentData.getStringArrayExtra("Files"))
|
||||
val target = File(requireNotNull(intentData.getStringExtra("SELECTED_FOLDER_PATH")))
|
||||
val repositoryPath = getRepositoryDirectory(applicationContext).absolutePath
|
||||
val repositoryPath = getRepositoryDirectory().absolutePath
|
||||
if (!target.isDirectory) {
|
||||
e { "Tried moving passwords to a non-existing folder." }
|
||||
return@registerForActivityResult
|
||||
|
@ -703,7 +704,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) {
|
|||
}
|
||||
}
|
||||
else -> {
|
||||
val repoDir = getRepositoryDirectory(applicationContext).absolutePath
|
||||
val repoDir = getRepositoryDirectory().absolutePath
|
||||
val relativePath = getRelativePath("${target.absolutePath}/", repoDir)
|
||||
withContext(Dispatchers.Main) {
|
||||
commitChange(
|
||||
|
@ -756,7 +757,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) {
|
|||
when {
|
||||
newCategoryEditText.text.isNullOrBlank() -> renameCategory(oldCategory, CategoryRenameError.EmptyField)
|
||||
newCategory.exists() -> renameCategory(oldCategory, CategoryRenameError.CategoryExists)
|
||||
!isInsideRepository(newCategory) -> renameCategory(oldCategory, CategoryRenameError.DestinationOutsideRepo)
|
||||
!newCategory.isInsideRepository() -> renameCategory(oldCategory, CategoryRenameError.DestinationOutsideRepo)
|
||||
else -> lifecycleScope.launch(Dispatchers.IO) {
|
||||
moveFile(oldCategory.file, newCategory)
|
||||
withContext(Dispatchers.Main) {
|
||||
|
@ -803,7 +804,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) {
|
|||
}
|
||||
|
||||
private val currentDir: File
|
||||
get() = plist?.currentDir ?: getRepositoryDirectory(applicationContext)
|
||||
get() = plist?.currentDir ?: getRepositoryDirectory()
|
||||
|
||||
private suspend fun moveFile(source: File, destinationFile: File) {
|
||||
val sourceDestinationMap = if (source.isDirectory) {
|
||||
|
@ -887,7 +888,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) {
|
|||
fun matchPasswordWithApp(item: PasswordItem) {
|
||||
val path = item.file
|
||||
.absolutePath
|
||||
.replace(getRepositoryDirectory(applicationContext).toString() + "/", "")
|
||||
.replace(getRepositoryDirectory().toString() + "/", "")
|
||||
.replace(".gpg", "")
|
||||
val data = Intent()
|
||||
data.putExtra("path", path)
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
package com.zeapo.pwdstore
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.os.Parcelable
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
|
@ -31,6 +30,7 @@ import com.zeapo.pwdstore.autofill.oreo.DirectoryStructure
|
|||
import com.zeapo.pwdstore.utils.PasswordItem
|
||||
import com.zeapo.pwdstore.utils.PasswordRepository
|
||||
import com.zeapo.pwdstore.utils.PreferenceKeys
|
||||
import com.zeapo.pwdstore.utils.sharedPrefs
|
||||
import java.io.File
|
||||
import java.text.Collator
|
||||
import java.util.Locale
|
||||
|
@ -50,10 +50,10 @@ import kotlinx.coroutines.flow.toList
|
|||
import kotlinx.coroutines.yield
|
||||
import me.zhanghai.android.fastscroll.PopupTextProvider
|
||||
|
||||
private fun File.toPasswordItem(root: File) = if (isFile)
|
||||
PasswordItem.newPassword(name, this, root)
|
||||
private fun File.toPasswordItem() = if (isFile)
|
||||
PasswordItem.newPassword(name, this, PasswordRepository.getRepositoryDirectory())
|
||||
else
|
||||
PasswordItem.newCategory(name, this, root)
|
||||
PasswordItem.newCategory(name, this, PasswordRepository.getRepositoryDirectory())
|
||||
|
||||
private fun PasswordItem.fuzzyMatch(filter: String): Int {
|
||||
var i = 0
|
||||
|
@ -138,8 +138,8 @@ class SearchableRepositoryViewModel(application: Application) : AndroidViewModel
|
|||
}
|
||||
|
||||
private val root
|
||||
get() = PasswordRepository.getRepositoryDirectory(getApplication())
|
||||
private val settings = PreferenceManager.getDefaultSharedPreferences(getApplication())
|
||||
get() = PasswordRepository.getRepositoryDirectory()
|
||||
private val settings by lazy { application.sharedPrefs }
|
||||
private val showHiddenDirs
|
||||
get() = settings.getBoolean(PreferenceKeys.SHOW_HIDDEN_FOLDERS, false)
|
||||
private val defaultSearchMode
|
||||
|
@ -216,7 +216,7 @@ class SearchableRepositoryViewModel(application: Application) : AndroidViewModel
|
|||
val passwordList = when (filterModeToUse) {
|
||||
FilterMode.NoFilter -> {
|
||||
prefilteredResultFlow
|
||||
.map { it.toPasswordItem(root) }
|
||||
.map { it.toPasswordItem() }
|
||||
.toList()
|
||||
.sortedWith(itemComparator)
|
||||
}
|
||||
|
@ -228,7 +228,7 @@ class SearchableRepositoryViewModel(application: Application) : AndroidViewModel
|
|||
.filter { absoluteFile ->
|
||||
regex.containsMatchIn(absoluteFile.relativeTo(root).path)
|
||||
}
|
||||
.map { it.toPasswordItem(root) }
|
||||
.map { it.toPasswordItem() }
|
||||
.toList()
|
||||
.sortedWith(itemComparator)
|
||||
} else {
|
||||
|
@ -238,7 +238,7 @@ class SearchableRepositoryViewModel(application: Application) : AndroidViewModel
|
|||
FilterMode.Fuzzy -> {
|
||||
prefilteredResultFlow
|
||||
.map {
|
||||
val item = it.toPasswordItem(root)
|
||||
val item = it.toPasswordItem()
|
||||
Pair(item.fuzzyMatch(searchAction.filter), item)
|
||||
}
|
||||
.filter { it.first > 0 }
|
||||
|
@ -443,10 +443,7 @@ open class SearchableRepositoryAdapter<T : RecyclerView.ViewHolder>(
|
|||
private val selectedFiles
|
||||
get() = requireSelectionTracker().selection.map { File(it) }
|
||||
|
||||
fun getSelectedItems(context: Context): List<PasswordItem> {
|
||||
val root = PasswordRepository.getRepositoryDirectory(context)
|
||||
return selectedFiles.map { it.toPasswordItem(root) }
|
||||
}
|
||||
fun getSelectedItems() = selectedFiles.map { it.toPasswordItem() }
|
||||
|
||||
fun getPositionForFile(file: File) = itemKeyProvider.getPosition(file.absolutePath)
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ class SelectFolderActivity : AppCompatActivity(R.layout.select_folder_layout) {
|
|||
|
||||
passwordList = SelectFolderFragment()
|
||||
val args = Bundle()
|
||||
args.putString(PasswordStore.REQUEST_ARG_PATH, PasswordRepository.getRepositoryDirectory(applicationContext).absolutePath)
|
||||
args.putString(PasswordStore.REQUEST_ARG_PATH, PasswordRepository.getRepositoryDirectory().absolutePath)
|
||||
|
||||
passwordList.arguments = args
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ package com.zeapo.pwdstore
|
|||
|
||||
import android.accessibilityservice.AccessibilityServiceInfo
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.content.pm.ShortcutManager
|
||||
|
@ -20,8 +21,8 @@ import android.text.TextUtils
|
|||
import android.view.MenuItem
|
||||
import android.view.accessibility.AccessibilityManager
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.ActivityResult
|
||||
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
|
||||
import androidx.activity.result.contract.ActivityResultContracts.OpenDocument
|
||||
import androidx.activity.result.contract.ActivityResultContracts.OpenDocumentTree
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.widget.AppCompatTextView
|
||||
import androidx.biometric.BiometricManager
|
||||
|
@ -53,6 +54,7 @@ import com.zeapo.pwdstore.utils.PasswordRepository
|
|||
import com.zeapo.pwdstore.utils.PreferenceKeys
|
||||
import com.zeapo.pwdstore.utils.autofillManager
|
||||
import com.zeapo.pwdstore.utils.getEncryptedPrefs
|
||||
import com.zeapo.pwdstore.utils.sharedPrefs
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
|
||||
|
@ -69,15 +71,15 @@ class UserPreference : AppCompatActivity() {
|
|||
private var clearSavedPassPreference: Preference? = null
|
||||
private lateinit var autofillDependencies: List<Preference>
|
||||
private lateinit var oreoAutofillDependencies: List<Preference>
|
||||
private lateinit var callingActivity: UserPreference
|
||||
private lateinit var prefsActivity: UserPreference
|
||||
private lateinit var sharedPreferences: SharedPreferences
|
||||
private lateinit var encryptedPreferences: SharedPreferences
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
callingActivity = requireActivity() as UserPreference
|
||||
prefsActivity = requireActivity() as UserPreference
|
||||
val context = requireContext()
|
||||
sharedPreferences = preferenceManager.sharedPreferences
|
||||
encryptedPreferences = requireActivity().applicationContext.getEncryptedPrefs("git_operation")
|
||||
encryptedPreferences = requireActivity().getEncryptedPrefs("git_operation")
|
||||
|
||||
addPreferencesFromResource(R.xml.preference)
|
||||
|
||||
|
@ -152,12 +154,12 @@ class UserPreference : AppCompatActivity() {
|
|||
appVersionPreference?.summary = "Version: ${BuildConfig.VERSION_NAME}"
|
||||
|
||||
sshKeyPreference?.onPreferenceClickListener = ClickListener {
|
||||
callingActivity.getSshKey()
|
||||
prefsActivity.getSshKey()
|
||||
true
|
||||
}
|
||||
|
||||
sshKeygenPreference?.onPreferenceClickListener = ClickListener {
|
||||
callingActivity.makeSshKey(true)
|
||||
prefsActivity.makeSshKey(true)
|
||||
true
|
||||
}
|
||||
|
||||
|
@ -185,24 +187,24 @@ class UserPreference : AppCompatActivity() {
|
|||
}
|
||||
|
||||
gitServerPreference?.onPreferenceClickListener = ClickListener {
|
||||
startActivity(Intent(callingActivity, GitServerConfigActivity::class.java))
|
||||
startActivity(Intent(prefsActivity, GitServerConfigActivity::class.java))
|
||||
true
|
||||
}
|
||||
|
||||
gitConfigPreference?.onPreferenceClickListener = ClickListener {
|
||||
startActivity(Intent(callingActivity, GitConfigActivity::class.java))
|
||||
startActivity(Intent(prefsActivity, GitConfigActivity::class.java))
|
||||
true
|
||||
}
|
||||
|
||||
deleteRepoPreference?.onPreferenceClickListener = ClickListener {
|
||||
val repoDir = PasswordRepository.getRepositoryDirectory(callingActivity.applicationContext)
|
||||
MaterialAlertDialogBuilder(callingActivity)
|
||||
val repoDir = PasswordRepository.getRepositoryDirectory()
|
||||
MaterialAlertDialogBuilder(prefsActivity)
|
||||
.setTitle(R.string.pref_dialog_delete_title)
|
||||
.setMessage(resources.getString(R.string.dialog_delete_msg, repoDir))
|
||||
.setCancelable(false)
|
||||
.setPositiveButton(R.string.dialog_delete) { dialogInterface, _ ->
|
||||
try {
|
||||
PasswordRepository.getRepositoryDirectory(callingActivity.applicationContext).deleteRecursively()
|
||||
PasswordRepository.getRepositoryDirectory().deleteRecursively()
|
||||
PasswordRepository.closeRepository()
|
||||
} catch (ignored: Exception) {
|
||||
// TODO Handle the different cases of exceptions
|
||||
|
@ -215,7 +217,7 @@ class UserPreference : AppCompatActivity() {
|
|||
}
|
||||
sharedPreferences.edit { putBoolean(PreferenceKeys.REPOSITORY_INITIALIZED, false) }
|
||||
dialogInterface.cancel()
|
||||
callingActivity.finish()
|
||||
prefsActivity.finish()
|
||||
}
|
||||
.setNegativeButton(R.string.dialog_do_not_delete) { dialogInterface, _ -> run { dialogInterface.cancel() } }
|
||||
.show()
|
||||
|
@ -226,7 +228,7 @@ class UserPreference : AppCompatActivity() {
|
|||
selectExternalGitRepositoryPreference?.summary =
|
||||
sharedPreferences.getString(PreferenceKeys.GIT_EXTERNAL_REPO, context.getString(R.string.no_repo_selected))
|
||||
selectExternalGitRepositoryPreference?.onPreferenceClickListener = ClickListener {
|
||||
callingActivity.selectExternalGitRepository()
|
||||
prefsActivity.selectExternalGitRepository()
|
||||
true
|
||||
}
|
||||
|
||||
|
@ -241,7 +243,7 @@ class UserPreference : AppCompatActivity() {
|
|||
externalGitRepositoryPreference?.onPreferenceChangeListener = resetRepo
|
||||
|
||||
autoFillAppsPreference?.onPreferenceClickListener = ClickListener {
|
||||
val intent = Intent(callingActivity, AutofillPreferenceActivity::class.java)
|
||||
val intent = Intent(prefsActivity, AutofillPreferenceActivity::class.java)
|
||||
startActivity(intent)
|
||||
true
|
||||
}
|
||||
|
@ -254,7 +256,7 @@ class UserPreference : AppCompatActivity() {
|
|||
findPreference<Preference>(PreferenceKeys.EXPORT_PASSWORDS)?.apply {
|
||||
isVisible = sharedPreferences.getBoolean(PreferenceKeys.REPOSITORY_INITIALIZED, false)
|
||||
onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
callingActivity.exportPasswords()
|
||||
prefsActivity.exportPasswords()
|
||||
true
|
||||
}
|
||||
}
|
||||
|
@ -316,7 +318,7 @@ class UserPreference : AppCompatActivity() {
|
|||
|
||||
val prefCustomXkpwdDictionary = findPreference<Preference>(PreferenceKeys.PREF_KEY_CUSTOM_DICT)
|
||||
prefCustomXkpwdDictionary?.onPreferenceClickListener = ClickListener {
|
||||
callingActivity.storeCustomDictionaryPath()
|
||||
prefsActivity.storeCustomDictionaryPath()
|
||||
true
|
||||
}
|
||||
val dictUri = sharedPreferences.getString(PreferenceKeys.PREF_KEY_CUSTOM_DICT, "")
|
||||
|
@ -361,8 +363,8 @@ class UserPreference : AppCompatActivity() {
|
|||
}
|
||||
|
||||
private fun updateAutofillSettings() {
|
||||
val isAccessibilityServiceEnabled = callingActivity.isAccessibilityServiceEnabled
|
||||
val isAutofillServiceEnabled = callingActivity.isAutofillServiceEnabled
|
||||
val isAccessibilityServiceEnabled = prefsActivity.isAccessibilityServiceEnabled
|
||||
val isAutofillServiceEnabled = prefsActivity.isAutofillServiceEnabled
|
||||
autoFillEnablePreference?.isChecked =
|
||||
isAccessibilityServiceEnabled || isAutofillServiceEnabled
|
||||
autofillDependencies.forEach {
|
||||
|
@ -391,16 +393,16 @@ class UserPreference : AppCompatActivity() {
|
|||
}
|
||||
|
||||
private fun onEnableAutofillClick() {
|
||||
if (callingActivity.isAccessibilityServiceEnabled) {
|
||||
if (prefsActivity.isAccessibilityServiceEnabled) {
|
||||
startActivity(Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS))
|
||||
} else if (callingActivity.isAutofillServiceEnabled) {
|
||||
} else if (prefsActivity.isAutofillServiceEnabled) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
|
||||
callingActivity.autofillManager!!.disableAutofillServices()
|
||||
prefsActivity.autofillManager!!.disableAutofillServices()
|
||||
else
|
||||
throw IllegalStateException("isAutofillServiceEnabled == true, but Build.VERSION.SDK_INT < Build.VERSION_CODES.O")
|
||||
} else {
|
||||
val enableOreoAutofill = callingActivity.isAutofillServiceSupported
|
||||
MaterialAlertDialogBuilder(callingActivity).run {
|
||||
val enableOreoAutofill = prefsActivity.isAutofillServiceSupported
|
||||
MaterialAlertDialogBuilder(prefsActivity).run {
|
||||
setTitle(R.string.pref_autofill_enable_title)
|
||||
if (enableOreoAutofill && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
@SuppressLint("InflateParams")
|
||||
|
@ -480,10 +482,8 @@ class UserPreference : AppCompatActivity() {
|
|||
.setTitle(this.resources.getString(R.string.external_repository_dialog_title))
|
||||
.setMessage(this.resources.getString(R.string.external_repository_dialog_text))
|
||||
.setPositiveButton(R.string.dialog_ok) { _, _ ->
|
||||
val i = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
||||
registerForActivityResult(StartActivityForResult()) { result ->
|
||||
if (!validateResult(result)) return@registerForActivityResult
|
||||
val uri = result.data?.data
|
||||
registerForActivityResult(OpenDocumentTree()) { uri: Uri? ->
|
||||
if (uri == null) return@registerForActivityResult
|
||||
|
||||
tag(TAG).d { "Selected repository URI is $uri" }
|
||||
// TODO: This is fragile. Workaround until PasswordItem is backed by DocumentFile
|
||||
|
@ -491,7 +491,7 @@ class UserPreference : AppCompatActivity() {
|
|||
val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||
val path = if (split.size > 1) split[1] else split[0]
|
||||
val repoPath = "${Environment.getExternalStorageDirectory()}/$path"
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(applicationContext)
|
||||
val prefs = sharedPrefs
|
||||
|
||||
tag(TAG).d { "Selected repository path is $repoPath" }
|
||||
|
||||
|
@ -500,14 +500,14 @@ class UserPreference : AppCompatActivity() {
|
|||
.setTitle(getString(R.string.sdcard_root_warning_title))
|
||||
.setMessage(getString(R.string.sdcard_root_warning_message))
|
||||
.setPositiveButton("Remove everything") { _, _ ->
|
||||
prefs.edit { putString(PreferenceKeys.GIT_EXTERNAL_REPO, uri?.path) }
|
||||
prefs.edit { putString(PreferenceKeys.GIT_EXTERNAL_REPO, uri.path) }
|
||||
}
|
||||
.setNegativeButton(R.string.dialog_cancel, null)
|
||||
.show()
|
||||
}
|
||||
prefs.edit { putString(PreferenceKeys.GIT_EXTERNAL_REPO, repoPath) }
|
||||
|
||||
}.launch(Intent.createChooser(i, "Choose Directory"))
|
||||
}.launch(null)
|
||||
}
|
||||
.setNegativeButton(R.string.dialog_cancel, null)
|
||||
.show()
|
||||
|
@ -527,29 +527,13 @@ class UserPreference : AppCompatActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a [ActivityResult], validates that the result is usable.
|
||||
*/
|
||||
private fun validateResult(result: ActivityResult): Boolean {
|
||||
if (result.resultCode != RESULT_OK) {
|
||||
return false
|
||||
}
|
||||
if (result.data == null) {
|
||||
setResult(RESULT_CANCELED)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a file explorer to import the private key
|
||||
*/
|
||||
private fun getSshKey() {
|
||||
registerForActivityResult(StartActivityForResult()) { result ->
|
||||
if (!validateResult(result)) return@registerForActivityResult
|
||||
registerForActivityResult(OpenDocument()) { uri: Uri? ->
|
||||
if (uri == null) return@registerForActivityResult
|
||||
try {
|
||||
val uri: Uri = result.data?.data ?: throw IOException("Unable to open file")
|
||||
|
||||
copySshKey(uri)
|
||||
|
||||
Toast.makeText(
|
||||
|
@ -557,7 +541,7 @@ class UserPreference : AppCompatActivity() {
|
|||
this.resources.getString(R.string.ssh_key_success_dialog_title),
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(applicationContext)
|
||||
val prefs = sharedPrefs
|
||||
|
||||
prefs.edit { putBoolean(PreferenceKeys.USE_GENERATED_KEY, false) }
|
||||
getEncryptedPrefs("git_operation").edit { remove(PreferenceKeys.SSH_KEY_LOCAL_PASSPHRASE) }
|
||||
|
@ -574,44 +558,39 @@ class UserPreference : AppCompatActivity() {
|
|||
.setPositiveButton(resources.getString(R.string.dialog_ok), null)
|
||||
.show()
|
||||
}
|
||||
}.launch(Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
|
||||
addCategory(Intent.CATEGORY_OPENABLE)
|
||||
type = "*/*"
|
||||
})
|
||||
}.launch(arrayOf("*/*"))
|
||||
}
|
||||
|
||||
/**
|
||||
* Exports the passwords
|
||||
*/
|
||||
private fun exportPasswords() {
|
||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply {
|
||||
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
|
||||
Intent.FLAG_GRANT_WRITE_URI_PERMISSION or
|
||||
Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION or
|
||||
Intent.FLAG_GRANT_PREFIX_URI_PERMISSION
|
||||
}
|
||||
|
||||
registerForActivityResult(StartActivityForResult()) { result ->
|
||||
if (!validateResult(result)) return@registerForActivityResult
|
||||
val uri = result.data?.data
|
||||
|
||||
if (uri != null) {
|
||||
val targetDirectory = DocumentFile.fromTreeUri(applicationContext, uri)
|
||||
|
||||
if (targetDirectory != null) {
|
||||
val service = Intent(applicationContext, PasswordExportService::class.java).apply {
|
||||
action = PasswordExportService.ACTION_EXPORT_PASSWORD
|
||||
putExtra("uri", uri)
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
startForegroundService(service)
|
||||
} else {
|
||||
startService(service)
|
||||
}
|
||||
registerForActivityResult(object : OpenDocumentTree() {
|
||||
override fun createIntent(context: Context, input: Uri?): Intent {
|
||||
return super.createIntent(context, input).apply {
|
||||
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
|
||||
Intent.FLAG_GRANT_WRITE_URI_PERMISSION or
|
||||
Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION or
|
||||
Intent.FLAG_GRANT_PREFIX_URI_PERMISSION
|
||||
}
|
||||
}
|
||||
}.launch(intent)
|
||||
}) { uri: Uri? ->
|
||||
if (uri == null) return@registerForActivityResult
|
||||
val targetDirectory = DocumentFile.fromTreeUri(applicationContext, uri)
|
||||
|
||||
if (targetDirectory != null) {
|
||||
val service = Intent(applicationContext, PasswordExportService::class.java).apply {
|
||||
action = PasswordExportService.ACTION_EXPORT_PASSWORD
|
||||
putExtra("uri", uri)
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
startForegroundService(service)
|
||||
} else {
|
||||
startService(service)
|
||||
}
|
||||
}
|
||||
}.launch(null)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -630,18 +609,16 @@ class UserPreference : AppCompatActivity() {
|
|||
* Pick custom xkpwd dictionary from sdcard
|
||||
*/
|
||||
private fun storeCustomDictionaryPath() {
|
||||
registerForActivityResult(StartActivityForResult()) { result ->
|
||||
if (!validateResult(result)) return@registerForActivityResult
|
||||
val uri: Uri = result.data?.data ?: throw IOException("Unable to open file")
|
||||
registerForActivityResult(OpenDocument()) { uri ->
|
||||
if (uri == null) return@registerForActivityResult
|
||||
|
||||
Toast.makeText(
|
||||
this,
|
||||
this.resources.getString(R.string.xkpwgen_custom_dict_imported, uri.path),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(applicationContext)
|
||||
|
||||
prefs.edit { putString(PreferenceKeys.PREF_KEY_CUSTOM_DICT, uri.toString()) }
|
||||
sharedPrefs.edit { putString(PreferenceKeys.PREF_KEY_CUSTOM_DICT, uri.toString()) }
|
||||
|
||||
val customDictPref = prefsFragment.findPreference<Preference>(PreferenceKeys.PREF_KEY_CUSTOM_DICT)
|
||||
setCustomDictSummary(customDictPref, uri)
|
||||
|
@ -653,10 +630,7 @@ class UserPreference : AppCompatActivity() {
|
|||
customDictFile.close()
|
||||
|
||||
setResult(RESULT_OK)
|
||||
}.launch(Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
|
||||
addCategory(Intent.CATEGORY_OPENABLE)
|
||||
type = "*/*"
|
||||
})
|
||||
}.launch(arrayOf("*/*"))
|
||||
}
|
||||
|
||||
@Throws(IllegalArgumentException::class, IOException::class)
|
||||
|
|
|
@ -76,7 +76,7 @@ class AutofillService : AccessibilityService(), CoroutineScope by CoroutineScope
|
|||
}
|
||||
|
||||
fun setPickedPassword(path: String) {
|
||||
items.add(File("${PasswordRepository.getRepositoryDirectory(applicationContext)}/$path.gpg"))
|
||||
items.add(File("${PasswordRepository.getRepositoryDirectory()}/$path.gpg"))
|
||||
bindDecryptAndVerify()
|
||||
}
|
||||
|
||||
|
@ -296,9 +296,9 @@ class AutofillService : AccessibilityService(), CoroutineScope by CoroutineScope
|
|||
when (preference) {
|
||||
"/first" -> {
|
||||
if (!PasswordRepository.isInitialized) {
|
||||
PasswordRepository.initialize(this)
|
||||
PasswordRepository.initialize()
|
||||
}
|
||||
items = searchPasswords(PasswordRepository.getRepositoryDirectory(this), webViewTitle)
|
||||
items = searchPasswords(PasswordRepository.getRepositoryDirectory(), webViewTitle)
|
||||
}
|
||||
"/never" -> items = ArrayList()
|
||||
else -> getPreferredPasswords(preference)
|
||||
|
@ -318,9 +318,9 @@ class AutofillService : AccessibilityService(), CoroutineScope by CoroutineScope
|
|||
when (preference) {
|
||||
"/first" -> {
|
||||
if (!PasswordRepository.isInitialized) {
|
||||
PasswordRepository.initialize(this)
|
||||
PasswordRepository.initialize()
|
||||
}
|
||||
items = searchPasswords(PasswordRepository.getRepositoryDirectory(this), appName)
|
||||
items = searchPasswords(PasswordRepository.getRepositoryDirectory(), appName)
|
||||
}
|
||||
"/never" -> items = ArrayList()
|
||||
else -> getPreferredPasswords(preference)
|
||||
|
@ -331,12 +331,12 @@ class AutofillService : AccessibilityService(), CoroutineScope by CoroutineScope
|
|||
// file into the items list.
|
||||
private fun getPreferredPasswords(preference: String) {
|
||||
if (!PasswordRepository.isInitialized) {
|
||||
PasswordRepository.initialize(this)
|
||||
PasswordRepository.initialize()
|
||||
}
|
||||
val preferredPasswords = preference.splitLines()
|
||||
items = ArrayList()
|
||||
for (password in preferredPasswords) {
|
||||
val path = PasswordRepository.getRepositoryDirectory(applicationContext).toString() + "/" + password + ".gpg"
|
||||
val path = PasswordRepository.getRepositoryDirectory().toString() + "/" + password + ".gpg"
|
||||
if (File(path).exists()) {
|
||||
items.add(File(path))
|
||||
}
|
||||
|
@ -417,7 +417,7 @@ class AutofillService : AccessibilityService(), CoroutineScope by CoroutineScope
|
|||
// populate the dialog items, always with pick + pick and match. Could
|
||||
// make it optional (or make height a setting for the same effect)
|
||||
val itemNames = arrayOfNulls<CharSequence>(items.size + 2)
|
||||
val passwordDirectory = PasswordRepository.getRepositoryDirectory(applicationContext).toString()
|
||||
val passwordDirectory = PasswordRepository.getRepositoryDirectory().toString()
|
||||
val autofillFullPath = settings!!.getBoolean(PreferenceKeys.AUTOFILL_FULL_PATH, false)
|
||||
for (i in items.indices) {
|
||||
if (autofillFullPath) {
|
||||
|
|
|
@ -121,7 +121,7 @@ private fun makeRemoteView(
|
|||
fun makeFillMatchRemoteView(context: Context, file: File, formOrigin: FormOrigin): RemoteViews {
|
||||
val title = formOrigin.getPrettyIdentifier(context, untrusted = false)
|
||||
val directoryStructure = AutofillPreferences.directoryStructure(context)
|
||||
val relativeFile = file.relativeTo(PasswordRepository.getRepositoryDirectory(context))
|
||||
val relativeFile = file.relativeTo(PasswordRepository.getRepositoryDirectory())
|
||||
val summary = directoryStructure.getUsernameFor(relativeFile)
|
||||
?: directoryStructure.getPathToIdentifierFor(relativeFile) ?: ""
|
||||
val iconRes = R.drawable.ic_person_black_24dp
|
||||
|
|
|
@ -9,12 +9,10 @@ import android.content.SharedPreferences
|
|||
import android.os.Build
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.zeapo.pwdstore.utils.sharedPrefs
|
||||
import java.io.File
|
||||
import java.nio.file.Paths
|
||||
|
||||
private val Context.defaultSharedPreferences: SharedPreferences
|
||||
get() = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
|
||||
enum class DirectoryStructure(val value: String) {
|
||||
EncryptedUsername("encrypted_username"),
|
||||
FileBased("file"),
|
||||
|
@ -122,8 +120,7 @@ enum class DirectoryStructure(val value: String) {
|
|||
object AutofillPreferences {
|
||||
|
||||
fun directoryStructure(context: Context): DirectoryStructure {
|
||||
val value =
|
||||
context.defaultSharedPreferences.getString(DirectoryStructure.PREFERENCE, null)
|
||||
val value = context.sharedPrefs.getString(DirectoryStructure.PREFERENCE, null)
|
||||
return DirectoryStructure.fromValue(value)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import android.content.Context
|
|||
import android.util.Patterns
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.zeapo.pwdstore.utils.PreferenceKeys
|
||||
import com.zeapo.pwdstore.utils.sharedPrefs
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import mozilla.components.lib.publicsuffixlist.PublicSuffixList
|
||||
|
||||
|
@ -68,8 +69,7 @@ fun getSuffixPlusUpToOne(domain: String, suffix: String): String? {
|
|||
}
|
||||
|
||||
fun getCustomSuffixes(context: Context): Sequence<String> {
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
return prefs.getString(PreferenceKeys.OREO_AUTOFILL_CUSTOM_PUBLIC_SUFFIXES, "")!!
|
||||
return context.sharedPrefs.getString(PreferenceKeys.OREO_AUTOFILL_CUSTOM_PUBLIC_SUFFIXES, "")!!
|
||||
.splitToSequence('\n')
|
||||
.filter { it.isNotBlank() && it.first() != '.' && it.last() != '.' }
|
||||
}
|
||||
|
|
|
@ -100,7 +100,7 @@ class AutofillSaveActivity : AppCompatActivity() {
|
|||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
val repo = PasswordRepository.getRepositoryDirectory(applicationContext)
|
||||
val repo = PasswordRepository.getRepositoryDirectory()
|
||||
val saveIntent = Intent(this, PasswordCreationActivity::class.java).apply {
|
||||
putExtras(
|
||||
bundleOf(
|
||||
|
|
|
@ -27,6 +27,7 @@ import com.zeapo.pwdstore.R
|
|||
import com.zeapo.pwdstore.utils.OPENPGP_PROVIDER
|
||||
import com.zeapo.pwdstore.utils.PreferenceKeys
|
||||
import com.zeapo.pwdstore.utils.clipboard
|
||||
import com.zeapo.pwdstore.utils.sharedPrefs
|
||||
import com.zeapo.pwdstore.utils.snackbar
|
||||
import java.io.File
|
||||
import me.msfjarvis.openpgpktx.util.OpenPgpApi
|
||||
|
@ -69,7 +70,7 @@ open class BasePgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBou
|
|||
/**
|
||||
* [SharedPreferences] instance used by subclasses to persist settings
|
||||
*/
|
||||
val settings: SharedPreferences by lazy { PreferenceManager.getDefaultSharedPreferences(this) }
|
||||
val settings: SharedPreferences by lazy { sharedPrefs }
|
||||
|
||||
/**
|
||||
* Handle to the [OpenPgpApi] instance that is used by subclasses to interface with OpenKeychain.
|
||||
|
|
|
@ -304,7 +304,7 @@ class PasswordCreationActivity : BasePgpActivity(), OpenPgpServiceConnection.OnB
|
|||
data.action = OpenPgpApi.ACTION_ENCRYPT
|
||||
|
||||
// pass enters the key ID into `.gpg-id`.
|
||||
val repoRoot = PasswordRepository.getRepositoryDirectory(applicationContext)
|
||||
val repoRoot = PasswordRepository.getRepositoryDirectory()
|
||||
val gpgIdentifierFile = File(repoRoot, directory.text.toString()).findTillRoot(".gpg-id", repoRoot)
|
||||
if (gpgIdentifierFile == null) {
|
||||
snackbar(message = resources.getString(R.string.failed_to_find_key_id))
|
||||
|
@ -391,7 +391,7 @@ class PasswordCreationActivity : BasePgpActivity(), OpenPgpServiceConnection.OnB
|
|||
return@executeApiAsync
|
||||
}
|
||||
|
||||
if (!isInsideRepository(file)) {
|
||||
if (!file.isInsideRepository()) {
|
||||
snackbar(message = getString(R.string.message_error_destination_outside_repo))
|
||||
return@executeApiAsync
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@ import androidx.appcompat.app.AppCompatActivity
|
|||
import androidx.core.content.edit
|
||||
import androidx.core.text.isDigitsOnly
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.github.ajalt.timberkt.Timber.tag
|
||||
import com.github.ajalt.timberkt.e
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
|
@ -31,6 +30,7 @@ import com.zeapo.pwdstore.git.operation.SyncOperation
|
|||
import com.zeapo.pwdstore.utils.PasswordRepository
|
||||
import com.zeapo.pwdstore.utils.PreferenceKeys
|
||||
import com.zeapo.pwdstore.utils.getEncryptedPrefs
|
||||
import com.zeapo.pwdstore.utils.sharedPrefs
|
||||
import java.io.File
|
||||
import java.net.URI
|
||||
import kotlinx.coroutines.launch
|
||||
|
@ -61,7 +61,7 @@ abstract class BaseGitActivity : AppCompatActivity() {
|
|||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
settings = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
settings = sharedPrefs
|
||||
encryptedSettings = getEncryptedPrefs("git_operation")
|
||||
protocol = Protocol.fromString(settings.getString(PreferenceKeys.GIT_REMOTE_PROTOCOL, null))
|
||||
connectionMode = ConnectionMode.fromString(settings.getString(PreferenceKeys.GIT_REMOTE_AUTH, null))
|
||||
|
@ -197,7 +197,7 @@ abstract class BaseGitActivity : AppCompatActivity() {
|
|||
return
|
||||
}
|
||||
|
||||
val localDir = requireNotNull(PasswordRepository.getRepositoryDirectory(this))
|
||||
val localDir = requireNotNull(PasswordRepository.getRepositoryDirectory())
|
||||
val op = when (operation) {
|
||||
REQUEST_CLONE, GitOperation.GET_SSH_KEY_FROM_CLONE -> CloneOperation(localDir, url!!, this)
|
||||
REQUEST_PULL -> PullOperation(localDir, this)
|
||||
|
|
|
@ -34,7 +34,7 @@ class GitConfigActivity : BaseGitActivity() {
|
|||
else
|
||||
binding.gitUserName.setText(username)
|
||||
binding.gitUserEmail.setText(email)
|
||||
val repo = PasswordRepository.getRepository(PasswordRepository.getRepositoryDirectory(this))
|
||||
val repo = PasswordRepository.getRepository(PasswordRepository.getRepositoryDirectory())
|
||||
if (repo != null) {
|
||||
try {
|
||||
val objectId = repo.resolve(Constants.HEAD)
|
||||
|
|
|
@ -113,7 +113,7 @@ class GitServerConfigActivity : BaseGitActivity() {
|
|||
|
||||
binding.saveButton.setOnClickListener {
|
||||
if (isClone && PasswordRepository.getRepository(null) == null)
|
||||
PasswordRepository.initialize(this)
|
||||
PasswordRepository.initialize()
|
||||
when (val result = updateUrl()) {
|
||||
GitUpdateUrlResult.Ok -> {
|
||||
settings.edit {
|
||||
|
@ -161,7 +161,7 @@ class GitServerConfigActivity : BaseGitActivity() {
|
|||
* Clones the repository, the directory exists, deletes it
|
||||
*/
|
||||
private fun cloneRepository() {
|
||||
val localDir = requireNotNull(PasswordRepository.getRepositoryDirectory(this))
|
||||
val localDir = requireNotNull(PasswordRepository.getRepositoryDirectory())
|
||||
val localDirFiles = localDir.listFiles() ?: emptyArray()
|
||||
// Warn if non-empty folder unless it's a just-initialized store that has just a .git folder
|
||||
if (localDir.exists() && localDirFiles.isNotEmpty() &&
|
||||
|
|
|
@ -158,9 +158,7 @@ abstract class GitOperation(gitDir: File, internal val callingActivity: Fragment
|
|||
.edit { remove(PreferenceKeys.SSH_OPENKEYSTORE_KEYID) }
|
||||
}
|
||||
is SshjSessionFactory -> {
|
||||
callingActivity.applicationContext
|
||||
.getEncryptedPrefs("git_operation")
|
||||
.edit {
|
||||
callingActivity.getEncryptedPrefs("git_operation").edit {
|
||||
remove(PreferenceKeys.SSH_KEY_LOCAL_PASSPHRASE)
|
||||
remove(PreferenceKeys.HTTPS_PASSWORD)
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import android.content.Context
|
|||
import androidx.preference.PreferenceManager
|
||||
import com.zeapo.pwdstore.R
|
||||
import com.zeapo.pwdstore.utils.PreferenceKeys
|
||||
import com.zeapo.pwdstore.utils.sharedPrefs
|
||||
import java.io.File
|
||||
|
||||
class XkpwdDictionary(context: Context) {
|
||||
|
@ -15,7 +16,7 @@ class XkpwdDictionary(context: Context) {
|
|||
val words: Map<Int, List<String>>
|
||||
|
||||
init {
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
val prefs = context.sharedPrefs
|
||||
val uri = prefs.getString(PreferenceKeys.PREF_KEY_CUSTOM_DICT, "")!!
|
||||
val customDictFile = File(context.filesDir, XKPWD_CUSTOM_DICT_FILE)
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ import com.jcraft.jsch.KeyPair
|
|||
import com.zeapo.pwdstore.R
|
||||
import com.zeapo.pwdstore.databinding.ActivitySshKeygenBinding
|
||||
import com.zeapo.pwdstore.utils.getEncryptedPrefs
|
||||
import com.zeapo.pwdstore.utils.sharedPrefs
|
||||
import com.zeapo.pwdstore.utils.viewBinding
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
|
@ -91,8 +92,7 @@ class SshKeyGenActivity : AppCompatActivity() {
|
|||
if (e == null) {
|
||||
val df = ShowSshKeyFragment()
|
||||
df.show(supportFragmentManager, "public_key")
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
prefs.edit { putBoolean("use_generated_key", true) }
|
||||
sharedPrefs.edit { putBoolean("use_generated_key", true) }
|
||||
} else {
|
||||
MaterialAlertDialogBuilder(this)
|
||||
.setTitle(getString(R.string.error_generate_ssh_key))
|
||||
|
|
|
@ -19,6 +19,7 @@ import com.zeapo.pwdstore.SearchableRepositoryAdapter
|
|||
import com.zeapo.pwdstore.stableId
|
||||
import com.zeapo.pwdstore.utils.PasswordItem
|
||||
import com.zeapo.pwdstore.utils.PreferenceKeys
|
||||
import com.zeapo.pwdstore.utils.sharedPrefs
|
||||
import java.io.File
|
||||
|
||||
open class PasswordItemRecyclerAdapter :
|
||||
|
@ -49,8 +50,7 @@ open class PasswordItemRecyclerAdapter :
|
|||
lateinit var itemDetails: ItemDetailsLookup.ItemDetails<String>
|
||||
|
||||
fun bind(item: PasswordItem) {
|
||||
val settings =
|
||||
PreferenceManager.getDefaultSharedPreferences(itemView.context.applicationContext)
|
||||
val settings = itemView.context.sharedPrefs
|
||||
val showHidden = settings.getBoolean(PreferenceKeys.SHOW_HIDDEN_FOLDERS, false)
|
||||
val parentPath = item.fullPathToParent.replace("(^/)|(/$)".toRegex(), "")
|
||||
val source = if (parentPath.isNotEmpty()) {
|
||||
|
|
|
@ -18,6 +18,7 @@ import androidx.annotation.RequiresApi
|
|||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.security.crypto.EncryptedSharedPreferences
|
||||
import androidx.security.crypto.MasterKey
|
||||
import com.github.ajalt.timberkt.d
|
||||
|
@ -97,6 +98,9 @@ fun Context.getEncryptedPrefs(fileName: String): SharedPreferences {
|
|||
)
|
||||
}
|
||||
|
||||
val Context.sharedPrefs: SharedPreferences
|
||||
get() = PreferenceManager.getDefaultSharedPreferences(applicationContext)
|
||||
|
||||
suspend fun FragmentActivity.commitChange(
|
||||
message: String,
|
||||
finishWithResultOnEnd: Intent? = null,
|
||||
|
@ -109,7 +113,7 @@ suspend fun FragmentActivity.commitChange(
|
|||
}
|
||||
return
|
||||
}
|
||||
object : GitOperation(getRepositoryDirectory(this@commitChange), this@commitChange) {
|
||||
object : GitOperation(getRepositoryDirectory(), this@commitChange) {
|
||||
override val commands = arrayOf(
|
||||
git.add().addFilepattern("."),
|
||||
git.status(),
|
||||
|
@ -151,6 +155,6 @@ val Context.autofillManager: AutofillManager?
|
|||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
get() = getSystemService()
|
||||
|
||||
fun FragmentActivity.isInsideRepository(file: File): Boolean {
|
||||
return file.canonicalPath.contains(getRepositoryDirectory(this).canonicalPath)
|
||||
fun File.isInsideRepository(): Boolean {
|
||||
return canonicalPath.contains(getRepositoryDirectory().canonicalPath)
|
||||
}
|
||||
|
|
|
@ -4,10 +4,9 @@
|
|||
*/
|
||||
package com.zeapo.pwdstore.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import androidx.core.content.edit
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.zeapo.pwdstore.Application
|
||||
import java.io.File
|
||||
import java.io.FileFilter
|
||||
import java.util.Comparator
|
||||
|
@ -49,7 +48,9 @@ open class PasswordRepository protected constructor() {
|
|||
companion object {
|
||||
|
||||
private var repository: Repository? = null
|
||||
private lateinit var settings: SharedPreferences
|
||||
private val settings by lazy { Application.instance.sharedPrefs }
|
||||
private val filesDir
|
||||
get() = Application.instance.filesDir
|
||||
|
||||
/**
|
||||
* Returns the git repository
|
||||
|
@ -152,27 +153,21 @@ open class PasswordRepository protected constructor() {
|
|||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getRepositoryDirectory(context: Context): File {
|
||||
if (!::settings.isInitialized) {
|
||||
settings = PreferenceManager.getDefaultSharedPreferences(context.applicationContext)
|
||||
}
|
||||
fun getRepositoryDirectory(): File {
|
||||
return if (settings.getBoolean(PreferenceKeys.GIT_EXTERNAL, false)) {
|
||||
val externalRepo = settings.getString(PreferenceKeys.GIT_EXTERNAL_REPO, null)
|
||||
if (externalRepo != null)
|
||||
File(externalRepo)
|
||||
else
|
||||
File(context.filesDir.toString(), "/store")
|
||||
File(filesDir.toString(), "/store")
|
||||
} else {
|
||||
File(context.filesDir.toString(), "/store")
|
||||
File(filesDir.toString(), "/store")
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun initialize(context: Context): Repository? {
|
||||
if (!::settings.isInitialized) {
|
||||
settings = PreferenceManager.getDefaultSharedPreferences(context.applicationContext)
|
||||
}
|
||||
val dir = getRepositoryDirectory(context)
|
||||
fun initialize(): Repository? {
|
||||
val dir = getRepositoryDirectory()
|
||||
// uninitialize the repo if the dir does not exist or is absolutely empty
|
||||
settings.edit {
|
||||
if (!dir.exists() || !dir.isDirectory || dir.listFiles()!!.isEmpty()) {
|
||||
|
|
Loading…
Reference in a new issue