|
|
|
|
@ -16,19 +16,22 @@
|
|
|
|
|
|
|
|
|
|
package com.keylesspalace.tusky.viewmodel |
|
|
|
|
|
|
|
|
|
import androidx.lifecycle.ViewModel |
|
|
|
|
import androidx.lifecycle.viewModelScope |
|
|
|
|
import com.keylesspalace.tusky.entity.MastoList |
|
|
|
|
import com.keylesspalace.tusky.network.MastodonApi |
|
|
|
|
import com.keylesspalace.tusky.util.RxAwareViewModel |
|
|
|
|
import com.keylesspalace.tusky.util.replacedFirstWhich |
|
|
|
|
import com.keylesspalace.tusky.util.withoutFirstWhich |
|
|
|
|
import io.reactivex.rxjava3.core.Observable |
|
|
|
|
import io.reactivex.rxjava3.subjects.BehaviorSubject |
|
|
|
|
import io.reactivex.rxjava3.subjects.PublishSubject |
|
|
|
|
import kotlinx.coroutines.channels.BufferOverflow |
|
|
|
|
import kotlinx.coroutines.flow.Flow |
|
|
|
|
import kotlinx.coroutines.flow.MutableSharedFlow |
|
|
|
|
import kotlinx.coroutines.flow.MutableStateFlow |
|
|
|
|
import kotlinx.coroutines.launch |
|
|
|
|
import java.io.IOException |
|
|
|
|
import java.net.ConnectException |
|
|
|
|
import javax.inject.Inject |
|
|
|
|
|
|
|
|
|
internal class ListsViewModel @Inject constructor(private val api: MastodonApi) : RxAwareViewModel() { |
|
|
|
|
internal class ListsViewModel @Inject constructor(private val api: MastodonApi) : ViewModel() { |
|
|
|
|
enum class LoadingState { |
|
|
|
|
INITIAL, LOADING, LOADED, ERROR_NETWORK, ERROR_OTHER |
|
|
|
|
} |
|
|
|
|
@ -39,86 +42,94 @@ internal class ListsViewModel @Inject constructor(private val api: MastodonApi)
|
|
|
|
|
|
|
|
|
|
data class State(val lists: List<MastoList>, val loadingState: LoadingState) |
|
|
|
|
|
|
|
|
|
val state: Observable<State> get() = _state |
|
|
|
|
val events: Observable<Event> get() = _events |
|
|
|
|
private val _state = BehaviorSubject.createDefault(State(listOf(), LoadingState.INITIAL)) |
|
|
|
|
private val _events = PublishSubject.create<Event>() |
|
|
|
|
val state: Flow<State> get() = _state |
|
|
|
|
val events: Flow<Event> get() = _events |
|
|
|
|
private val _state = MutableStateFlow(State(listOf(), LoadingState.INITIAL)) |
|
|
|
|
private val _events = MutableSharedFlow<Event>(replay = 0, extraBufferCapacity = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST) |
|
|
|
|
|
|
|
|
|
fun retryLoading() { |
|
|
|
|
loadIfNeeded() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private fun loadIfNeeded() { |
|
|
|
|
val state = _state.value!! |
|
|
|
|
val state = _state.value |
|
|
|
|
if (state.loadingState == LoadingState.LOADING || state.lists.isNotEmpty()) return |
|
|
|
|
updateState { |
|
|
|
|
copy(loadingState = LoadingState.LOADING) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
api.getLists().subscribe( |
|
|
|
|
{ lists -> |
|
|
|
|
updateState { |
|
|
|
|
copy( |
|
|
|
|
lists = lists, |
|
|
|
|
loadingState = LoadingState.LOADED |
|
|
|
|
) |
|
|
|
|
viewModelScope.launch { |
|
|
|
|
api.getLists().fold( |
|
|
|
|
{ lists -> |
|
|
|
|
updateState { |
|
|
|
|
copy( |
|
|
|
|
lists = lists, |
|
|
|
|
loadingState = LoadingState.LOADED |
|
|
|
|
) |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
{ err -> |
|
|
|
|
updateState { |
|
|
|
|
copy( |
|
|
|
|
loadingState = if (err is IOException || err is ConnectException) |
|
|
|
|
LoadingState.ERROR_NETWORK else LoadingState.ERROR_OTHER |
|
|
|
|
) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
{ err -> |
|
|
|
|
updateState { |
|
|
|
|
copy( |
|
|
|
|
loadingState = if (err is IOException || err is ConnectException) |
|
|
|
|
LoadingState.ERROR_NETWORK else LoadingState.ERROR_OTHER |
|
|
|
|
) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
).autoDispose() |
|
|
|
|
) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fun createNewList(listName: String) { |
|
|
|
|
api.createList(listName).subscribe( |
|
|
|
|
{ list -> |
|
|
|
|
updateState { |
|
|
|
|
copy(lists = lists + list) |
|
|
|
|
viewModelScope.launch { |
|
|
|
|
api.createList(listName).fold( |
|
|
|
|
{ list -> |
|
|
|
|
updateState { |
|
|
|
|
copy(lists = lists + list) |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
sendEvent(Event.CREATE_ERROR) |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
sendEvent(Event.CREATE_ERROR) |
|
|
|
|
} |
|
|
|
|
).autoDispose() |
|
|
|
|
) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fun renameList(listId: String, listName: String) { |
|
|
|
|
api.updateList(listId, listName).subscribe( |
|
|
|
|
{ list -> |
|
|
|
|
updateState { |
|
|
|
|
copy(lists = lists.replacedFirstWhich(list) { it.id == listId }) |
|
|
|
|
viewModelScope.launch { |
|
|
|
|
api.updateList(listId, listName).fold( |
|
|
|
|
{ list -> |
|
|
|
|
updateState { |
|
|
|
|
copy(lists = lists.replacedFirstWhich(list) { it.id == listId }) |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
sendEvent(Event.RENAME_ERROR) |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
sendEvent(Event.RENAME_ERROR) |
|
|
|
|
} |
|
|
|
|
).autoDispose() |
|
|
|
|
) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fun deleteList(listId: String) { |
|
|
|
|
api.deleteList(listId).subscribe( |
|
|
|
|
{ |
|
|
|
|
updateState { |
|
|
|
|
copy(lists = lists.withoutFirstWhich { it.id == listId }) |
|
|
|
|
viewModelScope.launch { |
|
|
|
|
api.deleteList(listId).fold( |
|
|
|
|
{ |
|
|
|
|
updateState { |
|
|
|
|
copy(lists = lists.withoutFirstWhich { it.id == listId }) |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
sendEvent(Event.DELETE_ERROR) |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
sendEvent(Event.DELETE_ERROR) |
|
|
|
|
} |
|
|
|
|
).autoDispose() |
|
|
|
|
) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private inline fun updateState(crossinline fn: State.() -> State) { |
|
|
|
|
_state.onNext(fn(_state.value!!)) |
|
|
|
|
_state.value = fn(_state.value) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private fun sendEvent(event: Event) { |
|
|
|
|
_events.onNext(event) |
|
|
|
|
private suspend fun sendEvent(event: Event) { |
|
|
|
|
_events.emit(event) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|