migrate profile fragment to paging v3
This commit is contained in:
parent
d1b5c73d8b
commit
444988a623
|
@ -1,95 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Conny Duck
|
||||
*
|
||||
* This file is part of Pixelcat.
|
||||
*
|
||||
* Pixelcat 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.
|
||||
*
|
||||
* Pixelcat 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package at.connyduck.pixelcat.components.profile
|
||||
|
||||
import androidx.paging.DataSource
|
||||
import androidx.paging.ItemKeyedDataSource
|
||||
import at.connyduck.pixelcat.db.AccountManager
|
||||
import at.connyduck.pixelcat.model.Status
|
||||
import at.connyduck.pixelcat.network.FediverseApi
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class ProfileDataSourceFactory(
|
||||
private val api: FediverseApi,
|
||||
private val accountId: String?,
|
||||
private val accountManager: AccountManager,
|
||||
private val scope: CoroutineScope
|
||||
) : DataSource.Factory<String, Status>() {
|
||||
|
||||
override fun create(): DataSource<String, Status> {
|
||||
val source = ProfileImageDataSource(api, accountId, accountManager, scope)
|
||||
return source
|
||||
}
|
||||
}
|
||||
|
||||
class ProfileImageDataSource(
|
||||
private val api: FediverseApi,
|
||||
private val accountId: String?,
|
||||
private val accountManager: AccountManager,
|
||||
private val scope: CoroutineScope
|
||||
) : ItemKeyedDataSource<String, Status>() {
|
||||
override fun loadInitial(
|
||||
params: LoadInitialParams<String>,
|
||||
callback: LoadInitialCallback<Status>
|
||||
) {
|
||||
scope.launch(context = Dispatchers.IO) {
|
||||
val id = accountId ?: accountManager.activeAccount()?.accountId!!
|
||||
api.accountStatuses(
|
||||
id,
|
||||
limit = params.requestedLoadSize,
|
||||
onlyMedia = true,
|
||||
excludeReblogs = true
|
||||
).fold(
|
||||
{
|
||||
callback.onResult(it)
|
||||
},
|
||||
{
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun loadAfter(params: LoadParams<String>, callback: LoadCallback<Status>) {
|
||||
scope.launch(context = Dispatchers.IO) {
|
||||
val id = accountId ?: accountManager.activeAccount()?.accountId!!
|
||||
api.accountStatuses(
|
||||
id,
|
||||
maxId = params.key,
|
||||
limit = params.requestedLoadSize,
|
||||
onlyMedia = true,
|
||||
excludeReblogs = true
|
||||
).fold(
|
||||
{
|
||||
callback.onResult(it)
|
||||
},
|
||||
{
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun loadBefore(params: LoadParams<String>, callback: LoadCallback<Status>) {
|
||||
// we always load from top
|
||||
}
|
||||
|
||||
override fun getKey(item: Status) = item.id
|
||||
}
|
|
@ -23,6 +23,8 @@ import android.os.Bundle
|
|||
import android.view.View
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.paging.ExperimentalPagingApi
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.MergeAdapter
|
||||
import at.connyduck.pixelcat.R
|
||||
|
@ -41,6 +43,8 @@ import at.connyduck.pixelcat.util.viewBinding
|
|||
import at.connyduck.pixelcat.util.withArgs
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import dagger.android.support.DaggerFragment
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
class ProfileFragment : DaggerFragment(R.layout.fragment_profile) {
|
||||
|
@ -60,6 +64,7 @@ class ProfileFragment : DaggerFragment(R.layout.fragment_profile) {
|
|||
private val headerAdapter = ProfileHeaderAdapter()
|
||||
private lateinit var imageAdapter: ProfileImageAdapter
|
||||
|
||||
@ExperimentalPagingApi
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
|
||||
if (activity is MainActivity) {
|
||||
|
@ -124,12 +129,9 @@ class ProfileFragment : DaggerFragment(R.layout.fragment_profile) {
|
|||
}
|
||||
}
|
||||
)
|
||||
viewModel.profileImages.observe(
|
||||
viewLifecycleOwner,
|
||||
Observer {
|
||||
imageAdapter.submitList(it)
|
||||
}
|
||||
)
|
||||
lifecycleScope.launch {
|
||||
viewModel.imageFlow.collectLatest { imageAdapter.submitData(it) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun onAccountChanged(account: Account?) {
|
||||
|
|
|
@ -21,7 +21,7 @@ package at.connyduck.pixelcat.components.profile
|
|||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.paging.PagedListAdapter
|
||||
import androidx.paging.PagingDataAdapter
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import at.connyduck.pixelcat.R
|
||||
|
@ -34,7 +34,7 @@ import coil.api.load
|
|||
|
||||
class ProfileImageAdapter(
|
||||
private val imageSizePx: Int
|
||||
) : PagedListAdapter<Status, ProfileImageViewHolder>(
|
||||
) : PagingDataAdapter<Status, ProfileImageViewHolder>(
|
||||
object : DiffUtil.ItemCallback<Status>() {
|
||||
override fun areItemsTheSame(old: Status, new: Status): Boolean {
|
||||
return false
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Conny Duck
|
||||
*
|
||||
* This file is part of Pixelcat.
|
||||
*
|
||||
* Pixelcat 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.
|
||||
*
|
||||
* Pixelcat 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package at.connyduck.pixelcat.components.profile
|
||||
|
||||
import androidx.paging.PagingSource
|
||||
import at.connyduck.pixelcat.db.AccountManager
|
||||
import at.connyduck.pixelcat.model.Status
|
||||
import at.connyduck.pixelcat.network.FediverseApi
|
||||
|
||||
class ProfileImagePagingSource(
|
||||
private val api: FediverseApi,
|
||||
private val accountId: String?,
|
||||
private val accountManager: AccountManager
|
||||
) : PagingSource<String, Status>() {
|
||||
|
||||
override suspend fun load(params: LoadParams<String>): LoadResult<String, Status> {
|
||||
|
||||
if (params is LoadParams.Prepend) {
|
||||
// we only load from top
|
||||
return LoadResult.Page(data = emptyList(), nextKey = null, prevKey = null)
|
||||
}
|
||||
|
||||
val id = accountId ?: accountManager.activeAccount()?.accountId!!
|
||||
|
||||
return api.accountStatuses(
|
||||
id,
|
||||
maxId = params.key,
|
||||
limit = params.loadSize,
|
||||
onlyMedia = true,
|
||||
excludeReblogs = true
|
||||
).fold(
|
||||
{
|
||||
LoadResult.Page(data = it, prevKey = null, nextKey = it.lastOrNull()?.id)
|
||||
},
|
||||
{
|
||||
LoadResult.Error(it)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
|
@ -22,16 +22,18 @@ package at.connyduck.pixelcat.components.profile
|
|||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.paging.PagedList
|
||||
import androidx.paging.ExperimentalPagingApi
|
||||
import androidx.paging.Pager
|
||||
import androidx.paging.PagingConfig
|
||||
import androidx.paging.cachedIn
|
||||
import at.connyduck.pixelcat.components.util.Error
|
||||
import at.connyduck.pixelcat.components.util.Success
|
||||
import at.connyduck.pixelcat.components.util.UiState
|
||||
import at.connyduck.pixelcat.db.AccountManager
|
||||
import at.connyduck.pixelcat.model.Account
|
||||
import at.connyduck.pixelcat.model.Relationship
|
||||
import at.connyduck.pixelcat.model.Status
|
||||
import at.connyduck.pixelcat.network.FediverseApi
|
||||
import com.bumptech.glide.util.Executors
|
||||
import kotlinx.coroutines.FlowPreview
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -42,7 +44,14 @@ class ProfileViewModel @Inject constructor(
|
|||
|
||||
val profile = MutableLiveData<UiState<Account>>()
|
||||
val relationship = MutableLiveData<UiState<Relationship>>()
|
||||
val profileImages = MutableLiveData<PagedList<Status>>()
|
||||
|
||||
@OptIn(FlowPreview::class)
|
||||
@ExperimentalPagingApi
|
||||
val imageFlow = Pager(
|
||||
config = PagingConfig(pageSize = 10, enablePlaceholders = false),
|
||||
pagingSourceFactory = { ProfileImagePagingSource(fediverseApi, accountId, accountManager) }
|
||||
).flow
|
||||
.cachedIn(viewModelScope)
|
||||
|
||||
val isSelf: Boolean
|
||||
get() = accountId == null
|
||||
|
@ -54,7 +63,6 @@ class ProfileViewModel @Inject constructor(
|
|||
if (!isSelf) {
|
||||
loadRelationship(reload)
|
||||
}
|
||||
loadImages(reload)
|
||||
}
|
||||
|
||||
fun setAccountInfo(accountId: String?) {
|
||||
|
@ -92,22 +100,6 @@ class ProfileViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun loadImages(reload: Boolean = false) {
|
||||
if (profileImages.value == null || reload) {
|
||||
profileImages.value = PagedList.Builder(
|
||||
ProfileImageDataSource(
|
||||
fediverseApi,
|
||||
accountId,
|
||||
accountManager,
|
||||
viewModelScope
|
||||
),
|
||||
20
|
||||
).setNotifyExecutor(Executors.mainThreadExecutor())
|
||||
.setFetchExecutor(java.util.concurrent.Executors.newSingleThreadExecutor())
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getAccountId(): String {
|
||||
return accountId ?: accountManager.activeAccount()?.accountId!!
|
||||
}
|
||||
|
|
|
@ -17,8 +17,6 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
package at.connyduck.pixelcat.db
|
||||
|
||||
import android.util.Log
|
||||
|
|
|
@ -17,8 +17,6 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
package at.connyduck.pixelcat.db.entitity
|
||||
|
||||
import androidx.room.Embedded
|
||||
|
|
|
@ -17,8 +17,6 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
package at.connyduck.pixelcat.db.entitity
|
||||
|
||||
import androidx.room.Embedded
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
package at.connyduck.pixelcat.model
|
||||
|
||||
import android.os.Parcelable
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
package at.connyduck.pixelcat.model
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
|
|
Loading…
Reference in New Issue