From da33cbedda02320d9e90aa421a1abb7910cbf048 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 8 Jan 2021 12:23:02 +0100 Subject: [PATCH] Introduce LocalFilesHelper to avoid using the Context directly --- .../vector/app/core/files/LocalFilesHelper.kt | 41 +++++++++++++++++++ .../vector/app/core/glide/MyAppGlideModule.kt | 3 +- .../app/core/glide/VectorGlideModelLoader.kt | 19 ++++----- .../im/vector/app/core/utils/FileUtils.kt | 16 -------- .../timeline/factory/MessageItemFactory.kt | 9 ++-- .../timeline/item/MessageImageVideoItem.kt | 4 +- .../features/media/ImageContentRenderer.kt | 7 ++-- .../features/media/VideoContentRenderer.kt | 9 ++-- 8 files changed, 65 insertions(+), 43 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/core/files/LocalFilesHelper.kt diff --git a/vector/src/main/java/im/vector/app/core/files/LocalFilesHelper.kt b/vector/src/main/java/im/vector/app/core/files/LocalFilesHelper.kt new file mode 100644 index 0000000000..d9cf4fc484 --- /dev/null +++ b/vector/src/main/java/im/vector/app/core/files/LocalFilesHelper.kt @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2021 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.core.files + +import android.content.Context +import android.net.Uri +import androidx.documentfile.provider.DocumentFile +import org.matrix.android.sdk.api.extensions.orFalse +import java.io.InputStream +import javax.inject.Inject + +class LocalFilesHelper @Inject constructor(private val context: Context) { + fun isLocalFile(fileUri: String?): Boolean { + return fileUri + ?.let { Uri.parse(it) } + ?.let { DocumentFile.fromSingleUri(context, it) } + ?.exists() + .orFalse() + } + + fun openInputStream(fileUri: String?): InputStream? { + return fileUri + ?.takeIf { isLocalFile(it) } + ?.let { Uri.parse(it) } + ?.let { context.contentResolver.openInputStream(it) } + } +} diff --git a/vector/src/main/java/im/vector/app/core/glide/MyAppGlideModule.kt b/vector/src/main/java/im/vector/app/core/glide/MyAppGlideModule.kt index d73c64b087..edd8de2f79 100644 --- a/vector/src/main/java/im/vector/app/core/glide/MyAppGlideModule.kt +++ b/vector/src/main/java/im/vector/app/core/glide/MyAppGlideModule.kt @@ -25,6 +25,7 @@ import com.bumptech.glide.Registry import com.bumptech.glide.annotation.GlideModule import com.bumptech.glide.module.AppGlideModule import im.vector.app.core.extensions.vectorComponent +import im.vector.app.core.files.LocalFilesHelper import im.vector.app.features.media.ImageContentRenderer import java.io.InputStream @@ -38,6 +39,6 @@ class MyAppGlideModule : AppGlideModule() { override fun registerComponents(context: Context, glide: Glide, registry: Registry) { registry.append(ImageContentRenderer.Data::class.java, InputStream::class.java, - VectorGlideModelLoaderFactory(context, context.vectorComponent().activeSessionHolder())) + VectorGlideModelLoaderFactory(LocalFilesHelper(context), context.vectorComponent().activeSessionHolder())) } } diff --git a/vector/src/main/java/im/vector/app/core/glide/VectorGlideModelLoader.kt b/vector/src/main/java/im/vector/app/core/glide/VectorGlideModelLoader.kt index 600ed0317e..3acbba6337 100644 --- a/vector/src/main/java/im/vector/app/core/glide/VectorGlideModelLoader.kt +++ b/vector/src/main/java/im/vector/app/core/glide/VectorGlideModelLoader.kt @@ -16,7 +16,6 @@ package im.vector.app.core.glide -import android.content.Context import com.bumptech.glide.Priority import com.bumptech.glide.load.DataSource import com.bumptech.glide.load.Options @@ -26,8 +25,7 @@ import com.bumptech.glide.load.model.ModelLoaderFactory import com.bumptech.glide.load.model.MultiModelLoaderFactory import com.bumptech.glide.signature.ObjectKey import im.vector.app.core.di.ActiveSessionHolder -import im.vector.app.core.utils.isLocalFile -import im.vector.app.core.utils.openInputStream +import im.vector.app.core.files.LocalFilesHelper import im.vector.app.features.media.ImageContentRenderer import okhttp3.OkHttpClient import org.matrix.android.sdk.api.MatrixCallback @@ -36,12 +34,12 @@ import java.io.File import java.io.IOException import java.io.InputStream -class VectorGlideModelLoaderFactory(private val context: Context, +class VectorGlideModelLoaderFactory(private val localFilesHelper: LocalFilesHelper, private val activeSessionHolder: ActiveSessionHolder ) : ModelLoaderFactory { override fun build(multiFactory: MultiModelLoaderFactory): ModelLoader { - return VectorGlideModelLoader(context, activeSessionHolder) + return VectorGlideModelLoader(localFilesHelper, activeSessionHolder) } override fun teardown() { @@ -49,7 +47,8 @@ class VectorGlideModelLoaderFactory(private val context: Context, } } -class VectorGlideModelLoader(private val context: Context, private val activeSessionHolder: ActiveSessionHolder) +class VectorGlideModelLoader(private val localFilesHelper: LocalFilesHelper, + private val activeSessionHolder: ActiveSessionHolder) : ModelLoader { override fun handles(model: ImageContentRenderer.Data): Boolean { // Always handle @@ -57,11 +56,11 @@ class VectorGlideModelLoader(private val context: Context, private val activeSes } override fun buildLoadData(model: ImageContentRenderer.Data, width: Int, height: Int, options: Options): ModelLoader.LoadData? { - return ModelLoader.LoadData(ObjectKey(model), VectorGlideDataFetcher(context, activeSessionHolder, model, width, height)) + return ModelLoader.LoadData(ObjectKey(model), VectorGlideDataFetcher(localFilesHelper, activeSessionHolder, model, width, height)) } } -class VectorGlideDataFetcher(private val context: Context, +class VectorGlideDataFetcher(private val localFilesHelper: LocalFilesHelper, private val activeSessionHolder: ActiveSessionHolder, private val data: ImageContentRenderer.Data, private val width: Int, @@ -102,8 +101,8 @@ class VectorGlideDataFetcher(private val context: Context, override fun loadData(priority: Priority, callback: DataFetcher.DataCallback) { Timber.v("Load data: $data") - if (data.url.isLocalFile(context)) { - data.url.openInputStream(context)?.use { + if (localFilesHelper.isLocalFile(data.url)) { + localFilesHelper.openInputStream(data.url)?.use { callback.onDataReady(it) } return diff --git a/vector/src/main/java/im/vector/app/core/utils/FileUtils.kt b/vector/src/main/java/im/vector/app/core/utils/FileUtils.kt index 2be06c09a5..b5ce922487 100644 --- a/vector/src/main/java/im/vector/app/core/utils/FileUtils.kt +++ b/vector/src/main/java/im/vector/app/core/utils/FileUtils.kt @@ -17,29 +17,13 @@ package im.vector.app.core.utils import android.content.Context -import android.net.Uri -import androidx.documentfile.provider.DocumentFile -import org.matrix.android.sdk.api.extensions.orFalse import timber.log.Timber import java.io.File -import java.io.InputStream import java.util.Locale // Implementation should return true in case of success typealias ActionOnFile = (file: File) -> Boolean -internal fun String?.isLocalFile(context: Context): Boolean { - return this?.let { - DocumentFile.fromSingleUri(context, Uri.parse(it))?.exists() - }.orFalse() -} - -internal fun String?.openInputStream(context: Context): InputStream? { - return if (isLocalFile(context)) { - context.contentResolver.openInputStream(Uri.parse(this)) - } else null -} - /* ========================================================================================== * Delete * ========================================================================================== */ diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt index 3dea83032c..4f52fcb54c 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt @@ -16,7 +16,6 @@ package im.vector.app.features.home.room.detail.timeline.factory -import android.content.Context import android.text.SpannableStringBuilder import android.text.Spanned import android.text.TextPaint @@ -27,12 +26,12 @@ import android.view.View import dagger.Lazy import im.vector.app.R import im.vector.app.core.epoxy.VectorEpoxyModel +import im.vector.app.core.files.LocalFilesHelper import im.vector.app.core.resources.ColorProvider import im.vector.app.core.resources.StringProvider import im.vector.app.core.utils.DebouncedClickListener import im.vector.app.core.utils.DimensionConverter import im.vector.app.core.utils.containsOnlyEmojis -import im.vector.app.core.utils.isLocalFile import im.vector.app.features.home.room.detail.timeline.TimelineEventController import im.vector.app.features.home.room.detail.timeline.helper.AvatarSizeProvider import im.vector.app.features.home.room.detail.timeline.helper.ContentDownloadStateTrackerBinder @@ -95,7 +94,7 @@ import org.matrix.android.sdk.internal.crypto.model.event.EncryptedEventContent import javax.inject.Inject class MessageItemFactory @Inject constructor( - private val context: Context, + private val localFilesHelper: LocalFilesHelper, private val colorProvider: ColorProvider, private val dimensionConverter: DimensionConverter, private val timelineMediaSizeProvider: TimelineMediaSizeProvider, @@ -207,7 +206,7 @@ class MessageItemFactory @Inject constructor( } ?: "" return MessageFileItem_() .attributes(attributes) - .izLocalFile(fileUrl.isLocalFile(context)) + .izLocalFile(localFilesHelper.isLocalFile(fileUrl)) .izDownloaded(session.fileService().isFileInCache( fileUrl, messageContent.getFileName(), @@ -272,7 +271,7 @@ class MessageItemFactory @Inject constructor( return MessageFileItem_() .attributes(attributes) .leftGuideline(avatarSizeProvider.leftGuideline) - .izLocalFile(messageContent.getFileUrl().isLocalFile(context)) + .izLocalFile(localFilesHelper.isLocalFile(messageContent.getFileUrl())) .izDownloaded(session.fileService().isFileInCache(messageContent)) .mxcUrl(mxcUrl) .contentUploadStateTrackerBinder(contentUploadStateTrackerBinder) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageImageVideoItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageImageVideoItem.kt index a8d5ed1631..5d14178088 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageImageVideoItem.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageImageVideoItem.kt @@ -25,8 +25,8 @@ import androidx.core.view.isVisible import com.airbnb.epoxy.EpoxyAttribute import com.airbnb.epoxy.EpoxyModelClass import im.vector.app.R +import im.vector.app.core.files.LocalFilesHelper import im.vector.app.core.glide.GlideApp -import im.vector.app.core.utils.isLocalFile import im.vector.app.features.home.room.detail.timeline.helper.ContentUploadStateTrackerBinder import im.vector.app.features.media.ImageContentRenderer import org.matrix.android.sdk.api.session.room.send.SendState @@ -56,7 +56,7 @@ abstract class MessageImageVideoItem : AbsMessageItem