Skip to content
Merged
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
Expand Up @@ -20,6 +20,7 @@ import androidx.compose.animation.ExitTransition
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.core.CubicBezierEasing
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.animation.togetherWith
Expand Down Expand Up @@ -91,6 +92,17 @@ private val pushedTokenInfoEntries: List<String> =
private fun isGiveKey(key: Any?): Boolean =
key?.toString()?.startsWith("Give(") == true

/**
* True when a scene key is [AppRoute.Menu.ProfileCard]. Same stringified-key match as
* [isTokenInfoKey]; a `data object` prints its simple name.
*/
private fun isProfileCardKey(key: Any?): Boolean =
key?.toString() == "ProfileCard"

/** The profile card's own fade; the screen's spring-in does the rest, so nothing slides. */
private const val ProfileCardFadeMillis = 250
private val EaseOutEasing = CubicBezierEasing(0f, 0f, 0.58f, 1f)

@Composable
internal fun AppContent(
codeNavigator: CodeNavigator,
Expand Down Expand Up @@ -201,6 +213,11 @@ internal fun AppContent(
// CardExpandTransition + TokenCardStack.
isTokenInfoKey(targetState.key) ->
CardExpandTransition.openEnter togetherWith CardExpandTransition.openExit
// The card presents like a scanned bill: the backdrop fades up over the
// You tab, which stays put beneath, and the screen pops the card itself.
isProfileCardKey(targetState.key) ->
fadeIn(tween(ProfileCardFadeMillis, easing = EaseOutEasing)) togetherWith
ExitTransition.None
landsOnTab ->
fadeIn(tween(300)) togetherWith fadeOut(tween(300))
else ->
Expand All @@ -221,6 +238,10 @@ internal fun AppContent(
// Swapping in a single frame keeps the scrim continuously up.
isGiveKey(initialState.key) ->
EnterTransition.None togetherWith ExitTransition.None
// The whole screen fades out at full size, no slide.
isProfileCardKey(initialState.key) ->
EnterTransition.None togetherWith
fadeOut(tween(ProfileCardFadeMillis, easing = EaseOutEasing))
else ->
slideInHorizontally(initialOffsetX = { -it }) togetherWith
slideOutHorizontally(targetOffsetX = { it })
Expand All @@ -234,6 +255,9 @@ internal fun AppContent(
isTokenInfoKey(initialState.key) ->
CardExpandTransition.predictiveCloseEnter togetherWith
CardExpandTransition.predictiveCloseExit
isProfileCardKey(initialState.key) ->
EnterTransition.None togetherWith
fadeOut(tween(ProfileCardFadeMillis, easing = EaseOutEasing))
else ->
slideInHorizontally(initialOffsetX = { -it }) togetherWith
slideOutHorizontally(targetOffsetX = { it })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ import com.flipcash.app.lab.LabsScreen
import com.flipcash.app.login.AccountSelectionScreen
import com.flipcash.app.login.OnboardingFlowScreen
import com.flipcash.app.menu.MenuScreen
import com.flipcash.app.menu.ProfileCardScreen
import com.flipcash.app.menu.ProfileShareScreen
import com.flipcash.app.myaccount.BlocklistScreen
import com.flipcash.app.myaccount.UserProfileScreen
import com.flipcash.app.myaccount.SettingsScreen
Expand Down Expand Up @@ -169,6 +171,8 @@ fun appEntryProvider(
annotatedEntry<AppRoute.Menu.Lab> { key -> LabsScreen(onboarding = key.onboarding) }
annotatedEntry<AppRoute.Menu.UserProfile> { UserProfileScreen() }
annotatedEntry<AppRoute.Menu.Settings> { SettingsScreen() }
annotatedEntry<AppRoute.Menu.ShareProfile> { ProfileShareScreen() }
annotatedEntry<AppRoute.Menu.ProfileCard> { ProfileCardScreen() }
annotatedEntry<AppRoute.Menu.Blocklist> { BlocklistScreen() }
annotatedEntry<AppRoute.Menu.BackupKey> { BackupKeyScreen() }
annotatedEntry<AppRoute.Menu.DeviceLogs> { DeviceLogsScreen() }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.AddCircleOutline
import androidx.compose.material.icons.outlined.Edit
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
Expand All @@ -26,22 +25,18 @@ import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewWrapper
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.util.fastForEach
import com.flipcash.app.theme.FlipcashThemeWrapper
import com.flipcash.core.R
import com.getcode.theme.CodeTheme
import com.getcode.theme.extraSmall

/**
* A row in a "what's left to do" checklist.
*
* Split by the screen that owns it: [Wallet] and [Profile] are drawn by different tabs and share
* nothing but the row layout, so each call site's `when` stays exhaustive over its own family and
* cannot be handed an item it has no branch for.
* [Wallet] is the family the wallet tab draws, so its call site's `when` stays exhaustive over
* the milestones it owns.
*/
sealed interface TutorialItem {
val title: String
Expand All @@ -55,9 +50,6 @@ sealed interface TutorialItem {
/** The wallet tab's new-user milestones. */
sealed interface Wallet : TutorialItem

/** The "You" tab's profile-completion steps (node 9544:18140). */
sealed interface Profile : TutorialItem

class AddMoney(override val isCompleted: Boolean) : Wallet {
override val title: String
@Composable get() = stringResource(R.string.title_addMoney)
Expand All @@ -75,41 +67,6 @@ sealed interface TutorialItem {
override val icon: Painter
@Composable get() = painterResource(R.drawable.ic_nav_tipcard)
}

/**
* Accounts created before onboarding asked for a name have none, and chat shows them as
* "Flipcash User" until they set one.
*/
class DisplayName(override val isCompleted: Boolean) : Profile {
override val title: String
@Composable get() = stringResource(R.string.title_addDisplayName)
override val description: String
@Composable get() = stringResource(R.string.subtitle_addDisplayName)
override val icon: Painter
@Composable get() = rememberVectorPainter(Icons.Outlined.Edit)
}

class ProfilePicture(override val isCompleted: Boolean) : Profile {
override val title: String
@Composable get() = stringResource(R.string.title_addProfilePicture)
override val description: String
@Composable get() = stringResource(R.string.subtitle_addProfilePicture)
override val icon: Painter
@Composable get() = painterResource(R.drawable.ic_people_circle)
}

/**
* The fee another user has to pay to open a DM, stored on the profile as `minDmChatInitFee`.
* Completes once one is set; the row stays outstanding while the server default applies.
*/
class MinimumTip(override val isCompleted: Boolean = false) : Profile {
override val title: String
@Composable get() = stringResource(R.string.title_setMinimumTip)
override val description: String
@Composable get() = stringResource(R.string.subtitle_setMinimumTip)
override val icon: Painter
@Composable get() = painterResource(R.drawable.ic_coins)
}
}

@Composable
Expand Down Expand Up @@ -210,33 +167,3 @@ private fun OnboardingItemRow(
)
}
}

@Preview(name = "Finish Your Profile — nothing done")
@PreviewWrapper(FlipcashThemeWrapper::class)
@Composable
private fun PreviewFinishProfileEmpty() {
NewUserTutorial(
title = stringResource(R.string.title_finishYourProfile),
items = listOf(
TutorialItem.DisplayName(isCompleted = false),
TutorialItem.ProfilePicture(isCompleted = false),
TutorialItem.MinimumTip(),
),
onItemClicked = {},
)
}

@Preview(name = "Finish Your Profile — photo set")
@PreviewWrapper(FlipcashThemeWrapper::class)
@Composable
private fun PreviewFinishProfilePhotoSet() {
NewUserTutorial(
title = stringResource(R.string.title_finishYourProfile),
items = listOf(
TutorialItem.DisplayName(isCompleted = true),
TutorialItem.ProfilePicture(isCompleted = true),
TutorialItem.MinimumTip(),
),
onItemClicked = {},
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,20 @@ sealed interface AppRoute : NavKey, Parcelable {
data object AccountSelection : Menu
@Serializable
data object UserProfile : Menu

/**
* What to do with your own profile: share it, show its card, copy its link. A
* [com.getcode.navigation.WrapContentSheet], for the reason [Messaging.MuteChat] is one.
*/
@Serializable
data object ShareProfile :
Menu,
com.getcode.navigation.Sheet,
com.getcode.navigation.WrapContentSheet

/** Your profile card, full screen, with its Download action. */
@Serializable
data object ProfileCard : Menu
@Serializable
data class Lab(val onboarding: Boolean = false) : Menu
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<!-- IconChevronDownSmall — the mint selector on the New Public Group form (node 10127:118258).
A 24dp stroked chevron rather than the 16dp filled ic_chevron_down_medium, which reads much
heavier once scaled to sit beside 16sp text. -->
A 24dp stroked chevron, which sits lighter beside 16sp text than a filled 16dp one. -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
Expand Down
19 changes: 8 additions & 11 deletions apps/flipcash/core/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -552,16 +552,9 @@
<string name="title_scanTipCard">Scan a Tip Card</string>
<string name="subtitle_scanTipCard">Give your first tip</string>

<string name="title_finishYourProfile">Finish Your Profile</string>

<!-- Copy matches iOS's "Finish Your Profile" display-name step. -->
<string name="title_addDisplayName">Add your display name</string>
<string name="subtitle_addDisplayName">Choose the name people see in chat</string>
<string name="title_addProfilePicture">Add a profile picture</string>
<string name="subtitle_addProfilePicture">Select a photo from your gallery</string>

<string name="title_setMinimumTip">Set your minimum tip amount</string>
<string name="subtitle_setMinimumTip">Decide what size tip matters to you</string>

<string name="title_amountToBuy">Amount to Buy</string>
<string name="title_amountToSell">Amount to Sell</string>
Expand Down Expand Up @@ -1206,8 +1199,6 @@
<!-- The "You" tab's username progress card (nodes 9536:4336 / 9537:1845). -->
<string name="title_usernameUpsell">Get a custom @username</string>
<string name="subtitle_usernameUpsellLocked">Get your balance to %1$s or more to unlock</string>
<string name="subtitle_usernameUpsellUnlocked">Tap to select your username now</string>
<string name="label_usernameAmountToGo">%1$s to go</string>
<string name="error_title_usernameTaken">Username Taken</string>
<string name="error_description_usernameTaken">Please try a different username</string>
<!-- Moderation rejections reuse the display-name descriptions above, per the design. -->
Expand Down Expand Up @@ -1333,8 +1324,14 @@
<string name="title_tipOnboarding">Send Your First Tip</string>

<!-- You tab (tip card) -->
<string name="action_viewFullScreen">Full Screen</string>
<string name="action_closeFullScreen">Close</string>
<string name="action_editProfile">Edit Profile</string>
<string name="action_claimYourUsernameLink">Claim your username ›</string>
<string name="title_shareUserProfile">Share User Profile</string>
<!-- Who the share sheet is for: display name, then @handle -->
<string name="subtitle_shareUserProfile">%1$s · @%2$s</string>
<string name="action_shareProfileLink">Share Profile</string>
<string name="action_showProfileCard">Show Profile Card</string>
<string name="action_copyLink">Copy Link</string>
<string name="action_download">Download</string>
<string name="title_clipboardLabelTipCardLink">Tip Card Link</string>
<string name="title_clipboardLabelGroupInviteLink">Group Invite Link</string>
Expand Down
3 changes: 3 additions & 0 deletions apps/flipcash/features/menu/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@ android {
dependencies {
testImplementation(kotlin("test"))
testImplementation(libs.kotlinx.coroutines.test)
testImplementation(libs.robolectric)

implementation(libs.bundles.haze)

implementation(project(":apps:flipcash:shared:analytics"))
implementation(project(":apps:flipcash:shared:authentication"))
implementation(project(":apps:flipcash:shared:bills"))
implementation(project(":apps:flipcash:shared:common-ui"))
implementation(project(":apps:flipcash:shared:funding"))
implementation(project(":apps:flipcash:shared:payments"))
implementation(project(":apps:flipcash:shared:shareable"))
implementation(project(":apps:flipcash:shared:tipping"))
// Balance for the username gate only — :shared:tokens:core is the narrow half, so the
Expand Down
Loading
Loading