Added public timeline (#134)

* added public timeline

* WIP fixing date

* added test for the Public timeline

* added tests for the public timeline

* took pr comments into account
This commit is contained in:
Andrew Dobis 2020-05-03 22:48:05 +02:00 committed by GitHub
parent 96e376887f
commit b873a90a9e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 111 additions and 14 deletions

View File

@ -245,6 +245,38 @@ class MockedServerTest {
onView(withId(R.id.list)).check(matches(isDisplayed()))
}
@Test
fun swipingLeftStopsAtPublicTimeline() {
activityScenario.onActivity {
a -> a.findViewById<TabLayout>(R.id.tabs).getTabAt(0)?.select()
}
Thread.sleep(1000)
onView(withId(R.id.main_activity_main_linear_layout))
.perform(ViewActions.swipeLeft()) // notifications
.perform(ViewActions.swipeLeft()) // camera
.perform(ViewActions.swipeLeft()) // search
.perform(ViewActions.swipeLeft()) // homepage
.perform(ViewActions.swipeLeft()) // should stop at homepage
onView(withId(R.id.list)).check(matches(isDisplayed()))
}
@Test
fun swipingPublicTimelineWorks() {
activityScenario.onActivity {
a -> a.findViewById<TabLayout>(R.id.tabs).getTabAt(4)?.select()
} // go to the last tab
Thread.sleep(1000)
onView(withId(R.id.main_activity_main_linear_layout))
.perform(ViewActions.swipeUp()) // notifications
.perform(ViewActions.swipeUp()) // camera
.perform(ViewActions.swipeUp()) // search
.perform(ViewActions.swipeUp()) // homepage
.perform(ViewActions.swipeUp()) // should stop at homepage
onView(withId(R.id.list)).check(matches(isDisplayed()))
}
@Test
fun clickingTabOnAlbumShowsNextPhoto() {
ActivityScenario.launch(MainActivity::class.java).onActivity {

View File

@ -202,6 +202,12 @@ class MockServer {
"application/json; charset=utf-8"
).setResponseCode(200).setBody(feedJson)
}
request.path?.startsWith("/api/v1/timelines/public") == true -> {
return MockResponse().addHeader(
"Content-Type",
"application/json; charset=utf-8"
).setResponseCode(200).setBody(feedJson)
}
request.path?.startsWith("/api/v1/accounts/0/statuses") == true -> {
return MockResponse().setHttp2ErrorCode(401)
}

View File

@ -24,6 +24,7 @@ import com.h.pixeldroid.fragments.NewPostFragment
import com.h.pixeldroid.fragments.SearchDiscoverFragment
import com.h.pixeldroid.fragments.feeds.PostsFeedFragment
import com.h.pixeldroid.fragments.feeds.NotificationsFragment
import com.h.pixeldroid.fragments.feeds.PublicTimelineFragment
import com.h.pixeldroid.objects.Account
import com.h.pixeldroid.utils.ImageConverter
import retrofit2.Call
@ -59,7 +60,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
searchDiscoverFragment,
NewPostFragment(),
NotificationsFragment(),
Fragment()
PublicTimelineFragment()
)
setupTabs(tabs)
@ -121,7 +122,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
1 -> tab.icon = getDrawable(R.drawable.ic_search_white_24dp)
2 -> tab.icon = getDrawable(R.drawable.ic_photo_camera_white_24dp)
3 -> tab.icon = getDrawable(R.drawable.ic_heart)
4 -> tab.icon = getDrawable(R.drawable.ic_person_white_24dp)
4 -> tab.icon = getDrawable(R.drawable.ic_filter_black_24dp)
}
}.attach()
}

View File

@ -104,7 +104,7 @@ open class FeedFragment<T: FeedContent, VH: RecyclerView.ViewHolder?>: Fragment(
//do nothing here, it is expected to pull to refresh to load newer notifications
}
private fun enqueueCall(call: Call<List<T>>, callback: LoadCallback<T>){
protected open 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>>) {

View File

@ -24,7 +24,6 @@ import com.h.pixeldroid.R
import com.h.pixeldroid.objects.Status
import retrofit2.Call
open class PostsFeedFragment : FeedFragment<Status, PostViewHolder>() {
lateinit var picRequest: RequestBuilder<Drawable>

View File

@ -0,0 +1,45 @@
package com.h.pixeldroid.fragments.feeds
import androidx.lifecycle.LiveData
import androidx.paging.LivePagedListBuilder
import androidx.paging.PagedList
import com.h.pixeldroid.objects.Status
import retrofit2.Call
class PublicTimelineFragment: PostsFeedFragment() {
inner class SearchFeedDataSource(
) : FeedDataSource(null, null){
override fun newSource(): FeedDataSource {
return SearchFeedDataSource()
}
private fun makeInitialCall(requestedLoadSize: Int): Call<List<Status>> {
return pixelfedAPI.timelinePublic(limit="$requestedLoadSize")
}
private fun makeAfterCall(requestedLoadSize: Int, key: String): Call<List<Status>> {
return pixelfedAPI.timelinePublic( max_id=key, limit="$requestedLoadSize")
}
override fun loadInitial(
params: LoadInitialParams<String>,
callback: LoadInitialCallback<Status>
) {
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<Status>) {
enqueueCall(makeAfterCall(params.requestedLoadSize, params.key), callback)
}
}
override fun makeContent(): LiveData<PagedList<Status>> {
val config: PagedList.Config = PagedList.Config.Builder().setPageSize(10).build()
factory = FeedFragment<Status, PostViewHolder>()
.FeedDataSourceFactory(SearchFeedDataSource())
return LivePagedListBuilder(factory, config).build()
}
}

View File

@ -55,15 +55,15 @@ class SearchAccountFragment: AccountListFragment(){
params: LoadInitialParams<String>,
callback: LoadInitialCallback<Account>
) {
enqueueCall(makeInitialCall(params.requestedLoadSize), callback)
searchEnqueueCall(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<Account>) {
enqueueCall(makeAfterCall(params.requestedLoadSize, params.key), callback)
searchEnqueueCall(makeAfterCall(params.requestedLoadSize, params.key), callback)
}
private fun enqueueCall(call: Call<Results>, callback: LoadCallback<Account>){
private fun searchEnqueueCall(call: Call<Results>, callback: LoadCallback<Account>) {
call.enqueue(object : Callback<Results> {
override fun onResponse(call: Call<Results>, response: Response<Results>) {

View File

@ -92,16 +92,16 @@ class SearchHashtagFragment: FeedFragment<Tag, SearchHashtagFragment.TagsRecycle
params: LoadInitialParams<String>,
callback: LoadInitialCallback<Tag>
) {
enqueueCall(makeInitialCall(params.requestedLoadSize), callback)
searchEnqueueCall(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<Tag>) {
enqueueCall(makeAfterCall(params.requestedLoadSize, params.key), callback)
searchEnqueueCall(makeAfterCall(params.requestedLoadSize, params.key), callback)
}
private fun enqueueCall(call: Call<Results>, callback: LoadCallback<Tag>){
private fun searchEnqueueCall(call: Call<Results>, callback: LoadCallback<Tag>){
call.enqueue(object : Callback<Results> {
override fun onResponse(call: Call<Results>, response: Response<Results>) {

View File

@ -57,16 +57,16 @@ class SearchPostsFragment: PostsFeedFragment(){
params: LoadInitialParams<String>,
callback: LoadInitialCallback<Status>
) {
enqueueCall(makeInitialCall(params.requestedLoadSize), callback)
searchEnqueueCall(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<Status>) {
enqueueCall(makeAfterCall(params.requestedLoadSize, params.key), callback)
searchEnqueueCall(makeAfterCall(params.requestedLoadSize, params.key), callback)
}
private fun enqueueCall(call: Call<Results>, callback: LoadCallback<Status>){
private fun searchEnqueueCall(call: Call<Results>, callback: LoadCallback<Status>){
call.enqueue(object : Callback<Results> {
override fun onResponse(call: Call<Results>, response: Response<Results>) {

View File

@ -132,7 +132,12 @@ data class Status(
}
private fun ISO8601toDate(dateString : String, textView: TextView, isActivity: Boolean) {
val format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.'000000Z'")
var format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.hhmmss'Z'")
if(dateString.matches("[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{6}Z".toRegex())) {
format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.hhmmss'Z'")
} else if(dateString.matches("[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}+[0-9]{2}:[0-9]{2}".toRegex())) {
format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss+hh:mm")
}
val now = Date().time
try {

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M15.96,10.29l-2.75,3.54 -1.96,-2.36L8.5,15h11l-3.54,-4.71zM3,5L1,5v16c0,1.1 0.9,2 2,2h16v-2L3,21L3,5zM21,1L7,1c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L23,3c0,-1.1 -0.9,-2 -2,-2zM21,17L7,17L7,3h14v14z"/>
</vector>