diff --git a/api/src/main/java/com/getcode/network/TipController.kt b/api/src/main/java/com/getcode/network/TipController.kt index 66ffb01f5..0cbfb92fa 100644 --- a/api/src/main/java/com/getcode/network/TipController.kt +++ b/api/src/main/java/com/getcode/network/TipController.kt @@ -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 @@ -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 @@ -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() } diff --git a/app/src/main/java/com/getcode/util/Context.kt b/app/src/main/java/com/getcode/util/Context.kt index 6e6089a1b..65678d42e 100644 --- a/app/src/main/java/com/getcode/util/Context.kt +++ b/app/src/main/java/com/getcode/util/Context.kt @@ -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) } \ No newline at end of file diff --git a/app/src/main/java/com/getcode/util/IntentUtils.kt b/app/src/main/java/com/getcode/util/IntentUtils.kt new file mode 100644 index 000000000..aaf9e8298 --- /dev/null +++ b/app/src/main/java/com/getcode/util/IntentUtils.kt @@ -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 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/getcode/view/main/home/HomeViewModel.kt b/app/src/main/java/com/getcode/view/main/home/HomeViewModel.kt index 42db4b6f9..149fba775 100644 --- a/app/src/main/java/com/getcode/view/main/home/HomeViewModel.kt +++ b/app/src/main/java/com/getcode/view/main/home/HomeViewModel.kt @@ -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 @@ -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) diff --git a/app/src/main/java/com/getcode/view/main/tip/TipConnectViewModel.kt b/app/src/main/java/com/getcode/view/main/tip/TipConnectViewModel.kt index 29e17e1c2..d4708fc66 100644 --- a/app/src/main/java/com/getcode/view/main/tip/TipConnectViewModel.kt +++ b/app/src/main/java/com/getcode/view/main/tip/TipConnectViewModel.kt @@ -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( initialState = State(""), updateStateForEvent = updateStateForEvent @@ -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)} @@ -62,11 +48,9 @@ class TipConnectViewModel @Inject constructor( eventFlow .filterIsInstance() - .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) } diff --git a/app/src/main/res/values-en-rGB/strings-localized.xml b/app/src/main/res/values-en-rGB/strings-localized.xml index 9cb679793..4de965c9f 100644 --- a/app/src/main/res/values-en-rGB/strings-localized.xml +++ b/app/src/main/res/values-en-rGB/strings-localized.xml @@ -262,7 +262,7 @@ An SMS message was sent to your phone number with a verification code. Please enter the verification code above. Someone sent you cash Someone tipped you - Your Tip Card lets you receive tips from Code users all over the world. To access your Tip Card connect your X identity. + Your Tip Card lets you receive tips from Code users all over the world. To access your Tip Card post to X. Type \"%1$s\" We\'ve made some changes to improve the experience. You\'ll need to update the app to keep using Code. Valid owner account diff --git a/app/src/main/res/values/strings-localized.xml b/app/src/main/res/values/strings-localized.xml index bf3df3ddc..a2107734a 100644 --- a/app/src/main/res/values/strings-localized.xml +++ b/app/src/main/res/values/strings-localized.xml @@ -94,7 +94,7 @@ To learn how to get more Kin go to the FAQ in Settings. Please enter a different Invite Code and try again. Please enter a valid phone number and try again. - This is an invalid Tip Card. + Send a tweet to this person to activate their Tip Card. Please enter a valid code and try again. Sorry, we experienced a network issue. Please try inviting your friend again. This Kin was automatically returned to the sender because it wasn\'t collected within 24 hours. Please ask them to send the Kin again. @@ -124,7 +124,7 @@ Insufficient Kin Invite Code Invalid or Expired Invalid Phone Number - Invalid Tip Card + Tip Card Not Yet Activated. Invalid Code Invitation Failed Link Expired @@ -262,7 +262,7 @@ An SMS message was sent to your phone number with a verification code. Please enter the verification code above. Someone sent you cash Someone tipped you - Your Tip Card lets you to receive tips from Code users all over the world. To access your Tip Card connect your X identity. + Your Tip Card lets you to receive tips from Code users all over the world. To access your Tip Card post to X. Type \"%1$s\" We\'ve made some changes to improve the experience. You\'ll need to update the app to keep using Code. Valid owner account diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 90ab821fc..3be168aad 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -33,4 +33,11 @@ 🙏 %1$s thanked you for your tip Send Kin + Tweet Them + + Hey @%1$s you should set up your @getcode Tip Card so I can tip you some cash. + + getcode.com/download + +