Skip to content

Commit 5701620

Browse files
mebarbosaashiagr
andauthored
[Project] Manage Downloaded Episodes - Display Modal when running on low storage and opening Storage & Data Use screen (#3149)
Co-authored-by: ashiagr <[email protected]>
1 parent bcae13b commit 5701620

File tree

13 files changed

+391
-70
lines changed

13 files changed

+391
-70
lines changed

app/lint-baseline.xml

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
errorLine2=" ~~~~~~~~">
4242
<location
4343
file="src/main/java/au/com/shiftyjelly/pocketcasts/player/view/EffectsFragment.kt"
44-
line="57"
44+
line="77"
4545
column="18"/>
4646
</issue>
4747

@@ -85,7 +85,7 @@
8585
errorLine2=" ~~~~~~~~">
8686
<location
8787
file="src/main/java/au/com/shiftyjelly/pocketcasts/podcasts/view/ProfileEpisodeListFragment.kt"
88-
line="196"
88+
line="202"
8989
column="18"/>
9090
</issue>
9191

@@ -111,14 +111,25 @@
111111
column="18"/>
112112
</issue>
113113

114+
<issue
115+
id="MissingSuperCall"
116+
message="Overriding method should call `super.onAttach`"
117+
errorLine1=" override fun onAttach(context: Context) {"
118+
errorLine2=" ~~~~~~~~">
119+
<location
120+
file="src/main/java/au/com/shiftyjelly/pocketcasts/settings/StorageSettingsFragment.kt"
121+
line="48"
122+
column="18"/>
123+
</issue>
124+
114125
<issue
115126
id="MissingSuperCall"
116127
message="Overriding method should call `super.onAttach`"
117128
errorLine1=" override fun onAttach(context: Context) {"
118129
errorLine2=" ~~~~~~~~">
119130
<location
120131
file="src/main/java/au/com/shiftyjelly/pocketcasts/player/view/UpNextFragment.kt"
121-
line="206"
132+
line="209"
122133
column="18"/>
123134
</issue>
124135

@@ -195,7 +206,7 @@
195206
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
196207
<location
197208
file="src/main/java/au/com/shiftyjelly/pocketcasts/ui/MainActivity.kt"
198-
line="966"
209+
line="1003"
199210
column="55"/>
200211
</issue>
201212

@@ -206,7 +217,7 @@
206217
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
207218
<location
208219
file="src/main/java/au/com/shiftyjelly/pocketcasts/ui/MainActivity.kt"
209-
line="973"
220+
line="1010"
210221
column="55"/>
211222
</issue>
212223

@@ -294,7 +305,7 @@
294305
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
295306
<location
296307
file="src/main/res/layout/fragment_effects.xml"
297-
line="60"
308+
line="70"
298309
column="17"/>
299310
</issue>
300311

@@ -305,7 +316,7 @@
305316
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
306317
<location
307318
file="src/main/res/layout/fragment_effects.xml"
308-
line="97"
319+
line="107"
309320
column="17"/>
310321
</issue>
311322

@@ -6761,7 +6772,7 @@
67616772
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
67626773
<location
67636774
file="../modules/features/player/src/main/res/layout/adapter_up_next_footer.xml"
6764-
line="62"
6775+
line="54"
67656776
column="13"/>
67666777
</issue>
67676778

@@ -6772,7 +6783,7 @@
67726783
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
67736784
<location
67746785
file="../modules/features/player/src/main/res/layout/adapter_up_next_footer.xml"
6775-
line="71"
6786+
line="63"
67766787
column="13"/>
67776788
</issue>
67786789

@@ -7333,7 +7344,7 @@
73337344
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
73347345
<location
73357346
file="../modules/features/podcasts/src/main/res/layout/fragment_profile_episode_list.xml"
7336-
line="13"
7347+
line="14"
73377348
column="13"/>
73387349
</issue>
73397350

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

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ import au.com.shiftyjelly.pocketcasts.player.view.bookmark.BookmarksContainerFra
9595
import au.com.shiftyjelly.pocketcasts.player.view.dialog.MiniPlayerDialog
9696
import au.com.shiftyjelly.pocketcasts.player.view.video.VideoActivity
9797
import au.com.shiftyjelly.pocketcasts.podcasts.view.ProfileEpisodeListFragment
98+
import au.com.shiftyjelly.pocketcasts.podcasts.view.ProfileEpisodeListFragment.Companion.CLEAN_UP
99+
import au.com.shiftyjelly.pocketcasts.podcasts.view.ProfileEpisodeListFragment.Companion.OPTION_KEY
98100
import au.com.shiftyjelly.pocketcasts.podcasts.view.episode.EpisodeContainerFragment
99101
import au.com.shiftyjelly.pocketcasts.podcasts.view.podcast.PodcastFragment
100102
import au.com.shiftyjelly.pocketcasts.podcasts.view.podcasts.PodcastsFragment
@@ -128,6 +130,7 @@ import au.com.shiftyjelly.pocketcasts.search.SearchFragment
128130
import au.com.shiftyjelly.pocketcasts.servers.ServerCallback
129131
import au.com.shiftyjelly.pocketcasts.servers.ServiceManager
130132
import au.com.shiftyjelly.pocketcasts.servers.discover.PodcastSearch
133+
import au.com.shiftyjelly.pocketcasts.settings.ManualCleanupFragment
131134
import au.com.shiftyjelly.pocketcasts.settings.onboarding.OnboardingFlow
132135
import au.com.shiftyjelly.pocketcasts.settings.onboarding.OnboardingLauncher
133136
import au.com.shiftyjelly.pocketcasts.settings.onboarding.OnboardingUpgradeSource
@@ -150,6 +153,8 @@ import au.com.shiftyjelly.pocketcasts.views.fragments.BaseFragment
150153
import au.com.shiftyjelly.pocketcasts.views.helper.HasBackstack
151154
import au.com.shiftyjelly.pocketcasts.views.helper.UiUtil
152155
import au.com.shiftyjelly.pocketcasts.views.helper.WarningsHelper
156+
import au.com.shiftyjelly.pocketcasts.views.lowstorage.LowStorageBottomSheetListener
157+
import au.com.shiftyjelly.pocketcasts.views.lowstorage.LowStorageLaunchBottomSheet
153158
import com.automattic.android.tracks.crashlogging.CrashLogging
154159
import com.google.android.material.bottomsheet.BottomSheetBehavior
155160
import com.google.android.material.snackbar.Snackbar
@@ -190,6 +195,7 @@ class MainActivity :
190195
FragmentHostListener,
191196
PlayerBottomSheet.PlayerBottomSheetListener,
192197
SearchFragment.Listener,
198+
LowStorageBottomSheetListener,
193199
OnboardingLauncher,
194200
CoroutineScope,
195201
NotificationPermissionChecker {
@@ -730,6 +736,37 @@ class MainActivity :
730736
)
731737
}
732738

739+
private fun setupLowStorageLaunchBottomSheet() {
740+
val viewGroup = binding.modalBottomSheet
741+
viewGroup.removeAllViews()
742+
viewGroup.addView(
743+
ComposeView(viewGroup.context).apply {
744+
setContent {
745+
val downloadedEpisodesState by viewModel.downloadedEpisodeState.collectAsState()
746+
747+
val shouldShow = downloadedEpisodesState.downloadedEpisodes != 0L &&
748+
FeatureFlag.isEnabled(Feature.MANAGE_DOWNLOADED_EPISODES)
749+
750+
AppTheme(theme.activeTheme) {
751+
LowStorageLaunchBottomSheet(
752+
parent = viewGroup,
753+
shouldShow = shouldShow,
754+
onManageDownloadsClick = {
755+
analyticsTracker.track(AnalyticsEvent.DOWNLOADS_OPTIONS_MODAL_OPTION_TAPPED, mapOf(OPTION_KEY to CLEAN_UP))
756+
addFragment(ManualCleanupFragment.newInstance())
757+
},
758+
onExpanded = {
759+
},
760+
onMaybeLaterClick = {
761+
},
762+
totalDownloadSize = downloadedEpisodesState.downloadedEpisodes,
763+
)
764+
}
765+
}
766+
},
767+
)
768+
}
769+
733770
private fun showEndOfYearModal() {
734771
viewModel.updateStoriesModalShowState(true)
735772
launch(Dispatchers.Main) {
@@ -1623,4 +1660,10 @@ class MainActivity :
16231660
.setTextColor(ThemeColor.primaryText01(Theme.ThemeType.DARK))
16241661
.show()
16251662
}
1663+
1664+
override fun showModal() {
1665+
launch(Dispatchers.Main) {
1666+
setupLowStorageLaunchBottomSheet()
1667+
}
1668+
}
16261669
}

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import kotlinx.coroutines.flow.asStateFlow
3636
import kotlinx.coroutines.flow.update
3737
import kotlinx.coroutines.launch
3838
import kotlinx.coroutines.reactive.asFlow
39+
import kotlinx.coroutines.reactive.collect
3940
import timber.log.Timber
4041
import au.com.shiftyjelly.pocketcasts.localization.R as LR
4142

@@ -56,6 +57,9 @@ class MainActivityViewModel
5657
private val _state = MutableStateFlow(State())
5758
val state = _state.asStateFlow()
5859

60+
private val _downloadedEpisodeState = MutableStateFlow(DownloadedEpisodesState())
61+
val downloadedEpisodeState = _downloadedEpisodeState.asStateFlow()
62+
5963
private val _snackbarMessage = MutableSharedFlow<Int>()
6064
val snackbarMessage = _snackbarMessage.asSharedFlow()
6165

@@ -74,6 +78,13 @@ class MainActivityViewModel
7478
updateStoriesModalShowState(settings.getEndOfYearShowModal())
7579
}
7680
}
81+
82+
viewModelScope.launch {
83+
episodeManager.observeDownloadedEpisodes()
84+
.collect { result ->
85+
_downloadedEpisodeState.update { state -> state.copy(downloadedEpisodes = result.sumOf { it.sizeInBytes }) }
86+
}
87+
}
7788
}
7889

7990
private fun showWhatsNewIfNeeded() {
@@ -200,6 +211,10 @@ class MainActivityViewModel
200211
val shouldShowWhatsNew: Boolean = false,
201212
)
202213

214+
data class DownloadedEpisodesState(
215+
val downloadedEpisodes: Long = 0L,
216+
)
217+
203218
sealed class NavigationState {
204219
object BookmarksForCurrentlyPlaying : NavigationState()
205220
data class BookmarksForPodcastEpisode(val episode: PodcastEpisode) : NavigationState()

app/src/test/java/au/com/shiftyjelly/pocketcasts/ui/MainActivityViewModelTest.kt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import io.reactivex.Flowable
2525
import java.util.Date
2626
import kotlinx.coroutines.ExperimentalCoroutinesApi
2727
import kotlinx.coroutines.test.runTest
28+
import org.junit.Assert.assertEquals
2829
import org.junit.Assert.assertFalse
2930
import org.junit.Assert.assertTrue
3031
import org.junit.Before
@@ -85,6 +86,12 @@ class MainActivityViewModelTest {
8586

8687
private val episode = UserEpisode(uuid = TEST_EPISODE_UUID, publishedDate = Date())
8788

89+
private val downloadedEpisodes = listOf(
90+
PodcastEpisode(sizeInBytes = 1024L, uuid = "episode-uuid", title = "Episode Title", publishedDate = Date()),
91+
PodcastEpisode(sizeInBytes = 2048L, uuid = "episode-uuid", title = "Episode Title", publishedDate = Date()),
92+
PodcastEpisode(sizeInBytes = 512L, uuid = "episode-uuid", title = "Episode Title", publishedDate = Date()),
93+
)
94+
8895
@Before
8996
fun setup() = runTest {
9097
whenever(playbackManager.playbackStateRelay).thenReturn(BehaviorRelay.create<PlaybackState>().toSerialized())
@@ -119,6 +126,15 @@ class MainActivityViewModelTest {
119126
}
120127
}
121128

129+
@Test
130+
fun `when episodeManager emits episodes, downloadedEpisodeState should update with total size`() = runTest {
131+
initViewModel()
132+
133+
viewModel.downloadedEpisodeState.test {
134+
assertEquals(downloadedEpisodes.sumOf { it.sizeInBytes }, awaitItem().downloadedEpisodes)
135+
}
136+
}
137+
122138
/* Bookmark added notification tests */
123139

124140
@Test
@@ -218,6 +234,8 @@ class MainActivityViewModelTest {
218234
),
219235
)
220236

237+
whenever(episodeManager.observeDownloadedEpisodes()).thenReturn(Flowable.just(downloadedEpisodes))
238+
221239
viewModel = MainActivityViewModel(
222240
episodeManager = episodeManager,
223241
playbackManager = playbackManager,

0 commit comments

Comments
 (0)