diff --git a/apps/flipcash/core/src/main/res/values/strings.xml b/apps/flipcash/core/src/main/res/values/strings.xml index aee06a45f6..7bd13b3c05 100644 --- a/apps/flipcash/core/src/main/res/values/strings.xml +++ b/apps/flipcash/core/src/main/res/values/strings.xml @@ -1242,7 +1242,7 @@ Your Name 500x500 Recommended My Tip Card - Tip %1$s + Chat with %1$s on Flipcash Share Your Tip Card to Get Tipped Show My Tip Card Send a Tip diff --git a/apps/flipcash/features/menu/src/main/kotlin/com/flipcash/app/menu/internal/MenuScreenViewModel.kt b/apps/flipcash/features/menu/src/main/kotlin/com/flipcash/app/menu/internal/MenuScreenViewModel.kt index 854a426b99..980b11cf72 100644 --- a/apps/flipcash/features/menu/src/main/kotlin/com/flipcash/app/menu/internal/MenuScreenViewModel.kt +++ b/apps/flipcash/features/menu/src/main/kotlin/com/flipcash/app/menu/internal/MenuScreenViewModel.kt @@ -467,16 +467,14 @@ internal class MenuScreenViewModel @Inject constructor( .filterIsInstance() .mapNotNull { tippingCoordinator.currentUserId } .map { userId -> - // Title shown above the link, e.g. "Tip Ada" (same label as the card). - val title = stateFlow.value.tipCard?.user?.displayName - ?.let { resources.getString(R.string.label_tipUser, it) } + val user = stateFlow.value.tipCard?.user // Attach the eagerly-rendered preview if it's ready; null shares the URL alone. shareable.present( - Shareable.TipCard( + Shareable.Profile( userId = userId, + displayName = user?.displayName, + username = user?.username, preview = tipCodePreviewCache.get(userId), - title = title, - username = stateFlow.value.tipCard?.user?.username, ) ) } diff --git a/apps/flipcash/features/messenger/src/main/kotlin/com/flipcash/app/messenger/internal/screens/MessengerScreen.kt b/apps/flipcash/features/messenger/src/main/kotlin/com/flipcash/app/messenger/internal/screens/MessengerScreen.kt index 8e568f6a0d..7dbd925b2d 100644 --- a/apps/flipcash/features/messenger/src/main/kotlin/com/flipcash/app/messenger/internal/screens/MessengerScreen.kt +++ b/apps/flipcash/features/messenger/src/main/kotlin/com/flipcash/app/messenger/internal/screens/MessengerScreen.kt @@ -49,7 +49,6 @@ import com.flipcash.shared.chat.models.ChatAction import com.flipcash.app.core.LocalUserManager import com.flipcash.app.shareable.LocalShareController import com.flipcash.app.shareable.Shareable -import com.flipcash.features.messenger.R import kotlinx.coroutines.launch import androidx.compose.runtime.rememberCoroutineScope import com.getcode.navigation.core.LocalCodeNavigator @@ -245,9 +244,9 @@ internal fun MessengerScreen(viewModel: ChatViewModel) { // shares it (`rememberProfileShare`): the handle form, titled with their name. is ChatAction.ShareProfile -> scope.launch { shareController.present( - Shareable.TipCard( + Shareable.Profile( userId = action.userId, - title = action.displayName?.let { context.getString(R.string.label_tipUser, it) }, + displayName = action.displayName, username = action.username, ) ) diff --git a/apps/flipcash/features/messenger/src/main/kotlin/com/flipcash/app/messenger/internal/screens/profile/ProfileShortcuts.kt b/apps/flipcash/features/messenger/src/main/kotlin/com/flipcash/app/messenger/internal/screens/profile/ProfileShortcuts.kt index a99684afe4..5bd103337a 100644 --- a/apps/flipcash/features/messenger/src/main/kotlin/com/flipcash/app/messenger/internal/screens/profile/ProfileShortcuts.kt +++ b/apps/flipcash/features/messenger/src/main/kotlin/com/flipcash/app/messenger/internal/screens/profile/ProfileShortcuts.kt @@ -86,9 +86,9 @@ internal fun rememberProfileShare(): (ChatParticipant.TipUser) -> Unit { { user -> scope.launch { shareController.present( - Shareable.TipCard( + Shareable.Profile( userId = user.userId, - title = user.profile.displayName, + displayName = user.profile.displayName, username = user.profile.username, ) ) diff --git a/apps/flipcash/shared/shareable/src/main/kotlin/com/flipcash/app/shareable/ShareSheetController.kt b/apps/flipcash/shared/shareable/src/main/kotlin/com/flipcash/app/shareable/ShareSheetController.kt index 8720f53abc..46629fd14c 100644 --- a/apps/flipcash/shared/shareable/src/main/kotlin/com/flipcash/app/shareable/ShareSheetController.kt +++ b/apps/flipcash/shared/shareable/src/main/kotlin/com/flipcash/app/shareable/ShareSheetController.kt @@ -69,16 +69,20 @@ sealed interface Shareable { override val pendingData: ShareablePendingData? = null } - data class TipCard( + /** + * A user's profile link. The Sharesheet title ("Chat with Ada on Flipcash") is built from + * [displayName] when sharing, so every place that shares a profile titles it the same way. + */ + data class Profile( val userId: ID, - // Optional pre-rendered Sharesheet preview. Null degrades to sharing the URL alone. - val preview: TipCodePreview? = null, - // Optional Sharesheet title shown above the link (e.g. "Tip Brandon McAnsh"). - val title: String? = null, + // The owner's display name. Null shares the link without a title. + val displayName: String? = null, // The owner's claimed handle, when they have one. Carried so the shared link is the vanity // form the You tab shows and copies — sharing a UUID for a card that displays // `flipcash.com/` would hand out a second, unrecognisable address for it. val username: String? = null, + // Optional pre-rendered Sharesheet preview. Null degrades to sharing the URL alone. + val preview: TipCodePreview? = null, ): Shareable { override val pendingData: ShareablePendingData? = null } @@ -86,7 +90,7 @@ sealed interface Shareable { /** * The tip code itself, as a file (see [TipCodeExport]) — what the "Download" action produces. * - * Distinct from [TipCard]: that shares the tip *link* and only uses an image as the Sharesheet's + * Distinct from [Profile]: that shares the profile *link* and only uses an image as the Sharesheet's * thumbnail. Here the file IS the payload, so it goes out as an `EXTRA_STREAM` of the export's * own MIME type and a "save to Files" target receives something real. */ diff --git a/apps/flipcash/shared/shareable/src/main/kotlin/com/flipcash/app/shareable/internal/InternalShareConfirmationController.kt b/apps/flipcash/shared/shareable/src/main/kotlin/com/flipcash/app/shareable/internal/InternalShareConfirmationController.kt index 4dc5e307f8..ed10feba52 100644 --- a/apps/flipcash/shared/shareable/src/main/kotlin/com/flipcash/app/shareable/internal/InternalShareConfirmationController.kt +++ b/apps/flipcash/shared/shareable/src/main/kotlin/com/flipcash/app/shareable/internal/InternalShareConfirmationController.kt @@ -31,7 +31,7 @@ internal class InternalShareConfirmationController( // Nothing to take back if the link never leaves — the chat exists either way, and // the same link can be shared again. Only a cash link needs confirming. is Shareable.GroupInvite -> ShareConfirmationResult.Confirmed(shareResult) - is Shareable.TipCard -> ShareConfirmationResult.Confirmed(shareResult) + is Shareable.Profile -> ShareConfirmationResult.Confirmed(shareResult) is Shareable.TipCodeImage -> ShareConfirmationResult.Confirmed(shareResult) } } diff --git a/apps/flipcash/shared/shareable/src/main/kotlin/com/flipcash/app/shareable/internal/InternalShareSheetController.kt b/apps/flipcash/shared/shareable/src/main/kotlin/com/flipcash/app/shareable/internal/InternalShareSheetController.kt index fff5bf441f..882121ba32 100644 --- a/apps/flipcash/shared/shareable/src/main/kotlin/com/flipcash/app/shareable/internal/InternalShareSheetController.kt +++ b/apps/flipcash/shared/shareable/src/main/kotlin/com/flipcash/app/shareable/internal/InternalShareSheetController.kt @@ -116,7 +116,7 @@ internal class InternalShareSheetController( is Shareable.TokenInfo -> Unit is Shareable.Invite -> Unit is Shareable.GroupInvite -> Unit - is Shareable.TipCard -> Unit + is Shareable.Profile -> Unit is Shareable.TipCodeImage -> Unit } } @@ -217,7 +217,7 @@ internal class InternalShareSheetController( shareGroupInvite(shareable) } - is Shareable.TipCard -> shareTipCard(shareable) + is Shareable.Profile -> shareProfile(shareable) is Shareable.TipCodeImage -> shareTipCodeImage(shareable) } @@ -392,7 +392,7 @@ internal class InternalShareSheetController( if (preview != null) { // The Sharesheet draws its thumbnail from ClipData, not from any extra — see - // shareTipCard. The payload stays the text; this is preview only. + // shareProfile. The payload stays the text; this is preview only. clipData = ClipData.newUri(context.contentResolver, "Group picture", preview) addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) } @@ -400,7 +400,7 @@ internal class InternalShareSheetController( val share = Intent.createChooser(intent, null).apply { // addFlags, not `flags =` — assigning would wipe the read grant createChooser migrates - // onto the chooser intent, and the Sharesheet could not open the image. See shareTipCard. + // onto the chooser intent, and the Sharesheet could not open the image. See shareProfile. addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) if (preview != null) addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) } @@ -408,7 +408,7 @@ internal class InternalShareSheetController( context.startActivity(share) } - private fun shareTipCard(shareable: Shareable.TipCard) { + private fun shareProfile(shareable: Shareable.Profile) { // Addressed the same way the You tab's link row addresses it, so what gets shared is what // the card says it is. val url = Linkify.tipcard( @@ -421,7 +421,9 @@ internal class InternalShareSheetController( // URL's OG tags. type stays text/plain and the bitmap is NOT an EXTRA_STREAM. type = "text/plain" putExtra(Intent.EXTRA_TEXT, url) - shareable.title?.let { putExtra(Intent.EXTRA_TITLE, it) } + shareable.displayName + ?.let { resources.getString(R.string.title_shareProfile, it) } + ?.let { putExtra(Intent.EXTRA_TITLE, it) } if (preview != null) { // Android draws the Sharesheet thumbnail from the intent's ClipData (a content:// URI), @@ -446,7 +448,7 @@ internal class InternalShareSheetController( } /** - * Shares the exported code file itself (PNG/SVG). Unlike [shareTipCard], the payload here IS the + * Shares the exported code file itself (PNG/SVG). Unlike [shareProfile], the payload here IS the * file: it goes out as an `EXTRA_STREAM` of the export's own MIME type, so "save to Files" and * image-consuming targets receive something real rather than a link. */ @@ -467,7 +469,7 @@ internal class InternalShareSheetController( } val share = Intent.createChooser(intent, null).apply { - // addFlags, not `flags =` — see shareTipCard: assigning would wipe the migrated grant. + // addFlags, not `flags =` — see shareProfile: assigning would wipe the migrated grant. addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) }