Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Thumbnail support #533

Open
wants to merge 21 commits into
base: develop
Choose a base branch
from

Conversation

JustFanta01
Copy link
Contributor

Hello guys 👋
This is our proposal for implementing thumbnail support [/issues/41]
Me, @WheelyMcBones and @taglioIsCoding have made the following changes.

We have implemented a uniform solution that works both for local and the remote clouds, this solution exploits the DiskLruCache in the CryptoImplDecorator and in the CryptoImplVaultFormat(Pre)7. We have decided these two location because we have access to all necessary informations: the decrypted image and the cloud type.

In cache we save a thumbnail when someone reads an image file and retrieve it from the same cache during the listing process. Thumbnails are stored as decrypted files in cache and, unlike other files in the /decrypted folder, these are persistent until the cache is deleted. We added the attribute ".thumbnail" in the CryptoFile pointing to the file in the disk cache and the CloudFileModel wraps it around.
We also added the Preference in the Settings for when it is supposed to generate the thumbnails; at the moment, the "Per Folder" preference is present but not implemented.
Finally we got rid of the full duplication of the image by elaborating the thumbnail in stream with an ad-hoc Thread pool.

JustFanta01 and others added 21 commits April 11, 2024 14:45
Also using cloud.id to be able to distinguish between two files with same path but on different instances of the same cloud
Copy link

coderabbitai bot commented May 8, 2024

Walkthrough

This update enhances Cryptomator's handling of media files, particularly focusing on image files by introducing thumbnail caching and management. It streamlines file operations like moving and deleting in the cache, and integrates thumbnail generation settings, improving user interaction and file management efficiency in cloud storage environments.

Changes

File Path Changes Summary
.../crypto/CryptoFile.kt Added file handling for thumbnails.
.../crypto/CryptoImplDecorator.kt Enhanced thumbnail caching and file management logic.
.../crypto/CryptoImplVaultFormat7.kt Similar changes as CryptoImplDecorator.kt.
.../crypto/CryptoImplVaultFormatPre7.kt Added thumbnail handling and cache management for file operations.
.../presentation/model/CloudFileModel.kt Integrated CryptoFile for thumbnail management.
.../presentation/model/CloudNodeModel.kt Minor import addition.
.../presentation/presenter/BrowseFilesPresenter.kt Enhanced handling of cloud file nodes.
.../presentation/ui/adapter/BrowseFilesAdapter.kt Updated methods for thumbnail handling using BitmapFactory.
.../presentation/ui/bottomsheet/... Enhanced thumbnail loading in UI components.
.../presentation/ui/fragment/... UI and settings enhancements for thumbnail generation.
.../util/SharedPreferencesHandler.kt Added functionality to manage thumbnail generation preferences.
.../util/ThumbnailsOption.kt Introduced options for thumbnail generation settings.
.../util/file/LruFileCacheUtil.kt Added new cache option for local file handling.

Possibly related issues

🐇✨
A hop and a skip in the code so neat,
Thumbnails cache and files so sweet.
With every change, a better flow,
Cryptomator's charm, now on the show!
🌟📁🌟


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share
Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger a review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@JustFanta01 JustFanta01 mentioned this pull request May 8, 2024
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Review Details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits Files that changed from the base of the PR and between 45f7d0e and a487f6d.
Files ignored due to path filters (3)
  • presentation/src/main/res/values/arrays.xml is excluded by !**/*.xml
  • presentation/src/main/res/values/strings.xml is excluded by !**/*.xml
  • presentation/src/main/res/xml/preferences.xml is excluded by !**/*.xml
Files selected for processing (14)
  • data/src/main/java/org/cryptomator/data/cloud/crypto/CryptoFile.kt (2 hunks)
  • data/src/main/java/org/cryptomator/data/cloud/crypto/CryptoImplDecorator.kt (7 hunks)
  • data/src/main/java/org/cryptomator/data/cloud/crypto/CryptoImplVaultFormat7.kt (5 hunks)
  • data/src/main/java/org/cryptomator/data/cloud/crypto/CryptoImplVaultFormatPre7.kt (3 hunks)
  • presentation/src/main/java/org/cryptomator/presentation/model/CloudFileModel.kt (1 hunks)
  • presentation/src/main/java/org/cryptomator/presentation/model/CloudNodeModel.kt (2 hunks)
  • presentation/src/main/java/org/cryptomator/presentation/presenter/BrowseFilesPresenter.kt (2 hunks)
  • presentation/src/main/java/org/cryptomator/presentation/ui/adapter/BrowseFilesAdapter.kt (4 hunks)
  • presentation/src/main/java/org/cryptomator/presentation/ui/bottomsheet/FileSettingsBottomSheet.kt (2 hunks)
  • presentation/src/main/java/org/cryptomator/presentation/ui/fragment/BrowseFilesFragment.kt (2 hunks)
  • presentation/src/main/java/org/cryptomator/presentation/ui/fragment/SettingsFragment.kt (6 hunks)
  • util/src/main/java/org/cryptomator/util/SharedPreferencesHandler.kt (2 hunks)
  • util/src/main/java/org/cryptomator/util/ThumbnailsOption.kt (1 hunks)
  • util/src/main/java/org/cryptomator/util/file/LruFileCacheUtil.kt (2 hunks)
Files skipped from review due to trivial changes (2)
  • presentation/src/main/java/org/cryptomator/presentation/model/CloudNodeModel.kt
  • util/src/main/java/org/cryptomator/util/ThumbnailsOption.kt
Additional comments not posted (22)
presentation/src/main/java/org/cryptomator/presentation/model/CloudFileModel.kt (1)

14-14: Addition of thumbnail property to handle optional thumbnail files for CloudFileModel looks good.

data/src/main/java/org/cryptomator/data/cloud/crypto/CryptoFile.kt (1)

16-16: Addition of nullable thumbnail property in CryptoFile class is implemented correctly.

presentation/src/main/java/org/cryptomator/presentation/ui/bottomsheet/FileSettingsBottomSheet.kt (1)

37-43: Handling of thumbnail display in FileSettingsBottomSheet using BitmapFactory and conditional UI updates is implemented correctly.

util/src/main/java/org/cryptomator/util/file/LruFileCacheUtil.kt (1)

34-34: Addition of LOCAL option to the Cache enum to support local caching of thumbnails is appropriate.

presentation/src/main/java/org/cryptomator/presentation/ui/fragment/BrowseFilesFragment.kt (1)

29-29: Import of SharedPreferencesHandler in BrowseFilesFragment for accessing preferences is correctly added.

data/src/main/java/org/cryptomator/data/cloud/crypto/CryptoImplVaultFormatPre7.kt (1)

131-142: Integration of thumbnail caching in CryptoImplVaultFormatPre7 is implemented correctly, handling cache retrieval and setting thumbnails appropriately.

util/src/main/java/org/cryptomator/util/SharedPreferencesHandler.kt (1)

164-171: Implementation of generateThumbnails() in SharedPreferencesHandler to retrieve user preferences for thumbnail generation is correctly done.

presentation/src/main/java/org/cryptomator/presentation/ui/fragment/SettingsFragment.kt (3)

31-31: Ensure that the newly added constant THUMBNAIL_GENERATION is used consistently throughout the code.


259-259: Ensure the functionality of thumbnailGenerationChangeListener is implemented as it is crucial for handling user preferences changes.


342-342: The constant THUMBNAIL_GENERATION is appropriately declared.

presentation/src/main/java/org/cryptomator/presentation/ui/adapter/BrowseFilesAdapter.kt (2)

151-157: Thumbnail display logic correctly checks if the file is an image and has a thumbnail before attempting to display it. Good use of Kotlin's safe call and smart cast.


159-160: The method isImageMediaType effectively determines if the file is an image based on its MIME type. This is crucial for the feature's correctness.

data/src/main/java/org/cryptomator/data/cloud/crypto/CryptoImplDecorator.kt (5)

78-81: The thread pool for thumbnail generation is correctly configured with a custom thread factory. This is good for debugging and resource management.


83-85: Method getLruCacheFor correctly abstracts the retrieval of the LRU cache based on the cloud type. This encapsulation aids maintainability.


98-109: The renameFileInCache method correctly handles renaming of files in the cache. It checks if the old cache key exists before attempting to rename, which is a safe approach.


Line range hint 384-500: The method read handles the reading of files and the conditional generation of thumbnails. It uses a PipedOutputStream and PipedInputStream for thumbnail generation, which is an appropriate use of Java I/O for this purpose. However, ensure that resources are always closed in case of exceptions to avoid resource leaks.


446-466: The startThumbnailGeneratorThread method correctly handles the generation of thumbnails in a separate thread. It uses a future to manage the asynchronous task, which is a good practice for concurrent operations.

data/src/main/java/org/cryptomator/data/cloud/crypto/CryptoImplVaultFormat7.kt (3)

168-179: Thumbnail caching logic added to the listing process.

This change integrates thumbnail caching into the file listing process, which should enhance the user experience by providing quick access to image previews. Ensure that the thumbnail generation and caching logic is thoroughly tested, especially in scenarios where the cache might become full or corrupted.


394-394: Ensure proper handling of file renaming in cache during file moves.

This method is crucial for maintaining consistency in the cache when files are moved. It's important to verify that it handles edge cases such as renaming non-existent files, concurrent access scenarios, and potential race conditions.


464-472: Properly handle thumbnail cache deletion during file deletion.

The implementation correctly checks for the existence of a thumbnail in the cache and deletes it if present. This is a necessary step to prevent orphaned cache entries which can lead to wasted storage space and potential privacy issues if sensitive thumbnails are not properly deleted.

presentation/src/main/java/org/cryptomator/presentation/presenter/BrowseFilesPresenter.kt (2)

5-5: Ensure that BitmapFactory is used appropriately in the file to handle image processing for thumbnails.


517-517: The implementation for handling image previews appears to be correctly integrated with the new thumbnail feature. Ensure that the ImagePreviewFilesStore is properly tested, especially its interaction with the UI.

Comment on lines +150 to +153
private fun setupThumbnailGeneration() {
val preference = findPreference(THUMBNAIL_GENERATION) as Preference?
// TODO ...
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Complete the implementation of setupThumbnailGeneration or provide additional details on the intended functionality.

Comment on lines +114 to +117
private val thumbnailGenerationChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->
// TODO ...
true
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Complete the implementation of thumbnailGenerationChangeListener or provide additional details on the intended functionality.

@@ -1,5 +1,6 @@
package org.cryptomator.presentation.ui.adapter

import android.graphics.BitmapFactory
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tip

Codebase Verification

The analysis of the BitmapFactory usage in CryptoImplDecorator.kt shows that it is configured safely. The BitmapFactory.Options is used with inSampleSize set to 4, effectively reducing the memory usage during image decoding. Additionally, the image is resized to a thumbnail, further mitigating memory concerns.

However, the other two files, FileSettingsBottomSheet.kt and BrowseFilesAdapter.kt, do not use any BitmapFactory.Options, which could potentially lead to unsafe configurations, especially in scenarios involving large images.

Recommended Actions:

  • Review and potentially refactor the usage of BitmapFactory.decodeFile in FileSettingsBottomSheet.kt and BrowseFilesAdapter.kt to include BitmapFactory.Options with appropriate settings to manage memory usage safely.
Analysis chain

Ensure BitmapFactory is used securely to avoid potential vulnerabilities related to image decoding.


The script results indicate that BitmapFactory.decodeFile and BitmapFactory.decodeStream are used in three different files. However, only in CryptoImplDecorator.kt is there an indication that BitmapFactory.Options might be used, which could potentially configure the decoding process safely. The other two usages in FileSettingsBottomSheet.kt and BrowseFilesAdapter.kt do not use any options, which might lead to unsafe configurations.

To confirm the safety of the usage in CryptoImplDecorator.kt and to provide specific guidance on what changes might be necessary in the other files, I need to inspect the options used in CryptoImplDecorator.kt.

Scripts Executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Description: Verify that BitmapFactory is used with safe configurations throughout the project.

# Test: Search for unsafe usage of BitmapFactory. Expect: No occurrences of unsafe configurations.
rg --type kotlin "BitmapFactory.decode"

Length of output: 512



Script:

#!/bin/bash
# Description: Inspect the BitmapFactory.Options used in CryptoImplDecorator.kt to determine if they configure safe usage.

# Test: Extract the relevant lines around the BitmapFactory.decodeStream usage to see the configuration of BitmapFactory.Options.
rg --context 5 "BitmapFactory.decodeStream" data/src/main/java/org/cryptomator/data/cloud/crypto/CryptoImplDecorator.kt

Length of output: 543

@infeo
Copy link
Member

infeo commented May 8, 2024

@JustFanta01 Not a review, but a general suggestion: For caching you use https://github.com/JakeWharton/DiskLruCache, which is unmaintained since 8 yrs. Consider using https://github.com/ben-manes/caffeine instead, which is a modern and quite good caching library.

Edit: my bad, this was the wrong dependency.

@SailReal
Copy link
Member

Thank you so much for this contribution ❤️, will have a closer look to it on Monday!

Consider using https://github.com/ben-manes/caffeine instead, which is a modern and quite good caching library.

@infeo can you please explain in detail why we should switch from DiskLruCache to Caffeine?

@infeo
Copy link
Member

infeo commented May 13, 2024

@SailReal I withdraw my suggestion^^ First, i thought this was an outdated, unmaintained dependency, but i was wrong. Second, the project already uses this dependency and then it is good practice to use what's already there. And third, the dependency targets Android, so i guess it is also "optimized" for the OS in some way.

Regarding Caffeine: It uses a different algorithm with a statistically higher hit rate. See also https://github.com/ben-manes/caffeine/wiki/Efficiency.

Copy link
Member

@SailReal SailReal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, it looks really good, thanks for your contribution!

Besides the comments in the code, here are some general thoughts:

  • Remove "Per folder" everywhere in the code, as it is not implemented yet.
  • Remove the Thumbnail category in the settings and move the setting to General to avoid having a category with only one entry.
  • I'll discuss this with Tobi, but I think the default should be to generate thumbnails by file, not never. Will come back with the result.
  • Always use brackets in if statements
  • The code is formatted almost everywhere, but some files are not completely 😅
  • Verify the performance impact of listing huge folders with a lot of generated thumbnails

Comment on lines +87 to +88
private fun getOrCreateLruCache(key: LruFileCacheUtil.Cache, cacheSize: Int): DiskLruCache? {
return diskLruCache.computeIfAbsent(key) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
private fun getOrCreateLruCache(key: LruFileCacheUtil.Cache, cacheSize: Int): DiskLruCache? {
return diskLruCache.computeIfAbsent(key) {
private fun getOrCreateLruCache(cache: LruFileCacheUtil.Cache, cacheSize: Int): DiskLruCache? {
return diskLruCache.computeIfAbsent(cache) {

Comment on lines +89 to +93
val where = LruFileCacheUtil(context).resolve(it)
try {
DiskLruCache.create(where, cacheSize.toLong())
} catch (e: IOException) {
Timber.tag("CryptoImplDecorator").e(e, "Failed to setup LRU cache for $where.name")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
val where = LruFileCacheUtil(context).resolve(it)
try {
DiskLruCache.create(where, cacheSize.toLong())
} catch (e: IOException) {
Timber.tag("CryptoImplDecorator").e(e, "Failed to setup LRU cache for $where.name")
val cacheFile = LruFileCacheUtil(context).resolve(it)
try {
DiskLruCache.create(cacheFile, cacheSize.toLong())
} catch (e: IOException) {
Timber.tag("CryptoImplDecorator").e(e, "Failed to setup LRU cache for $cacheFile.name")

}
}
}
protected fun renameFileInCache(source: CryptoFile, target: CryptoFile){
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a newline before this method and a blank before the {

Comment on lines +470 to +477
return buildString {
if (cloudFile.cloud?.id() != null)
this.append(cloudFile.cloud!!.id())
else
this.append("c") // "common"
this.append("-")
this.append(cloudFile.path.hashCode())
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return buildString {
if (cloudFile.cloud?.id() != null)
this.append(cloudFile.cloud!!.id())
else
this.append("c") // "common"
this.append("-")
this.append(cloudFile.path.hashCode())
}
return String.format("%s-%d", cloudFile.cloud?.id() ?: "common", cloudFile.path.hashCode())

}

private fun isGenerateThumbnailsEnabled(cache: DiskLruCache?, fileName: String): Boolean {
return sharedPreferencesHandler.useLruCache() &&
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From a user perspective, it is currently not obvious that you need to enable caching for thumbnail generation to work. We may need to show a dialogue when changing the thumbnail generation from NONE to something else, and also for when caching gets disabled.

Even better, we could also decouple it here completely from the response cache so that we do not depend on this response caching feature, right?

@@ -513,6 +514,7 @@ class BrowseFilesPresenter @Inject constructor( //
)
} else if (!lowerFileName.endsWith(".gif") && isImageMediaType(cloudFile.name)) {
val cloudFileNodes = previewCloudFileNodes

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove newline

Comment on lines +41 to +42
if(iv_file_image.drawable == null)
iv_file_image.setImageResource(cloudFileModel.icon.iconResource)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use brackets and auto format.

@@ -106,6 +107,7 @@ class BrowseFilesFragment : BaseFragment() {
navigationMode?.let { cloudNodesAdapter.updateNavigationMode(it) }

recyclerView.layoutManager = LinearLayoutManager(context())
// recyclerView.layoutManager = GridLayoutManager(context(), 2)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove unused layout

Comment on lines +150 to +153
private fun setupThumbnailGeneration() {
val preference = findPreference(THUMBNAIL_GENERATION) as Preference?
// TODO ...
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be removed

Comment on lines +114 to +117
private val thumbnailGenerationChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->
// TODO ...
true
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be removed

@SailReal
Copy link
Member

SailReal commented May 14, 2024

Also there is a bug if you use an svg-file, then BitmapFactory.decodeStream(thumbnailReader, null, options) returns null, thumbnailBitmap is then null (I think we shouldn't even call ThumbnailUtils.extractThumbnail if it is null) and then it crashes when we write to it in thumbnailWriter.write(buff.array(), 0, buff.remaining()) because we didn't even create the file we want to write into

org.cryptomator.domain.exception.FatalBackendException: java.io.IOException: Pipe closed
    	at org.cryptomator.data.cloud.crypto.CryptoImplDecorator.read(CryptoImplDecorator.kt:422)
    	at org.cryptomator.data.cloud.crypto.CryptoCloudContentRepository.read(CryptoCloudContentRepository.kt:95)
    	at org.cryptomator.data.cloud.crypto.CryptoCloudContentRepository.read(CryptoCloudContentRepository.kt:21)
    	at org.cryptomator.data.repository.DispatchingCloudContentRepository.read(DispatchingCloudContentRepository.kt:160)
    	at org.cryptomator.domain.usecases.cloud.DownloadFiles.execute(DownloadFiles.java:32)
    	at org.cryptomator.domain.usecases.cloud.DownloadFilesUseCase$Launcher$2.subscribe(DownloadFilesUseCase.java:99)
    	at io.reactivex.internal.operators.flowable.FlowableFromPublisher.subscribeActual(FlowableFromPublisher.java:29)
    	at io.reactivex.Flowable.subscribe(Flowable.java:14935)
    	at io.reactivex.Flowable.subscribe(Flowable.java:14882)
    	at io.reactivex.internal.operators.flowable.FlowableSubscribeOn$SubscribeOnSubscriber.run(FlowableSubscribeOn.java:82)
    	at io.reactivex.internal.schedulers.ExecutorScheduler$ExecutorWorker$BooleanRunnable.run(ExecutorScheduler.java:288)
    	at io.reactivex.internal.schedulers.ExecutorScheduler$ExecutorWorker.run(ExecutorScheduler.java:253)
    	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
    	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
    	at java.lang.Thread.run(Thread.java:920)
    Caused by: java.io.IOException: Pipe closed
    	at java.io.PipedInputStream.checkStateForReceive(PipedInputStream.java:263)
    	at java.io.PipedInputStream.awaitSpace(PipedInputStream.java:271)
    	at java.io.PipedInputStream.receive(PipedInputStream.java:234)
    	at java.io.PipedOutputStream.write(PipedOutputStream.java:149)
    	at org.cryptomator.data.cloud.crypto.CryptoImplDecorator.read(CryptoImplDecorator.kt:398)
    	at org.cryptomator.data.cloud.crypto.CryptoCloudContentRepository.read(CryptoCloudContentRepository.kt:95) 
    	at org.cryptomator.data.cloud.crypto.CryptoCloudContentRepository.read(CryptoCloudContentRepository.kt:21) 
    	at org.cryptomator.data.repository.DispatchingCloudContentRepository.read(DispatchingCloudContentRepository.kt:160) 
    	at org.cryptomator.domain.usecases.cloud.DownloadFiles.execute(DownloadFiles.java:32) 
    	at org.cryptomator.domain.usecases.cloud.DownloadFilesUseCase$Launcher$2.subscribe(DownloadFilesUseCase.java:99) 
    	at io.reactivex.internal.operators.flowable.FlowableFromPublisher.subscribeActual(FlowableFromPublisher.java:29) 
    	at io.reactivex.Flowable.subscribe(Flowable.java:14935) 
    	at io.reactivex.Flowable.subscribe(Flowable.java:14882) 
    	at io.reactivex.internal.operators.flowable.FlowableSubscribeOn$SubscribeOnSubscriber.run(FlowableSubscribeOn.java:82) 
    	at io.reactivex.internal.schedulers.ExecutorScheduler$ExecutorWorker$BooleanRunnable.run(ExecutorScheduler.java:288) 
    	at io.reactivex.internal.schedulers.ExecutorScheduler$ExecutorWorker.run(ExecutorScheduler.java:253) 
    	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) 
    	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) 
    	at java.lang.Thread.run(Thread.java:920) 
    
ErrorCode: F1D9:OBF0

In this case, the file can not be opened anymore.

Please also test it with further other file types.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants