kotlin – Upload document not updating but still keep loading in android?

I am developing an android app. user to create a project and create worksheets and upload documents user go to the android app and clicks worksheets and see loading documents but from the webside it is showing uploaded even after opening documents but from android side user only see loading documents even after clicking loaded document not updating how can show to user loaded document from android side

we have API request to download file and the file is downloaded completely by coroutine but the ui only updates when open document intent activity called loading documents

below my DocumentViewModel.kt

class DocumentsViewModel(
    res: ResourceResolver,
    prefs: Prefs,
    private val onlineManager: OnlineManager,
    val documentsRepository: DocumentsRepository,
    private val assignmentsRepository: AssignmentsRepository
) : BaseViewModel(res, prefs, onlineManager), DocumentItem.Listener {

    sealed class DocumentsEvent : BaseViewEvent {
        data class OpenFile(val url: String?) : DocumentsEvent()
    }

    val toolbarData = ToolbarData(
        title = str(R.string.documentsToolbarTitle)
    )

    private val assignmentId = MutableLiveData<Int>()

    private val assignment = assignmentId.switchMap {
        assignmentsRepository.loadAssignment(it)
    }


    val isDownloading:MutableLiveData<Int> =MutableLiveData(-1)

    val items = assignment.switchMap {
        loadDocuments(it)
    }
    var itemBinding = ItemBinding.of<DocumentItem>(BR.item, R.layout.item_document)
        .bindExtra(BR.listener, this)

    val diff: DiffUtil.ItemCallback<DocumentItem> = object : DiffUtil.ItemCallback<DocumentItem>() {
        override fun areItemsTheSame(old: DocumentItem, new: DocumentItem): Boolean {
            return old.document.id == new.document.id
        }

        override fun areContentsTheSame(old: DocumentItem, new: DocumentItem): Boolean {
            return old == new
        }
    }

    fun init(assignmentId: Int, update: Boolean) {
        this.assignmentId.value = assignmentId
        if (update) runUpdate(true)
    }


    override fun onClick(item: DocumentItem) {
        val upload = item.document.upload ?: return

        val fileType = upload.fileType?.let {
            val typeString = if (it.isEmpty()) "UNDEFINED" else it
            FileType.valueOf(typeString)
        }

        if (item.isDownloaded) {


            openDocument(item.document.id, fileType, item.document.title, item.document.info, upload.localUrl, item.preview)
            return
        }

        viewModelScope.launch {
            setProgressVisibility(true)
            isDownloading.value=0

            val media = documentsRepository.getMedia(item.document.id, upload)
            setProgressVisibility(false)
            isDownloading.value=1


            openDocument(item.document.id, fileType, item.document.title, item.document.info, media.first, media.second
                ?: item.preview)
        }
    }

    private fun loadDocuments(assignment: Assignment?): LiveData<List<DocumentItem>> {
        assignment ?: return MutableLiveData(emptyList())

        return documentsRepository.getDocuments(assignment.id).map { result ->
            when (result.status) {
                LOADING -> setProgressVisibility(true)
                ERROR -> {
                    setProgressVisibility(false)
                    handleError(result.exception)
                }
                SUCCESS -> {
                    setProgressVisibility(false)
                    return@map result.data?.map {

                        DocumentItem(it, assignment.isInRange, onlineManager.connectivityLiveData)



                    } ?: emptyList()
                }
            }

            return@map items.value ?: emptyList()
        }
    }

    private fun openDocument(documentId: Int, fileType: FileType?, title: String?, info: String?, fileUrl: String?, previewUrl: String?) {
        if (info != null) {
            sendEvent(ViewEvent.NavigateDirection(
                R.id.mainNavHostFragment,
                openDocumentDetailsScreen(
                    documentId = documentId,
                    previewUrl = previewUrl
                )
            ))
        } else {
            if (fileUrl == null) return

            if (fileType == FileType.IMAGE) {
                sendEvent(ViewEvent.NavigateDirection(
                    R.id.mainNavHostFragment,
                    openPreviewScreen(
                        title = title,
                        pictureUrl = fileUrl
                    )
                ))
            } else {
                sendEvent(DocumentsEvent.OpenFile(fileUrl))
            }
        }
    }

    fun runUpdate(forceUpdate: Boolean = false) {
        assignmentsRepository.runUpdate(assignmentId.value, forceUpdate)
            .async()
            .subscribeBy(
                onNext = {
                    Timber.d("Success")
                },
                onError = {
                    Timber.d(it)
                }
            ).collect()
    }
}

where I have implemented loading documents functionality

below DocumentsFragment where I have implemented toast messages where I let user to show wheither document downloading or file downloaded

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Bundle

import android.view.View
import android.widget.Toast
import androidx.lifecycle.Observer

import androidx.localbroadcastmanager.content.LocalBroadcastManager
import androidx.navigation.fragment.navArgs
import com.craftboxx.R
import com.craftboxx.base.BaseBoundVmFragment
import com.craftboxx.databinding.FragmentDocumentsBinding

import com.craftboxx.livedata.BaseViewEvent
import com.craftboxx.screens.documents.DocumentsViewModel.DocumentsEvent.OpenFile
import com.craftboxx.utils.ACTION_UPDATE
import com.craftboxx.utils.openFile

import timber.log.Timber

class DocumentsFragment : BaseBoundVmFragment<FragmentDocumentsBinding, DocumentsViewModel>(
    R.layout.fragment_documents,
    DocumentsViewModel::class
) {

    private val updateReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            Timber.d("Update received")
            vm.runUpdate(forceUpdate = true)
        }
    }

    private val args: DocumentsFragmentArgs by navArgs()

    lateinit var toast:Toast
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        vm.init(args.assignmentId, args.update)

        vm.isDownloading.observe(viewLifecycleOwner, Observer {

            if (it==0){
                Toast.makeText(requireContext(),"downloading...",Toast.LENGTH_SHORT).show()
            }else if (it==1){
                Toast.makeText(requireContext(),"file downloaded",Toast.LENGTH_SHORT).show()
            }


        })

    }
    override fun onResume() {
        super.onResume()
        LocalBroadcastManager.getInstance(requireActivity()).registerReceiver(updateReceiver, IntentFilter(ACTION_UPDATE))
        vm.runUpdate()
    }

    override fun onPause() {
        LocalBroadcastManager.getInstance(requireActivity()).unregisterReceiver(updateReceiver)
        super.onPause()
    }

    override fun onViewEvent(event: BaseViewEvent) = when (event) {
        is OpenFile -> {
            activity?.openFile(event.url)
            true
        }
        else -> super.onViewEvent(event)
    }
}

below my DocumentItem where we can use downloaded document

import androidx.lifecycle.LiveData
import androidx.lifecycle.Transformations
import androidx.lifecycle.map
import com.craftboxx.R
import com.craftboxx.database.entities.Document
import com.craftboxx.enums.FileType
import java.io.File

data class DocumentItem(
    val document: Document,
    val isInRange: Boolean,
    val connectivity: LiveData<Boolean>
) {
    interface Listener {
        fun onClick(item: DocumentItem)
    }

    val title: String
        get() = document.title ?: "-"


    val isDownloaded: Boolean
        get() = document.upload?.localUrl?.let {
            val file = File(it)
            (file.exists() && file.length() == document.upload.size || file.exists() && file.length() > 1)
        } ?: false

    val isAssignment: Boolean
        get() = document.type == "ASSIGNMENT"

    val preview: String?
        get() = document.upload?.let {
            if (!isDownloaded) {
                return it.mediumUrl
            }

            when (it.fileType) {
                FileType.IMAGE.name -> it.localUrl
                else -> it.coverUrl
            }
        }

    val fileType: FileType
        get() = document.upload?.fileType?.let {
            val typeString = it.ifEmpty { "UNDEFINED" }
            FileType.valueOf(typeString)
        } ?: FileType.UNDEFINED

    val syncVisibility = connectivity.map { hasInternet ->
        !isDownloaded && hasInternet && isInRange
    }

    var icon = Transformations.map(connectivity) { hasInternet ->
        when {
            isDownloaded -> R.drawable.ic_arrow_right
            !hasInternet -> R.drawable.ic_clock
            else -> R.drawable.ic_angle_double_down
        }
    }
}

Leave a Comment