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:
parent
96e376887f
commit
b873a90a9e
|
@ -245,6 +245,38 @@ class MockedServerTest {
|
||||||
onView(withId(R.id.list)).check(matches(isDisplayed()))
|
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
|
@Test
|
||||||
fun clickingTabOnAlbumShowsNextPhoto() {
|
fun clickingTabOnAlbumShowsNextPhoto() {
|
||||||
ActivityScenario.launch(MainActivity::class.java).onActivity {
|
ActivityScenario.launch(MainActivity::class.java).onActivity {
|
||||||
|
|
|
@ -202,6 +202,12 @@ class MockServer {
|
||||||
"application/json; charset=utf-8"
|
"application/json; charset=utf-8"
|
||||||
).setResponseCode(200).setBody(feedJson)
|
).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 -> {
|
request.path?.startsWith("/api/v1/accounts/0/statuses") == true -> {
|
||||||
return MockResponse().setHttp2ErrorCode(401)
|
return MockResponse().setHttp2ErrorCode(401)
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ import com.h.pixeldroid.fragments.NewPostFragment
|
||||||
import com.h.pixeldroid.fragments.SearchDiscoverFragment
|
import com.h.pixeldroid.fragments.SearchDiscoverFragment
|
||||||
import com.h.pixeldroid.fragments.feeds.PostsFeedFragment
|
import com.h.pixeldroid.fragments.feeds.PostsFeedFragment
|
||||||
import com.h.pixeldroid.fragments.feeds.NotificationsFragment
|
import com.h.pixeldroid.fragments.feeds.NotificationsFragment
|
||||||
|
import com.h.pixeldroid.fragments.feeds.PublicTimelineFragment
|
||||||
import com.h.pixeldroid.objects.Account
|
import com.h.pixeldroid.objects.Account
|
||||||
import com.h.pixeldroid.utils.ImageConverter
|
import com.h.pixeldroid.utils.ImageConverter
|
||||||
import retrofit2.Call
|
import retrofit2.Call
|
||||||
|
@ -59,7 +60,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
|
||||||
searchDiscoverFragment,
|
searchDiscoverFragment,
|
||||||
NewPostFragment(),
|
NewPostFragment(),
|
||||||
NotificationsFragment(),
|
NotificationsFragment(),
|
||||||
Fragment()
|
PublicTimelineFragment()
|
||||||
)
|
)
|
||||||
|
|
||||||
setupTabs(tabs)
|
setupTabs(tabs)
|
||||||
|
@ -121,7 +122,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
|
||||||
1 -> tab.icon = getDrawable(R.drawable.ic_search_white_24dp)
|
1 -> tab.icon = getDrawable(R.drawable.ic_search_white_24dp)
|
||||||
2 -> tab.icon = getDrawable(R.drawable.ic_photo_camera_white_24dp)
|
2 -> tab.icon = getDrawable(R.drawable.ic_photo_camera_white_24dp)
|
||||||
3 -> tab.icon = getDrawable(R.drawable.ic_heart)
|
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()
|
}.attach()
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
//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>> {
|
call.enqueue(object : Callback<List<T>> {
|
||||||
override fun onResponse(call: Call<List<T>>, response: Response<List<T>>) {
|
override fun onResponse(call: Call<List<T>>, response: Response<List<T>>) {
|
||||||
|
|
|
@ -24,7 +24,6 @@ import com.h.pixeldroid.R
|
||||||
import com.h.pixeldroid.objects.Status
|
import com.h.pixeldroid.objects.Status
|
||||||
import retrofit2.Call
|
import retrofit2.Call
|
||||||
|
|
||||||
|
|
||||||
open class PostsFeedFragment : FeedFragment<Status, PostViewHolder>() {
|
open class PostsFeedFragment : FeedFragment<Status, PostViewHolder>() {
|
||||||
|
|
||||||
lateinit var picRequest: RequestBuilder<Drawable>
|
lateinit var picRequest: RequestBuilder<Drawable>
|
||||||
|
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
|
@ -55,15 +55,15 @@ class SearchAccountFragment: AccountListFragment(){
|
||||||
params: LoadInitialParams<String>,
|
params: LoadInitialParams<String>,
|
||||||
callback: LoadInitialCallback<Account>
|
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
|
//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)
|
//older than the given key (params.key)
|
||||||
override fun loadAfter(params: LoadParams<String>, callback: LoadCallback<Account>) {
|
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> {
|
call.enqueue(object : Callback<Results> {
|
||||||
override fun onResponse(call: Call<Results>, response: Response<Results>) {
|
override fun onResponse(call: Call<Results>, response: Response<Results>) {
|
||||||
|
|
|
@ -92,16 +92,16 @@ class SearchHashtagFragment: FeedFragment<Tag, SearchHashtagFragment.TagsRecycle
|
||||||
params: LoadInitialParams<String>,
|
params: LoadInitialParams<String>,
|
||||||
callback: LoadInitialCallback<Tag>
|
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
|
//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)
|
//older than the given key (params.key)
|
||||||
override fun loadAfter(params: LoadParams<String>, callback: LoadCallback<Tag>) {
|
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> {
|
call.enqueue(object : Callback<Results> {
|
||||||
override fun onResponse(call: Call<Results>, response: Response<Results>) {
|
override fun onResponse(call: Call<Results>, response: Response<Results>) {
|
||||||
|
|
|
@ -57,16 +57,16 @@ class SearchPostsFragment: PostsFeedFragment(){
|
||||||
params: LoadInitialParams<String>,
|
params: LoadInitialParams<String>,
|
||||||
callback: LoadInitialCallback<Status>
|
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
|
//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)
|
//older than the given key (params.key)
|
||||||
override fun loadAfter(params: LoadParams<String>, callback: LoadCallback<Status>) {
|
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> {
|
call.enqueue(object : Callback<Results> {
|
||||||
override fun onResponse(call: Call<Results>, response: Response<Results>) {
|
override fun onResponse(call: Call<Results>, response: Response<Results>) {
|
||||||
|
|
|
@ -132,7 +132,12 @@ data class Status(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ISO8601toDate(dateString : String, textView: TextView, isActivity: Boolean) {
|
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
|
val now = Date().time
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -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>
|
Loading…
Reference in New Issue