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.fragment.app.Fragment
|
||||
import com.github.ajalt.timberkt.d
|
||||
import com.github.ajalt.timberkt.e
|
||||
import com.github.michaelbull.result.onFailure
|
||||
import com.github.michaelbull.result.runCatching
|
||||
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.isPermissionGranted
|
||||
import com.zeapo.pwdstore.utils.listFilesRecursively
|
||||
import com.zeapo.pwdstore.utils.performTransactionWithBackStack
|
||||
import com.zeapo.pwdstore.utils.sharedPrefs
|
||||
import com.zeapo.pwdstore.utils.viewBinding
|
||||
import java.io.File
|
||||
|
||||
class RepoLocationFragment : Fragment(R.layout.fragment_repo_location) {
|
||||
|
||||
private val firstRunActivity by lazy { requireActivity() }
|
||||
private val settings by lazy { firstRunActivity.applicationContext.sharedPrefs }
|
||||
private val settings by lazy { requireActivity().applicationContext.sharedPrefs }
|
||||
private val binding by viewBinding(FragmentRepoLocationBinding::bind)
|
||||
private val sortOrder: PasswordRepository.PasswordSortOrder
|
||||
get() = PasswordRepository.PasswordSortOrder.getSortOrder(settings)
|
||||
|
@ -151,18 +152,14 @@ class RepoLocationFragment : Fragment(R.layout.fragment_repo_location) {
|
|||
if (!PasswordRepository.isInitialized) {
|
||||
PasswordRepository.initialize()
|
||||
}
|
||||
if (File(localDir.absolutePath + "/.gpg-id").createNewFile()) {
|
||||
settings.edit { putBoolean(PreferenceKeys.REPOSITORY_INITIALIZED, true) }
|
||||
} else {
|
||||
throw IllegalStateException("Failed to initialize repository state.")
|
||||
}
|
||||
parentFragmentManager.performTransactionWithBackStack(KeySelectionFragment.newInstance())
|
||||
}.onFailure { e ->
|
||||
e.printStackTrace()
|
||||
e(e)
|
||||
if (!localDir.delete()) {
|
||||
d { "Failed to delete local repository: $localDir" }
|
||||
}
|
||||
finish()
|
||||
}
|
||||
finish()
|
||||
}
|
||||
|
||||
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="clone_remote_repo">Clone Remote 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 -->
|
||||
<string name="ssh_scheme_needed_title">Potentially incorrect URL</string>
|
||||
|
|
Loading…
Reference in a new issue