Skip to content

Commit

Permalink
Mobileapps 1380 (#102)
Browse files Browse the repository at this point in the history
* Mobileapps 1314 (#146)

* added screen to view all attached files related to a task

* added attachment screen and preview for attachment

* add analytics for attached files screen

* if the file is already available on the device then it will open its preview directly otherwise download it first.

* codacy correction

* code merging
  • Loading branch information
aman-alfresco authored Aug 22, 2022
1 parent 461d8a4 commit 9a1a40a
Show file tree
Hide file tree
Showing 26 changed files with 452 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import com.alfresco.content.data.BrowseRepository
import com.alfresco.content.data.Entry
import com.alfresco.content.data.EventName
import com.alfresco.content.data.OfflineRepository
import com.alfresco.content.data.TaskRepository
import com.alfresco.content.mimetype.MimeType
import com.alfresco.download.ContentDownloader
import com.google.android.material.dialog.MaterialAlertDialogBuilder
Expand All @@ -20,6 +21,7 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
import kotlinx.coroutines.cancelAndJoin
import kotlinx.coroutines.suspendCancellableCoroutine
import okhttp3.OkHttpClient

data class ActionOpenWith(
override var entry: Entry,
Expand All @@ -37,18 +39,31 @@ data class ActionOpenWith(
fetchRemoteFile(context)
}

showFileChooserDialog(context, target)

return entry
return if (!entry.isProcessService) {
showFileChooserDialog(context, target)
entry
} else Entry.updateDownloadEntry(entry, target.path)
}

private suspend fun fetchRemoteFile(context: Context): File {
val deferredDialog = showProgressDialogAsync(context)

val uri = BrowseRepository().contentUri(entry)
val output = File(context.cacheDir, entry.name)
val uri: String
val client: OkHttpClient?
val output: File

if (entry.isProcessService) {
uri = TaskRepository().contentUri(entry)
client = TaskRepository().getHttpClient()
output = TaskRepository().getContentDirectory(entry.name)
} else {
uri = BrowseRepository().contentUri(entry)
client = null
output = File(context.cacheDir, entry.name)
}

val deferredDownload = GlobalScope.async(Dispatchers.IO) {
ContentDownloader.downloadFileTo(uri, output.path)
ContentDownloader.downloadFileTo(uri, output.path, client)
}
this.deferredDownload.compareAndSet(null, deferredDownload)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,10 +174,7 @@ class BrowseFragment : ListFragment<BrowseViewModel, BrowseViewState>() {

if (entry.isUpload)
entry.mimeType?.let {
findNavController().navigateToLocalPreview(
it,
entry.path.toString(), entry.name
)
findNavController().navigateToLocalPreview(it, entry.path.toString(), entry.name)
}
else
findNavController().navigateTo(entry)
Expand Down Expand Up @@ -215,7 +212,7 @@ class BrowseFragment : ListFragment<BrowseViewModel, BrowseViewState>() {
}
}

override fun onFolderCreated(entry: Entry) {
override fun onEntryCreated(entry: Entry) {
if (isAdded)
onItemClicked(entry)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class OfflineFragment : ListFragment<OfflineViewModel, OfflineViewState>() {
fab = null
}

override fun onFolderCreated(entry: Entry) {
override fun onEntryCreated(entry: Entry) {
TODO("Not yet implemented")
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,10 @@ class LocalPreviewActivity : AppCompatActivity() {
fragment.arguments = intent.extras
}
}

companion object {
const val KEY_PATH = "path"
const val KEY_MIME_TYPE = "mimeType"
const val KEY_TITLE = "title"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package com.alfresco.content.browse.tasks.attachments

import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.RecyclerView
import com.airbnb.epoxy.AsyncEpoxyController
import com.airbnb.mvrx.MavericksView
import com.airbnb.mvrx.activityViewModel
import com.airbnb.mvrx.withState
import com.alfresco.content.actions.ActionOpenWith
import com.alfresco.content.browse.R
import com.alfresco.content.browse.databinding.FragmentAttachedFilesBinding
import com.alfresco.content.browse.preview.LocalPreviewActivity
import com.alfresco.content.browse.tasks.detail.TaskDetailViewModel
import com.alfresco.content.data.AnalyticsManager
import com.alfresco.content.data.ContentEntry
import com.alfresco.content.data.Entry
import com.alfresco.content.data.PageView
import com.alfresco.content.listview.EntryListener
import com.alfresco.content.simpleController
import com.alfresco.ui.getDrawableForAttribute

/**
* Marked as AttachedFilesFragment class
*/
class AttachedFilesFragment : Fragment(), MavericksView, EntryListener {

val viewModel: TaskDetailViewModel by activityViewModel()
private lateinit var binding: FragmentAttachedFilesBinding
private val epoxyController: AsyncEpoxyController by lazy { epoxyController() }

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentAttachedFilesBinding.inflate(inflater, container, false)
return binding.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

AnalyticsManager().screenViewEvent(PageView.AttachedFiles)

binding.toolbar.apply {
navigationContentDescription = getString(R.string.label_navigation_back)
navigationIcon = requireContext().getDrawableForAttribute(R.attr.homeAsUpIndicator)
setNavigationOnClickListener { requireActivity().onBackPressed() }
title = resources.getString(R.string.title_attached_files)
}

binding.recyclerView.setController(epoxyController)

epoxyController.adapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
if (positionStart == 0) {
// @see: https://github.com/airbnb/epoxy/issues/224
binding.recyclerView.layoutManager?.scrollToPosition(0)
}
}
})
binding.refreshLayout.setOnRefreshListener {
viewModel.getComments()
}

viewModel.setListener(this)
}

override fun invalidate() = withState(viewModel) { state ->
if (state.requestContents.complete) {
binding.refreshLayout.isRefreshing = false
}

epoxyController.requestModelBuild()

if (state.listContents.size > 4) {
binding.tvNoOfAttachments.visibility = View.VISIBLE
binding.tvNoOfAttachments.text = getString(R.string.text_multiple_attachment, state.listContents.size)
} else {
binding.tvNoOfAttachments.visibility = View.GONE
}
}

private fun epoxyController() = simpleController(viewModel) { state ->

if (state.listContents.isNotEmpty()) {
state.listContents.forEach { obj ->
listViewAttachmentRow {
id(obj.id)
data(obj)
clickListener { model, _, _, _ -> onItemClicked(model.data()) }
}
}
}
}

private fun onItemClicked(contentEntry: ContentEntry) {
viewModel.execute(ActionOpenWith(Entry.convertContentEntryToEntry(contentEntry)))
}

override fun onEntryCreated(entry: Entry) {
if (isAdded)
entry.mimeType?.let {
startActivity(
Intent(requireActivity(), LocalPreviewActivity::class.java)
.putExtra(LocalPreviewActivity.KEY_PATH, entry.path)
.putExtra(LocalPreviewActivity.KEY_MIME_TYPE, it)
.putExtra(LocalPreviewActivity.KEY_TITLE, entry.name)
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.alfresco.content.browse.tasks.attachments

import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.FrameLayout
import androidx.core.content.res.ResourcesCompat
import com.airbnb.epoxy.CallbackProp
import com.airbnb.epoxy.ModelProp
import com.airbnb.epoxy.ModelView
import com.alfresco.content.browse.databinding.ViewListAttachmentRowBinding
import com.alfresco.content.data.ContentEntry
import com.alfresco.content.mimetype.MimeType

/**
* Marked as ListViewAttachmentRow class
*/
@ModelView(autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT)
class ListViewAttachmentRow @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) {

private val binding = ViewListAttachmentRowBinding.inflate(LayoutInflater.from(context), this)

/**
* set the content data on list row
*/
@ModelProp
fun setData(data: ContentEntry) {
binding.tvName.text = data.name
binding.iconFile.setImageDrawable(ResourcesCompat.getDrawable(resources, MimeType.with(data.mimeType).icon, context.theme))
}

/**
* list row click listener
*/
@CallbackProp
fun setClickListener(listener: OnClickListener?) {
setOnClickListener(listener)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import com.airbnb.mvrx.withState
import com.alfresco.content.browse.R
import com.alfresco.content.browse.databinding.FragmentCommentsBinding
import com.alfresco.content.browse.tasks.detail.TaskDetailViewModel
import com.alfresco.content.browse.tasks.detail.listViewCommentRow
import com.alfresco.content.data.AnalyticsManager
import com.alfresco.content.data.PageView
import com.alfresco.content.hideSoftInput
Expand Down Expand Up @@ -98,13 +97,11 @@ class CommentsFragment : Fragment(), MavericksView {
})

requireActivity().window.decorView.viewTreeObserver.addOnGlobalLayoutListener {
println("CommentsFragment.setListeners 1")
if (isAdded) {
val r = Rect()
requireActivity().window.decorView.getWindowVisibleDisplayFrame(r)
val height = requireActivity().window.decorView.height
if (height - r.bottom > height * 0.1399 && !isScrolled) {
println("CommentsFragment.setListeners 2")
// keyboard is open
withState(viewModel) { state ->
binding.recyclerView.scrollToPosition(state.listComments.size - 1)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.alfresco.content.browse.tasks.comments

import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.FrameLayout
import com.airbnb.epoxy.ModelProp
import com.airbnb.epoxy.ModelView
import com.alfresco.content.DATE_FORMAT_1
import com.alfresco.content.DATE_FORMAT_4
import com.alfresco.content.browse.databinding.ViewListCommentRowBinding
import com.alfresco.content.data.CommentEntry
import com.alfresco.content.getDateZoneFormat

/**
* Marked as ListViewCommentRow class
*/
@ModelView(autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT)
class ListViewCommentRow @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) {

private val binding = ViewListCommentRowBinding.inflate(LayoutInflater.from(context), this)

/**
* set the comment row on list row
*/
@ModelProp
fun setData(data: CommentEntry) {
binding.tvName.text = data.userDetails?.name
binding.tvUserInitial.text = data.userDetails?.nameInitial
binding.tvComment.text = data.message
binding.tvDate.text = if (data.created != null) data.created?.toLocalDate().toString().getDateZoneFormat(DATE_FORMAT_1, DATE_FORMAT_4) else ""
}
}
Loading

0 comments on commit 9a1a40a

Please sign in to comment.