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
1 change: 1 addition & 0 deletions apps/flipcash/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ dependencies {
implementation(project(":apps:flipcash:shared:google-play-billing"))
implementation(project(":apps:flipcash:shared:currency-selection:core"))
implementation(project(":apps:flipcash:shared:currency-selection:ui"))
implementation(project(":apps:flipcash:shared:contacts"))
implementation(project(":apps:flipcash:shared:notifications"))
implementation(project(":apps:flipcash:shared:onramp:coinbase"))
implementation(project(":apps:flipcash:shared:onramp:deeplinks"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import com.flipcash.app.appsettings.LocalAppSettings
import com.flipcash.app.bill.customization.BillPlaygroundController
import com.flipcash.app.bill.customization.LocalBillPlaygroundController
import com.flipcash.app.billing.BillingClient
import com.flipcash.app.contacts.ContactCoordinator
import com.flipcash.app.contacts.LocalContactCoordinator
import com.flipcash.app.core.LocalUserManager
import com.flipcash.app.core.verification.email.EmailCodeChannel
import com.flipcash.app.core.verification.email.LocalEmailCodeChannel
Expand Down Expand Up @@ -115,6 +117,9 @@ class MainActivity : FragmentActivity() {
@Inject
lateinit var emailCodeChannel: EmailCodeChannel

@Inject
lateinit var contactCoordinator: ContactCoordinator

@Inject
lateinit var coinbaseOnRampController: CoinbaseOnRampController

Expand All @@ -141,6 +146,7 @@ class MainActivity : FragmentActivity() {
LocalBillPlaygroundController provides billPlaygroundController,
LocalAppUpdater provides appUpdater,
LocalEmailCodeChannel provides emailCodeChannel,
LocalContactCoordinator provides contactCoordinator,
LocalCoinbaseOnRampController provides coinbaseOnRampController,
LocalUiTesting provides intent.getBooleanExtra(UI_TEST, false),
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import com.flipcash.app.login.router.LoginRouter
import com.flipcash.app.login.seed.SeedInputScreen
import com.flipcash.app.menu.MenuScreen
import com.flipcash.app.myaccount.MyAccountScreen
import com.flipcash.app.permissions.ContactPermissionScreen
import com.flipcash.app.permissions.NotificationPermissionRationaleScreen
import com.flipcash.app.permissions.NotificationPermissionScreen
import com.flipcash.app.purchase.PurchaseAccountScreen
Expand Down Expand Up @@ -80,6 +81,7 @@ fun appEntryProvider(
annotatedEntry<AppRoute.Onboarding.AccessKey> { AccessKeyScreen() }
annotatedEntry<AppRoute.Onboarding.AccessKeySavedLocation> { PhotoAccessKeyScreen() }
annotatedEntry<AppRoute.Onboarding.Purchase> { key -> PurchaseAccountScreen(key.fromLogin) }
annotatedEntry<AppRoute.Onboarding.ContactPermission> { key -> ContactPermissionScreen(key.postCreate) }
annotatedEntry<AppRoute.Onboarding.NotificationPermission> { key -> NotificationPermissionScreen(key.postCreate) }
annotatedEntry<AppRoute.Onboarding.NotificationPermissionRationale> { key -> NotificationPermissionRationaleScreen(key.permanentlyDenied) }
annotatedEntry<AppRoute.Onboarding.CameraPermission> { }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ sealed interface AppRoute : NavKey, Parcelable {
@Serializable
data class Purchase(val fromLogin: Boolean = false) : Onboarding

@Serializable
data class ContactPermission(val postCreate: Boolean): Onboarding
@Serializable
data class NotificationPermission(val postCreate: Boolean = false) : Onboarding
@Serializable
Expand Down Expand Up @@ -88,6 +90,8 @@ sealed interface AppRoute : NavKey, Parcelable {
val includeEmail: Boolean = true,
val email: String? = null,
val emailVerificationCode: String? = null,
val target: AppRoute? = null,
val fullScreen: Boolean = false,
) : AppRoute, FlowRouteWithResult<VerificationResult> {
override val initialStack: List<NavKey>
get() = buildVerificationInitialStack(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,28 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import com.flipcash.core.R

@Composable
fun ScreenFrame(
modifier: Modifier = Modifier,
contentAlignment: Alignment = Alignment.TopCenter,
contents: @Composable () -> Unit,
) {
Box(modifier = modifier, contentAlignment = Alignment.TopCenter) {
Image(
painter = painterResource(id = R.drawable.ic_screen_frame),
contentDescription = "",
)
Box(
modifier = Modifier
.matchParentSize()
.clip(RoundedCornerShape(35.dp)),
contentAlignment = contentAlignment,
) {
contents()
}
}
}

@Composable
fun DeviceFrame(
modifier: Modifier = Modifier,
Expand Down
36 changes: 36 additions & 0 deletions apps/flipcash/core/src/main/res/drawable/ic_screen_frame.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<!--
~ Copyright (C) 2026 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="276dp"
android:height="475dp"
android:viewportWidth="276"
android:viewportHeight="475">
<path
android:pathData="M35,0L240.77,0A35,35 0,0 1,275.77 35L275.77,439.26A35,35 0,0 1,240.77 474.26L35,474.26A35,35 0,0 1,0 439.26L0,35A35,35 0,0 1,35 0z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="137.88"
android:startY="0"
android:endX="137.88"
android:endY="394.91"
android:type="linear">
<item android:offset="0" android:color="#0CFFFFFF"/>
<item android:offset="1" android:color="#00FFFFFF"/>
</gradient>
</aapt:attr>
</path>
</vector>
7 changes: 7 additions & 0 deletions apps/flipcash/core/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,13 @@
<string name="error_description_ignoredPushPermissions">You won\'t receive updates when your balance changes</string>
<string name="action_okAllow">Ok Allow</string>
<string name="action_imSure">I\'m Sure</string>
<string name="action_notNow">Not Now</string>

<string name="permissions_title_contacts">Find Your Friends</string>
<string name="permissions_description_contacts">Sync your contacts to find,\ninvite, and pay friends.</string>
<string name="action_giveAccessToContacts">Give Access To Contacts</string>
<string name="error_title_ignoredContactPermissions">Are You Sure?</string>
<string name="error_description_ignoredContactPermissions">You won\'t be able to send cash to your contacts</string>

<string name="subtitle_allowCameraAccess">Start your camera to grab cash</string>
<string name="action_allowCameraAccess">Start Camera</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,11 @@ fun VerificationFlowScreen(
route = route,
value = NavResultOrCanceled.ReturnValue(result),
)
outerNavigator.pop()
if (route.target != null && result is VerificationResult.Success) {
outerNavigator.replace(route.target!!)
} else {
outerNavigator.pop()
}
},
entryProvider = verificationEntryProvider(route),
)
Expand All @@ -59,13 +63,13 @@ private fun verificationEntryProvider(
VerificationFlowIntroContent(isForOnRamp = step.isForOnRamp)
}
annotatedEntry<VerificationStep.PhoneEntry> {
PhoneVerificationContent()
PhoneVerificationContent(isInModal = !route.fullScreen)
}
annotatedEntry<VerificationStep.PhoneCode> {
PhoneCodeContent(includeEmail = route.includeEmail)
PhoneCodeContent(includeEmail = route.includeEmail, isInModal = !route.fullScreen)
}
annotatedEntry<VerificationStep.PhoneCountryCode> {
PhoneCountryCodeContent()
PhoneCountryCodeContent(isInModal = !route.fullScreen)
}
annotatedEntry<VerificationStep.EmailEntry> {
EmailVerificationContent(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import kotlinx.coroutines.flow.onEach
@Composable
fun PhoneCodeContent(
includeEmail: Boolean,
isInModal: Boolean = true,
) {
val flowNavigator = rememberFlowNavigator<VerificationStep, VerificationResult>()
val viewModel = flowSharedViewModel<PhoneVerificationViewModel>()
Expand All @@ -34,7 +35,7 @@ fun PhoneCodeContent(
) {
AppBarWithTitle(
title = stringResource(R.string.title_enterTheCode),
isInModal = true,
isInModal = isInModal,
titleAlignment = Alignment.CenterHorizontally,
backButton = true,
onBackIconClicked = { flowNavigator.back() },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach

@Composable
fun PhoneCountryCodeContent() {
fun PhoneCountryCodeContent(isInModal: Boolean = true) {
val flowNavigator = rememberFlowNavigator<VerificationStep, VerificationResult>()
val viewModel = flowSharedViewModel<PhoneVerificationViewModel>()

Expand All @@ -30,7 +30,7 @@ fun PhoneCountryCodeContent() {
) {
AppBarWithTitle(
title = stringResource(R.string.title_verifyPhoneNumber),
isInModal = true,
isInModal = isInModal,
titleAlignment = Alignment.CenterHorizontally,
backButton = true,
onBackIconClicked = { flowNavigator.back() },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach

@Composable
fun PhoneVerificationContent() {
fun PhoneVerificationContent(isInModal: Boolean = true) {
val codeNavigator = LocalCodeNavigator.current
val flowNavigator = rememberFlowNavigator<VerificationStep, VerificationResult>()
val viewModel = flowSharedViewModel<PhoneVerificationViewModel>()
Expand All @@ -37,7 +37,7 @@ fun PhoneVerificationContent() {
) {
AppBarWithTitle(
title = stringResource(R.string.title_verifyPhoneNumber),
isInModal = true,
isInModal = isInModal,
titleAlignment = Alignment.CenterHorizontally,
backButton = true,
onBackIconClicked = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,16 +89,6 @@ internal fun LabsScreenContent(viewModel: LabsScreenViewModel) {
)
}

item { SectionHeader(stringResource(R.string.title_settingsSectionHomeScreen)) }
item {
ListItem(
headline = stringResource(R.string.title_settingsButtonOrder),
icon = painterResource(R.drawable.ic_bottom_navigation),
) {
navigator.navigate(AppRoute.Menu.NavBarSettings)
}
}

if (betaFlags.isEmpty()) {
item {
Box {
Expand Down Expand Up @@ -126,6 +116,16 @@ internal fun LabsScreenContent(viewModel: LabsScreenViewModel) {
}
}

item { SectionHeader(stringResource(R.string.title_settingsSectionHomeScreen)) }
item {
ListItem(
headline = stringResource(R.string.title_settingsButtonOrder),
icon = painterResource(R.drawable.ic_bottom_navigation),
) {
navigator.navigate(AppRoute.Menu.NavBarSettings)
}
}

if (isStaff) {
item { SectionHeader(stringResource(R.string.title_settingsSectionDeveloper)) }
item {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ sealed interface Button: AppAction {
override val value: String = "Button: Skip Push"
}

data object AllowContacts : Button {
override val value: String = "Button: Allow Contacts"
}

data object SkipContacts: Button {
override val value: String = "Button: Skip Contacts"
}

data object TokenBuyWithReserves : Button {
override val value: String = "Button: Buy With Reserves"
}
Expand Down
2 changes: 2 additions & 0 deletions apps/flipcash/shared/contacts/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
build/
.gradle/
23 changes: 23 additions & 0 deletions apps/flipcash/shared/contacts/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
plugins {
alias(libs.plugins.flipcash.android.feature)
}

android {
namespace = "${Gradle.flipcashNamespace}.shared.contacts"
}

dependencies {
testImplementation(kotlin("test"))
testImplementation(libs.bundles.unit.testing)
testImplementation(libs.robolectric)

implementation(project(":services:flipcash"))
implementation(project(":services:opencode"))
implementation(project(":apps:flipcash:shared:persistence:db"))
implementation(project(":apps:flipcash:shared:phone"))
implementation(project(":apps:flipcash:shared:featureflags"))
implementation(project(":libs:encryption:keys"))
implementation(project(":libs:network:connectivity:public"))
implementation(libs.androidx.lifecycle.process)
implementation(libs.bundles.room)
}
8 changes: 8 additions & 0 deletions apps/flipcash/shared/contacts/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<uses-permission android:name="android.permission.READ_CONTACTS" />
<application>

</application>

</manifest>
Loading
Loading