feat: Support "Trending posts"
- Implement the trending posts API - Display trending statuses as a new Timeline kind - Allow the user to add trending statuses to a dedicated tab - Always show the "Trending" option in the navigation menu
This commit is contained in:
parent
049710e0b0
commit
b1fd20e005
|
@ -36,6 +36,7 @@ const val FEDERATED = "Federated"
|
||||||
const val DIRECT = "Direct"
|
const val DIRECT = "Direct"
|
||||||
const val TRENDING_TAGS = "TrendingTags"
|
const val TRENDING_TAGS = "TrendingTags"
|
||||||
const val TRENDING_LINKS = "TrendingLinks"
|
const val TRENDING_LINKS = "TrendingLinks"
|
||||||
|
const val TRENDING_STATUSES = "TrendingStatuses"
|
||||||
const val HASHTAG = "Hashtag"
|
const val HASHTAG = "Hashtag"
|
||||||
const val LIST = "List"
|
const val LIST = "List"
|
||||||
const val BOOKMARKS = "Bookmarks"
|
const val BOOKMARKS = "Bookmarks"
|
||||||
|
@ -107,6 +108,12 @@ fun createTabDataFromId(id: String, arguments: List<String> = emptyList()): TabD
|
||||||
icon = R.drawable.ic_trending_up_24px,
|
icon = R.drawable.ic_trending_up_24px,
|
||||||
fragment = { TrendingLinksFragment.newInstance() }
|
fragment = { TrendingLinksFragment.newInstance() }
|
||||||
)
|
)
|
||||||
|
TRENDING_STATUSES -> TabData(
|
||||||
|
id = TRENDING_STATUSES,
|
||||||
|
text = R.string.title_public_trending_statuses,
|
||||||
|
icon = R.drawable.ic_trending_up_24px,
|
||||||
|
fragment = { TimelineFragment.newInstance(TimelineViewModel.Kind.TRENDING_STATUSES) }
|
||||||
|
)
|
||||||
HASHTAG -> TabData(
|
HASHTAG -> TabData(
|
||||||
id = HASHTAG,
|
id = HASHTAG,
|
||||||
text = R.string.hashtags,
|
text = R.string.hashtags,
|
||||||
|
|
|
@ -386,6 +386,9 @@ class TabPreferenceActivity : BaseActivity(), Injectable, ItemInteractionListene
|
||||||
if (!currentTabs.contains(trendingLinksTab)) {
|
if (!currentTabs.contains(trendingLinksTab)) {
|
||||||
addableTabs.add(trendingLinksTab)
|
addableTabs.add(trendingLinksTab)
|
||||||
}
|
}
|
||||||
|
createTabDataFromId(TRENDING_STATUSES).apply {
|
||||||
|
currentTabs.contains(this) || addableTabs.add(this)
|
||||||
|
}
|
||||||
val bookmarksTab = createTabDataFromId(BOOKMARKS)
|
val bookmarksTab = createTabDataFromId(BOOKMARKS)
|
||||||
if (!currentTabs.contains(trendingTagsTab)) {
|
if (!currentTabs.contains(trendingTagsTab)) {
|
||||||
addableTabs.add(bookmarksTab)
|
addableTabs.add(bookmarksTab)
|
||||||
|
|
|
@ -549,7 +549,8 @@ class TimelineFragment :
|
||||||
TimelineViewModel.Kind.FAVOURITES,
|
TimelineViewModel.Kind.FAVOURITES,
|
||||||
TimelineViewModel.Kind.LIST,
|
TimelineViewModel.Kind.LIST,
|
||||||
TimelineViewModel.Kind.BOOKMARKS,
|
TimelineViewModel.Kind.BOOKMARKS,
|
||||||
TimelineViewModel.Kind.USER_PINNED -> return
|
TimelineViewModel.Kind.USER_PINNED,
|
||||||
|
TimelineViewModel.Kind.TRENDING_STATUSES -> return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -562,6 +563,7 @@ class TimelineFragment :
|
||||||
return viewModel.kind != TimelineViewModel.Kind.TAG &&
|
return viewModel.kind != TimelineViewModel.Kind.TAG &&
|
||||||
viewModel.kind != TimelineViewModel.Kind.FAVOURITES &&
|
viewModel.kind != TimelineViewModel.Kind.FAVOURITES &&
|
||||||
viewModel.kind != TimelineViewModel.Kind.BOOKMARKS &&
|
viewModel.kind != TimelineViewModel.Kind.BOOKMARKS &&
|
||||||
|
viewModel.kind != TimelineViewModel.Kind.TRENDING_STATUSES &&
|
||||||
activity is ActionButtonActivity
|
activity is ActionButtonActivity
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -308,6 +308,7 @@ class NetworkTimelineViewModel @Inject constructor(
|
||||||
Kind.FAVOURITES -> api.favourites(fromId, uptoId, limit)
|
Kind.FAVOURITES -> api.favourites(fromId, uptoId, limit)
|
||||||
Kind.BOOKMARKS -> api.bookmarks(fromId, uptoId, limit)
|
Kind.BOOKMARKS -> api.bookmarks(fromId, uptoId, limit)
|
||||||
Kind.LIST -> api.listTimeline(id!!, fromId, uptoId, limit)
|
Kind.LIST -> api.listTimeline(id!!, fromId, uptoId, limit)
|
||||||
|
Kind.TRENDING_STATUSES -> api.trendingStatuses()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -321,7 +321,7 @@ abstract class TimelineViewModel(
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class Kind {
|
enum class Kind {
|
||||||
HOME, PUBLIC_LOCAL, PUBLIC_FEDERATED, TAG, USER, USER_PINNED, USER_WITH_REPLIES, FAVOURITES, LIST, BOOKMARKS;
|
HOME, PUBLIC_LOCAL, PUBLIC_FEDERATED, TAG, USER, USER_PINNED, USER_WITH_REPLIES, FAVOURITES, LIST, BOOKMARKS, TRENDING_STATUSES;
|
||||||
|
|
||||||
fun toFilterKind(): Filter.Kind {
|
fun toFilterKind(): Filter.Kind {
|
||||||
return when (valueOf(name)) {
|
return when (valueOf(name)) {
|
||||||
|
|
|
@ -30,8 +30,10 @@ import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||||
import com.google.android.material.tabs.TabLayoutMediator
|
import com.google.android.material.tabs.TabLayoutMediator
|
||||||
import com.keylesspalace.tusky.BaseActivity
|
import com.keylesspalace.tusky.BottomSheetActivity
|
||||||
import com.keylesspalace.tusky.R
|
import com.keylesspalace.tusky.R
|
||||||
|
import com.keylesspalace.tusky.components.timeline.TimelineFragment
|
||||||
|
import com.keylesspalace.tusky.components.timeline.viewmodel.TimelineViewModel
|
||||||
import com.keylesspalace.tusky.databinding.ActivityTrendingBinding
|
import com.keylesspalace.tusky.databinding.ActivityTrendingBinding
|
||||||
import com.keylesspalace.tusky.util.reduceSwipeSensitivity
|
import com.keylesspalace.tusky.util.reduceSwipeSensitivity
|
||||||
import com.keylesspalace.tusky.util.viewBinding
|
import com.keylesspalace.tusky.util.viewBinding
|
||||||
|
@ -39,7 +41,7 @@ import dagger.android.DispatchingAndroidInjector
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class TrendingActivity : BaseActivity(), HasAndroidInjector, MenuProvider {
|
class TrendingActivity : BottomSheetActivity(), HasAndroidInjector, MenuProvider {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Any>
|
lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Any>
|
||||||
|
@ -93,12 +95,13 @@ class TrendingActivity : BaseActivity(), HasAndroidInjector, MenuProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
class TrendingFragmentAdapter(val activity: FragmentActivity) : FragmentStateAdapter(activity) {
|
class TrendingFragmentAdapter(val activity: FragmentActivity) : FragmentStateAdapter(activity) {
|
||||||
override fun getItemCount() = 2
|
override fun getItemCount() = 3
|
||||||
|
|
||||||
override fun createFragment(position: Int): Fragment {
|
override fun createFragment(position: Int): Fragment {
|
||||||
return when (position) {
|
return when (position) {
|
||||||
0 -> TrendingTagsFragment.newInstance()
|
0 -> TrendingTagsFragment.newInstance()
|
||||||
1 -> TrendingLinksFragment.newInstance()
|
1 -> TrendingLinksFragment.newInstance()
|
||||||
|
2 -> TimelineFragment.newInstance(TimelineViewModel.Kind.TRENDING_STATUSES)
|
||||||
else -> throw IllegalStateException()
|
else -> throw IllegalStateException()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,6 +110,7 @@ class TrendingFragmentAdapter(val activity: FragmentActivity) : FragmentStateAda
|
||||||
return when (position) {
|
return when (position) {
|
||||||
0 -> activity.getString(R.string.title_tab_public_trending_hashtags)
|
0 -> activity.getString(R.string.title_tab_public_trending_hashtags)
|
||||||
1 -> activity.getString(R.string.title_tab_public_trending_links)
|
1 -> activity.getString(R.string.title_tab_public_trending_links)
|
||||||
|
2 -> activity.getString(R.string.title_tab_public_trending_statuses)
|
||||||
else -> throw IllegalStateException()
|
else -> throw IllegalStateException()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -789,4 +789,7 @@ interface MastodonApi {
|
||||||
|
|
||||||
@GET("api/v1/trends/links")
|
@GET("api/v1/trends/links")
|
||||||
suspend fun trendingLinks(): NetworkResult<List<TrendsLink>>
|
suspend fun trendingLinks(): NetworkResult<List<TrendsLink>>
|
||||||
|
|
||||||
|
@GET("api/v1/trends/statuses")
|
||||||
|
suspend fun trendingStatuses(): Response<List<Status>>
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,10 +53,12 @@
|
||||||
<string name="title_notifications">Notifications</string>
|
<string name="title_notifications">Notifications</string>
|
||||||
<string name="title_public_local">Local</string>
|
<string name="title_public_local">Local</string>
|
||||||
<string name="title_public_trending">Trending</string>
|
<string name="title_public_trending">Trending</string>
|
||||||
<string name="title_public_trending_hashtags">Trending Hashtags</string>
|
<string name="title_public_trending_hashtags">Trending hashtags</string>
|
||||||
<string name="title_public_trending_links">Trending Links</string>
|
<string name="title_public_trending_links">Trending links</string>
|
||||||
|
<string name="title_public_trending_statuses">Trending posts</string>
|
||||||
<string name="title_tab_public_trending_hashtags">Hashtags</string>
|
<string name="title_tab_public_trending_hashtags">Hashtags</string>
|
||||||
<string name="title_tab_public_trending_links">Links</string>
|
<string name="title_tab_public_trending_links">Links</string>
|
||||||
|
<string name="title_tab_public_trending_statuses">Posts</string>
|
||||||
<string name="title_public_federated">Federated</string>
|
<string name="title_public_federated">Federated</string>
|
||||||
<string name="title_direct_messages">Direct messages</string>
|
<string name="title_direct_messages">Direct messages</string>
|
||||||
<string name="title_tab_preferences">Tabs</string>
|
<string name="title_tab_preferences">Tabs</string>
|
||||||
|
|
Loading…
Reference in New Issue