Compare commits
15 Commits
update-usf
...
master
Author | SHA1 | Date | |
---|---|---|---|
82dda95211 | |||
40bed2db21 | |||
f901495e41 | |||
07f5f8b5d9 | |||
2d5f5a82c9 | |||
b477272d65 | |||
88bd746359 | |||
9872cab7c2 | |||
4aa211bca4 | |||
0a1406769b | |||
a62f32e364 | |||
f865c864a2 | |||
e804059b23 | |||
|
bb821d5f41 | ||
6c0e20c68e |
77
README.md
@ -28,41 +28,47 @@ Do not use this app with volumes containing sensitive data unless you know exact
|
||||
- Unlocking volumes using fingerprint authentication
|
||||
- Volume auto-locking when the app goes in background
|
||||
|
||||
_For upcoming features, see [TODO.md](https://forge.chapril.org/hardcoresushi/DroidFS/src/branch/master/TODO.md)._
|
||||
For planned features, see [TODO.md](https://forge.chapril.org/hardcoresushi/DroidFS/src/branch/master/TODO.md).
|
||||
|
||||
# Unsafe features
|
||||
Some available features are considered risky and are therefore disabled by default. It is strongly recommended that you read the following documentation if you wish to activate one of these options.
|
||||
|
||||
<ul>
|
||||
<li><h4>Allow screenshots:</h4>
|
||||
<li><b>Allow screenshots:</b>
|
||||
|
||||
Disable the secure flag of DroidFS activities. This will allow you to take screenshots from the app, but will also allow other apps to record the screen while using DroidFS.
|
||||
|
||||
Note: apps with root access don't care about this flag: they can take screenshots or record the screen of any app without any permissions.
|
||||
</li>
|
||||
<li><h4>Allow exporting files:</h4>
|
||||
Decrypt and write file to disk (external storage). Any app with storage permissions could access exported files.
|
||||
</li>
|
||||
<li><h4>Allow sharing files via the android share menu*:</h4>
|
||||
Decrypt and share file with other apps. These apps could save and send the files thus shared.
|
||||
</li>
|
||||
<li><h4>Allow saving password hash using fingerprint:</h4>
|
||||
Generate an AES-256 GCM key in the Android Keystore (protected by fingerprint authentication), then use it to encrypt the volume password hash and store it to the DroidFS internal storage. This require Android v6.0+. If your device is not encrypted, extracting the encryption key with physical access may be possible.
|
||||
</li>
|
||||
<li><h4>Keep volume open when the app goes in background:</h4>
|
||||
Don't close the volume when you leave the app but keep running it in the background. Anyone going back to the activity could have access to the volume.
|
||||
</li>
|
||||
<li><h4>Allow opening files with other applications*:</h4>
|
||||
Decrypt and open file using external apps. These apps could save and send the files thus opened.
|
||||
</li>
|
||||
<li><h4>Expose open volumes*:</h4>
|
||||
Allow open volumes to be browsed in the system file explorer (<a href="https://developer.android.com/guide/topics/providers/document-provider">DocumentProvider</a> API). Encrypted files can then be selected from other applications, potentially with permanent access. This feature requires <i>"Keep volume open when the app goes in background"</i> to be enabled.
|
||||
</li>
|
||||
<li><h4>Grant write access:</h4>
|
||||
Files opened with another applications can be modified by them. This applies to both previous unsafe features.
|
||||
</li>
|
||||
Note: apps with root access don't care about this flag: they can take screenshots or record the screen of any app without any permissions.</li>
|
||||
<li><b>Allow exporting files:</b>
|
||||
|
||||
Decrypt and write file to disk (external storage). Any app with storage permissions could access exported files.</li>
|
||||
<li><b>Allow sharing files via the android share menu⁽¹⁾:</b>
|
||||
|
||||
Decrypt and share file with other apps. These apps could save and send the files thus shared.</li>
|
||||
<li><b>Allow saving password hash using fingerprint:</b>
|
||||
|
||||
Generate an AES-256 GCM key in the Android Keystore (protected by fingerprint authentication), then use it to encrypt the volume password hash and store it to the DroidFS internal storage. This require Android v6.0+. If your device is not encrypted, extracting the encryption key with physical access may be possible.</li>
|
||||
<li><b>Disable volume auto-locking:</b> (previously called <i>"Keep volumes open when the app goes in background"</i>)
|
||||
|
||||
Don't close open volumes when you leave the app. Anyone going back to the application could have access to open volumes. Cryptographic secrets are kept in memory for an undefined amount of time.</li>
|
||||
<li><b>Keep volumes open:</b>
|
||||
(Different from the old <i>"Keep volumes open when the app goes in background"</i>. Yes it's confusing, sorry)
|
||||
|
||||
Keep the app running as a [foreground service](https://developer.android.com/develop/background-work/services/foreground-services) to maintain volumes open, even when the app is removed from recent tasks.
|
||||
|
||||
This avoid the app from being killed by the system during file operations or while accessing exposed volumes, but this mean cryptographic secrets stay in memory for an undefined amount of time.</li>
|
||||
<li><b>Allow opening files with other applications⁽¹⁾:</b>
|
||||
|
||||
Decrypt and open file using external apps. These apps could save and send the files thus opened.</li>
|
||||
<li><b>Expose open volumes⁽¹⁾:</b>
|
||||
|
||||
Allow open volumes to be browsed in the system file explorer (<a href="https://developer.android.com/guide/topics/providers/document-provider">DocumentProvider</a> API). Encrypted files can then be selected from other applications, potentially with permanent access. This feature requires <i>"Disable volume auto-locking"</i>, and works more reliably when <i>"Keep volumes open"</i> is also enabled.</li>
|
||||
<li><b>Grant write access:</b>
|
||||
|
||||
Files opened with another applications can be modified by them. This applies to both previous unsafe features.</li>
|
||||
</ul>
|
||||
|
||||
\* These features can work in two ways: temporarily writing the plain file to disk (DroidFS internal storage) or sharing it via memory. By default, DroidFS will choose to keep the file only in memory as it's more secure, but will fallback to disk export if the file is too large to be held in memory. This behavior can be changed with the *"Export method"* parameter in the settings. Please note that some applications require the file to be stored on disk, and therefore do not work with memory-exported files.
|
||||
⁽¹⁾: These features can work in two ways: temporarily writing the plain file to disk (DroidFS internal storage) or sharing it via memory. By default, DroidFS will choose to keep the file only in memory as it's more secure, but will fallback to disk export if the file is too large to be held in memory. This behavior can be changed with the *"Export method"* parameter in the settings. Please note that some applications require the file to be stored on disk, and therefore do not work with memory-exported files.
|
||||
|
||||
# Download
|
||||
<a href="https://f-droid.org/packages/sushi.hardcore.droidfs">
|
||||
@ -90,20 +96,11 @@ F-Droid APKs should be signed with the F-Droid key. More details [here](https://
|
||||
# Permissions
|
||||
DroidFS needs some permissions for certain features. However, you are free to deny them if you do not wish to use these features.
|
||||
|
||||
<ul>
|
||||
<li><h4>Read & write access to shared storage:</h4>
|
||||
Required to access volumes located on shared storage.
|
||||
</li>
|
||||
<li><h4>Biometric/Fingerprint hardware:</h4>
|
||||
Required to encrypt/decrypt password hashes using a fingerprint protected key.
|
||||
</li>
|
||||
<li><h4>Camera:</h4>
|
||||
Required to take encrypted photos or videos directly from the app.
|
||||
</li>
|
||||
<li><h4>Record audio:</h4>
|
||||
Required if you want sound on video recorded with DroidFS.
|
||||
</li>
|
||||
</ul>
|
||||
- **Read & write access to shared storage**: Required to access volumes located on shared storage.
|
||||
- **Biometric/Fingerprint hardware**: Required to encrypt/decrypt password hashes using a fingerprint protected key.
|
||||
- **Camera**: Required to take encrypted photos or videos directly from the app.
|
||||
- **Record audio**: Required if you want sound on video recorded with DroidFS.
|
||||
- **Notifications**: Used to report file operations progress and notify about volumes kept open.
|
||||
|
||||
# Limitations
|
||||
DroidFS works as a wrapper around modified versions of the original encrypted container implementations ([libgocryptfs](https://forge.chapril.org/hardcoresushi/libgocryptfs) and [libcryfs](https://forge.chapril.org/hardcoresushi/libcryfs)). These programs were designed to run on standard x86 Linux systems: they access the underlying file system with file paths and syscalls. However, on Android, you can't access files from other applications using file paths. Instead, one has to use the [ContentProvider](https://developer.android.com/guide/topics/providers/content-providers) API. Obviously, neither Gocryptfs nor CryFS support this API. As a result, DroidFS cannot open volumes provided by other applications (such as cloud storage clients). If you want to synchronize your volumes on a cloud, the cloud application must synchronize the encrypted directory from disk.
|
||||
|
4
TODO.md
@ -10,7 +10,7 @@ Here's a list of features that it would be nice to have in DroidFS. As this is a
|
||||
- File associations editor
|
||||
- Discovery before exporting
|
||||
- Making discovery before file operations optional
|
||||
- Modifiable CryFS scrypt parameters
|
||||
- Modifiable scrypt parameters
|
||||
- Alert dialog showing details of file operations
|
||||
- Internal file browser to select volumes
|
||||
|
||||
@ -19,8 +19,6 @@ Here's a list of features that it would be nice to have in DroidFS. As this is a
|
||||
- [fscrypt](https://www.kernel.org/doc/html/latest/filesystems/fscrypt.html): filesystem encryption at the kernel level
|
||||
|
||||
## Health
|
||||
- F-Droid ABI split
|
||||
- OpenSSL & FFmpeg as git submodules (useful for F-Droid)
|
||||
- Remove all android:configChanges from AndroidManifest.xml
|
||||
- More efficient thumbnails cache
|
||||
- Guide for translators
|
||||
|
@ -27,14 +27,14 @@ android {
|
||||
jvmTarget = "17"
|
||||
}
|
||||
|
||||
def abiCodes = [ "arm64-v8a": 1, "armeabi-v7a": 2, "x86_64": 3, "x86": 4]
|
||||
def abiCodes = [ "x86": 1, "x86_64": 2, "armeabi-v7a": 3, "arm64-v8a": 4]
|
||||
|
||||
defaultConfig {
|
||||
applicationId "sushi.hardcore.droidfs"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 34
|
||||
versionCode 36
|
||||
versionName "2.1.3"
|
||||
versionCode 37
|
||||
versionName "2.2.0"
|
||||
|
||||
splits {
|
||||
abi {
|
||||
|
@ -9,6 +9,8 @@ import android.system.Os
|
||||
import android.util.Log
|
||||
import androidx.preference.PreferenceManager
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import sushi.hardcore.droidfs.filesystems.EncryptedVolume
|
||||
import sushi.hardcore.droidfs.util.Compat
|
||||
@ -86,9 +88,11 @@ class EncryptedFileProvider(context: Context) {
|
||||
}
|
||||
|
||||
override fun free() {
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
Wiper.wipe(file)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ExportedMemFile private constructor(path: String, private val file: MemFile) :
|
||||
ExportedFile(path) {
|
||||
@ -160,8 +164,10 @@ class EncryptedFileProvider(context: Context) {
|
||||
exportedFile: ExportedFile,
|
||||
encryptedVolume: EncryptedVolume,
|
||||
): Boolean {
|
||||
val fd = exportedFile.open(ParcelFileDescriptor.MODE_WRITE_ONLY, false).fileDescriptor
|
||||
return encryptedVolume.exportFile(exportedFile.path, FileOutputStream(fd))
|
||||
val pfd = exportedFile.open(ParcelFileDescriptor.MODE_WRITE_ONLY, false)
|
||||
return encryptedVolume.exportFile(exportedFile.path, FileOutputStream(pfd.fileDescriptor)).also {
|
||||
pfd.close()
|
||||
}
|
||||
}
|
||||
|
||||
enum class Error {
|
||||
|
@ -4,8 +4,8 @@ import java.io.File
|
||||
|
||||
object FileTypes {
|
||||
private val FILE_EXTENSIONS = mapOf(
|
||||
Pair("image", listOf("png", "jpg", "jpeg", "gif", "webp", "bmp", "heic")),
|
||||
Pair("video", listOf("mp4", "webm", "mkv", "mov")),
|
||||
Pair("image", listOf("png", "jpg", "jpeg", "gif", "avif", "webp", "bmp", "heic")),
|
||||
Pair("video", listOf("mp4", "webm", "mkv", "mov", "m4v")),
|
||||
Pair("audio", listOf("mp3", "ogg", "m4a", "wav", "flac", "opus")),
|
||||
Pair("pdf", listOf("pdf")),
|
||||
Pair("text", listOf(
|
||||
|
@ -177,25 +177,32 @@ class SettingsActivity : BaseActivity() {
|
||||
val switchExpose = findPreference<SwitchPreference>("usf_expose")!!
|
||||
val switchSafWrite = findPreference<SwitchPreference>("usf_saf_write")!!
|
||||
|
||||
fun updateView(usfOpen: Boolean? = null, usfBackground: Boolean? = null, usfExpose: Boolean? = null) {
|
||||
val usfBackground = usfBackground ?: switchBackground.isChecked
|
||||
switchKeepOpen.isEnabled = usfBackground
|
||||
switchExpose.isEnabled = usfBackground
|
||||
switchSafWrite.isEnabled = usfOpen ?: switchExternalOpen.isChecked || (usfBackground && usfExpose ?: switchExpose.isChecked)
|
||||
fun onUsfBackgroundChanged(usfBackground: Boolean) {
|
||||
fun updateSwitchPreference(switch: SwitchPreference) = with (switch) {
|
||||
isChecked = isChecked && usfBackground
|
||||
isEnabled = usfBackground
|
||||
onPreferenceChangeListener?.onPreferenceChange(switch, isChecked)
|
||||
}
|
||||
updateSwitchPreference(switchKeepOpen)
|
||||
updateSwitchPreference(switchExpose)
|
||||
}
|
||||
onUsfBackgroundChanged(switchBackground.isChecked)
|
||||
|
||||
fun updateSafWrite(usfOpen: Boolean? = null, usfExpose: Boolean? = null) {
|
||||
switchSafWrite.isEnabled = usfOpen ?: switchExternalOpen.isChecked || usfExpose ?: switchExpose.isChecked
|
||||
}
|
||||
updateSafWrite()
|
||||
|
||||
updateView()
|
||||
switchBackground.setOnPreferenceChangeListener { _, checked ->
|
||||
updateView(usfBackground = checked as Boolean)
|
||||
switchKeepOpen.isChecked = switchKeepOpen.isChecked && checked
|
||||
onUsfBackgroundChanged(checked as Boolean)
|
||||
true
|
||||
}
|
||||
switchExternalOpen.setOnPreferenceChangeListener { _, checked ->
|
||||
updateView(usfOpen = checked as Boolean)
|
||||
updateSafWrite(usfOpen = checked as Boolean)
|
||||
true
|
||||
}
|
||||
switchExpose.setOnPreferenceChangeListener { _, checked ->
|
||||
updateView(usfExpose = checked as Boolean)
|
||||
updateSafWrite(usfExpose = checked as Boolean)
|
||||
VolumeProvider.notifyRootsChanged(requireContext())
|
||||
true
|
||||
}
|
||||
|
@ -258,9 +258,8 @@ class SelectPathFragment: Fragment() {
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
} else {
|
||||
binding.editVolumeName.setText(path)
|
||||
inputViewModel.showEditText = true
|
||||
updateUi(path)
|
||||
binding.editVolumeName.setText(path)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -328,8 +328,8 @@ class ExplorerActivity : BaseExplorerActivity() {
|
||||
activityScope.launch {
|
||||
onTaskResult(
|
||||
fileOperationService.moveElements(volumeId, toMove, toClean),
|
||||
R.string.move_success,
|
||||
R.string.move_failed,
|
||||
R.string.move_success,
|
||||
)
|
||||
setCurrentPath(currentDirectoryPath)
|
||||
}
|
||||
|
@ -104,7 +104,9 @@ class FileOperationService : Service() {
|
||||
activity.lifecycle.addObserver(object : DefaultLifecycleObserver {
|
||||
override fun onDestroy(owner: LifecycleOwner) {
|
||||
activity.unbindService(serviceConnection)
|
||||
service.notificationPermissionHelpers.removeLast()
|
||||
// Could have been more efficient with a LinkedHashMap but the JDK implementation doesn't allow
|
||||
// to access the latest element in O(1) unless using reflection
|
||||
service.notificationPermissionHelpers.removeAll { it.activity == activity }
|
||||
}
|
||||
})
|
||||
activity.bindService(
|
||||
|
@ -14,6 +14,8 @@ import androidx.lifecycle.lifecycleScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.coroutines.withContext
|
||||
import sushi.hardcore.droidfs.BaseActivity
|
||||
import sushi.hardcore.droidfs.FileTypes
|
||||
@ -21,7 +23,6 @@ import sushi.hardcore.droidfs.R
|
||||
import sushi.hardcore.droidfs.VolumeManagerApp
|
||||
import sushi.hardcore.droidfs.explorers.ExplorerElement
|
||||
import sushi.hardcore.droidfs.filesystems.EncryptedVolume
|
||||
import sushi.hardcore.droidfs.util.IntentUtils
|
||||
import sushi.hardcore.droidfs.util.PathUtils
|
||||
import sushi.hardcore.droidfs.util.finishOnClose
|
||||
import sushi.hardcore.droidfs.widgets.CustomAlertDialogBuilder
|
||||
@ -32,9 +33,8 @@ abstract class FileViewerActivity: BaseActivity() {
|
||||
private lateinit var originalParentPath: String
|
||||
private lateinit var windowInsetsController: WindowInsetsControllerCompat
|
||||
private var windowTypeMask = 0
|
||||
private var foldersFirst = true
|
||||
private var wasMapped = false
|
||||
protected val mappedPlaylist = mutableListOf<ExplorerElement>()
|
||||
protected val playlist = mutableListOf<ExplorerElement>()
|
||||
private val playlistMutex = Mutex()
|
||||
protected var currentPlaylistIndex = -1
|
||||
private val isLegacyFullscreen = Build.VERSION.SDK_INT <= Build.VERSION_CODES.R
|
||||
|
||||
@ -46,7 +46,6 @@ abstract class FileViewerActivity: BaseActivity() {
|
||||
intent.getIntExtra("volumeId", -1)
|
||||
)!!
|
||||
finishOnClose(encryptedVolume)
|
||||
foldersFirst = sharedPrefs.getBoolean("folders_first", true)
|
||||
windowInsetsController = WindowInsetsControllerCompat(window, window.decorView)
|
||||
windowInsetsController.addOnControllableInsetsChangedListener { _, typeMask ->
|
||||
windowTypeMask = typeMask
|
||||
@ -131,48 +130,57 @@ abstract class FileViewerActivity: BaseActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
protected fun createPlaylist() {
|
||||
if (!wasMapped){
|
||||
encryptedVolume.recursiveMapFiles(originalParentPath)?.let { elements ->
|
||||
for (e in elements) {
|
||||
if (e.isRegularFile) {
|
||||
if (FileTypes.isExtensionType(getFileType(), e.name) || filePath == e.fullPath) {
|
||||
mappedPlaylist.add(e)
|
||||
}
|
||||
}
|
||||
protected suspend fun createPlaylist() {
|
||||
playlistMutex.withLock {
|
||||
if (currentPlaylistIndex != -1) {
|
||||
// playlist already initialized
|
||||
return
|
||||
}
|
||||
withContext(Dispatchers.IO) {
|
||||
if (sharedPrefs.getBoolean("map_folders", true)) {
|
||||
encryptedVolume.recursiveMapFiles(originalParentPath)
|
||||
} else {
|
||||
encryptedVolume.readDir(originalParentPath)
|
||||
}?.filterTo(playlist) { e ->
|
||||
e.isRegularFile && (FileTypes.isExtensionType(getFileType(), e.name) || filePath == e.fullPath)
|
||||
}
|
||||
val sortOrder = intent.getStringExtra("sortOrder") ?: "name"
|
||||
ExplorerElement.sortBy(sortOrder, foldersFirst, mappedPlaylist)
|
||||
//find current index
|
||||
for ((i, e) in mappedPlaylist.withIndex()){
|
||||
if (filePath == e.fullPath){
|
||||
currentPlaylistIndex = i
|
||||
break
|
||||
val foldersFirst = sharedPrefs.getBoolean("folders_first", true)
|
||||
ExplorerElement.sortBy(sortOrder, foldersFirst, playlist)
|
||||
currentPlaylistIndex = playlist.indexOfFirst { it.fullPath == filePath }
|
||||
}
|
||||
}
|
||||
wasMapped = true
|
||||
}
|
||||
}
|
||||
|
||||
protected fun playlistNext(forward: Boolean) {
|
||||
private fun updateCurrentItem() {
|
||||
filePath = playlist[currentPlaylistIndex].fullPath
|
||||
}
|
||||
|
||||
protected suspend fun playlistNext(forward: Boolean) {
|
||||
createPlaylist()
|
||||
currentPlaylistIndex = if (forward) {
|
||||
(currentPlaylistIndex+1)%mappedPlaylist.size
|
||||
(currentPlaylistIndex + 1).mod(playlist.size)
|
||||
} else {
|
||||
var x = (currentPlaylistIndex-1)%mappedPlaylist.size
|
||||
if (x < 0) {
|
||||
x += mappedPlaylist.size
|
||||
(currentPlaylistIndex - 1).mod(playlist.size)
|
||||
}
|
||||
x
|
||||
}
|
||||
filePath = mappedPlaylist[currentPlaylistIndex].fullPath
|
||||
updateCurrentItem()
|
||||
}
|
||||
|
||||
protected fun refreshPlaylist() {
|
||||
mappedPlaylist.clear()
|
||||
wasMapped = false
|
||||
createPlaylist()
|
||||
protected suspend fun deleteCurrentFile(): Boolean {
|
||||
createPlaylist() // ensure we know the current position in the playlist
|
||||
return if (encryptedVolume.deleteFile(filePath)) {
|
||||
playlist.removeAt(currentPlaylistIndex)
|
||||
if (playlist.size != 0) {
|
||||
if (currentPlaylistIndex == playlist.size) {
|
||||
// deleted the last element of the playlist, go back to the first
|
||||
currentPlaylistIndex = 0
|
||||
}
|
||||
updateCurrentItem()
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
protected fun goBackToExplorer() {
|
||||
|
@ -12,10 +12,12 @@ import android.widget.Toast
|
||||
import androidx.activity.addCallback
|
||||
import androidx.activity.viewModels
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.RequestBuilder
|
||||
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool
|
||||
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation
|
||||
import kotlinx.coroutines.launch
|
||||
import sushi.hardcore.droidfs.Constants
|
||||
import sushi.hardcore.droidfs.R
|
||||
import sushi.hardcore.droidfs.databinding.ActivityImageViewerBinding
|
||||
@ -105,17 +107,15 @@ class ImageViewer: FileViewerActivity() {
|
||||
.keepFullScreen()
|
||||
.setTitle(R.string.warning)
|
||||
.setPositiveButton(R.string.ok) { _, _ ->
|
||||
createPlaylist() //be sure the playlist is created before deleting if there is only one image
|
||||
if (encryptedVolume.deleteFile(filePath)) {
|
||||
playlistNext(true)
|
||||
refreshPlaylist()
|
||||
if (mappedPlaylist.size == 0) { //deleted all images of the playlist
|
||||
lifecycleScope.launch {
|
||||
if (deleteCurrentFile()) {
|
||||
if (playlist.size == 0) { // no more image left
|
||||
goBackToExplorer()
|
||||
} else {
|
||||
loadImage(true)
|
||||
}
|
||||
} else {
|
||||
CustomAlertDialogBuilder(this, theme)
|
||||
CustomAlertDialogBuilder(this@ImageViewer, theme)
|
||||
.keepFullScreen()
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(getString(R.string.remove_failed, fileName))
|
||||
@ -123,6 +123,7 @@ class ImageViewer: FileViewerActivity() {
|
||||
.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.setMessage(getString(R.string.single_delete_confirm, fileName))
|
||||
.show()
|
||||
@ -199,6 +200,7 @@ class ImageViewer: FileViewerActivity() {
|
||||
}
|
||||
|
||||
private fun swipeImage(deltaX: Float, slideshowSwipe: Boolean = false) {
|
||||
lifecycleScope.launch {
|
||||
playlistNext(deltaX < 0)
|
||||
loadImage(true)
|
||||
if (slideshowActive) {
|
||||
@ -208,6 +210,7 @@ class ImageViewer: FileViewerActivity() {
|
||||
handler.postDelayed(slideshowNext, Constants.SLIDESHOW_DELAY)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun stopSlideshow(){
|
||||
slideshowActive = false
|
||||
|
@ -2,6 +2,7 @@ package sushi.hardcore.droidfs.file_viewers
|
||||
|
||||
import android.view.WindowManager
|
||||
import androidx.annotation.OptIn
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.media3.common.MediaItem
|
||||
import androidx.media3.common.PlaybackException
|
||||
import androidx.media3.common.Player
|
||||
@ -11,6 +12,7 @@ import androidx.media3.exoplayer.ExoPlayer
|
||||
import androidx.media3.exoplayer.source.MediaSource
|
||||
import androidx.media3.exoplayer.source.ProgressiveMediaSource
|
||||
import androidx.media3.extractor.DefaultExtractorsFactory
|
||||
import kotlinx.coroutines.launch
|
||||
import sushi.hardcore.droidfs.Constants
|
||||
import sushi.hardcore.droidfs.R
|
||||
import sushi.hardcore.droidfs.widgets.CustomAlertDialogBuilder
|
||||
@ -39,12 +41,16 @@ abstract class MediaPlayer: FileViewerActivity() {
|
||||
private fun initializePlayer(){
|
||||
player = ExoPlayer.Builder(this).setSeekForwardIncrementMs(5000).build()
|
||||
bindPlayer(player)
|
||||
player.addMediaSource(createMediaSource(filePath))
|
||||
lifecycleScope.launch {
|
||||
createPlaylist()
|
||||
for (e in mappedPlaylist) {
|
||||
player.addMediaSource(createMediaSource(e.fullPath))
|
||||
playlist.forEachIndexed { index, e ->
|
||||
if (index != currentPlaylistIndex) {
|
||||
player.addMediaSource(index, createMediaSource(e.fullPath))
|
||||
}
|
||||
}
|
||||
}
|
||||
player.repeatMode = Player.REPEAT_MODE_ALL
|
||||
player.seekToDefaultPosition(currentPlaylistIndex)
|
||||
player.playWhenReady = true
|
||||
player.addListener(object : Player.Listener{
|
||||
override fun onVideoSizeChanged(videoSize: VideoSize) {
|
||||
@ -67,11 +73,13 @@ abstract class MediaPlayer: FileViewerActivity() {
|
||||
}
|
||||
|
||||
override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) {
|
||||
if (player.repeatMode != Player.REPEAT_MODE_ONE) {
|
||||
playlistNext(player.currentMediaItemIndex == (currentPlaylistIndex + 1) % mappedPlaylist.size)
|
||||
if (player.repeatMode != Player.REPEAT_MODE_ONE && currentPlaylistIndex != -1) {
|
||||
lifecycleScope.launch {
|
||||
playlistNext(player.currentMediaItemIndex == (currentPlaylistIndex + 1) % player.mediaItemCount)
|
||||
refreshFileName()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
player.prepare()
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ object AndroidUtils {
|
||||
/**
|
||||
* A [Manifest.permission.POST_NOTIFICATIONS] permission helper.
|
||||
*
|
||||
* Must be initialized before [Activity.onCreate].
|
||||
* Must be initialized before [Activity.onCreate] finishes.
|
||||
*/
|
||||
class NotificationPermissionHelper<out A: AppCompatActivity>(val activity: A) {
|
||||
private var listener: ((Boolean) -> Unit)? = null
|
||||
|
@ -196,6 +196,7 @@ Java_sushi_hardcore_droidfs_filesystems_GocryptfsVolume_native_1list_1dir(JNIEnv
|
||||
jint sessionID, jstring jplain_dir) {
|
||||
const char* plain_dir = (*env)->GetStringUTFChars(env, jplain_dir, NULL);
|
||||
const size_t plain_dir_len = strlen(plain_dir);
|
||||
const char append_slash = plain_dir[plain_dir_len-1] != '/';
|
||||
GoString go_plain_dir = {plain_dir, plain_dir_len};
|
||||
|
||||
struct gcf_list_dir_return elements = gcf_list_dir(sessionID, go_plain_dir);
|
||||
@ -216,7 +217,7 @@ Java_sushi_hardcore_droidfs_filesystems_GocryptfsVolume_native_1list_1dir(JNIEnv
|
||||
|
||||
char* fullPath = malloc(sizeof(char) * (plain_dir_len + nameLen + 2));
|
||||
strcpy(fullPath, plain_dir);
|
||||
if (plain_dir[-2] != '/') {
|
||||
if (append_slash) {
|
||||
strcat(fullPath, "/");
|
||||
}
|
||||
strcat(fullPath, name);
|
||||
|
52
app/src/main/res/values-iw/arrays.xml
Normal file
@ -0,0 +1,52 @@
|
||||
<resources>
|
||||
<string-array name="sort_orders_entries">
|
||||
<item>שם</item>
|
||||
<item>גודל</item>
|
||||
<item>תאריך</item>
|
||||
<item>שם (בסדר יורד)</item>
|
||||
<item>גודל (בסדר יורד)</item>
|
||||
<item>תאריך (בסדר יורד)</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="color_names">
|
||||
<item>ירוק</item>
|
||||
<item>אדום</item>
|
||||
<item>כחול</item>
|
||||
<item>צהוב</item>
|
||||
<item>כתום</item>
|
||||
<item>סגול</item>
|
||||
<item>ורוד</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="export_methods">
|
||||
<item>אוטומטי (בהתאם לזיכרון הזמין)</item>
|
||||
<item>ייצוא זמני לאחסון הפנימי (אמין אך עשוי להשאיר עקבות)</item>
|
||||
<item>קובץ זיכרון (בטוח יותר אבל לא תמיד עובד)</item>
|
||||
</string-array>
|
||||
|
||||
<!-- don't translate the following otherwise the app will crash -->
|
||||
<string-array name="sort_orders_values">
|
||||
<item>name</item>
|
||||
<item>size</item>
|
||||
<item>date</item>
|
||||
<item>name_desc</item>
|
||||
<item>size_desc</item>
|
||||
<item>date_desc</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="color_values">
|
||||
<item>green</item>
|
||||
<item>red</item>
|
||||
<item>blue</item>
|
||||
<item>yellow</item>
|
||||
<item>orange</item>
|
||||
<item>purple</item>
|
||||
<item>pink</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="export_methods_values">
|
||||
<item>auto</item>
|
||||
<item>disk</item>
|
||||
<item>memory</item>
|
||||
</string-array>
|
||||
</resources>
|
282
app/src/main/res/values-iw/strings.xml
Normal file
@ -0,0 +1,282 @@
|
||||
<resources>
|
||||
<string name="app_name">DroidFS</string>
|
||||
<string name="create_volume">צור אמצעי אחסון</string>
|
||||
<string name="open">פתח</string>
|
||||
<string name="create">צור</string>
|
||||
<string name="change_password">שנה סיסמא</string>
|
||||
<string name="password">סיסמא</string>
|
||||
<string name="import_files">ייבוא/להצפין קבצים</string>
|
||||
<string name="import_folder">ייבוא/להצפין תיקיות</string>
|
||||
<string name="discovering_files">סורק קבצים..</string>
|
||||
<string name="mkdir">צור תיקייה</string>
|
||||
<string name="dir_empty">ספריה ריקה</string>
|
||||
<string name="warning">אזהרה !</string>
|
||||
<string name="ask_lock_volume">האם אתה בטוח שברצונך לנעול אמצעי אחסון זה?</string>
|
||||
<string name="ok">בסדר</string>
|
||||
<string name="cancel">ביטול</string>
|
||||
<string name="enter_folder_name">שם תיקייה:</string>
|
||||
<string name="error">שגיאה</string>
|
||||
<string name="error_filename_empty">.נא להזין שם</string>
|
||||
<string name="error_mkdir">יצירת תיקייה נכשלה.</string>
|
||||
<string name="success_import">יובא בהצלחה!</string>
|
||||
<string name="success_import_msg">הקבצים שנבחרו יובאו בהצלחה.</string>
|
||||
<string name="import_failed">ייבוא של %s נכשל.</string>
|
||||
<string name="export_failed">ייצוא של %s נכשל.</string>
|
||||
<string name="success_export">יוצא בהצלחה!</string>
|
||||
<string name="remove_failed">המחיקה של %s נכשלה.</string>
|
||||
<string name="passwords_mismatch">סיסמאות לא תואמות</string>
|
||||
<string name="dir_not_empty">הספריה שנבחרה אינה ריקה</string>
|
||||
<string name="create_volume_failed">יצירת אמצעי אחסון נכשלה</string>
|
||||
<string name="open_volume_failed">פתיחה נכשלה</string>
|
||||
<string name="share_chooser">שתף קובץ</string>
|
||||
<string name="storage_perm_denied">הרשאת אחסון נדחתה</string>
|
||||
<string name="storage_perm_denied_msg">DroidFS לא יכול לעבוד ללא הרשאת אחסון.</string>
|
||||
<string name="get_size_failed">אחזור גודל הקובץ נכשל.</string>
|
||||
<string name="parent_folder">תיקיית אב</string>
|
||||
<string name="empty_volume_path">אנא הזן נתיב לאמצעי אחסון</string>
|
||||
<string name="empty_volume_name">הזן שם לאמצעי אחסון</string>
|
||||
<string name="external_open">פתח עם אפליקציה חיצונית</string>
|
||||
<string name="single_delete_confirm">האם אתה בטוח שברצונך למחוק %s ?</string>
|
||||
<string name="multiple_delete_confirm">האם אתה בטוח שברצנך למחוק פריטים אלה? %s </string>
|
||||
<string name="location">מיקום: %s</string>
|
||||
<string name="total_size">משקל כולל: %s</string>
|
||||
<string name="import_from_other_volume">ייבא מאמצעי אחסון אחר</string>
|
||||
<string name="read_file_failed">נכשל לפתוח את הקובץ הזה.</string>
|
||||
<string name="volume">אמצעי אחסון: %s</string>
|
||||
<string name="yes">כן</string>
|
||||
<string name="no">לא</string>
|
||||
<string name="ask_for_wipe">האם ברצונך למחוק את הקבצים המקוריים?</string>
|
||||
<string name="wipe_failed">המחיקה נכשלה: %s</string>
|
||||
<string name="wipe_successful">הקבצים נמחקו בהצלחה!</string>
|
||||
<string name="rename">שנה שם</string>
|
||||
<string name="rename_title">שם חדש:</string>
|
||||
<string name="rename_failed">שינוי השם נכשל</string>
|
||||
<string name="sort_order">מיין לפי:</string>
|
||||
<string name="change_password_failed">הפעולה נכשלה. אנא בדוק את הסיסמה הישנה שלך.</string>
|
||||
<string name="share_menu_label">הצפן עם DroidFS</string>
|
||||
<string name="share_intent_parsing_failed">בקשת השיתוף נכשלה</string>
|
||||
<string name="listdir_null_error_msg">אין אפשרות לגשת לספריה זו</string>
|
||||
<string name="fingerprint_save_checkbox_text">שמור גיבוב של הסיסמא באמצעות טביעת אצבע</string>
|
||||
<string name="fingerprint_instruction">אנא גע בחיישן טביעת האצבע</string>
|
||||
<string name="illegal_block_size_exception">הרחבת גודל בלוק לא חוקית</string>
|
||||
<string name="illegal_block_size_exception_msg">זה יכול לקרות אם הוספת טביעת אצבע חדשה, איפוס אחסון מגובב יכול לפתור את זה.</string>
|
||||
<string name="reset_hash_storage">אפס אחסון מגובב</string>
|
||||
<string name="MAC_verification_failed">חתימה/אימות מאק נכשל. חנות המפתחות של אנדרואיד או הקוד המגובב שנשמר השתנו. איפוס אחסון מגובב יכול לפתור את זה.</string>
|
||||
<string name="hash_storage_reset">אפס אחסון מגובב</string>
|
||||
<string name="encrypt_action_description">מצפין ושומר גיבוב של הסיסמא</string>
|
||||
<string name="decrypt_action_description">מפענח גיבוב סיסמא.</string>
|
||||
<string name="title_activity_settings">DroidFS הגדרות</string>
|
||||
<string name="explorer">גלה</string>
|
||||
<string name="settings_title_sort_order">מיון ברירת המחדל</string>
|
||||
<string name="usf_decrypt">אפשר ייצוא קבצים/פענוח</string>
|
||||
<string name="usf_share"> אפשר שיתוף קבצים דרך תפריט השיתוף של אנדרואיד </string>
|
||||
<string name="usf_open">אפשר פתיחת קבצים עם יישומים אחרים </string>
|
||||
<string name="usf_screenshot">אפשר צילומי מסך</string>
|
||||
<string name="usf_fingerprint">אפשר שימרת גיבוב של הסיסמא באמצעות טביעת אצבע</string>
|
||||
<string name="usf_volume_management">הגדרת אמצעי אחסון</string>
|
||||
<string name="usf_keep_open">השאר את האמצעי אחסון פתוח כשהאפליקציה רצה ברקע</string>
|
||||
<string name="unsafe_features">פיצרים לא בטוחים</string>
|
||||
<string name="manage_unsafe_features">נהל פיצרים לא בטוחים</string>
|
||||
<string name="manage_unsafe_features_summary">אפשר/מנע פיצרים לא בטוחים</string>
|
||||
<string name="usf_home_warning_msg">DroidFS מנסה להיות מאובטח ככל האפשר,עם זאת אבטחה כרוכה לעיתים קרובת בחוסר נוחות. זה הסיבה ש DroidFS מציע פיצרים לא בטוחים שאתה יכול להפעיל /להשבית בהתאם לצרכים שלך .\n\n אזהרה: פיצרים אלה יכולים להיות לא בטוחים. אל תשתמש בהם אלא אם כן אתה יודע בידיוק מה אתה עושה. מומלץ מאוד לקרוא את הקובץ דוקמנטציה לפני שמפעילים אותם.</string>
|
||||
<string name="see_unsafe_features">הראה פיצרים לא בטוחים</string>
|
||||
<string name="open_as">פתח כ</string>
|
||||
<string name="image">תמונה</string>
|
||||
<string name="video">וידאו</string>
|
||||
<string name="audio">שמע</string>
|
||||
<string name="playing_failed">נכשל לנגן את הקובץ הזה: %s</string>
|
||||
<string name="text">טקסט</string>
|
||||
<string name="save_failed">השמירה נכשלה</string>
|
||||
<string name="file_saved">קובץ נשמר!</string>
|
||||
<string name="ask_save">הקובץ מכיל שינויים שלא נשמרו. האם ברצונך לשמור אותם לפני היציאה?</string>
|
||||
<string name="save">שמור</string>
|
||||
<string name="discard">אל תשמור</string>
|
||||
<string name="word_wrap">התחל שורה משמאל לשפה האנגלית</string>
|
||||
<string name="outofmemoryerror_msg">OutOfMemoryError: הקובץ גדול מדי כדי לטעון אותו בזכרון.</string>
|
||||
<string name="new_file">צור קובץ חדש</string>
|
||||
<string name="enter_file_name">שם הקובץ:</string>
|
||||
<string name="file_creation_failed">נכשל ליצור קובץ חדש.</string>
|
||||
<string name="loading">טוען</string>
|
||||
<string name="loading_msg_create">יוצר אמצעי אחסון…</string>
|
||||
<string name="loading_msg_change_password">משנה סיסמא…</string>
|
||||
<string name="loading_msg_open">פותח אמצעי אחסון…</string>
|
||||
<string name="loading_msg_export">מייצא קבצים…</string>
|
||||
<string name="query_cursor_null_error_msg">לא הצלחתי לגשת לקובץ הזה.</string>
|
||||
<string name="about">אודות</string>
|
||||
<string name="github">GitHub</string>
|
||||
<string name="github_summary">מאגר DroidFS ב- GitHub. קוד מקור, תיעוד, מעקב אחר באגים…</string>
|
||||
<string name="gitea">Gitea</string>
|
||||
<string name="gitea_summary">מאגר DroidFS בChapril Gitea. שלא כמו GitHub, Gitea היא תוכנה חינמית לחלוטין ומתארחת בעצמה. קוד מקור, תיעוד, מעקב אחר באגים…</string>
|
||||
<string name="share">שתף</string>
|
||||
<string name="decrypt_files">ייצא/פענח</string>
|
||||
<string name="copy_failed">העתקת %s נכשלה.</string>
|
||||
<string name="copy_success">העתקה בוצע בהצלחה.</string>
|
||||
<string name="add">הוסף</string>
|
||||
<string name="camera">מצלמה</string>
|
||||
<string name="picture_save_success">התמונה נשמרה ל %s</string>
|
||||
<string name="picture_save_failed">נכשל לשמור את התמונה הזאת.</string>
|
||||
<string name="video_save_success">הסרטון נשמר ל %s</string>
|
||||
<string name="file_overwrite_question">%s כבר קיים, האם ברצונך להחליף אותו?</string>
|
||||
<string name="dir_overwrite_question">%s כבר קיים, האם ברצונך למזג את התוכן שלו ?</string>
|
||||
<string name="enter_new_name">הזן שם חדש</string>
|
||||
<string name="copy_menu_title">העתק</string>
|
||||
<string name="move_failed">העברת %s נכשלה.</string>
|
||||
<string name="move_success">העברה בוצעה בהצלחה!</string>
|
||||
<string name="enter_timer_duration">הזן את משך זמן הטיימר (בשניות)</string>
|
||||
<string name="path_error">לא הצלחתי לגשת לנתיב הזה.</string>
|
||||
<string name="create_cant_write_error_msg">לDroidFS אין הרשאת כתיבה במיקום הזה, תנסה מיקום אחר</string>
|
||||
<string name="add_cant_write_warning">ל- DroidFS אין הרשאת כתיבה לנתיב זה. מוסיף אמצעי אחסון עם הרשאת קריאה בלבד.</string>
|
||||
<string name="sdcard_error_header">DroidFS יכול לכתוב רק לכרטיסי SD נשלפים תחת:</string>
|
||||
<string name="sdcard_error_add_footer">מוסיף אמצעי אחסון עם הרשאת קריאה בלבד.</string>
|
||||
<string name="sdcard_error_create_footer">אנא השתמש בספריית משנה של נתיב זה או באחסון פנימי.</string>
|
||||
<string name="slideshow_stopped">הצגת השקופיות הופסקה</string>
|
||||
<string name="slideshow_started">התחל מצגת</string>
|
||||
<string name="ask_save_img_rotated">התמונה סובבה. האם ברצונך לשמור את השינויים הללו ולדרוס את התמונה המקורית?</string>
|
||||
<string name="image_saved_successfully">השינויים בתמונה נשמרו בהצלחה.</string>
|
||||
<string name="bitmap_compress_failed">דחיסת מפת הסיביות נכשלה.</string>
|
||||
<string name="file_write_failed">כתיבת הקובץ נכשלה.</string>
|
||||
<string name="error_not_a_volume">אמצעי אחסון מוצפן לא זוהה. אנא בדוק את הנתיב שנבחר.</string>
|
||||
<string name="version">גרסא</string>
|
||||
<string name="error_cipher_null">שגיאה: הסיסמא ריקה.</string>
|
||||
<string name="key_permanently_invalidated_exception">KeyPermanentlyInvalidatedException</string>
|
||||
<string name="key_permanently_invalidated_exception_msg">נראה שהוספת טביעת אצבע חדשה. הגיבוב של סיסמאות שמורות הפך לבלתי שמיש.</string>
|
||||
<string name="usf_read_doc">עליך לקרוא אותו בעיון לפני הפעלת כל אחת מהאפשרויות הללו.</string>
|
||||
<string name="usf_doc">דוקמנטציה של פיצרים לא בטוחים</string>
|
||||
<string name="error_retrieving_filename">לא ניתן לאחזר את שם הקובץ עבור הקישור: %s</string>
|
||||
<string name="hidden_volume">אמצעי אחסון נסתר</string>
|
||||
<string name="error_slash_in_name">שם האמצעי אחסון לא יכול להכיל סלאשים</string>
|
||||
<string name="hidden_volume_warning">אמצעי אחסון נסתרים מאוחסנים באחסון הפנימי של האפליקציה. אפליקציות אחרות לא יכולות לראות את אמצעי האחסון האלה ללא גישת שורש. עם זאת, אם תסיר את ההתקנה של DroidFS או תנקה את נתוני האפליקציה, כל אמצעי האחסון הנסתרים שלך יאבדו. הקפד לבצע גיבויים!</string>
|
||||
<string name="camera_perm_needed">הרשאת מצלמה נדרשת כדי לצלם תמונות</string>
|
||||
<string name="choose_resolution">בחר רזולוציה</string>
|
||||
<string name="file_operations">פעולות קובץ</string>
|
||||
<string name="file_op_copy_msg">מעתיק קבצים…</string>
|
||||
<string name="file_op_import_msg">מייבא קבצים…</string>
|
||||
<string name="file_op_export_msg">מייצא קבצים…</string>
|
||||
<string name="file_op_move_msg">מעביר קבצים…</string>
|
||||
<string name="file_op_wiping_msg">מוחק קבצים…</string>
|
||||
<string name="folders_first">תיקיות קודם</string>
|
||||
<string name="folders_first_summary">הראה תיקיות בתחילת הרשימה</string>
|
||||
<string name="auto_fit_title">סיבוב אוטומטי של מסך נגן מדיה</string>
|
||||
<string name="auto_fit_summary">סובב אוטומטית את המסך כך שיתאים למידות הווידאו</string>
|
||||
<string name="open_tree_failed">לא נמצא סייר קבצים. אנא התקן אחד ונסה שוב.</string>
|
||||
<string name="close_volume">סגור אמצעי אחסון</string>
|
||||
<string name="sort_by">מיין לפי</string>
|
||||
<string name="cut">גזור</string>
|
||||
<string name="map_folders">מפה תיקיות</string>
|
||||
<string name="map_folders_summary">מפה באופן רקורסיבי תיקיות כדי לחשב את הגדלים שלהן (עליך להשבית זאת בעת פתיחת אמצעי אחסון גדולים)</string>
|
||||
<string name="camera_optimization">אופטימיזציה של מצלמה</string>
|
||||
<string name="maximize_quality">איכות מקסימלית</string>
|
||||
<string name="minimize_latency">איכות מינימלית</string>
|
||||
<string name="auto">אוטומטי</string>
|
||||
<string name="encryption_cipher_label">הצפנת צופן:</string>
|
||||
<string name="theme">ערכת נושא</string>
|
||||
<string name="thumbnails">תמונות ממוזערות</string>
|
||||
<string name="thumbnails_summary">הצג תמונות וסרטונים ממוזערים</string>
|
||||
<string name="seek_seconds_forward">+%d שניות</string>
|
||||
<string name="seek_seconds_backward">-%d שניות</string>
|
||||
<string name="add_volume">הוסף אמצעי אחסון</string>
|
||||
<string name="pick_directory">בחר ספרייה</string>
|
||||
<string name="volume_alread_saved">אמצעי אחסון כבר נשמר</string>
|
||||
<string name="open_dialog_title">פותח %s:</string>
|
||||
<string name="remove">הסר</string>
|
||||
<string name="settings">הגדרות</string>
|
||||
<string name="select_all">בחר הכל</string>
|
||||
<string name="remove_fingerprint">הסר טביעת אצבע</string>
|
||||
<string name="unrecoverable_key_exception_msg">%s. לא מצליח לטעון מפתח הצפנה</string>
|
||||
<string name="unrecoverable_key_exception">UnrecoverableKeyException</string>
|
||||
<string name="delete_hidden_volume_question">%s מוסתר, האם אתה רק רוצה לשכוח את הנתיב של האמצעי אחסון או גם למחוק את כל התוכן שלו?</string>
|
||||
<string name="forget_only">שכח בלבד</string>
|
||||
<string name="delete_volume">מחק אמצעי אחסון</string>
|
||||
<string name="hidden_volume_description">אחסן את אמצעי האחסון באחסון הפנימי של DroidFS</string>
|
||||
<string name="error_is_file">שגיאה: קובץ בשם זה כבר קיים</string>
|
||||
<string name="volume_path_label">הזן נתיב לאמצעי אחסון:</string>
|
||||
<string name="volume_name_label">הזן שם לאמצעי אחסון:</string>
|
||||
<string name="volume_path_hint">נתיב אמצעי אחסון</string>
|
||||
<string name="volume_name_hint">שם אמצעי אחסון</string>
|
||||
<string name="password_label">הזן את הסיסמא של האמצעי אחסון:</string>
|
||||
<string name="password_confirmation_label">חזור שנית על הסיסמא:</string>
|
||||
<string name="password_confirmation_hint">אישור סיסמא</string>
|
||||
<string name="password_hash_saved">הגיבוב של הסיסמא נשמר</string>
|
||||
<string name="no_volumes_text">אין אמצעי אחסון שמורים, הוסף ע"י לחציה על הסימן +</string>
|
||||
<string name="fingerprint_error_msg">לא ניתן להשתמש באימות טביעת אצבע: %s.</string>
|
||||
<string name="keyguard_not_secure">מגן מקשים לא מאובטח</string>
|
||||
<string name="no_hardware">לא נמצאה חומרה מתאימה</string>
|
||||
<string name="hardware_unavailable">החומרה אינה זמינה</string>
|
||||
<string name="no_fingerprint">אין טביעת אצבע שמורה</string>
|
||||
<string name="unknown_error">שגיאה לא ידועה</string>
|
||||
<string name="biometric_error">שגיאה ביומטרית: %s</string>
|
||||
<string name="apply_to_all">החל את הבחירה הזו על כל אמצעי האחסון הנסתרים</string>
|
||||
<string name="select_volume">בחר אמצעי אחסון</string>
|
||||
<string name="current_password_label">הזן את סיסמאת אמצעי אחסון הנוכחי:</string>
|
||||
<string name="current_password_hint">סיסמא נוכחית</string>
|
||||
<string name="new_password_label">הזן את הסיסמא החדשה לאמצעי אחסון:</string>
|
||||
<string name="new_password_hint">סיסמא חדשה</string>
|
||||
<string name="new_password_confirmation_label">חזור שנית על הסיסמא החדשה:</string>
|
||||
<string name="error_marshmallow_required">הפיצר הזה זמין רק למשתמשי אנדרואיד 6 (מרשמלו) ומעלה</string>
|
||||
<string name="copy_hidden_volume">העתק לאחסון משותף</string>
|
||||
<string name="copy_external_volume">צור עותק נסתר</string>
|
||||
<string name="copy_volume_notification">מעתיק אמצעי אחסון…</string>
|
||||
<string name="hidden_volume_already_exists">אמצעי אחסון נסתר עם אותו שם כבר קיים.</string>
|
||||
<string name="pdf_document">מסמך PDF</string>
|
||||
<string name="thumbnail_max_size">גודל מקסימלי עבור תמונות ממוזערות</string>
|
||||
<string name="thumbnail_max_size_summary">גודל קובץ מקסימלי לטעינת תמונה ממוזערת. ערך נוכחי: %s</string>
|
||||
<string name="size_hint">גודל (בקילו בייט)</string>
|
||||
<string name="invalid_number">מספר לא תקין</string>
|
||||
<string name="new_volume_name">שם אמצעי אחסון חדש:</string>
|
||||
<string name="volume_rename_failed">שינוי שם אמצעי אחסון נכשל</string>
|
||||
<string name="switch_display_layout">החלף פריסת תצוגה</string>
|
||||
<string name="one_file">קובץ 1</string>
|
||||
<string name="multiple_files">%d קבצים</string>
|
||||
<string name="one_folder">1 תיקייה</string>
|
||||
<string name="multiple_folders">%d תיקיות</string>
|
||||
<string name="default_open">פתח אמצעי אחסון זה בעת הפעלת היישום</string>
|
||||
<string name="remove_default_open">אל תפתח כברירת מחדל</string>
|
||||
<string name="elements_selected">%d/%d נבחרו</string>
|
||||
<string name="pin_passwords_title">פריסת מקלדת מספרים</string>
|
||||
<string name="pin_passwords_summary">שימוש בפריסת מקלדת מספרים בעת הזנת סיסמאות אמצעי אחסון</string>
|
||||
<string name="volume_type_label">סוג אמצעי אחסון:</string>
|
||||
<string name="gocryptfs">Gocryptfs</string>
|
||||
<string name="cryfs">CryFS</string>
|
||||
<string name="gocryptfs_disabled">תמיכת Gocryptfs הושבתה</string>
|
||||
<string name="cryfs_disabled">תמיכת CryFS הושבתה</string>
|
||||
<string name="file_op_delete_msg">מוחק קבצים…</string>
|
||||
<string name="volume_type">(%s)</string>
|
||||
<string name="volume_type_read_only">(%s, קריאה בלבד)</string>
|
||||
<string name="volume_type_inaccessible">(%s, לא נגיש)</string>
|
||||
<string name="io_error">שגיאת קלט/פלט.</string>
|
||||
<string name="use_fingerprint">השתמש בטביעת אצבע במקום בסיסמה הנוכחית</string>
|
||||
<string name="remember_volume">זכור אמצעי אחסון</string>
|
||||
<string name="open_volume">פתח אמצעי אחסון</string>
|
||||
<string name="choose_existing_volume">אנא בחר אמצעי אחסון קיים</string>
|
||||
<string name="volume_unlocked">אמצעי אחסון פתוח</string>
|
||||
<string name="lock_volume">נעל אמצעי אחסון</string>
|
||||
<string name="lock">נעל</string>
|
||||
<string name="ux">חוויית משתמש</string>
|
||||
<string name="theme_color">צבע ערכת נושא</string>
|
||||
<string name="theme_color_summary">שנה את צבע הערכת נושא של היישום</string>
|
||||
<string name="black_theme">שחור</string>
|
||||
<string name="password_fallback">חזרה לסיסמא</string>
|
||||
<string name="password_fallback_summary">בקש סיסמה כאשר אימות טביעת האצבע מבוטל</string>
|
||||
<string name="unknown_error_code">קוד שגיאה לא ידוע: %d</string>
|
||||
<string name="config_load_error">לא ניתן לטעון את קובץ התצורה. ודא שיש גישה לאמצעי אחסון.</string>
|
||||
<string name="wrong_password">לא ניתן לפענח את קובץ התצורה. אנא בדוק את הסיסמה שלך.</string>
|
||||
<string name="filesystem_id_changed">מזהה מערכת הקבצים בקובץ התצורה שונה מהפעם האחרונה שפתחנו אמצעי אחסון זה. פירוש הדבר יכול להיות מפני שתוקף החליף את מערכת הקבצים במערכת אחרת.</string>
|
||||
<string name="inaccessible_base_dir">אמצעי האחסון לא קיים או שאינו נגיש.</string>
|
||||
<string name="task_failed">המשימה נכשלה: %s</string>
|
||||
<string name="usf_expose">חשוף אמצעי אחסון פתוחים</string>
|
||||
<string name="usf_expose_summary">אפשר ליישומים אחרים לעיין באמצעי אחסון פתוחים כספקי מסמכים</string>
|
||||
<string name="usf_saf_write">הענק הרשאת כתיבה</string>
|
||||
<string name="usf_saf_write_summary">הענק הרשאת כתיבה בעת פתיחת קבצים עם יישומים אחרים</string>
|
||||
<string name="saf">גישה לאחסון Framework</string>
|
||||
<string name="tmp_export_failed">הייצוא נכשל: %s</string>
|
||||
<string name="export_failed_create">לא הצלחתי ליצור קובץ ייצוא</string>
|
||||
<string name="export_failed_export">ייצוא הקובץ נכשל</string>
|
||||
<string name="export_mem">מייצא לזיכרון…</string>
|
||||
<string name="export_disk">מייצא לאחסון פנימי…</string>
|
||||
<string name="memfd_create_unsupported">הקרנל הנוכחי שלך לא תומכת ב-memfd_create(). תכונה זו דורשת גרסת קרנל מינימלי של %s.</string>
|
||||
<string name="export_method">שיטת ייצוא</string>
|
||||
<string name="export_method_summary">שיטת ייצוא קבצים. משמש לשיתוף, פתיחה חיצונית וגישה לקבצים חשופים.</string>
|
||||
<string name="debug">דיבאג</string>
|
||||
<string name="logcat_title">DroidFS Logcat</string>
|
||||
<string name="logcat_saved">Logcat נשמר</string>
|
||||
</resources>
|
@ -267,4 +267,17 @@
|
||||
<string name="debug">Отладка</string>
|
||||
<string name="logcat_title">Журнал logcat DroidFS</string>
|
||||
<string name="logcat_saved">Журнал logcat сохранён</string>
|
||||
<string name="later">Позже</string>
|
||||
<string name="notification_denied_msg">Разрешение на отображение уведомления не получено. Фоновые операции с файлами не будут видны. Это можно изменить в настройках разрешений приложения.</string>
|
||||
<string name="keep_alive_notification_title">Служба поддержки работы</string>
|
||||
<string name="keep_alive_notification_text">Один или несколько томов остаются открытыми.</string>
|
||||
<string name="close_all">Закрыть все</string>
|
||||
<string name="usf_background">Отключить автоблокировку томов</string>
|
||||
<string name="usf_background_summary">Не блокировать тома автоматически при работе приложения в фоновом режиме</string>
|
||||
<string name="usf_keep_open">Держать тома открытыми</string>
|
||||
<string name="usf_keep_open_summary">Поддерживать постоянную работу приложения в фоновом режиме, чтобы тома оставались открытыми</string>
|
||||
<string name="gocryptfs_details">Быстрый, но не скрывает размеры файлов и структуру папок</string>
|
||||
<string name="cryfs_details">Медленнее, но защищает метаданные и предотвращает атаки замещения</string>
|
||||
<string name="or">или</string>
|
||||
<string name="enter_volume_path">Введите путь к тому</string>
|
||||
</resources>
|
||||
|
@ -77,7 +77,7 @@
|
||||
<string name="unsafe_features">Unsafe Features</string>
|
||||
<string name="manage_unsafe_features">Manage unsafe features</string>
|
||||
<string name="manage_unsafe_features_summary">Enable/Disable unsafe features</string>
|
||||
<string name="usf_home_warning_msg">DroidFS try to be as secure as possible. However, security often involves lack of comfort. This is why DroidFS offer you additional unsafe features that you can enable/disable according to your needs.\n\nWarning: this features can be UNSAFE. Do not use them unless you know exactly what you are doing. It is highly recommended to read the documentation before enabling them.</string>
|
||||
<string name="usf_home_warning_msg">DroidFS aims to be as secure as possible. However, security often involves lack of comfort. This is why DroidFS offers you additional unsafe features that you can enable and disable according to your needs.\n\nWarning: this features can be UNSAFE. Do not use them unless you know exactly what you are doing. It is highly recommended to read the documentation before enabling them.</string>
|
||||
<string name="see_unsafe_features">See unsafe features</string>
|
||||
<string name="open_as">Open as</string>
|
||||
<string name="image">Image</string>
|
||||
|
8
fastlane/metadata/android/en-US/changelogs/374.txt
Normal file
@ -0,0 +1,8 @@
|
||||
- Reworked UI for adding volumes
|
||||
- New unsafe feature to keep the app running as a foreground service
|
||||
- Allow choosing file export method
|
||||
- Logcat viewer (for easier debugging)
|
||||
- New turkish, chinese-simplified, and hebrew translations
|
||||
- UX improvements
|
||||
- Bug fixes
|
||||
- Translations updates
|
@ -7,6 +7,7 @@ Currently, DroidFS supports the following encrypted containers:
|
||||
- Compatible with original encrypted volume implementations
|
||||
- Internal support for video, audio, images, text and PDF files
|
||||
- Built-in camera to take on-the-fly encrypted photos and videos
|
||||
- Ability to expose volumes to other applications
|
||||
- Unlocking volumes using fingerprint authentication
|
||||
- Volume auto-locking when the app goes in background
|
||||
|
||||
@ -15,6 +16,7 @@ Currently, DroidFS supports the following encrypted containers:
|
||||
<b>Biometric/Fingerprint hardware:</b> needed to encrypt/decrypt password hashes using a fingerprint protected key.
|
||||
<b>Camera:</b> required to take encrypted photos or videos directly from the app.
|
||||
<b>Record audio:</b> required if you want sound on videos recorded with DroidFS.
|
||||
<b>Notifications:</b> used to report file operations progress and notify about volumes kept open
|
||||
|
||||
All of these permissions can be denied if you don't want to use the corresponding feature.
|
||||
|
||||
|
BIN
fastlane/metadata/android/en-US/images/phoneScreenshots/1.jpg
Normal file
After Width: | Height: | Size: 631 B |
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 91 KiB |
BIN
fastlane/metadata/android/en-US/images/phoneScreenshots/2.jpg
Normal file
After Width: | Height: | Size: 631 B |
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 100 KiB |
BIN
fastlane/metadata/android/en-US/images/phoneScreenshots/3.jpg
Normal file
After Width: | Height: | Size: 631 B |
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 133 KiB |
Before Width: | Height: | Size: 116 KiB After Width: | Height: | Size: 144 KiB |
Before Width: | Height: | Size: 2.7 MiB After Width: | Height: | Size: 2.7 MiB |
Before Width: | Height: | Size: 147 KiB After Width: | Height: | Size: 232 KiB |