forked from hardcoresushi/DroidFS
Replace file systems dropdown with radio buttons
This commit is contained in:
parent
15f288be11
commit
85e24921fa
@ -7,13 +7,23 @@ import android.text.InputType
|
|||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.AdapterView
|
|
||||||
import android.widget.ArrayAdapter
|
import android.widget.ArrayAdapter
|
||||||
|
import android.widget.RadioButton
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.core.view.children
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import sushi.hardcore.droidfs.*
|
import sushi.hardcore.droidfs.BuildConfig
|
||||||
|
import sushi.hardcore.droidfs.Constants
|
||||||
|
import sushi.hardcore.droidfs.FingerprintProtector
|
||||||
|
import sushi.hardcore.droidfs.LoadingTask
|
||||||
|
import sushi.hardcore.droidfs.R
|
||||||
|
import sushi.hardcore.droidfs.Theme
|
||||||
|
import sushi.hardcore.droidfs.VolumeData
|
||||||
|
import sushi.hardcore.droidfs.VolumeDatabase
|
||||||
|
import sushi.hardcore.droidfs.VolumeManagerApp
|
||||||
|
import sushi.hardcore.droidfs.databinding.FileSystemRadioBinding
|
||||||
import sushi.hardcore.droidfs.databinding.FragmentCreateVolumeBinding
|
import sushi.hardcore.droidfs.databinding.FragmentCreateVolumeBinding
|
||||||
import sushi.hardcore.droidfs.filesystems.CryfsVolume
|
import sushi.hardcore.droidfs.filesystems.CryfsVolume
|
||||||
import sushi.hardcore.droidfs.filesystems.EncryptedVolume
|
import sushi.hardcore.droidfs.filesystems.EncryptedVolume
|
||||||
@ -23,9 +33,11 @@ import sushi.hardcore.droidfs.util.ObjRef
|
|||||||
import sushi.hardcore.droidfs.util.UIUtils
|
import sushi.hardcore.droidfs.util.UIUtils
|
||||||
import sushi.hardcore.droidfs.widgets.CustomAlertDialogBuilder
|
import sushi.hardcore.droidfs.widgets.CustomAlertDialogBuilder
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.*
|
import java.util.Arrays
|
||||||
|
|
||||||
class CreateVolumeFragment: Fragment() {
|
class CreateVolumeFragment: Fragment() {
|
||||||
|
internal data class FileSystemInfo(val nameResource: Int, val detailsResource: Int, val ciphersResource: Int)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val KEY_THEME_VALUE = "theme"
|
private const val KEY_THEME_VALUE = "theme"
|
||||||
private const val KEY_VOLUME_PATH = "path"
|
private const val KEY_VOLUME_PATH = "path"
|
||||||
@ -34,6 +46,17 @@ class CreateVolumeFragment: Fragment() {
|
|||||||
private const val KEY_PIN_PASSWORDS = Constants.PIN_PASSWORDS_KEY
|
private const val KEY_PIN_PASSWORDS = Constants.PIN_PASSWORDS_KEY
|
||||||
private const val KEY_USF_FINGERPRINT = "fingerprint"
|
private const val KEY_USF_FINGERPRINT = "fingerprint"
|
||||||
|
|
||||||
|
private val GOCRYPTFS_INFO = FileSystemInfo(
|
||||||
|
R.string.gocryptfs,
|
||||||
|
R.string.gocryptfs_details,
|
||||||
|
R.array.gocryptfs_encryption_ciphers,
|
||||||
|
)
|
||||||
|
private val CRYFS_INFO = FileSystemInfo(
|
||||||
|
R.string.cryfs,
|
||||||
|
R.string.cryfs_details,
|
||||||
|
R.array.cryfs_encryption_ciphers,
|
||||||
|
)
|
||||||
|
|
||||||
fun newInstance(
|
fun newInstance(
|
||||||
theme: Theme,
|
theme: Theme,
|
||||||
volumePath: String,
|
volumePath: String,
|
||||||
@ -57,7 +80,7 @@ class CreateVolumeFragment: Fragment() {
|
|||||||
|
|
||||||
private lateinit var binding: FragmentCreateVolumeBinding
|
private lateinit var binding: FragmentCreateVolumeBinding
|
||||||
private lateinit var theme: Theme
|
private lateinit var theme: Theme
|
||||||
private val volumeTypes = ArrayList<String>(2)
|
private val fileSystemInfos = ArrayList<FileSystemInfo>(2)
|
||||||
private lateinit var volumePath: String
|
private lateinit var volumePath: String
|
||||||
private var isHiddenVolume: Boolean = false
|
private var isHiddenVolume: Boolean = false
|
||||||
private var rememberVolume: Boolean = false
|
private var rememberVolume: Boolean = false
|
||||||
@ -92,17 +115,10 @@ class CreateVolumeFragment: Fragment() {
|
|||||||
binding.checkboxSavePassword.visibility = View.GONE
|
binding.checkboxSavePassword.visibility = View.GONE
|
||||||
}
|
}
|
||||||
if (!BuildConfig.GOCRYPTFS_DISABLED) {
|
if (!BuildConfig.GOCRYPTFS_DISABLED) {
|
||||||
volumeTypes.add(resources.getString(R.string.gocryptfs))
|
fileSystemInfos.add(GOCRYPTFS_INFO)
|
||||||
}
|
}
|
||||||
if (!BuildConfig.CRYFS_DISABLED) {
|
if (!BuildConfig.CRYFS_DISABLED) {
|
||||||
volumeTypes.add(resources.getString(R.string.cryfs))
|
fileSystemInfos.add(CRYFS_INFO)
|
||||||
}
|
|
||||||
binding.spinnerVolumeType.adapter = ArrayAdapter(
|
|
||||||
requireContext(),
|
|
||||||
android.R.layout.simple_spinner_item,
|
|
||||||
volumeTypes
|
|
||||||
).apply {
|
|
||||||
setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
|
|
||||||
}
|
}
|
||||||
val encryptionCipherAdapter = ArrayAdapter(
|
val encryptionCipherAdapter = ArrayAdapter(
|
||||||
requireContext(),
|
requireContext(),
|
||||||
@ -111,19 +127,29 @@ class CreateVolumeFragment: Fragment() {
|
|||||||
).apply {
|
).apply {
|
||||||
setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
|
setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
|
||||||
}
|
}
|
||||||
binding.spinnerVolumeType.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
for ((i, fs) in fileSystemInfos.iterator().withIndex()) {
|
||||||
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
|
with(FileSystemRadioBinding.inflate(layoutInflater)) {
|
||||||
val ciphersArray = if (volumeTypes[position] == resources.getString(R.string.gocryptfs)) {
|
title.text = getString(fs.nameResource)
|
||||||
R.array.gocryptfs_encryption_ciphers
|
details.text = getString(fs.detailsResource)
|
||||||
} else {
|
radio.isChecked = i == 0
|
||||||
R.array.cryfs_encryption_ciphers
|
root.setOnClickListener {
|
||||||
|
radio.performClick()
|
||||||
}
|
}
|
||||||
|
radio.setOnCheckedChangeListener { _, isChecked ->
|
||||||
|
if (isChecked) {
|
||||||
with(encryptionCipherAdapter) {
|
with(encryptionCipherAdapter) {
|
||||||
clear()
|
clear()
|
||||||
addAll(resources.getStringArray(ciphersArray).asList())
|
addAll(resources.getStringArray(fs.ciphersResource).asList())
|
||||||
|
}
|
||||||
|
binding.radioGroupFilesystems.children.forEach {
|
||||||
|
if (it != root) {
|
||||||
|
it.findViewById<RadioButton>(R.id.radio).isChecked = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
override fun onNothingSelected(parent: AdapterView<*>?) {}
|
}
|
||||||
|
}
|
||||||
|
binding.radioGroupFilesystems.addView(root)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
binding.spinnerCipher.adapter = encryptionCipherAdapter
|
binding.spinnerCipher.adapter = encryptionCipherAdapter
|
||||||
if (pinPasswords) {
|
if (pinPasswords) {
|
||||||
@ -145,6 +171,15 @@ class CreateVolumeFragment: Fragment() {
|
|||||||
(activity as AddVolumeActivity).onFragmentLoaded(false)
|
(activity as AddVolumeActivity).onFragmentLoaded(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getSelectedFileSystemIndex(): Int {
|
||||||
|
for ((i, child) in binding.radioGroupFilesystems.children.iterator().withIndex()) {
|
||||||
|
if (child.findViewById<RadioButton>(R.id.radio).isChecked) {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
private fun createVolume() {
|
private fun createVolume() {
|
||||||
val password = UIUtils.encodeEditTextContent(binding.editPassword)
|
val password = UIUtils.encodeEditTextContent(binding.editPassword)
|
||||||
val passwordConfirm = UIUtils.encodeEditTextContent(binding.editPasswordConfirm)
|
val passwordConfirm = UIUtils.encodeEditTextContent(binding.editPasswordConfirm)
|
||||||
@ -173,7 +208,7 @@ class CreateVolumeFragment: Fragment() {
|
|||||||
val volumeFile = File(volumePath)
|
val volumeFile = File(volumePath)
|
||||||
if (!volumeFile.exists())
|
if (!volumeFile.exists())
|
||||||
volumeFile.mkdirs()
|
volumeFile.mkdirs()
|
||||||
val result = if (volumeTypes[binding.spinnerVolumeType.selectedItemPosition] == resources.getString(R.string.gocryptfs)) {
|
val result = if (fileSystemInfos[getSelectedFileSystemIndex()] == GOCRYPTFS_INFO) {
|
||||||
val xchacha = when (binding.spinnerCipher.selectedItemPosition) {
|
val xchacha = when (binding.spinnerCipher.selectedItemPosition) {
|
||||||
0 -> -1 // auto
|
0 -> -1 // auto
|
||||||
1 -> 0 // AES-GCM
|
1 -> 0 // AES-GCM
|
||||||
|
39
app/src/main/res/layout/file_system_radio.xml
Normal file
39
app/src/main/res/layout/file_system_radio.xml
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:paddingVertical="@dimen/selectable_row_vertical_padding">
|
||||||
|
|
||||||
|
<RadioButton
|
||||||
|
android:id="@+id/radio"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_marginStart="30dp"
|
||||||
|
android:layout_marginEnd="10dp"/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_toEndOf="@+id/radio"
|
||||||
|
android:layout_alignParentEnd="true">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="@dimen/title_text_size"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/details"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@color/textColorSecondary"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
@ -3,25 +3,25 @@
|
|||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical">
|
||||||
android:layout_marginHorizontal="@dimen/volume_operation_horizontal_gap">
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/volume_type_label"/>
|
android:text="@string/volume_type_label"
|
||||||
|
android:layout_marginHorizontal="@dimen/volume_operation_horizontal_gap"/>
|
||||||
|
|
||||||
<Spinner
|
<RadioGroup
|
||||||
android:id="@+id/spinner_volume_type"
|
android:id="@+id/radio_group_filesystems"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_horizontal"
|
android:layout_marginVertical="10dp"/>
|
||||||
android:layout_marginVertical="@dimen/volume_operation_vertical_gap"/>
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/password_label"/>
|
android:text="@string/password_label"
|
||||||
|
android:layout_marginHorizontal="@dimen/volume_operation_horizontal_gap"/>
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
android:id="@+id/edit_password"
|
android:id="@+id/edit_password"
|
||||||
@ -30,13 +30,15 @@
|
|||||||
android:inputType="textPassword"
|
android:inputType="textPassword"
|
||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
android:autofillHints="password"
|
android:autofillHints="password"
|
||||||
android:hint="@string/password"/>
|
android:hint="@string/password"
|
||||||
|
android:layout_marginHorizontal="@dimen/volume_operation_horizontal_gap"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/password_confirmation_label"
|
android:text="@string/password_confirmation_label"
|
||||||
android:layout_marginTop="@dimen/volume_operation_vertical_gap"/>
|
android:layout_marginTop="@dimen/volume_operation_vertical_gap"
|
||||||
|
android:layout_marginHorizontal="@dimen/volume_operation_horizontal_gap"/>
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
android:id="@+id/edit_password_confirm"
|
android:id="@+id/edit_password_confirm"
|
||||||
@ -45,11 +47,13 @@
|
|||||||
android:inputType="textPassword"
|
android:inputType="textPassword"
|
||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
android:autofillHints="password"
|
android:autofillHints="password"
|
||||||
android:hint="@string/password_confirmation_hint"/>
|
android:hint="@string/password_confirmation_hint"
|
||||||
|
android:layout_marginHorizontal="@dimen/volume_operation_horizontal_gap"/>
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="@dimen/volume_operation_horizontal_gap"
|
||||||
android:layout_marginVertical="@dimen/volume_operation_vertical_gap">
|
android:layout_marginVertical="@dimen/volume_operation_vertical_gap">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:background="?attr/selectableItemBackground"
|
android:background="?attr/selectableItemBackground"
|
||||||
android:paddingHorizontal="@dimen/volume_operation_horizontal_gap"
|
android:paddingHorizontal="@dimen/volume_operation_horizontal_gap"
|
||||||
|
android:paddingVertical="@dimen/selectable_row_vertical_padding"
|
||||||
android:layout_marginBottom="@dimen/volume_operation_vertical_gap">
|
android:layout_marginBottom="@dimen/volume_operation_vertical_gap">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
|
@ -12,4 +12,5 @@
|
|||||||
<dimen name="dialog_padding_top">10dp</dimen>
|
<dimen name="dialog_padding_top">10dp</dimen>
|
||||||
<dimen name="dialog_text_size">16sp</dimen>
|
<dimen name="dialog_text_size">16sp</dimen>
|
||||||
<dimen name="title_file_name_text_size">20sp</dimen>
|
<dimen name="title_file_name_text_size">20sp</dimen>
|
||||||
|
<dimen name="selectable_row_vertical_padding">10dp</dimen>
|
||||||
</resources>
|
</resources>
|
@ -287,4 +287,6 @@
|
|||||||
<string name="usf_background_summary">Don\'t lock volumes when the app goes in background</string>
|
<string name="usf_background_summary">Don\'t lock volumes when the app goes in background</string>
|
||||||
<string name="usf_keep_open">Keep volumes open</string>
|
<string name="usf_keep_open">Keep volumes open</string>
|
||||||
<string name="usf_keep_open_summary">Maintain the app always running in the background to keep volumes open</string>
|
<string name="usf_keep_open_summary">Maintain the app always running in the background to keep volumes open</string>
|
||||||
|
<string name="gocryptfs_details">Fast, but doesn\'t hide file sizes and directory structure</string>
|
||||||
|
<string name="cryfs_details">Slower, but protects metadata and prevents replacement attacks</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
Reference in New Issue
Block a user