Tusky-App-Android/app/src/main/java/com/keylesspalace/tusky/components/report/ReportViewModel.kt

234 lines
7.9 KiB
Kotlin
Raw Normal View History

/* Copyright 2019 Joel Pyska
*
* This file is a part of Tusky.
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see <http://www.gnu.org/licenses>. */
package com.keylesspalace.tusky.components.report
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.cachedIn
import androidx.paging.map
import at.connyduck.calladapter.networkresult.fold
import com.keylesspalace.tusky.appstore.BlockEvent
import com.keylesspalace.tusky.appstore.EventHub
import com.keylesspalace.tusky.appstore.MuteEvent
import com.keylesspalace.tusky.components.report.adapter.StatusesPagingSource
import com.keylesspalace.tusky.components.report.model.StatusViewState
import com.keylesspalace.tusky.entity.Relationship
import com.keylesspalace.tusky.entity.Status
import com.keylesspalace.tusky.network.MastodonApi
import com.keylesspalace.tusky.util.Error
import com.keylesspalace.tusky.util.Loading
import com.keylesspalace.tusky.util.Resource
import com.keylesspalace.tusky.util.Success
import com.keylesspalace.tusky.util.toViewData
import javax.inject.Inject
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.MutableSharedFlow
2024-03-27 11:34:17 +01:00
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
class ReportViewModel @Inject constructor(
private val mastodonApi: MastodonApi,
private val eventHub: EventHub
) : ViewModel() {
2024-03-27 11:34:17 +01:00
private val navigationMutable = MutableStateFlow(null as Screen?)
val navigation: StateFlow<Screen?> = navigationMutable.asStateFlow()
2024-03-27 11:34:17 +01:00
private val muteStateMutable = MutableStateFlow(null as Resource<Boolean>?)
val muteState: StateFlow<Resource<Boolean>?> = muteStateMutable.asStateFlow()
2024-03-27 11:34:17 +01:00
private val blockStateMutable = MutableStateFlow(null as Resource<Boolean>?)
val blockState: StateFlow<Resource<Boolean>?> = blockStateMutable.asStateFlow()
2024-03-27 11:34:17 +01:00
private val reportingStateMutable = MutableStateFlow(null as Resource<Boolean>?)
var reportingState: StateFlow<Resource<Boolean>?> = reportingStateMutable.asStateFlow()
2024-03-27 11:34:17 +01:00
private val checkUrlMutable = MutableStateFlow(null as String?)
val checkUrl: StateFlow<String?> = checkUrlMutable.asStateFlow()
private val accountIdFlow = MutableSharedFlow<String>(
replay = 1,
onBufferOverflow = BufferOverflow.DROP_OLDEST
)
val statusesFlow = accountIdFlow.flatMapLatest { accountId ->
Pager(
initialKey = statusId,
config = PagingConfig(pageSize = 20, initialLoadSize = 20),
pagingSourceFactory = { StatusesPagingSource(accountId, mastodonApi) }
).flow
}
.map { pagingData ->
/* TODO: refactor reports to use the isShowingContent / isExpanded / isCollapsed attributes from StatusViewData.Concrete
instead of StatusViewState */
pagingData.map { status -> status.toViewData(false, false, false) }
}
.cachedIn(viewModelScope)
private val selectedIds = HashSet<String>()
val statusViewState = StatusViewState()
var reportNote: String = ""
var isRemoteNotify = false
private var statusId: String? = null
lateinit var accountUserName: String
lateinit var accountId: String
var isRemoteAccount: Boolean = false
var remoteServer: String? = null
fun init(accountId: String, userName: String, statusId: String?) {
this.accountId = accountId
this.accountUserName = userName
this.statusId = statusId
statusId?.let {
selectedIds.add(it)
}
isRemoteAccount = userName.contains('@')
if (isRemoteAccount) {
remoteServer = userName.substring(userName.indexOf('@') + 1)
}
obtainRelationship()
viewModelScope.launch {
accountIdFlow.emit(accountId)
}
}
fun navigateTo(screen: Screen) {
navigationMutable.value = screen
}
fun navigated() {
navigationMutable.value = null
}
private fun obtainRelationship() {
val ids = listOf(accountId)
muteStateMutable.value = Loading()
blockStateMutable.value = Loading()
viewModelScope.launch {
mastodonApi.relationships(ids).fold(
{ data ->
updateRelationship(data.getOrNull(0))
},
{
updateRelationship(null)
}
)
}
}
private fun updateRelationship(relationship: Relationship?) {
if (relationship != null) {
muteStateMutable.value = Success(relationship.muting)
blockStateMutable.value = Success(relationship.blocking)
} else {
muteStateMutable.value = Error(false)
blockStateMutable.value = Error(false)
}
}
fun toggleMute() {
val alreadyMuted = muteStateMutable.value?.data == true
viewModelScope.launch {
if (alreadyMuted) {
mastodonApi.unmuteAccount(accountId)
} else {
mastodonApi.muteAccount(accountId)
}.fold(
{ relationship ->
val muting = relationship.muting
muteStateMutable.value = Success(muting)
if (muting) {
eventHub.dispatch(MuteEvent(accountId))
}
},
{ t ->
muteStateMutable.value = Error(false, t.message)
}
)
}
muteStateMutable.value = Loading()
}
fun toggleBlock() {
val alreadyBlocked = blockStateMutable.value?.data == true
viewModelScope.launch {
if (alreadyBlocked) {
mastodonApi.unblockAccount(accountId)
} else {
mastodonApi.blockAccount(accountId)
}.fold({ relationship ->
val blocking = relationship.blocking
blockStateMutable.value = Success(blocking)
if (blocking) {
eventHub.dispatch(BlockEvent(accountId))
}
}, { t ->
blockStateMutable.value = Error(false, t.message)
})
}
blockStateMutable.value = Loading()
}
fun doReport() {
reportingStateMutable.value = Loading()
viewModelScope.launch {
mastodonApi.report(
accountId,
selectedIds.toList(),
reportNote,
if (isRemoteAccount) isRemoteNotify else null
)
.fold({
reportingStateMutable.value = Success(true)
}, { error ->
reportingStateMutable.value = Error(cause = error)
})
}
}
fun checkClickedUrl(url: String?) {
checkUrlMutable.value = url
}
fun urlChecked() {
checkUrlMutable.value = null
}
fun setStatusChecked(status: Status, checked: Boolean) {
if (checked) {
selectedIds.add(status.id)
} else {
selectedIds.remove(status.id)
}
}
fun isStatusChecked(id: String): Boolean {
return selectedIds.contains(id)
}
}