diff --git a/core/android/src/main/kotlin/com/walletconnect/android/CoreProtocol.kt b/core/android/src/main/kotlin/com/walletconnect/android/CoreProtocol.kt index 7cc4cf051b..0690e1d1f2 100644 --- a/core/android/src/main/kotlin/com/walletconnect/android/CoreProtocol.kt +++ b/core/android/src/main/kotlin/com/walletconnect/android/CoreProtocol.kt @@ -8,6 +8,7 @@ import com.walletconnect.android.internal.common.di.coreJsonRpcModule import com.walletconnect.android.internal.common.di.corePairingModule import com.walletconnect.android.internal.common.di.explorerModule import com.walletconnect.android.internal.common.di.keyServerModule +import com.walletconnect.android.internal.common.di.pulseModule import com.walletconnect.android.internal.common.di.pushModule import com.walletconnect.android.internal.common.di.web3ModalModule import com.walletconnect.android.internal.common.explorer.ExplorerInterface @@ -38,6 +39,7 @@ class CoreProtocol(private val koinApp: KoinApplication = wcKoinApp) : CoreInter override val Pairing: PairingInterface = PairingProtocol(koinApp) override val PairingController: PairingControllerInterface = PairingController(koinApp) override var Relay = RelayClient(koinApp) + @Deprecated(message = "Replaced with Push") override val Echo: PushInterface = PushClient override val Push: PushInterface = PushClient @@ -83,7 +85,8 @@ class CoreProtocol(private val koinApp: KoinApplication = wcKoinApp) : CoreInter corePairingModule(Pairing, PairingController), keyServerModule(keyServerUrl), explorerModule(), - web3ModalModule() + web3ModalModule(), + pulseModule() ) } diff --git a/core/android/src/main/kotlin/com/walletconnect/android/internal/common/di/AndroidCommonDITags.kt b/core/android/src/main/kotlin/com/walletconnect/android/internal/common/di/AndroidCommonDITags.kt index b0b8e9ce5f..9f95cdffb1 100644 --- a/core/android/src/main/kotlin/com/walletconnect/android/internal/common/di/AndroidCommonDITags.kt +++ b/core/android/src/main/kotlin/com/walletconnect/android/internal/common/di/AndroidCommonDITags.kt @@ -20,7 +20,9 @@ enum class AndroidCommonDITags { USER_AGENT, RELAY_URL, KEYSERVER_URL, + PULSE_URL, KEYSERVER_RETROFIT, + PULSE_RETROFIT, VERIFY_RETROFIT, VERIFY_URL, EXPLORER_URL, @@ -36,5 +38,7 @@ enum class AndroidCommonDITags { DECRYPT_SIGN_MESSAGE, DECRYPT_AUTH_MESSAGE, DECRYPT_NOTIFY_MESSAGE, - DECRYPT_USE_CASES + DECRYPT_USE_CASES, + BUNDLE_ID, + ENABLE_ANALYTICS } \ No newline at end of file diff --git a/core/android/src/main/kotlin/com/walletconnect/android/internal/common/di/CoreCommonModule.kt b/core/android/src/main/kotlin/com/walletconnect/android/internal/common/di/CoreCommonModule.kt index b68ef8502e..d4366d836e 100644 --- a/core/android/src/main/kotlin/com/walletconnect/android/internal/common/di/CoreCommonModule.kt +++ b/core/android/src/main/kotlin/com/walletconnect/android/internal/common/di/CoreCommonModule.kt @@ -9,6 +9,7 @@ import com.walletconnect.android.internal.common.adapter.JsonRpcResultAdapter import com.walletconnect.android.internal.common.adapter.TagsAdapter import com.walletconnect.android.internal.common.model.Expiry import com.walletconnect.android.internal.common.model.Tags +import com.walletconnect.android.pulse.model.properties.Props import com.walletconnect.foundation.di.FoundationDITags import com.walletconnect.foundation.di.foundationCommonModule import com.walletconnect.foundation.util.Logger @@ -27,6 +28,25 @@ fun coreCommonModule() = module { .withSubtype(JsonRpcResponse.JsonRpcError::class.java, "error") } + single> { + PolymorphicJsonAdapterFactory.of(Props::class.java, "type") + .withSubtype(Props.ModalCreated::class.java, "modal_created") + .withSubtype(Props.ModalLoaded::class.java, "modal_loaded") + .withSubtype(Props.ModalOpen::class.java, "modal_open") + .withSubtype(Props.ModalClose::class.java, "modal_close") + .withSubtype(Props.ClickNetworks::class.java, "click_networks") + .withSubtype(Props.ClickAllWallets::class.java, "click_all_wallets") + .withSubtype(Props.SwitchNetwork::class.java, "switch_network") + .withSubtype(Props.SelectWallet::class.java, "select_wallet") + .withSubtype(Props.ConnectSuccess::class.java, "connect_success") + .withSubtype(Props.ConnectError::class.java, "connect_error") + .withSubtype(Props.DisconnectSuccess::class.java, "disconnect_success") + .withSubtype(Props.DisconnectError::class.java, "disconnect_error") + .withSubtype(Props.ClickWalletHelp::class.java, "click_wallet_help") + .withSubtype(Props.ClickNetworkHelp::class.java, "click_network_help") + .withSubtype(Props.ClickGetWallet::class.java, "click_get_wallet") + } + single(named(AndroidCommonDITags.MOSHI)) { get(named(FoundationDITags.MOSHI)) .newBuilder() @@ -39,6 +59,7 @@ fun coreCommonModule() = module { } } .add(get>()) + .add(get>()) } single { diff --git a/core/android/src/main/kotlin/com/walletconnect/android/internal/common/di/CoreNetworkModule.kt b/core/android/src/main/kotlin/com/walletconnect/android/internal/common/di/CoreNetworkModule.kt index 45a27ac22b..d7a3946c24 100644 --- a/core/android/src/main/kotlin/com/walletconnect/android/internal/common/di/CoreNetworkModule.kt +++ b/core/android/src/main/kotlin/com/walletconnect/android/internal/common/di/CoreNetworkModule.kt @@ -27,7 +27,6 @@ import org.koin.android.ext.koin.androidApplication import org.koin.android.ext.koin.androidContext import org.koin.core.qualifier.named import org.koin.dsl.module -import java.util.* import java.util.concurrent.TimeUnit @@ -54,6 +53,8 @@ fun coreAndroidNetworkModule(serverUrl: String, connectionType: ConnectionType, """wc-2/kotlin-${sdkVersion}/android-${Build.VERSION.RELEASE}""" } + single(named(AndroidCommonDITags.BUNDLE_ID)) { androidContext().packageName } + single { GenerateJwtStoreClientIdUseCase(get(), get()) } @@ -62,7 +63,7 @@ fun coreAndroidNetworkModule(serverUrl: String, connectionType: ConnectionType, Interceptor { chain -> val updatedRequest = chain.request().newBuilder() .addHeader("User-Agent", get(named(AndroidCommonDITags.USER_AGENT))) - .addHeader("Origin", androidContext().packageName) + .addHeader("Origin", get(named(AndroidCommonDITags.BUNDLE_ID))) .build() chain.proceed(updatedRequest) @@ -73,6 +74,7 @@ fun coreAndroidNetworkModule(serverUrl: String, connectionType: ConnectionType, HttpLoggingInterceptor().apply { setLevel(HttpLoggingInterceptor.Level.BODY) } } + //TODO: make this more scalable single(named(AndroidCommonDITags.FAIL_OVER_INTERCEPTOR)) { Interceptor { chain -> val request = chain.request() @@ -82,6 +84,7 @@ fun coreAndroidNetworkModule(serverUrl: String, connectionType: ConnectionType, shouldFallbackRelay(host) -> chain.proceed(request.newBuilder().url(get(named(AndroidCommonDITags.RELAY_URL))).build()) shouldFallbackPush(host) -> chain.proceed(request.newBuilder().url(getFallbackPushUrl(request.url.toString())).build()) shouldFallbackVerify(host) -> chain.proceed(request.newBuilder().url(getFallbackVerifyUrl(request.url.toString())).build()) + shouldFallbackPulse(host) -> chain.proceed(request.newBuilder().url(getFallbackPulseUrl()).build()) else -> chain.proceed(request) } } catch (e: Exception) { @@ -90,6 +93,7 @@ fun coreAndroidNetworkModule(serverUrl: String, connectionType: ConnectionType, DEFAULT_RELAY_URL.host -> fallbackRelay(request, chain) DEFAULT_PUSH_URL.host -> fallbackPush(request, chain) DEFAULT_VERIFY_URL.host -> fallbackVerify(request, chain) + DEFAULT_PULSE_URL.host -> fallbackPulse(request, chain) else -> chain.proceed(request) } } else { diff --git a/core/android/src/main/kotlin/com/walletconnect/android/internal/common/di/FailoverUtils.kt b/core/android/src/main/kotlin/com/walletconnect/android/internal/common/di/FailoverUtils.kt index dc675699d5..0fb4a73ef3 100644 --- a/core/android/src/main/kotlin/com/walletconnect/android/internal/common/di/FailoverUtils.kt +++ b/core/android/src/main/kotlin/com/walletconnect/android/internal/common/di/FailoverUtils.kt @@ -20,13 +20,19 @@ internal var VERIFY_URL: String = "https://verify.walletconnect.com/" internal const val DEFAULT_VERIFY_URL: String = "https://verify.walletconnect.com/" internal const val FAIL_OVER_VERIFY_URL: String = "https://verify.walletconnect.org" +internal var PULSE_URL: String = "https://pulse.walletconnect.com" +internal const val DEFAULT_PULSE_URL: String = "https://pulse.walletconnect.com" +internal const val FAIL_OVER_PULSE_URL: String = "https://pulse.walletconnect.org" + internal var wasRelayFailOvered = false internal var wasEchoFailOvered = false internal var wasVerifyFailOvered = false +internal var wasPulseFailOvered = false internal fun shouldFallbackRelay(host: String): Boolean = wasRelayFailOvered && host == DEFAULT_RELAY_URL.host internal fun shouldFallbackPush(host: String): Boolean = wasEchoFailOvered && host == DEFAULT_PUSH_URL.host internal fun shouldFallbackVerify(host: String): Boolean = wasVerifyFailOvered && host == DEFAULT_VERIFY_URL.host +internal fun shouldFallbackPulse(host: String): Boolean = wasPulseFailOvered && host == DEFAULT_PULSE_URL.host internal fun getFallbackPushUrl(url: String): String = with(Uri.parse(url)) { val (path, query) = Pair(this.path, this.query) return@with "$FAIL_OVER_PUSH_URL$path?$query}" @@ -34,6 +40,8 @@ internal fun getFallbackPushUrl(url: String): String = with(Uri.parse(url)) { internal fun getFallbackVerifyUrl(url: String): String = "$FAIL_OVER_VERIFY_URL/attestation/${Uri.parse(url).lastPathSegment}" +internal fun getFallbackPulseUrl(): String = "$FAIL_OVER_PULSE_URL/e" + internal fun isFailOverException(e: Exception) = (e is SocketException || e is IOException) internal val String.host: String? get() = Uri.parse(this).host @@ -53,4 +61,10 @@ internal fun Scope.fallbackRelay(request: Request, chain: Interceptor.Chain): Re SERVER_URL = "$FAIL_OVER_RELAY_URL?projectId=${Uri.parse(SERVER_URL).getQueryParameter("projectId")}" wasRelayFailOvered = true return chain.proceed(request.newBuilder().url(get(named(AndroidCommonDITags.RELAY_URL))).build()) +} + +internal fun fallbackPulse(request: Request, chain: Interceptor.Chain): Response { + PULSE_URL = FAIL_OVER_PULSE_URL + wasPulseFailOvered = true + return chain.proceed(request.newBuilder().url(getFallbackPulseUrl()).build()) } \ No newline at end of file diff --git a/core/android/src/main/kotlin/com/walletconnect/android/internal/common/di/PulseModule.kt b/core/android/src/main/kotlin/com/walletconnect/android/internal/common/di/PulseModule.kt new file mode 100644 index 0000000000..d80c2efd0e --- /dev/null +++ b/core/android/src/main/kotlin/com/walletconnect/android/internal/common/di/PulseModule.kt @@ -0,0 +1,158 @@ +package com.walletconnect.android.internal.common.di + +import com.walletconnect.android.pulse.data.PulseService +import com.walletconnect.android.pulse.domain.SendClickAllWalletsUseCase +import com.walletconnect.android.pulse.domain.SendClickGetWalletUseCase +import com.walletconnect.android.pulse.domain.SendClickNetworkHelpUseCase +import com.walletconnect.android.pulse.domain.SendClickNetworksUseCase +import com.walletconnect.android.pulse.domain.SendClickWalletHelpUseCase +import com.walletconnect.android.pulse.domain.SendConnectErrorUseCase +import com.walletconnect.android.pulse.domain.SendConnectSuccessUseCase +import com.walletconnect.android.pulse.domain.SendDisconnectErrorUseCase +import com.walletconnect.android.pulse.domain.SendDisconnectSuccessUseCase +import com.walletconnect.android.pulse.domain.SendModalCloseUseCase +import com.walletconnect.android.pulse.domain.SendModalCreatedUseCase +import com.walletconnect.android.pulse.domain.SendModalLoadedUseCase +import com.walletconnect.android.pulse.domain.SendModalLoadedUseCaseInterface +import com.walletconnect.android.pulse.domain.SendModalOpenUseCase +import com.walletconnect.android.pulse.domain.SendSelectWalletUseCase +import com.walletconnect.android.pulse.domain.SendSwitchNetworkUseCase +import org.koin.core.qualifier.named +import org.koin.dsl.module +import retrofit2.Retrofit +import retrofit2.converter.moshi.MoshiConverterFactory + +@JvmSynthetic +fun pulseModule() = module { + single(named(AndroidCommonDITags.PULSE_URL)) { "https://pulse.walletconnect.com" } + + single(named(AndroidCommonDITags.PULSE_RETROFIT)) { + Retrofit.Builder() + .baseUrl(get(named(AndroidCommonDITags.PULSE_URL))) + .client(get(named(AndroidCommonDITags.WEB3MODAL_OKHTTP))) + .addConverterFactory(MoshiConverterFactory.create(get(named(AndroidCommonDITags.MOSHI)))) + .build() + } + + single { get(named(AndroidCommonDITags.PULSE_RETROFIT)).create(PulseService::class.java) } + + single { + SendModalCreatedUseCase( + pulseService = get(), + logger = get(named(AndroidCommonDITags.LOGGER)), + bundleId = get(named(AndroidCommonDITags.BUNDLE_ID)) + ) + } + + single { + SendClickAllWalletsUseCase( + pulseService = get(), + logger = get(named(AndroidCommonDITags.LOGGER)), + bundleId = get(named(AndroidCommonDITags.BUNDLE_ID)) + ) + } + + single { + SendClickGetWalletUseCase( + pulseService = get(), + logger = get(named(AndroidCommonDITags.LOGGER)), + bundleId = get(named(AndroidCommonDITags.BUNDLE_ID)) + ) + } + + single { + SendClickWalletHelpUseCase( + pulseService = get(), + logger = get(named(AndroidCommonDITags.LOGGER)), + bundleId = get(named(AndroidCommonDITags.BUNDLE_ID)) + ) + } + + single { + SendClickNetworkHelpUseCase( + pulseService = get(), + logger = get(named(AndroidCommonDITags.LOGGER)), + bundleId = get(named(AndroidCommonDITags.BUNDLE_ID)) + ) + } + + single { + SendClickNetworksUseCase( + pulseService = get(), + logger = get(named(AndroidCommonDITags.LOGGER)), + bundleId = get(named(AndroidCommonDITags.BUNDLE_ID)) + ) + } + + single { + SendConnectErrorUseCase( + pulseService = get(), + logger = get(named(AndroidCommonDITags.LOGGER)), + bundleId = get(named(AndroidCommonDITags.BUNDLE_ID)) + ) + } + + single { + SendConnectSuccessUseCase( + pulseService = get(), + logger = get(named(AndroidCommonDITags.LOGGER)), + bundleId = get(named(AndroidCommonDITags.BUNDLE_ID)) + ) + } + + single { + SendDisconnectErrorUseCase( + pulseService = get(), + logger = get(named(AndroidCommonDITags.LOGGER)), + bundleId = get(named(AndroidCommonDITags.BUNDLE_ID)) + ) + } + + single { + SendDisconnectSuccessUseCase( + pulseService = get(), + logger = get(named(AndroidCommonDITags.LOGGER)), + bundleId = get(named(AndroidCommonDITags.BUNDLE_ID)) + ) + } + + single { + SendModalCloseUseCase( + pulseService = get(), + logger = get(named(AndroidCommonDITags.LOGGER)), + bundleId = get(named(AndroidCommonDITags.BUNDLE_ID)) + ) + } + + single { + SendModalLoadedUseCase( + pulseService = get(), + logger = get(named(AndroidCommonDITags.LOGGER)), + bundleId = get(named(AndroidCommonDITags.BUNDLE_ID)) + ) + } + + single { + SendModalOpenUseCase( + pulseService = get(), + logger = get(named(AndroidCommonDITags.LOGGER)), + bundleId = get(named(AndroidCommonDITags.BUNDLE_ID)) + ) + } + + single { + SendSelectWalletUseCase( + pulseService = get(), + logger = get(named(AndroidCommonDITags.LOGGER)), + bundleId = get(named(AndroidCommonDITags.BUNDLE_ID)) + ) + } + + single { + SendSwitchNetworkUseCase( + pulseService = get(), + logger = get(named(AndroidCommonDITags.LOGGER)), + bundleId = get(named(AndroidCommonDITags.BUNDLE_ID)) + ) + } +} \ No newline at end of file diff --git a/core/android/src/main/kotlin/com/walletconnect/android/internal/common/di/Web3ModalModule.kt b/core/android/src/main/kotlin/com/walletconnect/android/internal/common/di/Web3ModalModule.kt index 19a75d6e8c..e72bd5567a 100644 --- a/core/android/src/main/kotlin/com/walletconnect/android/internal/common/di/Web3ModalModule.kt +++ b/core/android/src/main/kotlin/com/walletconnect/android/internal/common/di/Web3ModalModule.kt @@ -3,6 +3,8 @@ package com.walletconnect.android.internal.common.di import com.walletconnect.android.BuildConfig import com.walletconnect.android.internal.common.modal.Web3ModalApiRepository import com.walletconnect.android.internal.common.modal.data.network.Web3ModalService +import com.walletconnect.android.internal.common.modal.domain.usecase.EnableAnalyticsUseCase +import com.walletconnect.android.internal.common.modal.domain.usecase.EnableAnalyticsUseCaseInterface import com.walletconnect.android.internal.common.modal.domain.usecase.GetInstalledWalletsIdsUseCase import com.walletconnect.android.internal.common.modal.domain.usecase.GetInstalledWalletsIdsUseCaseInterface import com.walletconnect.android.internal.common.modal.domain.usecase.GetSampleWalletsUseCase @@ -60,4 +62,5 @@ internal fun web3ModalModule() = module { single { GetInstalledWalletsIdsUseCase(web3ModalApiRepository = get()) } single { GetWalletsUseCase(web3ModalApiRepository = get()) } single { GetSampleWalletsUseCase(context = get()) } + single { EnableAnalyticsUseCase(repository = get()) } } diff --git a/core/android/src/main/kotlin/com/walletconnect/android/internal/common/modal/Web3ModalApiRepository.kt b/core/android/src/main/kotlin/com/walletconnect/android/internal/common/modal/Web3ModalApiRepository.kt index 5d2ba76efe..cb22ee072d 100644 --- a/core/android/src/main/kotlin/com/walletconnect/android/internal/common/modal/Web3ModalApiRepository.kt +++ b/core/android/src/main/kotlin/com/walletconnect/android/internal/common/modal/Web3ModalApiRepository.kt @@ -21,6 +21,12 @@ internal class Web3ModalApiRepository( response.body()!!.data.toWalletsAppData().filter { it.isInstalled } } + suspend fun getAnalyticsConfig(sdkType: String = "w3m") = runCatching { + web3ModalService.getAnalyticsConfig(sdkType = sdkType) + }.mapCatching { response -> + response.body()!!.isAnalyticsEnabled + } + suspend fun getWallets( sdkType: String, page: Int, diff --git a/core/android/src/main/kotlin/com/walletconnect/android/internal/common/modal/data/network/Web3ModalService.kt b/core/android/src/main/kotlin/com/walletconnect/android/internal/common/modal/data/network/Web3ModalService.kt index b12711de5c..4a60589adf 100644 --- a/core/android/src/main/kotlin/com/walletconnect/android/internal/common/modal/data/network/Web3ModalService.kt +++ b/core/android/src/main/kotlin/com/walletconnect/android/internal/common/modal/data/network/Web3ModalService.kt @@ -1,5 +1,6 @@ package com.walletconnect.android.internal.common.modal.data.network +import com.walletconnect.android.internal.common.modal.data.network.model.EnableAnalyticsDTO import com.walletconnect.android.internal.common.modal.data.network.model.GetAndroidDataDTO import com.walletconnect.android.internal.common.modal.data.network.model.GetWalletsDTO import retrofit2.Response @@ -23,4 +24,9 @@ internal interface Web3ModalService { suspend fun getAndroidData( @Header("x-sdk-type") sdkType: String, ): Response + + @GET("getAnalyticsConfig") + suspend fun getAnalyticsConfig( + @Header("x-sdk-type") sdkType: String, + ): Response } diff --git a/core/android/src/main/kotlin/com/walletconnect/android/internal/common/modal/data/network/model/EnableAnalyticsDTO.kt b/core/android/src/main/kotlin/com/walletconnect/android/internal/common/modal/data/network/model/EnableAnalyticsDTO.kt new file mode 100644 index 0000000000..ccb7dfe0b8 --- /dev/null +++ b/core/android/src/main/kotlin/com/walletconnect/android/internal/common/modal/data/network/model/EnableAnalyticsDTO.kt @@ -0,0 +1,8 @@ +package com.walletconnect.android.internal.common.modal.data.network.model + +import com.squareup.moshi.Json + +data class EnableAnalyticsDTO( + @Json(name = "isAnalyticsEnabled") + val isAnalyticsEnabled: Boolean +) diff --git a/core/android/src/main/kotlin/com/walletconnect/android/internal/common/modal/domain/usecase/EnableAnalyticsUseCase.kt b/core/android/src/main/kotlin/com/walletconnect/android/internal/common/modal/domain/usecase/EnableAnalyticsUseCase.kt new file mode 100644 index 0000000000..716caa09b6 --- /dev/null +++ b/core/android/src/main/kotlin/com/walletconnect/android/internal/common/modal/domain/usecase/EnableAnalyticsUseCase.kt @@ -0,0 +1,25 @@ +package com.walletconnect.android.internal.common.modal.domain.usecase + +import com.walletconnect.android.internal.common.modal.Web3ModalApiRepository +import kotlinx.coroutines.runBlocking + +interface EnableAnalyticsUseCaseInterface { + fun fetchAnalyticsConfig(): Boolean +} + +internal class EnableAnalyticsUseCase(private val repository: Web3ModalApiRepository) : EnableAnalyticsUseCaseInterface { + override fun fetchAnalyticsConfig(): Boolean { + return runBlocking { + try { + val response = repository.getAnalyticsConfig() + if (response.isSuccess) { + response.getOrDefault(false) + } else { + false + } + } catch (e: Exception) { + false + } + } + } +} \ No newline at end of file diff --git a/core/android/src/main/kotlin/com/walletconnect/android/pulse/data/PulseService.kt b/core/android/src/main/kotlin/com/walletconnect/android/pulse/data/PulseService.kt new file mode 100644 index 0000000000..bcc135978e --- /dev/null +++ b/core/android/src/main/kotlin/com/walletconnect/android/pulse/data/PulseService.kt @@ -0,0 +1,16 @@ +@file:JvmSynthetic + +package com.walletconnect.android.pulse.data + +import com.walletconnect.android.pulse.model.Event +import retrofit2.Response +import retrofit2.http.Body +import retrofit2.http.Header +import retrofit2.http.Headers +import retrofit2.http.POST + +interface PulseService { + @Headers("Content-Type: application/json") + @POST("/e") + suspend fun sendEvent(@Header("x-sdk-type") sdkType: String = "w3m", @Body body: Event): Response +} \ No newline at end of file diff --git a/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendClickAllWalletsUseCase.kt b/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendClickAllWalletsUseCase.kt new file mode 100644 index 0000000000..97b0a9910e --- /dev/null +++ b/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendClickAllWalletsUseCase.kt @@ -0,0 +1,25 @@ +package com.walletconnect.android.pulse.domain + +import com.walletconnect.android.internal.utils.currentTimeInSeconds +import com.walletconnect.android.pulse.data.PulseService +import com.walletconnect.android.pulse.model.Event +import com.walletconnect.android.pulse.model.properties.Props +import com.walletconnect.foundation.util.Logger +import com.walletconnect.util.generateId + +class SendClickAllWalletsUseCase( + pulseService: PulseService, + logger: Logger, + bundleId: String +) : SendEventUseCase(pulseService, logger, bundleId) { + operator fun invoke() { + super.invoke( + Event( + eventId = generateId(), + bundleId = bundleId, + timestamp = currentTimeInSeconds, + props = Props.ClickAllWallets() + ) + ) + } +} \ No newline at end of file diff --git a/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendClickGetWalletUseCase.kt b/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendClickGetWalletUseCase.kt new file mode 100644 index 0000000000..380d5d812d --- /dev/null +++ b/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendClickGetWalletUseCase.kt @@ -0,0 +1,25 @@ +package com.walletconnect.android.pulse.domain + +import com.walletconnect.android.internal.utils.currentTimeInSeconds +import com.walletconnect.android.pulse.data.PulseService +import com.walletconnect.android.pulse.model.Event +import com.walletconnect.android.pulse.model.properties.Props +import com.walletconnect.foundation.util.Logger +import com.walletconnect.util.generateId + +class SendClickGetWalletUseCase( + pulseService: PulseService, + logger: Logger, + bundleId: String +) : SendEventUseCase(pulseService, logger, bundleId) { + operator fun invoke() { + super.invoke( + Event( + eventId = generateId(), + bundleId = bundleId, + timestamp = currentTimeInSeconds, + props = Props.ClickGetWallet() + ) + ) + } +} \ No newline at end of file diff --git a/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendClickNetworkHelpUseCase.kt b/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendClickNetworkHelpUseCase.kt new file mode 100644 index 0000000000..6d7693a826 --- /dev/null +++ b/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendClickNetworkHelpUseCase.kt @@ -0,0 +1,25 @@ +package com.walletconnect.android.pulse.domain + +import com.walletconnect.android.internal.utils.currentTimeInSeconds +import com.walletconnect.android.pulse.data.PulseService +import com.walletconnect.android.pulse.model.Event +import com.walletconnect.android.pulse.model.properties.Props +import com.walletconnect.foundation.util.Logger +import com.walletconnect.util.generateId + +class SendClickNetworkHelpUseCase( + pulseService: PulseService, + logger: Logger, + bundleId: String +) : SendEventUseCase(pulseService, logger, bundleId) { + operator fun invoke() { + super.invoke( + Event( + eventId = generateId(), + bundleId = bundleId, + timestamp = currentTimeInSeconds, + props = Props.ClickNetworkHelp() + ) + ) + } +} \ No newline at end of file diff --git a/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendClickNetworksUseCase.kt b/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendClickNetworksUseCase.kt new file mode 100644 index 0000000000..e58e760929 --- /dev/null +++ b/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendClickNetworksUseCase.kt @@ -0,0 +1,25 @@ +package com.walletconnect.android.pulse.domain + +import com.walletconnect.android.internal.utils.currentTimeInSeconds +import com.walletconnect.android.pulse.data.PulseService +import com.walletconnect.android.pulse.model.Event +import com.walletconnect.android.pulse.model.properties.Props +import com.walletconnect.foundation.util.Logger +import com.walletconnect.util.generateId + +class SendClickNetworksUseCase( + pulseService: PulseService, + logger: Logger, + bundleId: String +) : SendEventUseCase(pulseService, logger, bundleId) { + operator fun invoke() { + super.invoke( + Event( + eventId = generateId(), + bundleId = bundleId, + timestamp = currentTimeInSeconds, + props = Props.ClickNetworks() + ) + ) + } +} \ No newline at end of file diff --git a/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendClickWalletHelpUseCase.kt b/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendClickWalletHelpUseCase.kt new file mode 100644 index 0000000000..5c465168bb --- /dev/null +++ b/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendClickWalletHelpUseCase.kt @@ -0,0 +1,25 @@ +package com.walletconnect.android.pulse.domain + +import com.walletconnect.android.internal.utils.currentTimeInSeconds +import com.walletconnect.android.pulse.data.PulseService +import com.walletconnect.android.pulse.model.Event +import com.walletconnect.android.pulse.model.properties.Props +import com.walletconnect.foundation.util.Logger +import com.walletconnect.util.generateId + +class SendClickWalletHelpUseCase( + pulseService: PulseService, + logger: Logger, + bundleId: String +) : SendEventUseCase(pulseService, logger, bundleId) { + operator fun invoke() { + super.invoke( + Event( + eventId = generateId(), + bundleId = bundleId, + timestamp = currentTimeInSeconds, + props = Props.ClickWalletHelp() + ) + ) + } +} \ No newline at end of file diff --git a/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendConnectErrorUseCase.kt b/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendConnectErrorUseCase.kt new file mode 100644 index 0000000000..f14388a62d --- /dev/null +++ b/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendConnectErrorUseCase.kt @@ -0,0 +1,27 @@ +package com.walletconnect.android.pulse.domain + +import com.walletconnect.android.internal.utils.currentTimeInSeconds +import com.walletconnect.android.pulse.data.PulseService +import com.walletconnect.android.pulse.model.Event +import com.walletconnect.android.pulse.model.properties.ConnectErrorProperties +import com.walletconnect.android.pulse.model.properties.Props +import com.walletconnect.foundation.util.Logger +import com.walletconnect.util.generateId + +class SendConnectErrorUseCase( + pulseService: PulseService, + logger: Logger, + bundleId: String +) : SendEventUseCase(pulseService, logger, bundleId) { + operator fun invoke(message: String) { + val properties = ConnectErrorProperties(message) + super.invoke( + Event( + eventId = generateId(), + bundleId = bundleId, + timestamp = currentTimeInSeconds, + props = Props.ConnectError(properties = properties) + ) + ) + } +} \ No newline at end of file diff --git a/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendConnectSuccessUseCase.kt b/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendConnectSuccessUseCase.kt new file mode 100644 index 0000000000..d719c5fd59 --- /dev/null +++ b/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendConnectSuccessUseCase.kt @@ -0,0 +1,27 @@ +package com.walletconnect.android.pulse.domain + +import com.walletconnect.android.internal.utils.currentTimeInSeconds +import com.walletconnect.android.pulse.data.PulseService +import com.walletconnect.android.pulse.model.Event +import com.walletconnect.android.pulse.model.properties.ConnectSuccessProperties +import com.walletconnect.android.pulse.model.properties.Props +import com.walletconnect.foundation.util.Logger +import com.walletconnect.util.generateId + +class SendConnectSuccessUseCase( + pulseService: PulseService, + logger: Logger, + bundleId: String +) : SendEventUseCase(pulseService, logger, bundleId) { + operator fun invoke(name: String, method: String) { + val properties = ConnectSuccessProperties(name, method) + super.invoke( + Event( + eventId = generateId(), + bundleId = bundleId, + timestamp = currentTimeInSeconds, + props = Props.ConnectSuccess(properties = properties) + ) + ) + } +} \ No newline at end of file diff --git a/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendDisconnectErrorUseCase.kt b/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendDisconnectErrorUseCase.kt new file mode 100644 index 0000000000..c249deb974 --- /dev/null +++ b/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendDisconnectErrorUseCase.kt @@ -0,0 +1,25 @@ +package com.walletconnect.android.pulse.domain + +import com.walletconnect.android.internal.utils.currentTimeInSeconds +import com.walletconnect.android.pulse.data.PulseService +import com.walletconnect.android.pulse.model.Event +import com.walletconnect.android.pulse.model.properties.Props +import com.walletconnect.foundation.util.Logger +import com.walletconnect.util.generateId + +class SendDisconnectErrorUseCase( + pulseService: PulseService, + logger: Logger, + bundleId: String +) : SendEventUseCase(pulseService, logger, bundleId) { + operator fun invoke() { + super.invoke( + Event( + eventId = generateId(), + bundleId = bundleId, + timestamp = currentTimeInSeconds, + props = Props.DisconnectError() + ) + ) + } +} \ No newline at end of file diff --git a/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendDisconnectSuccessUseCase.kt b/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendDisconnectSuccessUseCase.kt new file mode 100644 index 0000000000..f6d0642f1c --- /dev/null +++ b/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendDisconnectSuccessUseCase.kt @@ -0,0 +1,25 @@ +package com.walletconnect.android.pulse.domain + +import com.walletconnect.android.internal.utils.currentTimeInSeconds +import com.walletconnect.android.pulse.data.PulseService +import com.walletconnect.android.pulse.model.Event +import com.walletconnect.android.pulse.model.properties.Props +import com.walletconnect.foundation.util.Logger +import com.walletconnect.util.generateId + +class SendDisconnectSuccessUseCase( + pulseService: PulseService, + logger: Logger, + bundleId: String +) : SendEventUseCase(pulseService, logger, bundleId) { + operator fun invoke() { + super.invoke( + Event( + eventId = generateId(), + bundleId = bundleId, + timestamp = currentTimeInSeconds, + props = Props.DisconnectSuccess() + ) + ) + } +} \ No newline at end of file diff --git a/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendEventUseCase.kt b/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendEventUseCase.kt new file mode 100644 index 0000000000..0931b23457 --- /dev/null +++ b/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendEventUseCase.kt @@ -0,0 +1,38 @@ +package com.walletconnect.android.pulse.domain + +import com.walletconnect.android.internal.common.di.AndroidCommonDITags +import com.walletconnect.android.internal.common.scope +import com.walletconnect.android.internal.common.wcKoinApp +import com.walletconnect.android.pulse.data.PulseService +import com.walletconnect.android.pulse.model.Event +import com.walletconnect.foundation.util.Logger +import kotlinx.coroutines.launch +import kotlinx.coroutines.supervisorScope +import org.koin.core.qualifier.named + +abstract class SendEventUseCase( + private val pulseService: PulseService, + private val logger: Logger, + internal val bundleId: String +) { + private val enableAnalytics: Boolean by lazy { wcKoinApp.koin.get(named(AndroidCommonDITags.ENABLE_ANALYTICS)) } + + operator fun invoke(event: Event) { + if (enableAnalytics) { + scope.launch { + supervisorScope { + try { + val response = pulseService.sendEvent(body = event) + if (!response.isSuccessful) { + logger.error("Failed to send event: ${event.props.type}") + } else { + logger.log("Event sent successfully: ${event.props.type}") + } + } catch (e: Exception) { + logger.error("Failed to send event: ${event.props.type}, error: $e") + } + } + } + } + } +} \ No newline at end of file diff --git a/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendModalCloseUseCase.kt b/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendModalCloseUseCase.kt new file mode 100644 index 0000000000..fd7926602c --- /dev/null +++ b/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendModalCloseUseCase.kt @@ -0,0 +1,27 @@ +package com.walletconnect.android.pulse.domain + +import com.walletconnect.android.internal.utils.currentTimeInSeconds +import com.walletconnect.android.pulse.data.PulseService +import com.walletconnect.android.pulse.model.Event +import com.walletconnect.android.pulse.model.properties.ModalConnectedProperties +import com.walletconnect.android.pulse.model.properties.Props +import com.walletconnect.foundation.util.Logger +import com.walletconnect.util.generateId + +class SendModalCloseUseCase( + pulseService: PulseService, + logger: Logger, + bundleId: String +) : SendEventUseCase(pulseService, logger, bundleId) { + operator fun invoke(connected: Boolean) { + val properties = ModalConnectedProperties(connected) + super.invoke( + Event( + eventId = generateId(), + bundleId = bundleId, + timestamp = currentTimeInSeconds, + props = Props.ModalClose(properties = properties) + ) + ) + } +} \ No newline at end of file diff --git a/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendModalCreatedUseCase.kt b/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendModalCreatedUseCase.kt new file mode 100644 index 0000000000..524218465b --- /dev/null +++ b/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendModalCreatedUseCase.kt @@ -0,0 +1,25 @@ +package com.walletconnect.android.pulse.domain + +import com.walletconnect.android.internal.utils.currentTimeInSeconds +import com.walletconnect.android.pulse.data.PulseService +import com.walletconnect.android.pulse.model.Event +import com.walletconnect.android.pulse.model.properties.Props +import com.walletconnect.foundation.util.Logger +import com.walletconnect.util.generateId + +class SendModalCreatedUseCase( + pulseService: PulseService, + logger: Logger, + bundleId: String +) : SendEventUseCase(pulseService, logger, bundleId) { + operator fun invoke() { + super.invoke( + Event( + eventId = generateId(), + bundleId = bundleId, + timestamp = currentTimeInSeconds, + props = Props.ModalCreated() + ) + ) + } +} \ No newline at end of file diff --git a/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendModalLoadedUseCase.kt b/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendModalLoadedUseCase.kt new file mode 100644 index 0000000000..107a0edcd2 --- /dev/null +++ b/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendModalLoadedUseCase.kt @@ -0,0 +1,30 @@ +package com.walletconnect.android.pulse.domain + +import com.walletconnect.android.internal.utils.currentTimeInSeconds +import com.walletconnect.android.pulse.data.PulseService +import com.walletconnect.android.pulse.model.Event +import com.walletconnect.android.pulse.model.properties.Props +import com.walletconnect.foundation.util.Logger +import com.walletconnect.util.generateId + +class SendModalLoadedUseCase( + pulseService: PulseService, + logger: Logger, + bundleId: String +) : SendModalLoadedUseCaseInterface, SendEventUseCase(pulseService, logger, bundleId) { + + override fun sendModalLoadedEvent() { + super.invoke( + Event( + eventId = generateId(), + bundleId = bundleId, + timestamp = currentTimeInSeconds, + props = Props.ModalLoaded() + ) + ) + } +} + +interface SendModalLoadedUseCaseInterface { + fun sendModalLoadedEvent() +} \ No newline at end of file diff --git a/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendModalOpenUseCase.kt b/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendModalOpenUseCase.kt new file mode 100644 index 0000000000..dc333abf38 --- /dev/null +++ b/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendModalOpenUseCase.kt @@ -0,0 +1,27 @@ +package com.walletconnect.android.pulse.domain + +import com.walletconnect.android.internal.utils.currentTimeInSeconds +import com.walletconnect.android.pulse.data.PulseService +import com.walletconnect.android.pulse.model.Event +import com.walletconnect.android.pulse.model.properties.ModalConnectedProperties +import com.walletconnect.android.pulse.model.properties.Props +import com.walletconnect.foundation.util.Logger +import com.walletconnect.util.generateId + +class SendModalOpenUseCase( + pulseService: PulseService, + logger: Logger, + bundleId: String +) : SendEventUseCase(pulseService, logger, bundleId) { + operator fun invoke(connected: Boolean) { + val properties = ModalConnectedProperties(connected) + super.invoke( + Event( + eventId = generateId(), + bundleId = bundleId, + timestamp = currentTimeInSeconds, + props = Props.ModalOpen(properties = properties) + ) + ) + } +} \ No newline at end of file diff --git a/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendSelectWalletUseCase.kt b/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendSelectWalletUseCase.kt new file mode 100644 index 0000000000..b108cca4f9 --- /dev/null +++ b/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendSelectWalletUseCase.kt @@ -0,0 +1,27 @@ +package com.walletconnect.android.pulse.domain + +import com.walletconnect.android.internal.utils.currentTimeInSeconds +import com.walletconnect.android.pulse.data.PulseService +import com.walletconnect.android.pulse.model.Event +import com.walletconnect.android.pulse.model.properties.Props +import com.walletconnect.android.pulse.model.properties.SelectWalletProperties +import com.walletconnect.foundation.util.Logger +import com.walletconnect.util.generateId + +class SendSelectWalletUseCase( + pulseService: PulseService, + logger: Logger, + bundleId: String +) : SendEventUseCase(pulseService, logger, bundleId) { + operator fun invoke(name: String, platform: String) { + val properties = SelectWalletProperties(name, platform) + super.invoke( + Event( + eventId = generateId(), + bundleId = bundleId, + timestamp = currentTimeInSeconds, + props = Props.SelectWallet(properties = properties) + ) + ) + } +} \ No newline at end of file diff --git a/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendSwitchNetworkUseCase.kt b/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendSwitchNetworkUseCase.kt new file mode 100644 index 0000000000..2bd2769a48 --- /dev/null +++ b/core/android/src/main/kotlin/com/walletconnect/android/pulse/domain/SendSwitchNetworkUseCase.kt @@ -0,0 +1,27 @@ +package com.walletconnect.android.pulse.domain + +import com.walletconnect.android.internal.utils.currentTimeInSeconds +import com.walletconnect.android.pulse.data.PulseService +import com.walletconnect.android.pulse.model.Event +import com.walletconnect.android.pulse.model.properties.NetworkProperties +import com.walletconnect.android.pulse.model.properties.Props +import com.walletconnect.foundation.util.Logger +import com.walletconnect.util.generateId + +class SendSwitchNetworkUseCase( + pulseService: PulseService, + logger: Logger, + bundleId: String +) : SendEventUseCase(pulseService, logger, bundleId) { + operator fun invoke(network: String) { + val properties = NetworkProperties(network) + super.invoke( + Event( + eventId = generateId(), + bundleId = bundleId, + timestamp = currentTimeInSeconds, + props = Props.SwitchNetwork(properties = properties) + ) + ) + } +} \ No newline at end of file diff --git a/core/android/src/main/kotlin/com/walletconnect/android/pulse/model/ConnectionMethod.kt b/core/android/src/main/kotlin/com/walletconnect/android/pulse/model/ConnectionMethod.kt new file mode 100644 index 0000000000..2736144189 --- /dev/null +++ b/core/android/src/main/kotlin/com/walletconnect/android/pulse/model/ConnectionMethod.kt @@ -0,0 +1,15 @@ +package com.walletconnect.android.pulse.model + +object ConnectionMethod { + @get:JvmSynthetic + const val QR_CODE = "qrcode" + + @get:JvmSynthetic + const val MOBILE = "mobile" + + @get:JvmSynthetic + const val WEB = "web" + + @get:JvmSynthetic + const val UNDEFINED = "undefined" +} \ No newline at end of file diff --git a/core/android/src/main/kotlin/com/walletconnect/android/pulse/model/Event.kt b/core/android/src/main/kotlin/com/walletconnect/android/pulse/model/Event.kt new file mode 100644 index 0000000000..601000625e --- /dev/null +++ b/core/android/src/main/kotlin/com/walletconnect/android/pulse/model/Event.kt @@ -0,0 +1,17 @@ +package com.walletconnect.android.pulse.model + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass +import com.walletconnect.android.pulse.model.properties.Props + +@JsonClass(generateAdapter = true) +data class Event( + @Json(name = "eventId") + val eventId: Long, + @Json(name = "bundleId") + val bundleId: String, + @Json(name = "timestamp") + val timestamp: Long, + @Json(name = "props") + val props: Props +) \ No newline at end of file diff --git a/core/android/src/main/kotlin/com/walletconnect/android/pulse/model/EventType.kt b/core/android/src/main/kotlin/com/walletconnect/android/pulse/model/EventType.kt new file mode 100644 index 0000000000..722fbd804c --- /dev/null +++ b/core/android/src/main/kotlin/com/walletconnect/android/pulse/model/EventType.kt @@ -0,0 +1,48 @@ +package com.walletconnect.android.pulse.model + +internal object EventType { + @get:JvmSynthetic + const val MODAL_CREATED: String = "MODAL_CREATED" + + @get:JvmSynthetic + const val MODAL_LOADED: String = "MODAL_LOADED" + + @get:JvmSynthetic + const val MODAL_OPEN: String = "MODAL_OPEN" + + @get:JvmSynthetic + const val MODAL_CLOSE: String = "MODAL_CLOSE" + + @get:JvmSynthetic + const val CLICK_ALL_WALLETS: String = "CLICK_ALL_WALLETS" + + @get:JvmSynthetic + const val CLICK_NETWORKS: String = "CLICK_NETWORKS" + + @get:JvmSynthetic + const val SWITCH_NETWORK: String = "SWITCH_NETWORK" + + @get:JvmSynthetic + const val SELECT_WALLET: String = "SELECT_WALLET" + + @get:JvmSynthetic + const val CONNECT_SUCCESS: String = "CONNECT_SUCCESS" + + @get:JvmSynthetic + const val CONNECT_ERROR: String = "CONNECT_ERROR" + + @get:JvmSynthetic + const val DISCONNECT_SUCCESS: String = "DISCONNECT_SUCCESS" + + @get:JvmSynthetic + const val DISCONNECT_ERROR: String = "DISCONNECT_ERROR" + + @get:JvmSynthetic + const val CLICK_WALLET_HELP: String = "CLICK_WALLET_HELP" + + @get:JvmSynthetic + const val CLICK_NETWORK_HELP: String = "CLICK_NETWORK_HELP" + + @get:JvmSynthetic + const val CLICK_GET_WALLET: String = "CLICK_GET_WALLET" +} \ No newline at end of file diff --git a/core/android/src/main/kotlin/com/walletconnect/android/pulse/model/properties/ConnectErrorProperties.kt b/core/android/src/main/kotlin/com/walletconnect/android/pulse/model/properties/ConnectErrorProperties.kt new file mode 100644 index 0000000000..c19159fb19 --- /dev/null +++ b/core/android/src/main/kotlin/com/walletconnect/android/pulse/model/properties/ConnectErrorProperties.kt @@ -0,0 +1,10 @@ +package com.walletconnect.android.pulse.model.properties + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class ConnectErrorProperties( + @Json(name = "message") + val message: String, +) diff --git a/core/android/src/main/kotlin/com/walletconnect/android/pulse/model/properties/ConnectSuccessProperties.kt b/core/android/src/main/kotlin/com/walletconnect/android/pulse/model/properties/ConnectSuccessProperties.kt new file mode 100644 index 0000000000..4203bc733e --- /dev/null +++ b/core/android/src/main/kotlin/com/walletconnect/android/pulse/model/properties/ConnectSuccessProperties.kt @@ -0,0 +1,12 @@ +package com.walletconnect.android.pulse.model.properties + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class ConnectSuccessProperties( + @Json(name = "name") + val name: String, + @Json(name = "method") + val method: String +) \ No newline at end of file diff --git a/core/android/src/main/kotlin/com/walletconnect/android/pulse/model/properties/ModalConnectedProperties.kt b/core/android/src/main/kotlin/com/walletconnect/android/pulse/model/properties/ModalConnectedProperties.kt new file mode 100644 index 0000000000..aa67aac966 --- /dev/null +++ b/core/android/src/main/kotlin/com/walletconnect/android/pulse/model/properties/ModalConnectedProperties.kt @@ -0,0 +1,10 @@ +package com.walletconnect.android.pulse.model.properties + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class ModalConnectedProperties( + @Json(name = "connected") + val connected: Boolean +) \ No newline at end of file diff --git a/core/android/src/main/kotlin/com/walletconnect/android/pulse/model/properties/NetworkProperties.kt b/core/android/src/main/kotlin/com/walletconnect/android/pulse/model/properties/NetworkProperties.kt new file mode 100644 index 0000000000..263cd48cc7 --- /dev/null +++ b/core/android/src/main/kotlin/com/walletconnect/android/pulse/model/properties/NetworkProperties.kt @@ -0,0 +1,10 @@ +package com.walletconnect.android.pulse.model.properties + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class NetworkProperties( + @Json(name = "network") + val network: String +) \ No newline at end of file diff --git a/core/android/src/main/kotlin/com/walletconnect/android/pulse/model/properties/Props.kt b/core/android/src/main/kotlin/com/walletconnect/android/pulse/model/properties/Props.kt new file mode 100644 index 0000000000..31f1cbb2c1 --- /dev/null +++ b/core/android/src/main/kotlin/com/walletconnect/android/pulse/model/properties/Props.kt @@ -0,0 +1,142 @@ +package com.walletconnect.android.pulse.model.properties + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass +import com.walletconnect.android.pulse.model.EventType + +sealed class Props { + abstract val event: String + abstract val type: String + + @JsonClass(generateAdapter = true) + data class ModalCreated( + @Json(name = "event") + override val event: String = "track", + @Json(name = "type") + override val type: String = EventType.MODAL_CREATED, + ) : Props() + + @JsonClass(generateAdapter = true) + data class ModalLoaded( + @Json(name = "event") + override val event: String = "track", + @Json(name = "type") + override val type: String = EventType.MODAL_LOADED, + ) : Props() + + @JsonClass(generateAdapter = true) + data class ModalOpen( + @Json(name = "event") + override val event: String = "track", + @Json(name = "type") + override val type: String = EventType.MODAL_OPEN, + @Json(name = "properties") + val properties: ModalConnectedProperties + ) : Props() + + @JsonClass(generateAdapter = true) + data class ModalClose( + @Json(name = "event") + override val event: String = "track", + @Json(name = "type") + override val type: String = EventType.MODAL_CLOSE, + @Json(name = "properties") + val properties: ModalConnectedProperties + ) : Props() + + @JsonClass(generateAdapter = true) + data class ClickNetworks( + @Json(name = "event") + override val event: String = "track", + @Json(name = "type") + override val type: String = EventType.CLICK_NETWORKS, + ) : Props() + + @JsonClass(generateAdapter = true) + data class ClickAllWallets( + @Json(name = "event") + override val event: String = "track", + @Json(name = "type") + override val type: String = EventType.CLICK_ALL_WALLETS, + ) : Props() + + @JsonClass(generateAdapter = true) + data class SwitchNetwork( + @Json(name = "event") + override val event: String = "track", + @Json(name = "type") + override val type: String = EventType.SWITCH_NETWORK, + @Json(name = "properties") + val properties: NetworkProperties + ) : Props() + + @JsonClass(generateAdapter = true) + data class SelectWallet( + @Json(name = "event") + override val event: String = "track", + @Json(name = "type") + override val type: String = EventType.SELECT_WALLET, + @Json(name = "properties") + val properties: SelectWalletProperties + ) : Props() + + @JsonClass(generateAdapter = true) + data class ConnectSuccess( + @Json(name = "event") + override val event: String = "track", + @Json(name = "type") + override val type: String = EventType.CONNECT_SUCCESS, + @Json(name = "properties") + val properties: ConnectSuccessProperties + ) : Props() + + @JsonClass(generateAdapter = true) + data class ConnectError( + @Json(name = "event") + override val event: String = "track", + @Json(name = "type") + override val type: String = EventType.CONNECT_ERROR, + @Json(name = "properties") + val properties: ConnectErrorProperties + ) : Props() + + @JsonClass(generateAdapter = true) + data class DisconnectSuccess( + @Json(name = "event") + override val event: String = "track", + @Json(name = "type") + override val type: String = EventType.DISCONNECT_SUCCESS + ) : Props() + + @JsonClass(generateAdapter = true) + data class DisconnectError( + @Json(name = "event") + override val event: String = "track", + @Json(name = "type") + override val type: String = EventType.DISCONNECT_ERROR + ) : Props() + + @JsonClass(generateAdapter = true) + data class ClickWalletHelp( + @Json(name = "event") + override val event: String = "track", + @Json(name = "type") + override val type: String = EventType.CLICK_WALLET_HELP + ) : Props() + + @JsonClass(generateAdapter = true) + data class ClickNetworkHelp( + @Json(name = "event") + override val event: String = "track", + @Json(name = "type") + override val type: String = EventType.CLICK_NETWORK_HELP + ) : Props() + + @JsonClass(generateAdapter = true) + data class ClickGetWallet( + @Json(name = "event") + override val event: String = "track", + @Json(name = "type") + override val type: String = EventType.CLICK_GET_WALLET + ) : Props() +} diff --git a/core/android/src/main/kotlin/com/walletconnect/android/pulse/model/properties/SelectWalletProperties.kt b/core/android/src/main/kotlin/com/walletconnect/android/pulse/model/properties/SelectWalletProperties.kt new file mode 100644 index 0000000000..956c84e324 --- /dev/null +++ b/core/android/src/main/kotlin/com/walletconnect/android/pulse/model/properties/SelectWalletProperties.kt @@ -0,0 +1,10 @@ +package com.walletconnect.android.pulse.model.properties + +import com.squareup.moshi.Json + +data class SelectWalletProperties( + @Json(name = "name") + val name: String, + @Json(name = "platform") + val platform: String +) \ No newline at end of file diff --git a/core/modal/src/main/kotlin/com/walletconnect/modal/utils/UriExtensions.kt b/core/modal/src/main/kotlin/com/walletconnect/modal/utils/UriExtensions.kt index 3e245a8151..e7f6fbb20a 100644 --- a/core/modal/src/main/kotlin/com/walletconnect/modal/utils/UriExtensions.kt +++ b/core/modal/src/main/kotlin/com/walletconnect/modal/utils/UriExtensions.kt @@ -14,6 +14,14 @@ fun UriHandler.openUri(uri: String, onError: (e: Throwable) -> Unit) { } } +fun UriHandler.goToNativeWallet(uri: String, nativeLink: String?) { + try { + nativeLink?.let { openUri(formatNativeDeeplink(it, uri)) } ?: Timber.e("Invalid native link") + } catch (e: Exception) { + Timber.e(e) + } +} + fun UriHandler.openMobileLink( uri: String, mobileLink: String?, @@ -26,14 +34,6 @@ fun UriHandler.openMobileLink( } } -fun UriHandler.goToNativeWallet(uri: String, nativeLink: String?) { - try { - nativeLink?.let { openUri(formatNativeDeeplink(it, uri)) } ?: Timber.e("Invalid native link") - } catch (e: Exception) { - Timber.e(e) - } -} - fun UriHandler.openWebAppLink(uri: String, universalLink: String?) { try { universalLink?.let { openUri(formatUniversalLink(it, uri)) } ?: Timber.e("Invalid universal link") diff --git a/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/client/Modal.kt b/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/client/Modal.kt index 46e37d1ff0..4f017b0a75 100644 --- a/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/client/Modal.kt +++ b/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/client/Modal.kt @@ -21,7 +21,8 @@ object Modal { val core: CoreInterface, val excludedWalletIds: List = listOf(), val recommendedWalletsIds: List = listOf(), - val coinbaseEnabled: Boolean = true + val coinbaseEnabled: Boolean = true, + val enableAnalytics: Boolean? = null ) : Params() data class Connect( @@ -111,13 +112,13 @@ object Modal { val metaData: Core.Model.AppMetaData?, val namespaces: Map, val accounts: List, - ): ApprovedSession() + ) : ApprovedSession() data class CoinbaseSession( val chain: String, val networkId: String, val address: String - ): ApprovedSession() + ) : ApprovedSession() } data class RejectedSession(val topic: String, val reason: String) : Model() diff --git a/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/client/Web3Modal.kt b/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/client/Web3Modal.kt index f293ea2c1e..bff381b0cb 100644 --- a/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/client/Web3Modal.kt +++ b/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/client/Web3Modal.kt @@ -1,6 +1,7 @@ package com.walletconnect.web3.modal.client import androidx.activity.ComponentActivity +import com.walletconnect.android.internal.common.di.AndroidCommonDITags import com.walletconnect.android.internal.common.scope import com.walletconnect.android.internal.common.wcKoinApp import com.walletconnect.sign.client.Sign @@ -20,6 +21,8 @@ import com.walletconnect.web3.modal.engine.Web3ModalEngine import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import org.jetbrains.annotations.ApiStatus.Experimental +import org.koin.core.qualifier.named +import org.koin.dsl.module object Web3Modal { @@ -107,9 +110,15 @@ object Web3Modal { web3ModalEngine = wcKoinApp.koin.get() web3ModalEngine.setup(init, onError) web3ModalEngine.setInternalDelegate(Web3ModalDelegate) + wcKoinApp.modules( + module { single(named(AndroidCommonDITags.ENABLE_ANALYTICS)) { init.enableAnalytics ?: web3ModalEngine.fetchAnalyticsConfig() } } + ) } .onFailure { error -> return@onInitializedClient onError(Modal.Model.Error(error)) } - .onSuccess { onSuccess() } + .onSuccess { + onSuccess() + web3ModalEngine.sendModalLoadedEvent() + } } else { onError(Modal.Model.Error(Web3ModelClientAlreadyInitializedException())) } diff --git a/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/di/EngineModule.kt b/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/di/EngineModule.kt index d758846493..f45a0e6b29 100644 --- a/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/di/EngineModule.kt +++ b/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/di/EngineModule.kt @@ -1,12 +1,40 @@ package com.walletconnect.web3.modal.di +import android.content.Context +import com.walletconnect.android.internal.common.di.AndroidCommonDITags +import com.walletconnect.web3.modal.domain.usecase.ConnectionEventRepository import com.walletconnect.web3.modal.engine.Web3ModalEngine import com.walletconnect.web3.modal.engine.coinbase.CoinbaseClient +import org.koin.android.ext.koin.androidContext +import org.koin.core.qualifier.named import org.koin.dsl.module internal fun engineModule() = module { - single { Web3ModalEngine(getSessionUseCase = get(), getSelectedChainUseCase = get(), deleteSessionDataUseCase = get(), saveSessionUseCase = get()) } - single { CoinbaseClient(context = get(), appMetaData = get()) } + single { + ConnectionEventRepository(sharedPreferences = androidContext().getSharedPreferences("ConnectionEvents", Context.MODE_PRIVATE)) + } + single { + Web3ModalEngine( + getSessionUseCase = get(), + getSelectedChainUseCase = get(), + deleteSessionDataUseCase = get(), + saveSessionUseCase = get(), + sendModalLoadedUseCase = get(), + sendDisconnectErrorUseCase = get(), + sendDisconnectSuccessUseCase = get(), + sendConnectErrorUseCase = get(), + sendConnectSuccessUseCase = get(), + connectionEventRepository = get(), + enableAnalyticsUseCase = get(), + logger = get(named(AndroidCommonDITags.LOGGER)), + ) + } + single { + CoinbaseClient( + context = get(), + appMetaData = get() + ) + } } diff --git a/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/di/Web3ModalDITags.kt b/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/di/Web3ModalDITags.kt index 4a56b7b935..24db155f53 100644 --- a/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/di/Web3ModalDITags.kt +++ b/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/di/Web3ModalDITags.kt @@ -4,5 +4,5 @@ internal enum class Web3ModalDITags { BALANCE_RPC_RETROFIT, BLOCKCHAIN_RETROFIT, MOSHI, - SESSION_DATA_STORE + SESSION_DATA_STORE, } \ No newline at end of file diff --git a/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/domain/usecase/ConnectionEventRepository.kt b/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/domain/usecase/ConnectionEventRepository.kt new file mode 100644 index 0000000000..7cf2b616fd --- /dev/null +++ b/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/domain/usecase/ConnectionEventRepository.kt @@ -0,0 +1,32 @@ +package com.walletconnect.web3.modal.domain.usecase + +import android.content.SharedPreferences + +class ConnectionEventRepository(private val sharedPreferences: SharedPreferences) { + + fun saveEvent(name: String, method: String) { + sharedPreferences.edit().apply { + putString(WALLET_NAME, name) + putString(CONNECTION_METHOD, method) + }.apply() + } + + fun getEvent(): Pair { + val walletName = sharedPreferences.getString(WALLET_NAME, "") ?: "" + val connectionMethod = sharedPreferences.getString(CONNECTION_METHOD, "") ?: "" + return if (walletName.isNotEmpty() && connectionMethod.isNotEmpty()) { + Pair(walletName, connectionMethod) + } else { + Pair("", "") + } + } + + fun deleteEvent() { + sharedPreferences.edit().clear().apply() + } + + private companion object { + const val WALLET_NAME = "wallet_name" + const val CONNECTION_METHOD = "connection_method" + } +} \ No newline at end of file diff --git a/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/engine/Web3ModalEngine.kt b/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/engine/Web3ModalEngine.kt index 3efc6eb091..160d0d2bc8 100644 --- a/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/engine/Web3ModalEngine.kt +++ b/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/engine/Web3ModalEngine.kt @@ -1,13 +1,19 @@ package com.walletconnect.web3.modal.engine - import android.content.Context import android.content.Intent import android.net.Uri import androidx.activity.ComponentActivity import androidx.activity.result.contract.ActivityResultContracts +import com.walletconnect.android.internal.common.modal.domain.usecase.EnableAnalyticsUseCaseInterface import com.walletconnect.android.internal.common.scope import com.walletconnect.android.internal.common.wcKoinApp +import com.walletconnect.android.pulse.domain.SendConnectErrorUseCase +import com.walletconnect.android.pulse.domain.SendConnectSuccessUseCase +import com.walletconnect.android.pulse.domain.SendDisconnectErrorUseCase +import com.walletconnect.android.pulse.domain.SendDisconnectSuccessUseCase +import com.walletconnect.android.pulse.domain.SendModalLoadedUseCaseInterface +import com.walletconnect.foundation.util.Logger import com.walletconnect.sign.client.Sign import com.walletconnect.sign.client.SignClient import com.walletconnect.util.Empty @@ -25,6 +31,7 @@ import com.walletconnect.web3.modal.client.toSign import com.walletconnect.web3.modal.domain.delegate.Web3ModalDelegate import com.walletconnect.web3.modal.domain.model.InvalidSessionException import com.walletconnect.web3.modal.domain.model.Session +import com.walletconnect.web3.modal.domain.usecase.ConnectionEventRepository import com.walletconnect.web3.modal.domain.usecase.DeleteSessionDataUseCase import com.walletconnect.web3.modal.domain.usecase.GetSelectedChainUseCase import com.walletconnect.web3.modal.domain.usecase.GetSessionUseCase @@ -43,7 +50,16 @@ internal class Web3ModalEngine( private val getSelectedChainUseCase: GetSelectedChainUseCase, private val saveSessionUseCase: SaveSessionUseCase, private val deleteSessionDataUseCase: DeleteSessionDataUseCase, -) { + private val sendModalLoadedUseCase: SendModalLoadedUseCaseInterface, + private val sendDisconnectSuccessUseCase: SendDisconnectSuccessUseCase, + private val sendDisconnectErrorUseCase: SendDisconnectErrorUseCase, + private val sendConnectErrorUseCase: SendConnectErrorUseCase, + private val sendConnectSuccessUseCase: SendConnectSuccessUseCase, + private val connectionEventRepository: ConnectionEventRepository, + private val enableAnalyticsUseCase: EnableAnalyticsUseCaseInterface, + private val logger: Logger +) : SendModalLoadedUseCaseInterface by sendModalLoadedUseCase, + EnableAnalyticsUseCaseInterface by enableAnalyticsUseCase { internal var excludedWalletsIds: MutableList = mutableListOf() internal var recommendedWalletsIds: MutableList = mutableListOf() @@ -71,14 +87,13 @@ internal class Web3ModalEngine( } fun connectWC( + name: String, method: String, connect: Modal.Params.Connect, onSuccess: (String) -> Unit, onError: (Throwable) -> Unit ) { - SignClient.connect( - connect.toSign(), - onSuccess - ) { onError(it.throwable) } + connectionEventRepository.saveEvent(name, method) + SignClient.connect(connect.toSign(), onSuccess) { onError(it.throwable) } } fun connectCoinbase( @@ -129,8 +144,8 @@ internal class Web3ModalEngine( coinbaseClient.request(request, { onSuccess(SentRequestResult.Coinbase(request.method, request.params, selectedChain.id, it)) }, onError) } - is Session.WalletConnect -> SignClient.request( - request.toSign(session.topic, selectedChain.id), + is Session.WalletConnect -> + SignClient.request(request.toSign(session.topic, selectedChain.id), { onSuccess(it.toSentRequest()) openWalletApp(session.topic, onError) @@ -175,7 +190,17 @@ internal class Web3ModalEngine( onSuccess() } - is Session.WalletConnect -> SignClient.disconnect(Sign.Params.Disconnect(session.topic), { onSuccess() }, { onError(it.throwable) }) + is Session.WalletConnect -> { + SignClient.disconnect(Sign.Params.Disconnect(session.topic), + onSuccess = { + sendDisconnectSuccessUseCase() + onSuccess() + }, + onError = { + sendDisconnectErrorUseCase() + onError(it.throwable) + }) + } } } @@ -191,7 +216,7 @@ internal class Web3ModalEngine( } fun getSession() = getSessionUseCase()?.let { session -> - when(session) { + when (session) { is Session.Coinbase -> coinbaseClient.getAccount(session)?.toCoinbaseSession() is Session.WalletConnect -> SignClient.getActiveSessionByTopic(session.topic)?.toSession() } @@ -201,10 +226,24 @@ internal class Web3ModalEngine( fun setInternalDelegate(delegate: Web3ModalDelegate) { val signDelegate = object : SignClient.DappDelegate { override fun onSessionApproved(approvedSession: Sign.Model.ApprovedSession) { + try { + val (name, method) = connectionEventRepository.getEvent() + sendConnectSuccessUseCase(name = name, method = method) + connectionEventRepository.deleteEvent() + } catch (e: Exception) { + logger.error(e) + } + delegate.onSessionApproved(approvedSession.toModal()) } override fun onSessionRejected(rejectedSession: Sign.Model.RejectedSession) { + try { + connectionEventRepository.deleteEvent() + } catch (e: Exception) { + logger.error(e) + } + sendConnectErrorUseCase(message = rejectedSession.reason) delegate.onSessionRejected(rejectedSession.toModal()) } diff --git a/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/components/ComponentDelegate.kt b/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/components/ComponentDelegate.kt index 0b7994f073..84afaebb37 100644 --- a/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/components/ComponentDelegate.kt +++ b/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/components/ComponentDelegate.kt @@ -1,36 +1,36 @@ package com.walletconnect.web3.modal.ui.components import com.walletconnect.web3.modal.client.Web3Modal -import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.onEach internal sealed class ComponentEvent(val isOpen: Boolean) { - object ModalHiddenEvent: ComponentEvent(false) - object ModalExpandedEvent: ComponentEvent(true) + object ModalHiddenEvent : ComponentEvent(false) + object ModalExpandedEvent : ComponentEvent(true) } internal object ComponentDelegate { - val modalComponentEvent: MutableSharedFlow = MutableSharedFlow() + val modalComponentEvent: MutableStateFlow = MutableStateFlow(ComponentEvent.ModalHiddenEvent) var isModalOpen: Boolean = false fun setDelegate(delegate: Web3Modal.ComponentDelegate) { modalComponentEvent.onEach { event -> - when(event) { + when (event) { ComponentEvent.ModalHiddenEvent -> delegate.onModalHidden() ComponentEvent.ModalExpandedEvent -> delegate.onModalExpanded() } } } - suspend fun openModalEvent() { - modalComponentEvent.emit(ComponentEvent.ModalExpandedEvent) + fun openModalEvent() { + modalComponentEvent.compareAndSet(ComponentEvent.ModalHiddenEvent, ComponentEvent.ModalExpandedEvent) isModalOpen = true } - suspend fun closeModalEvent() { - modalComponentEvent.emit(ComponentEvent.ModalHiddenEvent) + fun closeModalEvent() { + modalComponentEvent.compareAndSet(ComponentEvent.ModalExpandedEvent, ComponentEvent.ModalHiddenEvent) isModalOpen = false } } diff --git a/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/components/button/ConnectButton.kt b/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/components/button/ConnectButton.kt index 7220021b95..5e13f1a2cc 100644 --- a/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/components/button/ConnectButton.kt +++ b/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/components/button/ConnectButton.kt @@ -23,7 +23,7 @@ fun ConnectButton( buttonSize: ConnectButtonSize = ConnectButtonSize.NORMAL ) { val isLoading: Boolean by state.isOpen.collectAsState(initial = false) - val isConnected by state.isConnected.collectAsState(initial = false) + val isConnected: Boolean by state.isConnected.collectAsState(initial = false) ConnectButton( size = buttonSize, diff --git a/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/components/button/NetworkButton.kt b/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/components/button/NetworkButton.kt index 9832907986..538b777cc5 100644 --- a/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/components/button/NetworkButton.kt +++ b/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/components/button/NetworkButton.kt @@ -14,7 +14,7 @@ import com.walletconnect.web3.modal.utils.getImageData @Composable fun NetworkButton( - state: Web3ModalState, + state: Web3ModalState ) { val selectedChain by state.selectedChain.collectAsState(initial = null) val image: @Composable () -> Unit = selectedChain?.let { chain -> @@ -26,7 +26,7 @@ fun NetworkButton( text = selectedChain?.chainName ?: "Select Network", image = image, isEnabled = true, - onClick = { state.openWeb3Modal(true) } + onClick = { state.openWeb3Modal(true, selectedChain != null) } ) } diff --git a/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/components/button/Web3ModalState.kt b/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/components/button/Web3ModalState.kt index 58164804b2..f4c1c58c5d 100644 --- a/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/components/button/Web3ModalState.kt +++ b/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/components/button/Web3ModalState.kt @@ -5,6 +5,9 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.navigation.NavController import com.walletconnect.android.internal.common.wcKoinApp +import com.walletconnect.android.pulse.domain.SendClickNetworksUseCase +import com.walletconnect.android.pulse.domain.SendModalCloseUseCase +import com.walletconnect.android.pulse.domain.SendModalOpenUseCase import com.walletconnect.foundation.util.Logger import com.walletconnect.web3.modal.client.Modal import com.walletconnect.web3.modal.client.Web3Modal @@ -15,6 +18,7 @@ import com.walletconnect.web3.modal.domain.usecase.ObserveSelectedChainUseCase import com.walletconnect.web3.modal.domain.usecase.ObserveSessionUseCase import com.walletconnect.web3.modal.engine.Web3ModalEngine import com.walletconnect.web3.modal.ui.components.ComponentDelegate +import com.walletconnect.web3.modal.ui.components.ComponentEvent import com.walletconnect.web3.modal.ui.openWeb3Modal import com.walletconnect.web3.modal.utils.getChainNetworkImageUrl import com.walletconnect.web3.modal.utils.getChains @@ -37,7 +41,7 @@ fun rememberWeb3ModalState( } class Web3ModalState( - private val coroutineScope: CoroutineScope, + coroutineScope: CoroutineScope, private val navController: NavController ) { private val logger: Logger = wcKoinApp.koin.get() @@ -46,13 +50,18 @@ class Web3ModalState( private val getSessionUseCase: GetSessionUseCase = wcKoinApp.koin.get() private val getEthBalanceUseCase: GetEthBalanceUseCase = wcKoinApp.koin.get() private val web3ModalEngine: Web3ModalEngine = wcKoinApp.koin.get() + private val sendModalOpenEvent: SendModalOpenUseCase = wcKoinApp.koin.get() + private val sendModalCloseEvent: SendModalCloseUseCase = wcKoinApp.koin.get() + private val sendClickNetworksEvent: SendClickNetworksUseCase = wcKoinApp.koin.get() + private val sessionTopicFlow = observeSessionTopicUseCase() val isOpen = ComponentDelegate.modalComponentEvent - .map { event -> event.isOpen } + .map { event -> + sendModalCloseOrOpenEvents(event) + event.isOpen + } .stateIn(coroutineScope, started = SharingStarted.Lazily, ComponentDelegate.isModalOpen) - private val sessionTopicFlow = observeSessionTopicUseCase() - val isConnected = sessionTopicFlow .map { it != null && getSessionUseCase() != null } .map { Web3Modal.getAccount() != null } @@ -66,13 +75,22 @@ class Web3ModalState( .mapOrAccountState(AccountButtonType.NORMAL) .stateIn(coroutineScope, started = SharingStarted.Lazily, initialValue = AccountButtonState.Loading) - internal val accountMixedButtonState = sessionTopicFlow.combine(selectedChain) { session, chain -> session to chain} + internal val accountMixedButtonState = sessionTopicFlow.combine(selectedChain) { session, chain -> session to chain } .mapOrAccountState(AccountButtonType.MIXED) .stateIn(coroutineScope, started = SharingStarted.Lazily, initialValue = AccountButtonState.Loading) private fun Flow>.mapOrAccountState(accountButtonType: AccountButtonType) = map { web3ModalEngine.getActiveSession()?.mapToAccountButtonState(accountButtonType) ?: AccountButtonState.Invalid } + private fun sendModalCloseOrOpenEvents(event: ComponentEvent) { + when { + event.isOpen && isConnected.value -> sendModalOpenEvent(connected = true) + event.isOpen && !isConnected.value -> sendModalOpenEvent(connected = false) + !event.isOpen && isConnected.value -> sendModalCloseEvent(connected = true) + !event.isOpen && !isConnected.value -> sendModalCloseEvent(connected = false) + } + } + private suspend fun Session.mapToAccountButtonState(accountButtonType: AccountButtonType) = try { val chains = getChains() val selectedChain = chains.getSelectedChain(this.chain) @@ -96,7 +114,11 @@ class Web3ModalState( private suspend fun getBalance(selectedChain: Modal.Model.Chain, address: String) = selectedChain.rpcUrl?.let { url -> getEthBalanceUseCase(selectedChain.token, url, address)?.valueWithSymbol } - internal fun openWeb3Modal(shouldOpenChooseNetwork: Boolean = false) { + internal fun openWeb3Modal(shouldOpenChooseNetwork: Boolean = false, isActiveNetwork: Boolean = false) { + if (shouldOpenChooseNetwork && isActiveNetwork) { + sendClickNetworksEvent() + } + navController.openWeb3Modal( shouldOpenChooseNetwork = shouldOpenChooseNetwork, onError = { logger.error(it) } diff --git a/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/components/internal/Web3ModalComponent.kt b/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/components/internal/Web3ModalComponent.kt index cd75013d53..d20a8650db 100644 --- a/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/components/internal/Web3ModalComponent.kt +++ b/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/components/internal/Web3ModalComponent.kt @@ -2,7 +2,6 @@ package com.walletconnect.web3.modal.ui.components.internal -import android.net.Uri import androidx.compose.animation.AnimatedContent import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.animation.core.tween @@ -60,8 +59,11 @@ internal fun Web3ModalComponent( Web3ModalDelegate .wcEventModels .onEach { event -> - when(event) { - is Modal.Model.ApprovedSession, is Modal.Model.DeletedSession.Success -> { closeModal() } + when (event) { + is Modal.Model.ApprovedSession, is Modal.Model.DeletedSession.Success -> { + closeModal() + } + else -> Unit } } @@ -93,11 +95,13 @@ internal fun Web3ModalComponent( navController = navController, shouldOpenChooseNetwork = shouldOpenChooseNetwork ) + is Web3ModalState.AccountState -> AccountNavGraph( navController = navController, closeModal = closeModal, shouldOpenChangeNetwork = shouldOpenChooseNetwork ) + Web3ModalState.Loading -> LoadingModalState() is Web3ModalState.Error -> ErrorModalState(retry = web3ModalViewModel::initModalState) } diff --git a/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/components/internal/root/Web3ModalRootState.kt b/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/components/internal/root/Web3ModalRootState.kt index c0a61ab5ab..c48f6a3d68 100644 --- a/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/components/internal/root/Web3ModalRootState.kt +++ b/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/components/internal/root/Web3ModalRootState.kt @@ -5,6 +5,8 @@ import androidx.compose.runtime.remember import androidx.navigation.NavBackStackEntry import androidx.navigation.NavController import androidx.navigation.NavDestination +import com.walletconnect.android.internal.common.wcKoinApp +import com.walletconnect.android.pulse.domain.SendClickWalletHelpUseCase import com.walletconnect.web3.modal.ui.navigation.Route import com.walletconnect.web3.modal.ui.navigation.getTitleArg import kotlinx.coroutines.CoroutineScope @@ -25,6 +27,7 @@ internal class Web3ModalRootState( private val coroutineScope: CoroutineScope, private val navController: NavController ) { + private val sendClickWalletHelpUseCase: SendClickWalletHelpUseCase = wcKoinApp.koin.get() val currentDestinationFlow: Flow get() = navController.currentBackStackEntryFlow @@ -38,6 +41,7 @@ internal class Web3ModalRootState( get() = navController.currentDestination?.route fun navigateToHelp() { + sendClickWalletHelpUseCase() navController.navigate(Route.WHAT_IS_WALLET.path) } diff --git a/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/routes/account/AccountViewModel.kt b/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/routes/account/AccountViewModel.kt index 116f6b5794..1da05b37f5 100644 --- a/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/routes/account/AccountViewModel.kt +++ b/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/routes/account/AccountViewModel.kt @@ -3,10 +3,11 @@ package com.walletconnect.web3.modal.ui.routes.account import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.walletconnect.android.internal.common.wcKoinApp +import com.walletconnect.android.pulse.domain.SendClickNetworkHelpUseCase +import com.walletconnect.android.pulse.domain.SendSwitchNetworkUseCase import com.walletconnect.foundation.util.Logger import com.walletconnect.modal.ui.model.UiState import com.walletconnect.web3.modal.client.Modal -import com.walletconnect.web3.modal.client.Web3Modal import com.walletconnect.web3.modal.client.models.request.Request import com.walletconnect.web3.modal.client.models.request.SentRequestResult import com.walletconnect.web3.modal.domain.model.AccountData @@ -46,27 +47,35 @@ internal class AccountViewModel : ViewModel(), Navigator by NavigatorImpl() { private val getIdentityUseCase: GetIdentityUseCase = wcKoinApp.koin.get() private val getEthBalanceUseCase: GetEthBalanceUseCase = wcKoinApp.koin.get() private val web3ModalEngine: Web3ModalEngine = wcKoinApp.koin.get() + private val sendClickNetworkHelpUseCase: SendClickNetworkHelpUseCase = wcKoinApp.koin.get() + private val sendSwitchNetworkUseCase: SendSwitchNetworkUseCase = wcKoinApp.koin.get() private val activeSessionFlow = observeSessionUseCase() private val accountDataFlow = activeSessionFlow - .map { if (web3ModalEngine.getAccount() != null) { it } else { null } } + .map { + if (web3ModalEngine.getAccount() != null) { + it + } else { + null + } + } .map { activeSession -> - if (activeSession != null) { - val chains = activeSession.getChains() - val identity = getIdentityUseCase(activeSession.address, activeSession.chain) - accountData = AccountData( - address = activeSession.address, chains = chains, identity = identity - ) - UiState.Success(accountData) - } else { - UiState.Error(Throwable("Active session not found")) + if (activeSession != null) { + val chains = activeSession.getChains() + val identity = getIdentityUseCase(activeSession.address, activeSession.chain) + accountData = AccountData( + address = activeSession.address, chains = chains, identity = identity + ) + UiState.Success(accountData) + } else { + UiState.Error(Throwable("Active session not found")) + } + }.catch { + showError(it.localizedMessage) + logger.error(it) + emit(UiState.Error(it)) } - }.catch { - showError(it.localizedMessage) - logger.error(it) - emit(UiState.Error(it)) - } lateinit var accountData: AccountData @@ -92,6 +101,7 @@ internal class AccountViewModel : ViewModel(), Navigator by NavigatorImpl() { fun changeActiveChain(chain: Modal.Model.Chain) = viewModelScope.launch { if (accountData.chains.contains(chain)) { + sendSwitchNetworkUseCase(network = chain.id) saveChainSelectionUseCase(chain.id) popBackStack() } else { @@ -101,6 +111,7 @@ internal class AccountViewModel : ViewModel(), Navigator by NavigatorImpl() { suspend fun updatedSessionAfterChainSwitch(updatedSession: Session) { if (updatedSession.getChains().any { it.id == updatedSession.chain }) { + sendSwitchNetworkUseCase(network = updatedSession.chain) saveSessionUseCase(updatedSession) popBackStack(path = Route.CHANGE_NETWORK.path, inclusive = true) } @@ -129,6 +140,7 @@ internal class AccountViewModel : ViewModel(), Navigator by NavigatorImpl() { onError(it.message) onReject() } + is CoinbaseResult.Result -> { viewModelScope.launch { updatedSessionAfterChainSwitch(Session.Coinbase(to.id, accountData.address)) @@ -165,6 +177,7 @@ internal class AccountViewModel : ViewModel(), Navigator by NavigatorImpl() { fun getSelectedChainOrFirst() = web3ModalEngine.getSelectedChainOrFirst() fun navigateToHelp() { + sendClickNetworkHelpUseCase() navigateTo(Route.WHAT_IS_WALLET.path) } } diff --git a/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/routes/connect/ConnectViewModel.kt b/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/routes/connect/ConnectViewModel.kt index 72fe94eff4..bd86ca76f4 100644 --- a/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/routes/connect/ConnectViewModel.kt +++ b/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/routes/connect/ConnectViewModel.kt @@ -4,17 +4,20 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.walletconnect.android.internal.common.modal.data.model.Wallet import com.walletconnect.android.internal.common.wcKoinApp +import com.walletconnect.android.pulse.domain.SendClickAllWalletsUseCase +import com.walletconnect.android.pulse.domain.SendClickNetworkHelpUseCase +import com.walletconnect.android.pulse.domain.SendConnectErrorUseCase +import com.walletconnect.android.pulse.domain.SendSelectWalletUseCase +import com.walletconnect.android.pulse.model.ConnectionMethod import com.walletconnect.foundation.util.Logger import com.walletconnect.modal.ui.model.LoadingState import com.walletconnect.modal.ui.model.UiState -import com.walletconnect.util.Empty import com.walletconnect.web3.modal.client.Modal import com.walletconnect.web3.modal.client.Web3Modal import com.walletconnect.web3.modal.domain.usecase.ObserveSelectedChainUseCase import com.walletconnect.web3.modal.domain.usecase.SaveChainSelectionUseCase import com.walletconnect.web3.modal.domain.usecase.SaveRecentWalletUseCase import com.walletconnect.web3.modal.engine.Web3ModalEngine -import com.walletconnect.web3.modal.engine.coinbase.isCoinbaseWallet import com.walletconnect.web3.modal.ui.navigation.Navigator import com.walletconnect.web3.modal.ui.navigation.NavigatorImpl import com.walletconnect.web3.modal.ui.navigation.Route @@ -32,7 +35,11 @@ internal class ConnectViewModel : ViewModel(), Navigator by NavigatorImpl(), Par private val saveRecentWalletUseCase: SaveRecentWalletUseCase = wcKoinApp.koin.get() private val saveChainSelectionUseCase: SaveChainSelectionUseCase = wcKoinApp.koin.get() private val observeSelectedChainUseCase: ObserveSelectedChainUseCase = wcKoinApp.koin.get() + private val sendClickAllWalletsEvent: SendClickAllWalletsUseCase = wcKoinApp.koin.get() private val web3ModalEngine: Web3ModalEngine = wcKoinApp.koin.get() + private val sendClickNetworkHelpUseCase: SendClickNetworkHelpUseCase = wcKoinApp.koin.get() + private val sendSelectWalletEvent: SendSelectWalletUseCase = wcKoinApp.koin.get() + private val sendConnectErrorUseCase: SendConnectErrorUseCase = wcKoinApp.koin.get() private var sessionParams = getSessionParamsSelectedChain(Web3Modal.selectedChain?.id) @@ -62,12 +69,17 @@ internal class ConnectViewModel : ViewModel(), Navigator by NavigatorImpl(), Par } fun navigateToHelp() { + sendClickNetworkHelpUseCase() navigateTo(Route.WHAT_IS_WALLET.path) } - fun navigateToScanQRCode() = connectWalletConnect { navigateTo(Route.QR_CODE.path) } + fun navigateToScanQRCode() { + sendSelectWalletEvent(name = "WalletConnect", platform = ConnectionMethod.QR_CODE) + connectWalletConnect(name = "WalletConnect", method = ConnectionMethod.QR_CODE) { navigateTo(Route.QR_CODE.path) } + } fun navigateToRedirectRoute(wallet: Wallet) { + sendSelectWalletEvent(name = wallet.name, platform = wallet.toConnectionType()) saveRecentWalletUseCase(wallet.id) walletsDataStore.updateRecentWallet(wallet.id) navigateTo(wallet.toRedirectPath()) @@ -80,18 +92,22 @@ internal class ConnectViewModel : ViewModel(), Navigator by NavigatorImpl(), Par } fun navigateToAllWallets() { + sendClickAllWalletsEvent() clearSearch() navigateTo(Route.ALL_WALLETS.path) } - fun connectWalletConnect(onSuccess: (String) -> Unit) = connect( - sessionParams = sessionParams, - onSuccess = onSuccess, - onError = { - showError(it.localizedMessage) - logger.error(it) - } - ) + fun connectWalletConnect(name: String, method: String, onSuccess: (String) -> Unit) = + connect( + name, method, + sessionParams = sessionParams, + onSuccess = onSuccess, + onError = { + sendConnectErrorUseCase(message = it.message ?: "Relay error while connecting") + showError(it.localizedMessage) + logger.error(it) + } + ) fun connectCoinbase(onSuccess: () -> Unit = {}) { web3ModalEngine.connectCoinbase( @@ -119,6 +135,17 @@ internal class ConnectViewModel : ViewModel(), Navigator by NavigatorImpl(), Par fun getWalletsTotalCount() = walletsDataStore.totalWalletsCount + private fun Wallet.toConnectionType(): String { + if (isWalletInstalled) ConnectionMethod.MOBILE + + return when { + hasMobileWallet && hasWebApp -> ConnectionMethod.UNDEFINED + hasMobileWallet -> ConnectionMethod.MOBILE + hasWebApp -> ConnectionMethod.WEB + else -> ConnectionMethod.UNDEFINED + } + } + private fun getSessionParamsSelectedChain(chainId: String?) = with(Web3Modal.chains) { val selectedChain = getSelectedChain(chainId) Modal.Params.SessionParams( diff --git a/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/routes/connect/ParingController.kt b/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/routes/connect/ParingController.kt index 4139fa459f..0eb5d8359a 100644 --- a/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/routes/connect/ParingController.kt +++ b/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/routes/connect/ParingController.kt @@ -9,6 +9,7 @@ import com.walletconnect.web3.modal.engine.Web3ModalEngine internal interface ParingController { fun connect( + name: String, method: String, sessionParams: Modal.Params.SessionParams, onSuccess: (uri: String) -> Unit, onError: (Throwable) -> Unit @@ -27,6 +28,7 @@ internal class PairingControllerImpl : ParingController { get() = _pairing ?: generatePairing() override fun connect( + name: String, method: String, sessionParams: Modal.Params.SessionParams, onSuccess: (uri: String) -> Unit, onError: (Throwable) -> Unit @@ -40,6 +42,7 @@ internal class PairingControllerImpl : ParingController { pairing ) web3ModalEngine.connectWC( + name = name, method = method, connect = connectParams, onSuccess = onSuccess, onError = onError @@ -52,7 +55,6 @@ internal class PairingControllerImpl : ParingController { override val uri: String get() = pairing.uri - private fun generatePairing() = CoreClient.Pairing.create { error -> - throw IllegalStateException("Creating Pairing failed: ${error.throwable.stackTraceToString()}") - }!!.also { _pairing = it } + private fun generatePairing(): Core.Model.Pairing = + CoreClient.Pairing.create { error -> throw IllegalStateException("Creating Pairing failed: ${error.throwable.stackTraceToString()}") }!!.also { _pairing = it } } diff --git a/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/routes/connect/redirect/RedirectWalletScreen.kt b/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/routes/connect/redirect/RedirectWalletScreen.kt index 72ddb1bec9..503a8f2062 100644 --- a/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/routes/connect/redirect/RedirectWalletScreen.kt +++ b/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/routes/connect/redirect/RedirectWalletScreen.kt @@ -34,6 +34,7 @@ import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import com.walletconnect.android.internal.common.modal.data.model.Wallet +import com.walletconnect.android.pulse.model.ConnectionMethod import com.walletconnect.modal.utils.openMobileLink import com.walletconnect.modal.utils.openPlayStore import com.walletconnect.modal.utils.openWebAppLink @@ -74,11 +75,12 @@ internal fun RedirectWalletRoute( val clipboardManager: ClipboardManager = LocalClipboardManager.current var redirectState by remember { mutableStateOf(RedirectState.Loading) } var platformTab by rememberWalletPlatformTabs(wallet.toPlatform()) + val connectMobile = { if (wallet.isCoinbaseWallet()) { connectState.connectCoinbase() } else { - connectState.connectWalletConnect { uri -> + connectState.connectWalletConnect(name = wallet.name, method = ConnectionMethod.MOBILE) { uri -> uriHandler.openMobileLink( uri = uri, mobileLink = wallet.mobileLink, @@ -92,8 +94,14 @@ internal fun RedirectWalletRoute( LaunchedEffect(Unit) { Web3ModalDelegate.wcEventModels.collect { when (it) { - is Modal.Model.RejectedSession -> { redirectState = RedirectState.Reject } - is Modal.Model.ExpiredProposal -> { redirectState = RedirectState.Expired } + is Modal.Model.RejectedSession -> { + redirectState = RedirectState.Reject + } + + is Modal.Model.ExpiredProposal -> { + redirectState = RedirectState.Expired + } + else -> Unit } } @@ -116,9 +124,11 @@ internal fun RedirectWalletRoute( redirectState = RedirectState.Loading connectMobile() }, - onOpenPlayStore = { uriHandler.openPlayStore(wallet.playStore) }, + onOpenPlayStore = { + uriHandler.openPlayStore(wallet.playStore) + }, onOpenWebApp = { - connectState.connectWalletConnect { + connectState.connectWalletConnect(name = wallet.name, method = ConnectionMethod.WEB) { uriHandler.openWebAppLink(it, wallet.webAppLink) } } @@ -292,18 +302,21 @@ private fun RedirectLabel(state: RedirectState, wallet: Wallet) { description = "Accept connection request in your wallet app" descriptionStyle = Web3ModalTheme.typo.small400.copy(color = Web3ModalTheme.colors.foreground.color200) } + RedirectState.Reject -> { header = "Connection declined" description = "Connection can be declined if a previous request is still active" headerStyle = Web3ModalTheme.typo.paragraph400.copy(Web3ModalTheme.colors.error) descriptionStyle = Web3ModalTheme.typo.small400.copy(color = Web3ModalTheme.colors.foreground.color200) } + RedirectState.Expired -> { header = "Connection expired" description = String.Empty headerStyle = Web3ModalTheme.typo.paragraph400.copy(Web3ModalTheme.colors.error) descriptionStyle = Web3ModalTheme.typo.small400.copy(color = Web3ModalTheme.colors.foreground.color200) } + RedirectState.NotDetected -> { header = "App not installed" description = String.Empty diff --git a/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/routes/connect/scan_code/ScanCodeRoute.kt b/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/routes/connect/scan_code/ScanCodeRoute.kt index c73ef17d9a..ac0679da9c 100644 --- a/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/routes/connect/scan_code/ScanCodeRoute.kt +++ b/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/routes/connect/scan_code/ScanCodeRoute.kt @@ -26,6 +26,7 @@ import androidx.compose.ui.platform.LocalClipboardManager import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp +import com.walletconnect.android.pulse.model.ConnectionMethod import com.walletconnect.modal.ui.components.qr.QrCodeType import com.walletconnect.modal.ui.components.qr.WalletConnectQRCode import com.walletconnect.web3.modal.client.Modal @@ -52,7 +53,7 @@ internal fun ScanQRCodeRoute(connectViewModel: ConnectViewModel) { .filterIsInstance() .collect { snackBarHandler.showErrorSnack("Declined") - connectViewModel.connectWalletConnect { newUri -> uri = newUri } + connectViewModel.connectWalletConnect(name = "WalletConnect", method = ConnectionMethod.QR_CODE) { newUri -> uri = newUri } } } diff --git a/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/routes/connect/what_is_wallet/WhatIsWallet.kt b/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/routes/connect/what_is_wallet/WhatIsWallet.kt index 1da101d2f7..e7b72ec596 100644 --- a/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/routes/connect/what_is_wallet/WhatIsWallet.kt +++ b/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/routes/connect/what_is_wallet/WhatIsWallet.kt @@ -1,11 +1,8 @@ package com.walletconnect.web3.modal.ui.routes.connect.what_is_wallet -import androidx.compose.foundation.background -import androidx.compose.foundation.border -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.runtime.Composable @@ -13,16 +10,16 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.navigation.NavController -import com.walletconnect.web3.modal.ui.navigation.Route +import com.walletconnect.android.internal.common.wcKoinApp +import com.walletconnect.android.pulse.domain.SendClickGetWalletUseCase import com.walletconnect.web3.modal.R -import com.walletconnect.web3.modal.ui.components.internal.commons.ExternalIcon import com.walletconnect.web3.modal.ui.components.internal.commons.HelpSection -import com.walletconnect.web3.modal.ui.components.internal.commons.HorizontalSpacer import com.walletconnect.web3.modal.ui.components.internal.commons.VerticalSpacer import com.walletconnect.web3.modal.ui.components.internal.commons.WalletIcon import com.walletconnect.web3.modal.ui.components.internal.commons.button.ButtonSize import com.walletconnect.web3.modal.ui.components.internal.commons.button.ButtonStyle import com.walletconnect.web3.modal.ui.components.internal.commons.button.ImageButton +import com.walletconnect.web3.modal.ui.navigation.Route import com.walletconnect.web3.modal.ui.previews.UiModePreview import com.walletconnect.web3.modal.ui.previews.Web3ModalPreview import com.walletconnect.web3.modal.ui.theme.Web3ModalTheme @@ -31,7 +28,11 @@ import com.walletconnect.web3.modal.ui.theme.Web3ModalTheme internal fun WhatIsWallet( navController: NavController ) { - WhatIsWallet { navController.navigate(Route.GET_A_WALLET.path) } + val sendClickGetWalletEvent: SendClickGetWalletUseCase = wcKoinApp.koin.get() + WhatIsWallet { + sendClickGetWalletEvent() + navController.navigate(Route.GET_A_WALLET.path) + } } @Composable diff --git a/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/utils/Lifecycle.kt b/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/utils/Lifecycle.kt index ee3b96afba..3fcccfe156 100644 --- a/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/utils/Lifecycle.kt +++ b/product/web3modal/src/main/kotlin/com/walletconnect/web3/modal/ui/utils/Lifecycle.kt @@ -25,9 +25,10 @@ internal fun ComposableLifecycleEffect( } } -internal suspend fun Lifecycle.Event.toComponentEvent() { - when(this) { - Lifecycle.Event.ON_CREATE, Lifecycle.Event.ON_START -> ComponentDelegate.openModalEvent() - else -> ComponentDelegate.closeModalEvent() +internal fun Lifecycle.Event.toComponentEvent() { + when (this) { + Lifecycle.Event.ON_CREATE, Lifecycle.Event.ON_START, Lifecycle.Event.ON_RESUME -> ComponentDelegate.openModalEvent() + Lifecycle.Event.ON_DESTROY, Lifecycle.Event.ON_STOP, Lifecycle.Event.ON_PAUSE -> ComponentDelegate.closeModalEvent() + else -> Unit } }