diff --git a/modules/features/player/src/main/java/au/com/shiftyjelly/pocketcasts/player/view/bookmark/BookmarkFragment.kt b/modules/features/player/src/main/java/au/com/shiftyjelly/pocketcasts/player/view/bookmark/BookmarkFragment.kt index fb507e1cd1d..adafe29e248 100644 --- a/modules/features/player/src/main/java/au/com/shiftyjelly/pocketcasts/player/view/bookmark/BookmarkFragment.kt +++ b/modules/features/player/src/main/java/au/com/shiftyjelly/pocketcasts/player/view/bookmark/BookmarkFragment.kt @@ -13,6 +13,7 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels import androidx.fragment.compose.content import au.com.shiftyjelly.pocketcasts.compose.AppThemeWithBackground +import au.com.shiftyjelly.pocketcasts.compose.CallOnce import au.com.shiftyjelly.pocketcasts.models.entity.Bookmark import au.com.shiftyjelly.pocketcasts.ui.theme.Theme import dagger.hilt.android.AndroidEntryPoint @@ -30,6 +31,11 @@ class BookmarkFragment : Fragment() { LaunchedEffect(Unit) { viewModel.load(BookmarkArguments.createFromArguments(arguments)) } AppThemeWithBackground(Theme.ThemeType.DARK) { val uiState: BookmarkViewModel.UiState by viewModel.uiState.collectAsState() + + CallOnce { + viewModel.onShown() + } + BookmarkPage( isNewBookmark = uiState.isNewBookmark, title = uiState.title, @@ -44,6 +50,7 @@ class BookmarkFragment : Fragment() { } private fun saveBookmark() { + viewModel.onSubmitBookmark() viewModel.saveBookmark(onSaved = { bookmark, isExisting -> bookmarkSaved(bookmark, isExisting) }) @@ -63,6 +70,7 @@ class BookmarkFragment : Fragment() { } private fun close() { + viewModel.onClose() requireActivity().run { setResult(Activity.RESULT_CANCELED) finish() diff --git a/modules/features/player/src/main/java/au/com/shiftyjelly/pocketcasts/player/view/bookmark/BookmarkViewModel.kt b/modules/features/player/src/main/java/au/com/shiftyjelly/pocketcasts/player/view/bookmark/BookmarkViewModel.kt index 6aa2ce217ce..3e10e7cd088 100644 --- a/modules/features/player/src/main/java/au/com/shiftyjelly/pocketcasts/player/view/bookmark/BookmarkViewModel.kt +++ b/modules/features/player/src/main/java/au/com/shiftyjelly/pocketcasts/player/view/bookmark/BookmarkViewModel.kt @@ -5,6 +5,8 @@ import androidx.compose.ui.text.TextRange import androidx.compose.ui.text.input.TextFieldValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import au.com.shiftyjelly.pocketcasts.analytics.AnalyticsEvent +import au.com.shiftyjelly.pocketcasts.analytics.AnalyticsTracker import au.com.shiftyjelly.pocketcasts.models.entity.Bookmark import au.com.shiftyjelly.pocketcasts.repositories.bookmark.BookmarkManager import au.com.shiftyjelly.pocketcasts.repositories.podcast.EpisodeManager @@ -25,6 +27,7 @@ class BookmarkViewModel private val episodeManager: EpisodeManager, private val userEpisodeManager: UserEpisodeManager, private val bookmarkManager: BookmarkManager, + private val analyticsTracker: AnalyticsTracker, ) : ViewModel(), CoroutineScope { private lateinit var arguments: BookmarkArguments @@ -114,4 +117,16 @@ class BookmarkViewModel } } } + + fun onShown() { + analyticsTracker.track(AnalyticsEvent.BOOKMARK_EDIT_FORM_SHOWN) + } + + fun onClose() { + analyticsTracker.track(AnalyticsEvent.BOOKMARK_EDIT_FORM_DISMISSED) + } + + fun onSubmitBookmark() { + analyticsTracker.track(AnalyticsEvent.BOOKMARK_EDIT_FORM_SUBMITTED) + } } diff --git a/modules/features/player/src/main/java/au/com/shiftyjelly/pocketcasts/player/view/bookmark/BookmarksFragment.kt b/modules/features/player/src/main/java/au/com/shiftyjelly/pocketcasts/player/view/bookmark/BookmarksFragment.kt index 24ae9f5184b..88840233c96 100644 --- a/modules/features/player/src/main/java/au/com/shiftyjelly/pocketcasts/player/view/bookmark/BookmarksFragment.kt +++ b/modules/features/player/src/main/java/au/com/shiftyjelly/pocketcasts/player/view/bookmark/BookmarksFragment.kt @@ -8,7 +8,6 @@ import androidx.compose.material.Surface import androidx.compose.runtime.Composable import androidx.compose.runtime.State import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -146,6 +145,12 @@ class BookmarksFragment : BaseFragment() { addFragment(fragment) } }, + onClearSearchTapped = { + bookmarksViewModel.clearSearchTapped() + }, + onSearchBarClearButtonTapped = { + bookmarksViewModel.searchBarClearButtonTapped() + }, bottomInset = if (sourceView == SourceView.PROFILE) { 0.dp + bottomInset.value.pxToDp(LocalContext.current).dp } else { @@ -212,6 +217,7 @@ class BookmarksFragment : BaseFragment() { private fun onShareBookmarkClick() { lifecycleScope.launch { val (podcast, episode, bookmark) = bookmarksViewModel.getSharedBookmark() ?: return@launch + bookmarksViewModel.onShare(podcast.uuid, episode.uuid, sourceView) val timestamp = bookmark.timeSecs.seconds if (FeatureFlag.isEnabled(Feature.REIMAGINE_SHARING)) { ShareEpisodeTimestampFragment diff --git a/modules/features/player/src/main/java/au/com/shiftyjelly/pocketcasts/player/view/bookmark/BookmarksPage.kt b/modules/features/player/src/main/java/au/com/shiftyjelly/pocketcasts/player/view/bookmark/BookmarksPage.kt index 48f9c9046ba..c69dbe6d397 100644 --- a/modules/features/player/src/main/java/au/com/shiftyjelly/pocketcasts/player/view/bookmark/BookmarksPage.kt +++ b/modules/features/player/src/main/java/au/com/shiftyjelly/pocketcasts/player/view/bookmark/BookmarksPage.kt @@ -67,6 +67,8 @@ fun BookmarksPage( onUpgradeClicked: () -> Unit, showOptionsDialog: (Int) -> Unit, openFragment: (Fragment) -> Unit, + onClearSearchTapped: () -> Unit, + onSearchBarClearButtonTapped: () -> Unit, bottomInset: Dp, ) { val context = LocalContext.current @@ -86,6 +88,8 @@ fun BookmarksPage( onUpgradeClicked = onUpgradeClicked, openFragment = openFragment, bottomInset = bottomInset, + onClearSearchTapped = onClearSearchTapped, + onSearchBarClearButtonTapped = onSearchBarClearButtonTapped, ) LaunchedEffect(episodeUuid) { bookmarksViewModel.loadBookmarks( @@ -132,6 +136,8 @@ private fun Content( onSearchTextChanged: (String) -> Unit, onUpgradeClicked: () -> Unit, openFragment: (Fragment) -> Unit, + onClearSearchTapped: () -> Unit, + onSearchBarClearButtonTapped: () -> Unit, bottomInset: Dp, ) { Box( @@ -149,6 +155,8 @@ private fun Content( onPlayClick = onPlayClick, onSearchTextChanged = onSearchTextChanged, bottomInset = bottomInset, + onClearSearchTapped = onClearSearchTapped, + onSearchBarClearButtonTapped = onSearchBarClearButtonTapped, ) is UiState.Empty -> NoBookmarksView( @@ -179,6 +187,8 @@ private fun BookmarksView( onOptionsMenuClicked: () -> Unit, onPlayClick: (Bookmark) -> Unit, onSearchTextChanged: (String) -> Unit, + onClearSearchTapped: () -> Unit, + onSearchBarClearButtonTapped: () -> Unit, bottomInset: Dp, ) { val focusRequester = remember { FocusRequester() } @@ -193,6 +203,7 @@ private fun BookmarksView( text = state.searchText, placeholder = stringResource(LR.string.search), onTextChanged = onSearchTextChanged, + onClearButtonTapped = onSearchBarClearButtonTapped, modifier = Modifier .fillMaxWidth() .padding(horizontal = 16.dp) @@ -205,7 +216,14 @@ private fun BookmarksView( state.searchText.isNotEmpty() && state.bookmarks.isEmpty() ) { - item { NoBookmarksInSearchView(onActionClick = { onSearchTextChanged("") }) } + item { + NoBookmarksInSearchView( + onActionClick = { + onClearSearchTapped() + onSearchTextChanged("") + }, + ) + } } else { item { val title = stringResource( @@ -294,6 +312,8 @@ private fun BookmarksPreview( onSearchTextChanged = {}, onUpgradeClicked = {}, openFragment = {}, + onClearSearchTapped = {}, + onSearchBarClearButtonTapped = {}, bottomInset = 0.dp, ) } diff --git a/modules/features/player/src/main/java/au/com/shiftyjelly/pocketcasts/player/viewmodel/BookmarksViewModel.kt b/modules/features/player/src/main/java/au/com/shiftyjelly/pocketcasts/player/viewmodel/BookmarksViewModel.kt index a8b33983af0..002eb51cc62 100644 --- a/modules/features/player/src/main/java/au/com/shiftyjelly/pocketcasts/player/viewmodel/BookmarksViewModel.kt +++ b/modules/features/player/src/main/java/au/com/shiftyjelly/pocketcasts/player/viewmodel/BookmarksViewModel.kt @@ -352,6 +352,18 @@ class BookmarksViewModel return sortType as UserSetting } + fun clearSearchTapped() { + analyticsTracker.track(AnalyticsEvent.BOOKMARKS_CLEAR_SEARCH_TAPPED) + } + + fun searchBarClearButtonTapped() { + analyticsTracker.track(AnalyticsEvent.BOOKMARKS_SEARCHBAR_CLEAR_BUTTON_TAPPED) + } + + fun onShare(podcastUuid: String, episodeUuid: String, source: SourceView) { + analyticsTracker.track(AnalyticsEvent.BOOKMARK_SHARE_TAPPED, mapOf("podcast_uuid" to podcastUuid, "episode_uuid" to episodeUuid, "source" to source.analyticsValue)) + } + sealed class UiState { data class Empty(val sourceView: SourceView) : UiState() { val colors: NoBookmarksViewColors diff --git a/modules/features/podcasts/src/main/java/au/com/shiftyjelly/pocketcasts/podcasts/view/podcast/PodcastFragment.kt b/modules/features/podcasts/src/main/java/au/com/shiftyjelly/pocketcasts/podcasts/view/podcast/PodcastFragment.kt index 40a64731b54..ffff21df9b7 100644 --- a/modules/features/podcasts/src/main/java/au/com/shiftyjelly/pocketcasts/podcasts/view/podcast/PodcastFragment.kt +++ b/modules/features/podcasts/src/main/java/au/com/shiftyjelly/pocketcasts/podcasts/view/podcast/PodcastFragment.kt @@ -723,6 +723,7 @@ class PodcastFragment : BaseFragment(), Toolbar.OnMenuItemClickListener { private fun onShareBookmarkClick() { lifecycleScope.launch { val (podcast, episode, bookmark) = viewModel.getSharedBookmark() ?: return@launch + viewModel.onBookmarkShare(podcast.uuid, episode.uuid, sourceView) val timestamp = bookmark.timeSecs.seconds if (FeatureFlag.isEnabled(Feature.REIMAGINE_SHARING)) { ShareEpisodeTimestampFragment diff --git a/modules/features/podcasts/src/main/java/au/com/shiftyjelly/pocketcasts/podcasts/viewmodel/PodcastViewModel.kt b/modules/features/podcasts/src/main/java/au/com/shiftyjelly/pocketcasts/podcasts/viewmodel/PodcastViewModel.kt index 69217b2a733..907dcc1d9ec 100644 --- a/modules/features/podcasts/src/main/java/au/com/shiftyjelly/pocketcasts/podcasts/viewmodel/PodcastViewModel.kt +++ b/modules/features/podcasts/src/main/java/au/com/shiftyjelly/pocketcasts/podcasts/viewmodel/PodcastViewModel.kt @@ -566,6 +566,10 @@ class PodcastViewModel } } + fun onBookmarkShare(podcastUuid: String, episodeUuid: String, source: SourceView) { + analyticsTracker.track(AnalyticsEvent.BOOKMARK_SHARE_TAPPED, mapOf("podcast_uuid" to podcastUuid, "episode_uuid" to episodeUuid, "source" to source.analyticsValue)) + } + private fun trackEpisodeBulkEvent(event: AnalyticsEvent, count: Int) { episodeAnalytics.trackBulkEvent( event, diff --git a/modules/services/analytics/src/main/java/au/com/shiftyjelly/pocketcasts/analytics/AnalyticsEvent.kt b/modules/services/analytics/src/main/java/au/com/shiftyjelly/pocketcasts/analytics/AnalyticsEvent.kt index 34271a0147b..a052bd64d10 100644 --- a/modules/services/analytics/src/main/java/au/com/shiftyjelly/pocketcasts/analytics/AnalyticsEvent.kt +++ b/modules/services/analytics/src/main/java/au/com/shiftyjelly/pocketcasts/analytics/AnalyticsEvent.kt @@ -16,6 +16,14 @@ enum class AnalyticsEvent(val key: String) { BOOKMARK_PLAY_TAPPED("bookmark_play_tapped"), BOOKMARKS_SORT_BY_CHANGED("bookmarks_sort_by_changed"), BOOKMARK_DELETED("bookmark_deleted"), + BOOKMARKS_CLEAR_SEARCH_TAPPED("bookmarks_clear_search_tapped"), + BOOKMARK_DELETE_FORM_SHOWN("bookmark_delete_form_shown"), + BOOKMARK_DELETE_FORM_SUBMITTED("bookmark_delete_form_submitted"), + BOOKMARKS_SEARCHBAR_CLEAR_BUTTON_TAPPED("bookmarks_searchbar_clear_button_tapped"), + BOOKMARK_EDIT_FORM_SHOWN("bookmark_edit_form_shown"), + BOOKMARK_EDIT_FORM_DISMISSED("bookmark_edit_form_dismissed"), + BOOKMARK_EDIT_FORM_SUBMITTED("bookmark_edit_form_submitted"), + BOOKMARK_SHARE_TAPPED("bookmark_share_tapped"), PROFILE_BOOKMARKS_SHOWN("profile_bookmarks_shown"), /* User lifecycle events */ diff --git a/modules/services/compose/src/main/java/au/com/shiftyjelly/pocketcasts/compose/components/SearchBar.kt b/modules/services/compose/src/main/java/au/com/shiftyjelly/pocketcasts/compose/components/SearchBar.kt index 0ae4527d32b..7e08e9c35c6 100644 --- a/modules/services/compose/src/main/java/au/com/shiftyjelly/pocketcasts/compose/components/SearchBar.kt +++ b/modules/services/compose/src/main/java/au/com/shiftyjelly/pocketcasts/compose/components/SearchBar.kt @@ -90,6 +90,7 @@ object SearchBarDefaults { fun SearchBar( text: String, onTextChanged: (String) -> Unit, + onClearButtonTapped: () -> Unit = {}, modifier: Modifier = Modifier, leadingIcon: @Composable (() -> Unit)? = null, trailingIcon: @Composable (() -> Unit)? = null, @@ -163,6 +164,7 @@ fun SearchBar( if (text.isNotEmpty()) { IconButton( onClick = { + onClearButtonTapped() onTextChanged("") focusManager.clearFocus() }, diff --git a/modules/services/views/src/main/java/au/com/shiftyjelly/pocketcasts/views/multiselect/MultiSelectBookmarksHelper.kt b/modules/services/views/src/main/java/au/com/shiftyjelly/pocketcasts/views/multiselect/MultiSelectBookmarksHelper.kt index ba5a6861902..4635b214ff4 100644 --- a/modules/services/views/src/main/java/au/com/shiftyjelly/pocketcasts/views/multiselect/MultiSelectBookmarksHelper.kt +++ b/modules/services/views/src/main/java/au/com/shiftyjelly/pocketcasts/views/multiselect/MultiSelectBookmarksHelper.kt @@ -109,6 +109,11 @@ class MultiSelectBookmarksHelper @Inject constructor( return } + analyticsTracker.track( + AnalyticsEvent.BOOKMARK_DELETE_FORM_SHOWN, + mapOf("source" to source.analyticsValue), + ) + val count = bookmarks.size ConfirmationDialog() .setForceDarkTheme(source == SourceView.PLAYER) @@ -133,6 +138,11 @@ class MultiSelectBookmarksHelper @Inject constructor( .setIconTint(UR.attr.support_05) .setOnConfirm { launch { + analyticsTracker.track( + AnalyticsEvent.BOOKMARK_DELETE_FORM_SUBMITTED, + mapOf("source" to source.analyticsValue), + ) + bookmarks.forEach { bookmarkManager.deleteToSync(it.uuid) analyticsTracker.track(