Add key selection step to onboarding flow
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
This commit is contained in:
parent
944efee00e
commit
14b51d5808
4 changed files with 156 additions and 9 deletions
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2014-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.content.Intent
|
||||||
|
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 androidx.lifecycle.lifecycleScope
|
||||||
|
import com.zeapo.pwdstore.R
|
||||||
|
import com.zeapo.pwdstore.crypto.GetKeyIdsActivity
|
||||||
|
import com.zeapo.pwdstore.databinding.FragmentKeySelectionBinding
|
||||||
|
import com.zeapo.pwdstore.utils.PasswordRepository
|
||||||
|
import com.zeapo.pwdstore.utils.PreferenceKeys
|
||||||
|
import com.zeapo.pwdstore.utils.commitChange
|
||||||
|
import com.zeapo.pwdstore.utils.finish
|
||||||
|
import com.zeapo.pwdstore.utils.sharedPrefs
|
||||||
|
import com.zeapo.pwdstore.utils.viewBinding
|
||||||
|
import java.io.File
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import me.msfjarvis.openpgpktx.util.OpenPgpApi
|
||||||
|
|
||||||
|
class KeySelectionFragment : Fragment(R.layout.fragment_key_selection) {
|
||||||
|
|
||||||
|
private val settings by lazy { requireActivity().applicationContext.sharedPrefs }
|
||||||
|
private val binding by viewBinding(FragmentKeySelectionBinding::bind)
|
||||||
|
|
||||||
|
private val gpgKeySelectAction = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||||
|
if (result.resultCode == AppCompatActivity.RESULT_OK) {
|
||||||
|
result.data?.getStringArrayExtra(OpenPgpApi.EXTRA_KEY_IDS)?.let { keyIds ->
|
||||||
|
lifecycleScope.launch {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
val gpgIdentifierFile = File(PasswordRepository.getRepositoryDirectory(), ".gpg-id")
|
||||||
|
gpgIdentifierFile.writeText(keyIds.joinToString("\n"))
|
||||||
|
}
|
||||||
|
settings.edit { putBoolean(PreferenceKeys.REPOSITORY_INITIALIZED, true) }
|
||||||
|
requireActivity().commitChange(getString(
|
||||||
|
R.string.git_commit_gpg_id,
|
||||||
|
getString(R.string.app_name)
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw IllegalStateException("Failed to initialize repository state.")
|
||||||
|
}
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
binding.selectKey.setOnClickListener { gpgKeySelectAction.launch(Intent(requireContext(), GetKeyIdsActivity::class.java)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
fun newInstance() = KeySelectionFragment()
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,6 +14,7 @@ import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import com.github.ajalt.timberkt.d
|
import com.github.ajalt.timberkt.d
|
||||||
|
import com.github.ajalt.timberkt.e
|
||||||
import com.github.michaelbull.result.onFailure
|
import com.github.michaelbull.result.onFailure
|
||||||
import com.github.michaelbull.result.runCatching
|
import com.github.michaelbull.result.runCatching
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
@ -26,14 +27,14 @@ import com.zeapo.pwdstore.utils.finish
|
||||||
import com.zeapo.pwdstore.utils.getString
|
import com.zeapo.pwdstore.utils.getString
|
||||||
import com.zeapo.pwdstore.utils.isPermissionGranted
|
import com.zeapo.pwdstore.utils.isPermissionGranted
|
||||||
import com.zeapo.pwdstore.utils.listFilesRecursively
|
import com.zeapo.pwdstore.utils.listFilesRecursively
|
||||||
|
import com.zeapo.pwdstore.utils.performTransactionWithBackStack
|
||||||
import com.zeapo.pwdstore.utils.sharedPrefs
|
import com.zeapo.pwdstore.utils.sharedPrefs
|
||||||
import com.zeapo.pwdstore.utils.viewBinding
|
import com.zeapo.pwdstore.utils.viewBinding
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class RepoLocationFragment : Fragment(R.layout.fragment_repo_location) {
|
class RepoLocationFragment : Fragment(R.layout.fragment_repo_location) {
|
||||||
|
|
||||||
private val firstRunActivity by lazy { requireActivity() }
|
private val settings by lazy { requireActivity().applicationContext.sharedPrefs }
|
||||||
private val settings by lazy { firstRunActivity.applicationContext.sharedPrefs }
|
|
||||||
private val binding by viewBinding(FragmentRepoLocationBinding::bind)
|
private val binding by viewBinding(FragmentRepoLocationBinding::bind)
|
||||||
private val sortOrder: PasswordRepository.PasswordSortOrder
|
private val sortOrder: PasswordRepository.PasswordSortOrder
|
||||||
get() = PasswordRepository.PasswordSortOrder.getSortOrder(settings)
|
get() = PasswordRepository.PasswordSortOrder.getSortOrder(settings)
|
||||||
|
@ -151,18 +152,14 @@ class RepoLocationFragment : Fragment(R.layout.fragment_repo_location) {
|
||||||
if (!PasswordRepository.isInitialized) {
|
if (!PasswordRepository.isInitialized) {
|
||||||
PasswordRepository.initialize()
|
PasswordRepository.initialize()
|
||||||
}
|
}
|
||||||
if (File(localDir.absolutePath + "/.gpg-id").createNewFile()) {
|
parentFragmentManager.performTransactionWithBackStack(KeySelectionFragment.newInstance())
|
||||||
settings.edit { putBoolean(PreferenceKeys.REPOSITORY_INITIALIZED, true) }
|
|
||||||
} else {
|
|
||||||
throw IllegalStateException("Failed to initialize repository state.")
|
|
||||||
}
|
|
||||||
}.onFailure { e ->
|
}.onFailure { e ->
|
||||||
e.printStackTrace()
|
e(e)
|
||||||
if (!localDir.delete()) {
|
if (!localDir.delete()) {
|
||||||
d { "Failed to delete local repository: $localDir" }
|
d { "Failed to delete local repository: $localDir" }
|
||||||
}
|
}
|
||||||
|
finish()
|
||||||
}
|
}
|
||||||
finish()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initializeRepositoryInfo() {
|
private fun initializeRepositoryInfo() {
|
||||||
|
|
81
app/src/main/res/layout/fragment_key_selection.xml
Normal file
81
app/src/main/res/layout/fragment_key_selection.xml
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?><!--
|
||||||
|
~ 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"
|
||||||
|
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/gpg_key"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="48dp"
|
||||||
|
android:text="@string/select_gpg_key_title"
|
||||||
|
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/gpg_key_text"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="48dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:text="@string/select_gpg_key_message"
|
||||||
|
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/gpg_key"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/gpg_key" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/select_key"
|
||||||
|
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/gpg_key_select"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/gpg_key_text" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -400,6 +400,9 @@
|
||||||
<string name="select_repo_type_text">Select if you want to create a local repo or clone a remote repo.</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="clone_remote_repo">Clone Remote Repo</string>
|
||||||
<string name="create_local_repo">Create Local Repo</string>
|
<string name="create_local_repo">Create Local Repo</string>
|
||||||
|
<string name="select_gpg_key_title">Select\nGPG\nKey</string>
|
||||||
|
<string name="select_gpg_key_message">Select a GPG key to initialize your store with</string>
|
||||||
|
<string name="gpg_key_select">Select key</string>
|
||||||
|
|
||||||
<!-- SSH port validation -->
|
<!-- SSH port validation -->
|
||||||
<string name="ssh_scheme_needed_title">Potentially incorrect URL</string>
|
<string name="ssh_scheme_needed_title">Potentially incorrect URL</string>
|
||||||
|
|
Loading…
Reference in a new issue