Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: Operate on statuses through a new StatusRepository #1279

Merged
merged 7 commits into from
Feb 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import androidx.paging.cachedIn
import androidx.paging.map
import app.pachli.core.data.repository.AccountManager
import app.pachli.core.data.repository.Loadable
import app.pachli.core.data.repository.StatusRepository
import app.pachli.core.database.Converters
import app.pachli.core.database.dao.ConversationsDao
import app.pachli.core.database.di.TransactionProvider
Expand All @@ -37,6 +38,7 @@ import com.github.michaelbull.result.onFailure
import com.github.michaelbull.result.onSuccess
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
import kotlin.properties.Delegates
import kotlinx.coroutines.currentCoroutineContext
import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.flow.SharingStarted
Expand All @@ -59,13 +61,17 @@ class ConversationsViewModel @Inject constructor(
private val accountManager: AccountManager,
private val api: MastodonApi,
sharedPreferencesRepository: SharedPreferencesRepository,
private val statusRepository: StatusRepository,
) : ViewModel() {

var pachliAccountId by Delegates.notNull<Long>()

@OptIn(ExperimentalPagingApi::class)
val conversationFlow = accountManager.activeAccountFlow
.filterIsInstance<Loadable.Loaded<AccountEntity?>>()
.mapNotNull { it.data }
.flatMapLatest { account ->
pachliAccountId = account.id
Pager(
config = PagingConfig(pageSize = 30),
remoteMediator = ConversationsRemoteMediator(
Expand Down Expand Up @@ -97,7 +103,7 @@ class ConversationsViewModel @Inject constructor(
*/
fun favourite(favourite: Boolean, lastStatusId: String) {
viewModelScope.launch {
timelineCases.favourite(lastStatusId, favourite).onSuccess {
statusRepository.favourite(pachliAccountId, lastStatusId, favourite).onSuccess {
conversationsDao.setFavourited(
accountManager.activeAccount!!.id,
lastStatusId,
Expand All @@ -114,7 +120,7 @@ class ConversationsViewModel @Inject constructor(
*/
fun bookmark(bookmark: Boolean, lastStatusId: String) {
viewModelScope.launch {
timelineCases.bookmark(lastStatusId, bookmark).onSuccess {
statusRepository.bookmark(pachliAccountId, lastStatusId, bookmark).onSuccess {
conversationsDao.setBookmarked(
accountManager.activeAccount!!.id,
lastStatusId,
Expand All @@ -131,15 +137,14 @@ class ConversationsViewModel @Inject constructor(
*/
fun voteInPoll(choices: List<Int>, lastStatusId: String, pollId: String) {
viewModelScope.launch {
timelineCases.voteInPoll(lastStatusId, pollId, choices)
statusRepository.voteInPoll(pachliAccountId, lastStatusId, pollId, choices)
.onSuccess {
val poll = it.body
conversationsDao.setPoll(
accountManager.activeAccount!!.id,
pachliAccountId,
lastStatusId,
converters.pollToJson(poll)!!,
converters.pollToJson(it)!!,
)
}.onFailure { Timber.w("failed to vote in poll: %s", it) }
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import app.pachli.core.data.model.StatusViewData
import app.pachli.core.data.repository.AccountManager
import app.pachli.core.data.repository.PachliAccount
import app.pachli.core.data.repository.StatusDisplayOptionsRepository
import app.pachli.core.data.repository.StatusRepository
import app.pachli.core.data.repository.notifications.NotificationsRepository
import app.pachli.core.data.repository.notifications.from
import app.pachli.core.database.model.AccountEntity
Expand Down Expand Up @@ -367,6 +368,7 @@ class NotificationsViewModel @AssistedInject constructor(
private val eventHub: EventHub,
statusDisplayOptionsRepository: StatusDisplayOptionsRepository,
private val sharedPreferencesRepository: SharedPreferencesRepository,
private val statusRepository: StatusRepository,
@Assisted val pachliAccountId: Long,
) : ViewModel() {
private val accountFlow = accountManager.getPachliAccountFlow(pachliAccountId)
Expand Down Expand Up @@ -478,25 +480,25 @@ class NotificationsViewModel @AssistedInject constructor(
.throttleFirst() // avoid double-taps
.collect { action ->
val result = when (action) {
is StatusAction.Bookmark -> repository.bookmark(
is StatusAction.Bookmark -> statusRepository.bookmark(
pachliAccountId,
action.statusViewData.actionableId,
action.state,
)

is StatusAction.Favourite -> repository.favourite(
is StatusAction.Favourite -> statusRepository.favourite(
pachliAccountId,
action.statusViewData.actionableId,
action.state,
)

is StatusAction.Reblog -> repository.reblog(
is StatusAction.Reblog -> statusRepository.reblog(
pachliAccountId,
action.statusViewData.actionableId,
action.state,
)

is StatusAction.VoteInPoll -> repository.voteInPoll(
is StatusAction.VoteInPoll -> statusRepository.voteInPoll(
pachliAccountId,
action.statusViewData.actionableId,
action.poll.id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import app.pachli.core.data.model.StatusViewData
import app.pachli.core.data.repository.AccountManager
import app.pachli.core.data.repository.Loadable
import app.pachli.core.data.repository.ServerRepository
import app.pachli.core.data.repository.StatusRepository
import app.pachli.core.database.model.AccountEntity
import app.pachli.core.model.ServerOperation.ORG_JOINMASTODON_SEARCH_QUERY_BY_DATE
import app.pachli.core.model.ServerOperation.ORG_JOINMASTODON_SEARCH_QUERY_FROM
Expand Down Expand Up @@ -83,6 +84,7 @@ class SearchViewModel @Inject constructor(
private val mastodonApi: MastodonApi,
private val timelineCases: TimelineCases,
private val accountManager: AccountManager,
private val statusRepository: StatusRepository,
serverRepository: ServerRepository,
) : ViewModel() {

Expand Down Expand Up @@ -277,12 +279,10 @@ class SearchViewModel @Inject constructor(
updateStatus(
statusViewData.status.copy(
reblogged = reblog,
reblog = statusViewData.status.reblog?.copy(
reblogged = reblog,
),
reblog = statusViewData.status.reblog?.copy(reblogged = reblog),
),
)
timelineCases.reblog(statusViewData.id, reblog)
statusRepository.reblog(statusViewData.pachliAccountId, statusViewData.id, reblog)
.onFailure {
updateStatus(statusViewData.status)
Timber.d("Failed to reblog status %s: %s", statusViewData.id, it)
Expand All @@ -302,7 +302,7 @@ class SearchViewModel @Inject constructor(
val votedPoll = poll.votedCopy(choices)
updateStatus(statusViewData.status.copy(poll = votedPoll))
viewModelScope.launch {
timelineCases.voteInPoll(statusViewData.id, votedPoll.id, choices)
statusRepository.voteInPoll(statusViewData.pachliAccountId, statusViewData.id, votedPoll.id, choices)
.onFailure {
updateStatus(statusViewData.status)
Timber.d("Failed to vote in poll: %s: %s", statusViewData.id, it)
Expand All @@ -313,15 +313,15 @@ class SearchViewModel @Inject constructor(
fun favorite(statusViewData: StatusViewData, isFavorited: Boolean) {
updateStatus(statusViewData.status.copy(favourited = isFavorited))
viewModelScope.launch {
timelineCases.favourite(statusViewData.id, isFavorited)
statusRepository.favourite(statusViewData.pachliAccountId, statusViewData.id, isFavorited)
.onFailure { updateStatus(statusViewData.status) }
}
}

fun bookmark(statusViewData: StatusViewData, isBookmarked: Boolean) {
updateStatus(statusViewData.status.copy(bookmarked = isBookmarked))
viewModelScope.launch {
timelineCases.bookmark(statusViewData.id, isBookmarked)
statusRepository.bookmark(statusViewData.pachliAccountId, statusViewData.id, isBookmarked)
.onFailure { updateStatus(statusViewData.status) }
}
}
Expand All @@ -332,9 +332,9 @@ class SearchViewModel @Inject constructor(
}
}

fun pinStatus(status: Status, isPin: Boolean) {
fun pinStatus(statusViewData: StatusViewData, isPin: Boolean) {
viewModelScope.launch {
timelineCases.pin(status.id, isPin)
statusRepository.pin(statusViewData.pachliAccountId, statusViewData.id, isPin)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ class SearchStatusesFragment : SearchFragment<StatusViewData>(), StatusActionLis
return@setOnMenuItemClickListener true
}
R.id.pin -> {
viewModel.pinStatus(status, !status.isPinned())
viewModel.pinStatus(statusViewData, !status.isPinned())
return@setOnMenuItemClickListener true
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import app.pachli.components.timeline.CachedTimelineRepository
import app.pachli.core.data.model.StatusViewData
import app.pachli.core.data.repository.AccountManager
import app.pachli.core.data.repository.StatusDisplayOptionsRepository
import app.pachli.core.data.repository.StatusRepository
import app.pachli.core.database.model.AccountEntity
import app.pachli.core.database.model.TimelineStatusWithAccount
import app.pachli.core.eventhub.BookmarkEvent
Expand Down Expand Up @@ -62,6 +63,7 @@ class CachedTimelineViewModel @Inject constructor(
accountManager: AccountManager,
statusDisplayOptionsRepository: StatusDisplayOptionsRepository,
sharedPreferencesRepository: SharedPreferencesRepository,
statusRepository: StatusRepository,
) : TimelineViewModel<TimelineStatusWithAccount>(
savedStateHandle,
timelineCases,
Expand All @@ -70,6 +72,7 @@ class CachedTimelineViewModel @Inject constructor(
repository,
statusDisplayOptionsRepository,
sharedPreferencesRepository,
statusRepository,
) {
val initialRefreshKey = accountFlow.flatMapLatest {
flow { emit(repository.getRefreshKey(it.data!!.id)) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import app.pachli.components.timeline.NetworkTimelineRepository
import app.pachli.core.data.model.StatusViewData
import app.pachli.core.data.repository.AccountManager
import app.pachli.core.data.repository.StatusDisplayOptionsRepository
import app.pachli.core.data.repository.StatusRepository
import app.pachli.core.database.model.AccountEntity
import app.pachli.core.eventhub.BookmarkEvent
import app.pachli.core.eventhub.EventHub
Expand Down Expand Up @@ -60,6 +61,7 @@ class NetworkTimelineViewModel @Inject constructor(
accountManager: AccountManager,
statusDisplayOptionsRepository: StatusDisplayOptionsRepository,
sharedPreferencesRepository: SharedPreferencesRepository,
statusRepository: StatusRepository,
) : TimelineViewModel<Status>(
savedStateHandle,
timelineCases,
Expand All @@ -68,6 +70,7 @@ class NetworkTimelineViewModel @Inject constructor(
repository,
statusDisplayOptionsRepository,
sharedPreferencesRepository,
statusRepository,
) {
private val modifiedViewData = mutableMapOf<String, StatusViewData>()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import app.pachli.core.data.model.StatusViewData
import app.pachli.core.data.repository.AccountManager
import app.pachli.core.data.repository.Loadable
import app.pachli.core.data.repository.StatusDisplayOptionsRepository
import app.pachli.core.data.repository.StatusRepository
import app.pachli.core.database.model.AccountEntity
import app.pachli.core.eventhub.BlockEvent
import app.pachli.core.eventhub.BookmarkEvent
Expand Down Expand Up @@ -285,6 +286,7 @@ abstract class TimelineViewModel<T : Any>(
private val repository: TimelineRepository<T>,
statusDisplayOptionsRepository: StatusDisplayOptionsRepository,
private val sharedPreferencesRepository: SharedPreferencesRepository,
private val statusRepository: StatusRepository,
) : ViewModel() {
val uiState: StateFlow<UiState>

Expand Down Expand Up @@ -345,25 +347,29 @@ abstract class TimelineViewModel<T : Any>(
.collect { action ->
val result = when (action) {
is StatusAction.Bookmark ->
timelineCases.bookmark(
statusRepository.bookmark(
action.statusViewData.pachliAccountId,
action.statusViewData.actionableId,
action.state,
)

is StatusAction.Favourite ->
timelineCases.favourite(
statusRepository.favourite(
action.statusViewData.pachliAccountId,
action.statusViewData.actionableId,
action.state,
)

is StatusAction.Reblog ->
timelineCases.reblog(
statusRepository.reblog(
action.statusViewData.pachliAccountId,
action.statusViewData.actionableId,
action.state,
)

is StatusAction.VoteInPoll ->
timelineCases.voteInPoll(
statusRepository.voteInPoll(
action.statusViewData.pachliAccountId,
action.statusViewData.actionableId,
action.poll.id,
action.choices,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import app.pachli.core.data.model.StatusViewData
import app.pachli.core.data.repository.AccountManager
import app.pachli.core.data.repository.Loadable
import app.pachli.core.data.repository.StatusDisplayOptionsRepository
import app.pachli.core.data.repository.StatusRepository
import app.pachli.core.database.dao.TimelineDao
import app.pachli.core.database.model.AccountEntity
import app.pachli.core.database.model.TranslatedStatusEntity
Expand Down Expand Up @@ -74,6 +75,7 @@ class ViewThreadViewModel @Inject constructor(
private val timelineDao: TimelineDao,
private val repository: CachedTimelineRepository,
statusDisplayOptionsRepository: StatusDisplayOptionsRepository,
private val statusRepository: StatusRepository,
) : ViewModel() {
private val _uiState: MutableStateFlow<ThreadUiState> = MutableStateFlow(ThreadUiState.Loading)
val uiState: Flow<ThreadUiState>
Expand Down Expand Up @@ -279,7 +281,7 @@ class ViewThreadViewModel @Inject constructor(
reblog = it.reblog?.copy(reblogged = reblog),
)
}
timelineCases.reblog(status.actionableId, reblog).onFailure {
statusRepository.reblog(status.pachliAccountId, status.actionableId, reblog).onFailure {
updateStatus(status.id) { it }
Timber.d("Failed to reblog status: %s: %s", status.actionableId, it)
}
Expand All @@ -292,15 +294,15 @@ class ViewThreadViewModel @Inject constructor(
favouritesCount = it.favouritesCount + 1,
)
}
timelineCases.favourite(status.actionableId, favorite).onFailure {
statusRepository.favourite(status.pachliAccountId, status.actionableId, favorite).onFailure {
updateStatus(status.id) { it }
Timber.d("Failed to favourite status: %s: %s", status.actionableId, it)
}
}

fun bookmark(bookmark: Boolean, status: StatusViewData) = viewModelScope.launch {
updateStatus(status.id) { it.copy(bookmarked = bookmark) }
timelineCases.bookmark(status.actionableId, bookmark).onFailure {
statusRepository.bookmark(status.pachliAccountId, status.actionableId, bookmark).onFailure {
updateStatus(status.id) { it }
Timber.d("Failed to bookmark status: %s: %s", status.actionableId, it)
}
Expand All @@ -312,10 +314,11 @@ class ViewThreadViewModel @Inject constructor(
status.copy(poll = votedPoll)
}

timelineCases.voteInPoll(status.actionableId, poll.id, choices).onFailure {
updateStatus(status.id) { it }
Timber.d("Failed to vote in poll: %s: %s", status.actionableId, it)
}
statusRepository.voteInPoll(status.pachliAccountId, status.actionableId, poll.id, choices)
.onFailure {
Timber.d("Failed to vote in poll: %s: %s", status.actionableId, it)
updateStatus(status.id) { it.copy(poll = poll) }
}
}

fun removeStatus(statusToRemove: StatusViewData) {
Expand Down
6 changes: 5 additions & 1 deletion app/src/main/java/app/pachli/fragment/SFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import app.pachli.core.activity.openLink
import app.pachli.core.data.model.IStatusViewData
import app.pachli.core.data.repository.AccountManager
import app.pachli.core.data.repository.ServerRepository
import app.pachli.core.data.repository.StatusRepository
import app.pachli.core.database.model.AccountEntity
import app.pachli.core.database.model.TranslationState
import app.pachli.core.domain.DownloadUrlUseCase
Expand Down Expand Up @@ -82,6 +83,9 @@ abstract class SFragment<T : IStatusViewData> : Fragment(), StatusActionListener
@Inject
lateinit var accountManager: AccountManager

@Inject
lateinit var statusRepository: StatusRepository

@Inject
lateinit var timelineCases: TimelineCases

Expand Down Expand Up @@ -338,7 +342,7 @@ abstract class SFragment<T : IStatusViewData> : Fragment(), StatusActionListener
}
R.id.pin -> {
lifecycleScope.launch {
timelineCases.pin(status.id, !status.isPinned()).onFailure { e ->
statusRepository.pin(pachliAccountId, status.id, !status.isPinned()).onFailure { e ->
val message = e.fmt(requireContext())
Snackbar.make(requireView(), message, Snackbar.LENGTH_LONG).show()
}
Expand Down
Loading
Loading