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
71 changes: 71 additions & 0 deletions apps/flipcash/core/src/main/res/drawable/ic_tipcode.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="20dp"
android:height="20dp"
android:viewportWidth="20"
android:viewportHeight="20">
<path
android:pathData="M6.26,17.549C6.413,17.346 6.688,17.281 6.921,17.38C8.047,17.857 9.287,18.075 10.552,17.985C10.804,17.967 11.042,18.116 11.122,18.356C11.225,18.669 11.021,19.001 10.693,19.027C9.212,19.145 7.759,18.888 6.447,18.32C6.146,18.19 6.062,17.812 6.26,17.549Z"
android:strokeAlpha="0.5"
android:fillColor="#ffffff"
android:fillAlpha="0.5"/>
<path
android:pathData="M18.196,11.688C18.532,11.683 18.788,11.987 18.702,12.312C18.127,14.497 16.748,16.42 14.815,17.65C14.536,17.827 14.175,17.684 14.072,17.371C13.993,17.131 14.095,16.87 14.307,16.732C15.971,15.655 17.161,13.993 17.674,12.106C17.739,11.867 17.949,11.692 18.196,11.688Z"
android:strokeAlpha="0.5"
android:fillColor="#ffffff"
android:fillAlpha="0.5"/>
<path
android:pathData="M1.944,12.917C2.225,12.761 2.577,12.896 2.704,13.191C2.984,13.842 3.345,14.441 3.769,14.979C3.925,15.176 3.937,15.455 3.785,15.656C3.587,15.919 3.198,15.939 2.993,15.683C2.48,15.043 2.049,14.326 1.719,13.543C1.621,13.309 1.722,13.041 1.944,12.917Z"
android:strokeAlpha="0.5"
android:fillColor="#ffffff"
android:fillAlpha="0.5"/>
<path
android:pathData="M17.397,5.917C17.653,5.749 17.997,5.834 18.128,6.11C18.359,6.599 18.549,7.115 18.693,7.657C18.918,8.501 19.015,9.349 18.998,10.182C18.993,10.451 18.77,10.661 18.5,10.665C18.194,10.67 17.952,10.41 17.956,10.103C17.965,9.385 17.879,8.655 17.685,7.928C17.563,7.469 17.402,7.03 17.209,6.614C17.094,6.366 17.168,6.067 17.397,5.917Z"
android:strokeAlpha="0.5"
android:fillColor="#ffffff"
android:fillAlpha="0.5"/>
<path
android:pathData="M2.706,5.783C2.917,5.941 2.976,6.232 2.86,6.47C2.264,7.689 1.973,9.065 2.057,10.473C2.07,10.687 1.964,10.894 1.776,10.998C1.451,11.18 1.046,10.981 1.021,10.609C0.909,8.969 1.247,7.365 1.951,5.951C2.092,5.668 2.454,5.594 2.706,5.783Z"
android:strokeAlpha="0.5"
android:fillColor="#ffffff"
android:fillAlpha="0.5"/>
<path
android:pathData="M16.17,4.006C16.379,3.868 16.658,3.899 16.82,4.09C17.015,4.319 16.955,4.666 16.703,4.832L16.651,4.866C16.449,4.999 16.18,4.951 16.022,4.769C15.831,4.548 15.868,4.204 16.112,4.043L16.17,4.006Z"
android:strokeAlpha="0.5"
android:fillColor="#ffffff"
android:fillAlpha="0.5"/>
<path
android:pathData="M8.878,1.644C8.774,1.331 8.978,0.999 9.307,0.973C11.337,0.812 13.313,1.355 14.947,2.436C15.252,2.638 15.233,3.08 14.927,3.281C14.742,3.403 14.503,3.396 14.318,3.276C12.9,2.356 11.198,1.89 9.448,2.015C9.195,2.033 8.957,1.884 8.878,1.644Z"
android:strokeAlpha="0.5"
android:fillColor="#ffffff"
android:fillAlpha="0.5"/>
<path
android:pathData="M5.927,2.629C6.007,2.869 5.904,3.13 5.692,3.268C4.969,3.736 4.335,4.314 3.808,4.974C3.622,5.205 3.287,5.261 3.05,5.084C2.825,4.914 2.773,4.595 2.948,4.373C3.568,3.586 4.321,2.899 5.184,2.349C5.463,2.172 5.824,2.316 5.927,2.629Z"
android:strokeAlpha="0.5"
android:fillColor="#ffffff"
android:fillAlpha="0.5"/>
<path
android:pathData="M6.681,14.826C6.859,14.707 7.09,14.708 7.276,14.814C8.491,15.511 9.968,15.746 11.425,15.353C11.82,15.247 12.193,15.099 12.542,14.917C12.847,14.757 13.24,14.896 13.335,15.227C13.396,15.443 13.308,15.676 13.111,15.784C12.67,16.023 12.196,16.216 11.691,16.352C9.925,16.828 8.135,16.528 6.677,15.66C6.362,15.473 6.375,15.03 6.681,14.826Z"
android:strokeAlpha="0.5"
android:fillColor="#ffffff"
android:fillAlpha="0.5"/>
<path
android:pathData="M13.625,5.095C13.803,4.903 14.099,4.876 14.295,5.048C15.242,5.877 15.962,6.988 16.311,8.299C16.662,9.616 16.588,10.946 16.176,12.144C16.007,12.633 15.37,12.566 15.229,12.069C15.195,11.95 15.2,11.824 15.238,11.706C15.555,10.723 15.604,9.639 15.319,8.567C15.031,7.489 14.447,6.571 13.678,5.878C13.452,5.674 13.416,5.319 13.625,5.095Z"
android:strokeAlpha="0.5"
android:fillColor="#ffffff"
android:fillAlpha="0.5"/>
<path
android:pathData="M6.168,5.321C6.353,5.54 6.322,5.868 6.118,6.072C4.767,7.426 4.153,9.448 4.681,11.435C4.729,11.616 4.786,11.792 4.851,11.963C4.942,12.205 4.867,12.484 4.652,12.628C4.391,12.802 4.036,12.708 3.922,12.417C3.832,12.186 3.754,11.947 3.689,11.702C3.053,9.314 3.81,6.881 5.459,5.274C5.661,5.077 5.985,5.106 6.168,5.321Z"
android:strokeAlpha="0.5"
android:fillColor="#ffffff"
android:fillAlpha="0.5"/>
<path
android:pathData="M8.309,3.65C8.829,3.51 9.352,3.438 9.867,3.427C10.32,3.418 10.513,3.946 10.204,4.279C10.096,4.395 9.945,4.459 9.788,4.465C9.386,4.48 8.98,4.54 8.575,4.649C8.244,4.739 7.929,4.856 7.631,4.999C7.402,5.109 7.124,5.063 6.96,4.87C6.753,4.625 6.812,4.251 7.1,4.108C7.48,3.919 7.884,3.765 8.309,3.65Z"
android:strokeAlpha="0.5"
android:fillColor="#ffffff"
android:fillAlpha="0.5"/>
<path
android:pathData="M13.329,9.99C13.329,11.806 11.855,13.279 10.038,13.279C8.22,13.279 6.747,11.806 6.747,9.99C6.747,8.174 8.22,6.701 10.038,6.701C11.855,6.701 13.329,8.174 13.329,9.99Z"
android:strokeAlpha="0.5"
android:fillColor="#ffffff"
android:fillAlpha="0.5"/>
</vector>
1 change: 1 addition & 0 deletions apps/flipcash/core/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -896,5 +896,6 @@
<string name="subtitle_tipHintMinimum">Minimum tip %1$s</string>
<string name="error_title_tipMinimum">Tips Start at %1$s</string>
<string name="error_description_tipMinimum">Enter a larger amount to send this tip</string>
<string name="label_viaTipCard">via Tip Card</string>

</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.text.TextAutoSize
import androidx.compose.material3.Icon
Expand All @@ -27,10 +28,15 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.tooling.preview.PreviewWrapper
import com.flipcash.app.core.android.IntentUtils
import com.flipcash.app.core.contacts.DeviceContact
import com.flipcash.app.messenger.internal.ChatParticipant
import com.flipcash.app.theme.FlipcashThemeWrapper
import com.flipcash.features.messenger.R
import com.flipcash.services.models.UserProfile
import com.getcode.theme.CodeTheme

@Composable
Expand Down Expand Up @@ -84,35 +90,55 @@ internal fun ContactInfoContainer(
contract = ActivityResultContracts.StartActivityForResult()
) { onRefreshContact() }

ContactPill(
Indicator(
participant = participant,
modifier = Modifier.padding(top = CodeTheme.dimens.inset),
contact = contact
) {
contact ?: return@ContactPill
val intent = IntentUtils.openContact(contact).apply {
// Remove NEW_TASK so the result callback fires when the user returns,
// not immediately.
flags = flags and Intent.FLAG_ACTIVITY_NEW_TASK.inv()
when (participant) {
is ChatParticipant.Contact -> {
val intent = IntentUtils.openContact(participant.contact).apply {
// Remove NEW_TASK so the result callback fires when the user returns,
// not immediately.
flags = flags and Intent.FLAG_ACTIVITY_NEW_TASK.inv()
}
launcher.launch(intent)
}
is ChatParticipant.TipUser -> Unit
null -> Unit
}
launcher.launch(intent)
}
}
}

@Composable
private fun Indicator(
participant: ChatParticipant?,
modifier: Modifier = Modifier,
onClick: () -> Unit,
) {
when (participant) {
is ChatParticipant.Contact -> ContactPill(
participant.contact,
modifier = modifier,
onClick = onClick
)

is ChatParticipant.TipUser -> TipPill(modifier = modifier)
null -> Spacer(modifier = modifier.fillMaxWidth())
}
}

@Composable
private fun ContactPill(
contact: DeviceContact?,
contact: DeviceContact,
modifier: Modifier = Modifier,
onClick: () -> Unit,
) {
AnimatedContent(contact) { c ->
if (c == null) {
Spacer(modifier = modifier.fillMaxWidth())
return@AnimatedContent
}

val backgroundColor by animateColorAsState(
if (!c.isUnknown) CodeTheme.colors.surfaceVariant else CodeTheme.colors.warning.copy(alpha = 0.10f)
if (!c.isUnknown) CodeTheme.colors.surfaceVariant else CodeTheme.colors.warning.copy(
alpha = 0.10f
)
)

val contentColor by animateColorAsState(
Expand All @@ -124,7 +150,10 @@ private fun ContactPill(
.background(color = backgroundColor, shape = CircleShape)
.clip(CircleShape)
.clickable { onClick() }
.padding(horizontal = CodeTheme.dimens.grid.x2, vertical = CodeTheme.dimens.grid.x1),
.padding(
horizontal = CodeTheme.dimens.grid.x2,
vertical = CodeTheme.dimens.grid.x1
),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(CodeTheme.dimens.grid.x1)
) {
Expand All @@ -142,10 +171,87 @@ private fun ContactPill(
)

Text(
text = if (!c.isUnknown) stringResource(R.string.label_fromYourContacts) else stringResource(R.string.label_addContact),
text = if (!c.isUnknown) stringResource(R.string.label_fromYourContacts) else stringResource(
R.string.label_addContact
),
color = contentColor,
style = CodeTheme.typography.textSmall,
)
}
}
}
}

@Composable
private fun TipPill(
modifier: Modifier = Modifier,
) {
Row(
modifier = modifier
.background(color = CodeTheme.colors.surfaceVariant, shape = CircleShape)
.clip(CircleShape)
.padding(horizontal = CodeTheme.dimens.grid.x2, vertical = CodeTheme.dimens.grid.x1),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(CodeTheme.dimens.grid.x1)
) {
Icon(
modifier = Modifier.size(CodeTheme.dimens.staticGrid.x4),
painter = painterResource(R.drawable.ic_tipcode),
contentDescription = null,
tint = CodeTheme.colors.textSecondary,
)

Text(
text = stringResource(R.string.label_viaTipCard),
color = CodeTheme.colors.textSecondary,
style = CodeTheme.typography.textSmall,
)
}
}

// region Previews

@Preview
@PreviewWrapper(FlipcashThemeWrapper::class)
@Composable
private fun Preview_AllStates() {
// A saved device contact: name + number + the "From your contacts" pill.
val knownContact = ChatParticipant.Contact(
DeviceContact(
e164 = "+15551234567",
androidContactId = 1L,
displayName = "Ada Lovelace",
photoUri = null,
displayNumber = "(555) 123-4567",
)
)

// An unknown number: falls back to the number as the name and shows the warning
// "Add contact" pill.
val unknownContact = ChatParticipant.Contact(
DeviceContact.unknownContact(
e164 = "+15559876543",
displayNumber = "(555) 987-6543",
)
)

// A tip DM's counterparty: identity from a server profile — no phone number, no pill.
val tipUser = ChatParticipant.TipUser(
userId = listOf(1.toByte()),
profile = UserProfile.Empty.copy(displayName = "Grace Hopper"),
)

// Fixed width so every state renders at the same size regardless of name/number length.
val cardWidth = Modifier.width(300.dp)
Column(
modifier = Modifier.padding(CodeTheme.dimens.grid.x4),
verticalArrangement = Arrangement.spacedBy(CodeTheme.dimens.grid.x4),
) {
ContactInfoContainer(participant = knownContact, modifier = cardWidth)
ContactInfoContainer(participant = unknownContact, modifier = cardWidth)
ContactInfoContainer(participant = tipUser, modifier = cardWidth)
// Null participant: loading / unknown fallback avatar, name empty, no pill.
ContactInfoContainer(participant = null, modifier = cardWidth)
}
}

// endregion
Loading