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

Commit 4ba3b75

Browse files
Update on-boarding UI (#1099)
* Add onboarding flow from v2 Signed-off-by: Aditya Wasan <[email protected]> * Minor fixes Signed-off-by: Aditya Wasan <[email protected]> * Add changelog entry Signed-off-by: Aditya Wasan <[email protected]> * Remove old activity from manifest Signed-off-by: Aditya Wasan <[email protected]> * Remove view type prefix from view ids Signed-off-by: Aditya Wasan <[email protected]> * Review fixes Signed-off-by: Aditya Wasan <[email protected]> * Treewide: Reformat code Signed-off-by: Aditya Wasan <[email protected]> * Moar review fixes Signed-off-by: Aditya Wasan <[email protected]> * Revert "Treewide: Reformat code" This reverts commit 348ef00. Signed-off-by: Harsh Shandilya <[email protected]> * onboarding: cleanup OnboardingActivity init Signed-off-by: Harsh Shandilya <[email protected]> * Remove unused layout Signed-off-by: Harsh Shandilya <[email protected]> * Remove unnecessary ConstraintLayout Signed-off-by: Harsh Shandilya <[email protected]> * Shorten animation duration Signed-off-by: Harsh Shandilya <[email protected]> * onboarding: use viewBinding extension in fragments Signed-off-by: Harsh Shandilya <[email protected]> Co-authored-by: Harsh Shandilya <[email protected]>
1 parent a34f749 commit 4ba3b75

18 files changed

+517
-142
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ All notable changes to this project will be documented in this file.
1919
- 'Show hidden folders' is now 'Show hidden files and folders'
2020
- Generated SSH keys are now stored in the Android Keystore if available, and encrypted at rest otherwise
2121
- Allow using device's screen lock credentials to secure generated SSH key
22+
- Update onboarding UI
2223

2324
### Fixed
2425

app/src/main/AndroidManifest.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
android:label="@string/app_name" />
3434

3535
<activity
36-
android:name=".OnboardingActivity"
36+
android:name=".ui.onboarding.activity.OnboardingActivity"
3737
android:configChanges="orientation|screenSize" />
3838

3939
<activity

app/src/main/java/com/zeapo/pwdstore/PasswordStore.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ import com.zeapo.pwdstore.git.BaseGitActivity
5252
import com.zeapo.pwdstore.git.config.AuthMode
5353
import com.zeapo.pwdstore.git.config.GitSettings
5454
import com.zeapo.pwdstore.ui.dialogs.FolderCreationDialogFragment
55+
import com.zeapo.pwdstore.ui.onboarding.activity.OnboardingActivity
5556
import com.zeapo.pwdstore.utils.PasswordItem
5657
import com.zeapo.pwdstore.utils.PasswordRepository
5758
import com.zeapo.pwdstore.utils.PasswordRepository.Companion.getRepository
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright © 2019-2020 The Android Password Store Authors. All Rights Reserved.
3+
* SPDX-License-Identifier: GPL-3.0-only
4+
*/
5+
6+
package com.zeapo.pwdstore.ui.onboarding.activity
7+
8+
import android.os.Bundle
9+
import androidx.appcompat.app.AppCompatActivity
10+
import com.zeapo.pwdstore.R
11+
12+
class OnboardingActivity : AppCompatActivity(R.layout.activity_onboarding) {
13+
14+
override fun onCreate(savedInstanceState: Bundle?) {
15+
super.onCreate(savedInstanceState)
16+
supportActionBar?.hide()
17+
}
18+
19+
override fun onBackPressed() {
20+
if (supportFragmentManager.backStackEntryCount == 0) {
21+
finishAffinity()
22+
} else {
23+
super.onBackPressed()
24+
}
25+
}
26+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright © 2019-2020 The Android Password Store Authors. All Rights Reserved.
3+
* SPDX-License-Identifier: GPL-3.0-only
4+
*
5+
*/
6+
7+
package com.zeapo.pwdstore.ui.onboarding.fragments
8+
9+
import android.os.Bundle
10+
import android.view.View
11+
import androidx.activity.result.contract.ActivityResultContracts
12+
import androidx.appcompat.app.AppCompatActivity
13+
import androidx.core.content.edit
14+
import androidx.fragment.app.Fragment
15+
import com.zeapo.pwdstore.R
16+
import com.zeapo.pwdstore.databinding.FragmentCloneBinding
17+
import com.zeapo.pwdstore.git.GitServerConfigActivity
18+
import com.zeapo.pwdstore.utils.PreferenceKeys
19+
import com.zeapo.pwdstore.utils.finish
20+
import com.zeapo.pwdstore.utils.performTransactionWithBackStack
21+
import com.zeapo.pwdstore.utils.sharedPrefs
22+
import com.zeapo.pwdstore.utils.viewBinding
23+
24+
class CloneFragment : Fragment(R.layout.fragment_clone) {
25+
26+
private val binding by viewBinding(FragmentCloneBinding::bind)
27+
28+
private val settings by lazy { requireActivity().applicationContext.sharedPrefs }
29+
30+
private val cloneAction = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
31+
if (result.resultCode == AppCompatActivity.RESULT_OK) {
32+
settings.edit { putBoolean(PreferenceKeys.REPOSITORY_INITIALIZED, true) }
33+
finish()
34+
}
35+
}
36+
37+
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
38+
super.onViewCreated(view, savedInstanceState)
39+
binding.cloneRemote.setOnClickListener {
40+
cloneToHiddenDir()
41+
}
42+
binding.createLocal.setOnClickListener {
43+
parentFragmentManager.performTransactionWithBackStack(RepoLocationFragment.newInstance())
44+
}
45+
}
46+
47+
/**
48+
* Clones a remote Git repository to the app's private directory
49+
*/
50+
private fun cloneToHiddenDir() {
51+
settings.edit { putBoolean(PreferenceKeys.GIT_EXTERNAL, false) }
52+
cloneAction.launch(GitServerConfigActivity.createCloneIntent(requireContext()))
53+
}
54+
55+
companion object {
56+
57+
fun newInstance(): CloneFragment = CloneFragment()
58+
}
59+
}

app/src/main/java/com/zeapo/pwdstore/OnboardingActivity.kt renamed to app/src/main/java/com/zeapo/pwdstore/ui/onboarding/fragments/RepoLocationFragment.kt

Lines changed: 54 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,51 @@
11
/*
22
* Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
33
* SPDX-License-Identifier: GPL-3.0-only
4+
*
45
*/
56

6-
package com.zeapo.pwdstore
7+
package com.zeapo.pwdstore.ui.onboarding.fragments
78

89
import android.Manifest
9-
import android.content.Intent
1010
import android.os.Bundle
11-
import androidx.activity.result.contract.ActivityResultContracts.RequestPermission
12-
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
11+
import android.view.View
12+
import androidx.activity.result.contract.ActivityResultContracts
1313
import androidx.appcompat.app.AppCompatActivity
1414
import androidx.core.content.edit
15+
import androidx.fragment.app.Fragment
1516
import com.github.ajalt.timberkt.d
1617
import com.github.michaelbull.result.onFailure
1718
import com.github.michaelbull.result.runCatching
1819
import com.google.android.material.dialog.MaterialAlertDialogBuilder
19-
import com.zeapo.pwdstore.databinding.ActivityOnboardingBinding
20-
import com.zeapo.pwdstore.git.GitServerConfigActivity
20+
import com.zeapo.pwdstore.R
21+
import com.zeapo.pwdstore.UserPreference
22+
import com.zeapo.pwdstore.databinding.FragmentRepoLocationBinding
2123
import com.zeapo.pwdstore.utils.PasswordRepository
2224
import com.zeapo.pwdstore.utils.PreferenceKeys
23-
import com.zeapo.pwdstore.utils.isPermissionGranted
25+
import com.zeapo.pwdstore.utils.finish
2426
import com.zeapo.pwdstore.utils.getString
27+
import com.zeapo.pwdstore.utils.isPermissionGranted
2528
import com.zeapo.pwdstore.utils.listFilesRecursively
2629
import com.zeapo.pwdstore.utils.sharedPrefs
2730
import com.zeapo.pwdstore.utils.viewBinding
2831
import java.io.File
2932

30-
class OnboardingActivity : AppCompatActivity() {
33+
class RepoLocationFragment : Fragment(R.layout.fragment_repo_location) {
3134

32-
private val binding by viewBinding(ActivityOnboardingBinding::inflate)
33-
private val settings by lazy { applicationContext.sharedPrefs }
35+
private val firstRunActivity by lazy { requireActivity() }
36+
private val settings by lazy { firstRunActivity.applicationContext.sharedPrefs }
37+
private val binding by viewBinding(FragmentRepoLocationBinding::bind)
3438
private val sortOrder: PasswordRepository.PasswordSortOrder
3539
get() = PasswordRepository.PasswordSortOrder.getSortOrder(settings)
3640

37-
private val cloneAction = registerForActivityResult(StartActivityForResult()) { result ->
38-
if (result.resultCode == RESULT_OK) {
39-
settings.edit { putBoolean(PreferenceKeys.REPOSITORY_INITIALIZED, true) }
40-
finish()
41-
}
42-
}
43-
44-
private val repositoryInitAction = registerForActivityResult(StartActivityForResult()) { result ->
45-
if (result.resultCode == RESULT_OK) {
41+
private val repositoryInitAction = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
42+
if (result.resultCode == AppCompatActivity.RESULT_OK) {
4643
initializeRepositoryInfo()
47-
finish()
4844
}
4945
}
5046

51-
private val externalDirectorySelectAction = registerForActivityResult(StartActivityForResult()) { result ->
52-
if (result.resultCode == RESULT_OK) {
47+
private val externalDirectorySelectAction = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
48+
if (result.resultCode == AppCompatActivity.RESULT_OK) {
5349
if (checkExternalDirectory()) {
5450
finish()
5551
} else {
@@ -58,40 +54,27 @@ class OnboardingActivity : AppCompatActivity() {
5854
}
5955
}
6056

61-
override fun onCreate(savedInstanceState: Bundle?) {
62-
super.onCreate(savedInstanceState)
63-
supportActionBar?.hide()
64-
setContentView(binding.root)
65-
binding.settingsButton.setOnClickListener {
66-
startActivity(Intent(this, UserPreference::class.java))
67-
}
68-
binding.localDirectoryButton.setOnClickListener {
69-
MaterialAlertDialogBuilder(this)
70-
.setTitle(resources.getString(R.string.location_dialog_title))
71-
.setMessage(resources.getString(R.string.location_dialog_create_text))
72-
.setPositiveButton(resources.getString(R.string.location_hidden)) { _, _ ->
73-
createRepoInHiddenDir()
74-
}
75-
.setNegativeButton(resources.getString(R.string.location_sdcard)) { _, _ ->
76-
createRepoFromExternalDir()
77-
}
78-
.show()
79-
}
80-
binding.cloneFromServerButton.setOnClickListener {
81-
cloneToHiddenDir()
82-
}
57+
private val externalDirPermGrantedAction = createPermGrantedAction {
58+
externalDirectorySelectAction.launch(UserPreference.createDirectorySelectionIntent(requireContext()))
8359
}
8460

85-
override fun onBackPressed() {
86-
finishAffinity()
61+
private val repositoryUsePermGrantedAction = createPermGrantedAction {
62+
initializeRepositoryInfo()
8763
}
8864

89-
/**
90-
* Clones a remote Git repository to the app's private directory
91-
*/
92-
private fun cloneToHiddenDir() {
93-
settings.edit { putBoolean(PreferenceKeys.GIT_EXTERNAL, false) }
94-
cloneAction.launch(GitServerConfigActivity.createCloneIntent(this))
65+
private val repositoryChangePermGrantedAction = createPermGrantedAction {
66+
repositoryInitAction.launch(UserPreference.createDirectorySelectionIntent(requireContext()))
67+
}
68+
69+
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
70+
super.onViewCreated(view, savedInstanceState)
71+
binding.hidden.setOnClickListener {
72+
createRepoInHiddenDir()
73+
}
74+
75+
binding.sdcard.setOnClickListener {
76+
createRepoFromExternalDir()
77+
}
9578
}
9679

9780
/**
@@ -103,7 +86,6 @@ class OnboardingActivity : AppCompatActivity() {
10386
remove(PreferenceKeys.GIT_EXTERNAL_REPO)
10487
}
10588
initializeRepositoryInfo()
106-
finish()
10789
}
10890

10991
/**
@@ -114,40 +96,28 @@ class OnboardingActivity : AppCompatActivity() {
11496
val externalRepo = settings.getString(PreferenceKeys.GIT_EXTERNAL_REPO)
11597
if (externalRepo == null) {
11698
if (!isPermissionGranted(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
117-
registerForActivityResult(RequestPermission()) { granted ->
118-
if (granted) {
119-
externalDirectorySelectAction.launch(UserPreference.createDirectorySelectionIntent(this))
120-
}
121-
}.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
99+
externalDirPermGrantedAction.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
122100
} else {
123101
// Unlikely we have storage permissions without user ever selecting a directory,
124102
// but let's not assume.
125-
externalDirectorySelectAction.launch(UserPreference.createDirectorySelectionIntent(this))
103+
externalDirectorySelectAction.launch(UserPreference.createDirectorySelectionIntent(requireContext()))
126104
}
127105
} else {
128-
MaterialAlertDialogBuilder(this)
106+
MaterialAlertDialogBuilder(requireActivity())
129107
.setTitle(resources.getString(R.string.directory_selected_title))
130108
.setMessage(resources.getString(R.string.directory_selected_message, externalRepo))
131109
.setPositiveButton(resources.getString(R.string.use)) { _, _ ->
132110
if (!isPermissionGranted(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
133-
registerForActivityResult(RequestPermission()) { granted ->
134-
if (granted) {
135-
initializeRepositoryInfo()
136-
}
137-
}.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
111+
repositoryUsePermGrantedAction.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
138112
} else {
139113
initializeRepositoryInfo()
140114
}
141115
}
142116
.setNegativeButton(resources.getString(R.string.change)) { _, _ ->
143117
if (!isPermissionGranted(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
144-
registerForActivityResult(RequestPermission()) { granted ->
145-
if (granted) {
146-
repositoryInitAction.launch(UserPreference.createDirectorySelectionIntent(this))
147-
}
148-
}.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
118+
repositoryChangePermGrantedAction.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
149119
} else {
150-
repositoryInitAction.launch(UserPreference.createDirectorySelectionIntent(this))
120+
repositoryInitAction.launch(UserPreference.createDirectorySelectionIntent(requireContext()))
151121
}
152122
}
153123
.show()
@@ -192,6 +162,7 @@ class OnboardingActivity : AppCompatActivity() {
192162
d { "Failed to delete local repository: $localDir" }
193163
}
194164
}
165+
finish()
195166
}
196167

197168
private fun initializeRepositoryInfo() {
@@ -205,4 +176,16 @@ class OnboardingActivity : AppCompatActivity() {
205176
}
206177
createRepository()
207178
}
179+
180+
private fun createPermGrantedAction(block: () -> Unit) =
181+
registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
182+
if (granted) {
183+
block.invoke()
184+
}
185+
}
186+
187+
companion object {
188+
189+
fun newInstance(): RepoLocationFragment = RepoLocationFragment()
190+
}
208191
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Copyright © 2019-2020 The Android Password Store Authors. All Rights Reserved.
3+
* SPDX-License-Identifier: GPL-3.0-only
4+
*/
5+
6+
package com.zeapo.pwdstore.ui.onboarding.fragments
7+
8+
import android.os.Bundle
9+
import android.view.View
10+
import androidx.fragment.app.Fragment
11+
import com.zeapo.pwdstore.R
12+
import com.zeapo.pwdstore.databinding.FragmentWelcomeBinding
13+
import com.zeapo.pwdstore.utils.performTransactionWithBackStack
14+
import com.zeapo.pwdstore.utils.viewBinding
15+
16+
@Suppress("unused")
17+
class WelcomeFragment : Fragment(R.layout.fragment_welcome) {
18+
19+
private val binding by viewBinding(FragmentWelcomeBinding::bind)
20+
21+
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
22+
super.onViewCreated(view, savedInstanceState)
23+
binding.letsGo.setOnClickListener { parentFragmentManager.performTransactionWithBackStack(CloneFragment.newInstance()) }
24+
}
25+
}

app/src/main/java/com/zeapo/pwdstore/utils/Extensions.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ fun String.base64(): String {
5656
return Base64.encodeToString(encodeToByteArray(), Base64.NO_WRAP)
5757
}
5858

59-
val Context.clipboard get() = getSystemService<ClipboardManager>()
59+
val Context.clipboard
60+
get() = getSystemService<ClipboardManager>()
6061

6162
fun FragmentActivity.snackbar(
6263
view: View = findViewById(android.R.id.content),

0 commit comments

Comments
 (0)