From fcf244a9d50c4f67bcbfb7006151a90062dff71c Mon Sep 17 00:00:00 2001 From: Eduarda Barbosa Date: Fri, 31 Jan 2025 12:08:09 -0300 Subject: [PATCH] wip --- .../podcasts/view/podcast/PodcastFragment.kt | 59 ++++++++++ .../podcasts/view/podcast/PodcastTooltip.kt | 110 ++++++++++++++++++ .../src/main/res/layout/fragment_podcast.xml | 13 +++ .../src/main/res/values/strings.xml | 2 + 4 files changed, 184 insertions(+) create mode 100644 modules/features/podcasts/src/main/java/au/com/shiftyjelly/pocketcasts/podcasts/view/podcast/PodcastTooltip.kt 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 64cb668b774..bced675e262 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 @@ -8,8 +8,14 @@ import android.view.View import android.view.ViewGroup import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.Toolbar +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.IntOffset import androidx.core.os.BundleCompat import androidx.core.os.bundleOf +import androidx.core.view.doOnNextLayout import androidx.core.view.isGone import androidx.core.view.isVisible import androidx.core.view.updatePadding @@ -23,6 +29,7 @@ import androidx.recyclerview.widget.SimpleItemAnimator import au.com.shiftyjelly.pocketcasts.analytics.AnalyticsEvent import au.com.shiftyjelly.pocketcasts.analytics.AnalyticsTracker import au.com.shiftyjelly.pocketcasts.analytics.SourceView +import au.com.shiftyjelly.pocketcasts.compose.AppTheme import au.com.shiftyjelly.pocketcasts.localization.extensions.getStringPlural import au.com.shiftyjelly.pocketcasts.models.entity.BaseEpisode import au.com.shiftyjelly.pocketcasts.models.entity.Bookmark @@ -90,6 +97,7 @@ import dagger.hilt.android.AndroidEntryPoint import javax.inject.Inject import kotlin.time.Duration.Companion.seconds import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.rx2.asObservable import kotlinx.coroutines.withContext @@ -168,6 +176,9 @@ class PodcastFragment : BaseFragment(), Toolbar.OnMenuItemClickListener { private var listState: Parcelable? = null + private var tooltipOffset by mutableStateOf(IntOffset.Zero) + private var showTooltip by mutableStateOf(false) + private var currentSnackBar: Snackbar? = null private val onScrollListener = object : RecyclerView.OnScrollListener() { @@ -735,6 +746,22 @@ class PodcastFragment : BaseFragment(), Toolbar.OnMenuItemClickListener { super.onViewCreated(view, savedInstanceState) binding?.setupMultiSelect() + binding?.composeTooltipHost?.setContent { + AppTheme(theme.activeTheme) { + if (showTooltip) { + Tooltip( + title = stringResource(LR.string.podcast_feed_update_tooltip_title), + subtitle = stringResource(LR.string.podcast_feed_update_tooltip_subtitle), + offset = tooltipOffset, + onDismissRequest = { + showTooltip = false + binding?.dimScrimView?.visibility = View.GONE + }, + ) + } + } + } + viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { viewModel.multiSelectBookmarksHelper.navigationState @@ -746,6 +773,38 @@ class PodcastFragment : BaseFragment(), Toolbar.OnMenuItemClickListener { } } } + + binding?.episodesRecyclerView?.doOnNextLayout { + showTooltipOnEpisodeOptions() + } + } + + private fun showTooltipOnEpisodeOptions() { + lifecycleScope.launch { + delay(500) + val positionOfHeader = 2 + val viewHolder = binding?.episodesRecyclerView?.findViewHolderForAdapterPosition(positionOfHeader) + as? PodcastAdapter.EpisodeHeaderViewHolder + + val anchorView = viewHolder?.binding?.btnEpisodeOptions + anchorView?.let { showTooltipAbove(it) } + } + } + + fun showTooltipAbove(view: View) { + val anchorLocation = IntArray(2) + view.getLocationOnScreen(anchorLocation) + + val composeLocation = IntArray(2) + requireView().findViewById(R.id.composeTooltipHost) + .getLocationOnScreen(composeLocation) + + val anchorX = anchorLocation[0] - composeLocation[0] + (view.width / 2) + val anchorY = anchorLocation[1] - composeLocation[1] - 200 + + tooltipOffset = IntOffset(anchorX, anchorY) + showTooltip = true + binding?.dimScrimView?.visibility = View.VISIBLE } private fun onShareBookmarkClick() { diff --git a/modules/features/podcasts/src/main/java/au/com/shiftyjelly/pocketcasts/podcasts/view/podcast/PodcastTooltip.kt b/modules/features/podcasts/src/main/java/au/com/shiftyjelly/pocketcasts/podcasts/view/podcast/PodcastTooltip.kt new file mode 100644 index 00000000000..cca1c389385 --- /dev/null +++ b/modules/features/podcasts/src/main/java/au/com/shiftyjelly/pocketcasts/podcasts/view/podcast/PodcastTooltip.kt @@ -0,0 +1,110 @@ +package au.com.shiftyjelly.pocketcasts.podcasts.view.podcast + +import androidx.compose.foundation.Canvas +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Card +import androidx.compose.material.Icon +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Close +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Path +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.IntOffset +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.compose.ui.window.Popup +import au.com.shiftyjelly.pocketcasts.compose.components.TextH40 +import au.com.shiftyjelly.pocketcasts.compose.theme +import au.com.shiftyjelly.pocketcasts.localization.R as LR + +@Composable +fun Tooltip( + title: String, + subtitle: String, + offset: IntOffset, + onDismissRequest: () -> Unit, +) { + val tooltipColor = MaterialTheme.theme.colors.primaryUi01 + + Popup( + alignment = Alignment.TopStart, + offset = offset, + onDismissRequest = onDismissRequest, + ) { + Box( + modifier = Modifier + .wrapContentSize() + .padding(horizontal = 16.dp), + ) { + Card( + backgroundColor = tooltipColor, + elevation = 8.dp, + shape = RoundedCornerShape(8.dp), + ) { + Row( + modifier = Modifier + .padding(8.dp), + verticalAlignment = Alignment.Top, + ) { + Column( + modifier = Modifier.weight(1f), + ) { + TextH40( + text = title, + modifier = Modifier.padding(bottom = 4.dp), + ) + + Text( + text = subtitle, + fontSize = 12.sp, + ) + } + + Spacer(modifier = Modifier.width(12.dp)) + + Icon( + imageVector = Icons.Default.Close, + contentDescription = stringResource(LR.string.close), + tint = MaterialTheme.theme.colors.primaryIcon02, + modifier = Modifier + .align(Alignment.Top) + .width(24.dp) + .clickable { + onDismissRequest.invoke() + }, + ) + } + } + + Canvas( + modifier = Modifier + .align(Alignment.BottomEnd) + .padding(end = 32.dp), + ) { + val triangleSize = 12.dp.toPx() + + drawPath( + path = Path().apply { + moveTo(0f, -2f) + lineTo(triangleSize, 0f) + lineTo(triangleSize / 2f, triangleSize) + close() + }, + color = tooltipColor, + ) + } + } + } +} diff --git a/modules/features/podcasts/src/main/res/layout/fragment_podcast.xml b/modules/features/podcasts/src/main/res/layout/fragment_podcast.xml index dd1dcaa0c74..8a6a36b1385 100644 --- a/modules/features/podcasts/src/main/res/layout/fragment_podcast.xml +++ b/modules/features/podcasts/src/main/res/layout/fragment_podcast.xml @@ -105,6 +105,19 @@ android:scaleType="centerCrop" tools:src="@tools:sample/avatars" /> + + + + diff --git a/modules/services/localization/src/main/res/values/strings.xml b/modules/services/localization/src/main/res/values/strings.xml index b2ebd307c2e..6958ecba5a7 100644 --- a/modules/services/localization/src/main/res/values/strings.xml +++ b/modules/services/localization/src/main/res/values/strings.xml @@ -566,6 +566,8 @@ @string/unplayed Hide archived There was an error loading the podcast. + Take control of your updates! + You can now refresh the episode list from this menu or by pulling down the screen. Loading your podcasts Next episode any day now Next episode today