coding-blocks/CBOnlineApp

View on GitHub
app/src/main/java/com/codingblocks/cbonlineapp/library/LibraryViewModel.kt

Summary

Maintainability
D
1 day
Test Coverage
package com.codingblocks.cbonlineapp.library

import androidx.lifecycle.LiveData
import androidx.lifecycle.SavedStateHandle
import androidx.work.BackoffPolicy
import androidx.work.Constraints
import androidx.work.Data
import androidx.work.NetworkType
import androidx.work.OneTimeWorkRequest
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import androidx.work.workDataOf
import com.codingblocks.cbonlineapp.baseclasses.BaseCBViewModel
import com.codingblocks.cbonlineapp.database.models.CourseRunPair
import com.codingblocks.cbonlineapp.database.models.NotesModel
import com.codingblocks.cbonlineapp.mycourse.MyCourseRepository
import com.codingblocks.cbonlineapp.mycourse.content.player.notes.NotesWorker
import com.codingblocks.cbonlineapp.util.COURSE_NAME
import com.codingblocks.cbonlineapp.util.RUN_ATTEMPT_ID
import com.codingblocks.cbonlineapp.util.TYPE
import com.codingblocks.cbonlineapp.util.extensions.runIO
import com.codingblocks.cbonlineapp.util.extensions.savedStateValue
import com.codingblocks.cbonlineapp.util.extensions.serializeToJson
import com.codingblocks.onlineapi.ResultWrapper
import com.codingblocks.onlineapi.fetchError
import com.codingblocks.onlineapi.models.LectureContent
import com.codingblocks.onlineapi.models.Note
import com.codingblocks.onlineapi.models.RunAttempts
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.util.concurrent.TimeUnit

class LibraryViewModel(
    private val handle: SavedStateHandle,
    private val repo: LibraryRepository,
    private val courseRepo: MyCourseRepository
) : BaseCBViewModel() {
    var attemptId: String? by savedStateValue(handle, RUN_ATTEMPT_ID)
    var type: String? by savedStateValue(handle, TYPE)
    var name: String? by savedStateValue(handle, COURSE_NAME)

    val run: LiveData<CourseRunPair>? by lazy {
        attemptId?.let { repo.getRunById(it) }
    }
    fun fetchNotes(): LiveData<List<NotesModel>> {
        val notes = repo.getNotes(attemptId!!)
        runIO {
            when (val response = repo.fetchCourseNotes(attemptId!!)) {
                is ResultWrapper.GenericError -> setError(response.error)
                is ResultWrapper.Success -> {
                    if (response.value.isSuccessful)
                        response.value.body()?.let { notes ->
                            repo.insertNotes(notes)
                        }
                    else {
                        setError(fetchError(response.value.code()))
                    }
                }
            }
        }
        return notes
    }

    fun fetchSections() {
        runIO {
            if (withContext(Dispatchers.IO) { courseRepo.getSectionWithContentNonLive(attemptId!!) }.isEmpty())
                when (val response = courseRepo.fetchSections(attemptId!!)) {
                    is ResultWrapper.GenericError -> setError(response.error)
                    is ResultWrapper.Success -> {
                        if (response.value.isSuccessful)
                            response.value.body()?.let { runAttempt ->
                                courseRepo.insertSections(runAttempt)
                            }
                        else {
                            setError(fetchError(response.value.code()))
                        }
                    }
                }
        }
    }

    fun deleteNote(noteId: String) {
        runIO {
            when (val response = repo.deleteNote(noteId)) {
                is ResultWrapper.GenericError ->
                    if (response.code in 100..103)
                        startWorkerRequest(noteId)
                    else {
                        setError(response.error)
                    }
                is ResultWrapper.Success -> {
                    if (response.value.isSuccessful)
                        repo.deleteNoteFromDb(noteId)
                    else {
                        setError(fetchError(response.value.code()))
                    }
                }
            }
        }
    }

    private fun startWorkerRequest(noteId: String = "", noteModel: Note? = null) {
        val constraints = Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()
        val progressData: Data = if (noteId.isEmpty()) {
            workDataOf("NOTE" to noteModel?.serializeToJson())
//            offlineSnackbar.postValue("Note will be updated once you connect to Network")
        } else {
            workDataOf("NOTE_ID" to noteId)
//            offlineSnackbar.postValue("Note will be Deleted once you connect to Network")
        }
        val request: OneTimeWorkRequest =
            OneTimeWorkRequestBuilder<NotesWorker>()
                .setConstraints(constraints)
                .setInputData(progressData)
                .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 20, TimeUnit.SECONDS)
                .build()

        WorkManager.getInstance()
            .enqueue(request)
    }

    fun fetchBookmarks() = repo.getBookmarks(attemptId!!)
    fun fetchDownloads() = repo.getDownloads(attemptId!!)
    fun updateDownload(status: Int, lectureId: String) = runIO { repo.updateDownload(status, lectureId) }

    fun removeBookmark(id: String) {
        runIO {
            when (val response = repo.removeBookmark(id)) {
                is ResultWrapper.GenericError -> setError(response.error)
                is ResultWrapper.Success -> {
                    if (response.value.code() == 204) {
                        repo.deleteBookmark(id)
                    } else {
                        setError(fetchError(response.value.code()))
                    }
                }
            }
        }
    }

    fun updateNote(note: NotesModel) {
        val newNote = Note(note.nttUid, note.duration, note.text, RunAttempts(note.runAttemptId), LectureContent(note.contentId))
        runIO {
            when (val response = repo.updateNote(newNote)) {
                is ResultWrapper.GenericError -> {
                    if (response.code in 100..103)
                        startWorkerRequest(noteModel = newNote)
                    else {
                        setError(response.error)
                    }
                }
                is ResultWrapper.Success -> {
                    if (response.value.isSuccessful) {
                        repo.updateNoteInDb(newNote)
                    } else {
                        setError(fetchError(response.value.code()))
                    }
                }
            }
        }
    }
}