Skip to content

Commit 096ecd0

Browse files
authored
Fix player theming responsivness (Automattic#4091)
1 parent 6926c09 commit 096ecd0

File tree

29 files changed

+759
-854
lines changed

29 files changed

+759
-854
lines changed

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
7.92
22
-----
3-
3+
* Bug Fixes
4+
* Fix player's theming responsivness
5+
([#4091](https://github.com/Automattic/pocket-casts-android/pull/4091))
46

57
7.91
68
-----

app/src/main/java/au/com/shiftyjelly/pocketcasts/ui/MainActivity.kt

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ import au.com.shiftyjelly.pocketcasts.payment.PaymentClient
113113
import au.com.shiftyjelly.pocketcasts.player.view.PlayerBottomSheet
114114
import au.com.shiftyjelly.pocketcasts.player.view.PlayerContainerFragment
115115
import au.com.shiftyjelly.pocketcasts.player.view.UpNextFragment
116+
import au.com.shiftyjelly.pocketcasts.player.view.bookmark.BookmarkActivity
116117
import au.com.shiftyjelly.pocketcasts.player.view.bookmark.BookmarkActivityContract
117118
import au.com.shiftyjelly.pocketcasts.player.view.bookmark.BookmarksContainerFragment
118119
import au.com.shiftyjelly.pocketcasts.player.view.dialog.MiniPlayerDialog
@@ -1339,16 +1340,22 @@ class MainActivity :
13391340
}
13401341

13411342
is AddBookmarkDeepLink -> {
1342-
viewModel.buildBookmarkArguments { args ->
1343-
bookmarkActivityLauncher.launch(args.getIntent(this))
1343+
launch {
1344+
val bookmarkArguments = viewModel.createBookmarkArguments(bookmarkUuid = null)
1345+
if (bookmarkArguments != null) {
1346+
bookmarkActivityLauncher.launch(BookmarkActivity.launchIntent(this@MainActivity, bookmarkArguments))
1347+
}
13441348
}
13451349
}
13461350

13471351
is ChangeBookmarkTitleDeepLink -> {
1348-
viewModel.buildBookmarkArguments(deepLink.bookmarkUuid) { args ->
1349-
bookmarkActivityLauncher.launch(args.getIntent(this))
1352+
launch {
1353+
val bookmarkArguments = viewModel.createBookmarkArguments(deepLink.bookmarkUuid)
1354+
if (bookmarkArguments != null) {
1355+
bookmarkActivityLauncher.launch(BookmarkActivity.launchIntent(this@MainActivity, bookmarkArguments))
1356+
}
1357+
notificationHelper.removeNotification(intent.extras, Settings.NotificationId.BOOKMARK.value)
13501358
}
1351-
notificationHelper.removeNotification(intent.extras, Settings.NotificationId.BOOKMARK.value)
13521359
}
13531360

13541361
is ShowBookmarkDeepLink -> {

app/src/main/java/au/com/shiftyjelly/pocketcasts/ui/MainActivityViewModel.kt

Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import androidx.lifecycle.viewModelScope
77
import au.com.shiftyjelly.pocketcasts.analytics.AnalyticsEvent
88
import au.com.shiftyjelly.pocketcasts.analytics.AnalyticsTracker
99
import au.com.shiftyjelly.pocketcasts.analytics.SourceView
10+
import au.com.shiftyjelly.pocketcasts.compose.PodcastColors
1011
import au.com.shiftyjelly.pocketcasts.models.entity.PodcastEpisode
1112
import au.com.shiftyjelly.pocketcasts.models.entity.UserEpisode
1213
import au.com.shiftyjelly.pocketcasts.models.type.SignInState
@@ -137,34 +138,29 @@ class MainActivityViewModel
137138
multiSelectBookmarksHelper.closeMultiSelect()
138139
}
139140

140-
fun buildBookmarkArguments(bookmarkUuid: String? = null, onSuccess: (BookmarkArguments) -> Unit) {
141-
viewModelScope.launch {
142-
// load the existing bookmark
143-
val bookmark = bookmarkUuid?.let { bookmarkManager.findBookmark(it) }
144-
if (bookmarkUuid != null && bookmark == null) {
141+
suspend fun createBookmarkArguments(bookmarkUuid: String?): BookmarkArguments? {
142+
val bookmark = if (bookmarkUuid != null) {
143+
val existingBookmark = bookmarkManager.findBookmark(bookmarkUuid)
144+
if (existingBookmark == null) {
145145
_snackbarMessage.emit(LR.string.bookmark_not_found)
146-
return@launch
146+
return null
147147
}
148-
val currentEpisode = playbackManager.getCurrentEpisode()
149-
val episodeUuid = bookmark?.episodeUuid ?: currentEpisode?.uuid ?: return@launch
150-
val timeInSecs = bookmark?.timeSecs ?: currentEpisode?.let { playbackManager.getCurrentTimeMs(currentEpisode) / 1000 } ?: 0
151-
152-
val podcast =
153-
bookmark?.let { podcastManager.findPodcastByUuid(bookmark.podcastUuid) }
154-
val backgroundColor =
155-
if (podcast == null) 0xFF000000.toInt() else theme.playerBackgroundColor(podcast)
156-
val tintColor =
157-
if (podcast == null) 0xFFFFFFFF.toInt() else theme.playerHighlightColor(podcast)
158-
159-
val arguments = BookmarkArguments(
160-
bookmarkUuid = bookmark?.uuid,
161-
episodeUuid = episodeUuid,
162-
timeSecs = timeInSecs,
163-
backgroundColor = backgroundColor,
164-
tintColor = tintColor,
165-
)
166-
onSuccess(arguments)
148+
existingBookmark
149+
} else {
150+
null
167151
}
152+
153+
val currentEpisode = playbackManager.getCurrentEpisode()
154+
val episodeUuid = bookmark?.episodeUuid ?: currentEpisode?.uuid ?: return null
155+
val timeInSecs = bookmark?.timeSecs ?: currentEpisode?.let { playbackManager.getCurrentTimeMs(currentEpisode) / 1000 } ?: 0
156+
val podcast = bookmark?.let { podcastManager.findPodcastByUuid(bookmark.podcastUuid) }
157+
158+
return BookmarkArguments(
159+
bookmarkUuid = bookmarkUuid,
160+
episodeUuid = episodeUuid,
161+
timeSecs = timeInSecs,
162+
podcastColors = podcast?.let(::PodcastColors) ?: PodcastColors.ForUserEpisode,
163+
)
168164
}
169165

170166
fun viewBookmark(bookmarkUuid: String) {

modules/features/player/src/main/java/au/com/shiftyjelly/pocketcasts/player/binding/ViewExtensions.kt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,13 @@ fun PlayerSeekBar.setSeekBarState(
3131
chapters: Chapters,
3232
playbackSpeed: Double,
3333
adjustDuration: Boolean,
34-
tintColor: Int,
3534
bufferedUpTo: Int,
3635
isBuffering: Boolean,
37-
theme: Theme.ThemeType,
3836
) {
3937
setDuration(duration)
4038
setPlaybackSpeed(playbackSpeed)
4139
setCurrentTime(position)
4240
setChapters(chapters)
43-
setTintColor(tintColor, theme)
4441
setAdjustDuration(adjustDuration)
4542
this.isBuffering = isBuffering
4643
bufferedUpToInSecs = bufferedUpTo / 1000

modules/features/player/src/main/java/au/com/shiftyjelly/pocketcasts/player/view/PlayerContainerFragment.kt

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import android.view.View
88
import android.view.ViewGroup
99
import androidx.annotation.StringRes
1010
import androidx.appcompat.content.res.AppCompatResources
11+
import androidx.compose.ui.graphics.toArgb
1112
import androidx.core.view.doOnLayout
1213
import androidx.core.view.isGone
1314
import androidx.core.view.isVisible
@@ -23,6 +24,8 @@ import androidx.viewpager2.widget.ViewPager2
2324
import au.com.shiftyjelly.pocketcasts.analytics.AnalyticsEvent
2425
import au.com.shiftyjelly.pocketcasts.analytics.AnalyticsTracker
2526
import au.com.shiftyjelly.pocketcasts.analytics.SourceView
27+
import au.com.shiftyjelly.pocketcasts.compose.PlayerColors
28+
import au.com.shiftyjelly.pocketcasts.compose.PodcastColors
2629
import au.com.shiftyjelly.pocketcasts.models.to.Chapter
2730
import au.com.shiftyjelly.pocketcasts.player.R
2831
import au.com.shiftyjelly.pocketcasts.player.databinding.FragmentPlayerContainerBinding
@@ -48,6 +51,8 @@ import com.google.android.material.tabs.TabLayoutMediator
4851
import dagger.hilt.android.AndroidEntryPoint
4952
import dagger.hilt.android.lifecycle.withCreationCallback
5053
import javax.inject.Inject
54+
import kotlinx.coroutines.flow.Flow
55+
import kotlinx.coroutines.flow.map
5156
import kotlinx.coroutines.launch
5257
import timber.log.Timber
5358
import au.com.shiftyjelly.pocketcasts.images.R as IR
@@ -203,8 +208,15 @@ class PlayerContainerFragment : BaseFragment(), HasBackstack {
203208
analyticsTracker.track(AnalyticsEvent.UP_NEXT_SHOWN, mapOf(SOURCE_KEY to UpNextSource.PLAYER.analyticsValue))
204209
openUpNext()
205210
}
211+
}
206212

207-
view.setBackgroundColor(it.podcastHeader.backgroundColor)
213+
viewLifecycleOwner.lifecycleScope.launch {
214+
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
215+
podcastColorsFlow().collect { podcastColors ->
216+
val playerColors = PlayerColors(theme.activeTheme, podcastColors)
217+
view.setBackgroundColor(playerColors.background01.toArgb())
218+
}
219+
}
208220
}
209221

210222
viewLifecycleOwner.lifecycleScope.launch {
@@ -337,6 +349,12 @@ class PlayerContainerFragment : BaseFragment(), HasBackstack {
337349
private val isTranscriptVisible: Boolean
338350
get() = binding?.tabHolder?.isVisible == false
339351

352+
private fun podcastColorsFlow(): Flow<PodcastColors> {
353+
return viewModel.podcastFlow.map { podcast ->
354+
podcast?.let(::PodcastColors) ?: PodcastColors.ForUserEpisode
355+
}
356+
}
357+
340358
companion object {
341359
private const val INVALID_TAB_POSITION = -1
342360
private const val SOURCE_KEY = "source"

modules/features/player/src/main/java/au/com/shiftyjelly/pocketcasts/player/view/PlayerHeaderFragment.kt

Lines changed: 35 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package au.com.shiftyjelly.pocketcasts.player.view
33
import android.animation.LayoutTransition
44
import android.content.ActivityNotFoundException
55
import android.content.Intent
6-
import android.net.Uri
76
import android.os.Bundle
87
import android.view.GestureDetector
98
import android.view.LayoutInflater
@@ -27,6 +26,7 @@ import androidx.compose.runtime.getValue
2726
import androidx.compose.runtime.remember
2827
import androidx.compose.ui.Alignment
2928
import androidx.compose.ui.Modifier
29+
import androidx.compose.ui.graphics.toArgb
3030
import androidx.compose.ui.unit.dp
3131
import androidx.core.net.toUri
3232
import androidx.core.view.isInvisible
@@ -45,13 +45,15 @@ import au.com.shiftyjelly.pocketcasts.analytics.AnalyticsEvent
4545
import au.com.shiftyjelly.pocketcasts.analytics.SourceView
4646
import au.com.shiftyjelly.pocketcasts.compose.AppTheme
4747
import au.com.shiftyjelly.pocketcasts.compose.LocalPodcastColors
48+
import au.com.shiftyjelly.pocketcasts.compose.PlayerColors
4849
import au.com.shiftyjelly.pocketcasts.compose.PodcastColors
4950
import au.com.shiftyjelly.pocketcasts.compose.ad.AdBanner
5051
import au.com.shiftyjelly.pocketcasts.compose.ad.rememberAdColors
5152
import au.com.shiftyjelly.pocketcasts.compose.components.AnimatedNonNullVisibility
5253
import au.com.shiftyjelly.pocketcasts.compose.extensions.setContentWithViewCompositionStrategy
5354
import au.com.shiftyjelly.pocketcasts.player.binding.setSeekBarState
5455
import au.com.shiftyjelly.pocketcasts.player.databinding.AdapterPlayerHeaderBinding
56+
import au.com.shiftyjelly.pocketcasts.player.view.bookmark.BookmarkActivity
5557
import au.com.shiftyjelly.pocketcasts.player.view.bookmark.BookmarkActivityContract
5658
import au.com.shiftyjelly.pocketcasts.player.view.nowplaying.PlayerControls
5759
import au.com.shiftyjelly.pocketcasts.player.view.nowplaying.PlayerHeadingSection
@@ -161,32 +163,29 @@ class PlayerHeaderFragment : BaseFragment(), PlayerClickListener {
161163
setupUpNextDrag(binding)
162164

163165
viewModel.listDataLive.observe(viewLifecycleOwner) {
164-
val headerViewModel = it.podcastHeader
166+
val podcastHeader = it.podcastHeader
165167

168+
binding.playerGroup.setBackgroundColor(podcastHeader.backgroundColor)
166169
binding.seekBar.setSeekBarState(
167-
duration = headerViewModel.durationMs.milliseconds,
168-
position = headerViewModel.positionMs.milliseconds,
169-
chapters = headerViewModel.chapters,
170-
playbackSpeed = headerViewModel.playbackEffects.playbackSpeed,
171-
adjustDuration = headerViewModel.adjustRemainingTimeDuration,
172-
tintColor = headerViewModel.iconTintColor,
173-
bufferedUpTo = headerViewModel.bufferedUpToMs,
174-
isBuffering = headerViewModel.isBuffering,
175-
theme = headerViewModel.theme,
170+
duration = podcastHeader.durationMs.milliseconds,
171+
position = podcastHeader.positionMs.milliseconds,
172+
chapters = podcastHeader.chapters,
173+
playbackSpeed = podcastHeader.playbackEffects.playbackSpeed,
174+
adjustDuration = podcastHeader.adjustRemainingTimeDuration,
175+
bufferedUpTo = podcastHeader.bufferedUpToMs,
176+
isBuffering = podcastHeader.isBuffering,
176177
)
178+
}
177179

178-
binding.playerGroup.setBackgroundColor(headerViewModel.backgroundColor)
179-
binding.seekBar.setSeekBarState(
180-
duration = headerViewModel.durationMs.milliseconds,
181-
position = headerViewModel.positionMs.milliseconds,
182-
chapters = headerViewModel.chapters,
183-
playbackSpeed = headerViewModel.playbackEffects.playbackSpeed,
184-
adjustDuration = headerViewModel.adjustRemainingTimeDuration,
185-
tintColor = headerViewModel.iconTintColor,
186-
bufferedUpTo = headerViewModel.bufferedUpToMs,
187-
isBuffering = headerViewModel.isBuffering,
188-
theme = headerViewModel.theme,
189-
)
180+
viewLifecycleOwner.lifecycleScope.launch {
181+
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
182+
podcastColorsFlow().collect { podcastColors ->
183+
val playerColors = PlayerColors(theme.activeTheme, podcastColors ?: PodcastColors.ForUserEpisode)
184+
185+
binding.playerGroup.setBackgroundColor(playerColors.background01.toArgb())
186+
binding.seekBar.setTintColor(playerColors.highlight01.toArgb(), theme.activeTheme)
187+
}
188+
}
190189
}
191190

192191
viewLifecycleOwner.lifecycleScope.launch {
@@ -226,7 +225,7 @@ class PlayerHeaderFragment : BaseFragment(), PlayerClickListener {
226225
is PlayerViewModel.NavigationState.OpenChapterUrl -> {
227226
val chapterUrl = navigationState.chapterUrl
228227
val intent = Intent(Intent.ACTION_VIEW)
229-
intent.data = Uri.parse(chapterUrl)
228+
intent.data = chapterUrl.toUri()
230229
try {
231230
startActivity(intent)
232231
} catch (e: ActivityNotFoundException) {
@@ -305,10 +304,16 @@ class PlayerHeaderFragment : BaseFragment(), PlayerClickListener {
305304

306305
private fun setupPlayerControlsComposeView() {
307306
binding?.playerControlsComposeView?.setContentWithViewCompositionStrategy {
307+
val podcastColors by remember { podcastColorsFlow() }.collectAsState(null)
308+
308309
AppTheme(theme.activeTheme) {
309-
PlayerControls(
310-
playerViewModel = viewModel,
311-
)
310+
CompositionLocalProvider(
311+
LocalPodcastColors provides podcastColors,
312+
) {
313+
PlayerControls(
314+
playerViewModel = viewModel,
315+
)
316+
}
312317
}
313318
}
314319
}
@@ -417,8 +422,9 @@ class PlayerHeaderFragment : BaseFragment(), PlayerClickListener {
417422
}
418423

419424
NavigationState.ShowAddBookmark -> {
420-
viewModel.buildBookmarkArguments { arguments ->
421-
activityLauncher.launch(arguments.getIntent(requireContext()))
425+
val bookmarkArguments = viewModel.createBookmarkArguments()
426+
if (bookmarkArguments != null) {
427+
activityLauncher.launch(BookmarkActivity.launchIntent(requireContext(), bookmarkArguments))
422428
}
423429
}
424430

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,38 @@
11
package au.com.shiftyjelly.pocketcasts.player.view.bookmark
22

3+
import android.content.Context
4+
import android.content.Intent
35
import android.os.Bundle
46
import androidx.appcompat.app.AppCompatActivity
5-
import androidx.core.view.WindowInsetsControllerCompat
7+
import androidx.core.content.IntentCompat
8+
import androidx.fragment.app.commitNow
69
import dagger.hilt.android.AndroidEntryPoint
710
import au.com.shiftyjelly.pocketcasts.views.R as VR
811

912
@AndroidEntryPoint
1013
class BookmarkActivity : AppCompatActivity() {
14+
companion object {
15+
private const val NEW_INSTANCE_KEY = "new_instance_key"
16+
17+
fun launchIntent(context: Context, args: BookmarkArguments): Intent {
18+
return Intent(context, BookmarkActivity::class.java).putExtra(NEW_INSTANCE_KEY, args)
19+
}
20+
}
21+
22+
private val args
23+
get() = requireNotNull(IntentCompat.getParcelableExtra(intent, NEW_INSTANCE_KEY, BookmarkArguments::class.java)) {
24+
"Missing input parameters"
25+
}
1126

1227
override fun onCreate(savedInstanceState: Bundle?) {
1328
super.onCreate(savedInstanceState)
1429

1530
setContentView(VR.layout.activity_blank_fragment)
1631

17-
val arguments = BookmarkArguments.createFromIntent(intent)
18-
19-
// set the status bar icons to white
20-
WindowInsetsControllerCompat(window, window.decorView).isAppearanceLightStatusBars = false
21-
2232
if (savedInstanceState == null) {
23-
val fragment = arguments.buildFragment()
24-
supportFragmentManager.beginTransaction()
25-
.replace(VR.id.container, fragment)
26-
.commitNow()
33+
supportFragmentManager.commitNow {
34+
replace(VR.id.container, BookmarkFragment.newInstance(args))
35+
}
2736
}
2837
}
2938
}

0 commit comments

Comments
 (0)