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:
Nik Clayton 2023-09-01 19:06:56 +02:00
parent 049710e0b0
commit b1fd20e005
No known key found for this signature in database
GPG Key ID: F95268159C2EC897
8 changed files with 29 additions and 7 deletions

View File

@ -36,6 +36,7 @@ const val FEDERATED = "Federated"
const val DIRECT = "Direct"
const val TRENDING_TAGS = "TrendingTags"
const val TRENDING_LINKS = "TrendingLinks"
const val TRENDING_STATUSES = "TrendingStatuses"
const val HASHTAG = "Hashtag"
const val LIST = "List"
const val BOOKMARKS = "Bookmarks"
@ -107,6 +108,12 @@ fun createTabDataFromId(id: String, arguments: List<String> = emptyList()): TabD
icon = R.drawable.ic_trending_up_24px,
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(
id = HASHTAG,
text = R.string.hashtags,

View File

@ -386,6 +386,9 @@ class TabPreferenceActivity : BaseActivity(), Injectable, ItemInteractionListene
if (!currentTabs.contains(trendingLinksTab)) {
addableTabs.add(trendingLinksTab)
}
createTabDataFromId(TRENDING_STATUSES).apply {
currentTabs.contains(this) || addableTabs.add(this)
}
val bookmarksTab = createTabDataFromId(BOOKMARKS)
if (!currentTabs.contains(trendingTagsTab)) {
addableTabs.add(bookmarksTab)

View File

@ -549,7 +549,8 @@ class TimelineFragment :
TimelineViewModel.Kind.FAVOURITES,
TimelineViewModel.Kind.LIST,
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 &&
viewModel.kind != TimelineViewModel.Kind.FAVOURITES &&
viewModel.kind != TimelineViewModel.Kind.BOOKMARKS &&
viewModel.kind != TimelineViewModel.Kind.TRENDING_STATUSES &&
activity is ActionButtonActivity
}

View File

@ -308,6 +308,7 @@ class NetworkTimelineViewModel @Inject constructor(
Kind.FAVOURITES -> api.favourites(fromId, uptoId, limit)
Kind.BOOKMARKS -> api.bookmarks(fromId, uptoId, limit)
Kind.LIST -> api.listTimeline(id!!, fromId, uptoId, limit)
Kind.TRENDING_STATUSES -> api.trendingStatuses()
}
}

View File

@ -321,7 +321,7 @@ abstract class TimelineViewModel(
}
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 {
return when (valueOf(name)) {

View File

@ -30,8 +30,10 @@ import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter
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.components.timeline.TimelineFragment
import com.keylesspalace.tusky.components.timeline.viewmodel.TimelineViewModel
import com.keylesspalace.tusky.databinding.ActivityTrendingBinding
import com.keylesspalace.tusky.util.reduceSwipeSensitivity
import com.keylesspalace.tusky.util.viewBinding
@ -39,7 +41,7 @@ import dagger.android.DispatchingAndroidInjector
import dagger.android.HasAndroidInjector
import javax.inject.Inject
class TrendingActivity : BaseActivity(), HasAndroidInjector, MenuProvider {
class TrendingActivity : BottomSheetActivity(), HasAndroidInjector, MenuProvider {
@Inject
lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Any>
@ -93,12 +95,13 @@ class TrendingActivity : BaseActivity(), HasAndroidInjector, MenuProvider {
}
class TrendingFragmentAdapter(val activity: FragmentActivity) : FragmentStateAdapter(activity) {
override fun getItemCount() = 2
override fun getItemCount() = 3
override fun createFragment(position: Int): Fragment {
return when (position) {
0 -> TrendingTagsFragment.newInstance()
1 -> TrendingLinksFragment.newInstance()
2 -> TimelineFragment.newInstance(TimelineViewModel.Kind.TRENDING_STATUSES)
else -> throw IllegalStateException()
}
}
@ -107,6 +110,7 @@ class TrendingFragmentAdapter(val activity: FragmentActivity) : FragmentStateAda
return when (position) {
0 -> activity.getString(R.string.title_tab_public_trending_hashtags)
1 -> activity.getString(R.string.title_tab_public_trending_links)
2 -> activity.getString(R.string.title_tab_public_trending_statuses)
else -> throw IllegalStateException()
}
}

View File

@ -789,4 +789,7 @@ interface MastodonApi {
@GET("api/v1/trends/links")
suspend fun trendingLinks(): NetworkResult<List<TrendsLink>>
@GET("api/v1/trends/statuses")
suspend fun trendingStatuses(): Response<List<Status>>
}

View File

@ -53,10 +53,12 @@
<string name="title_notifications">Notifications</string>
<string name="title_public_local">Local</string>
<string name="title_public_trending">Trending</string>
<string name="title_public_trending_hashtags">Trending Hashtags</string>
<string name="title_public_trending_links">Trending Links</string>
<string name="title_public_trending_hashtags">Trending hashtags</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_links">Links</string>
<string name="title_tab_public_trending_statuses">Posts</string>
<string name="title_public_federated">Federated</string>
<string name="title_direct_messages">Direct messages</string>
<string name="title_tab_preferences">Tabs</string>