diff --git a/app/src/main/java/com/nextcloud/talk/adapters/SharedItemsAdapter.kt b/app/src/main/java/com/nextcloud/talk/adapters/SharedItemsAdapter.kt index e1b8ca3c0..119e41bef 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/SharedItemsAdapter.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/SharedItemsAdapter.kt @@ -1,18 +1,18 @@ package com.nextcloud.talk.adapters import android.net.Uri -import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import com.facebook.drawee.backends.pipeline.Fresco import com.facebook.drawee.interfaces.DraweeController +import com.facebook.drawee.view.SimpleDraweeView import com.facebook.imagepipeline.common.RotationOptions import com.facebook.imagepipeline.request.ImageRequestBuilder -import com.nextcloud.talk.activities.SharedItemsActivity import com.nextcloud.talk.databinding.AttachmentItemBinding import com.nextcloud.talk.repositories.SharedItem +import com.nextcloud.talk.utils.FileViewerUtils class SharedItemsAdapter : RecyclerView.Adapter() { @@ -50,7 +50,19 @@ class SharedItemsAdapter : RecyclerView.Adapter() holder.binding.image.controller = draweeController holder.binding.image.setOnClickListener { - Log.d(TAG, "clicked " + currentItem.name) + val fileViewerUtils = FileViewerUtils(it.context, currentItem.userEntity) + + fileViewerUtils.openFile( + currentItem.id, + currentItem.name, + currentItem.fileSize, + currentItem.path, + currentItem.link, + currentItem.mimeType, + null, + null, + it as SimpleDraweeView + ) } } } diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/MagicPreviewMessageViewHolder.java b/app/src/main/java/com/nextcloud/talk/adapters/messages/MagicPreviewMessageViewHolder.java index daeb6c3cb..9d7d40b40 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/MagicPreviewMessageViewHolder.java +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/MagicPreviewMessageViewHolder.java @@ -41,7 +41,6 @@ import android.widget.PopupMenu; import android.widget.ProgressBar; import com.facebook.drawee.view.SimpleDraweeView; -import com.google.common.util.concurrent.ListenableFuture; import com.nextcloud.talk.R; import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.components.filebrowser.models.BrowserFile; @@ -59,16 +58,14 @@ import com.stfalcon.chatkit.messages.MessageHolders; import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.List; +import java.util.Objects; import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; import javax.inject.Inject; import androidx.appcompat.view.ContextThemeWrapper; import androidx.core.content.ContextCompat; import androidx.emoji.widget.EmojiTextView; -import androidx.work.WorkInfo; -import androidx.work.WorkManager; import autodagger.AutoInjector; import io.reactivex.Single; import io.reactivex.SingleObserver; @@ -112,7 +109,6 @@ public abstract class MagicPreviewMessageViewHolder extends MessageHolders.Incom public MagicPreviewMessageViewHolder(View itemView, Object payload) { super(itemView, payload); NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this); - fileViewerUtils = new FileViewerUtils(context); } @SuppressLint("SetTextI18n") @@ -154,6 +150,8 @@ public abstract class MagicPreviewMessageViewHolder extends MessageHolders.Incom if (message.getMessageType() == ChatMessage.MessageType.SINGLE_NC_ATTACHMENT_MESSAGE) { + fileViewerUtils = new FileViewerUtils(context, message.activeUser); + String fileName = message.getSelectedIndividualHashMap().get(KEY_NAME); getMessageText().setText(fileName); if (message.getSelectedIndividualHashMap().containsKey(KEY_CONTACT_NAME)) { @@ -183,52 +181,26 @@ public abstract class MagicPreviewMessageViewHolder extends MessageHolders.Incom } if (message.activeUser != null && message.activeUser.getUsername() != null && message.activeUser.getBaseUrl() != null) { - String accountString = - message.activeUser.getUsername() + "@" + - message.activeUser.getBaseUrl() - .replace("https://", "") - .replace("http://", ""); - clickView.setOnClickListener(v -> { fileViewerUtils.openFile(message, progressBar, getMessageText(), image); }); clickView.setOnLongClickListener(l -> { - onMessageViewLongClick(message, accountString); + onMessageViewLongClick(message); return true; }); } else { Log.e(TAG, "failed to set click listener because activeUser, username or baseUrl were null"); } + fileViewerUtils.resumeToUpdateViewsByProgress( + Objects.requireNonNull(message.getSelectedIndividualHashMap().get(MagicPreviewMessageViewHolder.KEY_NAME)), + Objects.requireNonNull(message.getSelectedIndividualHashMap().get(MagicPreviewMessageViewHolder.KEY_ID)), + Objects.requireNonNull(message.getSelectedIndividualHashMap().get(MagicPreviewMessageViewHolder.KEY_MIMETYPE)), + progressBar, + getMessageText(), + image); - // check if download worker is already running - String fileId = message.getSelectedIndividualHashMap().get(KEY_ID); - ListenableFuture> workers = WorkManager.getInstance(context).getWorkInfosByTag(fileId); - - try { - for (WorkInfo workInfo : workers.get()) { - if (workInfo.getState() == WorkInfo.State.RUNNING || - workInfo.getState() == WorkInfo.State.ENQUEUED) { - progressBar.setVisibility(View.VISIBLE); - - String mimetype = message.getSelectedIndividualHashMap().get(KEY_MIMETYPE); - - WorkManager - .getInstance(context) - .getWorkInfoByIdLiveData(workInfo.getId()) - .observeForever(info -> fileViewerUtils.updateViewsByProgress( - fileName, - mimetype, - info, - progressBar, - getMessageText(), - image)); - } - } - } catch (ExecutionException | InterruptedException e) { - Log.e(TAG, "Error when checking if worker already exists", e); - } } else if (message.getMessageType() == ChatMessage.MessageType.SINGLE_LINK_GIPHY_MESSAGE) { getMessageText().setText("GIPHY"); DisplayUtils.setClickableString("GIPHY", "https://giphy.com", getMessageText()); @@ -279,7 +251,7 @@ public abstract class MagicPreviewMessageViewHolder extends MessageHolders.Incom return drawable; } - private void onMessageViewLongClick(ChatMessage message, String accountString) { + private void onMessageViewLongClick(ChatMessage message) { if (fileViewerUtils.isSupportedForInternalViewer(message.getSelectedIndividualHashMap().get(KEY_MIMETYPE))) { previewMessageInterface.onPreviewMessageLongClick(message); return; @@ -301,7 +273,11 @@ public abstract class MagicPreviewMessageViewHolder extends MessageHolders.Incom popupMenu.inflate(R.menu.chat_preview_message_menu); popupMenu.setOnMenuItemClickListener(item -> { - fileViewerUtils.openFileInFilesApp(message, accountString); + if (item.getItemId()== R.id.openInFiles){ + String keyID = message.getSelectedIndividualHashMap().get(KEY_ID); + String link = message.getSelectedIndividualHashMap().get("link"); + fileViewerUtils.openFileInFilesApp(link, keyID); + } return true; }); diff --git a/app/src/main/java/com/nextcloud/talk/models/json/chat/ChatMessage.java b/app/src/main/java/com/nextcloud/talk/models/json/chat/ChatMessage.java index 3057a51ca..e3ac0445b 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/chat/ChatMessage.java +++ b/app/src/main/java/com/nextcloud/talk/models/json/chat/ChatMessage.java @@ -156,6 +156,9 @@ public class ChatMessage implements MessageContentType, MessageContentType.Image if (MessageDigest.isEqual( Objects.requireNonNull(individualHashMap.get("type")).getBytes(Charsets.UTF_8), ("file").getBytes(Charsets.UTF_8))) { + + // TODO: this selectedIndividualHashMap stuff needs to be analyzed and most likely be refactored! + // it just feels wrong to fill this here inside getImageUrl() selectedIndividualHashMap = individualHashMap; if (!isVoiceMessage()) { if (getActiveUser() != null && getActiveUser().getBaseUrl() != null) { diff --git a/app/src/main/java/com/nextcloud/talk/repositories/SharedItem.kt b/app/src/main/java/com/nextcloud/talk/repositories/SharedItem.kt index 4b956bffa..d620c04a1 100644 --- a/app/src/main/java/com/nextcloud/talk/repositories/SharedItem.kt +++ b/app/src/main/java/com/nextcloud/talk/repositories/SharedItem.kt @@ -1,10 +1,15 @@ package com.nextcloud.talk.repositories +import com.nextcloud.talk.models.database.UserEntity + data class SharedItem( val id: String, val name: String, - val mimeType: String, + val fileSize: Int, + val path: String, val link: String, + val mimeType: String, val previewAvailable: Boolean, - val previewLink: String + val previewLink: String, + val userEntity: UserEntity, ) diff --git a/app/src/main/java/com/nextcloud/talk/repositories/SharedItemsRepository.kt b/app/src/main/java/com/nextcloud/talk/repositories/SharedItemsRepository.kt index 63ffce29c..afb6f80e4 100644 --- a/app/src/main/java/com/nextcloud/talk/repositories/SharedItemsRepository.kt +++ b/app/src/main/java/com/nextcloud/talk/repositories/SharedItemsRepository.kt @@ -4,6 +4,7 @@ import autodagger.AutoInjector import com.nextcloud.talk.api.NcApi import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication +import com.nextcloud.talk.models.database.UserEntity import com.nextcloud.talk.models.json.chat.ChatShareOverall import com.nextcloud.talk.utils.ApiUtils import io.reactivex.Observable @@ -48,6 +49,7 @@ class SharedItemsRepository { val userName: String, val userToken: String, val baseUrl: String, + val userEntity: UserEntity, val roomToken: String ) } diff --git a/app/src/main/java/com/nextcloud/talk/utils/FileViewerUtils.kt b/app/src/main/java/com/nextcloud/talk/utils/FileViewerUtils.kt index 99de87bb5..b7aabc628 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/FileViewerUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/FileViewerUtils.kt @@ -27,23 +27,68 @@ import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ACCOUNT import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_FILE_ID import androidx.emoji.widget.EmojiTextView import com.facebook.drawee.view.SimpleDraweeView +import com.nextcloud.talk.models.database.UserEntity import java.io.File import java.util.concurrent.ExecutionException -class FileViewerUtils(private val context: Context) { - fun openFile(message: ChatMessage, progressBar: ProgressBar, messageText: EmojiTextView, previewImage: SimpleDraweeView) { - val accountString = message.activeUser.username + "@" + - message.activeUser.baseUrl - .replace("https://", "") - .replace("http://", "") +class FileViewerUtils(private val context: Context, private val userEntity: UserEntity) { + fun openFile( + message: ChatMessage, + progressBar: ProgressBar?, + messageText: EmojiTextView?, + previewImage: SimpleDraweeView + ) { val fileName = message.getSelectedIndividualHashMap()[MagicPreviewMessageViewHolder.KEY_NAME]!! val mimetype = message.getSelectedIndividualHashMap()[MagicPreviewMessageViewHolder.KEY_MIMETYPE]!! + val link = message.getSelectedIndividualHashMap()["link"]!! + val fileId = message.getSelectedIndividualHashMap()[MagicPreviewMessageViewHolder.KEY_ID]!! + val path = message.getSelectedIndividualHashMap()[MagicPreviewMessageViewHolder.KEY_PATH]!! + + var size = message.getSelectedIndividualHashMap()["size"] + if (size == null) { + size = "-1" + } + val fileSize = Integer.valueOf(size) + + openFile( + fileId, + fileName, + fileSize, + path, + link, + mimetype, + progressBar, + messageText, + previewImage + ) + } + + fun openFile( + fileId: String, + fileName: String, + fileSize: Int, + path: String, + link: String, + mimetype: String, + progressBar: ProgressBar?, + messageText: EmojiTextView?, + previewImage: SimpleDraweeView + ) { if (isSupportedForInternalViewer(mimetype) || canBeHandledByExternalApp(mimetype, fileName)) { - openOrDownloadFile(message, progressBar, messageText, previewImage) + openOrDownloadFile( + fileName, + fileId, + path, + fileSize, + mimetype, + progressBar, + messageText, + previewImage + ) } else { - openFileInFilesApp(message, accountString) + openFileInFilesApp(link, fileId) } } @@ -55,26 +100,51 @@ class FileViewerUtils(private val context: Context) { return intent.resolveActivity(context.packageManager) != null } - private fun openOrDownloadFile(message: ChatMessage, progressBar: ProgressBar, messageText: EmojiTextView, previewImage: SimpleDraweeView) { - val filename = message.getSelectedIndividualHashMap()[MagicPreviewMessageViewHolder.KEY_NAME] - val mimetype = message.getSelectedIndividualHashMap()[MagicPreviewMessageViewHolder.KEY_MIMETYPE] - val file = File(context.cacheDir, filename) + private fun openOrDownloadFile( + fileName: String, + fileId: String, + path: String, + fileSize: Int, + mimetype: String, + progressBar: ProgressBar?, + messageText: EmojiTextView?, + previewImage: SimpleDraweeView + ) { + val file = File(context.cacheDir, fileName) if (file.exists()) { - openFile(filename!!, mimetype!!) + openFileByMimetype(fileName!!, mimetype!!) } else { - downloadFileToCache(message, progressBar, messageText, previewImage) + downloadFileToCache( + fileName, + fileId, + path, + fileSize, + mimetype, + progressBar, + messageText, + previewImage + ) } } - private fun openFile(filename: String, mimetype: String) { + private fun openFileByMimetype(filename: String, mimetype: String) { when (mimetype) { - "audio/mpeg", "audio/wav", "audio/ogg", "video/mp4", "video/quicktime", "video/ogg" -> openMediaView( - filename, - mimetype - ) - "image/png", "image/jpeg", "image/gif" -> openImageView(filename, mimetype) - "text/markdown", "text/plain" -> openTextView(filename, mimetype) - else -> openFileByExternalApp(filename, mimetype) + "audio/mpeg", + "audio/wav", + "audio/ogg", + "video/mp4", + "video/quicktime", + "video/ogg" + -> openMediaView(filename, mimetype) + "image/png", + "image/jpeg", + "image/gif" + -> openImageView(filename, mimetype) + "text/markdown", + "text/plain" + -> openTextView(filename, mimetype) + else + -> openFileByExternalApp(filename, mimetype) } } @@ -106,7 +176,12 @@ class FileViewerUtils(private val context: Context) { } } - fun openFileInFilesApp(message: ChatMessage, accountString: String) { + fun openFileInFilesApp(link: String, keyID: String) { + val accountString = userEntity.username + "@" + + userEntity.baseUrl + .replace("https://", "") + .replace("http://", "") + if (canWeOpenFilesApp(context, accountString)) { val filesAppIntent = Intent(Intent.ACTION_VIEW, null) val componentName = ComponentName( @@ -117,15 +192,12 @@ class FileViewerUtils(private val context: Context) { filesAppIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) filesAppIntent.setPackage(context.getString(R.string.nc_import_accounts_from)) filesAppIntent.putExtra(KEY_ACCOUNT, accountString) - filesAppIntent.putExtra( - KEY_FILE_ID, - message.getSelectedIndividualHashMap()[MagicPreviewMessageViewHolder.KEY_ID] - ) + filesAppIntent.putExtra(KEY_FILE_ID, keyID) context.startActivity(filesAppIntent) } else { val browserIntent = Intent( Intent.ACTION_VIEW, - Uri.parse(message.getSelectedIndividualHashMap()["link"]) + Uri.parse(link) ) browserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) context.startActivity(browserIntent) @@ -176,20 +248,16 @@ class FileViewerUtils(private val context: Context) { } @SuppressLint("LongLogTag") - private fun downloadFileToCache(message: ChatMessage, progressBar: ProgressBar, messageText: EmojiTextView, previewImage: SimpleDraweeView) { - val baseUrl = message.activeUser.baseUrl - val userId = message.activeUser.userId - val attachmentFolder = CapabilitiesUtil.getAttachmentFolder(message.activeUser) - val fileName = message.getSelectedIndividualHashMap()[MagicPreviewMessageViewHolder.KEY_NAME]!! - val mimetype = message.getSelectedIndividualHashMap()[MagicPreviewMessageViewHolder.KEY_MIMETYPE]!! - var size = message.getSelectedIndividualHashMap()["size"] - if (size == null) { - size = "-1" - } - val fileSize = Integer.valueOf(size) - val fileId = message.getSelectedIndividualHashMap()[MagicPreviewMessageViewHolder.KEY_ID] - val path = message.getSelectedIndividualHashMap()[MagicPreviewMessageViewHolder.KEY_PATH] - + private fun downloadFileToCache( + fileName: String, + fileId: String, + path: String, + fileSize: Int, + mimetype: String, + progressBar: ProgressBar?, + messageText: EmojiTextView?, + previewImage: SimpleDraweeView + ) { // check if download worker is already running val workers = WorkManager.getInstance(context).getWorkInfosByTag( fileId!! @@ -208,9 +276,12 @@ class FileViewerUtils(private val context: Context) { } val downloadWorker: OneTimeWorkRequest val data: Data = Data.Builder() - .putString(DownloadFileToCacheWorker.KEY_BASE_URL, baseUrl) - .putString(DownloadFileToCacheWorker.KEY_USER_ID, userId) - .putString(DownloadFileToCacheWorker.KEY_ATTACHMENT_FOLDER, attachmentFolder) + .putString(DownloadFileToCacheWorker.KEY_BASE_URL, userEntity.baseUrl) + .putString(DownloadFileToCacheWorker.KEY_USER_ID, userEntity.userId) + .putString( + DownloadFileToCacheWorker.KEY_ATTACHMENT_FOLDER, + CapabilitiesUtil.getAttachmentFolder(userEntity) + ) .putString(DownloadFileToCacheWorker.KEY_FILE_NAME, fileName) .putString(DownloadFileToCacheWorker.KEY_FILE_PATH, path) .putInt(DownloadFileToCacheWorker.KEY_FILE_SIZE, fileSize) @@ -220,7 +291,7 @@ class FileViewerUtils(private val context: Context) { .addTag(fileId) .build() WorkManager.getInstance().enqueue(downloadWorker) - progressBar.visibility = View.VISIBLE + progressBar?.visibility = View.VISIBLE WorkManager.getInstance(context).getWorkInfoByIdLiveData(downloadWorker.id) .observeForever { workInfo: WorkInfo? -> updateViewsByProgress( @@ -234,19 +305,19 @@ class FileViewerUtils(private val context: Context) { } } - fun updateViewsByProgress( + private fun updateViewsByProgress( fileName: String, mimetype: String, workInfo: WorkInfo, - progressBar: ProgressBar, - messageText: EmojiTextView, + progressBar: ProgressBar?, + messageText: EmojiTextView?, previewImage: SimpleDraweeView ) { when (workInfo.state) { WorkInfo.State.RUNNING -> { val progress = workInfo.progress.getInt(DownloadFileToCacheWorker.PROGRESS, -1) if (progress > -1) { - messageText.text = String.format( + messageText?.text = String.format( context.resources.getString(R.string.filename_progress), fileName, progress @@ -255,25 +326,66 @@ class FileViewerUtils(private val context: Context) { } WorkInfo.State.SUCCEEDED -> { if (previewImage.isShown) { - openFile(fileName, mimetype) + openFileByMimetype(fileName, mimetype) } else { - Log.d(TAG, "file " + fileName + + Log.d( + TAG, "file " + fileName + " was downloaded but it's not opened because view is not shown on screen" ) } - messageText.text = fileName - progressBar.visibility = View.GONE + messageText?.text = fileName + progressBar?.visibility = View.GONE } WorkInfo.State.FAILED -> { - messageText.text = fileName - progressBar.visibility = View.GONE + messageText?.text = fileName + progressBar?.visibility = View.GONE } else -> { } } } + fun resumeToUpdateViewsByProgress( + fileName: String, + fileId: String, + mimeType: String, + progressBar: ProgressBar, + messageText: EmojiTextView?, + previewImage: SimpleDraweeView + ) { + val workers = WorkManager.getInstance(context).getWorkInfosByTag(fileId) + + try { + for (workInfo in workers.get()) { + if (workInfo.state == WorkInfo.State.RUNNING || + workInfo.state == WorkInfo.State.ENQUEUED + ) { + progressBar.visibility = View.VISIBLE + WorkManager + .getInstance(context) + .getWorkInfoByIdLiveData(workInfo.id) + .observeForever { info: WorkInfo? -> + updateViewsByProgress( + fileName, + mimeType, + info!!, + progressBar, + messageText, + previewImage + ) + } + } + } + } catch (e: ExecutionException) { + Log.e(TAG, "Error when checking if worker already exists", e) + } catch (e: InterruptedException) { + Log.e(TAG, "Error when checking if worker already exists", e) + } + } + companion object { private val TAG = FileViewerUtils::class.simpleName + + const val KEY_ID = "id" } } \ No newline at end of file diff --git a/app/src/main/java/com/nextcloud/talk/viewmodels/SharedItemsViewModel.kt b/app/src/main/java/com/nextcloud/talk/viewmodels/SharedItemsViewModel.kt index 25e0667a6..183187931 100644 --- a/app/src/main/java/com/nextcloud/talk/viewmodels/SharedItemsViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/viewmodels/SharedItemsViewModel.kt @@ -51,10 +51,15 @@ class SharedItemsViewModel(private val repository: SharedItemsRepository) : View val previewAvailable = "yes".equals(fileParameters["preview-available"]!!, ignoreCase = true) items[it.value.id] = SharedItem( - fileParameters["id"]!!, fileParameters["name"]!!, - fileParameters["mimetype"]!!, fileParameters["link"]!!, + fileParameters["id"]!!, + fileParameters["name"]!!, + fileParameters["size"]!!.toInt(), + fileParameters["path"]!!, + fileParameters["link"]!!, + fileParameters["mimetype"]!!, previewAvailable, - repository.previewLink(fileParameters["id"]) + repository.previewLink(fileParameters["id"]), + repository.parameters!!.userEntity ) } } @@ -84,6 +89,7 @@ class SharedItemsViewModel(private val repository: SharedItemsRepository) : View userEntity.userId, userEntity.token, userEntity.baseUrl, + userEntity, roomToken )