Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ object ThumbnailsRequester : KoinComponent {

private val thumbnailImageLoaders = ConcurrentHashMap<String, ImageLoader>()
private val avatarImageLoaders = ConcurrentHashMap<String, ImageLoader>()
private val accountBaseUrls = ConcurrentHashMap<String, String>()

private val sharedDiskCache: DiskCache by lazy {
DiskCache.Builder()
Expand All @@ -86,11 +87,12 @@ object ThumbnailsRequester : KoinComponent {
}

fun getAvatarUri(account: Account): String {
val accountManager = AccountManager.get(appContext)
val baseUrl =
val baseUrl = accountBaseUrls.getOrPut(account.name) {
val accountManager = AccountManager.get(appContext)
accountManager.getUserData(account, eu.opencloud.android.lib.common.accounts.AccountUtils.Constants.KEY_OC_BASE_URL)
?.trimEnd('/')
.orEmpty()
}
// ?u= disambiguates the Coil cache key per account; without it two accounts
// on the same server share the same URL and collide in the shared disk/memory cache.
return "$baseUrl/graph/v1.0/me/photo/\$value?u=${account.name.hashCode().toString(16)}"
Expand All @@ -106,10 +108,12 @@ object ThumbnailsRequester : KoinComponent {
String.format(Locale.US, SPACE_SPECIAL_PREVIEW_URI, spaceSpecial.webDavUrl, 1024, 1024, spaceSpecial.eTag)

private fun getPreviewUri(remotePath: String?, etag: String?, account: Account, width: Int, height: Int): String {
val accountManager = AccountManager.get(appContext)
val baseUrl = accountManager.getUserData(account, eu.opencloud.android.lib.common.accounts.AccountUtils.Constants.KEY_OC_BASE_URL)
?.trimEnd('/')
.orEmpty()
val baseUrl = accountBaseUrls.getOrPut(account.name) {
val accountManager = AccountManager.get(appContext)
accountManager.getUserData(account, eu.opencloud.android.lib.common.accounts.AccountUtils.Constants.KEY_OC_BASE_URL)
?.trimEnd('/')
.orEmpty()
}
val path = if (remotePath?.startsWith("/") == true) remotePath else "/$remotePath"
val encodedPath = Uri.encode(path, "/")

Expand Down Expand Up @@ -156,7 +160,9 @@ object ThumbnailsRequester : KoinComponent {
// must not run on the main thread.
clientManager.getClientForCoilThumbnails(account.name)
.okHttpClient.newBuilder()
.addInterceptor(interceptor).build()
.addInterceptor(interceptor)
.addNetworkInterceptor(CoilCacheResponseInterceptor())
.build()
}
.apply { if (preferencesProvider.getBoolean("enable_logging", false)) logger(DebugLogger()) }
.memoryCache { sharedMemoryCache }
Expand All @@ -172,6 +178,7 @@ object ThumbnailsRequester : KoinComponent {
clientManager.getClientForCoilThumbnails(account.name)
.okHttpClient.newBuilder()
.addInterceptor(interceptor)
.addNetworkInterceptor(CoilCacheResponseInterceptor())
.cache(avatarHttpCache)
.build()
}
Expand Down Expand Up @@ -221,7 +228,13 @@ object ThumbnailsRequester : KoinComponent {
requestHeaders.toHeaders().forEach { requestBuilder.addHeader(it.first, it.second) }
val requestWithHeaders = requestBuilder.build()

var response = chain.proceed(requestWithHeaders)
return chain.proceed(requestWithHeaders)
}
}

private class CoilCacheResponseInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val response = chain.proceed(chain.request())

var builder = response.newBuilder()
var changed = false
Expand Down Expand Up @@ -252,6 +265,5 @@ object ThumbnailsRequester : KoinComponent {
}
return response
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,9 @@ class CreateRemoteShareOperation(
}

if (expirationDateInMillis > INIT_EXPIRATION_DATE_IN_MILLIS) {
val dateFormat = SimpleDateFormat(FORMAT_EXPIRATION_DATE, Locale.getDefault())
val dateFormat = SimpleDateFormat(FORMAT_EXPIRATION_DATE, Locale.getDefault()).apply {
timeZone = java.util.TimeZone.getTimeZone("UTC")
}
val expirationDate = Calendar.getInstance()
expirationDate.timeInMillis = expirationDateInMillis
val formattedExpirationDate = dateFormat.format(expirationDate.time)
Expand Down Expand Up @@ -197,6 +199,9 @@ class CreateRemoteShareOperation(
private const val PARAM_PERMISSIONS = "permissions"

//Arguments - constant values
private const val FORMAT_EXPIRATION_DATE = "yyyy-MM-dd"
// ISO-8601 UTC format is required by the backend to correctly parse expiration dates,
// especially for private user/group share creations and updates, ensuring compatibility
// when these features are eventually exposed in the mobile UI.
private const val FORMAT_EXPIRATION_DATE = "yyyy-MM-dd'T'HH:mm:ss'Z'"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,9 @@ class UpdateRemoteShareOperation

} else if (expirationDateInMillis > INITIAL_EXPIRATION_DATE_IN_MILLIS) {
// set expiration date
val dateFormat = SimpleDateFormat(FORMAT_EXPIRATION_DATE, Locale.getDefault())
val dateFormat = SimpleDateFormat(FORMAT_EXPIRATION_DATE, Locale.getDefault()).apply {
timeZone = java.util.TimeZone.getTimeZone("UTC")
}
val expirationDate = Calendar.getInstance()
expirationDate.timeInMillis = expirationDateInMillis
val formattedExpirationDate = dateFormat.format(expirationDate.time)
Expand Down Expand Up @@ -216,7 +218,10 @@ class UpdateRemoteShareOperation
private const val PARAM_PERMISSIONS = "permissions"

//Arguments - constant values
private const val FORMAT_EXPIRATION_DATE = "yyyy-MM-dd"
// ISO-8601 UTC format is required by the backend to correctly parse expiration dates,
// especially for private user/group share creations and updates, ensuring compatibility
// when these features are eventually exposed in the mobile UI.
private const val FORMAT_EXPIRATION_DATE = "yyyy-MM-dd'T'HH:mm:ss'Z'"
private const val INITIAL_EXPIRATION_DATE_IN_MILLIS: Long = 0
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,11 @@ class OCRemoteFileDataSource(
OCFile(
owner = owner,
remoteId = remoteId,
remotePath = remotePath,
remotePath = if (isFolder && !remotePath.endsWith(OCFile.PATH_SEPARATOR)) {
"$remotePath${OCFile.PATH_SEPARATOR}"
} else {
remotePath
},
length = if (isFolder) {
size
} else {
Expand Down
Loading