Skip to content

Commit

Permalink
Add share action to swipe menus (#1190)
Browse files Browse the repository at this point in the history
Co-authored-by: Philip Simpson <[email protected]>
  • Loading branch information
mchowning and geekygecko authored Jul 24, 2023
1 parent 1afc448 commit a89c30f
Show file tree
Hide file tree
Showing 37 changed files with 1,440 additions and 582 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@
-----
* New Feature:
* Added 3 episodes on the Filter AutoDownload
([#1169])(https://github.com/Automattic/pocket-casts-android/pull/1169)
([#1169](https://github.com/Automattic/pocket-casts-android/pull/1169))
* Added capability to deselect all/below and above on the multiselect feature
([#1172](https://github.com/Automattic/pocket-casts-android/pull/1172))
* Added share option to episode swipe and multiselect menus
([#1190](https://github.com/Automattic/pocket-casts-android/pull/1190)),
([#1191](https://github.com/Automattic/pocket-casts-android/pull/1191))

7.43
-----
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ import au.com.shiftyjelly.pocketcasts.views.fragments.BaseFragment
import au.com.shiftyjelly.pocketcasts.views.fragments.BaseFragmentToolbar.ChromeCastButton.Shown
import au.com.shiftyjelly.pocketcasts.views.helper.EpisodeItemTouchHelper
import au.com.shiftyjelly.pocketcasts.views.helper.NavigationIcon.BackArrow
import au.com.shiftyjelly.pocketcasts.views.helper.SwipeButtonLayoutFactory
import au.com.shiftyjelly.pocketcasts.views.helper.SwipeButtonLayoutViewModel
import au.com.shiftyjelly.pocketcasts.views.helper.ToolbarColors
import au.com.shiftyjelly.pocketcasts.views.multiselect.MultiSelectEpisodesHelper
import au.com.shiftyjelly.pocketcasts.views.multiselect.MultiSelectHelper
Expand Down Expand Up @@ -80,6 +82,7 @@ class FilterEpisodeListFragment : BaseFragment() {
}

private val viewModel by viewModels<FilterEpisodeListViewModel>()
private val swipeButtonLayoutViewModel: SwipeButtonLayoutViewModel by viewModels()

@Inject lateinit var downloadManager: DownloadManager
@Inject lateinit var playbackManager: PlaybackManager
Expand All @@ -92,7 +95,28 @@ class FilterEpisodeListFragment : BaseFragment() {

private lateinit var imageLoader: PodcastImageLoader

private lateinit var adapter: EpisodeListAdapter
private val adapter: EpisodeListAdapter by lazy {
EpisodeListAdapter(
downloadManager = downloadManager,
playbackManager = playbackManager,
upNextQueue = upNextQueue,
settings = settings,
onRowClick = this::onRowClick,
playButtonListener = playButtonListener,
imageLoader = imageLoader,
multiSelectHelper = multiSelectHelper,
fragmentManager = childFragmentManager,
swipeButtonLayoutFactory = SwipeButtonLayoutFactory(
swipeButtonLayoutViewModel = swipeButtonLayoutViewModel,
onItemUpdated = this::lazyNotifyAdapterChanged,
defaultUpNextSwipeAction = { settings.getUpNextSwipeAction() },
context = requireContext(),
fragmentManager = parentFragmentManager,
swipeSource = EpisodeItemTouchHelper.SwipeSource.FILTERS,
)
)
}

private var showingFilterOptionsBeforeMultiSelect: Boolean = false
private var multiSelectLoaded: Boolean = false
private var listSavedState: Parcelable? = null
Expand All @@ -114,7 +138,15 @@ class FilterEpisodeListFragment : BaseFragment() {
}.smallPlaceholder()

playButtonListener.source = SourceView.FILTERS
adapter = EpisodeListAdapter(downloadManager, playbackManager, upNextQueue, settings, this::onRowClick, playButtonListener, imageLoader, multiSelectHelper, childFragmentManager)
}

// Cannot call notify.notifyItemChanged directly because the compiler gets confused
// when the adapter's constructor includes references to the adapter
private fun lazyNotifyAdapterChanged(
@Suppress("UNUSED_PARAMETER") episode: BaseEpisode,
index: Int,
) {
adapter.notifyItemChanged(index)
}

override fun onSaveInstanceState(outState: Bundle) {
Expand Down Expand Up @@ -383,7 +415,7 @@ class FilterEpisodeListFragment : BaseFragment() {
binding.btnChevron.setOnClickListener(clickListener)
toolbar.setOnClickListener(clickListener)

val itemTouchHelper = EpisodeItemTouchHelper(this::episodeSwipedRightItem1, this::episodeSwipedRightItem2, viewModel::episodeSwiped)
val itemTouchHelper = EpisodeItemTouchHelper()
itemTouchHelper.attachToRecyclerView(recyclerView)

val multiSelectToolbar = binding.multiSelectToolbar
Expand Down Expand Up @@ -563,22 +595,6 @@ class FilterEpisodeListFragment : BaseFragment() {
.show(childFragmentManager, "confirm")
}

private fun episodeSwipedRightItem1(episode: BaseEpisode, index: Int) {
when (settings.getUpNextSwipeAction()) {
Settings.UpNextAction.PLAY_NEXT -> viewModel.episodeSwipeUpNext(episode)
Settings.UpNextAction.PLAY_LAST -> viewModel.episodeSwipeUpLast(episode)
}
adapter.notifyItemChanged(index)
}

private fun episodeSwipedRightItem2(episode: BaseEpisode, index: Int) {
when (settings.getUpNextSwipeAction()) {
Settings.UpNextAction.PLAY_NEXT -> viewModel.episodeSwipeUpLast(episode)
Settings.UpNextAction.PLAY_LAST -> viewModel.episodeSwipeUpNext(episode)
}
adapter.notifyItemChanged(index)
}

private fun downloadAll() {
val episodeCount = (viewModel.episodesList.value ?: emptyList()).count()
if (episodeCount < 5) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,8 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.toLiveData
import au.com.shiftyjelly.pocketcasts.analytics.AnalyticsEvent
import au.com.shiftyjelly.pocketcasts.analytics.AnalyticsTrackerWrapper
import au.com.shiftyjelly.pocketcasts.analytics.EpisodeAnalytics
import au.com.shiftyjelly.pocketcasts.analytics.FirebaseAnalyticsTracker
import au.com.shiftyjelly.pocketcasts.analytics.SourceView
import au.com.shiftyjelly.pocketcasts.models.entity.BaseEpisode
import au.com.shiftyjelly.pocketcasts.models.entity.Playlist
import au.com.shiftyjelly.pocketcasts.models.entity.PodcastEpisode
import au.com.shiftyjelly.pocketcasts.preferences.Settings
Expand All @@ -20,8 +18,6 @@ import au.com.shiftyjelly.pocketcasts.repositories.podcast.PlaylistManager
import au.com.shiftyjelly.pocketcasts.repositories.podcast.PlaylistProperty
import au.com.shiftyjelly.pocketcasts.repositories.podcast.PlaylistUpdateSource
import au.com.shiftyjelly.pocketcasts.repositories.podcast.UserPlaylistUpdate
import au.com.shiftyjelly.pocketcasts.views.helper.EpisodeItemTouchHelper.SwipeAction
import au.com.shiftyjelly.pocketcasts.views.helper.EpisodeItemTouchHelper.SwipeSource
import dagger.hilt.android.lifecycle.HiltViewModel
import io.reactivex.BackpressureStrategy
import io.reactivex.Flowable
Expand All @@ -40,18 +36,15 @@ import kotlin.math.min

@HiltViewModel
class FilterEpisodeListViewModel @Inject constructor(
val playlistManager: PlaylistManager,
val episodeManager: EpisodeManager,
val playbackManager: PlaybackManager,
val downloadManager: DownloadManager,
val settings: Settings,
private val playlistManager: PlaylistManager,
private val episodeManager: EpisodeManager,
private val playbackManager: PlaybackManager,
private val downloadManager: DownloadManager,
private val settings: Settings,
private val analyticsTracker: AnalyticsTrackerWrapper,
private val episodeAnalytics: EpisodeAnalytics,
) : ViewModel(), CoroutineScope {

companion object {
private const val ACTION_KEY = "action"
private const val SOURCE_KEY = "source"
const val MAX_DOWNLOAD_ALL = Settings.MAX_DOWNLOAD
}

Expand Down Expand Up @@ -102,23 +95,6 @@ class FilterEpisodeListViewModel @Inject constructor(
}
}

@Suppress("UNUSED_PARAMETER")
fun episodeSwiped(episode: BaseEpisode, index: Int) {
if (episode !is PodcastEpisode) return

launch {
if (!episode.isArchived) {
episodeManager.archive(episode, playbackManager)
trackSwipeAction(SwipeAction.ARCHIVE)
episodeAnalytics.trackEvent(AnalyticsEvent.EPISODE_ARCHIVED, SourceView.FILTERS, episode.uuid)
} else {
episodeManager.unarchive(episode)
trackSwipeAction(SwipeAction.UNARCHIVE)
episodeAnalytics.trackEvent(AnalyticsEvent.EPISODE_UNARCHIVED, SourceView.FILTERS, episode.uuid)
}
}
}

fun onPlayAllFromHere(episode: PodcastEpisode) {
launch {
val episodes = episodesList.value ?: emptyList()
Expand Down Expand Up @@ -159,30 +135,6 @@ class FilterEpisodeListViewModel @Inject constructor(
}
}

fun episodeSwipeUpNext(episode: BaseEpisode) {
launch {
if (playbackManager.upNextQueue.contains(episode.uuid)) {
playbackManager.removeEpisode(episodeToRemove = episode, source = SourceView.FILTERS)
trackSwipeAction(SwipeAction.UP_NEXT_REMOVE)
} else {
playbackManager.playNext(episode = episode, source = SourceView.FILTERS)
trackSwipeAction(SwipeAction.UP_NEXT_ADD_TOP)
}
}
}

fun episodeSwipeUpLast(episode: BaseEpisode) {
launch {
if (playbackManager.upNextQueue.contains(episode.uuid)) {
playbackManager.removeEpisode(episodeToRemove = episode, source = SourceView.FILTERS)
trackSwipeAction(SwipeAction.UP_NEXT_REMOVE)
} else {
playbackManager.playLast(episode = episode, source = SourceView.FILTERS)
trackSwipeAction(SwipeAction.UP_NEXT_ADD_BOTTOM)
}
}
}

fun downloadAll() {
val episodes = (episodesList.value ?: emptyList())
val trimmedList = episodes.subList(0, min(MAX_DOWNLOAD_ALL, episodes.count()))
Expand All @@ -199,16 +151,6 @@ class FilterEpisodeListViewModel @Inject constructor(
return min(episodes.count() - index, settings.getMaxUpNextEpisodes())
}

private fun trackSwipeAction(swipeAction: SwipeAction) {
analyticsTracker.track(
AnalyticsEvent.EPISODE_SWIPE_ACTION_PERFORMED,
mapOf(
ACTION_KEY to swipeAction.analyticsValue,
SOURCE_KEY to SwipeSource.FILTERS.analyticsValue
)
)
}

fun onFragmentPause(isChangingConfigurations: Boolean?) {
isFragmentChangingConfigurations = isChangingConfigurations ?: false
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import au.com.shiftyjelly.pocketcasts.repositories.podcast.EpisodeManager
import au.com.shiftyjelly.pocketcasts.ui.theme.Theme
import au.com.shiftyjelly.pocketcasts.ui.theme.ThemeColor
import au.com.shiftyjelly.pocketcasts.utils.extensions.dpToPx
import au.com.shiftyjelly.pocketcasts.views.helper.SwipeButtonLayoutFactory
import au.com.shiftyjelly.pocketcasts.views.multiselect.MultiSelectEpisodesHelper
import timber.log.Timber
import au.com.shiftyjelly.pocketcasts.localization.R as LR
Expand All @@ -44,7 +45,8 @@ class UpNextAdapter(
val fragmentManager: FragmentManager,
private val analyticsTracker: AnalyticsTrackerWrapper,
private val upNextSource: UpNextSource,
private val settings: Settings
private val settings: Settings,
private val swipeButtonLayoutFactory: SwipeButtonLayoutFactory,
) : ListAdapter<Any, RecyclerView.ViewHolder>(UPNEXT_ADAPTER_DIFF) {
private val dateFormatter = RelativeDateFormatter(context)

Expand All @@ -63,7 +65,14 @@ class UpNextAdapter(
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val inflater = LayoutInflater.from(parent.context)
return when (viewType) {
R.layout.adapter_up_next -> UpNextEpisodeViewHolder(DataBindingUtil.inflate(inflater, R.layout.adapter_up_next, parent, false), listener, dateFormatter, imageLoader, episodeManager)
R.layout.adapter_up_next -> UpNextEpisodeViewHolder(
binding = DataBindingUtil.inflate(inflater, R.layout.adapter_up_next, parent, false),
listener = listener,
dateFormatter = dateFormatter,
imageLoader = imageLoader,
episodeManager = episodeManager,
swipeButtonLayoutFactory = swipeButtonLayoutFactory,
)
R.layout.adapter_up_next_footer -> HeaderViewHolder(DataBindingUtil.inflate(inflater, R.layout.adapter_up_next_footer, parent, false))
R.layout.adapter_up_next_playing -> PlayingViewHolder(DataBindingUtil.inflate(inflater, R.layout.adapter_up_next_playing, parent, false))
else -> throw IllegalStateException("Unknown view type in up next")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ import au.com.shiftyjelly.pocketcasts.utils.extensions.dpToPx
import au.com.shiftyjelly.pocketcasts.views.extensions.setRippleBackground
import au.com.shiftyjelly.pocketcasts.views.helper.EpisodeItemTouchHelper
import au.com.shiftyjelly.pocketcasts.views.helper.RowSwipeable
import au.com.shiftyjelly.pocketcasts.views.helper.SwipeButtonLayout
import au.com.shiftyjelly.pocketcasts.views.helper.SwipeButtonLayoutFactory
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.rxkotlin.subscribeBy
Expand All @@ -45,13 +47,16 @@ class UpNextEpisodeViewHolder(
val listener: UpNextListener?,
val dateFormatter: RelativeDateFormatter,
val imageLoader: PodcastImageLoader,
val episodeManager: EpisodeManager
val episodeManager: EpisodeManager,
private val swipeButtonLayoutFactory: SwipeButtonLayoutFactory,
) : RecyclerView.ViewHolder(binding.root),
UpNextTouchCallback.ItemTouchHelperViewHolder,
RowSwipeable {
private val elevatedBackground = ContextCompat.getColor(binding.root.context, R.color.elevatedBackground)
private val selectedBackground = ContextCompat.getColor(binding.root.context, R.color.selectedBackground)

override lateinit var swipeButtonLayout: SwipeButtonLayout

var disposable: Disposable? = null
set(value) {
field?.dispose()
Expand Down Expand Up @@ -95,6 +100,9 @@ class UpNextEpisodeViewHolder(
binding.executePendingBindings()
}
.subscribeBy(onError = { Timber.e(it) })

swipeButtonLayout = swipeButtonLayoutFactory.forEpisode(episode)

binding.episode = episode
binding.date.text = episode.getSummaryText(dateFormatter = dateFormatter, tintColor = tintColor, showDuration = false, context = binding.date.context)
binding.executePendingBindings()
Expand Down Expand Up @@ -138,14 +146,16 @@ class UpNextEpisodeViewHolder(
get() = binding.itemContainer
override val episode: BaseEpisode?
get() = binding.episode
override val swipeLeftIcon: ImageView
get() = binding.archiveIcon
override val positionAdapter: Int
get() = bindingAdapterPosition
override val leftRightIcon1: ImageView
get() = binding.leftRightIcon1
override val leftRightIcon2: ImageView
get() = binding.leftRightIcon2
override val rightLeftIcon1: ImageView
get() = binding.rightLeftIcon1
override val rightLeftIcon2: ImageView
get() = binding.rightLeftIcon2
override val isMultiSelecting: Boolean
get() = binding.checkbox.isVisible
override val rightToLeftSwipeLayout: ViewGroup
Expand All @@ -159,6 +169,6 @@ class UpNextEpisodeViewHolder(
EpisodeItemTouchHelper.IconWithBackground(R.drawable.ic_upnext_movetotop, binding.itemContainer.context.getThemeColor(UR.attr.support_04)),
EpisodeItemTouchHelper.IconWithBackground(R.drawable.ic_upnext_movetobottom, binding.itemContainer.context.getThemeColor(UR.attr.support_03))
)
override val rightIconDrawableRes: List<EpisodeItemTouchHelper.IconWithBackground>
override val rightIconDrawablesRes: List<EpisodeItemTouchHelper.IconWithBackground>
get() = listOf(EpisodeItemTouchHelper.IconWithBackground(R.drawable.ic_upnext_remove, binding.itemContainer.context.getThemeColor(UR.attr.support_05)))
}
Loading

0 comments on commit a89c30f

Please sign in to comment.