introduce DomainBlocksRepository
This commit is contained in:
parent
8e56b5429b
commit
f8a6e0d8b8
6 changed files with 93 additions and 40 deletions
|
@ -46,7 +46,7 @@ class DomainBlocksFragment : Fragment(R.layout.fragment_domain_blocks), Injectab
|
|||
}
|
||||
|
||||
lifecycleScope.launch {
|
||||
viewModel.pager.collectLatest { pagingData ->
|
||||
viewModel.domainPager.collectLatest { pagingData ->
|
||||
adapter.submitData(pagingData)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,12 +3,15 @@ package com.keylesspalace.tusky.components.domainblocks
|
|||
import androidx.paging.PagingSource
|
||||
import androidx.paging.PagingState
|
||||
|
||||
class DomainBlocksPagingSource(private val viewModel: DomainBlocksViewModel) : PagingSource<String, String>() {
|
||||
class DomainBlocksPagingSource(
|
||||
private val domains: List<String>,
|
||||
private val nextKey: String?
|
||||
) : PagingSource<String, String>() {
|
||||
override fun getRefreshKey(state: PagingState<String, String>): String? = null
|
||||
|
||||
override suspend fun load(params: LoadParams<String>): LoadResult<String, String> {
|
||||
return if (params is LoadParams.Refresh) {
|
||||
LoadResult.Page(viewModel.domains.toList(), null, viewModel.nextKey)
|
||||
LoadResult.Page(domains, null, nextKey)
|
||||
} else {
|
||||
LoadResult.Page(emptyList(), null, null)
|
||||
}
|
||||
|
|
|
@ -12,8 +12,9 @@ import retrofit2.Response
|
|||
@OptIn(ExperimentalPagingApi::class)
|
||||
class DomainBlocksRemoteMediator(
|
||||
private val api: MastodonApi,
|
||||
private val viewModel: DomainBlocksViewModel
|
||||
private val repository: DomainBlocksRepository
|
||||
) : RemoteMediator<String, String>() {
|
||||
|
||||
override suspend fun load(
|
||||
loadType: LoadType,
|
||||
state: PagingState<String, String>
|
||||
|
@ -31,10 +32,10 @@ class DomainBlocksRemoteMediator(
|
|||
private suspend fun request(loadType: LoadType): Response<List<String>>? {
|
||||
return when (loadType) {
|
||||
LoadType.PREPEND -> null
|
||||
LoadType.APPEND -> api.domainBlocks(maxId = viewModel.nextKey)
|
||||
LoadType.APPEND -> api.domainBlocks(maxId = repository.nextKey)
|
||||
LoadType.REFRESH -> {
|
||||
viewModel.nextKey = null
|
||||
viewModel.domains.clear()
|
||||
repository.nextKey = null
|
||||
repository.domains.clear()
|
||||
api.domainBlocks()
|
||||
}
|
||||
}
|
||||
|
@ -47,10 +48,10 @@ class DomainBlocksRemoteMediator(
|
|||
}
|
||||
|
||||
val links = HttpHeaderLink.parse(response.headers()["Link"])
|
||||
viewModel.nextKey = HttpHeaderLink.findByRelationType(links, "next")?.uri?.getQueryParameter("max_id")
|
||||
viewModel.domains.addAll(tags)
|
||||
viewModel.currentSource?.invalidate()
|
||||
repository.nextKey = HttpHeaderLink.findByRelationType(links, "next")?.uri?.getQueryParameter("max_id")
|
||||
repository.domains.addAll(tags)
|
||||
repository.invalidate()
|
||||
|
||||
return MediatorResult.Success(endOfPaginationReached = viewModel.nextKey == null)
|
||||
return MediatorResult.Success(endOfPaginationReached = repository.nextKey == null)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright 2023 Tusky Contributors
|
||||
*
|
||||
* 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.domainblocks
|
||||
|
||||
import androidx.paging.ExperimentalPagingApi
|
||||
import androidx.paging.InvalidatingPagingSourceFactory
|
||||
import androidx.paging.Pager
|
||||
import androidx.paging.PagingConfig
|
||||
import androidx.paging.PagingSource
|
||||
import at.connyduck.calladapter.networkresult.NetworkResult
|
||||
import at.connyduck.calladapter.networkresult.onSuccess
|
||||
import com.keylesspalace.tusky.network.MastodonApi
|
||||
import javax.inject.Inject
|
||||
|
||||
class DomainBlocksRepository @Inject constructor(
|
||||
private val api: MastodonApi
|
||||
) {
|
||||
val domains: MutableList<String> = mutableListOf()
|
||||
var nextKey: String? = null
|
||||
|
||||
private var factory = InvalidatingPagingSourceFactory {
|
||||
DomainBlocksPagingSource(domains.toList(), nextKey)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalPagingApi::class)
|
||||
val domainPager = Pager(
|
||||
config = PagingConfig(pageSize = PAGE_SIZE, initialLoadSize = PAGE_SIZE),
|
||||
remoteMediator = DomainBlocksRemoteMediator(api, this),
|
||||
pagingSourceFactory = factory
|
||||
).flow
|
||||
|
||||
/** Invalidate the active paging source, see [PagingSource.invalidate] */
|
||||
fun invalidate() {
|
||||
factory.invalidate()
|
||||
}
|
||||
|
||||
suspend fun block(domain: String): NetworkResult<Unit> {
|
||||
return api.blockDomain(domain).onSuccess {
|
||||
domains.add(domain)
|
||||
factory.invalidate()
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun unblock(domain: String): NetworkResult<Unit> {
|
||||
return api.unblockDomain(domain).onSuccess {
|
||||
domains.remove(domain)
|
||||
factory.invalidate()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val PAGE_SIZE = 20
|
||||
}
|
||||
}
|
|
@ -4,44 +4,25 @@ import android.view.View
|
|||
import androidx.annotation.StringRes
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.paging.ExperimentalPagingApi
|
||||
import androidx.paging.Pager
|
||||
import androidx.paging.PagingConfig
|
||||
import androidx.paging.cachedIn
|
||||
import at.connyduck.calladapter.networkresult.fold
|
||||
import at.connyduck.calladapter.networkresult.onFailure
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.network.MastodonApi
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
class DomainBlocksViewModel @Inject constructor(
|
||||
private val api: MastodonApi
|
||||
private val repo: DomainBlocksRepository
|
||||
) : ViewModel() {
|
||||
val domains: MutableList<String> = mutableListOf()
|
||||
val uiEvents = MutableSharedFlow<SnackbarEvent>()
|
||||
var nextKey: String? = null
|
||||
var currentSource: DomainBlocksPagingSource? = null
|
||||
|
||||
@OptIn(ExperimentalPagingApi::class)
|
||||
val pager = Pager(
|
||||
config = PagingConfig(pageSize = 20),
|
||||
remoteMediator = DomainBlocksRemoteMediator(api, this),
|
||||
pagingSourceFactory = {
|
||||
DomainBlocksPagingSource(
|
||||
viewModel = this
|
||||
).also { source ->
|
||||
currentSource = source
|
||||
}
|
||||
}
|
||||
).flow.cachedIn(viewModelScope)
|
||||
val domainPager = repo.domainPager.cachedIn(viewModelScope)
|
||||
|
||||
val uiEvents = MutableSharedFlow<SnackbarEvent>()
|
||||
|
||||
fun block(domain: String) {
|
||||
viewModelScope.launch {
|
||||
api.blockDomain(domain).fold({
|
||||
domains.add(domain)
|
||||
currentSource?.invalidate()
|
||||
}, { e ->
|
||||
repo.block(domain).onFailure { e ->
|
||||
uiEvents.emit(
|
||||
SnackbarEvent(
|
||||
message = R.string.error_blocking_domain,
|
||||
|
@ -51,15 +32,13 @@ class DomainBlocksViewModel @Inject constructor(
|
|||
action = { block(domain) }
|
||||
)
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun unblock(domain: String) {
|
||||
viewModelScope.launch {
|
||||
api.unblockDomain(domain).fold({
|
||||
domains.remove(domain)
|
||||
currentSource?.invalidate()
|
||||
repo.unblock(domain).fold({
|
||||
uiEvents.emit(
|
||||
SnackbarEvent(
|
||||
message = R.string.confirmation_domain_unmuted,
|
||||
|
|
|
@ -21,6 +21,7 @@ import android.content.SharedPreferences
|
|||
import android.os.Looper
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.keylesspalace.tusky.appstore.EventHub
|
||||
import com.keylesspalace.tusky.components.domainblocks.NotificationsRepository
|
||||
import com.keylesspalace.tusky.db.AccountEntity
|
||||
import com.keylesspalace.tusky.db.AccountManager
|
||||
import com.keylesspalace.tusky.settings.PrefKeys
|
||||
|
|
Loading…
Reference in a new issue