Skip to content

Commit 9d1487b

Browse files
committed
[UI Enhancement] Displayed File Name During Password Entry
Implemented a feature to show the file name on the password entry dialog, providing users with a clear context of the file they are accessing. This UI enhancement improves usability by ensuring users are aware of which specific file requires password authentication.
1 parent 3a3c7e3 commit 9d1487b

File tree

13 files changed

+94
-32
lines changed

13 files changed

+94
-32
lines changed

app/src/main/java/de/davis/passwordmanager/backup/StreamProvider.kt renamed to app/src/main/java/de/davis/passwordmanager/backup/BackupResourceProvider.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ package de.davis.passwordmanager.backup
33
import java.io.InputStream
44
import java.io.OutputStream
55

6-
interface StreamProvider {
6+
interface BackupResourceProvider {
77

88
suspend fun provideInputStream(): InputStream
99
suspend fun provideOutputStream(): OutputStream
10+
11+
suspend fun getFileName(): String
1012
}

app/src/main/java/de/davis/passwordmanager/backup/DataBackup.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,15 @@ abstract class DataBackup(private val backupListener: BackupListener = BackupLis
2525
}
2626
}
2727

28-
open suspend fun execute(backupOperation: BackupOperation, streamProvider: StreamProvider) {
28+
open suspend fun execute(
29+
backupOperation: BackupOperation,
30+
backupResourceProvider: BackupResourceProvider
31+
) {
2932
backupListener.run {
3033
runCatching {
3134
withContext(Dispatchers.Main) { onStart(backupOperation) }
3235

33-
streamProvider.run {
36+
backupResourceProvider.run {
3437
progressContext.run {
3538
when (backupOperation) {
3639
BackupOperation.IMPORT -> provideInputStream().use { runImport(it) }

app/src/main/java/de/davis/passwordmanager/backup/PasswordProvider.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ interface PasswordProvider {
44

55
suspend operator fun invoke(
66
backupOperation: BackupOperation,
7+
backupResourceProvider: BackupResourceProvider,
78
callback: suspend (password: String) -> Unit
89
)
910
}

app/src/main/java/de/davis/passwordmanager/backup/SecureDataBackup.kt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,13 @@ abstract class SecureDataBackup(
2727
final override suspend fun ProgressContext.runExport(outputStream: OutputStream): BackupResult =
2828
runExport(outputStream, password)
2929

30-
override suspend fun execute(backupOperation: BackupOperation, streamProvider: StreamProvider) {
31-
passwordProvider(backupOperation) {
30+
override suspend fun execute(
31+
backupOperation: BackupOperation,
32+
backupResourceProvider: BackupResourceProvider
33+
) {
34+
passwordProvider(backupOperation, backupResourceProvider) {
3235
password = it
33-
super.execute(backupOperation, streamProvider)
36+
super.execute(backupOperation, backupResourceProvider)
3437
}
3538
}
3639
}

app/src/main/java/de/davis/passwordmanager/backup/impl/AndroidPasswordProvider.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import androidx.appcompat.content.res.AppCompatResources
1010
import com.google.android.material.textfield.TextInputLayout
1111
import de.davis.passwordmanager.R
1212
import de.davis.passwordmanager.backup.BackupOperation
13+
import de.davis.passwordmanager.backup.BackupResourceProvider
1314
import de.davis.passwordmanager.backup.PasswordProvider
1415
import de.davis.passwordmanager.dialog.EditDialogBuilder
1516
import de.davis.passwordmanager.ui.views.InformationView
@@ -22,6 +23,7 @@ import kotlinx.coroutines.withContext
2223
class AndroidPasswordProvider(private val context: Context) : PasswordProvider {
2324
override suspend fun invoke(
2425
backupOperation: BackupOperation,
26+
backupResourceProvider: BackupResourceProvider,
2527
callback: suspend (password: String) -> Unit
2628
) {
2729
withContext(Dispatchers.Main) {
@@ -33,6 +35,12 @@ class AndroidPasswordProvider(private val context: Context) : PasswordProvider {
3335

3436
EditDialogBuilder(context).apply {
3537
setTitle(R.string.password)
38+
setMessage(
39+
context.getString(
40+
R.string.enter_password_for_s,
41+
backupResourceProvider.getFileName()
42+
)
43+
)
3644
setPositiveButton(R.string.yes) { _: DialogInterface?, _: Int -> }
3745
setButtonListener(
3846
DialogInterface.BUTTON_POSITIVE,

app/src/main/java/de/davis/passwordmanager/backup/impl/KdbxBackup.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,7 @@ class KdbxBackup(
3939
inputStream: InputStream,
4040
password: String
4141
): BackupResult {
42-
val database =
43-
inputStream.use { KeePassDatabase.decode(it, credentialFactory(password)) }
42+
val database = inputStream.use { KeePassDatabase.decode(it, credentialFactory(password)) }
4443

4544
val existingElements = SecureElementManager.getSecureElements(ElementType.PASSWORD.typeId)
4645
val elementsToAdd = mutableListOf<SecureElement>()
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package de.davis.passwordmanager.backup.impl
2+
3+
import android.annotation.SuppressLint
4+
import android.content.ContentResolver
5+
import android.database.Cursor
6+
import android.net.Uri
7+
import android.provider.OpenableColumns
8+
import de.davis.passwordmanager.backup.BackupResourceProvider
9+
import kotlinx.coroutines.Dispatchers
10+
import kotlinx.coroutines.withContext
11+
import java.io.InputStream
12+
import java.io.OutputStream
13+
14+
class UriBackupResourceProvider(
15+
private var uri: Uri,
16+
private var contentResolver: ContentResolver
17+
) : BackupResourceProvider {
18+
19+
override suspend fun provideInputStream(): InputStream = contentResolver.openInputStream(uri)
20+
?: throw IllegalStateException("ContentResolver returned null")
21+
22+
override suspend fun provideOutputStream(): OutputStream = contentResolver.openOutputStream(uri)
23+
?: throw IllegalStateException("ContentResolver returned null")
24+
25+
override suspend fun getFileName(): String = contentResolver.getFileName(uri) ?: "Unknown"
26+
27+
private suspend fun ContentResolver.getFileName(uri: Uri): String? =
28+
withContext(Dispatchers.IO) {
29+
var fileName: String? = null
30+
if (uri.scheme == ContentResolver.SCHEME_CONTENT) {
31+
val cursor: Cursor? = query(uri, null, null, null, null)
32+
cursor?.use {
33+
if (it.moveToFirst()) {
34+
@SuppressLint("Range")
35+
fileName = it.getString(it.getColumnIndex(OpenableColumns.DISPLAY_NAME))
36+
}
37+
}
38+
} else if (uri.scheme == ContentResolver.SCHEME_FILE) {
39+
fileName = uri.lastPathSegment
40+
}
41+
42+
fileName
43+
}
44+
}

app/src/main/java/de/davis/passwordmanager/backup/impl/UriStreamProvider.kt

Lines changed: 0 additions & 17 deletions
This file was deleted.

app/src/main/java/de/davis/passwordmanager/ui/backup/BackupFragment.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import de.davis.passwordmanager.backup.impl.AndroidBackupListener
2121
import de.davis.passwordmanager.backup.impl.AndroidPasswordProvider
2222
import de.davis.passwordmanager.backup.impl.CsvBackup
2323
import de.davis.passwordmanager.backup.impl.KdbxBackup
24-
import de.davis.passwordmanager.backup.impl.UriStreamProvider
24+
import de.davis.passwordmanager.backup.impl.UriBackupResourceProvider
2525
import de.davis.passwordmanager.ktx.getParcelableCompat
2626
import de.davis.passwordmanager.ui.auth.AuthenticationRequest
2727
import de.davis.passwordmanager.ui.auth.createRequestAuthenticationIntent
@@ -95,7 +95,7 @@ class BackupFragment : PreferenceFragmentCompat() {
9595
backup: DataBackup
9696
): ActivityResultLauncher<T> {
9797
val createStreamProvider = { uri: Uri ->
98-
UriStreamProvider(uri, requireContext().contentResolver)
98+
UriBackupResourceProvider(uri, requireContext().contentResolver)
9999
}
100100

101101
return registerForActivityResult(contract) { uri: Uri? ->

app/src/main/java/de/davis/passwordmanager/ui/sync/ImportActivity.kt

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,18 @@ import androidx.activity.result.ActivityResult
77
import androidx.activity.result.contract.ActivityResultContracts
88
import androidx.appcompat.app.AppCompatActivity
99
import androidx.lifecycle.lifecycleScope
10+
import de.davis.passwordmanager.R
1011
import de.davis.passwordmanager.backup.BackupOperation
1112
import de.davis.passwordmanager.backup.BackupResult
1213
import de.davis.passwordmanager.backup.impl.AndroidBackupListener
1314
import de.davis.passwordmanager.backup.impl.AndroidPasswordProvider
1415
import de.davis.passwordmanager.backup.impl.KdbxBackup
15-
import de.davis.passwordmanager.backup.impl.UriStreamProvider
16+
import de.davis.passwordmanager.backup.impl.UriBackupResourceProvider
1617
import de.davis.passwordmanager.databinding.ActivityImportBinding
1718
import de.davis.passwordmanager.ui.MainActivity
1819
import de.davis.passwordmanager.ui.auth.AuthenticationRequest
1920
import de.davis.passwordmanager.ui.auth.createRequestAuthenticationIntent
21+
import kotlinx.coroutines.Dispatchers
2022
import kotlinx.coroutines.launch
2123

2224
class ImportActivity : AppCompatActivity() {
@@ -46,18 +48,32 @@ class ImportActivity : AppCompatActivity() {
4648
layoutInflater
4749
)
4850
setContentView(binding.root)
51+
val fileUri = intent.data ?: run {
52+
finish()
53+
return
54+
}
55+
56+
val uriBackupResourceProvider = UriBackupResourceProvider(fileUri, contentResolver)
57+
58+
lifecycleScope.launch(Dispatchers.Main) {
59+
binding.informationView.setInformationText(
60+
getString(
61+
R.string.authenticate_to_import,
62+
uriBackupResourceProvider.getFileName()
63+
)
64+
)
65+
}
4966

5067
val auth =
5168
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result: ActivityResult ->
5269
if (result.resultCode != RESULT_OK) return@registerForActivityResult
5370
if (intent.action == null) return@registerForActivityResult
5471
if (intent.action != Intent.ACTION_VIEW) return@registerForActivityResult
55-
val fileUri = intent.data ?: return@registerForActivityResult
5672

5773
lifecycleScope.launch {
5874
kdbxBackup.execute(
5975
BackupOperation.IMPORT,
60-
UriStreamProvider(fileUri, contentResolver)
76+
UriBackupResourceProvider(fileUri, contentResolver)
6177
)
6278
}
6379
}

0 commit comments

Comments
 (0)