Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Suggested Folder] Create suggested folder screen UI #3554

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
package au.com.shiftyjelly.pocketcasts.podcasts.view.folders

import android.content.res.Configuration
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Icon
import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.clearAndSetSemantics
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import au.com.shiftyjelly.pocketcasts.compose.AppTheme
import au.com.shiftyjelly.pocketcasts.compose.buttons.RowButton
import au.com.shiftyjelly.pocketcasts.compose.buttons.RowOutlinedButton
import au.com.shiftyjelly.pocketcasts.compose.components.TextH30
import au.com.shiftyjelly.pocketcasts.compose.components.TextH50
import au.com.shiftyjelly.pocketcasts.compose.folder.FolderImage
import au.com.shiftyjelly.pocketcasts.compose.preview.ThemePreviewParameterProvider
import au.com.shiftyjelly.pocketcasts.compose.theme
import au.com.shiftyjelly.pocketcasts.ui.theme.Theme
import au.com.shiftyjelly.pocketcasts.images.R as IR
import au.com.shiftyjelly.pocketcasts.localization.R as LR

@Composable
fun SuggestedFoldersPaywall(
onUseTheseFolders: () -> Unit,
onMaybeLater: () -> Unit,
modifier: Modifier = Modifier,
) {
Column(
modifier = modifier
.wrapContentSize()
.padding(horizontal = 16.dp)
.padding(top = 8.dp, bottom = 16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
) {
val isPortrait = LocalConfiguration.current.orientation == Configuration.ORIENTATION_PORTRAIT

val animatedPadding by animateDpAsState(
targetValue = if (isPortrait) 32.dp else 8.dp,
)

Icon(
painter = painterResource(IR.drawable.ic_swipe),
contentDescription = null,
tint = MaterialTheme.theme.colors.primaryUi05,
modifier = Modifier.clearAndSetSemantics {},
)

AnimatedVisibility(isPortrait) {
Folders(
podcastUuids = mockedPodcastsUuids,
modifier = Modifier
.fillMaxWidth()
.padding(vertical = animatedPadding)
.align(Alignment.CenterHorizontally),
)
}

TextH30(
text = stringResource(LR.string.suggested_folders_paywall_tittle),
fontWeight = FontWeight.W600,
textAlign = TextAlign.Center,
modifier = Modifier.padding(bottom = 12.dp),
)

TextH50(
text = stringResource(LR.string.suggested_folders_paywall_subtitle),
color = MaterialTheme.theme.colors.primaryText02,
textAlign = TextAlign.Center,
modifier = Modifier.padding(bottom = 12.dp),
)

RowButton(
text = stringResource(LR.string.suggested_folders_use_these_folders_button),
modifier = Modifier.padding(bottom = 16.dp),
textColor = MaterialTheme.theme.colors.primaryInteractive02,
fontSize = 18.sp,
fontWeight = FontWeight.W600,
colors = ButtonDefaults.buttonColors(
backgroundColor = MaterialTheme.theme.colors.primaryInteractive01,
),
includePadding = false,
onClick = onUseTheseFolders,
)

RowOutlinedButton(
text = stringResource(id = LR.string.maybe_later),
modifier = Modifier.padding(bottom = 16.dp),
onClick = onMaybeLater,
includePadding = false,
colors = ButtonDefaults.outlinedButtonColors(contentColor = MaterialTheme.theme.colors.primaryIcon01, backgroundColor = Color.Transparent),
fontSize = 18.sp,
fontWeight = FontWeight.W600,
)
}
}

@Composable
private fun Folders(podcastUuids: List<String>, modifier: Modifier = Modifier) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When this PR got merged I will refactor this common part

val folders = 3
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a need for this val?


LazyVerticalGrid(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might be missing something by why use LazyVerticalGrid over a Row?

columns = GridCells.Fixed(3),
horizontalArrangement = Arrangement.spacedBy(6.dp),
modifier = modifier,
) {
items(
count = folders,
key = { index -> index },
) { index ->
FolderItem("Test", Color.Yellow, podcastUuids)
}
}
}

@Composable
private fun FolderItem(folderName: String, folderColor: Color, podcastUuids: List<String>, modifier: Modifier = Modifier) {
val stringResource = stringResource(LR.string.folder_content_description, folderName)

FolderImage(
name = folderName,
color = folderColor,
podcastUuids = podcastUuids,
textSpacing = true,
modifier = modifier.clearAndSetSemantics {
contentDescription = stringResource
},
)
}

@Preview(showBackground = true)
@Composable
private fun SuggestedFoldersPagePreview(@PreviewParameter(ThemePreviewParameterProvider::class) themeType: Theme.ThemeType) {
AppTheme(themeType) {
SuggestedFoldersPaywall(
onUseTheseFolders = {},
onMaybeLater = {},
)
}
}

private val mockedPodcastsUuids = listOf(
"5d308950-1fe3-012e-02b0-00163e1b201c",
"f086f200-4f32-0139-3396-0acc26574db2",
"2e61ba20-50a9-0135-902b-63f4b61a9224",
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package au.com.shiftyjelly.pocketcasts.podcasts.view.folders

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.core.view.doOnLayout
import au.com.shiftyjelly.pocketcasts.compose.AppTheme
import au.com.shiftyjelly.pocketcasts.compose.extensions.contentWithoutConsumedInsets
import au.com.shiftyjelly.pocketcasts.settings.onboarding.OnboardingFlow
import au.com.shiftyjelly.pocketcasts.settings.onboarding.OnboardingLauncher
import au.com.shiftyjelly.pocketcasts.settings.onboarding.OnboardingUpgradeSource
import au.com.shiftyjelly.pocketcasts.ui.theme.Theme
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject

@AndroidEntryPoint
class SuggestedFoldersPaywallBottomSheet : BottomSheetDialogFragment() {

@Inject
lateinit var theme: Theme

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
) = contentWithoutConsumedInsets {
AppTheme(theme.activeTheme) {
SuggestedFoldersPaywall(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should handle window insets and not draw the content behind the camera punch hole.

410124626-120bd39b-bafd-42b5-8f17-0be36c14a7c9

onUseTheseFolders = {
dismiss()
val source = OnboardingUpgradeSource.PROFILE
val onboardingFlow = OnboardingFlow.PlusAccountUpgrade(source)
OnboardingLauncher.openOnboardingFlow(activity, onboardingFlow)
},
onMaybeLater = {
dismiss()
},
)
}
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

view.doOnLayout {
val dialog = dialog as BottomSheetDialog
val bottomSheet = dialog.findViewById<View>(com.google.android.material.R.id.design_bottom_sheet) as FrameLayout?
if (bottomSheet != null) {
BottomSheetBehavior.from(bottomSheet).run {
state = BottomSheetBehavior.STATE_EXPANDED
peekHeight = 0
skipCollapsed = true
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import au.com.shiftyjelly.pocketcasts.podcasts.view.folders.FolderCreateFragment
import au.com.shiftyjelly.pocketcasts.podcasts.view.folders.FolderCreateSharedViewModel
import au.com.shiftyjelly.pocketcasts.podcasts.view.folders.FolderEditFragment
import au.com.shiftyjelly.pocketcasts.podcasts.view.folders.FolderEditPodcastsFragment
import au.com.shiftyjelly.pocketcasts.podcasts.view.folders.SuggestedFoldersPaywallBottomSheet
import au.com.shiftyjelly.pocketcasts.podcasts.view.podcast.PodcastFragment
import au.com.shiftyjelly.pocketcasts.podcasts.viewmodel.PodcastsViewModel
import au.com.shiftyjelly.pocketcasts.preferences.Settings
Expand All @@ -42,6 +43,8 @@ import au.com.shiftyjelly.pocketcasts.settings.onboarding.OnboardingUpgradeSourc
import au.com.shiftyjelly.pocketcasts.ui.extensions.getColor
import au.com.shiftyjelly.pocketcasts.ui.helper.FragmentHostListener
import au.com.shiftyjelly.pocketcasts.utils.extensions.hideShadow
import au.com.shiftyjelly.pocketcasts.utils.featureflag.Feature
import au.com.shiftyjelly.pocketcasts.utils.featureflag.FeatureFlag
import au.com.shiftyjelly.pocketcasts.views.adapter.PodcastTouchCallback
import au.com.shiftyjelly.pocketcasts.views.extensions.showIf
import au.com.shiftyjelly.pocketcasts.views.fragments.BaseFragment
Expand Down Expand Up @@ -195,7 +198,11 @@ class PodcastsFragment : BaseFragment(), FolderAdapter.ClickListener, PodcastTou
toolbar.setOnMenuItemClickListener(this)

toolbar.menu.findItem(R.id.folders_locked).setOnMenuItemClickListener {
OnboardingLauncher.openOnboardingFlow(activity, OnboardingFlow.Upsell(OnboardingUpgradeSource.FOLDERS))
if (FeatureFlag.isEnabled(Feature.SUGGESTED_FOLDERS)) {
SuggestedFoldersPaywallBottomSheet().show(childFragmentManager, "suggested_folders_paywall")
} else {
OnboardingLauncher.openOnboardingFlow(activity, OnboardingFlow.Upsell(OnboardingUpgradeSource.FOLDERS))
}
true
}

Expand Down
9 changes: 9 additions & 0 deletions modules/services/images/src/main/res/drawable/ic_swipe.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="55dp"
android:height="5dp"
android:viewportWidth="55"
android:viewportHeight="5">
<path
android:pathData="M2.782,0.616L52.34,0.616A1.906,1.906 0,0 1,54.246 2.522L54.246,2.522A1.906,1.906 0,0 1,52.34 4.428L2.782,4.428A1.906,1.906 0,0 1,0.875 2.522L0.875,2.522A1.906,1.906 0,0 1,2.782 0.616z"
android:fillColor="#E4E4E4"/>
</vector>
Original file line number Diff line number Diff line change
Expand Up @@ -2315,4 +2315,10 @@
<string name="winback_cancel_subscription_stay_button_label">Actually, I want to stay</string>
<string name="winback_cancel_subscription_cancel_button_label">Yes, Cancel my Subscription</string>

<!-- Suggested Folders -->
<string name="suggested_folders_paywall_tittle">Your podcasts, automatically organized</string>
<string name="suggested_folders_paywall_subtitle">We\'ve pre-made folders for your podcasts. Unlock this and features like bookmarks, transcripts, and more with Pocket Casts Plus.</string>
<string name="suggested_folders_use_these_folders_button">Use these folders</string>
<string name="folder_content_description">Folder %s</string>

</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,14 @@ enum class Feature(
hasFirebaseRemoteFlag = false,
hasDevToggle = true,
),
SUGGESTED_FOLDERS(
key = "suggested_folders",
title = "Suggested Folders",
defaultValue = BuildConfig.DEBUG,
tier = FeatureTier.Free,
hasFirebaseRemoteFlag = false,
hasDevToggle = true,
),
;

companion object {
Expand Down
Loading