package org.moire.ultrasonic.fragment import android.app.Application import android.content.Context import android.os.Bundle import android.os.Handler import android.os.Looper import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.koin.core.component.KoinComponent import org.koin.core.component.inject import org.moire.ultrasonic.data.ActiveServerProvider import org.moire.ultrasonic.data.ServerSetting import org.moire.ultrasonic.domain.MusicFolder import org.moire.ultrasonic.service.MusicService import org.moire.ultrasonic.service.MusicServiceFactory import org.moire.ultrasonic.util.CommunicationError import org.moire.ultrasonic.util.Settings /** * An abstract Model, which can be extended to retrieve a list of items from the API */ open class GenericListModel(application: Application) : AndroidViewModel(application), KoinComponent { val activeServerProvider: ActiveServerProvider by inject() val activeServer: ServerSetting get() = activeServerProvider.getActiveServer() val context: Context get() = getApplication().applicationContext var currentListIsSortable = true var showHeader = true @Suppress("UNUSED_PARAMETER") open fun showSelectFolderHeader(args: Bundle?): Boolean { return true } internal val musicFolders: MutableLiveData> = MutableLiveData(listOf()) /** * Helper function to check online status */ fun isOffline(): Boolean { return ActiveServerProvider.isOffline() } /** * Refreshes the cached items from the server */ fun refresh(swipe: SwipeRefreshLayout, bundle: Bundle?) { backgroundLoadFromServer(true, swipe, bundle ?: Bundle()) } /** * Trigger a load() and notify the UI that we are loading */ fun backgroundLoadFromServer( refresh: Boolean, swipe: SwipeRefreshLayout, bundle: Bundle = Bundle() ) { viewModelScope.launch { swipe.isRefreshing = true loadFromServer(refresh, swipe, bundle) swipe.isRefreshing = false } } /** * Calls the load() function with error handling */ suspend fun loadFromServer(refresh: Boolean, swipe: SwipeRefreshLayout, bundle: Bundle) = withContext(Dispatchers.IO) { val musicService = MusicServiceFactory.getMusicService() val isOffline = ActiveServerProvider.isOffline() val useId3Tags = Settings.shouldUseId3Tags try { load(isOffline, useId3Tags, musicService, refresh, bundle) } catch (all: Exception) { handleException(all, swipe.context) } } private fun handleException(exception: Exception, context: Context) { Handler(Looper.getMainLooper()).post { CommunicationError.handleError(exception, context) } } /** * This is the central function you need to implement if you want to extend this class */ open fun load( isOffline: Boolean, useId3Tags: Boolean, musicService: MusicService, refresh: Boolean, args: Bundle ) { // Update the list of available folders if enabled if (showSelectFolderHeader(args) && !isOffline && !useId3Tags) { musicFolders.postValue( musicService.getMusicFolders(refresh) ) } } /** * Retrieves the available Music Folders in a LiveData */ fun getMusicFolders(): LiveData> { return musicFolders } }