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.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import android.graphics.pdf.PdfDocument
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
@ -10,6 +11,8 @@ import android.view.ViewGroup
import android.widget.Toast import android.widget.Toast
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.paging.DataSource
import androidx.paging.ItemKeyedDataSource import androidx.paging.ItemKeyedDataSource
import androidx.paging.PagedList import androidx.paging.PagedList
import androidx.paging.PagedListAdapter import androidx.paging.PagedListAdapter
@ -31,7 +34,7 @@ import retrofit2.Response
open class FeedFragment<T: FeedContent, VH: RecyclerView.ViewHolder?>: Fragment() { open class FeedFragment<T: FeedContent, VH: RecyclerView.ViewHolder?>: Fragment() {
lateinit var content: LiveData<PagedList<T>> lateinit var content: LiveData<PagedList<T>>
lateinit var factory: FeedDataSourceFactory
protected var accessToken: String? = null protected var accessToken: String? = null
protected lateinit var pixelfedAPI: PixelfedAPI protected lateinit var pixelfedAPI: PixelfedAPI
@ -66,26 +69,73 @@ open class FeedFragment<T: FeedContent, VH: RecyclerView.ViewHolder?>: Fragment(
pixelfedAPI = PixelfedAPI.create("${preferences.getString("domain", "")}") pixelfedAPI = PixelfedAPI.create("${preferences.getString("domain", "")}")
accessToken = preferences.getString("accessToken", "") 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>){ inner class FeedDataSource(private val makeInitialCall: (Int) -> Call<List<T>>,
call.enqueue(object : Callback<List<T>> { private val makeAfterCall: (Int, String) -> Call<List<T>>
override fun onResponse(call: Call<List<T>>, response: Response<List<T>>) { ): ItemKeyedDataSource<String, T>() {
if (response.code() == 200) {
val notifications = response.body()!! as ArrayList<T> //We use the id as the key
callback.onResult(notifications as List<T>) override fun getKey(item: T): String {
} else{ return item.id
Toast.makeText(context,"Something went wrong while loading", Toast.LENGTH_SHORT).show() }
} //This is called to initialize the list, so we want some of the latest statuses
swipeRefreshLayout.isRefreshing = false override fun loadInitial(
progressBar.visibility = View.GONE 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())
}
})
} }
} }
@ -103,3 +153,4 @@ abstract class FeedsRecyclerViewAdapter<T: FeedContent, VH : RecyclerView.ViewHo
protected lateinit var context: Context protected lateinit var context: Context
} }

View File

@ -9,10 +9,8 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageView import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.paging.DataSource
import androidx.paging.ItemKeyedDataSource
import androidx.paging.LivePagedListBuilder import androidx.paging.LivePagedListBuilder
import androidx.paging.PagedList import androidx.paging.PagedList
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
@ -25,12 +23,12 @@ import com.h.pixeldroid.R
import com.h.pixeldroid.objects.Status import com.h.pixeldroid.objects.Status
import com.h.pixeldroid.utils.ImageConverter import com.h.pixeldroid.utils.ImageConverter
import kotlinx.android.synthetic.main.fragment_home.* import kotlinx.android.synthetic.main.fragment_home.*
import retrofit2.Call
class HomeFragment : FeedFragment<Status, HomeFragment.HomeRecyclerViewAdapter.ViewHolder>() { class HomeFragment : FeedFragment<Status, HomeFragment.HomeRecyclerViewAdapter.ViewHolder>() {
lateinit var picRequest: RequestBuilder<Drawable> lateinit var picRequest: RequestBuilder<Drawable>
lateinit var factory: HomeDataSourceFactory
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, inflater: LayoutInflater, container: ViewGroup?,
@ -38,9 +36,7 @@ class HomeFragment : FeedFragment<Status, HomeFragment.HomeRecyclerViewAdapter.V
): View? { ): View? {
val view = super.onCreateView(inflater, container, savedInstanceState) val view = super.onCreateView(inflater, container, savedInstanceState)
val config: PagedList.Config = PagedList.Config.Builder().setPageSize(10).build() content = makeContent()
factory = HomeDataSourceFactory()
content = LivePagedListBuilder(factory, config).build()
//RequestBuilder that is re-used for every image //RequestBuilder that is re-used for every image
picRequest = Glide.with(this) picRequest = Glide.with(this)
@ -67,13 +63,24 @@ class HomeFragment : FeedFragment<Status, HomeFragment.HomeRecyclerViewAdapter.V
return view 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?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) 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()) 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.ImageView
import android.widget.TextView import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.paging.DataSource
import androidx.paging.ItemKeyedDataSource
import androidx.paging.LivePagedListBuilder import androidx.paging.LivePagedListBuilder
import androidx.paging.PagedList import androidx.paging.PagedList
import androidx.recyclerview.widget.RecyclerView 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.Notification
import com.h.pixeldroid.objects.Status import com.h.pixeldroid.objects.Status
import kotlinx.android.synthetic.main.fragment_feed.* 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 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>() { class NotificationsFragment : FeedFragment<Notification, NotificationsFragment.NotificationsRecyclerViewAdapter.ViewHolder>() {
lateinit var profilePicRequest: RequestBuilder<Drawable> lateinit var profilePicRequest: RequestBuilder<Drawable>
lateinit var factory: NotificationsDataSourceFactory
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, inflater: LayoutInflater, container: ViewGroup?,
@ -50,9 +45,7 @@ class NotificationsFragment : FeedFragment<Notification, NotificationsFragment.N
val view = super.onCreateView(inflater, container, savedInstanceState) val view = super.onCreateView(inflater, container, savedInstanceState)
val config: PagedList.Config = PagedList.Config.Builder().setPageSize(10).build() content = makeContent()
factory = NotificationsDataSourceFactory()
content = LivePagedListBuilder(factory, config).build()
//RequestBuilder that is re-used for every image //RequestBuilder that is re-used for every image
profilePicRequest = Glide.with(this) profilePicRequest = Glide.with(this)
@ -79,13 +72,24 @@ class NotificationsFragment : FeedFragment<Notification, NotificationsFragment.N
return view 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?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) 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) 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
}
}
} }