Skip to content

feat: add prompt flow when scanning non-activated tip cards #416

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 21, 2024
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
25 changes: 25 additions & 0 deletions api/src/main/java/com/getcode/network/TipController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ import com.getcode.network.client.Client
import com.getcode.network.client.fetchTwitterUser
import com.getcode.network.repository.PrefRepository
import com.getcode.network.repository.TwitterUserFetchError
import com.getcode.network.repository.base58
import com.getcode.utils.bytes
import com.getcode.utils.getOrPutIfNonNull
import com.getcode.vendor.Base58
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
Expand All @@ -31,6 +34,7 @@ import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import timber.log.Timber
import java.util.Timer
import java.util.UUID
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.concurrent.fixedRateTimer
Expand Down Expand Up @@ -142,6 +146,27 @@ class TipController @Inject constructor(
prefRepository.set(PrefsBool.SEEN_TIP_CARD, true)
}

fun generateTipVerification(): String? {
val authority = SessionManager.getOrganizer()?.tray?.owner?.getCluster()?.authority
val tipAddress = SessionManager.getOrganizer()?.primaryVault
?.let { Base58.encode(it.byteArray) }

if (tipAddress != null && authority != null) {
val nonce = UUID.randomUUID()
val signature = authority.keyPair.sign(nonce.bytes.toByteArray())
val verificationMessage = listOf(
"CodeAccount",
tipAddress,
Base58.encode(nonce.bytes.toByteArray()),
signature.base58
).joinToString(":")

return verificationMessage
}

return null
}

private fun stopTimer() {
pollTimer?.cancel()
}
Expand Down
23 changes: 3 additions & 20 deletions app/src/main/java/com/getcode/util/Context.kt
Original file line number Diff line number Diff line change
@@ -1,31 +1,14 @@
package com.getcode.util

import android.content.Context
import android.content.Intent
import android.net.Uri
import android.provider.Settings
import androidx.core.content.ContextCompat
import com.getcode.BuildConfig
import com.getcode.utils.makeE164

fun Context.launchAppSettings() {
ContextCompat.startActivity(
this,
Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
data = Uri.fromParts("package", BuildConfig.APPLICATION_ID, null)
flags = Intent.FLAG_ACTIVITY_NEW_TASK
},
null
)
val intent = IntentUtils.appSettings()
ContextCompat.startActivity(this, intent, null)
}

fun Context.launchSmsIntent(phoneValue: String, message: String) {
val uri: Uri = Uri.parse("smsto:${phoneValue.makeE164()}")
val intent = Intent(Intent.ACTION_SENDTO, uri)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
intent.putExtra(
"sms_body",
message
)
val intent = IntentUtils.sendSms(phoneValue, message)
ContextCompat.startActivity(this, intent, null)
}
30 changes: 30 additions & 0 deletions app/src/main/java/com/getcode/util/IntentUtils.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.getcode.util

import android.content.Intent
import android.net.Uri
import android.provider.Settings
import com.getcode.BuildConfig
import com.getcode.network.repository.urlEncode
import com.getcode.utils.makeE164

object IntentUtils {

fun appSettings() = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
data = Uri.fromParts("package", BuildConfig.APPLICATION_ID, null)
flags = Intent.FLAG_ACTIVITY_NEW_TASK
}

fun sendSms(phoneValue: String, message: String) = Intent(
Intent.ACTION_SENDTO,
Uri.parse("smsto:${phoneValue.makeE164()}")
).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK
putExtra("sms_body", message)
}

fun tweet(message: String) = Intent(Intent.ACTION_VIEW).apply {
val url = "https://www.twitter.com/intent/tweet?text=${message.urlEncode()}"
setData(Uri.parse(url))
flags = Intent.FLAG_ACTIVITY_NEW_TASK
}
}
19 changes: 17 additions & 2 deletions app/src/main/java/com/getcode/view/main/home/HomeViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ import com.getcode.network.repository.toPublicKey
import com.getcode.solana.organizer.GiftCardAccount
import com.getcode.solana.organizer.Organizer
import com.getcode.util.CurrencyUtils
import com.getcode.util.IntentUtils
import com.getcode.util.Kin
import com.getcode.util.formatted
import com.getcode.util.resources.ResourceHelper
Expand Down Expand Up @@ -727,8 +728,22 @@ class HomeViewModel @Inject constructor(
scannedRendezvous.add(payload.rendezvous.publicKey)
cancelTip()
TopBarManager.showMessage(
resources.getString(R.string.error_title_invalidTipCard),
resources.getString(R.string.error_description_invalidTipCard),
TopBarManager.TopBarMessage(
title = resources.getString(R.string.error_title_invalidTipCard),
message = resources.getString(R.string.error_description_invalidTipCard),
primaryText = resources.getString(R.string.action_tweetThem),
primaryAction = {
val intent = IntentUtils.tweet(
resources.getString(
R.string.subtitle_linkingTwitterPrompt, username
)
)
viewModelScope.launch {
_eventFlow.emit(HomeEvent.SendIntent(intent))
}
},
secondaryText = resources.getString(R.string.action_notNow)
)
)
}.onSuccess {
delay(300.milliseconds)
Expand Down
32 changes: 8 additions & 24 deletions app/src/main/java/com/getcode/view/main/tip/TipConnectViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,22 @@ import android.content.Intent
import android.net.Uri
import androidx.lifecycle.viewModelScope
import com.getcode.R
import com.getcode.manager.SessionManager
import com.getcode.network.repository.base58
import com.getcode.network.TipController
import com.getcode.network.repository.urlEncode
import com.getcode.util.IntentUtils
import com.getcode.util.resources.ResourceHelper
import com.getcode.utils.bytes
import com.getcode.vendor.Base58
import com.getcode.view.BaseViewModel2
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import java.util.UUID
import javax.inject.Inject

@HiltViewModel
class TipConnectViewModel @Inject constructor(
resources: ResourceHelper,
tipController: TipController,
) : BaseViewModel2<TipConnectViewModel.State, TipConnectViewModel.Event>(
initialState = State(""),
updateStateForEvent = updateStateForEvent
Expand All @@ -38,20 +36,8 @@ class TipConnectViewModel @Inject constructor(
}

init {
val authority = SessionManager.getOrganizer()?.tray?.owner?.getCluster()?.authority
val tipAddress = SessionManager.getOrganizer()?.primaryVault
?.let { Base58.encode(it.byteArray) }

if (tipAddress != null && authority != null) {
val nonce = UUID.randomUUID()
val signature = authority.keyPair.sign(nonce.bytes.toByteArray())
val verificationMessage = listOf(
"CodeAccount",
tipAddress,
Base58.encode(nonce.bytes.toByteArray()),
signature.base58
).joinToString(":")

val verificationMessage = tipController.generateTipVerification()
if (verificationMessage != null) {
val message = """
${resources.getString(R.string.subtitle_linkingTwitter)}

Expand All @@ -62,11 +48,9 @@ class TipConnectViewModel @Inject constructor(

eventFlow
.filterIsInstance<Event.PostToX>()
.map {
// build intent
val url = "https://www.twitter.com/intent/tweet?text=${stateFlow.value.xMessage.urlEncode()}"
Intent(Intent.ACTION_VIEW).apply { setData(Uri.parse(url)) }
}.onEach {
.map { stateFlow.value.xMessage }
.map { IntentUtils.tweet(it) }
.onEach {
dispatchEvent(Event.OpenX(it))
}.launchIn(viewModelScope)
}
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/values-en-rGB/strings-localized.xml
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@
<string name="subtitle_smsWasSent">An SMS message was sent to your phone number with a verification code. Please enter the verification code above.</string>
<string name="subtitle_someoneSendYouCash">Someone sent you cash</string>
<string name="subtitle_someoneTippedYou">Someone tipped you</string>
<string name="subtitle_tipCardForX">Your Tip Card lets you receive tips from Code users all over the world. To access your Tip Card connect your X identity.</string>
<string name="subtitle_tipCardForX">Your Tip Card lets you receive tips from Code users all over the world. To access your Tip Card post to X.</string>
<string name="subtitle_typeDelete">Type \"%1$s\"</string>
<string name="subtitle_updateRequiredDescription">We\'ve made some changes to improve the experience. You\'ll need to update the app to keep using Code.</string>
<string name="subtitle_validOwnerAccount">Valid owner account</string>
Expand Down
6 changes: 3 additions & 3 deletions app/src/main/res/values/strings-localized.xml
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@
<string name="error_description_insuffiecientKin">To learn how to get more Kin go to the FAQ in Settings.</string>
<string name="error_description_invalidInviteCode">Please enter a different Invite Code and try again.</string>
<string name="error_description_invalidInvitePhone">Please enter a valid phone number and try again.</string>
<string name="error_description_invalidTipCard">This is an invalid Tip Card.</string>
<string name="error_description_invalidTipCard">Send a tweet to this person to activate their Tip Card.</string>
<string name="error_description_invalidVerificationCode">Please enter a valid code and try again.</string>
<string name="error_description_invitationFailed">Sorry, we experienced a network issue. Please try inviting your friend again.</string>
<string name="error_description_linkExpired">This Kin was automatically returned to the sender because it wasn\'t collected within 24 hours. Please ask them to send the Kin again.</string>
Expand Down Expand Up @@ -124,7 +124,7 @@
<string name="error_title_insuffiecientKin">Insufficient Kin</string>
<string name="error_title_invalidInviteCode">Invite Code Invalid or Expired</string>
<string name="error_title_invalidInvitePhone">Invalid Phone Number</string>
<string name="error_title_invalidTipCard">Invalid Tip Card</string>
<string name="error_title_invalidTipCard">Tip Card Not Yet Activated.</string>
<string name="error_title_invalidVerificationCode">Invalid Code</string>
<string name="error_title_invitationFailed">Invitation Failed</string>
<string name="error_title_linkExpired">Link Expired</string>
Expand Down Expand Up @@ -262,7 +262,7 @@
<string name="subtitle_smsWasSent">An SMS message was sent to your phone number with a verification code. Please enter the verification code above.</string>
<string name="subtitle_someoneSendYouCash">Someone sent you cash</string>
<string name="subtitle_someoneTippedYou">Someone tipped you</string>
<string name="subtitle_tipCardForX">Your Tip Card lets you to receive tips from Code users all over the world. To access your Tip Card connect your X identity.</string>
<string name="subtitle_tipCardForX">Your Tip Card lets you to receive tips from Code users all over the world. To access your Tip Card post to X.</string>
<string name="subtitle_typeDelete">Type \"%1$s\"</string>
<string name="subtitle_updateRequiredDescription">We\'ve made some changes to improve the experience. You\'ll need to update the app to keep using Code.</string>
<string name="subtitle_validOwnerAccount">Valid owner account</string>
Expand Down
7 changes: 7 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,11 @@
<string name="title_chat_announcement_thanksReceived">🙏 %1$s thanked you for your tip</string>

<string name="title_sendKin">Send Kin</string>
<string name="action_tweetThem">Tweet Them</string>
<string name="subtitle_linkingTwitterPrompt">
Hey @%1$s you should set up your @getcode Tip Card so I can tip you some cash.

getcode.com/download
</string>

</resources>
Loading