Skip to content
This repository has been archived by the owner on Oct 15, 2024. It is now read-only.

Commit

Permalink
Scroll to files and enter folders when created (#909)
Browse files Browse the repository at this point in the history
  • Loading branch information
FabianHenneke authored Jul 1, 2020
1 parent c5a93b8 commit 1c9f797
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 12 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ All notable changes to this project will be documented in this file.
- TOTP support is reintroduced by popular demand. HOTP continues to be unsupported and heavily discouraged.
- Initial support for detecting and filling OTP fields with Autofill
- Importing TOTP secrets using QR codes
- Navigate into newly created folders and scroll to newly created passwords

## [1.9.2] - 2020-06-30

Expand Down
26 changes: 20 additions & 6 deletions app/src/main/java/com/zeapo/pwdstore/PasswordFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class PasswordFragment : Fragment(R.layout.password_recycler_view) {

private var recyclerViewStateToRestore: Parcelable? = null
private var actionMode: ActionMode? = null
private var scrollTarget: File? = null

private val model: SearchableRepositoryViewModel by activityViewModels()
private val binding by viewBinding(PasswordRecyclerViewBinding::bind)
Expand Down Expand Up @@ -132,6 +133,11 @@ class PasswordFragment : Fragment(R.layout.password_recycler_view) {
// When the result is filtered, we always scroll to the top since that is where
// the best fuzzy match appears.
recyclerView.scrollToPosition(0)
} else if (scrollTarget != null) {
scrollTarget?.let {
recyclerView.scrollToPosition(recyclerAdapter.getPositionForFile(it))
}
scrollTarget == null
} else {
// When the result is not filtered and there is a saved scroll position for it,
// we try to restore it.
Expand Down Expand Up @@ -223,12 +229,7 @@ class PasswordFragment : Fragment(R.layout.password_recycler_view) {
listener = object : OnFragmentInteractionListener {
override fun onFragmentInteraction(item: PasswordItem) {
if (item.type == PasswordItem.TYPE_CATEGORY) {
requireStore().clearSearch()
model.navigateTo(
item.file,
recyclerViewState = binding.passRecycler.layoutManager!!.onSaveInstanceState()
)
requireStore().supportActionBar?.setDisplayHomeAsUpEnabled(true)
navigateTo(item.file)
} else {
if (requireArguments().getBoolean("matchWith", false)) {
requireStore().matchPasswordWithApp(item)
Expand Down Expand Up @@ -272,6 +273,19 @@ class PasswordFragment : Fragment(R.layout.password_recycler_view) {

fun createPassword() = requireStore().createPassword()

fun navigateTo(file: File) {
requireStore().clearSearch()
model.navigateTo(
file,
recyclerViewState = binding.passRecycler.layoutManager!!.onSaveInstanceState()
)
requireStore().supportActionBar?.setDisplayHomeAsUpEnabled(true)
}

fun scrollToOnNextRefresh(file: File) {
scrollTarget = file
}

interface OnFragmentInteractionListener {
fun onFragmentInteraction(item: PasswordItem)
}
Expand Down
17 changes: 13 additions & 4 deletions app/src/main/java/com/zeapo/pwdstore/PasswordStore.kt
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ import com.zeapo.pwdstore.utils.PasswordRepository.Companion.isInitialized
import com.zeapo.pwdstore.utils.PasswordRepository.PasswordSortOrder.Companion.getSortOrder
import com.zeapo.pwdstore.utils.PreferenceKeys
import com.zeapo.pwdstore.utils.commitChange
import com.zeapo.pwdstore.utils.contains
import com.zeapo.pwdstore.utils.isInsideRepository
import com.zeapo.pwdstore.utils.listFilesRecursively
import com.zeapo.pwdstore.utils.requestInputFocusOnView
Expand Down Expand Up @@ -734,10 +735,17 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) {
/**
* Refreshes the password list by re-executing the last navigation or search action, preserving
* the navigation stack and scroll position. If the current directory no longer exists,
* navigation is reset to the repository root.
* navigation is reset to the repository root. If the optional [target] argument is provided,
* it will be entered if it is a directory or scrolled into view if it is a file (both inside
* the current directory).
*/
fun refreshPasswordList() {
if (model.currentDir.value?.isDirectory == true) {
fun refreshPasswordList(target: File? = null) {
if (target?.isDirectory == true && model.currentDir.value?.contains(target) == true) {
plist?.navigateTo(target)
} else if (target?.isFile == true && model.currentDir.value?.contains(target) == true) {
// Creating new passwords is handled by an activity, so we will refresh in onStart.
plist?.scrollToOnNextRefresh(target)
} else if (model.currentDir.value?.isDirectory == true) {
model.forceRefresh()
} else {
model.reset()
Expand All @@ -764,7 +772,8 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) {
}
REQUEST_CODE_ENCRYPT -> {
commitChange(resources.getString(R.string.git_commit_add_text,
data!!.extras!!.getString("LONG_NAME")))
data!!.extras!!.getString(PasswordCreationActivity.RETURN_EXTRA_LONG_NAME)))
refreshPasswordList(File(data.extras!!.getString(PasswordCreationActivity.RETURN_EXTRA_CREATED_FILE)!!))
}
BaseGitActivity.REQUEST_INIT, NEW_REPO_BUTTON -> initializeRepositoryInfo()
BaseGitActivity.REQUEST_SYNC, BaseGitActivity.REQUEST_PULL -> refreshPasswordList()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,8 @@ open class SearchableRepositoryAdapter<T : RecyclerView.ViewHolder>(
return selectedFiles.map { it.toPasswordItem(root) }
}

fun getPositionForFile(file: File) = itemKeyProvider.getPosition(file.absolutePath)

final override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): T {
val view = LayoutInflater.from(parent.context)
.inflate(layoutRes, parent, false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,9 @@ class FolderCreationDialogFragment : DialogFragment() {
val dialog = requireDialog()
val materialTextView = dialog.findViewById<TextInputEditText>(R.id.folder_name_text)
val folderName = materialTextView.text.toString()
File("$currentDir/$folderName").mkdir()
(requireActivity() as PasswordStore).refreshPasswordList()
val newFolder = File("$currentDir/$folderName")
newFolder.mkdir()
(requireActivity() as PasswordStore).refreshPasswordList(newFolder)
dismiss()
}

Expand Down
17 changes: 17 additions & 0 deletions app/src/main/java/com/zeapo/pwdstore/utils/Extensions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,23 @@ fun Activity.snackbar(

fun File.listFilesRecursively() = walkTopDown().filter { !it.isDirectory }.toList()

/**
* Checks whether this [File] is a directory that contains [other].
*/
fun File.contains(other: File): Boolean {
if (!isDirectory)
return false
if (!other.exists())
return false
val relativePath = try {
other.relativeTo(this)
} catch (e: Exception) {
return false
}
// Direct containment is equivalent to the relative path being equal to the filename.
return relativePath.path == other.name
}

fun Context.resolveAttribute(attr: Int): Int {
val typedValue = TypedValue()
this.theme.resolveAttribute(attr, typedValue, true)
Expand Down

0 comments on commit 1c9f797

Please sign in to comment.