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 android.view.View
|
||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.paging.ExperimentalPagingApi
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import androidx.recyclerview.widget.MergeAdapter
|
import androidx.recyclerview.widget.MergeAdapter
|
||||||
import at.connyduck.pixelcat.R
|
import at.connyduck.pixelcat.R
|
||||||
|
@ -41,6 +43,8 @@ import at.connyduck.pixelcat.util.viewBinding
|
||||||
import at.connyduck.pixelcat.util.withArgs
|
import at.connyduck.pixelcat.util.withArgs
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import dagger.android.support.DaggerFragment
|
import dagger.android.support.DaggerFragment
|
||||||
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class ProfileFragment : DaggerFragment(R.layout.fragment_profile) {
|
class ProfileFragment : DaggerFragment(R.layout.fragment_profile) {
|
||||||
|
@ -60,6 +64,7 @@ class ProfileFragment : DaggerFragment(R.layout.fragment_profile) {
|
||||||
private val headerAdapter = ProfileHeaderAdapter()
|
private val headerAdapter = ProfileHeaderAdapter()
|
||||||
private lateinit var imageAdapter: ProfileImageAdapter
|
private lateinit var imageAdapter: ProfileImageAdapter
|
||||||
|
|
||||||
|
@ExperimentalPagingApi
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
|
||||||
if (activity is MainActivity) {
|
if (activity is MainActivity) {
|
||||||
|
@ -124,12 +129,9 @@ class ProfileFragment : DaggerFragment(R.layout.fragment_profile) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
viewModel.profileImages.observe(
|
lifecycleScope.launch {
|
||||||
viewLifecycleOwner,
|
viewModel.imageFlow.collectLatest { imageAdapter.submitData(it) }
|
||||||
Observer {
|
}
|
||||||
imageAdapter.submitList(it)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onAccountChanged(account: Account?) {
|
private fun onAccountChanged(account: Account?) {
|
||||||
|
|
|
@ -21,7 +21,7 @@ package at.connyduck.pixelcat.components.profile
|
||||||
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.paging.PagedListAdapter
|
import androidx.paging.PagingDataAdapter
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import at.connyduck.pixelcat.R
|
import at.connyduck.pixelcat.R
|
||||||
|
@ -34,7 +34,7 @@ import coil.api.load
|
||||||
|
|
||||||
class ProfileImageAdapter(
|
class ProfileImageAdapter(
|
||||||
private val imageSizePx: Int
|
private val imageSizePx: Int
|
||||||
) : PagedListAdapter<Status, ProfileImageViewHolder>(
|
) : PagingDataAdapter<Status, ProfileImageViewHolder>(
|
||||||
object : DiffUtil.ItemCallback<Status>() {
|
object : DiffUtil.ItemCallback<Status>() {
|
||||||
override fun areItemsTheSame(old: Status, new: Status): Boolean {
|
override fun areItemsTheSame(old: Status, new: Status): Boolean {
|
||||||
return false
|
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.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
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.Error
|
||||||
import at.connyduck.pixelcat.components.util.Success
|
import at.connyduck.pixelcat.components.util.Success
|
||||||
import at.connyduck.pixelcat.components.util.UiState
|
import at.connyduck.pixelcat.components.util.UiState
|
||||||
import at.connyduck.pixelcat.db.AccountManager
|
import at.connyduck.pixelcat.db.AccountManager
|
||||||
import at.connyduck.pixelcat.model.Account
|
import at.connyduck.pixelcat.model.Account
|
||||||
import at.connyduck.pixelcat.model.Relationship
|
import at.connyduck.pixelcat.model.Relationship
|
||||||
import at.connyduck.pixelcat.model.Status
|
|
||||||
import at.connyduck.pixelcat.network.FediverseApi
|
import at.connyduck.pixelcat.network.FediverseApi
|
||||||
import com.bumptech.glide.util.Executors
|
import kotlinx.coroutines.FlowPreview
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@ -42,7 +44,14 @@ class ProfileViewModel @Inject constructor(
|
||||||
|
|
||||||
val profile = MutableLiveData<UiState<Account>>()
|
val profile = MutableLiveData<UiState<Account>>()
|
||||||
val relationship = MutableLiveData<UiState<Relationship>>()
|
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
|
val isSelf: Boolean
|
||||||
get() = accountId == null
|
get() = accountId == null
|
||||||
|
@ -54,7 +63,6 @@ class ProfileViewModel @Inject constructor(
|
||||||
if (!isSelf) {
|
if (!isSelf) {
|
||||||
loadRelationship(reload)
|
loadRelationship(reload)
|
||||||
}
|
}
|
||||||
loadImages(reload)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setAccountInfo(accountId: String?) {
|
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 {
|
private suspend fun getAccountId(): String {
|
||||||
return accountId ?: accountManager.activeAccount()?.accountId!!
|
return accountId ?: accountManager.activeAccount()?.accountId!!
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,6 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
package at.connyduck.pixelcat.db
|
package at.connyduck.pixelcat.db
|
||||||
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
|
|
@ -17,8 +17,6 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
package at.connyduck.pixelcat.db.entitity
|
package at.connyduck.pixelcat.db.entitity
|
||||||
|
|
||||||
import androidx.room.Embedded
|
import androidx.room.Embedded
|
||||||
|
|
|
@ -17,8 +17,6 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
package at.connyduck.pixelcat.db.entitity
|
package at.connyduck.pixelcat.db.entitity
|
||||||
|
|
||||||
import androidx.room.Embedded
|
import androidx.room.Embedded
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package at.connyduck.pixelcat.model
|
package at.connyduck.pixelcat.model
|
||||||
|
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package at.connyduck.pixelcat.model
|
package at.connyduck.pixelcat.model
|
||||||
|
|
||||||
import com.squareup.moshi.Json
|
import com.squareup.moshi.Json
|
||||||
|
|
Loading…
Reference in New Issue