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

Patron - Add icons #953

Merged
merged 11 commits into from May 12, 2023
Merged

Patron - Add icons #953

merged 11 commits into from May 12, 2023

Conversation

ashiagr
Copy link
Contributor

@ashiagr ashiagr commented May 11, 2023

Description

This adds icons Patron icons and starts upsell flow to show only Patron plans.

Testing Instructions

Test.1 Feature Flag disabled

  1. Launch the app without being logged in
  2. Go to Profile -> Settings -> Appearance
  3. ✅ Notice there are no Patron app icons

Test.2 Feature Flag enabled - Plus only

  1. Enable the feature flag for Patron
  2. Login with a Plus account
  3. Go to Profile -> Settings -> Appearance
  4. Notice that Patron app icons are disabled
  5. Tap on a Patron app icon
  6. ✅ Notice that Upsell flow starts with only Patron plans

Test.3 Feature Flag enabled - Patron

  1. Enable the feature flag and SignInState for Patron
  2. Install the app
  3. Login with Plus account
  4. Go to Profile -> Settings -> Appearance
  5. Notice that Patron app icons are enabled
  6. Tap on a Patron icon
  7. ✅ Notice that you can now change the icon

Screenshots or Screencast

Plus and Patron disabled Plus enabled and Patron Disabled Patron enabled
0 Screenshot_20230511_182005 1 Screenshot_20230511_182051 2 Screenshot_20230511_182131
Screen_recording_20230511_182351.mp4

Checklist

  • If this is a user-facing change, I have added an entry in CHANGELOG.md
  • I have considered whether it makes sense to add tests for my changes
  • All strings that need to be localized are in modules/services/localization/src/main/res/values/strings.xml
  • Any jetpack compose components I added or changed are covered by compose previews

I have tested any UI changes...

  • with different themes
  • with a landscape orientation
  • with the device set to have a large display and font size
  • for accessibility with TalkBack

@ashiagr ashiagr added the patron label May 11, 2023
// The route variable should only be used to navigate to the PlusUpgrade screens
// when they are the startDestination. In all other cases, use the routeWithSource function.
const val route = "$routeBase/{$sourceArgumentKey}"
const val route = "$routeBase/{$sourceArgumentKey}/{$showPatronOnlyArgumentKey}"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm passing showPatronOnly boolean as another argument in the upsell flow so that I can access it in OnboardingUpgradeFeaturesViewModel init and show only the Patron plans if the key is set.

Copy link
Contributor

Choose a reason for hiding this comment

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

Am I right that we don't actually pass this argument when we navigate, but instead we're just using the default value (and we have some logic to intelligently set the default)? If so, that feels a bit confusing to me.

I've definitely run into this issue of how best to get some data from the compose layer to the view model, and it doesn't seem like there's a clear best approach. I wonder if it would be worth directly passing the flow to the view model here in the composable's lambda parameter with something like this (untested) code:

val viewModel = hiltViewModel<OnboardingUpgradeFeaturesViewModel>()
LaunchedEffect(flow) {
    viewModel.setFlow(flow)
}

What you have is working fine though, so feel free to leave it as-is if you prefer. I'm still not sure how best to handle this tbh.

Copy link
Contributor

@mchowning mchowning May 11, 2023

Choose a reason for hiding this comment

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

Thinking about this some more, It seems like my suggestion would break if multiple views were using this view model (probably not an issue in this case, but as a general matter could be a problem) since currently it is not possible to scope a view model to a particular composable. 🤔

I'm thinking about this more because I have the same issue, but I can't use navigation arguments for my use case really (well, I could, but it would be pretty hacky and hard to understand). Looks like this might be a possibility as well, but I think it's too complicated for me for now. Just sharing this as additional info, it's probably not really applicable to what you're doing here.

While I'm saving links, here is a relevant discussion issue about not currently being able to use assisted injection with hilt.

Copy link
Contributor Author

@ashiagr ashiagr May 12, 2023

Choose a reason for hiding this comment

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

I've definitely run into this issue of how best to get some data from the Compose layer to the view model, and it doesn't seem like there's a clear best approach.

That's true. Passing objects via routes from Compose layer to view model is currently not supported. There are hacks to do so using custom nav type and json string <-> object conversion but passing complex data is considered an anti-pattern. I also considered using assisted variables in HiltViewModel but as you pointed it is currently not supported for Compose.

Am I right that we don't actually pass this argument when we navigate, but instead we're just using the default value (and we have some logic to intelligently set the default)? If so, that feels a bit confusing to me.

I understand what you're saying but I wasn't able to find a simpler solution. The approach I took in this PR follows official guidelines to pass nav args similar to how they are passed in "implicit" deep links. Default values are set as arguments for a start destination, the navigation component parses them based on the deep-link-like route that we provide and allows us to access them using saveStateHandle in the view model.

The Navigation component attempts to parse the placeholder values into appropriate types by matching placeholder names to the defined arguments that are defined for the deep link destination.

It is also explained here. Since I require simple boolean and string sources in the view model, sending them using routes fits my case.

To make it more natural so that the route looks closer to a deep-link-like structure, I made showPatronOnly an optional param and added a comment linking the documentation to help understand it in f6f5a8a

New: "$routeBase/{$sourceArgumentKey}?{$showPatronOnlyArgumentKey}={$showPatronOnlyArgumentKey}"
Vs 
Old: "$routeBase/{$sourceArgumentKey}/{$showPatronOnlyArgumentKey}"

Maybe I should also convert the source string to an optional one. 🤔

thinking about this more because I have the same issue, but I can't use navigation arguments for my use case really (well, I could, but it would be pretty hacky and hard to understand).

The recommended approach to getting complex data in view models is getting them using the data layer like through a repository. Lmk your use case though I'm not sure if there are good options currently.

@ashiagr ashiagr marked this pull request as ready for review May 11, 2023 13:43
@ashiagr ashiagr requested a review from a team as a code owner May 11, 2023 13:43
Copy link
Contributor

@mchowning mchowning left a comment

Choose a reason for hiding this comment

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

Nice work! 👍

Comment on lines 52 to +53
private val source = savedStateHandle.get<OnboardingUpgradeSource>("source")
private val showPatronOnly = savedStateHandle.get<Boolean>("show_patron_only")
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of hardcoding these, I think it would be good to reuse the variables from OnboardingNavRoute. In addition to ensuring they stay consistent, this also makes it easier to use code navigation to see where this argument is being set and used.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Already tried but there's a cyclic dependency between the account and profile modules 😞

// The route variable should only be used to navigate to the PlusUpgrade screens
// when they are the startDestination. In all other cases, use the routeWithSource function.
const val route = "$routeBase/{$sourceArgumentKey}"
const val route = "$routeBase/{$sourceArgumentKey}/{$showPatronOnlyArgumentKey}"
Copy link
Contributor

Choose a reason for hiding this comment

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

Am I right that we don't actually pass this argument when we navigate, but instead we're just using the default value (and we have some logic to intelligently set the default)? If so, that feels a bit confusing to me.

I've definitely run into this issue of how best to get some data from the compose layer to the view model, and it doesn't seem like there's a clear best approach. I wonder if it would be worth directly passing the flow to the view model here in the composable's lambda parameter with something like this (untested) code:

val viewModel = hiltViewModel<OnboardingUpgradeFeaturesViewModel>()
LaunchedEffect(flow) {
    viewModel.setFlow(flow)
}

What you have is working fine though, so feel free to leave it as-is if you prefer. I'm still not sure how best to handle this tbh.

@ashiagr
Copy link
Contributor Author

ashiagr commented May 12, 2023

@mchowning I'm merging this PR, feel free to suggest any changes and I'll take it up in another PR.
Thank you so much for discussing the nav-args issue. 🙏

@ashiagr ashiagr merged commit 66e3d73 into main May 12, 2023
8 checks passed
@ashiagr ashiagr deleted the task/patron-icons branch May 12, 2023 13:00
ashiagr added a commit that referenced this pull request Jun 5, 2023
This reverts commit 66e3d73, reversing
changes made to 68f19c9.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants