Timeline refactor (#2175)
* Move Timeline files into their own package * Introduce TimelineViewModel, add coroutines * Simplify StatusViewData * Handle timeilne fetch errors * Rework filters, fix ViewThreadFragment * Fix NotificationsFragment * Simplify Notifications and Thread, handle pin * Redo loading in TimelineViewModel * Improve error handling in TimelineViewModel * Rewrite actions in TimelineViewModel * Apply feedback after timeline factoring review * Handle initial failure in timeline correctly
This commit is contained in:
parent
0a992480c2
commit
44a5b42cac
58 changed files with 3956 additions and 3618 deletions
|
|
@ -73,7 +73,7 @@ data class ConversationStatusEntity(
|
|||
val sensitive: Boolean,
|
||||
val spoilerText: String,
|
||||
val attachments: ArrayList<Attachment>,
|
||||
val mentions: Array<Status.Mention>,
|
||||
val mentions: List<Status.Mention>,
|
||||
val showingHiddenContent: Boolean,
|
||||
val expanded: Boolean,
|
||||
val collapsible: Boolean,
|
||||
|
|
@ -101,7 +101,7 @@ data class ConversationStatusEntity(
|
|||
if (sensitive != other.sensitive) return false
|
||||
if (spoilerText != other.spoilerText) return false
|
||||
if (attachments != other.attachments) return false
|
||||
if (!mentions.contentEquals(other.mentions)) return false
|
||||
if (mentions != other.mentions) return false
|
||||
if (showingHiddenContent != other.showingHiddenContent) return false
|
||||
if (expanded != other.expanded) return false
|
||||
if (collapsible != other.collapsible) return false
|
||||
|
|
@ -125,7 +125,7 @@ data class ConversationStatusEntity(
|
|||
result = 31 * result + sensitive.hashCode()
|
||||
result = 31 * result + spoilerText.hashCode()
|
||||
result = 31 * result + attachments.hashCode()
|
||||
result = 31 * result + mentions.contentHashCode()
|
||||
result = 31 * result + mentions.hashCode()
|
||||
result = 31 * result + showingHiddenContent.hashCode()
|
||||
result = 31 * result + expanded.hashCode()
|
||||
result = 31 * result + collapsible.hashCode()
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ import com.keylesspalace.tusky.util.NetworkState
|
|||
import com.keylesspalace.tusky.util.StatusDisplayOptions
|
||||
import com.keylesspalace.tusky.util.hide
|
||||
import com.keylesspalace.tusky.util.viewBinding
|
||||
import com.keylesspalace.tusky.viewdata.AttachmentViewData
|
||||
import javax.inject.Inject
|
||||
|
||||
class ConversationsFragment : SFragment(), StatusActionListener, Injectable, ReselectableFragment {
|
||||
|
|
@ -132,13 +133,14 @@ class ConversationsFragment : SFragment(), StatusActionListener, Injectable, Res
|
|||
|
||||
override fun onViewMedia(position: Int, attachmentIndex: Int, view: View?) {
|
||||
viewModel.conversations.value?.getOrNull(position)?.lastStatus?.let {
|
||||
viewMedia(attachmentIndex, it.toStatus(), view)
|
||||
viewMedia(attachmentIndex, AttachmentViewData.list(it.toStatus()), view)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewThread(position: Int) {
|
||||
viewModel.conversations.value?.getOrNull(position)?.lastStatus?.let {
|
||||
viewThread(it.toStatus())
|
||||
val status = it.toStatus()
|
||||
viewThread(status.actionableId, status.actionableStatus.url)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,17 +15,20 @@ import io.reactivex.rxjava3.schedulers.Schedulers
|
|||
import javax.inject.Inject
|
||||
|
||||
class ConversationsViewModel @Inject constructor(
|
||||
private val repository: ConversationsRepository,
|
||||
private val timelineCases: TimelineCases,
|
||||
private val database: AppDatabase,
|
||||
private val accountManager: AccountManager
|
||||
private val repository: ConversationsRepository,
|
||||
private val timelineCases: TimelineCases,
|
||||
private val database: AppDatabase,
|
||||
private val accountManager: AccountManager
|
||||
) : RxAwareViewModel() {
|
||||
|
||||
private val repoResult = MutableLiveData<Listing<ConversationEntity>>()
|
||||
|
||||
val conversations: LiveData<PagedList<ConversationEntity>> = Transformations.switchMap(repoResult) { it.pagedList }
|
||||
val networkState: LiveData<NetworkState> = Transformations.switchMap(repoResult) { it.networkState }
|
||||
val refreshState: LiveData<NetworkState> = Transformations.switchMap(repoResult) { it.refreshState }
|
||||
val conversations: LiveData<PagedList<ConversationEntity>> =
|
||||
Transformations.switchMap(repoResult) { it.pagedList }
|
||||
val networkState: LiveData<NetworkState> =
|
||||
Transformations.switchMap(repoResult) { it.networkState }
|
||||
val refreshState: LiveData<NetworkState> =
|
||||
Transformations.switchMap(repoResult) { it.refreshState }
|
||||
|
||||
fun load() {
|
||||
val accountId = accountManager.activeAccount?.id ?: return
|
||||
|
|
@ -45,57 +48,76 @@ class ConversationsViewModel @Inject constructor(
|
|||
|
||||
fun favourite(favourite: Boolean, position: Int) {
|
||||
conversations.value?.getOrNull(position)?.let { conversation ->
|
||||
timelineCases.favourite(conversation.lastStatus.toStatus(), favourite)
|
||||
.flatMap {
|
||||
val newConversation = conversation.copy(
|
||||
lastStatus = conversation.lastStatus.copy(favourited = favourite)
|
||||
)
|
||||
timelineCases.favourite(conversation.lastStatus.id, favourite)
|
||||
.flatMap {
|
||||
val newConversation = conversation.copy(
|
||||
lastStatus = conversation.lastStatus.copy(favourited = favourite)
|
||||
)
|
||||
|
||||
database.conversationDao().insert(newConversation)
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
.doOnError { t -> Log.w("ConversationViewModel", "Failed to favourite conversation", t) }
|
||||
.onErrorReturnItem(0)
|
||||
.subscribe()
|
||||
.autoDispose()
|
||||
database.conversationDao().insert(newConversation)
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
.doOnError { t ->
|
||||
Log.w(
|
||||
"ConversationViewModel",
|
||||
"Failed to favourite conversation",
|
||||
t
|
||||
)
|
||||
}
|
||||
.onErrorReturnItem(0)
|
||||
.subscribe()
|
||||
.autoDispose()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun bookmark(bookmark: Boolean, position: Int) {
|
||||
conversations.value?.getOrNull(position)?.let { conversation ->
|
||||
timelineCases.bookmark(conversation.lastStatus.toStatus(), bookmark)
|
||||
.flatMap {
|
||||
val newConversation = conversation.copy(
|
||||
lastStatus = conversation.lastStatus.copy(bookmarked = bookmark)
|
||||
)
|
||||
timelineCases.bookmark(conversation.lastStatus.id, bookmark)
|
||||
.flatMap {
|
||||
val newConversation = conversation.copy(
|
||||
lastStatus = conversation.lastStatus.copy(bookmarked = bookmark)
|
||||
)
|
||||
|
||||
database.conversationDao().insert(newConversation)
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
.doOnError { t -> Log.w("ConversationViewModel", "Failed to bookmark conversation", t) }
|
||||
.onErrorReturnItem(0)
|
||||
.subscribe()
|
||||
.autoDispose()
|
||||
database.conversationDao().insert(newConversation)
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
.doOnError { t ->
|
||||
Log.w(
|
||||
"ConversationViewModel",
|
||||
"Failed to bookmark conversation",
|
||||
t
|
||||
)
|
||||
}
|
||||
.onErrorReturnItem(0)
|
||||
.subscribe()
|
||||
.autoDispose()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun voteInPoll(position: Int, choices: MutableList<Int>) {
|
||||
conversations.value?.getOrNull(position)?.let { conversation ->
|
||||
timelineCases.voteInPoll(conversation.lastStatus.toStatus(), choices)
|
||||
.flatMap { poll ->
|
||||
val newConversation = conversation.copy(
|
||||
lastStatus = conversation.lastStatus.copy(poll = poll)
|
||||
)
|
||||
val poll = conversation.lastStatus.poll ?: return
|
||||
timelineCases.voteInPoll(conversation.lastStatus.id, poll.id, choices)
|
||||
.flatMap { newPoll ->
|
||||
val newConversation = conversation.copy(
|
||||
lastStatus = conversation.lastStatus.copy(poll = newPoll)
|
||||
)
|
||||
|
||||
database.conversationDao().insert(newConversation)
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
.doOnError { t -> Log.w("ConversationViewModel", "Failed to favourite conversation", t) }
|
||||
.onErrorReturnItem(0)
|
||||
.subscribe()
|
||||
.autoDispose()
|
||||
database.conversationDao().insert(newConversation)
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
.doOnError { t ->
|
||||
Log.w(
|
||||
"ConversationViewModel",
|
||||
"Failed to favourite conversation",
|
||||
t
|
||||
)
|
||||
}
|
||||
.onErrorReturnItem(0)
|
||||
.subscribe()
|
||||
.autoDispose()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -103,7 +125,7 @@ class ConversationsViewModel @Inject constructor(
|
|||
fun expandHiddenStatus(expanded: Boolean, position: Int) {
|
||||
conversations.value?.getOrNull(position)?.let { conversation ->
|
||||
val newConversation = conversation.copy(
|
||||
lastStatus = conversation.lastStatus.copy(expanded = expanded)
|
||||
lastStatus = conversation.lastStatus.copy(expanded = expanded)
|
||||
)
|
||||
saveConversationToDb(newConversation)
|
||||
}
|
||||
|
|
@ -112,7 +134,7 @@ class ConversationsViewModel @Inject constructor(
|
|||
fun collapseLongStatus(collapsed: Boolean, position: Int) {
|
||||
conversations.value?.getOrNull(position)?.let { conversation ->
|
||||
val newConversation = conversation.copy(
|
||||
lastStatus = conversation.lastStatus.copy(collapsed = collapsed)
|
||||
lastStatus = conversation.lastStatus.copy(collapsed = collapsed)
|
||||
)
|
||||
saveConversationToDb(newConversation)
|
||||
}
|
||||
|
|
@ -121,7 +143,7 @@ class ConversationsViewModel @Inject constructor(
|
|||
fun showContent(showing: Boolean, position: Int) {
|
||||
conversations.value?.getOrNull(position)?.let { conversation ->
|
||||
val newConversation = conversation.copy(
|
||||
lastStatus = conversation.lastStatus.copy(showingHiddenContent = showing)
|
||||
lastStatus = conversation.lastStatus.copy(showingHiddenContent = showing)
|
||||
)
|
||||
saveConversationToDb(newConversation)
|
||||
}
|
||||
|
|
@ -135,8 +157,8 @@ class ConversationsViewModel @Inject constructor(
|
|||
|
||||
private fun saveConversationToDb(conversation: ConversationEntity) {
|
||||
database.conversationDao().insert(conversation)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue