Update on-boarding UI (#1099)
* Add onboarding flow from v2 Signed-off-by: Aditya Wasan <adityawasan55@gmail.com> * Minor fixes Signed-off-by: Aditya Wasan <adityawasan55@gmail.com> * Add changelog entry Signed-off-by: Aditya Wasan <adityawasan55@gmail.com> * Remove old activity from manifest Signed-off-by: Aditya Wasan <adityawasan55@gmail.com> * Remove view type prefix from view ids Signed-off-by: Aditya Wasan <adityawasan55@gmail.com> * Review fixes Signed-off-by: Aditya Wasan <adityawasan55@gmail.com> * Treewide: Reformat code Signed-off-by: Aditya Wasan <adityawasan55@gmail.com> * Moar review fixes Signed-off-by: Aditya Wasan <adityawasan55@gmail.com> * Revert "Treewide: Reformat code" This reverts commit 348ef0050942526a55890b245afec8d7fee4d81e. Signed-off-by: Harsh Shandilya <me@msfjarvis.dev> * onboarding: cleanup OnboardingActivity init Signed-off-by: Harsh Shandilya <me@msfjarvis.dev> * Remove unused layout Signed-off-by: Harsh Shandilya <me@msfjarvis.dev> * Remove unnecessary ConstraintLayout Signed-off-by: Harsh Shandilya <me@msfjarvis.dev> * Shorten animation duration Signed-off-by: Harsh Shandilya <me@msfjarvis.dev> * onboarding: use viewBinding extension in fragments Signed-off-by: Harsh Shandilya <me@msfjarvis.dev> Co-authored-by: Harsh Shandilya <me@msfjarvis.dev>
This commit is contained in:
parent
a34f749e9a
commit
4ba3b75f85
18 changed files with 517 additions and 142 deletions
|
@ -19,6 +19,7 @@ All notable changes to this project will be documented in this file.
|
|||
- 'Show hidden folders' is now 'Show hidden files and folders'
|
||||
- Generated SSH keys are now stored in the Android Keystore if available, and encrypted at rest otherwise
|
||||
- Allow using device's screen lock credentials to secure generated SSH key
|
||||
- Update onboarding UI
|
||||
|
||||
### Fixed
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
android:label="@string/app_name" />
|
||||
|
||||
<activity
|
||||
android:name=".OnboardingActivity"
|
||||
android:name=".ui.onboarding.activity.OnboardingActivity"
|
||||
android:configChanges="orientation|screenSize" />
|
||||
|
||||
<activity
|
||||
|
|
|
@ -52,6 +52,7 @@ import com.zeapo.pwdstore.git.BaseGitActivity
|
|||
import com.zeapo.pwdstore.git.config.AuthMode
|
||||
import com.zeapo.pwdstore.git.config.GitSettings
|
||||
import com.zeapo.pwdstore.ui.dialogs.FolderCreationDialogFragment
|
||||
import com.zeapo.pwdstore.ui.onboarding.activity.OnboardingActivity
|
||||
import com.zeapo.pwdstore.utils.PasswordItem
|
||||
import com.zeapo.pwdstore.utils.PasswordRepository
|
||||
import com.zeapo.pwdstore.utils.PasswordRepository.Companion.getRepository
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright © 2019-2020 The Android Password Store Authors. All Rights Reserved.
|
||||
* SPDX-License-Identifier: GPL-3.0-only
|
||||
*/
|
||||
|
||||
package com.zeapo.pwdstore.ui.onboarding.activity
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.zeapo.pwdstore.R
|
||||
|
||||
class OnboardingActivity : AppCompatActivity(R.layout.activity_onboarding) {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
supportActionBar?.hide()
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
if (supportFragmentManager.backStackEntryCount == 0) {
|
||||
finishAffinity()
|
||||
} else {
|
||||
super.onBackPressed()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright © 2019-2020 The Android Password Store Authors. All Rights Reserved.
|
||||
* SPDX-License-Identifier: GPL-3.0-only
|
||||
*
|
||||
*/
|
||||
|
||||
package com.zeapo.pwdstore.ui.onboarding.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.edit
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.zeapo.pwdstore.R
|
||||
import com.zeapo.pwdstore.databinding.FragmentCloneBinding
|
||||
import com.zeapo.pwdstore.git.GitServerConfigActivity
|
||||
import com.zeapo.pwdstore.utils.PreferenceKeys
|
||||
import com.zeapo.pwdstore.utils.finish
|
||||
import com.zeapo.pwdstore.utils.performTransactionWithBackStack
|
||||
import com.zeapo.pwdstore.utils.sharedPrefs
|
||||
import com.zeapo.pwdstore.utils.viewBinding
|
||||
|
||||
class CloneFragment : Fragment(R.layout.fragment_clone) {
|
||||
|
||||
private val binding by viewBinding(FragmentCloneBinding::bind)
|
||||
|
||||
private val settings by lazy { requireActivity().applicationContext.sharedPrefs }
|
||||
|
||||
private val cloneAction = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||
if (result.resultCode == AppCompatActivity.RESULT_OK) {
|
||||
settings.edit { putBoolean(PreferenceKeys.REPOSITORY_INITIALIZED, true) }
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
binding.cloneRemote.setOnClickListener {
|
||||
cloneToHiddenDir()
|
||||
}
|
||||
binding.createLocal.setOnClickListener {
|
||||
parentFragmentManager.performTransactionWithBackStack(RepoLocationFragment.newInstance())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clones a remote Git repository to the app's private directory
|
||||
*/
|
||||
private fun cloneToHiddenDir() {
|
||||
settings.edit { putBoolean(PreferenceKeys.GIT_EXTERNAL, false) }
|
||||
cloneAction.launch(GitServerConfigActivity.createCloneIntent(requireContext()))
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun newInstance(): CloneFragment = CloneFragment()
|
||||
}
|
||||
}
|
|
@ -1,55 +1,51 @@
|
|||
/*
|
||||
* Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
|
||||
* SPDX-License-Identifier: GPL-3.0-only
|
||||
*
|
||||
*/
|
||||
|
||||
package com.zeapo.pwdstore
|
||||
package com.zeapo.pwdstore.ui.onboarding.fragments
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.activity.result.contract.ActivityResultContracts.RequestPermission
|
||||
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
|
||||
import android.view.View
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.edit
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.github.ajalt.timberkt.d
|
||||
import com.github.michaelbull.result.onFailure
|
||||
import com.github.michaelbull.result.runCatching
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.zeapo.pwdstore.databinding.ActivityOnboardingBinding
|
||||
import com.zeapo.pwdstore.git.GitServerConfigActivity
|
||||
import com.zeapo.pwdstore.R
|
||||
import com.zeapo.pwdstore.UserPreference
|
||||
import com.zeapo.pwdstore.databinding.FragmentRepoLocationBinding
|
||||
import com.zeapo.pwdstore.utils.PasswordRepository
|
||||
import com.zeapo.pwdstore.utils.PreferenceKeys
|
||||
import com.zeapo.pwdstore.utils.isPermissionGranted
|
||||
import com.zeapo.pwdstore.utils.finish
|
||||
import com.zeapo.pwdstore.utils.getString
|
||||
import com.zeapo.pwdstore.utils.isPermissionGranted
|
||||
import com.zeapo.pwdstore.utils.listFilesRecursively
|
||||
import com.zeapo.pwdstore.utils.sharedPrefs
|
||||
import com.zeapo.pwdstore.utils.viewBinding
|
||||
import java.io.File
|
||||
|
||||
class OnboardingActivity : AppCompatActivity() {
|
||||
class RepoLocationFragment : Fragment(R.layout.fragment_repo_location) {
|
||||
|
||||
private val binding by viewBinding(ActivityOnboardingBinding::inflate)
|
||||
private val settings by lazy { applicationContext.sharedPrefs }
|
||||
private val firstRunActivity by lazy { requireActivity() }
|
||||
private val settings by lazy { firstRunActivity.applicationContext.sharedPrefs }
|
||||
private val binding by viewBinding(FragmentRepoLocationBinding::bind)
|
||||
private val sortOrder: PasswordRepository.PasswordSortOrder
|
||||
get() = PasswordRepository.PasswordSortOrder.getSortOrder(settings)
|
||||
|
||||
private val cloneAction = registerForActivityResult(StartActivityForResult()) { result ->
|
||||
if (result.resultCode == RESULT_OK) {
|
||||
settings.edit { putBoolean(PreferenceKeys.REPOSITORY_INITIALIZED, true) }
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
private val repositoryInitAction = registerForActivityResult(StartActivityForResult()) { result ->
|
||||
if (result.resultCode == RESULT_OK) {
|
||||
private val repositoryInitAction = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||
if (result.resultCode == AppCompatActivity.RESULT_OK) {
|
||||
initializeRepositoryInfo()
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
private val externalDirectorySelectAction = registerForActivityResult(StartActivityForResult()) { result ->
|
||||
if (result.resultCode == RESULT_OK) {
|
||||
private val externalDirectorySelectAction = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||
if (result.resultCode == AppCompatActivity.RESULT_OK) {
|
||||
if (checkExternalDirectory()) {
|
||||
finish()
|
||||
} else {
|
||||
|
@ -58,40 +54,27 @@ class OnboardingActivity : AppCompatActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
supportActionBar?.hide()
|
||||
setContentView(binding.root)
|
||||
binding.settingsButton.setOnClickListener {
|
||||
startActivity(Intent(this, UserPreference::class.java))
|
||||
private val externalDirPermGrantedAction = createPermGrantedAction {
|
||||
externalDirectorySelectAction.launch(UserPreference.createDirectorySelectionIntent(requireContext()))
|
||||
}
|
||||
binding.localDirectoryButton.setOnClickListener {
|
||||
MaterialAlertDialogBuilder(this)
|
||||
.setTitle(resources.getString(R.string.location_dialog_title))
|
||||
.setMessage(resources.getString(R.string.location_dialog_create_text))
|
||||
.setPositiveButton(resources.getString(R.string.location_hidden)) { _, _ ->
|
||||
|
||||
private val repositoryUsePermGrantedAction = createPermGrantedAction {
|
||||
initializeRepositoryInfo()
|
||||
}
|
||||
|
||||
private val repositoryChangePermGrantedAction = createPermGrantedAction {
|
||||
repositoryInitAction.launch(UserPreference.createDirectorySelectionIntent(requireContext()))
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
binding.hidden.setOnClickListener {
|
||||
createRepoInHiddenDir()
|
||||
}
|
||||
.setNegativeButton(resources.getString(R.string.location_sdcard)) { _, _ ->
|
||||
|
||||
binding.sdcard.setOnClickListener {
|
||||
createRepoFromExternalDir()
|
||||
}
|
||||
.show()
|
||||
}
|
||||
binding.cloneFromServerButton.setOnClickListener {
|
||||
cloneToHiddenDir()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
finishAffinity()
|
||||
}
|
||||
|
||||
/**
|
||||
* Clones a remote Git repository to the app's private directory
|
||||
*/
|
||||
private fun cloneToHiddenDir() {
|
||||
settings.edit { putBoolean(PreferenceKeys.GIT_EXTERNAL, false) }
|
||||
cloneAction.launch(GitServerConfigActivity.createCloneIntent(this))
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -103,7 +86,6 @@ class OnboardingActivity : AppCompatActivity() {
|
|||
remove(PreferenceKeys.GIT_EXTERNAL_REPO)
|
||||
}
|
||||
initializeRepositoryInfo()
|
||||
finish()
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -114,40 +96,28 @@ class OnboardingActivity : AppCompatActivity() {
|
|||
val externalRepo = settings.getString(PreferenceKeys.GIT_EXTERNAL_REPO)
|
||||
if (externalRepo == null) {
|
||||
if (!isPermissionGranted(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
|
||||
registerForActivityResult(RequestPermission()) { granted ->
|
||||
if (granted) {
|
||||
externalDirectorySelectAction.launch(UserPreference.createDirectorySelectionIntent(this))
|
||||
}
|
||||
}.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
externalDirPermGrantedAction.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
} else {
|
||||
// Unlikely we have storage permissions without user ever selecting a directory,
|
||||
// but let's not assume.
|
||||
externalDirectorySelectAction.launch(UserPreference.createDirectorySelectionIntent(this))
|
||||
externalDirectorySelectAction.launch(UserPreference.createDirectorySelectionIntent(requireContext()))
|
||||
}
|
||||
} else {
|
||||
MaterialAlertDialogBuilder(this)
|
||||
MaterialAlertDialogBuilder(requireActivity())
|
||||
.setTitle(resources.getString(R.string.directory_selected_title))
|
||||
.setMessage(resources.getString(R.string.directory_selected_message, externalRepo))
|
||||
.setPositiveButton(resources.getString(R.string.use)) { _, _ ->
|
||||
if (!isPermissionGranted(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
|
||||
registerForActivityResult(RequestPermission()) { granted ->
|
||||
if (granted) {
|
||||
initializeRepositoryInfo()
|
||||
}
|
||||
}.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
repositoryUsePermGrantedAction.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
} else {
|
||||
initializeRepositoryInfo()
|
||||
}
|
||||
}
|
||||
.setNegativeButton(resources.getString(R.string.change)) { _, _ ->
|
||||
if (!isPermissionGranted(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
|
||||
registerForActivityResult(RequestPermission()) { granted ->
|
||||
if (granted) {
|
||||
repositoryInitAction.launch(UserPreference.createDirectorySelectionIntent(this))
|
||||
}
|
||||
}.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
repositoryChangePermGrantedAction.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
} else {
|
||||
repositoryInitAction.launch(UserPreference.createDirectorySelectionIntent(this))
|
||||
repositoryInitAction.launch(UserPreference.createDirectorySelectionIntent(requireContext()))
|
||||
}
|
||||
}
|
||||
.show()
|
||||
|
@ -192,6 +162,7 @@ class OnboardingActivity : AppCompatActivity() {
|
|||
d { "Failed to delete local repository: $localDir" }
|
||||
}
|
||||
}
|
||||
finish()
|
||||
}
|
||||
|
||||
private fun initializeRepositoryInfo() {
|
||||
|
@ -205,4 +176,16 @@ class OnboardingActivity : AppCompatActivity() {
|
|||
}
|
||||
createRepository()
|
||||
}
|
||||
|
||||
private fun createPermGrantedAction(block: () -> Unit) =
|
||||
registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
|
||||
if (granted) {
|
||||
block.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun newInstance(): RepoLocationFragment = RepoLocationFragment()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright © 2019-2020 The Android Password Store Authors. All Rights Reserved.
|
||||
* SPDX-License-Identifier: GPL-3.0-only
|
||||
*/
|
||||
|
||||
package com.zeapo.pwdstore.ui.onboarding.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.zeapo.pwdstore.R
|
||||
import com.zeapo.pwdstore.databinding.FragmentWelcomeBinding
|
||||
import com.zeapo.pwdstore.utils.performTransactionWithBackStack
|
||||
import com.zeapo.pwdstore.utils.viewBinding
|
||||
|
||||
@Suppress("unused")
|
||||
class WelcomeFragment : Fragment(R.layout.fragment_welcome) {
|
||||
|
||||
private val binding by viewBinding(FragmentWelcomeBinding::bind)
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
binding.letsGo.setOnClickListener { parentFragmentManager.performTransactionWithBackStack(CloneFragment.newInstance()) }
|
||||
}
|
||||
}
|
|
@ -56,7 +56,8 @@ fun String.base64(): String {
|
|||
return Base64.encodeToString(encodeToByteArray(), Base64.NO_WRAP)
|
||||
}
|
||||
|
||||
val Context.clipboard get() = getSystemService<ClipboardManager>()
|
||||
val Context.clipboard
|
||||
get() = getSystemService<ClipboardManager>()
|
||||
|
||||
fun FragmentActivity.snackbar(
|
||||
view: View = findViewById(android.R.id.content),
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
package com.zeapo.pwdstore.utils
|
||||
|
||||
import android.content.pm.PackageManager
|
||||
import android.view.View
|
||||
import androidx.annotation.IdRes
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.fragment.app.commit
|
||||
import com.zeapo.pwdstore.R
|
||||
|
||||
fun Fragment.isPermissionGranted(permission: String): Boolean {
|
||||
return ContextCompat.checkSelfPermission(requireActivity(), permission) == PackageManager.PERMISSION_GRANTED
|
||||
}
|
||||
|
||||
fun Fragment.finish() = requireActivity().finish()
|
||||
|
||||
fun FragmentManager.performTransaction(destinationFragment: Fragment, @IdRes containerViewId: Int = android.R.id.content) {
|
||||
this.commit {
|
||||
beginTransaction()
|
||||
setCustomAnimations(
|
||||
R.animator.slide_in_left,
|
||||
R.animator.slide_out_left,
|
||||
R.animator.slide_in_right,
|
||||
R.animator.slide_out_right)
|
||||
replace(containerViewId, destinationFragment)
|
||||
}
|
||||
}
|
||||
|
||||
fun FragmentManager.performTransactionWithBackStack(destinationFragment: Fragment, @IdRes containerViewId: Int = android.R.id.content) {
|
||||
this.commit {
|
||||
beginTransaction()
|
||||
addToBackStack(destinationFragment.tag)
|
||||
setCustomAnimations(
|
||||
R.animator.slide_in_left,
|
||||
R.animator.slide_out_left,
|
||||
R.animator.slide_in_right,
|
||||
R.animator.slide_out_right)
|
||||
replace(containerViewId, destinationFragment)
|
||||
}
|
||||
}
|
||||
|
||||
fun FragmentManager.performSharedElementTransaction(destinationFragment: Fragment, views: List<View>, @IdRes containerViewId: Int = android.R.id.content) {
|
||||
this.commit {
|
||||
beginTransaction()
|
||||
for (view in views) {
|
||||
addSharedElement(view, view.transitionName)
|
||||
}
|
||||
addToBackStack(destinationFragment.tag)
|
||||
replace(containerViewId, destinationFragment)
|
||||
}
|
||||
}
|
11
app/src/main/res/animator/slide_in_left.xml
Normal file
11
app/src/main/res/animator/slide_in_left.xml
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<objectAnimator
|
||||
android:duration="250"
|
||||
android:propertyName="x"
|
||||
android:valueFrom="1000"
|
||||
android:valueTo="0"
|
||||
android:valueType="floatType" />
|
||||
|
||||
</set>
|
11
app/src/main/res/animator/slide_in_right.xml
Normal file
11
app/src/main/res/animator/slide_in_right.xml
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<objectAnimator
|
||||
android:duration="250"
|
||||
android:propertyName="x"
|
||||
android:valueFrom="-1000"
|
||||
android:valueTo="0"
|
||||
android:valueType="floatType" />
|
||||
|
||||
</set>
|
11
app/src/main/res/animator/slide_out_left.xml
Normal file
11
app/src/main/res/animator/slide_out_left.xml
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<objectAnimator
|
||||
android:duration="250"
|
||||
android:propertyName="x"
|
||||
android:valueFrom="0"
|
||||
android:valueTo="-1000"
|
||||
android:valueType="floatType" />
|
||||
|
||||
</set>
|
11
app/src/main/res/animator/slide_out_right.xml
Normal file
11
app/src/main/res/animator/slide_out_right.xml
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<objectAnimator
|
||||
android:duration="250"
|
||||
android:propertyName="x"
|
||||
android:valueFrom="0"
|
||||
android:valueTo="1000"
|
||||
android:valueType="floatType" />
|
||||
|
||||
</set>
|
|
@ -1,73 +1,13 @@
|
|||
<!--
|
||||
~ Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
|
||||
~ SPDX-License-Identifier: GPL-3.0-only
|
||||
-->
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/colorPrimary"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/app_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:contentDescription="@string/app_icon_hint"
|
||||
android:src="@mipmap/ic_launcher"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/app_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/app_icon"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:text="@string/app_name"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:textColor="?attr/colorOnPrimary"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/app_icon" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/settings_button"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_marginEnd="@dimen/activity_horizontal_margin"
|
||||
android:text="@string/action_settings"
|
||||
android:textColor="?attr/colorOnPrimary"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/local_directory_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="48dp"
|
||||
android:text="@string/initialize"
|
||||
android:textSize="12sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/app_name" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/clone_from_server_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/clone"
|
||||
android:textSize="12sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/local_directory_button" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/fragment_first_run"
|
||||
android:name="com.zeapo.pwdstore.ui.onboarding.fragments.WelcomeFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:tag="welcome_fragment" />
|
||||
</LinearLayout>
|
||||
|
|
87
app/src/main/res/layout/fragment_clone.xml
Normal file
87
app/src/main/res/layout/fragment_clone.xml
Normal file
|
@ -0,0 +1,87 @@
|
|||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/colorPrimary"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/app_icon"
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginTop="100dp"
|
||||
android:contentDescription="@string/app_icon_hint"
|
||||
android:src="@mipmap/ic_launcher"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/app_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginStart="16dp"
|
||||
android:text="@string/app_name"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline5"
|
||||
android:textColor="@color/color_control_normal"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="@id/app_icon"
|
||||
app:layout_constraintStart_toEndOf="@id/app_icon"
|
||||
app:layout_constraintTop_toTopOf="@+id/app_icon" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/repo_type"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="48dp"
|
||||
android:text="@string/select_n_repository_type"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline4"
|
||||
android:textColor="@color/color_control_normal"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0"
|
||||
app:layout_constraintStart_toStartOf="@id/app_icon"
|
||||
app:layout_constraintTop_toBottomOf="@id/app_icon" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_repo_type_text"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="48dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:text="@string/select_repo_type_text"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
|
||||
android:textColor="@color/color_control_normal"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="@id/repo_type"
|
||||
app:layout_constraintTop_toBottomOf="@id/repo_type" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/clone_remote"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:maxWidth="300dp"
|
||||
android:minWidth="100dp"
|
||||
android:text="@string/clone_remote_repo"
|
||||
app:layout_constraintBottom_toTopOf="@id/create_local"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/create_local"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="128dp"
|
||||
android:maxWidth="300dp"
|
||||
android:minWidth="100dp"
|
||||
android:text="@string/create_local_repo"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="@id/clone_remote"
|
||||
app:layout_constraintStart_toStartOf="@id/clone_remote" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
87
app/src/main/res/layout/fragment_repo_location.xml
Normal file
87
app/src/main/res/layout/fragment_repo_location.xml
Normal file
|
@ -0,0 +1,87 @@
|
|||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/colorPrimary"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/app_icon"
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginTop="100dp"
|
||||
android:contentDescription="@string/app_icon_hint"
|
||||
android:src="@mipmap/ic_launcher"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/app_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginStart="16dp"
|
||||
android:text="@string/app_name"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline5"
|
||||
android:textColor="@color/color_control_normal"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="@id/app_icon"
|
||||
app:layout_constraintStart_toEndOf="@id/app_icon"
|
||||
app:layout_constraintTop_toTopOf="@+id/app_icon" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/repo_location"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="48dp"
|
||||
android:text="@string/repository_n_location"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline4"
|
||||
android:textColor="@color/color_control_normal"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0"
|
||||
app:layout_constraintStart_toStartOf="@id/app_icon"
|
||||
app:layout_constraintTop_toBottomOf="@id/app_icon" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/repo_location_text"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="48dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:text="@string/location_dialog_create_text"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
|
||||
android:textColor="@color/color_control_normal"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="@id/repo_location"
|
||||
app:layout_constraintTop_toBottomOf="@id/repo_location" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/hidden"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:maxWidth="300dp"
|
||||
android:minWidth="100dp"
|
||||
android:text="@string/location_hidden"
|
||||
app:layout_constraintBottom_toTopOf="@id/sdcard"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/sdcard"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="128dp"
|
||||
android:maxWidth="300dp"
|
||||
android:minWidth="100dp"
|
||||
android:text="@string/location_sdcard"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="@id/hidden"
|
||||
app:layout_constraintStart_toStartOf="@id/hidden" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
51
app/src/main/res/layout/fragment_welcome.xml
Normal file
51
app/src/main/res/layout/fragment_welcome.xml
Normal file
|
@ -0,0 +1,51 @@
|
|||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/colorPrimary"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/app_icon"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
android:contentDescription="@string/app_icon_hint"
|
||||
android:src="@mipmap/ic_launcher"
|
||||
android:transitionName="transition_first_app_icon"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/app_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/app_name"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline5"
|
||||
android:textColor="@color/color_control_normal"
|
||||
android:textStyle="bold"
|
||||
android:transitionName="transition_first_run_app_name"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/app_icon" />
|
||||
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/lets_go"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="48dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:maxWidth="300dp"
|
||||
android:minWidth="100dp"
|
||||
android:text="@string/let_s_go"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/app_name" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -77,7 +77,7 @@
|
|||
<string name="clone">Clone from server</string>
|
||||
<string name="initialize">Use local directory</string>
|
||||
<string name="location_dialog_title">Repository location</string>
|
||||
<string name="location_dialog_create_text">Select where to create your password repository</string>
|
||||
<string name="location_dialog_create_text">Select where do you want to create your password repository</string>
|
||||
<string name="location_sdcard">SD-Card</string>
|
||||
<string name="location_hidden">Hidden (Preferred)</string>
|
||||
<string name="external_repository_dialog_title">Choose where to store the passwords</string>
|
||||
|
@ -418,4 +418,22 @@
|
|||
<string name="folder_creation_err_folder_exists">A folder by that name already exists</string>
|
||||
<string name="xkpwgen_extrachars_label">Digits/Symbols (d/s)</string>
|
||||
<string name="xk_numbers_symbols_append_default">ds</string>
|
||||
|
||||
<!-- Onboarding flow -->
|
||||
<string name="repository_n_location">Repository \nLocation</string>
|
||||
<string name="select_n_openpgp_provider">Select \nOpenPGP Provider</string>
|
||||
<string name="let_s_go">Let\'s Go</string>
|
||||
<string name="select_n_repository_type">Select \nRepository Type</string>
|
||||
<string name="select_repo_type_text">Select if you want to create a local repo or clone a remote repo.</string>
|
||||
<string name="clone_remote_repo">Clone Remote Repo</string>
|
||||
<string name="create_local_repo">Create Local Repo</string>
|
||||
<string name="error_directory_uri">Error getting directory uri</string>
|
||||
<string name="select_directory_passwords">Select a directory to store passwords</string>
|
||||
<string name="select_n_store_name">Select \nStore Name</string>
|
||||
<string name="select_n_store_text">Select a name for your password store.</string>
|
||||
<string name="store_name">Store Name</string>
|
||||
<string name="select_empty_directory">Select an empty directory for password store</string>
|
||||
<string name="err_enter_store_name">Enter a store name to continue</string>
|
||||
<string name="exception_cannot_create_directory">Cannot create new directory.</string>
|
||||
|
||||
</resources>
|
||||
|
|
Loading…
Reference in a new issue