mirror of
https://github.com/pachli/pachli-android.git
synced 2025-02-03 10:47:34 +01:00
feat: Simplify adding/removing timelines from tabs (#587)
Previously, modifying any tabs meant opening the left-side nav, opening Account preferences > Tabs, and then adding / removing tabs. This is time consuming, and difficult for new users to discover. In addition, it was possible to remove the Home tab, and there was a hardcoded minimum of at least two tabs. Fix this. When viewing a timeline that is not already in a tab an "Add to tab" menu item is enabled, which appends the timeline to the list of existing tabs. When viewing a timeline in a tab (that is not the Home timeline) a "Remove tab" menu item is enabled, which removes the tab from the list of existing tabs. If the user removes the active tab (either with this menu item, or through preferences) the tab to the left of the active tab becomes the new active tab. A new "Manage tabs" menu item is also provided, as a shortcut to the existing Account preferences > Tabs screen. When managing tabs the Home timeline can not be removed; the button to remove it is removed, and swiping is disabled on that list item. The restriction of "at least two tabs" has also been removed. `NotificationsActivity` has been removed, as `TimelineActivity` can display `NotificationsFragment`. To make the three "Trending" types (hashtags, links, and posts) more visually distinct add two new icons for links (ic_newspaper) and posts (ic_whatshot). Fixes #572, #584, #585, #569
This commit is contained in:
parent
0829d91989
commit
6bef6f2fae
@ -949,21 +949,10 @@
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/app/pachli/adapter/TabAdapter.kt"
|
||||
line="55"
|
||||
line="53"
|
||||
column="9"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="NotifyDataSetChanged"
|
||||
message="It will always be more efficient to use more specific change events if you can. Rely on `notifyDataSetChanged` as a last resort."
|
||||
errorLine1=" notifyDataSetChanged()"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/app/pachli/adapter/TabAdapter.kt"
|
||||
line="158"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="VectorPath"
|
||||
message="Very long vector path (2783 characters), which is bad for performance. Considering reducing precision, removing minor details or rasterizing vector."
|
||||
@ -2430,7 +2419,7 @@
|
||||
errorLine2=" ~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/layout/item_tab_preference.xml"
|
||||
line="26"
|
||||
line="27"
|
||||
column="6"/>
|
||||
</issue>
|
||||
|
||||
@ -2621,28 +2610,6 @@
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="ClickableViewAccessibility"
|
||||
message="Custom view ``ImageView`` has `setOnTouchListener` called on it but does not override `performClick`"
|
||||
errorLine1=" binding.imageView.setOnTouchListener { _, event ->"
|
||||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/java/app/pachli/adapter/TabAdapter.kt"
|
||||
line="92"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="ClickableViewAccessibility"
|
||||
message="`onTouch` lambda should call `View#performClick` when a click is detected"
|
||||
errorLine1=" binding.imageView.setOnTouchListener { _, event ->"
|
||||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/java/app/pachli/adapter/TabAdapter.kt"
|
||||
line="92"
|
||||
column="50"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="ContentDescription"
|
||||
message="Missing `contentDescription` attribute on image"
|
||||
|
@ -122,7 +122,6 @@
|
||||
<activity
|
||||
android:name=".components.account.AccountActivity"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden|screenLayout|smallestScreenSize" />
|
||||
<activity android:name=".components.notifications.NotificationsActivity" />
|
||||
<activity android:name=".EditProfileActivity" />
|
||||
<activity android:name=".components.preference.PreferencesActivity" />
|
||||
<activity android:name=".TimelineActivity" />
|
||||
|
@ -94,11 +94,11 @@ import app.pachli.core.navigation.ListActivityIntent
|
||||
import app.pachli.core.navigation.LoginActivityIntent
|
||||
import app.pachli.core.navigation.LoginActivityIntent.LoginMode
|
||||
import app.pachli.core.navigation.MainActivityIntent
|
||||
import app.pachli.core.navigation.NotificationsActivityIntent
|
||||
import app.pachli.core.navigation.PreferencesActivityIntent
|
||||
import app.pachli.core.navigation.PreferencesActivityIntent.PreferenceScreen
|
||||
import app.pachli.core.navigation.ScheduledStatusActivityIntent
|
||||
import app.pachli.core.navigation.SearchActivityIntent
|
||||
import app.pachli.core.navigation.TabPreferenceActivityIntent
|
||||
import app.pachli.core.navigation.TimelineActivityIntent
|
||||
import app.pachli.core.navigation.TrendingActivityIntent
|
||||
import app.pachli.core.network.model.Account
|
||||
@ -115,6 +115,7 @@ import app.pachli.updatecheck.UpdateCheck
|
||||
import app.pachli.usecase.DeveloperToolsUseCase
|
||||
import app.pachli.usecase.LogoutUsecase
|
||||
import app.pachli.util.getDimension
|
||||
import app.pachli.util.makeIcon
|
||||
import app.pachli.util.updateShortcut
|
||||
import at.connyduck.calladapter.networkresult.fold
|
||||
import com.bumptech.glide.Glide
|
||||
@ -131,10 +132,8 @@ import com.google.android.material.snackbar.Snackbar
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
import com.google.android.material.tabs.TabLayout.OnTabSelectedListener
|
||||
import com.google.android.material.tabs.TabLayoutMediator
|
||||
import com.mikepenz.iconics.IconicsDrawable
|
||||
import com.mikepenz.iconics.IconicsSize
|
||||
import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
|
||||
import com.mikepenz.iconics.utils.colorInt
|
||||
import com.mikepenz.iconics.utils.sizeDp
|
||||
import com.mikepenz.materialdrawer.holder.BadgeStyle
|
||||
import com.mikepenz.materialdrawer.holder.ColorHolder
|
||||
import com.mikepenz.materialdrawer.holder.StringHolder
|
||||
@ -163,7 +162,9 @@ import com.mikepenz.materialdrawer.widget.AccountHeaderView
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import de.c1710.filemojicompat_ui.helpers.EMOJI_PREFERENCE
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.max
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
||||
@ -407,18 +408,18 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvider {
|
||||
|
||||
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
|
||||
super.onCreateMenu(menu, menuInflater)
|
||||
|
||||
menuInflater.inflate(R.menu.activity_main, menu)
|
||||
menu.findItem(R.id.action_search)?.apply {
|
||||
icon = IconicsDrawable(this@MainActivity, GoogleMaterial.Icon.gmd_search).apply {
|
||||
sizeDp = 20
|
||||
colorInt = MaterialColors.getColor(binding.mainToolbar, android.R.attr.textColorPrimary)
|
||||
}
|
||||
icon = makeIcon(this@MainActivity, GoogleMaterial.Icon.gmd_search, IconicsSize.dp(20))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPrepareMenu(menu: Menu) {
|
||||
super<BottomSheetActivity>.onPrepareMenu(menu)
|
||||
|
||||
menu.findItem(R.id.action_remove_tab).isVisible = tabAdapter.tabs[binding.viewPager.currentItem].timeline != Timeline.Home
|
||||
|
||||
// If the main toolbar is hidden then there's no space in the top/bottomNav to show
|
||||
// the menu items as icons, so forceably disable them
|
||||
if (!binding.mainToolbar.isVisible) menu.forEach { it.setShowAsAction(SHOW_AS_ACTION_NEVER) }
|
||||
@ -431,6 +432,21 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvider {
|
||||
startActivity(SearchActivityIntent(this@MainActivity))
|
||||
true
|
||||
}
|
||||
R.id.action_remove_tab -> {
|
||||
val timeline = tabAdapter.tabs[binding.viewPager.currentItem].timeline
|
||||
accountManager.activeAccount?.let {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
it.tabPreferences = it.tabPreferences.filterNot { it == timeline }
|
||||
accountManager.saveAccount(it)
|
||||
eventHub.dispatch(MainTabsChangedEvent(it.tabPreferences))
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
R.id.action_tab_preferences -> {
|
||||
startActivity(TabPreferenceActivityIntent(this))
|
||||
true
|
||||
}
|
||||
else -> super.onOptionsItemSelected(menuItem)
|
||||
}
|
||||
}
|
||||
@ -620,7 +636,7 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvider {
|
||||
iconicsIcon = GoogleMaterial.Icon.gmd_notifications
|
||||
onClick = {
|
||||
startActivityWithSlideInAnimation(
|
||||
NotificationsActivityIntent(context),
|
||||
TimelineActivityIntent.notifications(context),
|
||||
)
|
||||
}
|
||||
},
|
||||
@ -876,7 +892,8 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvider {
|
||||
}
|
||||
|
||||
// Save the previous tab so it can be restored later
|
||||
val previousTab = tabAdapter.tabs.getOrNull(binding.viewPager.currentItem)
|
||||
val previousTabIndex = binding.viewPager.currentItem
|
||||
val previousTab = tabAdapter.tabs.getOrNull(previousTabIndex)
|
||||
|
||||
val tabs = accountManager.activeAccount!!.tabPreferences.map { TabViewData.from(it) }
|
||||
|
||||
@ -896,6 +913,8 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvider {
|
||||
// - Notification tab (if appropriate)
|
||||
// - The previously selected tab (if it hasn't been removed)
|
||||
// - Tabs containing lists are compared by list ID, in case the list was renamed
|
||||
// - The tab to the left of the previous selected tab (if the previously selected tab
|
||||
// was removed)
|
||||
// - Left-most tab
|
||||
val position = if (selectNotificationTab) {
|
||||
tabs.indexOfFirst { it.timeline is Timeline.Notifications }
|
||||
@ -909,7 +928,7 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvider {
|
||||
}
|
||||
}
|
||||
}
|
||||
}.takeIf { it != -1 } ?: 0
|
||||
}.takeIf { it != -1 } ?: max(previousTabIndex - 1, 0)
|
||||
binding.viewPager.setCurrentItem(position, false)
|
||||
|
||||
val pageMargin = resources.getDimensionPixelSize(DR.dimen.tab_page_margin)
|
||||
|
@ -112,7 +112,7 @@ class TabPreferenceActivity : BaseActivity(), ItemInteractionListener {
|
||||
}
|
||||
|
||||
currentTabs = accountManager.activeAccount?.tabPreferences.orEmpty().map { TabViewData.from(it) }.toMutableList()
|
||||
currentTabsAdapter = TabAdapter(currentTabs, false, this, currentTabs.size <= MIN_TAB_COUNT)
|
||||
currentTabsAdapter = TabAdapter(currentTabs, false, this)
|
||||
binding.currentTabsRecyclerView.adapter = currentTabsAdapter
|
||||
binding.currentTabsRecyclerView.layoutManager = LinearLayoutManager(this)
|
||||
binding.currentTabsRecyclerView.addItemDecoration(
|
||||
@ -129,12 +129,9 @@ class TabPreferenceActivity : BaseActivity(), ItemInteractionListener {
|
||||
return makeMovementFlags(ItemTouchHelper.UP or ItemTouchHelper.DOWN, ItemTouchHelper.END)
|
||||
}
|
||||
|
||||
override fun isLongPressDragEnabled(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun isItemViewSwipeEnabled(): Boolean {
|
||||
return MIN_TAB_COUNT < currentTabs.size
|
||||
// Swiping enabled in TabAdapter.onBindViewHolder if the timeline is not Timeline.Home
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
|
||||
@ -394,8 +391,6 @@ class TabPreferenceActivity : BaseActivity(), ItemInteractionListener {
|
||||
addableTabs.add(TabViewData.from(Timeline.UserList("", "")))
|
||||
|
||||
addTabAdapter.updateData(addableTabs)
|
||||
|
||||
currentTabsAdapter.setRemoveButtonVisible(currentTabs.size > MIN_TAB_COUNT)
|
||||
}
|
||||
|
||||
override fun onStartDelete(viewHolder: RecyclerView.ViewHolder) {
|
||||
@ -424,8 +419,4 @@ class TabPreferenceActivity : BaseActivity(), ItemInteractionListener {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val MIN_TAB_COUNT = 2
|
||||
}
|
||||
}
|
||||
|
@ -102,7 +102,6 @@ data class TabViewData(
|
||||
ComposeActivityIntent.ComposeOptions(visibility = Status.Visibility.PRIVATE),
|
||||
)
|
||||
}
|
||||
|
||||
Timeline.TrendingHashtags -> TabViewData(
|
||||
timeline = timeline,
|
||||
text = R.string.title_public_trending_hashtags,
|
||||
@ -113,13 +112,13 @@ data class TabViewData(
|
||||
Timeline.TrendingLinks -> TabViewData(
|
||||
timeline = timeline,
|
||||
text = R.string.title_public_trending_links,
|
||||
icon = R.drawable.ic_trending_up_24px,
|
||||
icon = R.drawable.ic_newspaper_24,
|
||||
fragment = { TrendingLinksFragment.newInstance() },
|
||||
)
|
||||
Timeline.TrendingStatuses -> TabViewData(
|
||||
timeline = timeline,
|
||||
text = R.string.title_public_trending_statuses,
|
||||
icon = R.drawable.ic_trending_up_24px,
|
||||
icon = R.drawable.ic_whatshot_24,
|
||||
fragment = { TimelineFragment.newInstance(timeline) },
|
||||
)
|
||||
is Timeline.Hashtags -> TabViewData(
|
||||
|
@ -19,11 +19,15 @@ package app.pachli
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.widget.Toast
|
||||
import androidx.core.view.MenuProvider
|
||||
import androidx.fragment.app.commit
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import app.pachli.appstore.EventHub
|
||||
import app.pachli.appstore.FilterChangedEvent
|
||||
import app.pachli.appstore.MainTabsChangedEvent
|
||||
import app.pachli.core.activity.BottomSheetActivity
|
||||
import app.pachli.core.common.extensions.viewBinding
|
||||
import app.pachli.core.common.util.unsafeLazy
|
||||
@ -46,6 +50,7 @@ import com.google.android.material.snackbar.Snackbar
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import io.github.z4kn4fein.semver.constraints.toConstraint
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import retrofit2.HttpException
|
||||
import timber.log.Timber
|
||||
@ -54,7 +59,7 @@ import timber.log.Timber
|
||||
* Show a single timeline.
|
||||
*/
|
||||
@AndroidEntryPoint
|
||||
class TimelineActivity : BottomSheetActivity(), AppBarLayoutHost, ActionButtonActivity {
|
||||
class TimelineActivity : BottomSheetActivity(), AppBarLayoutHost, ActionButtonActivity, MenuProvider {
|
||||
@Inject
|
||||
lateinit var eventHub: EventHub
|
||||
|
||||
@ -89,15 +94,15 @@ class TimelineActivity : BottomSheetActivity(), AppBarLayoutHost, ActionButtonAc
|
||||
setContentView(binding.root)
|
||||
|
||||
setSupportActionBar(binding.includedToolbar.toolbar)
|
||||
addMenuProvider(this)
|
||||
|
||||
timeline = TimelineActivityIntent.getTimeline(intent)
|
||||
hashtag = (timeline as? Timeline.Hashtags)?.tags?.firstOrNull()
|
||||
|
||||
val viewData = TabViewData.from(timeline)
|
||||
|
||||
val title = viewData.title(this)
|
||||
|
||||
supportActionBar?.run {
|
||||
setTitle(title)
|
||||
title = viewData.title(this@TimelineActivity)
|
||||
setDisplayHomeAsUpEnabled(true)
|
||||
setDisplayShowHomeEnabled(true)
|
||||
}
|
||||
@ -116,9 +121,10 @@ class TimelineActivity : BottomSheetActivity(), AppBarLayoutHost, ActionButtonAc
|
||||
} ?: binding.composeButton.hide()
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
val tag = hashtag
|
||||
if (timeline is Timeline.Hashtags && tag != null) {
|
||||
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
|
||||
menuInflater.inflate(R.menu.activity_timeline, menu)
|
||||
|
||||
hashtag?.let { tag ->
|
||||
lifecycleScope.launch {
|
||||
mastodonApi.tag(tag).fold(
|
||||
{ tagEntity ->
|
||||
@ -129,10 +135,6 @@ class TimelineActivity : BottomSheetActivity(), AppBarLayoutHost, ActionButtonAc
|
||||
unmuteTagItem = menu.findItem(R.id.action_unmute_hashtag)
|
||||
followTagItem?.isVisible = tagEntity.following == false
|
||||
unfollowTagItem?.isVisible = tagEntity.following == true
|
||||
followTagItem?.setOnMenuItemClickListener { followTag() }
|
||||
unfollowTagItem?.setOnMenuItemClickListener { unfollowTag() }
|
||||
muteTagItem?.setOnMenuItemClickListener { muteTag() }
|
||||
unmuteTagItem?.setOnMenuItemClickListener { unmuteTag() }
|
||||
updateMuteTagMenuItems()
|
||||
},
|
||||
{
|
||||
@ -142,7 +144,52 @@ class TimelineActivity : BottomSheetActivity(), AppBarLayoutHost, ActionButtonAc
|
||||
}
|
||||
}
|
||||
|
||||
return super.onCreateOptionsMenu(menu)
|
||||
return super.onCreateMenu(menu, menuInflater)
|
||||
}
|
||||
|
||||
override fun onPrepareMenu(menu: Menu) {
|
||||
// Check if this timeline is in a tab; if not, enable the add_to_tab menu item
|
||||
val currentTabs = accountManager.activeAccount?.tabPreferences.orEmpty()
|
||||
val hideMenu = currentTabs.contains(timeline)
|
||||
menu.findItem(R.id.action_add_to_tab)?.setVisible(!hideMenu)
|
||||
}
|
||||
|
||||
override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
|
||||
return when (menuItem.itemId) {
|
||||
R.id.action_add_to_tab -> {
|
||||
addToTab()
|
||||
Toast.makeText(this, getString(R.string.action_add_to_tab_success, supportActionBar?.title), Toast.LENGTH_LONG).show()
|
||||
menuItem.setVisible(false)
|
||||
true
|
||||
}
|
||||
R.id.action_follow_hashtag -> {
|
||||
followTag()
|
||||
true
|
||||
}
|
||||
R.id.action_unfollow_hashtag -> {
|
||||
unfollowTag()
|
||||
true
|
||||
}
|
||||
R.id.action_mute_hashtag -> {
|
||||
muteTag()
|
||||
true
|
||||
}
|
||||
R.id.action_unmute_hashtag -> {
|
||||
unmuteTag()
|
||||
true
|
||||
}
|
||||
else -> super.onMenuItemSelected(menuItem)
|
||||
}
|
||||
}
|
||||
|
||||
private fun addToTab() {
|
||||
accountManager.activeAccount?.let {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
it.tabPreferences += timeline
|
||||
accountManager.saveAccount(it)
|
||||
eventHub.dispatch(MainTabsChangedEvent(it.tabPreferences))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun followTag(): Boolean {
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
package app.pachli.adapter
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MotionEvent
|
||||
import android.view.ViewGroup
|
||||
@ -26,12 +27,10 @@ import app.pachli.R
|
||||
import app.pachli.TabViewData
|
||||
import app.pachli.core.common.extensions.hide
|
||||
import app.pachli.core.common.extensions.show
|
||||
import app.pachli.core.designsystem.R as DR
|
||||
import app.pachli.core.model.Timeline
|
||||
import app.pachli.core.ui.BindingHolder
|
||||
import app.pachli.databinding.ItemTabPreferenceBinding
|
||||
import app.pachli.databinding.ItemTabPreferenceSmallBinding
|
||||
import app.pachli.util.setDrawableTint
|
||||
import com.google.android.material.chip.Chip
|
||||
|
||||
interface ItemInteractionListener {
|
||||
@ -47,7 +46,6 @@ class TabAdapter(
|
||||
private var data: List<TabViewData>,
|
||||
private val small: Boolean,
|
||||
private val listener: ItemInteractionListener,
|
||||
private var removeButtonEnabled: Boolean = false,
|
||||
) : RecyclerView.Adapter<BindingHolder<ViewBinding>>() {
|
||||
|
||||
fun updateData(newData: List<TabViewData>) {
|
||||
@ -64,30 +62,26 @@ class TabAdapter(
|
||||
return BindingHolder(binding)
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
override fun onBindViewHolder(holder: BindingHolder<ViewBinding>, position: Int) {
|
||||
val context = holder.itemView.context
|
||||
val tab = data[position]
|
||||
val tabViewData = data[position]
|
||||
|
||||
if (small) {
|
||||
val binding = holder.binding as ItemTabPreferenceSmallBinding
|
||||
|
||||
binding.textView.setText(tab.text)
|
||||
binding.textView.setText(tabViewData.text)
|
||||
|
||||
binding.textView.setCompoundDrawablesRelativeWithIntrinsicBounds(tab.icon, 0, 0, 0)
|
||||
binding.textView.setCompoundDrawablesRelativeWithIntrinsicBounds(tabViewData.icon, 0, 0, 0)
|
||||
|
||||
binding.textView.setOnClickListener {
|
||||
listener.onTabAdded(tab)
|
||||
listener.onTabAdded(tabViewData)
|
||||
}
|
||||
} else {
|
||||
val binding = holder.binding as ItemTabPreferenceBinding
|
||||
|
||||
if (tab.timeline is Timeline.UserList) {
|
||||
binding.textView.text = tab.timeline.title
|
||||
} else {
|
||||
binding.textView.setText(tab.text)
|
||||
}
|
||||
|
||||
binding.textView.setCompoundDrawablesRelativeWithIntrinsicBounds(tab.icon, 0, 0, 0)
|
||||
binding.textView.text = tabViewData.title(context)
|
||||
binding.textView.setCompoundDrawablesRelativeWithIntrinsicBounds(tabViewData.icon, 0, 0, 0)
|
||||
|
||||
binding.imageView.setOnTouchListener { _, event ->
|
||||
if (event.action == MotionEvent.ACTION_DOWN) {
|
||||
@ -97,17 +91,27 @@ class TabAdapter(
|
||||
false
|
||||
}
|
||||
}
|
||||
if (tabViewData.timeline !is Timeline.Home) {
|
||||
binding.removeButton.setOnClickListener {
|
||||
listener.onTabRemoved(holder.bindingAdapterPosition)
|
||||
}
|
||||
binding.removeButton.isEnabled = removeButtonEnabled
|
||||
setDrawableTint(
|
||||
holder.itemView.context,
|
||||
binding.removeButton.drawable,
|
||||
(if (removeButtonEnabled) android.R.attr.textColorTertiary else DR.attr.textColorDisabled),
|
||||
)
|
||||
|
||||
if (tab.timeline is Timeline.Hashtags) {
|
||||
binding.removeButton.show()
|
||||
binding.textView.setOnTouchListener { _, event ->
|
||||
if (event.action == MotionEvent.ACTION_DOWN) {
|
||||
listener.onStartDelete(holder)
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
} else {
|
||||
binding.removeButton.hide()
|
||||
}
|
||||
|
||||
if (tabViewData.timeline is Timeline.Hashtags) {
|
||||
// Hashtags are shown as chips, set the text back to generic "Hashtags"
|
||||
binding.textView.setText(tabViewData.text)
|
||||
binding.chipGroup.show()
|
||||
|
||||
/*
|
||||
@ -115,7 +119,7 @@ class TabAdapter(
|
||||
* The other dynamic chips are inserted in front of the actionChip.
|
||||
* This code tries to reuse already added chips to reduce the number of Views created.
|
||||
*/
|
||||
tab.timeline.tags.forEachIndexed { i, arg ->
|
||||
tabViewData.timeline.tags.forEachIndexed { i, arg ->
|
||||
|
||||
val chip = binding.chipGroup.getChildAt(i).takeUnless { it.id == R.id.actionChip } as Chip?
|
||||
?: Chip(context).apply {
|
||||
@ -126,23 +130,23 @@ class TabAdapter(
|
||||
|
||||
chip.text = arg
|
||||
|
||||
if (tab.timeline.tags.size <= 1) {
|
||||
if (tabViewData.timeline.tags.size <= 1) {
|
||||
chip.isCloseIconVisible = false
|
||||
chip.setOnClickListener(null)
|
||||
} else {
|
||||
chip.isCloseIconVisible = true
|
||||
chip.setOnClickListener {
|
||||
listener.onChipClicked(tab.timeline, holder.bindingAdapterPosition, i)
|
||||
listener.onChipClicked(tabViewData.timeline, holder.bindingAdapterPosition, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (binding.chipGroup.size - 1 > tab.timeline.tags.size) {
|
||||
binding.chipGroup.removeViewAt(tab.timeline.tags.size)
|
||||
while (binding.chipGroup.size - 1 > tabViewData.timeline.tags.size) {
|
||||
binding.chipGroup.removeViewAt(tabViewData.timeline.tags.size)
|
||||
}
|
||||
|
||||
binding.actionChip.setOnClickListener {
|
||||
listener.onActionChipClicked(tab.timeline, holder.bindingAdapterPosition)
|
||||
listener.onActionChipClicked(tabViewData.timeline, holder.bindingAdapterPosition)
|
||||
}
|
||||
} else {
|
||||
binding.chipGroup.hide()
|
||||
@ -151,11 +155,4 @@ class TabAdapter(
|
||||
}
|
||||
|
||||
override fun getItemCount() = data.size
|
||||
|
||||
fun setRemoveButtonVisible(enabled: Boolean) {
|
||||
if (removeButtonEnabled != enabled) {
|
||||
removeButtonEnabled = enabled
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 Pachli Association
|
||||
*
|
||||
* This file is a part of Pachli.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* Pachli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with Pachli; if not,
|
||||
* see <http://www.gnu.org/licenses>.
|
||||
*/
|
||||
|
||||
package app.pachli.components.notifications
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import androidx.core.view.MenuProvider
|
||||
import androidx.fragment.app.commit
|
||||
import app.pachli.R
|
||||
import app.pachli.core.activity.BottomSheetActivity
|
||||
import app.pachli.core.common.extensions.viewBinding
|
||||
import app.pachli.core.common.util.unsafeLazy
|
||||
import app.pachli.core.navigation.ComposeActivityIntent
|
||||
import app.pachli.databinding.ActivityNotificationsBinding
|
||||
import app.pachli.interfaces.ActionButtonActivity
|
||||
import app.pachli.interfaces.AppBarLayoutHost
|
||||
import com.google.android.material.appbar.AppBarLayout
|
||||
|
||||
class NotificationsActivity : BottomSheetActivity(), ActionButtonActivity, AppBarLayoutHost, MenuProvider {
|
||||
private val binding by viewBinding(ActivityNotificationsBinding::inflate)
|
||||
|
||||
override val actionButton by unsafeLazy { binding.composeButton }
|
||||
|
||||
override val appBarLayout: AppBarLayout
|
||||
get() = binding.includedToolbar.appbar
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(binding.root)
|
||||
|
||||
setSupportActionBar(binding.includedToolbar.toolbar)
|
||||
|
||||
supportActionBar?.run {
|
||||
setTitle(R.string.title_notifications)
|
||||
setDisplayHomeAsUpEnabled(true)
|
||||
setDisplayShowHomeEnabled(true)
|
||||
}
|
||||
|
||||
if (supportFragmentManager.findFragmentById(R.id.fragmentContainer) == null) {
|
||||
supportFragmentManager.commit {
|
||||
val fragment = NotificationsFragment.newInstance()
|
||||
replace(R.id.fragmentContainer, fragment)
|
||||
}
|
||||
}
|
||||
|
||||
binding.composeButton.setOnClickListener {
|
||||
val composeIntent = ComposeActivityIntent(applicationContext)
|
||||
startActivity(composeIntent)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
|
||||
super.onCreateMenu(menu, menuInflater)
|
||||
menuInflater.inflate(R.menu.activity_notifications, menu)
|
||||
}
|
||||
|
||||
override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
|
||||
super.onMenuItemSelected(menuItem)
|
||||
return super.onOptionsItemSelected(menuItem)
|
||||
}
|
||||
}
|
@ -66,15 +66,14 @@ import app.pachli.interfaces.StatusActionListener
|
||||
import app.pachli.util.ListStatusAccessibilityDelegate
|
||||
import app.pachli.util.UserRefreshState
|
||||
import app.pachli.util.asRefreshState
|
||||
import app.pachli.util.makeIcon
|
||||
import app.pachli.viewdata.NotificationViewData
|
||||
import at.connyduck.sparkbutton.helpers.Utils
|
||||
import com.google.android.material.color.MaterialColors
|
||||
import com.google.android.material.divider.MaterialDividerItemDecoration
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.mikepenz.iconics.IconicsDrawable
|
||||
import com.mikepenz.iconics.IconicsSize
|
||||
import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
|
||||
import com.mikepenz.iconics.utils.colorInt
|
||||
import com.mikepenz.iconics.utils.sizeDp
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.collect
|
||||
@ -448,18 +447,11 @@ class NotificationsFragment :
|
||||
|
||||
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
|
||||
menuInflater.inflate(R.menu.fragment_notifications, menu)
|
||||
val iconColor = MaterialColors.getColor(binding.root, android.R.attr.textColorPrimary)
|
||||
menu.findItem(R.id.action_refresh)?.apply {
|
||||
icon = IconicsDrawable(requireContext(), GoogleMaterial.Icon.gmd_refresh).apply {
|
||||
sizeDp = 20
|
||||
colorInt = iconColor
|
||||
}
|
||||
icon = makeIcon(requireContext(), GoogleMaterial.Icon.gmd_refresh, IconicsSize.dp(20))
|
||||
}
|
||||
menu.findItem(R.id.action_edit_notification_filter)?.apply {
|
||||
icon = IconicsDrawable(requireContext(), GoogleMaterial.Icon.gmd_tune).apply {
|
||||
sizeDp = 20
|
||||
colorInt = iconColor
|
||||
}
|
||||
icon = makeIcon(requireContext(), GoogleMaterial.Icon.gmd_tune, IconicsSize.dp(20))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,7 +101,7 @@ class AccountPreferencesFragment : PreferenceFragmentCompat() {
|
||||
|
||||
preference {
|
||||
setTitle(R.string.title_tab_preferences)
|
||||
setIcon(R.drawable.ic_tabs)
|
||||
setIcon(R.drawable.ic_add_to_tab_24)
|
||||
setOnPreferenceClickListener {
|
||||
val intent = TabPreferenceActivityIntent(context)
|
||||
activity?.startActivity(intent)
|
||||
@ -191,9 +191,11 @@ class AccountPreferencesFragment : PreferenceFragmentCompat() {
|
||||
val server = serverRepository.flow.value.getOrElse { null }
|
||||
isEnabled = server?.let {
|
||||
it.can(
|
||||
ORG_JOINMASTODON_FILTERS_CLIENT, ">1.0.0".toConstraint(),
|
||||
ORG_JOINMASTODON_FILTERS_CLIENT,
|
||||
">1.0.0".toConstraint(),
|
||||
) || it.can(
|
||||
ORG_JOINMASTODON_FILTERS_SERVER, ">1.0.0".toConstraint(),
|
||||
ORG_JOINMASTODON_FILTERS_SERVER,
|
||||
">1.0.0".toConstraint(),
|
||||
)
|
||||
} ?: false
|
||||
if (!isEnabled) summary = context.getString(R.string.pref_summary_timeline_filters)
|
||||
|
@ -21,33 +21,44 @@ import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.widget.Toast
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.core.view.MenuProvider
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import app.pachli.R
|
||||
import app.pachli.components.timeline.TimelineFragment
|
||||
import app.pachli.TabViewData
|
||||
import app.pachli.appstore.EventHub
|
||||
import app.pachli.appstore.MainTabsChangedEvent
|
||||
import app.pachli.core.activity.BottomSheetActivity
|
||||
import app.pachli.core.common.extensions.viewBinding
|
||||
import app.pachli.core.model.Timeline
|
||||
import app.pachli.core.ui.extensions.reduceSwipeSensitivity
|
||||
import app.pachli.databinding.ActivityTrendingBinding
|
||||
import app.pachli.interfaces.AppBarLayoutHost
|
||||
import app.pachli.pager.MainPagerAdapter
|
||||
import com.google.android.material.appbar.AppBarLayout
|
||||
import com.google.android.material.tabs.TabLayoutMediator
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@AndroidEntryPoint
|
||||
class TrendingActivity : BottomSheetActivity(), AppBarLayoutHost, MenuProvider {
|
||||
@Inject
|
||||
lateinit var eventHub: EventHub
|
||||
|
||||
private val binding: ActivityTrendingBinding by viewBinding(ActivityTrendingBinding::inflate)
|
||||
|
||||
override val appBarLayout: AppBarLayout
|
||||
get() = binding.appBar
|
||||
|
||||
private lateinit var adapter: MainPagerAdapter
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(binding.root)
|
||||
addMenuProvider(this)
|
||||
|
||||
setSupportActionBar(binding.toolbar)
|
||||
|
||||
@ -57,12 +68,26 @@ class TrendingActivity : BottomSheetActivity(), AppBarLayoutHost, MenuProvider {
|
||||
setDisplayShowHomeEnabled(true)
|
||||
}
|
||||
|
||||
val adapter = TrendingFragmentAdapter(this)
|
||||
adapter = MainPagerAdapter(
|
||||
listOf(
|
||||
TabViewData.from(Timeline.TrendingHashtags),
|
||||
TabViewData.from(Timeline.TrendingLinks),
|
||||
TabViewData.from(Timeline.TrendingStatuses),
|
||||
),
|
||||
this,
|
||||
)
|
||||
|
||||
binding.pager.adapter = adapter
|
||||
binding.pager.reduceSwipeSensitivity()
|
||||
|
||||
TabLayoutMediator(binding.tabLayout, binding.pager) { tab, position ->
|
||||
tab.text = adapter.title(position)
|
||||
// Use a shorter tab label, as "Trending" is already in the toolbar
|
||||
tab.text = when (position) {
|
||||
0 -> getString(R.string.title_tab_public_trending_hashtags)
|
||||
1 -> getString(R.string.title_tab_public_trending_links)
|
||||
2 -> getString(R.string.title_tab_public_trending_statuses)
|
||||
else -> throw IllegalStateException()
|
||||
}
|
||||
}.attach()
|
||||
|
||||
onBackPressedDispatcher.addCallback(
|
||||
@ -80,30 +105,29 @@ class TrendingActivity : BottomSheetActivity(), AppBarLayoutHost, MenuProvider {
|
||||
menuInflater.inflate(R.menu.activity_trending, menu)
|
||||
}
|
||||
|
||||
override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
|
||||
super.onMenuItemSelected(menuItem)
|
||||
return super.onOptionsItemSelected(menuItem)
|
||||
}
|
||||
}
|
||||
|
||||
class TrendingFragmentAdapter(val activity: FragmentActivity) : FragmentStateAdapter(activity) {
|
||||
override fun getItemCount() = 3
|
||||
|
||||
override fun createFragment(position: Int): Fragment {
|
||||
return when (position) {
|
||||
0 -> TrendingTagsFragment.newInstance()
|
||||
1 -> TrendingLinksFragment.newInstance()
|
||||
2 -> TimelineFragment.newInstance(Timeline.TrendingStatuses)
|
||||
else -> throw IllegalStateException()
|
||||
}
|
||||
}
|
||||
|
||||
fun title(position: Int): CharSequence {
|
||||
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()
|
||||
}
|
||||
override fun onPrepareMenu(menu: Menu) {
|
||||
val timeline = adapter.tabs[binding.pager.currentItem].timeline
|
||||
// Check if this timeline is in a tab; if not, enable the add_to_tab menu item
|
||||
val currentTabs = accountManager.activeAccount?.tabPreferences.orEmpty()
|
||||
val hideMenu = currentTabs.contains(timeline)
|
||||
menu.findItem(R.id.action_add_to_tab)?.setVisible(!hideMenu)
|
||||
}
|
||||
|
||||
override fun onMenuItemSelected(menuItem: MenuItem) = when (menuItem.itemId) {
|
||||
R.id.action_add_to_tab -> {
|
||||
val tabViewData = adapter.tabs[binding.pager.currentItem]
|
||||
val timeline = tabViewData.timeline
|
||||
accountManager.activeAccount?.let {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
it.tabPreferences += timeline
|
||||
accountManager.saveAccount(it)
|
||||
eventHub.dispatch(MainTabsChangedEvent(it.tabPreferences))
|
||||
}
|
||||
}
|
||||
Toast.makeText(this, getString(R.string.action_add_to_tab_success, tabViewData.title(this)), Toast.LENGTH_LONG).show()
|
||||
menuItem.setVisible(false)
|
||||
true
|
||||
}
|
||||
else -> super.onMenuItemSelected(menuItem)
|
||||
}
|
||||
}
|
||||
|
22
app/src/main/res/drawable/ic_add_to_tab_24.xml
Normal file
22
app/src/main/res/drawable/ic_add_to_tab_24.xml
Normal file
@ -0,0 +1,22 @@
|
||||
<!--
|
||||
~ Copyright 2024 Pachli Association
|
||||
~
|
||||
~ This file is a part of Pachli.
|
||||
~
|
||||
~ This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
~ GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
~ License, or (at your option) any later version.
|
||||
~
|
||||
~ Pachli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
~ the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
~ Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License along with Pachli; if not,
|
||||
~ see <http://www.gnu.org/licenses>.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="?attr/colorControlNormal" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M21,3L3,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM21,19L3,19L3,5h10v4h8v10z"/>
|
||||
|
||||
</vector>
|
@ -2,7 +2,8 @@
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="?android:attr/textColorPrimary"
|
||||
android:pathData="M11,18c0,1.1 -0.9,2 -2,2s-2,-0.9 -2,-2 0.9,-2 2,-2 2,0.9 2,2zM9,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM9,4c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM15,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM15,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM15,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z" />
|
||||
|
5
app/src/main/res/drawable/ic_newspaper_24.xml
Normal file
5
app/src/main/res/drawable/ic_newspaper_24.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M22,3l-1.67,1.67L18.67,3L17,4.67L15.33,3l-1.66,1.67L12,3l-1.67,1.67L8.67,3L7,4.67L5.33,3L3.67,4.67L2,3v16c0,1.1 0.9,2 2,2l16,0c1.1,0 2,-0.9 2,-2V3zM11,19H4v-6h7V19zM20,19h-7v-2h7V19zM20,15h-7v-2h7V15zM20,11H4V8h16V11z"/>
|
||||
|
||||
</vector>
|
@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path android:fillColor="#000" android:pathData="M22,14A2,2 0 0,1 20,16H4A2,2 0 0,1 2,14V10A2,2 0 0,1 4,8H20A2,2 0 0,1 22,10V14M4,14H8V10H4V14M10,14H14V10H10V14M16,14H20V10H16V14Z" />
|
||||
</vector>
|
5
app/src/main/res/drawable/ic_whatshot_24.xml
Normal file
5
app/src/main/res/drawable/ic_whatshot_24.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M13.5,0.67s0.74,2.65 0.74,4.8c0,2.06 -1.35,3.73 -3.41,3.73 -2.07,0 -3.63,-1.67 -3.63,-3.73l0.03,-0.36C5.21,7.51 4,10.62 4,14c0,4.42 3.58,8 8,8s8,-3.58 8,-8C20,8.61 17.41,3.8 13.5,0.67zM11.71,19c-1.78,0 -3.22,-1.4 -3.22,-3.14 0,-1.62 1.05,-2.76 2.81,-3.12 1.77,-0.36 3.6,-1.21 4.62,-2.58 0.39,1.29 0.59,2.65 0.59,4.04 0,2.65 -2.15,4.8 -4.8,4.8z"/>
|
||||
|
||||
</vector>
|
@ -1,48 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright 2024 Pachli Association
|
||||
~
|
||||
~ This file is a part of Pachli.
|
||||
~
|
||||
~ This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
~ GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
~ License, or (at your option) any later version.
|
||||
~
|
||||
~ Pachli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
~ the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
~ Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License along with Pachli; if not,
|
||||
~ see <http://www.gnu.org/licenses>.
|
||||
-->
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context="app.pachli.components.notifications.NotificationsActivity">
|
||||
|
||||
<include
|
||||
android:id="@+id/includedToolbar"
|
||||
layout="@layout/toolbar_basic" />
|
||||
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/fragmentContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/composeButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/fabMargin"
|
||||
android:contentDescription="@string/action_compose"
|
||||
app:layout_anchor="@id/fragmentContainer"
|
||||
app:layout_anchorGravity="bottom|end"
|
||||
app:srcCompat="@drawable/ic_create_24dp" />
|
||||
|
||||
<include layout="@layout/item_status_bottom_sheet" />
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
@ -19,6 +19,7 @@
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:src="@drawable/ic_drag_indicator_24dp"
|
||||
app:tint="?attr/colorControlNormal"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="@id/textView"/>
|
||||
@ -33,7 +34,7 @@
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:textAppearance="?android:attr/textAppearanceListItemSmall"
|
||||
app:drawableTint="?android:attr/textColorSecondary"
|
||||
app:drawableTint="?android:attr/colorControlNormal"
|
||||
app:layout_constraintBottom_toTopOf="@id/chipGroup"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/imageView"
|
||||
@ -53,7 +54,8 @@
|
||||
android:contentDescription="@string/action_delete"
|
||||
android:src="@drawable/ic_clear_24dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:tint="?attr/colorControlNormal" />
|
||||
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/chipGroup"
|
||||
|
@ -22,4 +22,14 @@
|
||||
android:id="@+id/action_search"
|
||||
android:title="@string/action_search"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_remove_tab"
|
||||
android:title="@string/action_remove_tab"
|
||||
app:showAsAction="never" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_tab_preferences"
|
||||
android:title="@string/action_manage_tabs"
|
||||
app:showAsAction="never" />
|
||||
</menu>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright 2024 Pachli Association
|
||||
~ Copyright 2023 Pachli Association
|
||||
~
|
||||
~ This file is a part of Pachli.
|
||||
~
|
||||
@ -18,4 +18,9 @@
|
||||
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/action_add_to_tab"
|
||||
android:title="@string/action_add_to_tab"
|
||||
android:icon="@drawable/ic_add_to_tab_24"
|
||||
app:showAsAction="ifRoom"/>
|
||||
</menu>
|
@ -18,4 +18,9 @@
|
||||
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/action_add_to_tab"
|
||||
android:title="@string/action_add_to_tab"
|
||||
android:icon="@drawable/ic_add_to_tab_24"
|
||||
app:showAsAction="ifRoom"/>
|
||||
</menu>
|
||||
|
@ -7,28 +7,28 @@
|
||||
android:id="@+id/action_follow_hashtag"
|
||||
android:title="@string/action_follow"
|
||||
app:showAsAction="ifRoom"
|
||||
app:iconTint="?attr/colorOnSurface"
|
||||
app:iconTint="?attr/colorControlNormal"
|
||||
android:icon="@drawable/ic_person_add_24dp" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_unfollow_hashtag"
|
||||
android:title="@string/action_unfollow"
|
||||
app:showAsAction="ifRoom"
|
||||
app:iconTint="?attr/colorOnSurface"
|
||||
app:iconTint="?attr/colorControlNormal"
|
||||
android:icon="@drawable/ic_person_remove_24dp" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_mute_hashtag"
|
||||
android:title="@string/action_mute"
|
||||
app:showAsAction="ifRoom"
|
||||
app:iconTint="?attr/colorOnSurface"
|
||||
app:iconTint="?attr/colorControlNormal"
|
||||
android:icon="@drawable/ic_mute_24dp" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_unmute_hashtag"
|
||||
android:title="@string/action_unmute"
|
||||
app:showAsAction="ifRoom"
|
||||
app:iconTint="?attr/colorOnSurface"
|
||||
app:iconTint="?attr/colorControlNormal"
|
||||
android:icon="@drawable/ic_unmute_24dp" />
|
||||
|
||||
</menu>
|
||||
|
@ -701,5 +701,9 @@
|
||||
<string name="pref_update_check_no_updates">There are no updates available</string>
|
||||
<string name="pref_update_next_scheduled_check">Next scheduled check: %1$s</string>
|
||||
<string name="error_media_download">Could not download %1$s: %2$d %3$s</string>
|
||||
<string name="action_add_to_tab">Add to tab</string>
|
||||
<string name="action_add_to_tab_success">Added \'%1$s\' to tabs</string>
|
||||
<string name="action_remove_tab">Remove tab</string>
|
||||
<string name="action_manage_tabs">Manage tabs</string>
|
||||
|
||||
</resources>
|
||||
|
@ -466,6 +466,15 @@ class TimelineActivityIntent private constructor(context: Context) : Intent() {
|
||||
putExtra(EXTRA_TIMELINE, Timeline.PublicLocal)
|
||||
}
|
||||
|
||||
/**
|
||||
* Show notifications timeline
|
||||
*
|
||||
* @param context
|
||||
*/
|
||||
fun notifications(context: Context) = TimelineActivityIntent(context).apply {
|
||||
putExtra(EXTRA_TIMELINE, Timeline.Notifications)
|
||||
}
|
||||
|
||||
/** @return The [Timeline] to show */
|
||||
fun getTimeline(intent: Intent) = IntentCompat.getParcelableExtra(intent, EXTRA_TIMELINE, Timeline::class.java)!!
|
||||
}
|
||||
@ -593,12 +602,6 @@ class LoginWebViewActivityIntent(context: Context) : Intent() {
|
||||
}
|
||||
}
|
||||
|
||||
class NotificationsActivityIntent(context: Context) : Intent() {
|
||||
init {
|
||||
setClassName(context, QuadrantConstants.NOTIFICATIONS_ACTIVITY)
|
||||
}
|
||||
}
|
||||
|
||||
class ScheduledStatusActivityIntent(context: Context) : Intent() {
|
||||
init {
|
||||
setClassName(context, QuadrantConstants.SCHEDULED_STATUS_ACTIVITY)
|
||||
|
Loading…
x
Reference in New Issue
Block a user