forked from hardcoresushi/DroidFS
Loading dialogs & Graphical bug fixes
This commit is contained in:
parent
24cfc1093e
commit
2571849bc3
@ -24,7 +24,9 @@ android {
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
minifyEnabled true
|
||||
shrinkResources true
|
||||
useProguard true
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package sushi.hardcore.droidfs
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Bundle
|
||||
import android.view.WindowManager
|
||||
import android.widget.Toast
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.jaredrummler.cyanea.app.CyaneaAppCompatActivity
|
||||
@ -29,4 +30,8 @@ open class BaseActivity: CyaneaAppCompatActivity() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected fun toastFromThread(stringId: Int){
|
||||
runOnUiThread { Toast.makeText(this, stringId, Toast.LENGTH_SHORT).show() }
|
||||
}
|
||||
}
|
@ -8,6 +8,7 @@ import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.view.View
|
||||
import android.widget.AdapterView.OnItemClickListener
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import kotlinx.android.synthetic.main.activity_change_password.*
|
||||
import kotlinx.android.synthetic.main.activity_change_password.checkbox_remember_path
|
||||
@ -21,7 +22,7 @@ import sushi.hardcore.droidfs.util.PathUtils
|
||||
import sushi.hardcore.droidfs.util.GocryptfsVolume
|
||||
import sushi.hardcore.droidfs.util.WidgetUtil
|
||||
import sushi.hardcore.droidfs.util.Wiper
|
||||
import sushi.hardcore.droidfs.widgets.ColoredAlertDialog
|
||||
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
|
||||
import java.util.*
|
||||
|
||||
class ChangePasswordActivity : BaseActivity() {
|
||||
@ -29,7 +30,7 @@ class ChangePasswordActivity : BaseActivity() {
|
||||
private const val PICK_DIRECTORY_REQUEST_CODE = 1
|
||||
}
|
||||
private lateinit var fingerprintPasswordHashSaver: FingerprintPasswordHashSaver
|
||||
private lateinit var root_cipher_dir: String
|
||||
private lateinit var rootCipherDir: String
|
||||
private var usf_fingerprint = false
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@ -87,75 +88,93 @@ class ChangePasswordActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
fun onClickChangePassword(view: View?) {
|
||||
root_cipher_dir = edit_volume_path.text.toString()
|
||||
if (root_cipher_dir.isEmpty()) {
|
||||
rootCipherDir = edit_volume_path.text.toString()
|
||||
if (rootCipherDir.isEmpty()) {
|
||||
Toast.makeText(this, R.string.enter_volume_path, Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
changePassword(null)
|
||||
}
|
||||
}
|
||||
|
||||
fun changePassword(givenHash: ByteArray?){
|
||||
val new_password = edit_new_password.text.toString().toCharArray()
|
||||
val new_password_confirm = edit_new_password_confirm.text.toString().toCharArray()
|
||||
if (!new_password.contentEquals(new_password_confirm)) {
|
||||
Toast.makeText(applicationContext, R.string.passwords_mismatch, Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
val old_password = edit_old_password.text.toString().toCharArray()
|
||||
var returnedHash: ByteArray? = null
|
||||
if (usf_fingerprint && checkbox_save_password.isChecked){
|
||||
returnedHash = ByteArray(GocryptfsVolume.KeyLen)
|
||||
}
|
||||
var changePasswordImmediately = true
|
||||
if (givenHash == null){
|
||||
val cipherText = sharedPrefs.getString(root_cipher_dir, null)
|
||||
if (cipherText != null){ //password hash saved
|
||||
fingerprintPasswordHashSaver.decrypt(cipherText, root_cipher_dir, ::changePassword)
|
||||
changePasswordImmediately = false
|
||||
private fun changePassword(givenHash: ByteArray?){
|
||||
val dialogLoadingView = layoutInflater.inflate(R.layout.dialog_loading, null)
|
||||
val dialogTextMessage = dialogLoadingView.findViewById<TextView>(R.id.text_message)
|
||||
dialogTextMessage.text = getString(R.string.loading_msg_change_password)
|
||||
val dialogLoading = ColoredAlertDialogBuilder(this)
|
||||
.setView(dialogLoadingView)
|
||||
.setTitle(R.string.loading)
|
||||
.setCancelable(false)
|
||||
.create()
|
||||
dialogLoading.show()
|
||||
Thread {
|
||||
val newPassword = edit_new_password.text.toString().toCharArray()
|
||||
val newPasswordConfirm = edit_new_password_confirm.text.toString().toCharArray()
|
||||
if (!newPassword.contentEquals(newPasswordConfirm)) {
|
||||
dialogLoading.dismiss()
|
||||
toastFromThread(R.string.passwords_mismatch)
|
||||
} else {
|
||||
val oldPassword = edit_old_password.text.toString().toCharArray()
|
||||
var returnedHash: ByteArray? = null
|
||||
if (usf_fingerprint && checkbox_save_password.isChecked){
|
||||
returnedHash = ByteArray(GocryptfsVolume.KeyLen)
|
||||
}
|
||||
}
|
||||
if (changePasswordImmediately){
|
||||
if (GocryptfsVolume.change_password(root_cipher_dir, old_password, givenHash, new_password, returnedHash)) {
|
||||
val editor = sharedPrefs.edit()
|
||||
if (sharedPrefs.getString(root_cipher_dir, null) != null){
|
||||
editor.remove(root_cipher_dir)
|
||||
editor.apply()
|
||||
var changePasswordImmediately = true
|
||||
if (givenHash == null){
|
||||
val cipherText = sharedPrefs.getString(rootCipherDir, null)
|
||||
if (cipherText != null){ //password hash saved
|
||||
dialogLoading.dismiss()
|
||||
fingerprintPasswordHashSaver.decrypt(cipherText, rootCipherDir, ::changePassword)
|
||||
changePasswordImmediately = false
|
||||
}
|
||||
var continueImmediately = true
|
||||
if (checkbox_remember_path.isChecked) {
|
||||
val old_saved_volumes_paths = sharedPrefs.getStringSet(ConstValues.saved_volumes_key, HashSet()) as Set<String>
|
||||
val new_saved_volumes_paths = old_saved_volumes_paths.toMutableList()
|
||||
if (!old_saved_volumes_paths.contains(root_cipher_dir)) {
|
||||
new_saved_volumes_paths.add(root_cipher_dir)
|
||||
editor.putStringSet(ConstValues.saved_volumes_key, new_saved_volumes_paths.toSet())
|
||||
}
|
||||
if (changePasswordImmediately){
|
||||
if (GocryptfsVolume.change_password(rootCipherDir, oldPassword, givenHash, newPassword, returnedHash)) {
|
||||
val editor = sharedPrefs.edit()
|
||||
if (sharedPrefs.getString(rootCipherDir, null) != null){
|
||||
editor.remove(rootCipherDir)
|
||||
editor.apply()
|
||||
}
|
||||
if (checkbox_save_password.isChecked && returnedHash != null){
|
||||
fingerprintPasswordHashSaver.encryptAndSave(returnedHash, root_cipher_dir){ _ ->
|
||||
onPasswordChanged()
|
||||
var continueImmediately = true
|
||||
if (checkbox_remember_path.isChecked) {
|
||||
val oldSavedVolumesPaths = sharedPrefs.getStringSet(ConstValues.saved_volumes_key, HashSet()) as Set<String>
|
||||
val newSavedVolumesPaths = oldSavedVolumesPaths.toMutableList()
|
||||
if (!oldSavedVolumesPaths.contains(rootCipherDir)) {
|
||||
newSavedVolumesPaths.add(rootCipherDir)
|
||||
editor.putStringSet(ConstValues.saved_volumes_key, newSavedVolumesPaths.toSet())
|
||||
editor.apply()
|
||||
}
|
||||
continueImmediately = false
|
||||
if (checkbox_save_password.isChecked && returnedHash != null){
|
||||
dialogLoading.dismiss()
|
||||
fingerprintPasswordHashSaver.encryptAndSave(returnedHash, rootCipherDir){ _ ->
|
||||
onPasswordChanged()
|
||||
}
|
||||
continueImmediately = false
|
||||
}
|
||||
}
|
||||
if (continueImmediately){
|
||||
dialogLoading.dismiss()
|
||||
runOnUiThread { onPasswordChanged() }
|
||||
}
|
||||
} else {
|
||||
dialogLoading.dismiss()
|
||||
runOnUiThread {
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(R.string.change_password_failed)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
if (continueImmediately){
|
||||
onPasswordChanged()
|
||||
}
|
||||
} else {
|
||||
ColoredAlertDialog(this)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(R.string.change_password_failed)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
Arrays.fill(oldPassword, 0.toChar())
|
||||
}
|
||||
Arrays.fill(old_password, 0.toChar())
|
||||
}
|
||||
Arrays.fill(new_password, 0.toChar())
|
||||
Arrays.fill(new_password_confirm, 0.toChar())
|
||||
Arrays.fill(newPassword, 0.toChar())
|
||||
Arrays.fill(newPasswordConfirm, 0.toChar())
|
||||
}.start()
|
||||
}
|
||||
|
||||
fun onPasswordChanged(){
|
||||
ColoredAlertDialog(this)
|
||||
private fun onPasswordChanged(){
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.success_change_password)
|
||||
.setMessage(R.string.success_change_password_msg)
|
||||
.setCancelable(false)
|
||||
|
@ -8,9 +8,8 @@ class ConstValues {
|
||||
const val creator = "DroidFS"
|
||||
const val saved_volumes_key = "saved_volumes"
|
||||
const val sort_order_key = "sort_order"
|
||||
val fakeUri = Uri.parse("fakeuri://droidfs")
|
||||
val fakeUri: Uri = Uri.parse("fakeuri://droidfs")
|
||||
const val wipe_passes = 2
|
||||
const val seek_bar_inc = 200
|
||||
private val fileExtensions = mapOf(
|
||||
Pair("image", listOf("png", "jpg", "jpeg")),
|
||||
Pair("video", listOf("mp4", "webm")),
|
||||
|
@ -5,7 +5,7 @@ import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import android.widget.TextView
|
||||
import kotlinx.android.synthetic.main.activity_create.*
|
||||
import kotlinx.android.synthetic.main.activity_create.checkbox_remember_path
|
||||
import kotlinx.android.synthetic.main.activity_create.checkbox_save_password
|
||||
@ -18,7 +18,7 @@ import sushi.hardcore.droidfs.util.PathUtils
|
||||
import sushi.hardcore.droidfs.util.GocryptfsVolume
|
||||
import sushi.hardcore.droidfs.util.WidgetUtil
|
||||
import sushi.hardcore.droidfs.util.Wiper
|
||||
import sushi.hardcore.droidfs.widgets.ColoredAlertDialog
|
||||
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
@ -27,7 +27,7 @@ class CreateActivity : BaseActivity() {
|
||||
private const val PICK_DIRECTORY_REQUEST_CODE = 1
|
||||
}
|
||||
private lateinit var fingerprintPasswordHashSaver: FingerprintPasswordHashSaver
|
||||
private lateinit var root_cipher_dir: String
|
||||
private lateinit var rootCipherDir: String
|
||||
private var sessionID = -1
|
||||
private var usf_fingerprint = false
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
@ -64,89 +64,110 @@ class CreateActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
fun onClickCreate(view: View?) {
|
||||
val password = edit_password.text.toString().toCharArray()
|
||||
val password_confirm = edit_password_confirm.text.toString().toCharArray()
|
||||
if (!password.contentEquals(password_confirm)) {
|
||||
Toast.makeText(applicationContext, R.string.passwords_mismatch, Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
root_cipher_dir = edit_volume_path.text.toString()
|
||||
val volume_path_file = File(root_cipher_dir)
|
||||
var good_directory = false
|
||||
if (!volume_path_file.isDirectory) {
|
||||
if (volume_path_file.mkdirs()) {
|
||||
good_directory = true
|
||||
} else {
|
||||
Toast.makeText(applicationContext, R.string.error_mkdir, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
val dialogLoadingView = layoutInflater.inflate(R.layout.dialog_loading, null)
|
||||
val dialogTextMessage = dialogLoadingView.findViewById<TextView>(R.id.text_message)
|
||||
dialogTextMessage.text = getString(R.string.loading_msg_create)
|
||||
val dialogLoading = ColoredAlertDialogBuilder(this)
|
||||
.setView(dialogLoadingView)
|
||||
.setTitle(R.string.loading)
|
||||
.setCancelable(false)
|
||||
.create()
|
||||
dialogLoading.show()
|
||||
Thread {
|
||||
val password = edit_password.text.toString().toCharArray()
|
||||
val passwordConfirm = edit_password_confirm.text.toString().toCharArray()
|
||||
if (!password.contentEquals(passwordConfirm)) {
|
||||
dialogLoading.dismiss()
|
||||
toastFromThread(R.string.passwords_mismatch)
|
||||
} else {
|
||||
val dir_content = volume_path_file.list()
|
||||
if (dir_content != null){
|
||||
if (dir_content.isEmpty()) {
|
||||
good_directory = true
|
||||
rootCipherDir = edit_volume_path.text.toString()
|
||||
val volumePathFile = File(rootCipherDir)
|
||||
var goodDirectory = false
|
||||
if (!volumePathFile.isDirectory) {
|
||||
if (volumePathFile.mkdirs()) {
|
||||
goodDirectory = true
|
||||
} else {
|
||||
Toast.makeText(applicationContext, R.string.dir_not_empty, Toast.LENGTH_SHORT).show()
|
||||
dialogLoading.dismiss()
|
||||
toastFromThread(R.string.error_mkdir)
|
||||
}
|
||||
} else {
|
||||
Toast.makeText(applicationContext, getString(R.string.listdir_null_error_msg), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
if (good_directory) {
|
||||
if (GocryptfsVolume.create_volume(root_cipher_dir, password, GocryptfsVolume.ScryptDefaultLogN, ConstValues.creator)) {
|
||||
var returnedHash: ByteArray? = null
|
||||
if (usf_fingerprint && checkbox_save_password.isChecked){
|
||||
returnedHash = ByteArray(GocryptfsVolume.KeyLen)
|
||||
}
|
||||
sessionID = GocryptfsVolume.init(root_cipher_dir, password, null, returnedHash)
|
||||
if (sessionID != -1) {
|
||||
var startExplorerImmediately = true
|
||||
if (checkbox_remember_path.isChecked) {
|
||||
val old_saved_volumes_paths = sharedPrefs.getStringSet(ConstValues.saved_volumes_key, HashSet()) as Set<String>
|
||||
val editor = sharedPrefs.edit()
|
||||
val new_saved_volumes_paths = old_saved_volumes_paths.toMutableList()
|
||||
if (old_saved_volumes_paths.contains(root_cipher_dir)) {
|
||||
if (sharedPrefs.getString(root_cipher_dir, null) != null){
|
||||
editor.remove(root_cipher_dir)
|
||||
}
|
||||
} else {
|
||||
new_saved_volumes_paths.add(root_cipher_dir)
|
||||
editor.putStringSet(ConstValues.saved_volumes_key, new_saved_volumes_paths.toSet())
|
||||
}
|
||||
editor.apply()
|
||||
if (checkbox_save_password.isChecked && returnedHash != null){
|
||||
fingerprintPasswordHashSaver.encryptAndSave(returnedHash, root_cipher_dir){ _ ->
|
||||
startExplorer()
|
||||
}
|
||||
startExplorerImmediately = false
|
||||
}
|
||||
}
|
||||
if (startExplorerImmediately){
|
||||
startExplorer()
|
||||
val dirContent = volumePathFile.list()
|
||||
if (dirContent != null){
|
||||
if (dirContent.isEmpty()) {
|
||||
goodDirectory = true
|
||||
} else {
|
||||
dialogLoading.dismiss()
|
||||
toastFromThread(R.string.dir_not_empty)
|
||||
}
|
||||
} else {
|
||||
Toast.makeText(this, R.string.open_volume_failed, Toast.LENGTH_SHORT).show()
|
||||
dialogLoading.dismiss()
|
||||
toastFromThread(R.string.listdir_null_error_msg)
|
||||
}
|
||||
}
|
||||
if (goodDirectory) {
|
||||
if (GocryptfsVolume.create_volume(rootCipherDir, password, GocryptfsVolume.ScryptDefaultLogN, ConstValues.creator)) {
|
||||
var returnedHash: ByteArray? = null
|
||||
if (usf_fingerprint && checkbox_save_password.isChecked){
|
||||
returnedHash = ByteArray(GocryptfsVolume.KeyLen)
|
||||
}
|
||||
sessionID = GocryptfsVolume.init(rootCipherDir, password, null, returnedHash)
|
||||
if (sessionID != -1) {
|
||||
var startExplorerImmediately = true
|
||||
if (checkbox_remember_path.isChecked) {
|
||||
val oldSavedVolumesPaths = sharedPrefs.getStringSet(ConstValues.saved_volumes_key, HashSet()) as Set<String>
|
||||
val editor = sharedPrefs.edit()
|
||||
val newSavedVolumesPaths = oldSavedVolumesPaths.toMutableList()
|
||||
if (oldSavedVolumesPaths.contains(rootCipherDir)) {
|
||||
if (sharedPrefs.getString(rootCipherDir, null) != null){
|
||||
editor.remove(rootCipherDir)
|
||||
}
|
||||
} else {
|
||||
newSavedVolumesPaths.add(rootCipherDir)
|
||||
editor.putStringSet(ConstValues.saved_volumes_key, newSavedVolumesPaths.toSet())
|
||||
}
|
||||
editor.apply()
|
||||
if (checkbox_save_password.isChecked && returnedHash != null){
|
||||
dialogLoading.dismiss()
|
||||
fingerprintPasswordHashSaver.encryptAndSave(returnedHash, rootCipherDir){ _ ->
|
||||
runOnUiThread { startExplorer() }
|
||||
}
|
||||
startExplorerImmediately = false
|
||||
}
|
||||
}
|
||||
if (startExplorerImmediately){
|
||||
dialogLoading.dismiss()
|
||||
runOnUiThread { startExplorer() }
|
||||
}
|
||||
} else {
|
||||
dialogLoading.dismiss()
|
||||
toastFromThread(R.string.open_volume_failed)
|
||||
}
|
||||
} else {
|
||||
dialogLoading.dismiss()
|
||||
runOnUiThread {
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(R.string.create_volume_failed)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ColoredAlertDialog(this)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(R.string.create_volume_failed)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
Arrays.fill(password, 0.toChar())
|
||||
Arrays.fill(password_confirm, 0.toChar())
|
||||
Arrays.fill(password, 0.toChar())
|
||||
Arrays.fill(passwordConfirm, 0.toChar())
|
||||
}.start()
|
||||
}
|
||||
|
||||
fun startExplorer(){
|
||||
ColoredAlertDialog(this)
|
||||
private fun startExplorer(){
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.success_volume_create)
|
||||
.setMessage(R.string.success_volume_create_msg)
|
||||
.setCancelable(false)
|
||||
.setPositiveButton(R.string.ok) { _, _ ->
|
||||
val intent = Intent(applicationContext, ExplorerActivity::class.java)
|
||||
intent.putExtra("sessionID", sessionID)
|
||||
intent.putExtra("volume_name", File(root_cipher_dir).name)
|
||||
intent.putExtra("volume_name", File(rootCipherDir).name)
|
||||
startActivity(intent)
|
||||
finish()
|
||||
}
|
||||
|
@ -9,11 +9,10 @@ import android.os.Environment
|
||||
import android.util.DisplayMetrics
|
||||
import android.view.*
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.bumptech.glide.Glide
|
||||
import kotlinx.android.synthetic.main.activity_main.*
|
||||
import kotlinx.android.synthetic.main.toolbar.*
|
||||
import sushi.hardcore.droidfs.widgets.ColoredAlertDialog
|
||||
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
|
||||
|
||||
class MainActivity : BaseActivity() {
|
||||
companion object {
|
||||
@ -33,14 +32,14 @@ class MainActivity : BaseActivity() {
|
||||
val state = Environment.getExternalStorageState()
|
||||
val storageAvailable = Environment.MEDIA_MOUNTED == state || Environment.MEDIA_MOUNTED_READ_ONLY == state
|
||||
if (!storageAvailable) {
|
||||
ColoredAlertDialog(this)
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.storage_unavailable)
|
||||
.setMessage(R.string.storage_unavailable_msg)
|
||||
.setPositiveButton(R.string.ok
|
||||
) { _, _ -> finish() }.show()
|
||||
}
|
||||
if (!sharedPrefs.getBoolean("alreadyLaunched", false)){
|
||||
ColoredAlertDialog(this)
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.warning)
|
||||
.setMessage(R.string.usf_home_warning_msg)
|
||||
.setCancelable(false)
|
||||
@ -63,7 +62,7 @@ class MainActivity : BaseActivity() {
|
||||
when (requestCode) {
|
||||
STORAGE_PERMISSIONS_REQUEST -> if (grantResults.size == 2) {
|
||||
if (grantResults[0] != PackageManager.PERMISSION_GRANTED || grantResults[1] != PackageManager.PERMISSION_GRANTED) {
|
||||
ColoredAlertDialog(this)
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.storage_perm_denied)
|
||||
.setMessage(R.string.storage_perm_denied_msg)
|
||||
.setPositiveButton(R.string.ok
|
||||
|
@ -6,7 +6,7 @@ import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.AdapterView.OnItemClickListener
|
||||
import android.widget.Toast
|
||||
import android.widget.TextView
|
||||
import kotlinx.android.synthetic.main.activity_open.checkbox_remember_path
|
||||
import kotlinx.android.synthetic.main.activity_open.checkbox_save_password
|
||||
import kotlinx.android.synthetic.main.activity_open.edit_password
|
||||
@ -22,7 +22,7 @@ import sushi.hardcore.droidfs.util.PathUtils
|
||||
import sushi.hardcore.droidfs.util.GocryptfsVolume
|
||||
import sushi.hardcore.droidfs.util.WidgetUtil
|
||||
import sushi.hardcore.droidfs.util.Wiper
|
||||
import sushi.hardcore.droidfs.widgets.ColoredAlertDialog
|
||||
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
@ -32,7 +32,7 @@ class OpenActivity : BaseActivity() {
|
||||
}
|
||||
private lateinit var savedVolumesAdapter: SavedVolumesAdapter
|
||||
private lateinit var fingerprintPasswordHashSaver: FingerprintPasswordHashSaver
|
||||
private lateinit var root_cipher_dir: String
|
||||
private lateinit var rootCipherDir: String
|
||||
private var sessionID = -1
|
||||
private var usf_fingerprint = false
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
@ -49,11 +49,11 @@ class OpenActivity : BaseActivity() {
|
||||
if (savedVolumesAdapter.count > 0){
|
||||
saved_path_listview.adapter = savedVolumesAdapter
|
||||
saved_path_listview.onItemClickListener = OnItemClickListener { _, _, position, _ ->
|
||||
root_cipher_dir = savedVolumesAdapter.getItem(position)
|
||||
edit_volume_path.setText(root_cipher_dir)
|
||||
val cipherText = sharedPrefs.getString(root_cipher_dir, null)
|
||||
rootCipherDir = savedVolumesAdapter.getItem(position)
|
||||
edit_volume_path.setText(rootCipherDir)
|
||||
val cipherText = sharedPrefs.getString(rootCipherDir, null)
|
||||
if (cipherText != null){ //password hash saved
|
||||
fingerprintPasswordHashSaver.decrypt(cipherText, root_cipher_dir, ::openUsingPasswordHash)
|
||||
fingerprintPasswordHashSaver.decrypt(cipherText, rootCipherDir, ::openUsingPasswordHash)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -83,49 +83,66 @@ class OpenActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
fun onClickOpen(view: View?) {
|
||||
root_cipher_dir = edit_volume_path.text.toString() //fresh get in case of manual rewrite
|
||||
if (root_cipher_dir.isEmpty()) {
|
||||
Toast.makeText(this, R.string.enter_volume_path, Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
val password = edit_password.text.toString().toCharArray()
|
||||
var returnedHash: ByteArray? = null
|
||||
if (usf_fingerprint && checkbox_save_password.isChecked){
|
||||
returnedHash = ByteArray(GocryptfsVolume.KeyLen)
|
||||
}
|
||||
sessionID = GocryptfsVolume.init(root_cipher_dir, password, null, returnedHash)
|
||||
if (sessionID != -1) {
|
||||
var startExplorerImmediately = true
|
||||
if (checkbox_remember_path.isChecked) {
|
||||
savedVolumesAdapter.addVolumePath(root_cipher_dir)
|
||||
if (checkbox_save_password.isChecked && returnedHash != null){
|
||||
fingerprintPasswordHashSaver.encryptAndSave(returnedHash, root_cipher_dir) {success ->
|
||||
if (success){
|
||||
startExplorer()
|
||||
val dialogLoadingView = layoutInflater.inflate(R.layout.dialog_loading, null)
|
||||
val dialogTextMessage = dialogLoadingView.findViewById<TextView>(R.id.text_message)
|
||||
dialogTextMessage.text = getString(R.string.loading_msg_open)
|
||||
val dialogLoading = ColoredAlertDialogBuilder(this)
|
||||
.setView(dialogLoadingView)
|
||||
.setTitle(R.string.loading)
|
||||
.setCancelable(false)
|
||||
.create()
|
||||
dialogLoading.show()
|
||||
Thread {
|
||||
rootCipherDir = edit_volume_path.text.toString() //fresh get in case of manual rewrite
|
||||
if (rootCipherDir.isEmpty()) {
|
||||
dialogLoading.dismiss()
|
||||
toastFromThread(R.string.enter_volume_path)
|
||||
} else {
|
||||
val password = edit_password.text.toString().toCharArray()
|
||||
var returnedHash: ByteArray? = null
|
||||
if (usf_fingerprint && checkbox_save_password.isChecked){
|
||||
returnedHash = ByteArray(GocryptfsVolume.KeyLen)
|
||||
}
|
||||
sessionID = GocryptfsVolume.init(rootCipherDir, password, null, returnedHash)
|
||||
if (sessionID != -1) {
|
||||
var startExplorerImmediately = true
|
||||
if (checkbox_remember_path.isChecked) {
|
||||
savedVolumesAdapter.addVolumePath(rootCipherDir)
|
||||
if (checkbox_save_password.isChecked && returnedHash != null){
|
||||
fingerprintPasswordHashSaver.encryptAndSave(returnedHash, rootCipherDir) { success ->
|
||||
dialogLoading.dismiss()
|
||||
if (success){
|
||||
startExplorer()
|
||||
}
|
||||
}
|
||||
startExplorerImmediately = false
|
||||
}
|
||||
startExplorerImmediately = false
|
||||
}
|
||||
if (startExplorerImmediately){
|
||||
dialogLoading.dismiss()
|
||||
startExplorer()
|
||||
}
|
||||
} else {
|
||||
dialogLoading.dismiss()
|
||||
runOnUiThread {
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.open_volume_failed)
|
||||
.setMessage(R.string.open_volume_failed_msg)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
if (startExplorerImmediately){
|
||||
startExplorer()
|
||||
}
|
||||
} else {
|
||||
ColoredAlertDialog(this)
|
||||
.setTitle(R.string.open_volume_failed)
|
||||
.setMessage(R.string.open_volume_failed_msg)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
Arrays.fill(password, 0.toChar())
|
||||
}
|
||||
Arrays.fill(password, 0.toChar())
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
|
||||
private fun openUsingPasswordHash(passwordHash: ByteArray){
|
||||
sessionID = GocryptfsVolume.init(root_cipher_dir, null, passwordHash, null)
|
||||
sessionID = GocryptfsVolume.init(rootCipherDir, null, passwordHash, null)
|
||||
if (sessionID != -1){
|
||||
startExplorer()
|
||||
} else {
|
||||
ColoredAlertDialog(this)
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.open_volume_failed)
|
||||
.setMessage(R.string.open_failed_hash_msg)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
@ -135,24 +152,24 @@ class OpenActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
private fun startExplorer() {
|
||||
var explorer_intent: Intent? = null
|
||||
val current_intent_action = intent.action
|
||||
if (current_intent_action != null) {
|
||||
if ((current_intent_action == Intent.ACTION_SEND || current_intent_action == Intent.ACTION_SEND_MULTIPLE) && intent.extras != null) { //import via android share menu
|
||||
explorer_intent = Intent(this, ExplorerActivityDrop::class.java)
|
||||
explorer_intent.action = current_intent_action //forward action
|
||||
explorer_intent.putExtras(intent.extras!!) //forward extras
|
||||
} else if (current_intent_action == "pick") { //pick items to import
|
||||
explorer_intent = Intent(this, ExplorerActivityPick::class.java)
|
||||
explorer_intent.flags = Intent.FLAG_ACTIVITY_FORWARD_RESULT
|
||||
var explorerIntent: Intent? = null
|
||||
val currentIntentAction = intent.action
|
||||
if (currentIntentAction != null) {
|
||||
if ((currentIntentAction == Intent.ACTION_SEND || currentIntentAction == Intent.ACTION_SEND_MULTIPLE) && intent.extras != null) { //import via android share menu
|
||||
explorerIntent = Intent(this, ExplorerActivityDrop::class.java)
|
||||
explorerIntent.action = currentIntentAction //forward action
|
||||
explorerIntent.putExtras(intent.extras!!) //forward extras
|
||||
} else if (currentIntentAction == "pick") { //pick items to import
|
||||
explorerIntent = Intent(this, ExplorerActivityPick::class.java)
|
||||
explorerIntent.flags = Intent.FLAG_ACTIVITY_FORWARD_RESULT
|
||||
}
|
||||
}
|
||||
if (explorer_intent == null) {
|
||||
explorer_intent = Intent(this, ExplorerActivity::class.java) //default opening
|
||||
if (explorerIntent == null) {
|
||||
explorerIntent = Intent(this, ExplorerActivity::class.java) //default opening
|
||||
}
|
||||
explorer_intent.putExtra("sessionID", sessionID)
|
||||
explorer_intent.putExtra("volume_name", File(root_cipher_dir).name)
|
||||
startActivity(explorer_intent)
|
||||
explorerIntent.putExtra("sessionID", sessionID)
|
||||
explorerIntent.putExtra("volume_name", File(rootCipherDir).name)
|
||||
startActivity(explorerIntent)
|
||||
finish()
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,7 @@ class SettingsActivity : BaseActivity(), PreferenceFragmentCompat.OnPreferenceSt
|
||||
.beginTransaction()
|
||||
.replace(R.id.settings, fragment)
|
||||
.commit()
|
||||
setTheme(R.style.AppTheme)
|
||||
}
|
||||
|
||||
class SettingsFragment : PreferenceFragmentCompat() {
|
||||
|
@ -0,0 +1,33 @@
|
||||
package sushi.hardcore.droidfs.adapters
|
||||
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.BaseAdapter
|
||||
import android.widget.CheckedTextView
|
||||
import sushi.hardcore.droidfs.R
|
||||
import sushi.hardcore.droidfs.widgets.ThemeColor
|
||||
|
||||
class DialogSingleChoiceAdapter(private val context: Context, private val entries: Array<String>): BaseAdapter() {
|
||||
private val inflater: LayoutInflater = LayoutInflater.from(context)
|
||||
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
|
||||
val view: View = convertView ?: inflater.inflate(R.layout.adapter_colored_dialog_single_choice, parent, false)
|
||||
val checkedTextView = view.findViewById<CheckedTextView>(android.R.id.text1)
|
||||
checkedTextView.text = getItem(position)
|
||||
val typedArray = context.theme.obtainStyledAttributes(arrayOf(android.R.attr.listChoiceIndicatorSingle).toIntArray())
|
||||
val drawable = typedArray.getDrawable(0)
|
||||
typedArray.recycle()
|
||||
drawable?.setTint(ThemeColor.getThemeColor(context))
|
||||
checkedTextView.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null)
|
||||
return view
|
||||
}
|
||||
|
||||
override fun getItem(position: Int): String {
|
||||
return entries[position]
|
||||
}
|
||||
|
||||
override fun getItemId(position: Int): Long { return 0 }
|
||||
|
||||
override fun getCount(): Int { return entries.size }
|
||||
}
|
@ -18,7 +18,7 @@ class OpenAsDialogAdapter(private val context: Context): BaseAdapter() {
|
||||
listOf("text", context.getString(R.string.text), R.drawable.icon_file_text)
|
||||
)
|
||||
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
|
||||
val view: View = convertView ?: inflater.inflate(R.layout.adapter_dialog_listview, parent, false)
|
||||
val view: View = convertView ?: inflater.inflate(R.layout.adapter_dialog_icon_text, parent, false)
|
||||
val text = view.findViewById<TextView>(R.id.text)
|
||||
text.text = items[position][1] as String
|
||||
val icon = view.findViewById<ColoredImageView>(R.id.icon)
|
||||
|
@ -1,10 +1,8 @@
|
||||
package sushi.hardcore.droidfs.adapters
|
||||
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.content.SharedPreferences.Editor
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
@ -14,7 +12,7 @@ import android.widget.TextView
|
||||
import sushi.hardcore.droidfs.ConstValues
|
||||
import sushi.hardcore.droidfs.R
|
||||
import sushi.hardcore.droidfs.util.WidgetUtil
|
||||
import sushi.hardcore.droidfs.widgets.ColoredAlertDialog
|
||||
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
|
||||
import java.util.*
|
||||
|
||||
class SavedVolumesAdapter(val context: Context, val shared_prefs: SharedPreferences) : BaseAdapter() {
|
||||
@ -56,7 +54,7 @@ class SavedVolumesAdapter(val context: Context, val shared_prefs: SharedPreferen
|
||||
val delete_imageview = view.findViewById<ImageView>(R.id.delete_imageview)
|
||||
delete_imageview.setOnClickListener {
|
||||
val volume_path = saved_volumes_paths[position]
|
||||
val dialog = ColoredAlertDialog(context)
|
||||
val dialog = ColoredAlertDialogBuilder(context)
|
||||
dialog.setTitle(R.string.warning)
|
||||
if (shared_prefs.getString(volume_path, null) != null){
|
||||
dialog.setMessage(context.getString(R.string.delete_hash_or_all))
|
||||
|
@ -9,7 +9,6 @@ import android.view.WindowManager
|
||||
import android.widget.AdapterView.OnItemClickListener
|
||||
import android.widget.AdapterView.OnItemLongClickListener
|
||||
import android.widget.EditText
|
||||
import android.widget.ListView
|
||||
import android.widget.Toast
|
||||
import com.github.clans.fab.FloatingActionMenu
|
||||
import kotlinx.android.synthetic.main.activity_explorer_base.*
|
||||
@ -22,6 +21,7 @@ import sushi.hardcore.droidfs.ConstValues.Companion.isImage
|
||||
import sushi.hardcore.droidfs.ConstValues.Companion.isText
|
||||
import sushi.hardcore.droidfs.ConstValues.Companion.isVideo
|
||||
import sushi.hardcore.droidfs.R
|
||||
import sushi.hardcore.droidfs.adapters.DialogSingleChoiceAdapter
|
||||
import sushi.hardcore.droidfs.adapters.OpenAsDialogAdapter
|
||||
import sushi.hardcore.droidfs.adapters.ExplorerElementAdapter
|
||||
import sushi.hardcore.droidfs.file_viewers.AudioPlayer
|
||||
@ -32,7 +32,7 @@ import sushi.hardcore.droidfs.provider.RestrictedFileProvider
|
||||
import sushi.hardcore.droidfs.util.ExternalProvider
|
||||
import sushi.hardcore.droidfs.util.PathUtils
|
||||
import sushi.hardcore.droidfs.util.GocryptfsVolume
|
||||
import sushi.hardcore.droidfs.widgets.ColoredAlertDialog
|
||||
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
|
||||
import java.util.*
|
||||
|
||||
open class BaseExplorerActivity : BaseActivity() {
|
||||
@ -111,25 +111,21 @@ open class BaseExplorerActivity : BaseActivity() {
|
||||
startFileViewer(AudioPlayer::class.java, fullPath)
|
||||
}
|
||||
else -> {
|
||||
val dialogListView = layoutInflater.inflate(R.layout.dialog_listview, null)
|
||||
val listView = dialogListView.findViewById<ListView>(R.id.listview)
|
||||
val adapter = OpenAsDialogAdapter(this)
|
||||
listView.adapter = adapter
|
||||
val dialog = ColoredAlertDialog(this)
|
||||
.setView(dialogListView)
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setSingleChoiceItems(adapter, -1){ dialog, which ->
|
||||
when (adapter.getItem(which)){
|
||||
"image" -> startFileViewer(ImageViewer::class.java, fullPath)
|
||||
"video" -> startFileViewer(VideoPlayer::class.java, fullPath)
|
||||
"audio" -> startFileViewer(AudioPlayer::class.java, fullPath)
|
||||
"text" -> startFileViewer(TextEditor::class.java, fullPath)
|
||||
}
|
||||
dialog.dismiss()
|
||||
}
|
||||
.setTitle(getString(R.string.open_as))
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.create()
|
||||
listView.setOnItemClickListener{_, _, fileTypePosition, _ ->
|
||||
when (adapter.getItem(fileTypePosition)){
|
||||
"image" -> startFileViewer(ImageViewer::class.java, fullPath)
|
||||
"video" -> startFileViewer(VideoPlayer::class.java, fullPath)
|
||||
"audio" -> startFileViewer(AudioPlayer::class.java, fullPath)
|
||||
"text" -> startFileViewer(TextEditor::class.java, fullPath)
|
||||
}
|
||||
dialog.dismiss()
|
||||
}
|
||||
dialog.show()
|
||||
.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -177,7 +173,7 @@ open class BaseExplorerActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
private fun askCloseVolume() {
|
||||
ColoredAlertDialog(this)
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.warning)
|
||||
.setMessage(R.string.ask_close_volume)
|
||||
.setPositiveButton(R.string.ok) { _, _ -> closeVolumeOnUserExit() }
|
||||
@ -213,7 +209,7 @@ open class BaseExplorerActivity : BaseActivity() {
|
||||
Toast.makeText(this, R.string.error_filename_empty, Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
if (!gocryptfsVolume.mkdir(PathUtils.path_join(currentDirectoryPath, folder_name))) {
|
||||
ColoredAlertDialog(this)
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(R.string.error_mkdir)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
@ -229,7 +225,7 @@ open class BaseExplorerActivity : BaseActivity() {
|
||||
findViewById<FloatingActionMenu>(R.id.fam_explorer).close(true)
|
||||
val dialogEditTextView = layoutInflater.inflate(R.layout.dialog_edit_text, null)
|
||||
val dialogEditText = dialogEditTextView.findViewById<EditText>(R.id.dialog_edit_text)
|
||||
val dialog = ColoredAlertDialog(this)
|
||||
val dialog = ColoredAlertDialogBuilder(this)
|
||||
.setView(dialogEditTextView)
|
||||
.setTitle(R.string.enter_folder_name)
|
||||
.setPositiveButton(R.string.ok) { _, _ ->
|
||||
@ -253,7 +249,7 @@ open class BaseExplorerActivity : BaseActivity() {
|
||||
Toast.makeText(this, R.string.error_filename_empty, Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
if (!gocryptfsVolume.rename(PathUtils.path_join(currentDirectoryPath, old_name), PathUtils.path_join(currentDirectoryPath, new_name))) {
|
||||
ColoredAlertDialog(this)
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(getString(R.string.rename_failed, old_name))
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
@ -296,13 +292,15 @@ open class BaseExplorerActivity : BaseActivity() {
|
||||
true
|
||||
}
|
||||
R.id.explorer_menu_sort -> {
|
||||
ColoredAlertDialog(this)
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.sort_order)
|
||||
.setSingleChoiceItems(sortModesEntries, currentSortModeIndex) { dialog, which ->
|
||||
.setSingleChoiceItems(DialogSingleChoiceAdapter(this, sortModesEntries), currentSortModeIndex) { dialog, which ->
|
||||
currentSortModeIndex = which
|
||||
setCurrentPath(currentDirectoryPath)
|
||||
dialog.dismiss()
|
||||
}.show()
|
||||
}
|
||||
.setNegativeButton(R.string.cancel) { dialog, _ -> dialog.dismiss() }
|
||||
.show()
|
||||
true
|
||||
}
|
||||
R.id.explorer_menu_rename -> {
|
||||
@ -311,7 +309,7 @@ open class BaseExplorerActivity : BaseActivity() {
|
||||
val dialogEditText = dialogEditTextView.findViewById<EditText>(R.id.dialog_edit_text)
|
||||
dialogEditText.setText(oldName)
|
||||
dialogEditText.selectAll()
|
||||
val dialog = ColoredAlertDialog(this)
|
||||
val dialog = ColoredAlertDialogBuilder(this)
|
||||
.setView(dialogEditTextView)
|
||||
.setTitle(R.string.rename_title)
|
||||
.setPositiveButton(R.string.ok) { _, _ ->
|
||||
|
@ -17,7 +17,7 @@ import sushi.hardcore.droidfs.util.ExternalProvider
|
||||
import sushi.hardcore.droidfs.util.PathUtils
|
||||
import sushi.hardcore.droidfs.util.GocryptfsVolume
|
||||
import sushi.hardcore.droidfs.util.Wiper
|
||||
import sushi.hardcore.droidfs.widgets.ColoredAlertDialog
|
||||
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
@ -39,7 +39,7 @@ class ExplorerActivity : BaseExplorerActivity() {
|
||||
} else {
|
||||
val handleID = gocryptfsVolume.open_write_mode(PathUtils.path_join(currentDirectoryPath, fileName))
|
||||
if (handleID == -1) {
|
||||
ColoredAlertDialog(this)
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(R.string.file_creation_failed)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
@ -56,7 +56,7 @@ class ExplorerActivity : BaseExplorerActivity() {
|
||||
findViewById<FloatingActionMenu>(R.id.fam_explorer).close(true)
|
||||
val dialogEditTextView = layoutInflater.inflate(R.layout.dialog_edit_text, null)
|
||||
val dialogEditText = dialogEditTextView.findViewById<EditText>(R.id.dialog_edit_text)
|
||||
val dialog = ColoredAlertDialog(this)
|
||||
val dialog = ColoredAlertDialogBuilder(this)
|
||||
.setView(dialogEditTextView)
|
||||
.setTitle(getString(R.string.enter_file_name))
|
||||
.setPositiveButton(R.string.ok) { _, _ ->
|
||||
@ -115,7 +115,7 @@ class ExplorerActivity : BaseExplorerActivity() {
|
||||
success = gocryptfsVolume.import_file(it, dstPath)
|
||||
}
|
||||
if (!success) {
|
||||
ColoredAlertDialog(this)
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(getString(R.string.import_failed, uri))
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
@ -124,7 +124,7 @@ class ExplorerActivity : BaseExplorerActivity() {
|
||||
}
|
||||
}
|
||||
if (success) {
|
||||
ColoredAlertDialog(this)
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.success_import)
|
||||
.setMessage("""
|
||||
${getString(R.string.success_import_msg)}
|
||||
@ -134,7 +134,7 @@ class ExplorerActivity : BaseExplorerActivity() {
|
||||
success = true
|
||||
for (uri in uris) {
|
||||
if (!Wiper.wipe(this, uri)) {
|
||||
ColoredAlertDialog(this)
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(getString(R.string.wipe_failed, uri))
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
@ -144,7 +144,7 @@ class ExplorerActivity : BaseExplorerActivity() {
|
||||
}
|
||||
}
|
||||
if (success) {
|
||||
ColoredAlertDialog(this)
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.wipe_successful)
|
||||
.setMessage(R.string.wipe_success_msg)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
@ -171,7 +171,7 @@ class ExplorerActivity : BaseExplorerActivity() {
|
||||
if (gocryptfsVolume.export_file(fullPath, PathUtils.path_join(outputDir, element.name))) null else fullPath
|
||||
}
|
||||
if (failedItem != null) {
|
||||
ColoredAlertDialog(this)
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(getString(R.string.export_failed, failedItem))
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
@ -180,7 +180,7 @@ class ExplorerActivity : BaseExplorerActivity() {
|
||||
}
|
||||
}
|
||||
if (failedItem == null) {
|
||||
ColoredAlertDialog(this)
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.success_export)
|
||||
.setMessage(R.string.success_export_msg)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
@ -214,13 +214,13 @@ class ExplorerActivity : BaseExplorerActivity() {
|
||||
failedItem = if (importFileFromOtherVolume(remoteGocryptfsVolume, path, currentDirectoryPath)) null else path
|
||||
}
|
||||
if (failedItem == null) {
|
||||
ColoredAlertDialog(this)
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.success_import)
|
||||
.setMessage(R.string.success_import_msg)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
} else {
|
||||
ColoredAlertDialog(this)
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(getString(R.string.import_failed, failedItem))
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
@ -266,7 +266,7 @@ class ExplorerActivity : BaseExplorerActivity() {
|
||||
}
|
||||
R.id.explorer_menu_delete -> {
|
||||
val size = explorerAdapter.selectedItems.size
|
||||
val dialog = ColoredAlertDialog(this)
|
||||
val dialog = ColoredAlertDialogBuilder(this)
|
||||
dialog.setTitle(R.string.warning)
|
||||
dialog.setPositiveButton(R.string.ok) { _, _ -> removeSelectedItems() }
|
||||
dialog.setNegativeButton(R.string.cancel, null)
|
||||
@ -399,7 +399,7 @@ class ExplorerActivity : BaseExplorerActivity() {
|
||||
}
|
||||
}
|
||||
if (failedItem != null) {
|
||||
ColoredAlertDialog(this)
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(getString(R.string.remove_failed, failedItem))
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
|
@ -6,7 +6,7 @@ import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import sushi.hardcore.droidfs.R
|
||||
import sushi.hardcore.droidfs.util.PathUtils
|
||||
import sushi.hardcore.droidfs.widgets.ColoredAlertDialog
|
||||
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
|
||||
|
||||
class ExplorerActivityDrop : BaseExplorerActivity() {
|
||||
override fun init() {
|
||||
@ -23,7 +23,7 @@ class ExplorerActivityDrop : BaseExplorerActivity() {
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.explorer_menu_validate -> {
|
||||
val alertDialog = ColoredAlertDialog(this)
|
||||
val alertDialog = ColoredAlertDialogBuilder(this)
|
||||
alertDialog.setCancelable(false)
|
||||
alertDialog.setPositiveButton(R.string.ok) { _, _ -> finish() }
|
||||
var error_msg: String? = null
|
||||
|
@ -5,7 +5,7 @@ import android.view.View
|
||||
import sushi.hardcore.droidfs.BaseActivity
|
||||
import sushi.hardcore.droidfs.R
|
||||
import sushi.hardcore.droidfs.util.GocryptfsVolume
|
||||
import sushi.hardcore.droidfs.widgets.ColoredAlertDialog
|
||||
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
|
||||
|
||||
abstract class FileViewerActivity: BaseActivity() {
|
||||
lateinit var gocryptfsVolume: GocryptfsVolume
|
||||
@ -49,7 +49,7 @@ abstract class FileViewerActivity: BaseActivity() {
|
||||
if (success){
|
||||
return fileBuff
|
||||
} else {
|
||||
ColoredAlertDialog(this)
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(R.string.read_file_failed)
|
||||
.setCancelable(false)
|
||||
@ -57,7 +57,7 @@ abstract class FileViewerActivity: BaseActivity() {
|
||||
.show()
|
||||
}
|
||||
} catch (e: OutOfMemoryError){
|
||||
ColoredAlertDialog(this)
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(R.string.outofmemoryerror_msg)
|
||||
.setCancelable(false)
|
||||
@ -66,7 +66,7 @@ abstract class FileViewerActivity: BaseActivity() {
|
||||
}
|
||||
|
||||
} else {
|
||||
ColoredAlertDialog(this)
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(R.string.get_size_failed)
|
||||
.setCancelable(false)
|
||||
|
@ -4,24 +4,32 @@ import androidx.appcompat.app.AlertDialog
|
||||
import com.google.android.exoplayer2.ExoPlaybackException
|
||||
import com.google.android.exoplayer2.Player
|
||||
import com.google.android.exoplayer2.SimpleExoPlayer
|
||||
import com.google.android.exoplayer2.extractor.ExtractorsFactory
|
||||
import com.google.android.exoplayer2.extractor.flv.FlvExtractor
|
||||
import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor
|
||||
import com.google.android.exoplayer2.extractor.mp3.Mp3Extractor
|
||||
import com.google.android.exoplayer2.extractor.mp4.Mp4Extractor
|
||||
import com.google.android.exoplayer2.extractor.ogg.OggExtractor
|
||||
import com.google.android.exoplayer2.extractor.wav.WavExtractor
|
||||
import com.google.android.exoplayer2.source.LoopingMediaSource
|
||||
import com.google.android.exoplayer2.source.ProgressiveMediaSource
|
||||
import sushi.hardcore.droidfs.ConstValues
|
||||
import sushi.hardcore.droidfs.R
|
||||
import sushi.hardcore.droidfs.widgets.ColoredAlertDialog
|
||||
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
|
||||
|
||||
abstract class MediaPlayer: FileViewerActivity() {
|
||||
private lateinit var player: SimpleExoPlayer
|
||||
private var currentWindow = 0
|
||||
private var playbackPosition: Long = 0
|
||||
private lateinit var errorDialog: AlertDialog.Builder
|
||||
private lateinit var errorDialog: AlertDialog
|
||||
|
||||
override fun viewFile() {
|
||||
errorDialog = ColoredAlertDialog(this)
|
||||
errorDialog = ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(R.string.playing_failed)
|
||||
.setCancelable(false)
|
||||
.setPositiveButton(R.string.ok) { _, _ -> finish() }
|
||||
.create()
|
||||
}
|
||||
|
||||
abstract fun bindPlayer(player: SimpleExoPlayer)
|
||||
@ -30,7 +38,16 @@ abstract class MediaPlayer: FileViewerActivity() {
|
||||
player = SimpleExoPlayer.Builder(this).build()
|
||||
bindPlayer(player)
|
||||
val dataSourceFactory = GocryptfsDataSource.Factory(gocryptfsVolume, filePath)
|
||||
val mediaSource = ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(ConstValues.fakeUri)
|
||||
val mediaSource = ProgressiveMediaSource.Factory(dataSourceFactory, ExtractorsFactory {
|
||||
arrayOf(
|
||||
MatroskaExtractor(),
|
||||
Mp4Extractor(),
|
||||
Mp3Extractor(),
|
||||
FlvExtractor(),
|
||||
OggExtractor(),
|
||||
WavExtractor()
|
||||
)
|
||||
}).createMediaSource(ConstValues.fakeUri)
|
||||
player.seekTo(currentWindow, playbackPosition)
|
||||
player.playWhenReady = true
|
||||
player.addListener(object : Player.EventListener{
|
||||
|
@ -10,7 +10,7 @@ import android.widget.Toast
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import sushi.hardcore.droidfs.R
|
||||
import sushi.hardcore.droidfs.util.GocryptfsVolume
|
||||
import sushi.hardcore.droidfs.widgets.ColoredAlertDialog
|
||||
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.File
|
||||
|
||||
@ -30,7 +30,7 @@ class TextEditor: FileViewerActivity() {
|
||||
try {
|
||||
loadLayout(String(it))
|
||||
} catch (e: OutOfMemoryError){
|
||||
ColoredAlertDialog(this)
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(R.string.outofmemoryerror_msg)
|
||||
.setCancelable(false)
|
||||
@ -98,7 +98,7 @@ class TextEditor: FileViewerActivity() {
|
||||
|
||||
private fun checkSaveAndExit(){
|
||||
if (changedSinceLastSave){
|
||||
ColoredAlertDialog(this)
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.warning)
|
||||
.setMessage(R.string.ask_save)
|
||||
.setPositiveButton(getString(R.string.save)) { _, _ ->
|
||||
|
@ -14,15 +14,13 @@ import android.os.Handler
|
||||
import android.security.keystore.KeyGenParameterSpec
|
||||
import android.security.keystore.KeyProperties
|
||||
import android.util.Base64
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.ContextCompat
|
||||
import sushi.hardcore.droidfs.ConstValues
|
||||
import sushi.hardcore.droidfs.R
|
||||
import sushi.hardcore.droidfs.widgets.ColoredAlertDialog
|
||||
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
|
||||
import java.security.KeyStore
|
||||
import javax.crypto.*
|
||||
import javax.crypto.spec.GCMParameterSpec
|
||||
@ -31,11 +29,11 @@ import javax.crypto.spec.GCMParameterSpec
|
||||
class FingerprintPasswordHashSaver(private val activityContext: AppCompatActivity, private val shared_prefs: SharedPreferences) {
|
||||
private var isPrepared = false
|
||||
var isListening = false
|
||||
var authenticationFailed = false
|
||||
private val shared_prefs_editor: SharedPreferences.Editor = shared_prefs.edit()
|
||||
private var authenticationFailed = false
|
||||
private val sharedPrefsEditor: SharedPreferences.Editor = shared_prefs.edit()
|
||||
private val fingerprintManager = activityContext.getSystemService(Context.FINGERPRINT_SERVICE) as FingerprintManager
|
||||
private lateinit var root_cipher_dir: String
|
||||
private lateinit var action_description: String
|
||||
private lateinit var rootCipherDir: String
|
||||
private lateinit var actionDescription: String
|
||||
private lateinit var onAuthenticationResult: (success: Boolean) -> Unit
|
||||
private lateinit var onPasswordDecrypted: (password: ByteArray) -> Unit
|
||||
private lateinit var keyStore: KeyStore
|
||||
@ -55,16 +53,16 @@ class FingerprintPasswordHashSaver(private val activityContext: AppCompatActivit
|
||||
private const val SUCCESS_DISMISS_DIALOG_DELAY: Long = 400
|
||||
private const val FAILED_DISMISS_DIALOG_DELAY: Long = 800
|
||||
}
|
||||
private fun reset_hash_storage() {
|
||||
private fun resetHashStorage() {
|
||||
keyStore.deleteEntry(KEY_ALIAS)
|
||||
val saved_volume_paths = shared_prefs.getStringSet(ConstValues.saved_volumes_key, HashSet<String>()) as Set<String>
|
||||
for (path in saved_volume_paths){
|
||||
val saved_hash = shared_prefs.getString(path, null)
|
||||
if (saved_hash != null){
|
||||
shared_prefs_editor.remove(path)
|
||||
val savedVolumePaths = shared_prefs.getStringSet(ConstValues.saved_volumes_key, HashSet<String>()) as Set<String>
|
||||
for (path in savedVolumePaths){
|
||||
val savedHash = shared_prefs.getString(path, null)
|
||||
if (savedHash != null){
|
||||
sharedPrefsEditor.remove(path)
|
||||
}
|
||||
}
|
||||
shared_prefs_editor.apply()
|
||||
sharedPrefsEditor.apply()
|
||||
Toast.makeText(activityContext, activityContext.getString(R.string.hash_storage_reset), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
@ -99,13 +97,13 @@ class FingerprintPasswordHashSaver(private val activityContext: AppCompatActivit
|
||||
keyGenerator.generateKey()
|
||||
}
|
||||
cipher = Cipher.getInstance(CIPHER_TYPE)
|
||||
fingerprintFragment = FingerprintFragment(root_cipher_dir, action_description, ::stopListening)
|
||||
fingerprintFragment = FingerprintFragment(rootCipherDir, actionDescription, ::stopListening)
|
||||
isPrepared = true
|
||||
}
|
||||
fun encryptAndSave(plainText: ByteArray, root_cipher_dir: String, onAuthenticationResult: (success: Boolean) -> Unit){
|
||||
if (shared_prefs.getString(root_cipher_dir, null) == null){
|
||||
this.root_cipher_dir = root_cipher_dir
|
||||
this.action_description = activityContext.getString(R.string.encrypt_action_description)
|
||||
this.rootCipherDir = root_cipher_dir
|
||||
this.actionDescription = activityContext.getString(R.string.encrypt_action_description)
|
||||
this.onAuthenticationResult = onAuthenticationResult
|
||||
if (!isPrepared){
|
||||
prepare()
|
||||
@ -117,8 +115,8 @@ class FingerprintPasswordHashSaver(private val activityContext: AppCompatActivit
|
||||
}
|
||||
}
|
||||
fun decrypt(cipherText: String, root_cipher_dir: String, onPasswordDecrypted: (password: ByteArray) -> Unit){
|
||||
this.root_cipher_dir = root_cipher_dir
|
||||
this.action_description = activityContext.getString(R.string.decrypt_action_description)
|
||||
this.rootCipherDir = root_cipher_dir
|
||||
this.actionDescription = activityContext.getString(R.string.decrypt_action_description)
|
||||
this.onPasswordDecrypted = onPasswordDecrypted
|
||||
if (!isPrepared){
|
||||
prepare()
|
||||
@ -136,8 +134,8 @@ class FingerprintPasswordHashSaver(private val activityContext: AppCompatActivit
|
||||
cancellationSignal = CancellationSignal()
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
val biometricPrompt = BiometricPrompt.Builder(activityContext)
|
||||
.setTitle(root_cipher_dir)
|
||||
.setSubtitle(action_description)
|
||||
.setTitle(rootCipherDir)
|
||||
.setSubtitle(actionDescription)
|
||||
.setDescription(activityContext.getString(R.string.fingerprint_instruction))
|
||||
.setNegativeButton(activityContext.getString(R.string.cancel), activityContext.mainExecutor, DialogInterface.OnClickListener{_, _ ->
|
||||
cancellationSignal.cancel()
|
||||
@ -180,7 +178,7 @@ class FingerprintPasswordHashSaver(private val activityContext: AppCompatActivit
|
||||
if (!authenticationFailed){
|
||||
if (fingerprintFragment.isAdded){
|
||||
fingerprintFragment.image_fingerprint.setColorFilter(ContextCompat.getColor(activityContext, R.color.fingerprint_failed))
|
||||
fingerprintFragment.text_instruction.setText(activityContext.getString(R.string.authentication_error))
|
||||
fingerprintFragment.text_instruction.text = activityContext.getString(R.string.authentication_error)
|
||||
handler.postDelayed({ fingerprintFragment.dismiss() }, 1000)
|
||||
}
|
||||
if (actionMode == Cipher.ENCRYPT_MODE){
|
||||
@ -215,8 +213,8 @@ class FingerprintPasswordHashSaver(private val activityContext: AppCompatActivit
|
||||
val cipherText = cipher.doFinal(dataToProcess)
|
||||
val encodedCipherText = Base64.encodeToString(cipherText, 0)
|
||||
val encodedIv = Base64.encodeToString(cipher.iv, 0)
|
||||
shared_prefs_editor.putString(root_cipher_dir, "$encodedIv:$encodedCipherText")
|
||||
shared_prefs_editor.apply()
|
||||
sharedPrefsEditor.putString(rootCipherDir, "$encodedIv:$encodedCipherText")
|
||||
sharedPrefsEditor.apply()
|
||||
handler.postDelayed({
|
||||
if (fingerprintFragment.isAdded){
|
||||
fingerprintFragment.dismiss()
|
||||
@ -234,11 +232,11 @@ class FingerprintPasswordHashSaver(private val activityContext: AppCompatActivit
|
||||
onPasswordDecrypted(plainText)
|
||||
}, SUCCESS_DISMISS_DIALOG_DELAY)
|
||||
} catch (e: AEADBadTagException){
|
||||
ColoredAlertDialog(activityContext)
|
||||
ColoredAlertDialogBuilder(activityContext)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(activityContext.getString(R.string.MAC_verification_failed))
|
||||
.setPositiveButton(activityContext.getString(R.string.reset_hash_storage)) { _, _ ->
|
||||
reset_hash_storage()
|
||||
resetHashStorage()
|
||||
}
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.show()
|
||||
@ -247,11 +245,11 @@ class FingerprintPasswordHashSaver(private val activityContext: AppCompatActivit
|
||||
}
|
||||
} catch (e: IllegalBlockSizeException){
|
||||
stopListening()
|
||||
ColoredAlertDialog(activityContext)
|
||||
ColoredAlertDialogBuilder(activityContext)
|
||||
.setTitle(R.string.authentication_error)
|
||||
.setMessage(activityContext.getString(R.string.authentication_error_msg))
|
||||
.setPositiveButton(activityContext.getString(R.string.reset_hash_storage)) { _, _ ->
|
||||
reset_hash_storage()
|
||||
resetHashStorage()
|
||||
}
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.show()
|
||||
|
@ -5,7 +5,7 @@ import android.content.Intent
|
||||
import android.net.Uri
|
||||
import sushi.hardcore.droidfs.R
|
||||
import sushi.hardcore.droidfs.provider.RestrictedFileProvider
|
||||
import sushi.hardcore.droidfs.widgets.ColoredAlertDialog
|
||||
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
|
||||
import java.io.File
|
||||
import java.net.URLConnection
|
||||
import java.util.*
|
||||
@ -37,7 +37,7 @@ object ExternalProvider {
|
||||
return Pair(tmpFileUri, getContentType(fileName, previous_content_type))
|
||||
}
|
||||
}
|
||||
ColoredAlertDialog(context)
|
||||
ColoredAlertDialogBuilder(context)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(context.getString(R.string.export_failed, file_path))
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
|
@ -79,7 +79,7 @@ object Wiper {
|
||||
return false
|
||||
}
|
||||
}
|
||||
fun randomString(minSize: Int, maxSize: Int): String {
|
||||
private fun randomString(minSize: Int, maxSize: Int): String {
|
||||
val r = Random()
|
||||
val sb = StringBuilder()
|
||||
val length = r.nextInt(maxSize-minSize)+minSize
|
||||
|
@ -1,10 +1,11 @@
|
||||
package sushi.hardcore.droidfs.widgets
|
||||
|
||||
//import android.app.AlertDialog
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import android.content.Context
|
||||
|
||||
class ColoredAlertDialog(context: Context): AlertDialog.Builder(context) {
|
||||
class ColoredAlertDialogBuilder: AlertDialog.Builder {
|
||||
constructor(context: Context): super(context)
|
||||
constructor(context: Context, themeResId: Int): super(context, themeResId)
|
||||
private fun applyColor(dialog: AlertDialog){
|
||||
dialog.setOnShowListener{
|
||||
val themeColor = ThemeColor.getThemeColor(context)
|
@ -11,7 +11,7 @@ import android.widget.ListView
|
||||
import androidx.core.content.ContextCompat
|
||||
import sushi.hardcore.droidfs.R
|
||||
|
||||
class ColoredBorderListView: ListView {
|
||||
open class ColoredBorderListView: ListView {
|
||||
constructor(context: Context) : super(context) {
|
||||
applyColor()
|
||||
}
|
||||
|
@ -0,0 +1,30 @@
|
||||
package sushi.hardcore.droidfs.widgets
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import androidx.preference.ListPreference
|
||||
import sushi.hardcore.droidfs.R
|
||||
import sushi.hardcore.droidfs.adapters.DialogSingleChoiceAdapter
|
||||
|
||||
class ColoredListPreference: ListPreference {
|
||||
constructor(context: Context): super(context)
|
||||
constructor(context: Context, attrs: AttributeSet): super(context, attrs)
|
||||
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int): super(context, attrs, defStyleAttr)
|
||||
|
||||
override fun onAttached() {
|
||||
super.onAttached()
|
||||
summary = entries[entryValues.indexOf(getPersistedString(value))]
|
||||
}
|
||||
|
||||
override fun onClick() {
|
||||
ColoredAlertDialogBuilder(context)
|
||||
.setTitle(title)
|
||||
.setSingleChoiceItems(DialogSingleChoiceAdapter(context, entries.map { s -> s.toString() }.toTypedArray()), entryValues.indexOf(getPersistedString(value))) { dialog, which ->
|
||||
dialog.dismiss()
|
||||
summary = entries[which].toString()
|
||||
persistString(entryValues[which].toString())
|
||||
}
|
||||
.setNegativeButton(R.string.cancel) { dialog, _ -> dialog.dismiss() }
|
||||
.show()
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package sushi.hardcore.droidfs.widgets
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.widget.ListAdapter
|
||||
|
||||
class NonScrollableColoredBorderListView: ColoredBorderListView {
|
||||
constructor(context: Context) : super(context)
|
||||
constructor(context: Context, attrs: AttributeSet): super(context, attrs)
|
||||
|
||||
override fun setAdapter(adapter: ListAdapter?) {
|
||||
super.setAdapter(adapter)
|
||||
adapter?.let {
|
||||
var totalHeight = 0
|
||||
for (i in 0 until adapter.count){
|
||||
val item = adapter.getView(i, null, this)
|
||||
item.measure(0, 0)
|
||||
totalHeight += item.measuredHeight
|
||||
}
|
||||
layoutParams.height = totalHeight + (dividerHeight * (adapter.count-1))
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M6,19h4L10,5L6,5v14zM14,5v14h4L18,5h-4z"/>
|
||||
</vector>
|
@ -1,5 +0,0 @@
|
||||
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M8,5v14l11,-7z"/>
|
||||
</vector>
|
@ -1,5 +0,0 @@
|
||||
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FFFFFF" android:pathData="M6,6h12v12H6z"/>
|
||||
</vector>
|
@ -7,7 +7,6 @@
|
||||
<include layout="@layout/toolbar"/>
|
||||
|
||||
<ScrollView
|
||||
android:fillViewport="true"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
@ -94,7 +93,7 @@
|
||||
android:layout_width="@dimen/change_password_activity_label_width"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center_vertical"
|
||||
android:text="New Password (confirmation):"
|
||||
android:text="@string/new_password_confirmation"
|
||||
android:textSize="@dimen/edit_text_label_size" />
|
||||
|
||||
<sushi.hardcore.droidfs.widgets.ColoredEditText
|
||||
@ -123,7 +122,7 @@
|
||||
android:text="@string/fingerprint_save_checkbox_text"
|
||||
android:onClick="onClickSavePasswordHash"/>
|
||||
|
||||
<sushi.hardcore.droidfs.widgets.ColoredBorderListView
|
||||
<sushi.hardcore.droidfs.widgets.NonScrollableColoredBorderListView
|
||||
android:id="@+id/saved_path_listview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -7,7 +7,6 @@
|
||||
<include layout="@layout/toolbar"/>
|
||||
|
||||
<ScrollView
|
||||
android:fillViewport="true"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
@ -83,7 +82,7 @@
|
||||
android:text="@string/fingerprint_save_checkbox_text"
|
||||
android:onClick="onClickSavePasswordHash"/>
|
||||
|
||||
<sushi.hardcore.droidfs.widgets.ColoredBorderListView
|
||||
<sushi.hardcore.droidfs.widgets.NonScrollableColoredBorderListView
|
||||
android:id="@+id/saved_path_listview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@android:id/text1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="marquee"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="?android:attr/listPreferredItemHeightSmall"
|
||||
android:paddingEnd="16dp"
|
||||
android:paddingStart="24dp"
|
||||
android:textSize="@dimen/adapter_text_size"
|
||||
android:textColor="?android:attr/textColorAlertDialogListItem"
|
||||
android:drawableStart="?android:attr/listChoiceIndicatorSingle"
|
||||
android:drawablePadding="20dp"/>
|
@ -14,7 +14,7 @@
|
||||
android:id="@+id/text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="18sp"
|
||||
android:textSize="@dimen/adapter_text_size"
|
||||
android:layout_gravity="center"/>
|
||||
|
||||
</LinearLayout>
|
@ -19,7 +19,7 @@
|
||||
android:id="@+id/text_element_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="18sp"/>
|
||||
android:textSize="@dimen/adapter_text_size"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
|
@ -1,13 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ListView
|
||||
android:id="@+id/listview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
style="@style/listViewNoDivider"
|
||||
android:layout_marginTop="10dp"/>
|
||||
|
||||
</LinearLayout>
|
21
app/src/main/res/layout/dialog_loading.xml
Normal file
21
app/src/main/res/layout/dialog_loading.xml
Normal file
@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingHorizontal="20dp"
|
||||
android:paddingTop="10dp"
|
||||
android:paddingBottom="20dp">
|
||||
|
||||
<ProgressBar
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_message"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginHorizontal="10dp"/>
|
||||
|
||||
</LinearLayout>
|
@ -9,4 +9,5 @@
|
||||
<dimen name="change_password_activity_label_width">100dp</dimen>
|
||||
<dimen name="action_activity_button_hor_margin">60dp</dimen>
|
||||
<dimen name="action_activity_button_height">60dp</dimen>
|
||||
<dimen name="adapter_text_size">18sp</dimen>
|
||||
</resources>
|
@ -30,7 +30,7 @@
|
||||
<string name="success_volume_create_msg">The volume has been successfully created.</string>
|
||||
<string name="create_volume_failed">The volume creation has failed.</string>
|
||||
<string name="open_volume_failed">Open failed</string>
|
||||
<string name="open_volume_failed_msg">Failed to open the volume. Check the selected volume path and your password.</string>
|
||||
<string name="open_volume_failed_msg">Failed to open the volume. Check the selected volume path and the entered password.</string>
|
||||
<string name="share_chooser">Share File</string>
|
||||
<string name="storage_unavailable">Storage unavailable</string>
|
||||
<string name="storage_unavailable_msg">DroidFS can\'t work without storage access.</string>
|
||||
@ -64,7 +64,7 @@
|
||||
<string name="new_password">New password:</string>
|
||||
<string name="success_change_password">Password successfully changed !</string>
|
||||
<string name="success_change_password_msg">The volume\'s password has been successfully changed.</string>
|
||||
<string name="change_password_failed">Failed to change the volume\'s password. Check the selected volume path and your old password.</string>
|
||||
<string name="change_password_failed">Failed to change the volume\'s password. Check the selected volume path and the entered old password.</string>
|
||||
<string name="share_menu_label">Encrypt with DroidFS</string>
|
||||
<string name="share_intent_parsing_failed">Failed to handle the share request.</string>
|
||||
<string name="listdir_null_error_msg">Unable to access this directory</string>
|
||||
@ -121,4 +121,9 @@
|
||||
<string name="new_file">New File</string>
|
||||
<string name="enter_file_name">File name:</string>
|
||||
<string name="file_creation_failed">Failed to create the file.</string>
|
||||
<string name="loading">Loading...</string>
|
||||
<string name="loading_msg_create">Creating volume...</string>
|
||||
<string name="loading_msg_change_password">Changing password...</string>
|
||||
<string name="new_password_confirmation">New Password (confirmation):</string>
|
||||
<string name="loading_msg_open">Opening volume...</string>
|
||||
</resources>
|
||||
|
@ -13,14 +13,13 @@
|
||||
|
||||
<PreferenceCategory android:title="@string/explorer">
|
||||
|
||||
<ListPreference
|
||||
<sushi.hardcore.droidfs.widgets.ColoredListPreference
|
||||
app:defaultValue="name"
|
||||
app:entries="@array/sort_orders_entries"
|
||||
app:entryValues="@array/sort_orders_values"
|
||||
app:key="sort_order"
|
||||
android:title="@string/settings_title_sort_order"
|
||||
android:icon="@drawable/icon_sort"
|
||||
app:useSimpleSummaryProvider="true"/>
|
||||
android:icon="@drawable/icon_sort"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user