Skip to content

Commit b68b900

Browse files
committed
feat(flipcash): add share download link sheet
Signed-off-by: Brandon McAnsh <git@bmcreations.dev>
1 parent a5401d2 commit b68b900

27 files changed

Lines changed: 619 additions & 165 deletions

File tree

apps/flipcash/app/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ dependencies {
119119
implementation(project(":apps:flipcash:shared:currency-selection:core"))
120120
implementation(project(":apps:flipcash:shared:currency-selection:ui"))
121121
implementation(project(":apps:flipcash:shared:permissions"))
122+
implementation(project(":apps:flipcash:shared:shareable"))
122123
implementation(project(":apps:flipcash:features:login"))
123124
implementation(project(":apps:flipcash:features:purchase"))
124125
implementation(project(":apps:flipcash:features:scanner"))
@@ -130,6 +131,7 @@ dependencies {
130131
implementation(project(":apps:flipcash:features:deposit"))
131132
implementation(project(":apps:flipcash:features:myaccount"))
132133
implementation(project(":apps:flipcash:features:backupkey"))
134+
implementation(project(":apps:flipcash:features:shareapp"))
133135

134136
implementation(project(":libs:datetime"))
135137
implementation(project(":libs:locale:bindings"))

apps/flipcash/app/src/main/kotlin/com/flipcash/app/App.kt

Lines changed: 90 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import androidx.compose.runtime.mutableStateOf
1313
import androidx.compose.runtime.remember
1414
import androidx.compose.runtime.setValue
1515
import androidx.compose.ui.Modifier
16+
import androidx.compose.ui.res.stringResource
17+
import androidx.compose.ui.unit.dp
1618
import androidx.lifecycle.Lifecycle
1719
import cafe.adriel.voyager.core.registry.ScreenRegistry
1820
import cafe.adriel.voyager.core.stack.StackEvent
@@ -29,12 +31,15 @@ import com.flipcash.app.session.LocalSessionController
2931
import com.flipcash.app.theme.FlipcashTheme
3032
import com.flipcash.app.ui.navigation.AppScreenContent
3133
import com.flipcash.app.ui.navigation.MainRoot
34+
import com.flipcash.features.shareapp.R
3235
import com.flipcash.services.modals.ModalManager
36+
import com.getcode.libs.qr.rememberQrBitmapPainter
3337
import com.getcode.navigation.core.BottomSheetNavigator
3438
import com.getcode.navigation.core.CombinedNavigator
3539
import com.getcode.navigation.core.LocalCodeNavigator
3640
import com.getcode.navigation.extensions.getActivityScopedViewModel
3741
import com.getcode.navigation.transitions.SheetSlideTransition
42+
import com.getcode.theme.CodeTheme
3843
import com.getcode.theme.LocalCodeColors
3944
import com.getcode.ui.components.OnLifecycleEvent
4045
import com.getcode.ui.components.bars.BottomBarContainer
@@ -75,111 +80,119 @@ fun App(
7580
val userState by userManager.state.collectAsState()
7681

7782
FlipcashTheme {
83+
// save download QR early
84+
rememberQrBitmapPainter(
85+
content = stringResource(
86+
R.string.app_download_link,
87+
stringResource(id = R.string.app_download_link_qr_ref)
88+
),
89+
size = CodeTheme.dimens.screenWidth * 0.60f,
90+
padding = 0.25.dp
91+
)
92+
7893
val barManager = rememberBarManager()
7994
AppScreenContent {
80-
// TODO: create PaymentScaffold for flipcash
81-
// PaymentScaffold {
82-
TipScaffold(tipsEngine = tipsEngine) {
83-
ScrimSupport {
84-
AppNavHost {
85-
val codeNavigator = LocalCodeNavigator.current
86-
CodeScaffold { innerPaddingModifier ->
87-
Navigator(
88-
screen = MainRoot { deepLink },
89-
) { navigator ->
90-
LaunchedEffect(navigator.lastItem) {
91-
// update global navigator for platform access to support push/pop from a single
92-
// navigator current
93-
codeNavigator.screensNavigator = navigator
94-
}
95+
TipScaffold(tipsEngine = tipsEngine) {
96+
ScrimSupport {
97+
AppNavHost {
98+
val codeNavigator = LocalCodeNavigator.current
99+
CodeScaffold { innerPaddingModifier ->
100+
Navigator(
101+
screen = MainRoot { deepLink },
102+
) { navigator ->
103+
LaunchedEffect(navigator.lastItem) {
104+
// update global navigator for platform access to support push/pop from a single
105+
// navigator current
106+
codeNavigator.screensNavigator = navigator
107+
}
95108

96-
Box(
97-
modifier = Modifier
98-
.padding(innerPaddingModifier)
99-
) {
100-
101-
when (navigator.lastEvent) {
102-
StackEvent.Push,
103-
StackEvent.Pop -> {
104-
when (navigator.lastItem) {
105-
ScreenRegistry.get(NavScreenProvider.Login.SeedInput),
106-
ScreenRegistry.get(NavScreenProvider.Permissions.Camera()),
107-
is MainRoot -> {
108-
CrossfadeTransition(navigator = navigator)
109-
}
110-
111-
else -> SlideTransition(navigator = navigator)
109+
Box(
110+
modifier = Modifier
111+
.padding(innerPaddingModifier)
112+
) {
113+
114+
when (navigator.lastEvent) {
115+
StackEvent.Push,
116+
StackEvent.Pop -> {
117+
when (navigator.lastItem) {
118+
ScreenRegistry.get(NavScreenProvider.Login.SeedInput),
119+
ScreenRegistry.get(NavScreenProvider.Permissions.Camera()),
120+
is MainRoot -> {
121+
CrossfadeTransition(navigator = navigator)
112122
}
113-
}
114123

115-
StackEvent.Idle,
116-
StackEvent.Replace -> CurrentScreen()
124+
else -> SlideTransition(navigator = navigator)
125+
}
117126
}
127+
128+
StackEvent.Idle,
129+
StackEvent.Replace -> CurrentScreen()
118130
}
131+
}
119132

120-
LaunchedEffect(deepLink) {
121-
if (codeNavigator.lastItem !is MainRoot) {
122-
if (deepLink != null) {
123-
val screenSet = router.processDestination(deepLink)
124-
if (screenSet.isNotEmpty()) {
125-
codeNavigator.replaceAll(screenSet)
126-
}
133+
LaunchedEffect(deepLink) {
134+
if (codeNavigator.lastItem !is MainRoot) {
135+
if (deepLink != null) {
136+
val screenSet = router.processDestination(deepLink)
137+
if (screenSet.isNotEmpty()) {
138+
codeNavigator.replaceAll(screenSet)
127139
}
128140
}
129141
}
142+
}
130143

131-
LaunchedEffect(loginRequest) {
132-
loginRequest?.let { entropy ->
133-
viewModel.handleLoginEntropy(
134-
entropy,
135-
onSwitchAccount = {
136-
loginRequest = null
137-
codeNavigator.replaceAll(
138-
ScreenRegistry.get(
139-
NavScreenProvider.Login.Home(
140-
entropy
141-
)
144+
LaunchedEffect(loginRequest) {
145+
loginRequest?.let { entropy ->
146+
viewModel.handleLoginEntropy(
147+
entropy,
148+
onSwitchAccount = {
149+
loginRequest = null
150+
codeNavigator.replaceAll(
151+
ScreenRegistry.get(
152+
NavScreenProvider.Login.Home(
153+
entropy
142154
)
143155
)
144-
},
145-
onCancel = {
146-
loginRequest = null
147-
}
148-
)
149-
}
156+
)
157+
},
158+
onCancel = {
159+
loginRequest = null
160+
}
161+
)
150162
}
163+
}
151164

152-
LaunchedEffect(userState.isTimelockUnlocked) {
153-
if (userState.isTimelockUnlocked) {
154-
codeNavigator.replaceAll(
155-
ScreenRegistry.get(
156-
NavScreenProvider.AppRestricted(RestrictionType.TIMELOCK_UNLOCKED)
157-
)
165+
LaunchedEffect(userState.isTimelockUnlocked) {
166+
if (userState.isTimelockUnlocked) {
167+
codeNavigator.replaceAll(
168+
ScreenRegistry.get(
169+
NavScreenProvider.AppRestricted(RestrictionType.TIMELOCK_UNLOCKED)
158170
)
159-
}
171+
)
160172
}
173+
}
161174

162-
OnLifecycleEvent { _, event ->
163-
when (event) {
164-
Lifecycle.Event.ON_RESUME -> {
165-
session.onAppInForeground()
166-
}
167-
168-
Lifecycle.Event.ON_STOP,
169-
Lifecycle.Event.ON_DESTROY -> {
170-
session.onAppInBackground()
171-
}
175+
OnLifecycleEvent { _, event ->
176+
when (event) {
177+
Lifecycle.Event.ON_RESUME -> {
178+
session.onAppInForeground()
179+
}
172180

173-
else -> Unit
181+
Lifecycle.Event.ON_STOP,
182+
Lifecycle.Event.ON_DESTROY -> {
183+
session.onAppInBackground()
174184
}
185+
186+
else -> Unit
175187
}
176188
}
177189
}
178190
}
179191
}
180192
}
181-
// }
193+
}
182194
}
195+
183196
TopBarContainer(barManager.barMessages)
184197
BottomBarContainer(barManager.barMessages)
185198
}

apps/flipcash/app/src/main/kotlin/com/flipcash/app/MainActivity.kt

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import com.flipcash.app.router.LocalRouter
1515
import com.flipcash.app.session.SessionController
1616
import com.flipcash.app.router.Router
1717
import com.flipcash.app.session.LocalSessionController
18+
import com.flipcash.app.shareable.LocalShareController
19+
import com.flipcash.app.shareable.ShareSheetController
1820
import com.flipcash.services.LocalBillingClient
1921
import com.flipcash.services.billing.BillingClient
2022
import com.flipcash.services.user.UserManager
@@ -71,16 +73,16 @@ class MainActivity : FragmentActivity() {
7173

7274
@Inject
7375
lateinit var exchange: Exchange
74-
//
75-
// @Inject
76-
// lateinit var paymentController: PaymentController
77-
//
76+
7877
@Inject
7978
lateinit var billing: BillingClient
8079

8180
@Inject
8281
lateinit var permissionChecker: PermissionChecker
8382

83+
@Inject
84+
lateinit var shareController: ShareSheetController
85+
8486
override fun onCreate(savedInstanceState: Bundle?) {
8587
super.onCreate(savedInstanceState)
8688
handleUncaughtException()
@@ -97,9 +99,9 @@ class MainActivity : FragmentActivity() {
9799
LocalRouter provides router,
98100
LocalUserManager provides userManager,
99101
LocalSessionController provides sessionController,
100-
// LocalPaymentController provides paymentController,
101102
LocalBillingClient provides billing,
102103
LocalPermissionChecker provides permissionChecker,
104+
LocalShareController provides shareController
103105
) {
104106
Rinku {
105107
App(tipsEngine = tipsEngine)

apps/flipcash/app/src/main/kotlin/com/flipcash/app/ui/navigation/AppScreenContent.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import com.flipcash.app.permissions.NotificationPermissionScreen
2020
import com.flipcash.app.purchase.PurchaseAccountScreen
2121
import com.flipcash.app.scanner.ScannerScreen
2222
import com.flipcash.app.send.SendScreen
23+
import com.flipcash.app.shareapp.ShareAppScreen
2324

2425

2526
@Composable
@@ -68,6 +69,10 @@ fun AppScreenContent(content: @Composable () -> Unit) {
6869
register<NavScreenProvider.HomeScreen.CurrencySelection> {
6970
CurrencySelectionModal(it.kind)
7071
}
72+
73+
register<NavScreenProvider.HomeScreen.ShareApp> {
74+
ShareAppScreen()
75+
}
7176

7277
register<NavScreenProvider.HomeScreen.Menu.Root> {
7378
MenuScreen()

apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/NavScreenProvider.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ sealed class NavScreenProvider : ScreenProvider {
2828
data object Give : NavScreenProvider()
2929
data object Send : NavScreenProvider()
3030
data object Balance : NavScreenProvider()
31+
32+
data object ShareApp: NavScreenProvider()
33+
3134
sealed class Menu {
3235
data object Root : NavScreenProvider()
3336
data object Deposit : NavScreenProvider()

apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/android/IntentUtils.kt

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -32,23 +32,4 @@ object IntentUtils {
3232

3333
return shareIntent
3434
}
35-
36-
fun cashLink(
37-
entropy: String,
38-
formattedAmount: String,
39-
): Intent {
40-
val url = Linkify.cashLink(entropy)
41-
val text = "$formattedAmount $url"
42-
43-
val sendIntent: Intent = Intent().apply {
44-
action = Intent.ACTION_SEND
45-
putExtra(Intent.EXTRA_TEXT, text)
46-
type = "text/plain"
47-
}
48-
val shareIntent = Intent.createChooser(sendIntent, null).apply {
49-
flags = Intent.FLAG_ACTIVITY_NEW_TASK
50-
}
51-
52-
return shareIntent
53-
}
5435
}

apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/android/extensions/Context.kt

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,6 @@ fun Context.launchAppSettings() {
1616
ContextCompat.startActivity(this, intent, null)
1717
}
1818

19-
fun Context.shareDownloadLink() {
20-
val shareRef = getString(R.string.app_download_link_share_ref)
21-
val url = getString(R.string.app_download_link_with_ref, shareRef)
22-
val intent = IntentUtils.share(url)
23-
ContextCompat.startActivity(this, intent, null)
24-
}
25-
2619
fun Context.uriToBitmap(uri: Uri): Bitmap? {
2720
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
2821
val source = ImageDecoder.createSource(contentResolver, uri)

apps/flipcash/core/src/main/res/values/strings.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,4 +87,7 @@
8787
<string name="title_clipboardLabelAccountId">Account ID</string>
8888

8989
<string name="prompt_description_viewAccessKey">Your Access Key will grant access to your Flipcash account. Keep it private and safe.</string>
90+
91+
<string name="subtitle_scanThisQRCode">Scan this QR code with your phone\'s camera to download the Flipcash app</string>
92+
<string name="subtitle_scanToDownload">Scan to download the\nFlipcash app</string>
9093
</resources>

apps/flipcash/features/purchase/src/main/kotlin/com/flipcash/app/purchase/internal/PurchaseAccountViewModel.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ internal class PurchaseAccountViewModel @Inject constructor(
137137
.mapNotNull { it.costOfAccount }
138138
.map { it.amount to (CurrencyCode.tryValueOf(it.currency) ?: CurrencyCode.USD) }
139139
.map { (amount, currency) -> Fiat(amount, currency) }
140-
.onEach { dispatchEvent(Event.OnPriceFormatted(it.formatted(truncated = true))) }
140+
.onEach { dispatchEvent(Event.OnPriceFormatted(it.formatted(truncate = true))) }
141141
.launchIn(viewModelScope)
142142

143143
eventFlow

0 commit comments

Comments
 (0)