Allow creating folders (#623)
* Introduce EmitExpandableTransformationBehaviour * Implement expand transition * More folder work * Add icons and tweak layout clipping Rishi again with the icon rescue * Theming rework * Dont set tag * Update list and commit after creating folder * Fix theme issues * Add dialog title * Fix hint text color * Remove commit method * Cleanup * Update CHANGELOG Signed-off-by: Harsh Shandilya <msfjarvis@gmail.com> Co-authored-by: Aditya Wasan <adityawasan55@gmail.com>
This commit is contained in:
parent
ab5aebeda3
commit
f295e97de6
21 changed files with 336 additions and 59 deletions
|
@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- Fast scroller with alphabetic hints
|
- Fast scroller with alphabetic hints
|
||||||
|
- UI button to create new folders
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Logging is now enabled in release builds
|
- Logging is now enabled in release builds
|
||||||
|
|
|
@ -70,12 +70,30 @@ class PasswordFragment : Fragment() {
|
||||||
recyclerView.adapter = recyclerAdapter
|
recyclerView.adapter = recyclerAdapter
|
||||||
// Setup fast scroller
|
// Setup fast scroller
|
||||||
FastScrollerBuilder(recyclerView).build()
|
FastScrollerBuilder(recyclerView).build()
|
||||||
val fab: FloatingActionButton = view.findViewById(R.id.fab)
|
val fab = view.findViewById<FloatingActionButton>(R.id.fab)
|
||||||
fab.setOnClickListener { (requireActivity() as PasswordStore).createPassword() }
|
fab.setOnClickListener {
|
||||||
|
toggleFabExpand(fab)
|
||||||
|
}
|
||||||
|
|
||||||
|
view.findViewById<FloatingActionButton>(R.id.create_folder).setOnClickListener {
|
||||||
|
(requireActivity() as PasswordStore).createFolder()
|
||||||
|
toggleFabExpand(fab)
|
||||||
|
}
|
||||||
|
|
||||||
|
view.findViewById<FloatingActionButton>(R.id.create_password).setOnClickListener {
|
||||||
|
(requireActivity() as PasswordStore).createPassword()
|
||||||
|
toggleFabExpand(fab)
|
||||||
|
}
|
||||||
registerForContextMenu(recyclerView)
|
registerForContextMenu(recyclerView)
|
||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun toggleFabExpand(fab: FloatingActionButton) = with(fab) {
|
||||||
|
isExpanded = !isExpanded
|
||||||
|
isActivated = isExpanded
|
||||||
|
animate().rotationBy(if (isExpanded) -45f else 45f).setDuration(100).start()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onAttach(context: Context) {
|
override fun onAttach(context: Context) {
|
||||||
super.onAttach(context)
|
super.onAttach(context)
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -38,6 +38,7 @@ import com.zeapo.pwdstore.git.GitActivity
|
||||||
import com.zeapo.pwdstore.git.GitAsyncTask
|
import com.zeapo.pwdstore.git.GitAsyncTask
|
||||||
import com.zeapo.pwdstore.git.GitOperation
|
import com.zeapo.pwdstore.git.GitOperation
|
||||||
import com.zeapo.pwdstore.ui.adapters.PasswordRecyclerAdapter
|
import com.zeapo.pwdstore.ui.adapters.PasswordRecyclerAdapter
|
||||||
|
import com.zeapo.pwdstore.ui.dialogs.FolderCreationDialogFragment
|
||||||
import com.zeapo.pwdstore.utils.PasswordItem
|
import com.zeapo.pwdstore.utils.PasswordItem
|
||||||
import com.zeapo.pwdstore.utils.PasswordRepository
|
import com.zeapo.pwdstore.utils.PasswordRepository
|
||||||
import com.zeapo.pwdstore.utils.PasswordRepository.Companion.closeRepository
|
import com.zeapo.pwdstore.utils.PasswordRepository.Companion.closeRepository
|
||||||
|
@ -435,13 +436,13 @@ class PasswordStore : AppCompatActivity() {
|
||||||
startActivityForResult(intent, REQUEST_CODE_EDIT)
|
startActivityForResult(intent, REQUEST_CODE_EDIT)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createPassword() {
|
private fun validateState(): Boolean {
|
||||||
if (!isInitialized) {
|
if (!isInitialized) {
|
||||||
MaterialAlertDialogBuilder(this)
|
MaterialAlertDialogBuilder(this)
|
||||||
.setMessage(this.resources.getString(R.string.creation_dialog_text))
|
.setMessage(this.resources.getString(R.string.creation_dialog_text))
|
||||||
.setPositiveButton(this.resources.getString(R.string.dialog_ok), null)
|
.setPositiveButton(this.resources.getString(R.string.dialog_ok), null)
|
||||||
.show()
|
.show()
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
if (settings.getStringSet("openpgp_key_ids_set", HashSet()).isNullOrEmpty()) {
|
if (settings.getStringSet("openpgp_key_ids_set", HashSet()).isNullOrEmpty()) {
|
||||||
MaterialAlertDialogBuilder(this)
|
MaterialAlertDialogBuilder(this)
|
||||||
|
@ -452,8 +453,13 @@ class PasswordStore : AppCompatActivity() {
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
}
|
}
|
||||||
.show()
|
.show()
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createPassword() {
|
||||||
|
if (!validateState()) return
|
||||||
val currentDir = currentDir
|
val currentDir = currentDir
|
||||||
Timber.tag(TAG).i("Adding file to : ${currentDir!!.absolutePath}")
|
Timber.tag(TAG).i("Adding file to : ${currentDir!!.absolutePath}")
|
||||||
val intent = Intent(this, PgpActivity::class.java)
|
val intent = Intent(this, PgpActivity::class.java)
|
||||||
|
@ -463,6 +469,11 @@ class PasswordStore : AppCompatActivity() {
|
||||||
startActivityForResult(intent, REQUEST_CODE_ENCRYPT)
|
startActivityForResult(intent, REQUEST_CODE_ENCRYPT)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun createFolder() {
|
||||||
|
if (!validateState()) return
|
||||||
|
FolderCreationDialogFragment.newInstance(currentDir!!.path).show(supportFragmentManager, null)
|
||||||
|
}
|
||||||
|
|
||||||
// deletes passwords in order from top to bottom
|
// deletes passwords in order from top to bottom
|
||||||
fun deletePasswords(adapter: PasswordRecyclerAdapter, selectedItems: MutableSet<Int>) {
|
fun deletePasswords(adapter: PasswordRecyclerAdapter, selectedItems: MutableSet<Int>) {
|
||||||
val it: MutableIterator<*> = selectedItems.iterator()
|
val it: MutableIterator<*> = selectedItems.iterator()
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2014-2019 The Android Password Store Authors. All Rights Reserved.
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
*/
|
||||||
|
package com.zeapo.pwdstore.ui.dialogs
|
||||||
|
|
||||||
|
import android.app.Dialog
|
||||||
|
import android.content.DialogInterface
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.core.os.bundleOf
|
||||||
|
import androidx.fragment.app.DialogFragment
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import com.google.android.material.textfield.TextInputEditText
|
||||||
|
import com.zeapo.pwdstore.PasswordStore
|
||||||
|
import com.zeapo.pwdstore.R
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
class FolderCreationDialogFragment : DialogFragment() {
|
||||||
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
|
val alertDialogBuilder = MaterialAlertDialogBuilder(requireContext())
|
||||||
|
alertDialogBuilder.setView(R.layout.folder_creation_dialog_fragment)
|
||||||
|
alertDialogBuilder.setPositiveButton(getString(R.string.button_create)) { _: DialogInterface, _: Int ->
|
||||||
|
createDirectory(requireArguments().getString(CURRENT_DIR_EXTRA)!!)
|
||||||
|
}
|
||||||
|
return alertDialogBuilder.create()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createDirectory(currentDir: String) {
|
||||||
|
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).updateListAdapter()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val CURRENT_DIR_EXTRA = "CURRENT_DIRECTORY"
|
||||||
|
fun newInstance(startingDirectory: String): FolderCreationDialogFragment {
|
||||||
|
val extras = bundleOf(CURRENT_DIR_EXTRA to startingDirectory)
|
||||||
|
val fragment = FolderCreationDialogFragment()
|
||||||
|
fragment.arguments = extras
|
||||||
|
return fragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,141 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2014-2019 The Android Password Store Authors. All Rights Reserved.
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
*/
|
||||||
|
package com.zeapo.pwdstore.widget.fab
|
||||||
|
|
||||||
|
import android.animation.Animator
|
||||||
|
import android.animation.AnimatorSet
|
||||||
|
import android.animation.ObjectAnimator
|
||||||
|
import android.animation.PropertyValuesHolder
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
|
import androidx.core.animation.addListener
|
||||||
|
import androidx.core.view.children
|
||||||
|
import androidx.core.view.isInvisible
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
|
import com.google.android.material.transformation.ExpandableTransformationBehavior
|
||||||
|
import java.util.ArrayList
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Taken from Mao Yufeng's excellent example at https://git.io/Jvml9, all credits to him for this.
|
||||||
|
* It's hard to create per-file copyright rules for Spotless so I'm choosing to credit him here.
|
||||||
|
*/
|
||||||
|
class EmitExpandableTransformationBehavior @JvmOverloads constructor(
|
||||||
|
context: Context? = null,
|
||||||
|
attrs: AttributeSet? = null
|
||||||
|
) : ExpandableTransformationBehavior(context, attrs) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val EXPAND_DELAY = 60L
|
||||||
|
private const val EXPAND_DURATION = 150L
|
||||||
|
private const val COLLAPSE_DELAY = 60L
|
||||||
|
private const val COLLAPSE_DURATION = 150L
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun layoutDependsOn(parent: CoordinatorLayout, child: View, dependency: View): Boolean {
|
||||||
|
return dependency is FloatingActionButton && child is ViewGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateExpandedStateChangeAnimation(
|
||||||
|
dependency: View,
|
||||||
|
child: View,
|
||||||
|
expanded: Boolean,
|
||||||
|
isAnimating: Boolean
|
||||||
|
): AnimatorSet {
|
||||||
|
|
||||||
|
if (child !is ViewGroup) {
|
||||||
|
return AnimatorSet()
|
||||||
|
}
|
||||||
|
|
||||||
|
val animations = ArrayList<Animator>()
|
||||||
|
|
||||||
|
if (expanded) {
|
||||||
|
createExpandAnimation(child, isAnimating, animations)
|
||||||
|
} else {
|
||||||
|
createCollapseAnimation(child, animations)
|
||||||
|
}
|
||||||
|
|
||||||
|
val set = AnimatorSet()
|
||||||
|
set.playTogether(animations)
|
||||||
|
set.addListener(
|
||||||
|
onStart = {
|
||||||
|
if (expanded) {
|
||||||
|
child.isVisible = true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onEnd = {
|
||||||
|
if (!expanded) {
|
||||||
|
child.isInvisible = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return set
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createExpandAnimation(
|
||||||
|
child: ViewGroup,
|
||||||
|
currentlyAnimating: Boolean,
|
||||||
|
animations: MutableList<Animator>
|
||||||
|
) {
|
||||||
|
if (!currentlyAnimating) {
|
||||||
|
child.children.forEach {
|
||||||
|
it.alpha = 0f
|
||||||
|
it.scaleX = 0.4f
|
||||||
|
it.scaleY = 0.4f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val delays = List(child.childCount) {
|
||||||
|
it * EXPAND_DELAY
|
||||||
|
}.reversed().asSequence()
|
||||||
|
val scaleXHolder = PropertyValuesHolder.ofFloat(View.SCALE_X, 1f)
|
||||||
|
val scaleYHolder = PropertyValuesHolder.ofFloat(View.SCALE_Y, 1f)
|
||||||
|
val alphaHolder = PropertyValuesHolder.ofFloat(View.ALPHA, 1f)
|
||||||
|
val animators = child.children.zip(delays) { view, delay ->
|
||||||
|
ObjectAnimator.ofPropertyValuesHolder(
|
||||||
|
view,
|
||||||
|
scaleXHolder,
|
||||||
|
scaleYHolder,
|
||||||
|
alphaHolder
|
||||||
|
).apply {
|
||||||
|
duration = EXPAND_DURATION
|
||||||
|
startDelay = delay
|
||||||
|
}
|
||||||
|
}.toList()
|
||||||
|
val animatorSet = AnimatorSet().apply {
|
||||||
|
playTogether(animators)
|
||||||
|
}
|
||||||
|
animations.add(animatorSet)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createCollapseAnimation(
|
||||||
|
child: ViewGroup,
|
||||||
|
animations: MutableList<Animator>
|
||||||
|
) {
|
||||||
|
val delays = List(child.childCount) {
|
||||||
|
it * COLLAPSE_DELAY
|
||||||
|
}.asSequence()
|
||||||
|
val scaleXHolder = PropertyValuesHolder.ofFloat(View.SCALE_X, 0.4f)
|
||||||
|
val scaleYHolder = PropertyValuesHolder.ofFloat(View.SCALE_Y, 0.4f)
|
||||||
|
val alphaHolder = PropertyValuesHolder.ofFloat(View.ALPHA, 0f)
|
||||||
|
val animators = child.children.zip(delays) { view, delay ->
|
||||||
|
ObjectAnimator.ofPropertyValuesHolder(
|
||||||
|
view,
|
||||||
|
scaleXHolder,
|
||||||
|
scaleYHolder,
|
||||||
|
alphaHolder
|
||||||
|
).apply {
|
||||||
|
duration = COLLAPSE_DURATION
|
||||||
|
startDelay = delay
|
||||||
|
}
|
||||||
|
}.toList()
|
||||||
|
val animatorSet = AnimatorSet().apply {
|
||||||
|
playTogether(animators)
|
||||||
|
}
|
||||||
|
animations.add(animatorSet)
|
||||||
|
}
|
||||||
|
}
|
9
app/src/main/res/drawable/ic_action_new_folder.xml
Normal file
9
app/src/main/res/drawable/ic_action_new_folder.xml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFFFF"
|
||||||
|
android:pathData="M20,18H4V8H20M20,6H12L10,4H4C2.89,4 2,4.89 2,6V18A2,2 0,0 0,4 20H20A2,2 0,0 0,22 18V8C22,6.89 21.1,6 20,6Z"/>
|
||||||
|
</vector>
|
9
app/src/main/res/drawable/ic_action_new_password.xml
Normal file
9
app/src/main/res/drawable/ic_action_new_password.xml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFFFF"
|
||||||
|
android:pathData="M14,2H6A2,2 0,0 0,4 4V20A2,2 0,0 0,6 22H18A2,2 0,0 0,20 20V8L14,2M18,20H6V4H13V9H18M12.83,15A3,3 0,1 0,12.83 17H14V19H16V17H17V15M10,17A1,1 0,1 1,11 16A1,1 0,0 1,10 17Z"/>
|
||||||
|
</vector>
|
|
@ -3,7 +3,7 @@
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24"
|
android:viewportHeight="24"
|
||||||
android:tint="?attr/passwordIconColor">
|
android:tint="?attr/colorOnPrimary">
|
||||||
<path
|
<path
|
||||||
android:fillColor="#FFFFFFFF"
|
android:fillColor="#FFFFFFFF"
|
||||||
android:pathData="M18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM9,6c0,-1.66 1.34,-3 3,-3s3,1.34 3,3v2L9,8L9,6zM18,20L6,20L6,10h12v10zM12,17c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2z"/>
|
android:pathData="M18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM9,6c0,-1.66 1.34,-3 3,-3s3,1.34 3,3v2L9,8L9,6zM18,20L6,20L6,10h12v10zM12,17c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2z"/>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24"
|
android:viewportHeight="24"
|
||||||
android:tint="?attr/passwordIconColor">
|
android:tint="?attr/colorOnPrimary">
|
||||||
<path
|
<path
|
||||||
android:fillColor="#FFFFFFFF"
|
android:fillColor="#FFFFFFFF"
|
||||||
android:pathData="M8.59,16.59L13.17,12 8.59,7.41 10,6l6,6 -6,6 -1.41,-1.41z"/>
|
android:pathData="M8.59,16.59L13.17,12 8.59,7.41 10,6l6,6 -6,6 -1.41,-1.41z"/>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24"
|
android:viewportHeight="24"
|
||||||
android:tint="?passwordIconColor">
|
android:tint="?colorOnPrimary">
|
||||||
<path
|
<path
|
||||||
android:fillColor="#FFFFFFFF"
|
android:fillColor="#FFFFFFFF"
|
||||||
android:pathData="M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM15,5L8,5c-1.1,0 -1.99,0.9 -1.99,2L6,21c0,1.1 0.89,2 1.99,2L19,23c1.1,0 2,-0.9 2,-2L21,11l-6,-6zM8,21L8,7h6v5h5v9L8,21z"/>
|
android:pathData="M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM15,5L8,5c-1.1,0 -1.99,0.9 -1.99,2L6,21c0,1.1 0.89,2 1.99,2L19,23c1.1,0 2,-0.9 2,-2L21,11l-6,-6zM8,21L8,7h6v5h5v9L8,21z"/>
|
||||||
|
|
33
app/src/main/res/layout/folder_creation_dialog_fragment.xml
Normal file
33
app/src/main/res/layout/folder_creation_dialog_fragment.xml
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/title_create_folder"
|
||||||
|
android:textColor="@color/color_control_normal"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.SearchResult.Title"/>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
style="@style/TextInputLayoutBase"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:hint="@string/crypto_name_hint"
|
||||||
|
app:hintTextColor="@color/color_control_normal"
|
||||||
|
app:hintEnabled="true">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/folder_name_text"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="textNoSuggestions|textVisiblePassword"/>
|
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
</LinearLayout>
|
|
@ -1,10 +1,13 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
|
android:clipChildren="false"
|
||||||
|
android:clipToPadding="false"
|
||||||
tools:context="com.zeapo.pwdstore.PasswordFragment">
|
tools:context="com.zeapo.pwdstore.PasswordFragment">
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
@ -13,7 +16,39 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:listitem="@layout/password_row_layout"
|
tools:listitem="@layout/password_row_layout"
|
||||||
tools:itemCount="20"/>
|
tools:itemCount="20" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/create_options"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="top|center_horizontal"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:visibility="invisible"
|
||||||
|
android:clipChildren="false"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
app:layout_anchor="@id/fab"
|
||||||
|
app:layout_anchorGravity="top|center_horizontal"
|
||||||
|
app:layout_behavior="com.zeapo.pwdstore.widget.fab.EmitExpandableTransformationBehavior"
|
||||||
|
tools:visibility="visible">
|
||||||
|
|
||||||
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
|
android:id="@+id/create_password"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="@dimen/fab_margin"
|
||||||
|
app:fabSize="mini"
|
||||||
|
app:srcCompat="@drawable/ic_action_new_password" />
|
||||||
|
|
||||||
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
|
android:id="@+id/create_folder"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="@dimen/fab_margin"
|
||||||
|
app:fabSize="mini"
|
||||||
|
app:srcCompat="@drawable/ic_action_new_folder" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
android:id="@+id/fab"
|
android:id="@+id/fab"
|
||||||
|
@ -21,12 +56,9 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="bottom|end"
|
android:layout_gravity="bottom|end"
|
||||||
app:elevation="6dp"
|
|
||||||
app:pressedTranslationZ="12dp"
|
|
||||||
app:backgroundTint="?attr/colorSecondary"
|
|
||||||
app:rippleColor="?attr/colorSecondary"
|
|
||||||
app:borderWidth="0dp"
|
|
||||||
android:layout_margin="@dimen/fab_compat_margin"
|
android:layout_margin="@dimen/fab_compat_margin"
|
||||||
android:layout_alignParentBottom="true"
|
android:layout_alignParentBottom="true"
|
||||||
android:layout_alignParentEnd="true"/>
|
android:layout_alignParentEnd="true"
|
||||||
</RelativeLayout>
|
app:backgroundTint="?attr/colorSecondary"
|
||||||
|
app:rippleColor="?attr/colorSecondary" />
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="bottom"
|
android:layout_gravity="bottom"
|
||||||
android:textColor="?android:attr/textColor"
|
|
||||||
android:textSize="18sp"
|
android:textSize="18sp"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintStart_toEndOf="@id/type_image"
|
app:layout_constraintStart_toEndOf="@id/type_image"
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
<resources>
|
|
||||||
<style name="TextInputLayoutBase" parent="@style/Widget.MaterialComponents.TextInputLayout.FilledBox.Dense">
|
|
||||||
<item name="boxBackgroundColor">?attr/colorPrimaryVariant</item>
|
|
||||||
<item name="boxStrokeColor">?attr/colorSecondary</item>
|
|
||||||
<item name="hintTextColor">?attr/colorOnPrimary</item>
|
|
||||||
</style>
|
|
||||||
</resources>
|
|
|
@ -1,4 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
<dimen name="fab_compat_margin">16dp</dimen>
|
|
||||||
</resources>
|
|
|
@ -1,6 +0,0 @@
|
||||||
<resources>
|
|
||||||
<!-- Example customization of dimensions originally defined in res/values/dimens.xml
|
|
||||||
(such as screen margins) for screens with more than 820dp of available width. This
|
|
||||||
would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
|
|
||||||
<dimen name="activity_horizontal_margin">64dp</dimen>
|
|
||||||
</resources>
|
|
|
@ -1,8 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<declare-styleable name="PasswordIconStyle">
|
|
||||||
<attr name="passwordIconColor" format="reference|color" />
|
|
||||||
</declare-styleable>
|
|
||||||
<declare-styleable name="Multiselected">
|
<declare-styleable name="Multiselected">
|
||||||
<attr name="state_multiselected" format="boolean"/>
|
<attr name="state_multiselected" format="boolean"/>
|
||||||
</declare-styleable>
|
</declare-styleable>
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
<color name="secondary_dark_color">#c63f17</color>
|
<color name="secondary_dark_color">#c63f17</color>
|
||||||
<color name="primary_text_color">#212121</color>
|
<color name="primary_text_color">#212121</color>
|
||||||
<color name="secondary_text_color">#ffffff</color>
|
<color name="secondary_text_color">#ffffff</color>
|
||||||
|
<color name="white">#ffffffff</color>
|
||||||
|
|
||||||
<!-- Theme variables -->
|
<!-- Theme variables -->
|
||||||
<color name="window_background">#eceff1</color>
|
<color name="window_background">#eceff1</color>
|
||||||
|
@ -17,4 +18,5 @@
|
||||||
<color name="color_control_normal">@color/primary_text_color</color>
|
<color name="color_control_normal">@color/primary_text_color</color>
|
||||||
<color name="color_surface">#FFFFFF</color>
|
<color name="color_surface">#FFFFFF</color>
|
||||||
<color name="list_multiselect_background">#668eacbb</color>
|
<color name="list_multiselect_background">#668eacbb</color>
|
||||||
|
<color name="status_bar_color">@color/primary_dark_color</color>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -2,5 +2,6 @@
|
||||||
<!-- Default screen margins, per the Android Design guidelines. -->
|
<!-- Default screen margins, per the Android Design guidelines. -->
|
||||||
<dimen name="activity_horizontal_margin">16dp</dimen>
|
<dimen name="activity_horizontal_margin">16dp</dimen>
|
||||||
<dimen name="activity_vertical_margin">16dp</dimen>
|
<dimen name="activity_vertical_margin">16dp</dimen>
|
||||||
<dimen name="fab_compat_margin">0dp</dimen>
|
<dimen name="fab_compat_margin">16dp</dimen>
|
||||||
|
<dimen name="fab_margin">8dp</dimen>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
<!-- git commits -->
|
<!-- git commits -->
|
||||||
<string name="git_commit_add_text">Add password for %1$s using android password store.</string>
|
<string name="git_commit_add_text">Add password for %1$s using android password store.</string>
|
||||||
<string name="git_commit_edit_text">"Edit %1$s using android password store."</string>
|
<string name="git_commit_edit_text">"Edit %1$s using android password store."</string>
|
||||||
|
<string name="git_commit_folder_text">"Folder %1$s created using android password store."</string>
|
||||||
<string name="git_commit_remove_text">"Remove %1$s from store."</string>
|
<string name="git_commit_remove_text">"Remove %1$s from store."</string>
|
||||||
<string name="git_commit_move_text">"Rename %1$s to %2$s."</string>
|
<string name="git_commit_move_text">"Rename %1$s to %2$s."</string>
|
||||||
<string name="git_commit_increment_text">"Increment HOTP counter for %1$s."</string>
|
<string name="git_commit_increment_text">"Increment HOTP counter for %1$s."</string>
|
||||||
|
@ -278,4 +279,6 @@
|
||||||
<string name="error_generate_ssh_key">Error while trying to generate the ssh-key</string>
|
<string name="error_generate_ssh_key">Error while trying to generate the ssh-key</string>
|
||||||
<string name="pref_show_hidden_title">Show hidden folders</string>
|
<string name="pref_show_hidden_title">Show hidden folders</string>
|
||||||
<string name="pref_show_hidden_summary">Include hidden directories in the password list</string>
|
<string name="pref_show_hidden_summary">Include hidden directories in the password list</string>
|
||||||
|
<string name="title_create_folder">Create folder</string>
|
||||||
|
<string name="button_create">Create</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
<resources>
|
||||||
|
|
||||||
<!-- Base application theme. -->
|
<!-- Base application theme. -->
|
||||||
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
|
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
|
||||||
|
@ -7,20 +7,15 @@
|
||||||
<item name="colorPrimaryDark">@color/primary_color</item>
|
<item name="colorPrimaryDark">@color/primary_color</item>
|
||||||
<item name="colorPrimaryVariant">@color/primary_light_color</item>
|
<item name="colorPrimaryVariant">@color/primary_light_color</item>
|
||||||
<item name="colorSecondary">@color/secondary_color</item>
|
<item name="colorSecondary">@color/secondary_color</item>
|
||||||
<item name="colorOnSecondary">@android:color/white</item>
|
<item name="colorOnSecondary">@color/white</item>
|
||||||
<item name="colorSurface">@color/color_surface</item>
|
<item name="colorSurface">@color/window_background</item>
|
||||||
|
<item name="android:textColor">@color/primary_text_color</item>
|
||||||
<item name="colorOnSurface">@color/color_control_normal</item>
|
<item name="colorOnSurface">@color/color_control_normal</item>
|
||||||
<item name="colorControlNormal">@color/color_control_normal</item>
|
<item name="colorControlNormal">@color/color_control_normal</item>
|
||||||
<item name="passwordIconColor">@color/password_icon_color</item>
|
<item name="android:colorBackgroundFloating">@color/primary_color</item>
|
||||||
<item name="android:colorBackground">@color/window_background</item>
|
<item name="android:statusBarColor">@color/status_bar_color</item>
|
||||||
<item name="colorBackgroundFloating">@color/primary_dark_color</item>
|
<item name="android:windowLightStatusBar">@bool/light_status_bar</item>
|
||||||
<item name="android:windowBackground">@color/window_background</item>
|
<item name="android:windowBackground">@color/window_background</item>
|
||||||
<item name="android:textColorPrimary">@color/primary_text_color</item>
|
|
||||||
<item name="android:textColor">@color/primary_text_color</item>
|
|
||||||
<item name="android:statusBarColor">@color/primary_dark_color</item>
|
|
||||||
<item name="android:navigationBarColor">@android:color/black</item>
|
|
||||||
<item name="android:windowLightStatusBar" tools:targetApi="m">@bool/light_status_bar</item>
|
|
||||||
<item name="android:windowLightNavigationBar" tools:targetApi="o_mr1">@bool/light_navigation_bar</item>
|
|
||||||
<item name="actionModeStyle">@style/ActionMode</item>
|
<item name="actionModeStyle">@style/ActionMode</item>
|
||||||
<item name="alertDialogTheme">@style/AppTheme.Dialog</item>
|
<item name="alertDialogTheme">@style/AppTheme.Dialog</item>
|
||||||
<item name="materialAlertDialogTheme">@style/AppTheme.Dialog</item>
|
<item name="materialAlertDialogTheme">@style/AppTheme.Dialog</item>
|
||||||
|
@ -38,9 +33,7 @@
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="TextInputLayoutBase" parent="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense">
|
<style name="TextInputLayoutBase" parent="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense">
|
||||||
<item name="boxBackgroundColor">?android:attr/windowBackground</item>
|
|
||||||
<item name="boxStrokeColor">?attr/colorSecondary</item>
|
<item name="boxStrokeColor">?attr/colorSecondary</item>
|
||||||
<item name="hintTextColor">?attr/colorOnPrimary</item>
|
<item name="hintTextColor">?attr/colorOnPrimary</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in a new issue