SDP-GeoHunt/geo-hunt

View on GitHub
app/src/main/java/com/github/geohunt/app/ui/components/bounties/viewmodel/AdminBountyViewModel.kt

Summary

Maintainability
A
1 hr
Test Coverage
A
90%
package com.github.geohunt.app.ui.components.bounties.viewmodel

import android.app.Application
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
import com.github.geohunt.app.data.repository.*
import com.github.geohunt.app.data.repository.bounties.BountiesRepositoryInterface
import com.github.geohunt.app.data.repository.bounties.TeamsRepositoryInterface
import com.github.geohunt.app.model.Bounty
import com.github.geohunt.app.model.Challenge
import com.github.geohunt.app.model.Team
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch

class AdminBountyViewModel(
    private val bountiesRepository: BountiesRepositoryInterface,
    private val userRepository: UserRepositoryInterface
) : ViewModel() {

    private val bid_ = MutableStateFlow<String?>(null)
    val bid : StateFlow<String?> = bid_

    private val bounty_ = MutableStateFlow<Bounty?>(null)
    val bounty : StateFlow<Bounty?> = bounty_

    private val challenges_ = MutableStateFlow<List<Challenge>>(listOf())
    val challenges : StateFlow<List<Challenge>> = challenges_

    var teamsFlow : Flow<List<Team>>? = null

    private var teamRepository: TeamsRepositoryInterface? = null
    private var challengeRepository: ChallengeRepositoryInterface? = null

    fun setBountyName(name: String) {
        require(bounty_.value != null)

        viewModelScope.launch {
            bountiesRepository.renameBounty(bounty_.value!!, name)
            refresh()
        }
    }

    fun withBusinessId(bid: String, onFailure: (Throwable) -> Unit) {
        reset()
        bid_.value = bid


        viewModelScope.launch(onFailure) {
            teamRepository = bountiesRepository.getTeamRepository(bid)
            challengeRepository = bountiesRepository.getChallengeRepository(bid)

            teamsFlow = teamRepository!!.getTeams()

            val bounty = bountiesRepository.getBountyById(bid)
            require(bounty.adminUid == userRepository.getCurrentUser().id)

            refresh(onFailure)

            bounty_.value = bounty
        }
    }

    fun refresh(onFailure: (Throwable) -> Unit = {}) {
        require(challengeRepository != null)

        viewModelScope.launch(onFailure) {
            challenges_.value = challengeRepository!!.getChallenges()
            bounty_.value = bountiesRepository.getBountyById(bounty_.value!!.bid)
        }
    }

    private fun reset() {
        bid_.value = null
        bounty_.value = null
        teamRepository = null
        challengeRepository = null
        teamsFlow = null
    }

    private fun CoroutineScope.launch(onFailure: (Throwable) -> Unit, callback: suspend CoroutineScope.() -> Unit) {
        val exceptionHandler = CoroutineExceptionHandler { _, throwable ->
            onFailure(throwable)
        }
        this.launch(context = exceptionHandler) {
            callback()
        }
    }

    companion object {
        val Factory: ViewModelProvider.Factory = viewModelFactory {
            initializer {
                val application = this[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY] as Application
                val container = AppContainer.getInstance(application)

                AdminBountyViewModel(
                    container.bounty,
                    container.user
                )
            }
        }
    }
}