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 @@ -9,6 +9,7 @@ import com.flipcash.services.controllers.ChatController
import com.flipcash.services.models.chat.ChatId
import com.flipcash.services.models.chat.ChatType
import com.flipcash.services.models.chat.ViewMode
import com.flipcash.shared.chat.FeaturedGroupsStore
import com.flipcash.shared.chat.models.LinkCard
import com.getcode.solana.keys.Mint
import com.getcode.util.resources.ResourceHelper
Expand All @@ -25,6 +26,9 @@ import javax.inject.Inject
* Anything that is not a group -- a DM id pasted into a `/chat/` link, or a chat that has gone --
* fails the lookup, and the card draws its unavailable state.
*
* A resolved record is also handed to [FeaturedGroupsStore], so the profile a tap opens has
* something to draw before its own fetch answers.
*
* The requirement is stated the way the chat's own head card states it, including the reserve
* being named by the amount alone ("$100", not "$100 of Dollars"). An unknown mint is not a
* failure: the amount is still true, so it is stated without a token beside it.
Expand All @@ -33,12 +37,17 @@ internal class GroupLinkLookup @Inject constructor(
private val chatController: ChatController,
private val tokenCoordinator: TokenCoordinator,
private val resources: ResourceHelper,
private val featuredGroups: FeaturedGroupsStore,
) {
suspend operator fun invoke(chatId: ChatId): Result<LinkCard.GroupInvite.State.Resolved> =
runCatching {
val chat = chatController.getChat(chatId, ViewMode.REDACTED).getOrThrow()
if (chat.type != ChatType.GROUP) throw NotAGroup(chatId)

// A tap opens the group's profile, which draws from this record at once rather than
// sitting empty through its own GetChat -- the same placeholder a featured group gets.
featuredGroups.remember(listOf(chat))

val balance = chat.rules.balanceRequirement()
val staffOnly = chat.rules.requiresStaff()
val requirement = if (balance != null || staffOnly) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,9 +190,15 @@ internal fun MessengerScreen(viewModel: ChatViewModel) {
keyboard.hideIfVisible {
viewModel.dispatchEvent(
ChatViewModel.Event.OpenScreen(
// Pushed, so Back returns to this chat. The pushed screen gates
// itself: a non-member sees the join or the buy there.
AppRoute.Messaging.Chat(ChatIdentifier.ByChatId(action.chatId))
// Pushed, so Back returns to this chat. A resolved card opens
// the group's profile, as a featured group does: Open Chat there
// pushes the transcript, which gates itself for a non-member.
// Until the card resolves there is no record to show, so it opens
// the chat.
AppRoute.Messaging.Chat(
identifier = ChatIdentifier.ByChatId(action.chatId),
openOnProfile = action.resolved,
)
)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,11 @@ sealed interface ChatAction {
/**
* Opens the group a link card names, pushed over this chat so Back returns here. The pushed
* screen gates itself; a card never joins or buys on the reader's behalf.
*
* [resolved] is whether the card has fetched the group's public record. A resolved card opens
* the group's profile, a card still loading or unavailable opens the chat itself.
*/
data class OpenGroup(val chatId: ChatId) : ChatAction
data class OpenGroup(val chatId: ChatId, val resolved: Boolean) : ChatAction

/**
* Opens the person a link card names: their DM, pushed over this chat so Back returns here, or
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -734,7 +734,8 @@ private fun BareLinkCard(
* app, wrong from inside a chat, where it swaps the transcript for the wallet on the way to a
* screen the reader asked for directly. There is no wallet card here for the detail to grow out of.
* So it pushes, exactly as the cash bubble's own token tap does, and back returns to the message.
* A group invite pushes the group's conversation for the same reason.
* A group invite pushes the group's profile (its conversation until the card has resolved) for
* the same reason.
*/
@Composable
private fun rememberLinkCardClick(): (LinkCard) -> Unit {
Expand All @@ -749,7 +750,12 @@ private fun rememberLinkCardClick(): (LinkCard) -> Unit {
is LinkCard.TokenInfo -> actionHandler(ChatAction.ViewToken(card.mint))
// Pushed over this chat rather than through the chat deep link, which replaces the
// stack: Back has to return to the message that held the invite.
is LinkCard.GroupInvite -> actionHandler(ChatAction.OpenGroup(card.chatId))
is LinkCard.GroupInvite -> actionHandler(
ChatAction.OpenGroup(
chatId = card.chatId,
resolved = card.state is LinkCard.GroupInvite.State.Resolved,
)
)
// Only a resolved card takes a tap. Which screen it opens -- the person's DM, your own
// tip card, or nothing for the person already on the other end -- is the chat's call.
is LinkCard.User -> (card.state as? LinkCard.User.State.Resolved)?.let {
Expand Down
Loading