Don't use mutable state flows in UI (#4336)
This commit is contained in:
parent
3274bd2660
commit
a3d87de8ac
|
@ -1040,7 +1040,7 @@ class ComposeActivity :
|
|||
|
||||
override fun onVisibilityChanged(visibility: Status.Visibility) {
|
||||
composeOptionsBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
|
||||
viewModel.statusVisibility.value = visibility
|
||||
viewModel.changeStatusVisibility(visibility)
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
|
|
|
@ -45,7 +45,9 @@ import kotlinx.coroutines.flow.MutableSharedFlow
|
|||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.shareIn
|
||||
import kotlinx.coroutines.flow.update
|
||||
|
@ -86,16 +88,25 @@ class ComposeViewModel @Inject constructor(
|
|||
val emoji: SharedFlow<List<Emoji>> = instanceInfoRepo::getEmojis.asFlow()
|
||||
.shareIn(viewModelScope, SharingStarted.Eagerly, replay = 1)
|
||||
|
||||
val markMediaAsSensitive: MutableStateFlow<Boolean> =
|
||||
private val _markMediaAsSensitive =
|
||||
MutableStateFlow(accountManager.activeAccount?.defaultMediaSensitivity ?: false)
|
||||
val markMediaAsSensitive: StateFlow<Boolean> = _markMediaAsSensitive.asStateFlow()
|
||||
|
||||
val statusVisibility: MutableStateFlow<Status.Visibility> =
|
||||
MutableStateFlow(Status.Visibility.UNKNOWN)
|
||||
val showContentWarning: MutableStateFlow<Boolean> = MutableStateFlow(false)
|
||||
val poll: MutableStateFlow<NewPoll?> = MutableStateFlow(null)
|
||||
val scheduledAt: MutableStateFlow<String?> = MutableStateFlow(null)
|
||||
private val _statusVisibility = MutableStateFlow(Status.Visibility.UNKNOWN)
|
||||
val statusVisibility: StateFlow<Status.Visibility> = _statusVisibility.asStateFlow()
|
||||
|
||||
private val _showContentWarning = MutableStateFlow(false)
|
||||
val showContentWarning: StateFlow<Boolean> = _showContentWarning.asStateFlow()
|
||||
|
||||
private val _poll = MutableStateFlow(null as NewPoll?)
|
||||
val poll: StateFlow<NewPoll?> = _poll.asStateFlow()
|
||||
|
||||
private val _scheduledAt = MutableStateFlow(null as String?)
|
||||
val scheduledAt: StateFlow<String?> = _scheduledAt.asStateFlow()
|
||||
|
||||
private val _media = MutableStateFlow(emptyList<QueuedMedia>())
|
||||
val media: StateFlow<List<QueuedMedia>> = _media.asStateFlow()
|
||||
|
||||
val media: MutableStateFlow<List<QueuedMedia>> = MutableStateFlow(emptyList())
|
||||
val uploadError =
|
||||
MutableSharedFlow<Throwable>(
|
||||
replay = 0,
|
||||
|
@ -103,7 +114,8 @@ class ComposeViewModel @Inject constructor(
|
|||
onBufferOverflow = BufferOverflow.DROP_OLDEST
|
||||
)
|
||||
|
||||
val closeConfirmation = MutableStateFlow(ConfirmationKind.NONE)
|
||||
private val _closeConfirmation = MutableStateFlow(ConfirmationKind.NONE)
|
||||
val closeConfirmation: StateFlow<ConfirmationKind> = _closeConfirmation.asStateFlow()
|
||||
|
||||
private lateinit var composeKind: ComposeKind
|
||||
|
||||
|
@ -121,7 +133,7 @@ class ComposeViewModel @Inject constructor(
|
|||
) {
|
||||
try {
|
||||
val (type, uri, size) = mediaUploader.prepareMedia(mediaUri, instanceInfo.first())
|
||||
val mediaItems = media.value
|
||||
val mediaItems = _media.value
|
||||
if (type != QueuedMedia.Type.IMAGE &&
|
||||
mediaItems.isNotEmpty() &&
|
||||
mediaItems[0].type == QueuedMedia.Type.IMAGE
|
||||
|
@ -146,7 +158,7 @@ class ComposeViewModel @Inject constructor(
|
|||
): QueuedMedia {
|
||||
var stashMediaItem: QueuedMedia? = null
|
||||
|
||||
media.update { mediaList ->
|
||||
_media.update { mediaList ->
|
||||
val mediaItem = QueuedMedia(
|
||||
localId = mediaUploader.getNewLocalMediaId(),
|
||||
uri = uri,
|
||||
|
@ -173,7 +185,7 @@ class ComposeViewModel @Inject constructor(
|
|||
mediaUploader
|
||||
.uploadMedia(mediaItem, instanceInfo.first())
|
||||
.collect { event ->
|
||||
val item = media.value.find { it.localId == mediaItem.localId }
|
||||
val item = _media.value.find { it.localId == mediaItem.localId }
|
||||
?: return@collect
|
||||
val newMediaItem = when (event) {
|
||||
is UploadEvent.ProgressEvent ->
|
||||
|
@ -189,12 +201,12 @@ class ComposeViewModel @Inject constructor(
|
|||
}
|
||||
)
|
||||
is UploadEvent.ErrorEvent -> {
|
||||
media.update { mediaList -> mediaList.filter { it.localId != mediaItem.localId } }
|
||||
_media.update { mediaList -> mediaList.filter { it.localId != mediaItem.localId } }
|
||||
uploadError.emit(event.error)
|
||||
return@collect
|
||||
}
|
||||
}
|
||||
media.update { mediaList ->
|
||||
_media.update { mediaList ->
|
||||
mediaList.map { mediaItem ->
|
||||
if (mediaItem.localId == newMediaItem.localId) {
|
||||
newMediaItem
|
||||
|
@ -209,6 +221,10 @@ class ComposeViewModel @Inject constructor(
|
|||
return mediaItem
|
||||
}
|
||||
|
||||
fun changeStatusVisibility(visibility: Status.Visibility) {
|
||||
_statusVisibility.value = visibility
|
||||
}
|
||||
|
||||
private fun addUploadedMedia(
|
||||
id: String,
|
||||
type: QueuedMedia.Type,
|
||||
|
@ -216,7 +232,7 @@ class ComposeViewModel @Inject constructor(
|
|||
description: String?,
|
||||
focus: Attachment.Focus?
|
||||
) {
|
||||
media.update { mediaList ->
|
||||
_media.update { mediaList ->
|
||||
val mediaItem = QueuedMedia(
|
||||
localId = mediaUploader.getNewLocalMediaId(),
|
||||
uri = uri,
|
||||
|
@ -234,12 +250,12 @@ class ComposeViewModel @Inject constructor(
|
|||
|
||||
fun removeMediaFromQueue(item: QueuedMedia) {
|
||||
mediaUploader.cancelUploadScope(item.localId)
|
||||
media.update { mediaList -> mediaList.filter { it.localId != item.localId } }
|
||||
_media.update { mediaList -> mediaList.filter { it.localId != item.localId } }
|
||||
updateCloseConfirmation()
|
||||
}
|
||||
|
||||
fun toggleMarkSensitive() {
|
||||
this.markMediaAsSensitive.value = this.markMediaAsSensitive.value != true
|
||||
this._markMediaAsSensitive.value = this._markMediaAsSensitive.value != true
|
||||
}
|
||||
|
||||
fun updateContent(newContent: String?) {
|
||||
|
@ -253,12 +269,12 @@ class ComposeViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun updateCloseConfirmation() {
|
||||
val contentWarning = if (showContentWarning.value) {
|
||||
val contentWarning = if (_showContentWarning.value) {
|
||||
currentContentWarning
|
||||
} else {
|
||||
""
|
||||
}
|
||||
this.closeConfirmation.value = if (didChange(currentContent, contentWarning)) {
|
||||
this._closeConfirmation.value = if (didChange(currentContent, contentWarning)) {
|
||||
when (composeKind) {
|
||||
ComposeKind.NEW -> if (isEmpty(currentContent, contentWarning)) {
|
||||
ConfirmationKind.NONE
|
||||
|
@ -281,19 +297,19 @@ class ComposeViewModel @Inject constructor(
|
|||
private fun didChange(content: String?, contentWarning: String?): Boolean {
|
||||
val textChanged = content.orEmpty() != startingText.orEmpty()
|
||||
val contentWarningChanged = contentWarning.orEmpty() != startingContentWarning
|
||||
val mediaChanged = media.value.isNotEmpty()
|
||||
val pollChanged = poll.value != null
|
||||
val mediaChanged = _media.value.isNotEmpty()
|
||||
val pollChanged = _poll.value != null
|
||||
val didScheduledTimeChange = hasScheduledTimeChanged
|
||||
|
||||
return modifiedInitialState || textChanged || contentWarningChanged || mediaChanged || pollChanged || didScheduledTimeChange
|
||||
}
|
||||
|
||||
private fun isEmpty(content: String?, contentWarning: String?): Boolean {
|
||||
return !modifiedInitialState && (content.isNullOrBlank() && contentWarning.isNullOrBlank() && media.value.isEmpty() && poll.value == null)
|
||||
return !modifiedInitialState && (content.isNullOrBlank() && contentWarning.isNullOrBlank() && _media.value.isEmpty() && _poll.value == null)
|
||||
}
|
||||
|
||||
fun contentWarningChanged(value: Boolean) {
|
||||
showContentWarning.value = value
|
||||
_showContentWarning.value = value
|
||||
contentWarningStateChanged = true
|
||||
updateCloseConfirmation()
|
||||
}
|
||||
|
@ -307,12 +323,12 @@ class ComposeViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
fun stopUploads() {
|
||||
mediaUploader.cancelUploadScope(*media.value.map { it.localId }.toIntArray())
|
||||
mediaUploader.cancelUploadScope(*_media.value.map { it.localId }.toIntArray())
|
||||
}
|
||||
|
||||
fun shouldShowSaveDraftDialog(): Boolean {
|
||||
// if any of the media files need to be downloaded first it could take a while, so show a loading dialog
|
||||
return media.value.any { mediaValue ->
|
||||
return _media.value.any { mediaValue ->
|
||||
mediaValue.uri.scheme == "https"
|
||||
}
|
||||
}
|
||||
|
@ -321,7 +337,7 @@ class ComposeViewModel @Inject constructor(
|
|||
val mediaUris: MutableList<String> = mutableListOf()
|
||||
val mediaDescriptions: MutableList<String?> = mutableListOf()
|
||||
val mediaFocus: MutableList<Attachment.Focus?> = mutableListOf()
|
||||
for (item in media.value) {
|
||||
for (item in _media.value) {
|
||||
mediaUris.add(item.uri.toString())
|
||||
mediaDescriptions.add(item.description)
|
||||
mediaFocus.add(item.focus)
|
||||
|
@ -333,15 +349,15 @@ class ComposeViewModel @Inject constructor(
|
|||
inReplyToId = inReplyToId,
|
||||
content = content,
|
||||
contentWarning = contentWarning,
|
||||
sensitive = markMediaAsSensitive.value,
|
||||
visibility = statusVisibility.value,
|
||||
sensitive = _markMediaAsSensitive.value,
|
||||
visibility = _statusVisibility.value,
|
||||
mediaUris = mediaUris,
|
||||
mediaDescriptions = mediaDescriptions,
|
||||
mediaFocus = mediaFocus,
|
||||
poll = poll.value,
|
||||
poll = _poll.value,
|
||||
failedToSend = false,
|
||||
failedToSendAlert = false,
|
||||
scheduledAt = scheduledAt.value,
|
||||
scheduledAt = _scheduledAt.value,
|
||||
language = postLanguage,
|
||||
statusId = originalStatusId
|
||||
)
|
||||
|
@ -356,7 +372,7 @@ class ComposeViewModel @Inject constructor(
|
|||
api.deleteScheduledStatus(scheduledTootId!!)
|
||||
}
|
||||
|
||||
val attachedMedia = media.value.map { item ->
|
||||
val attachedMedia = _media.value.map { item ->
|
||||
MediaToSend(
|
||||
localId = item.localId,
|
||||
id = item.id,
|
||||
|
@ -369,12 +385,12 @@ class ComposeViewModel @Inject constructor(
|
|||
val tootToSend = StatusToSend(
|
||||
text = content,
|
||||
warningText = spoilerText,
|
||||
visibility = statusVisibility.value.serverString(),
|
||||
sensitive = attachedMedia.isNotEmpty() && (markMediaAsSensitive.value || showContentWarning.value),
|
||||
visibility = _statusVisibility.value.serverString(),
|
||||
sensitive = attachedMedia.isNotEmpty() && (_markMediaAsSensitive.value || _showContentWarning.value),
|
||||
media = attachedMedia,
|
||||
scheduledAt = scheduledAt.value,
|
||||
scheduledAt = _scheduledAt.value,
|
||||
inReplyToId = inReplyToId,
|
||||
poll = poll.value,
|
||||
poll = _poll.value,
|
||||
replyingStatusContent = null,
|
||||
replyingStatusAuthorUsername = null,
|
||||
accountId = accountId,
|
||||
|
@ -389,7 +405,7 @@ class ComposeViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun updateMediaItem(localId: Int, mutator: (QueuedMedia) -> QueuedMedia) {
|
||||
media.update { mediaList ->
|
||||
_media.update { mediaList ->
|
||||
mediaList.map { mediaItem ->
|
||||
if (mediaItem.localId == localId) {
|
||||
mutator(mediaItem)
|
||||
|
@ -478,7 +494,7 @@ class ComposeViewModel @Inject constructor(
|
|||
startingContentWarning = contentWarning
|
||||
}
|
||||
if (!contentWarningStateChanged) {
|
||||
showContentWarning.value = !contentWarning.isNullOrBlank()
|
||||
_showContentWarning.value = !contentWarning.isNullOrBlank()
|
||||
}
|
||||
|
||||
// recreate media list
|
||||
|
@ -512,7 +528,7 @@ class ComposeViewModel @Inject constructor(
|
|||
if (tootVisibility.num != Status.Visibility.UNKNOWN.num) {
|
||||
startingVisibility = tootVisibility
|
||||
}
|
||||
statusVisibility.value = startingVisibility
|
||||
_statusVisibility.value = startingVisibility
|
||||
val mentionedUsernames = composeOptions?.mentionedUsernames
|
||||
if (mentionedUsernames != null) {
|
||||
val builder = StringBuilder()
|
||||
|
@ -524,13 +540,13 @@ class ComposeViewModel @Inject constructor(
|
|||
startingText = builder.toString()
|
||||
}
|
||||
|
||||
scheduledAt.value = composeOptions?.scheduledAt
|
||||
_scheduledAt.value = composeOptions?.scheduledAt
|
||||
|
||||
composeOptions?.sensitive?.let { markMediaAsSensitive.value = it }
|
||||
composeOptions?.sensitive?.let { _markMediaAsSensitive.value = it }
|
||||
|
||||
val poll = composeOptions?.poll
|
||||
if (poll != null && composeOptions.mediaAttachments.isNullOrEmpty()) {
|
||||
this.poll.value = poll
|
||||
this._poll.value = poll
|
||||
}
|
||||
replyingStatusContent = composeOptions?.replyingStatusContent
|
||||
replyingStatusAuthor = composeOptions?.replyingStatusAuthor
|
||||
|
@ -541,16 +557,16 @@ class ComposeViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
fun updatePoll(newPoll: NewPoll?) {
|
||||
poll.value = newPoll
|
||||
_poll.value = newPoll
|
||||
updateCloseConfirmation()
|
||||
}
|
||||
|
||||
fun updateScheduledAt(newScheduledAt: String?) {
|
||||
if (newScheduledAt != scheduledAt.value) {
|
||||
if (newScheduledAt != _scheduledAt.value) {
|
||||
hasScheduledTimeChanged = true
|
||||
}
|
||||
|
||||
scheduledAt.value = newScheduledAt
|
||||
_scheduledAt.value = newScheduledAt
|
||||
}
|
||||
|
||||
val editing: Boolean
|
||||
|
|
|
@ -11,79 +11,91 @@ import com.keylesspalace.tusky.network.MastodonApi
|
|||
import com.keylesspalace.tusky.util.isHttpNotFound
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class EditFilterViewModel @Inject constructor(val api: MastodonApi, val eventHub: EventHub) : ViewModel() {
|
||||
private var originalFilter: Filter? = null
|
||||
val title = MutableStateFlow("")
|
||||
val keywords = MutableStateFlow(listOf<FilterKeyword>())
|
||||
val action = MutableStateFlow(Filter.Action.WARN)
|
||||
val duration = MutableStateFlow(0)
|
||||
val contexts = MutableStateFlow(listOf<Filter.Kind>())
|
||||
|
||||
private val _title = MutableStateFlow("")
|
||||
val title: StateFlow<String> = _title.asStateFlow()
|
||||
|
||||
private val _keywords = MutableStateFlow(listOf<FilterKeyword>())
|
||||
val keywords: StateFlow<List<FilterKeyword>> = _keywords.asStateFlow()
|
||||
|
||||
private val _action = MutableStateFlow(Filter.Action.WARN)
|
||||
val action: StateFlow<Filter.Action> = _action.asStateFlow()
|
||||
|
||||
private val _duration = MutableStateFlow(0)
|
||||
val duration: StateFlow<Int> = _duration.asStateFlow()
|
||||
|
||||
private val _contexts = MutableStateFlow(listOf<Filter.Kind>())
|
||||
val contexts: StateFlow<List<Filter.Kind>> = _contexts.asStateFlow()
|
||||
|
||||
fun load(filter: Filter) {
|
||||
originalFilter = filter
|
||||
title.value = filter.title
|
||||
keywords.value = filter.keywords
|
||||
action.value = filter.action
|
||||
duration.value = if (filter.expiresAt == null) {
|
||||
_title.value = filter.title
|
||||
_keywords.value = filter.keywords
|
||||
_action.value = filter.action
|
||||
_duration.value = if (filter.expiresAt == null) {
|
||||
0
|
||||
} else {
|
||||
-1
|
||||
}
|
||||
contexts.value = filter.kinds
|
||||
_contexts.value = filter.kinds
|
||||
}
|
||||
|
||||
fun addKeyword(keyword: FilterKeyword) {
|
||||
keywords.value += keyword
|
||||
_keywords.value += keyword
|
||||
}
|
||||
|
||||
fun deleteKeyword(keyword: FilterKeyword) {
|
||||
keywords.value = keywords.value.filterNot { it == keyword }
|
||||
_keywords.value = _keywords.value.filterNot { it == keyword }
|
||||
}
|
||||
|
||||
fun modifyKeyword(original: FilterKeyword, updated: FilterKeyword) {
|
||||
val index = keywords.value.indexOf(original)
|
||||
val index = _keywords.value.indexOf(original)
|
||||
if (index >= 0) {
|
||||
keywords.value = keywords.value.toMutableList().apply {
|
||||
_keywords.value = _keywords.value.toMutableList().apply {
|
||||
set(index, updated)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun setTitle(title: String) {
|
||||
this.title.value = title
|
||||
this._title.value = title
|
||||
}
|
||||
|
||||
fun setDuration(index: Int) {
|
||||
duration.value = index
|
||||
_duration.value = index
|
||||
}
|
||||
|
||||
fun setAction(action: Filter.Action) {
|
||||
this.action.value = action
|
||||
this._action.value = action
|
||||
}
|
||||
|
||||
fun addContext(context: Filter.Kind) {
|
||||
if (!contexts.value.contains(context)) {
|
||||
contexts.value += context
|
||||
if (!_contexts.value.contains(context)) {
|
||||
_contexts.value += context
|
||||
}
|
||||
}
|
||||
|
||||
fun removeContext(context: Filter.Kind) {
|
||||
contexts.value = contexts.value.filter { it != context }
|
||||
_contexts.value = _contexts.value.filter { it != context }
|
||||
}
|
||||
|
||||
fun validate(): Boolean {
|
||||
return title.value.isNotBlank() &&
|
||||
keywords.value.isNotEmpty() &&
|
||||
contexts.value.isNotEmpty()
|
||||
return _title.value.isNotBlank() &&
|
||||
_keywords.value.isNotEmpty() &&
|
||||
_contexts.value.isNotEmpty()
|
||||
}
|
||||
|
||||
suspend fun saveChanges(context: Context): Boolean {
|
||||
val contexts = contexts.value.map { it.kind }
|
||||
val title = title.value
|
||||
val durationIndex = duration.value
|
||||
val action = action.value.action
|
||||
val contexts = _contexts.value.map { it.kind }
|
||||
val title = _title.value
|
||||
val durationIndex = _duration.value
|
||||
val action = _action.value.action
|
||||
|
||||
return withContext(viewModelScope.coroutineContext) {
|
||||
originalFilter?.let { filter ->
|
||||
|
@ -108,7 +120,7 @@ class EditFilterViewModel @Inject constructor(val api: MastodonApi, val eventHub
|
|||
).fold(
|
||||
{ newFilter ->
|
||||
// This is _terrible_, but the all-in-one update filter api Just Doesn't Work
|
||||
return keywords.value.map { keyword ->
|
||||
return _keywords.value.map { keyword ->
|
||||
api.addFilterKeyword(
|
||||
filterId = newFilter.id,
|
||||
keyword = keyword.keyword,
|
||||
|
@ -144,7 +156,7 @@ class EditFilterViewModel @Inject constructor(val api: MastodonApi, val eventHub
|
|||
).fold(
|
||||
{
|
||||
// This is _terrible_, but the all-in-one update filter api Just Doesn't Work
|
||||
val results = keywords.value.map { keyword ->
|
||||
val results = _keywords.value.map { keyword ->
|
||||
if (keyword.id.isEmpty()) {
|
||||
api.addFilterKeyword(filterId = originalFilter.id, keyword = keyword.keyword, wholeWord = keyword.wholeWord)
|
||||
} else {
|
||||
|
@ -152,7 +164,7 @@ class EditFilterViewModel @Inject constructor(val api: MastodonApi, val eventHub
|
|||
}
|
||||
} + originalFilter.keywords.filter { keyword ->
|
||||
// Deleted keywords
|
||||
keywords.value.none { it.id == keyword.id }
|
||||
_keywords.value.none { it.id == keyword.id }
|
||||
}.map { api.deleteFilterKeyword(it.id) }
|
||||
|
||||
return results.none { it.isFailure }
|
||||
|
@ -170,13 +182,13 @@ class EditFilterViewModel @Inject constructor(val api: MastodonApi, val eventHub
|
|||
}
|
||||
|
||||
private suspend fun createFilterV1(context: List<String>, expiresInSeconds: Int?): Boolean {
|
||||
return keywords.value.map { keyword ->
|
||||
return _keywords.value.map { keyword ->
|
||||
api.createFilterV1(keyword.keyword, context, false, keyword.wholeWord, expiresInSeconds)
|
||||
}.none { it.isFailure }
|
||||
}
|
||||
|
||||
private suspend fun updateFilterV1(context: List<String>, expiresInSeconds: Int?): Boolean {
|
||||
val results = keywords.value.map { keyword ->
|
||||
val results = _keywords.value.map { keyword ->
|
||||
if (originalFilter == null) {
|
||||
api.createFilterV1(
|
||||
phrase = keyword.keyword,
|
||||
|
|
|
@ -23,13 +23,15 @@ import com.keylesspalace.tusky.network.MastodonApi
|
|||
import com.keylesspalace.tusky.util.isHttpNotFound
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class LoginWebViewViewModel @Inject constructor(
|
||||
private val api: MastodonApi
|
||||
) : ViewModel() {
|
||||
|
||||
val instanceRules: MutableStateFlow<List<String>> = MutableStateFlow(emptyList())
|
||||
private val _instanceRules = MutableStateFlow(emptyList<String>())
|
||||
val instanceRules = _instanceRules.asStateFlow()
|
||||
|
||||
private var domain: String? = null
|
||||
|
||||
|
@ -39,13 +41,13 @@ class LoginWebViewViewModel @Inject constructor(
|
|||
viewModelScope.launch {
|
||||
api.getInstance().fold(
|
||||
{ instance ->
|
||||
instanceRules.value = instance.rules.orEmpty().map { rule -> rule.text }
|
||||
_instanceRules.value = instance.rules.orEmpty().map { rule -> rule.text }
|
||||
},
|
||||
{ throwable ->
|
||||
if (throwable.isHttpNotFound()) {
|
||||
api.getInstanceV1(domain).fold(
|
||||
{ instance ->
|
||||
instanceRules.value = instance.rules?.map { rule -> rule.text }.orEmpty()
|
||||
_instanceRules.value = instance.rules?.map { rule -> rule.text }.orEmpty()
|
||||
},
|
||||
{ throwable ->
|
||||
Log.w(
|
||||
|
|
|
@ -51,6 +51,7 @@ import kotlinx.coroutines.channels.BufferOverflow
|
|||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
@ -64,9 +65,8 @@ class ViewThreadViewModel @Inject constructor(
|
|||
private val gson: Gson
|
||||
) : ViewModel() {
|
||||
|
||||
private val _uiState: MutableStateFlow<ThreadUiState> = MutableStateFlow(ThreadUiState.Loading)
|
||||
val uiState: Flow<ThreadUiState>
|
||||
get() = _uiState
|
||||
private val _uiState = MutableStateFlow(ThreadUiState.Loading as ThreadUiState)
|
||||
val uiState: Flow<ThreadUiState> = _uiState.asStateFlow()
|
||||
|
||||
private val _errors =
|
||||
MutableSharedFlow<Throwable>(
|
||||
|
|
|
@ -45,7 +45,7 @@ import org.pageseeder.xmlwriter.XMLStringWriter
|
|||
|
||||
class ViewEditsViewModel @Inject constructor(private val api: MastodonApi) : ViewModel() {
|
||||
|
||||
private val _uiState: MutableStateFlow<EditsUiState> = MutableStateFlow(EditsUiState.Initial)
|
||||
private val _uiState = MutableStateFlow(EditsUiState.Initial as EditsUiState)
|
||||
val uiState: StateFlow<EditsUiState> = _uiState.asStateFlow()
|
||||
|
||||
/** The API call to fetch edit history returned less than two items */
|
||||
|
|
|
@ -41,6 +41,7 @@ import kotlinx.coroutines.flow.Flow
|
|||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.asFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.shareIn
|
||||
import kotlinx.coroutines.launch
|
||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
|
@ -73,7 +74,8 @@ class EditProfileViewModel @Inject constructor(
|
|||
val instanceData: Flow<InstanceInfo> = instanceInfoRepo::getUpdatedInstanceInfoOrFallback.asFlow()
|
||||
.shareIn(viewModelScope, SharingStarted.Eagerly, replay = 1)
|
||||
|
||||
val isChanged = MutableStateFlow(false)
|
||||
private val _isChanged = MutableStateFlow(false)
|
||||
val isChanged = _isChanged.asStateFlow()
|
||||
|
||||
private var apiProfileAccount: Account? = null
|
||||
|
||||
|
@ -106,7 +108,7 @@ class EditProfileViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
internal fun dataChanged(newProfileData: ProfileDataInUi) {
|
||||
isChanged.value = getProfileDiff(apiProfileAccount, newProfileData).hasChanges()
|
||||
_isChanged.value = getProfileDiff(apiProfileAccount, newProfileData).hasChanges()
|
||||
}
|
||||
|
||||
internal fun save(newProfileData: ProfileDataInUi) {
|
||||
|
|
Loading…
Reference in New Issue