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:
Fabian Henneke 2020-08-06 10:58:20 +02:00 committed by GitHub
parent 14c44bf584
commit 3dace243e4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 159 additions and 191 deletions

View file

@ -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

View file

@ -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) {

View file

@ -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) {

View file

@ -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" }

View file

@ -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
}

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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,28 +558,24 @@ 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 {
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
}
registerForActivityResult(StartActivityForResult()) { result ->
if (!validateResult(result)) return@registerForActivityResult
val uri = result.data?.data
if (uri != null) {
}
}) { uri: Uri? ->
if (uri == null) return@registerForActivityResult
val targetDirectory = DocumentFile.fromTreeUri(applicationContext, uri)
if (targetDirectory != null) {
@ -610,8 +590,7 @@ class UserPreference : AppCompatActivity() {
startService(service)
}
}
}
}.launch(intent)
}.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)

View file

@ -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) {

View file

@ -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

View file

@ -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)
}
}

View file

@ -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() != '.' }
}

View file

@ -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(

View file

@ -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.

View file

@ -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
}

View file

@ -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)

View file

@ -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)

View file

@ -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() &&

View file

@ -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)
}

View file

@ -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)

View 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))

View file

@ -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()) {

View file

@ -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)
}

View file

@ -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()) {