Refactor into superclass

This commit is contained in:
Matthieu 2020-04-03 09:11:57 +02:00
parent aedd697759
commit 0d6a5b6c86
3 changed files with 108 additions and 132 deletions

View File

@ -2,6 +2,7 @@ package com.h.pixeldroid.fragments.feeds
import android.content.Context
import android.content.SharedPreferences
import android.graphics.pdf.PdfDocument
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
@ -10,6 +11,8 @@ import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.paging.DataSource
import androidx.paging.ItemKeyedDataSource
import androidx.paging.PagedList
import androidx.paging.PagedListAdapter
@ -31,7 +34,7 @@ import retrofit2.Response
open class FeedFragment<T: FeedContent, VH: RecyclerView.ViewHolder?>: Fragment() {
lateinit var content: LiveData<PagedList<T>>
lateinit var factory: FeedDataSourceFactory
protected var accessToken: String? = null
protected lateinit var pixelfedAPI: PixelfedAPI
@ -66,26 +69,73 @@ open class FeedFragment<T: FeedContent, VH: RecyclerView.ViewHolder?>: Fragment(
pixelfedAPI = PixelfedAPI.create("${preferences.getString("domain", "")}")
accessToken = preferences.getString("accessToken", "")
swipeRefreshLayout.setOnRefreshListener {
//by invalidating data, loadInitial will be called again
factory.liveData.value!!.invalidate()
}
}
internal fun enqueueCall(call: Call<List<T>>, callback: ItemKeyedDataSource.LoadCallback<T>){
call.enqueue(object : Callback<List<T>> {
override fun onResponse(call: Call<List<T>>, response: Response<List<T>>) {
if (response.code() == 200) {
val notifications = response.body()!! as ArrayList<T>
callback.onResult(notifications as List<T>)
} else{
Toast.makeText(context,"Something went wrong while loading", Toast.LENGTH_SHORT).show()
}
swipeRefreshLayout.isRefreshing = false
progressBar.visibility = View.GONE
}
inner class FeedDataSource(private val makeInitialCall: (Int) -> Call<List<T>>,
private val makeAfterCall: (Int, String) -> Call<List<T>>
): ItemKeyedDataSource<String, T>() {
//We use the id as the key
override fun getKey(item: T): String {
return item.id
}
//This is called to initialize the list, so we want some of the latest statuses
override fun loadInitial(
params: LoadInitialParams<String>,
callback: LoadInitialCallback<T>
) {
enqueueCall(makeInitialCall(params.requestedLoadSize), callback)
}
//This is called to when we get to the bottom of the loaded content, so we want statuses
//older than the given key (params.key)
override fun loadAfter(params: LoadParams<String>, callback: LoadCallback<T>) {
enqueueCall(makeAfterCall(params.requestedLoadSize, params.key), callback)
}
override fun loadBefore(params: LoadParams<String>, callback: LoadCallback<T>) {
//do nothing here, it is expected to pull to refresh to load newer notifications
}
private fun enqueueCall(call: Call<List<T>>, callback: LoadCallback<T>){
call.enqueue(object : Callback<List<T>> {
override fun onResponse(call: Call<List<T>>, response: Response<List<T>>) {
if (response.code() == 200) {
val notifications = response.body()!! as ArrayList<T>
callback.onResult(notifications as List<T>)
} else{
Toast.makeText(context,"Something went wrong while loading", Toast.LENGTH_SHORT).show()
}
swipeRefreshLayout.isRefreshing = false
progressBar.visibility = View.GONE
}
override fun onFailure(call: Call<List<T>>, t: Throwable) {
Toast.makeText(context,"Could not get feed", Toast.LENGTH_SHORT).show()
Log.e("FeedFragment", t.toString())
}
})
}
}
inner class FeedDataSourceFactory(
private val makeInitialCall: (Int) -> Call<List<T>>,
private val makeAfterCall: (Int, String) -> Call<List<T>>
): DataSource.Factory<String, T>() {
lateinit var liveData: MutableLiveData<FeedDataSource>
override fun create(): DataSource<String, T> {
val dataSource = FeedDataSource(::makeInitialCall.get(), ::makeAfterCall.get())
liveData = MutableLiveData()
liveData.postValue(dataSource)
return dataSource
}
override fun onFailure(call: Call<List<T>>, t: Throwable) {
Toast.makeText(context,"Could not get feed", Toast.LENGTH_SHORT).show()
Log.e("FeedFragment", t.toString())
}
})
}
}
@ -102,4 +152,5 @@ abstract class FeedsRecyclerViewAdapter<T: FeedContent, VH : RecyclerView.ViewHo
), PreloadModelProvider<T> {
protected lateinit var context: Context
}
}

View File

@ -9,10 +9,8 @@ import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import androidx.paging.DataSource
import androidx.paging.ItemKeyedDataSource
import androidx.paging.LivePagedListBuilder
import androidx.paging.PagedList
import androidx.recyclerview.widget.RecyclerView
@ -25,12 +23,12 @@ import com.h.pixeldroid.R
import com.h.pixeldroid.objects.Status
import com.h.pixeldroid.utils.ImageConverter
import kotlinx.android.synthetic.main.fragment_home.*
import retrofit2.Call
class HomeFragment : FeedFragment<Status, HomeFragment.HomeRecyclerViewAdapter.ViewHolder>() {
lateinit var picRequest: RequestBuilder<Drawable>
lateinit var factory: HomeDataSourceFactory
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
@ -38,9 +36,7 @@ class HomeFragment : FeedFragment<Status, HomeFragment.HomeRecyclerViewAdapter.V
): View? {
val view = super.onCreateView(inflater, container, savedInstanceState)
val config: PagedList.Config = PagedList.Config.Builder().setPageSize(10).build()
factory = HomeDataSourceFactory()
content = LivePagedListBuilder(factory, config).build()
content = makeContent()
//RequestBuilder that is re-used for every image
picRequest = Glide.with(this)
@ -67,13 +63,24 @@ class HomeFragment : FeedFragment<Status, HomeFragment.HomeRecyclerViewAdapter.V
return view
}
private fun makeContent(): LiveData<PagedList<Status>> {
fun makeInitialCall(requestedLoadSize: Int): Call<List<Status>> {
return pixelfedAPI
.timelineHome("Bearer $accessToken", limit="$requestedLoadSize")
}
fun makeAfterCall(requestedLoadSize: Int, key: String): Call<List<Status>> {
return pixelfedAPI
.timelineHome("Bearer $accessToken", max_id=key,
limit="$requestedLoadSize")
}
val config: PagedList.Config = PagedList.Config.Builder().setPageSize(10).build()
factory = FeedDataSourceFactory(::makeInitialCall, ::makeAfterCall)
return LivePagedListBuilder(factory, config).build()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
swipeRefreshLayout.setOnRefreshListener {
//by invalidating data, loadInitial will be called again
factory.postLiveData.value!!.invalidate()
}
}
/**
@ -138,47 +145,4 @@ class HomeFragment : FeedFragment<Status, HomeFragment.HomeRecyclerViewAdapter.V
return picRequest.load(item.getPostUrl())
}
}
inner class HomeDataSource: ItemKeyedDataSource<String, Status>() {
//We use the id as the key
override fun getKey(item: Status): String {
return item.id
}
//This is called to initialize the list, so we want some of the latest statuses
override fun loadInitial(
params: LoadInitialParams<String>,
callback: LoadInitialCallback<Status>
) {
val call = pixelfedAPI
.timelineHome("Bearer $accessToken", limit="${params.requestedLoadSize}")
enqueueCall(call, callback)
}
//This is called to when we get to the bottom of the loaded content, so we want statuses
//older than the given key (params.key)
override fun loadAfter(params: LoadParams<String>, callback: LoadCallback<Status>) {
val call = pixelfedAPI
.timelineHome("Bearer $accessToken", max_id=params.key,
limit="${params.requestedLoadSize}")
enqueueCall(call, callback)
}
override fun loadBefore(params: LoadParams<String>, callback: LoadCallback<Status>) {
//do nothing here, it is expected to pull to refresh to load newer content
}
}
inner class HomeDataSourceFactory: DataSource.Factory<String, Status>() {
lateinit var postLiveData: MutableLiveData<HomeDataSource>
override fun create(): DataSource<String, Status> {
val dataSource = HomeDataSource()
postLiveData = MutableLiveData()
postLiveData.postValue(dataSource)
return dataSource
}
}
}

View File

@ -11,10 +11,8 @@ import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import androidx.paging.DataSource
import androidx.paging.ItemKeyedDataSource
import androidx.paging.LivePagedListBuilder
import androidx.paging.PagedList
import androidx.recyclerview.widget.RecyclerView
@ -29,9 +27,8 @@ import com.h.pixeldroid.R
import com.h.pixeldroid.objects.Notification
import com.h.pixeldroid.objects.Status
import kotlinx.android.synthetic.main.fragment_feed.*
import kotlinx.android.synthetic.main.fragment_feed.swipeRefreshLayout
import kotlinx.android.synthetic.main.fragment_home.*
import kotlinx.android.synthetic.main.fragment_notifications.view.*
import retrofit2.Call
/**
@ -40,8 +37,6 @@ import kotlinx.android.synthetic.main.fragment_notifications.view.*
class NotificationsFragment : FeedFragment<Notification, NotificationsFragment.NotificationsRecyclerViewAdapter.ViewHolder>() {
lateinit var profilePicRequest: RequestBuilder<Drawable>
lateinit var factory: NotificationsDataSourceFactory
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
@ -50,9 +45,7 @@ class NotificationsFragment : FeedFragment<Notification, NotificationsFragment.N
val view = super.onCreateView(inflater, container, savedInstanceState)
val config: PagedList.Config = PagedList.Config.Builder().setPageSize(10).build()
factory = NotificationsDataSourceFactory()
content = LivePagedListBuilder(factory, config).build()
content = makeContent()
//RequestBuilder that is re-used for every image
profilePicRequest = Glide.with(this)
@ -79,13 +72,24 @@ class NotificationsFragment : FeedFragment<Notification, NotificationsFragment.N
return view
}
private fun makeContent(): LiveData<PagedList<Notification>> {
fun makeInitialCall(requestedLoadSize: Int): Call<List<Notification>> {
return pixelfedAPI
.notifications("Bearer $accessToken", min_id="1", limit="$requestedLoadSize")
}
fun makeAfterCall(requestedLoadSize: Int, key: String): Call<List<Notification>> {
return pixelfedAPI
.notifications("Bearer $accessToken", max_id=key, limit="$requestedLoadSize")
}
val config: PagedList.Config = PagedList.Config.Builder().setPageSize(10).build()
factory = FeedDataSourceFactory(::makeInitialCall, ::makeAfterCall)
return LivePagedListBuilder(factory, config).build()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
swipeRefreshLayout.setOnRefreshListener {
factory.notificationsLiveData.value!!.invalidate()
}
}
/**
@ -196,47 +200,4 @@ class NotificationsFragment : FeedFragment<Notification, NotificationsFragment.N
return profilePicRequest.load(item.account.avatar_static)
}
}
inner class NotificationsDataSource: ItemKeyedDataSource<String, Notification>() {
//We use the id as the key
override fun getKey(item: Notification): String {
return item.id
}
//This is called to initialize the list, so we want some of the latest statuses
override fun loadInitial(
params: LoadInitialParams<String>,
callback: LoadInitialCallback<Notification>
) {
val call = pixelfedAPI
.notifications("Bearer $accessToken", min_id="1", limit="${params.requestedLoadSize}")
enqueueCall(call, callback)
}
//This is called to when we get to the bottom of the loaded content, so we want statuses
//older than the given key (params.key)
override fun loadAfter(params: LoadParams<String>, callback: LoadCallback<Notification>) {
val call = pixelfedAPI
.notifications("Bearer $accessToken", max_id=params.key, limit="${params.requestedLoadSize}")
enqueueCall(call, callback)
}
override fun loadBefore(params: LoadParams<String>, callback: LoadCallback<Notification>) {
//do nothing here, it is expected to pull to refresh to load newer notifications
}
}
inner class NotificationsDataSourceFactory: DataSource.Factory<String, Notification>() {
lateinit var notificationsLiveData: MutableLiveData<NotificationsDataSource>
override fun create(): DataSource<String, Notification> {
val dataSource = NotificationsDataSource()
notificationsLiveData = MutableLiveData()
notificationsLiveData.postValue(dataSource)
return dataSource
}
}
}