Skip to content

Commit

Permalink
add connect with WalletConnectModal in ConnectWalletFragment
Browse files Browse the repository at this point in the history
  • Loading branch information
Babak-gh committed Nov 11, 2023
1 parent 728e919 commit 9d5bbb1
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,24 @@ import android.accounts.AccountManager
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.activity.viewModels
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.fragment.NavHostFragment.Companion.findNavController
import androidx.navigation.fragment.findNavController
import com.walletconnect.wcmodal.client.Modal
import com.walletconnect.wcmodal.client.WalletConnectModal
import com.walletconnect.wcmodal.ui.openWalletConnectModal
import kotlinx.coroutines.launch
import org.xmtp.android.example.MainActivity
import org.xmtp.android.example.R
import org.xmtp.android.example.databinding.FragmentConnectWalletBinding
import timber.log.Timber


class ConnectWalletFragment : Fragment() {
Expand All @@ -39,7 +36,7 @@ class ConnectWalletFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
): View {
_binding = FragmentConnectWalletBinding.inflate(inflater, container, false)
return binding.root
}
Expand All @@ -53,6 +50,12 @@ class ConnectWalletFragment : Fragment() {
}
}

viewLifecycleOwner.lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.showWalletState.collect(::showWalletState)
}
}

binding.generateButton.setOnClickListener {
viewModel.generateWallet()
}
Expand All @@ -61,19 +64,12 @@ class ConnectWalletFragment : Fragment() {
binding.connectButton.isEnabled = isConnectWalletAvailable
binding.connectError.isVisible = !isConnectWalletAvailable
binding.connectButton.setOnClickListener {
binding.connectButton.start(viewModel.walletConnectKit, ::onConnected, ::onDisconnected)
WalletConnectModal.setSessionParams(viewModel.getSessionParams())
findNavController().openWalletConnectModal(id = R.id.action_to_bottomSheet)
}

}

private fun onConnected(address: String) {
viewModel.connectWallet()
}

private fun onDisconnected() {
// No-op currently.
}

private fun isConnectAvailable(): Boolean {
val wcIntent = Intent(Intent.ACTION_VIEW).apply {
data = Uri.parse(WC_URI_SCHEME)
Expand All @@ -89,10 +85,24 @@ class ConnectWalletFragment : Fragment() {
uiState.address,
uiState.encodedKeyData
)

ConnectWalletViewModel.ConnectUiState.Unknown -> Unit
}
}

private fun showWalletState(walletState: ConnectWalletViewModel.ShowWalletForSigningState) {
if (walletState.showWallet) {
try {
val intent = Intent(Intent.ACTION_VIEW, walletState.uri)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
requireActivity().startActivity(intent)
viewModel.clearShowWalletState()
} catch (e: Exception) {
Timber.tag(FRAGMENT_LOG_TAG).e("Activity not found: $e")
}
}
}

private fun signIn(address: String, encodedKey: String) {
val accountManager = AccountManager.get(requireContext())
Account(address, resources.getString(R.string.account_type)).also { account ->
Expand Down Expand Up @@ -124,6 +134,7 @@ class ConnectWalletFragment : Fragment() {

companion object {
private const val WC_URI_SCHEME = "wc://wc?uri="
private const val FRAGMENT_LOG_TAG = "ConnectWalletFragment"
}

}
Original file line number Diff line number Diff line change
@@ -1,35 +1,82 @@
package org.xmtp.android.example.connect

import android.app.Application
import android.net.Uri
import androidx.annotation.UiThread
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dev.pinkroom.walletconnectkit.WalletConnectKit
import dev.pinkroom.walletconnectkit.WalletConnectKitConfig
import com.walletconnect.wcmodal.client.Modal
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import org.xmtp.android.example.ClientManager
import org.xmtp.android.example.account.WalletConnectAccount
import org.xmtp.android.example.account.WalletConnectV2Account
import org.xmtp.android.library.Client
import org.xmtp.android.library.XMTPException
import org.xmtp.android.library.messages.PrivateKeyBuilder
import org.xmtp.android.library.messages.PrivateKeyBundleV1Builder

class ConnectWalletViewModel(application: Application) : AndroidViewModel(application) {
class ConnectWalletViewModel : ViewModel() {

private val chains: List<ChainSelectionUi> =
Chains.values().map { it.toChainUiState() }

private val _showWalletState = MutableStateFlow(ShowWalletForSigningState(showWallet = false))
val showWalletState: StateFlow<ShowWalletForSigningState>
get() = _showWalletState.asStateFlow()

private val _uiState = MutableStateFlow<ConnectUiState>(ConnectUiState.Unknown)
val uiState: StateFlow<ConnectUiState> = _uiState

private val walletConnectKitConfig = WalletConnectKitConfig(
context = application,
bridgeUrl = "https://safe-walletconnect.safe.global/",
appUrl = "https://xmtp.org",
appName = "XMTP Example",
appDescription = "Example app using the xmtp-android SDK"
init {
DappDelegate.wcEventModels
.filterNotNull()
.onEach { walletEvent ->
when (walletEvent) {
is Modal.Model.ApprovedSession -> {
connectWallet(walletEvent)
}

else -> Unit
}

}.launchIn(viewModelScope)
}

fun getSessionParams() = Modal.Params.SessionParams(
requiredNamespaces = getNamespaces(),
optionalNamespaces = getOptionalNamespaces()
)
val walletConnectKit = WalletConnectKit.Builder(walletConnectKitConfig).build()

private fun getNamespaces(): Map<String, Modal.Model.Namespace.Proposal> {
val namespaces: Map<String, Modal.Model.Namespace.Proposal> =
chains
.groupBy { it.chainNamespace }
.map { (key: String, selectedChains: List<ChainSelectionUi>) ->
key to Modal.Model.Namespace.Proposal(
chains = selectedChains.map { it.chainId },
methods = selectedChains.flatMap { it.methods }.distinct(),
events = selectedChains.flatMap { it.events }.distinct()
)
}.toMap()


return namespaces.toMutableMap()
}

private fun getOptionalNamespaces() = chains
.groupBy { it.chainId }
.map { (key: String, selectedChains: List<ChainSelectionUi>) ->
key to Modal.Model.Namespace.Proposal(
methods = selectedChains.flatMap { it.methods }.distinct(),
events = selectedChains.flatMap { it.events }.distinct()
)
}.toMap()

@UiThread
fun generateWallet() {
Expand All @@ -49,11 +96,18 @@ class ConnectWalletViewModel(application: Application) : AndroidViewModel(applic
}

@UiThread
fun connectWallet() {
fun connectWallet(approvedSession: Modal.Model.ApprovedSession) {
viewModelScope.launch(Dispatchers.IO) {
_uiState.value = ConnectUiState.Loading
try {
val wallet = WalletConnectAccount(walletConnectKit)
val wallet = WalletConnectV2Account(
approvedSession,
Chains.ETHEREUM_MAIN.chainNamespace
) { uri ->
_showWalletState.update {
it.copy(showWallet = true, uri = uri)
}
}
val client = Client().create(wallet, ClientManager.CLIENT_OPTIONS)
_uiState.value = ConnectUiState.Success(
wallet.address,
Expand All @@ -65,10 +119,18 @@ class ConnectWalletViewModel(application: Application) : AndroidViewModel(applic
}
}

fun clearShowWalletState() {
_showWalletState.update {
it.copy(showWallet = false)
}
}

sealed class ConnectUiState {
object Unknown : ConnectUiState()
object Loading : ConnectUiState()
data class Success(val address: String, val encodedKeyData: String) : ConnectUiState()
data class Error(val message: String) : ConnectUiState()
}

data class ShowWalletForSigningState(val showWallet: Boolean, val uri: Uri? = null)
}

0 comments on commit 9d5bbb1

Please sign in to comment.