Newer
Older
artist-browser / app / src / main / java / fr / dbsoft / swapcardtest / artistbrowser / ui / ArtistBrowserViewModel.kt
@dbangoura dbangoura on 8 Mar 2021 5 KB first commit
package fr.dbsoft.swapcardtest.artistbrowser.ui


import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import fr.dbsoft.swapcardtest.artistbrowser.data.model.*
import fr.dbsoft.swapcardtest.artistbrowser.data.repository.ArtistRepository
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import timber.log.Timber


class ArtistBrowserViewModel(val repository: ArtistRepository) : ViewModel() {

    private val coroutineScope = CoroutineScope(Dispatchers.Main)

    // Search
    val fetchedArtistsLiveData = MutableLiveData<List<BasicArtist>>()
    private var fetchedArtists = mutableListOf<BasicArtist>()
    var editTextErrorMessage = MutableLiveData<String>()
    var showErrorLiveData = MutableLiveData<Unit>()
    var lastHandledErrorMessage = ""
    var totalSearchCount = 0
    private var pageInfo = PageInfo()
    private var searchText = ""

    //Bookmark
    var readyForDataTracking = MutableLiveData<Boolean>()
    var bookmarkedArtistsLiveData: LiveData<List<BasicArtist>>? = null
    var bookmarkedArtistsHashSetLiveData = MutableLiveData<HashSet<String>>()
    var bookmarkedArtistsHashSet = HashSet<String>()

    //Details
    var artistLiveData = MutableLiveData<Artist>()
    var artist: Artist? = null

    var isLoadingData = MutableLiveData<Boolean>()

// region Search

    fun search(searchText: String) = coroutineScope.launch {
        Timber.d("search(searchText = $searchText)")
        try {
            isLoadingData.value = true
            this@ArtistBrowserViewModel.searchText = searchText
            val result = repository.searchArtistsFor(searchText)
            resetSearchResult()
            when (result) {
                is Response.Success -> updateResult(result.value)
                is Response.Error -> onError(result)
            }
            isLoadingData.value = false
        } catch (e: IllegalArgumentException) {
            isLoadingData.value = false
            editTextErrorMessage.value = e.message
        }
    }

    fun fetchMoreResult() = coroutineScope.launch {
        Timber.d("fetchMoreResult for=${this@ArtistBrowserViewModel.searchText} after=${pageInfo.endCursor}")
        if (isLoadingData.value == false && pageInfo.hasNextPage && this@ArtistBrowserViewModel.searchText.isNotBlank()) {
            isLoadingData.value = true
            val result =
                repository.fetchMoreResultFor(
                    this@ArtistBrowserViewModel.searchText,
                    pageInfo.endCursor
                )
            when (result) {
                is Response.Success -> updateResult(result.value)
                is Response.Error -> onError(result)
            }
            isLoadingData.value = false
        }
    }

    private fun resetSearchResult() {
        fetchedArtists.clear()
    }

    private fun updateResult(result: SearchFetchResult?) {
        result?.let {
            totalSearchCount = result.totalCount
            pageInfo = result.pageInfo
            fetchedArtists.addAll(result.artists)
        }
        fetchedArtistsLiveData.value = fetchedArtists
    }

    private fun onError(error: Response.Error) {
        var errorMessage = error.throwable?.message
        errorMessage += error.throwable?.cause?.message?.let { ". Caused by: $it" }
        errorMessage?.let {
            lastHandledErrorMessage = errorMessage
            showErrorLiveData.value = Unit
        }
    }

// endregion

// region Bookmark

    fun onBookmarkViewCreated() {
        getBookMarks()
    }

    private fun getBookMarks() = coroutineScope.launch {
        bookmarkedArtistsLiveData = repository.getBookMarks()
        readyForDataTracking.value = true
    }

    fun onBookmarksUpdated() {
        val bookmarkedArtists = bookmarkedArtistsLiveData?.value
        bookmarkedArtistsHashSet.clear()
        bookmarkedArtists?.forEach {
            bookmarkedArtistsHashSet.add(it.id)
        }
        bookmarkedArtistsHashSetLiveData.value = bookmarkedArtistsHashSet
    }

// endregion

// region Artist Detail

    fun onDetailsViewOpened(artistId: String) {
        getDetailsFor(artistId)
    }

    private fun getDetailsFor(artistId: String) = coroutineScope.launch {
        isLoadingData.value = true
        when (val result = repository.getArtistFor(artistId)) {
            is Response.Success -> updateArtistDetails(result.value)
            is Response.Error -> onError(result)
        }
        isLoadingData.value = false
    }

    private fun updateArtistDetails(result: Artist?) {
        artist = result
        artist?.isBookmarked = bookmarkedArtistsHashSet.contains(result?.id)
        artistLiveData.value = artist
    }

    fun detailBookMarkButtonClickedFor(artist: BasicArtist) = coroutineScope.launch {
        bookmarkButtonClickedFor(artist)
        this@ArtistBrowserViewModel.artist?.isBookmarked = !artist.isBookmarked
        artistLiveData.value = this@ArtistBrowserViewModel.artist
    }

// endregion

    fun bookmarkButtonClickedFor(artist: BasicArtist) = coroutineScope.launch {
        val artistIndex = fetchedArtists.indexOf(artist)
        artist.isBookmarked = !artist.isBookmarked
        if (artist.isBookmarked) {
            repository.bookmark(artist)
        } else {
            repository.unBookMark(artist)
        }

        if (artistIndex != -1) {
            fetchedArtists[artistIndex] = artist
            fetchedArtistsLiveData.value = fetchedArtists
        }
    }

    override fun onCleared() {
        super.onCleared()
        repository.stopRequests()
    }
}