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.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.flipcash.app.analytics.Button
import com.flipcash.app.core.AppRoute
import com.flipcash.app.core.send.SendResult
import com.flipcash.app.core.send.SendStep
Expand All @@ -28,6 +29,7 @@ import com.flipcash.app.directsend.internal.screens.components.ContactList
import com.flipcash.app.permissions.ContactAccessResult
import com.flipcash.app.permissions.rememberContactAccessHandle
import com.flipcash.features.directsend.R
import com.getcode.libs.analytics.LocalAnalytics
import com.getcode.navigation.flow.LocalOuterCodeNavigator
import com.getcode.navigation.flow.flowSharedViewModel
import com.getcode.navigation.flow.rememberFlowNavigator
Expand All @@ -47,6 +49,7 @@ internal fun ContactListScreen() {
val flowNavigator = rememberFlowNavigator<SendStep, SendResult>()
val viewModel = flowSharedViewModel<SendFlowViewModel>()
val navigator = LocalOuterCodeNavigator.current
val analytics = LocalAnalytics.current

val state by viewModel.stateFlow.collectAsStateWithLifecycle()

Expand All @@ -72,6 +75,14 @@ internal fun ContactListScreen() {
isPickerMode = state.isPickerMode,
) { result ->
when (result) {
ContactAccessResult.Granted -> {
// Granting via the in-list rationale card kicks off the same contact
// sync the permission gate does; otherwise the newly-allowed contacts
// are never fetched.
analytics.action(Button.AllowContacts)
viewModel.dispatchEvent(SendFlowViewModel.Event.ContactsGranted)
}

is ContactAccessResult.Picked -> {
viewModel.dispatchEvent(SendFlowViewModel.Event.ContactsPicked(result.contacts))
}
Expand Down Expand Up @@ -161,8 +172,8 @@ internal fun ContactListScreen() {
items = state.listItems,
searchState = state.searchState,
listState = listState,
accessHandle = accessHandle,
isPickerMode = state.isPickerMode,
onAddMoreContacts = { accessHandle.launch() },
onItemClick = { contact ->
viewModel.dispatchEvent(SendFlowViewModel.Event.OnContactClicked(contact))
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,16 @@ internal fun ContactsPermissionGateScreen() {
// If this step has been removed from the flow (e.g. chats arrived while we're
// on this screen, or on re-open when chats already exist), advance immediately.
// FlowNavigator.proceed() handles removed steps by replacing with the first remaining step.
//
// Exception: while a sync is actively running (the user just granted access),
// the device contacts land first and remove this gate from the steps, but the
// on-Flipcash contacts are fetched in a second pass. If we advanced now, the list
// would render with only the "not on Flipcash" section, then prepend the
// on-Flipcash contacts above the viewport once they arrive — pushing them
// offscreen. Let ContactSyncComplete drive navigation instead so the list is
// fully formed before it's shown.
val gateStillInSteps = state.steps.any { it is SendStep.ContactsGate }
if (!gateStillInSteps) {
if (!gateStillInSteps && !state.contactSyncState.loading) {
LaunchedEffect(Unit) { flowNavigator.proceed() }
return
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ import com.flipcash.app.contacts.ui.ContactAvatar
import com.flipcash.app.core.android.extensions.launchAppSettings
import com.flipcash.app.core.contacts.DeviceContact
import com.flipcash.app.directsend.internal.ContactListItem
import com.flipcash.app.permissions.rememberContactAccessHandle
import com.flipcash.app.permissions.ContactAccessHandle
import com.flipcash.app.theme.FlipcashThemeWrapper
import com.flipcash.features.directsend.R
import com.flipcash.shared.chat.ui.AnimatedConversationPaymentsPreview
Expand All @@ -65,16 +65,13 @@ internal fun ContactList(
items: List<ContactListItem>,
searchState: TextFieldState,
listState: LazyListState,
accessHandle: ContactAccessHandle,
modifier: Modifier = Modifier,
isPickerMode: Boolean = false,
onAddMoreContacts: () -> Unit = {},
onItemClick: (ContactListItem.ContactRow) -> Unit = {},
onItemDismissed: (ContactListItem.ContactRow) -> Unit = {},
) {
val context = LocalContext.current
val accessHandle = rememberContactAccessHandle(
isPickerMode = isPickerMode,
)

LazyColumn(
modifier = Modifier
Expand Down Expand Up @@ -188,7 +185,7 @@ internal fun ContactList(
if (isPickerMode) {
item {
PickerModeHeader(
onAddMoreContacts = onAddMoreContacts,
onAddMoreContacts = { accessHandle.launch() },
)
}
}
Expand Down Expand Up @@ -563,5 +560,6 @@ private fun ContactListPreview() {
items = items,
searchState = TextFieldState(),
listState = rememberLazyListState(),
accessHandle = ContactAccessHandle(launch = {}),
)
}
Loading