Skip to content

Commit

Permalink
PERA-1060 :: Staking WIP snapshot
Browse files Browse the repository at this point in the history
  • Loading branch information
michaeltchuang committed Nov 5, 2024
1 parent 7600d38 commit 0a90b90
Show file tree
Hide file tree
Showing 30 changed files with 754 additions and 26 deletions.
2 changes: 2 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ android {
buildConfigField "String", "DISCOVER_URL", '"https://discover-mobile-staging.perawallet.app/"'
buildConfigField "String", "DISCOVER_BROWSE_DAPP_URL", '"https://discover-mobile-staging.perawallet.app/main/browser"'
buildConfigField "String", "MELD_URL", '"https://mainnet.staging.api.perawallet.app/v1/onramp-services/meld/redirect-to-fluidmoney/?walletAddress="'
buildConfigField "String", "STAKING_URL", '"https://staking-mobile-staging.perawallet.app"'
buildConfigField "String", "NODE_MAINNET_URL", apiUrlProps["NODE_MAINNET_URL"]
buildConfigField "String", "NODE_TESTNET_URL", apiUrlProps["NODE_TESTNET_URL"]
buildConfigField "String", "INDEXER_MAINNET_URL", apiUrlProps["INDEXER_MAINNET_URL"]
Expand Down Expand Up @@ -158,6 +159,7 @@ android {
buildConfigField "String", "DISCOVER_URL", '"https://discover-mobile.perawallet.app/"'
buildConfigField "String", "DISCOVER_BROWSE_DAPP_URL", '"https://discover-mobile.perawallet.app/main/browser"'
buildConfigField "String", "MELD_URL", '"https://mainnet.api.perawallet.app/v1/onramp-services/meld/redirect-to-fluidmoney/?walletAddress="'
buildConfigField "String", "STAKING_URL", '"https://staking-mobile.perawallet.app"'
buildConfigField "String", "NODE_MAINNET_URL", apiUrlProps["NODE_MAINNET_URL"]
buildConfigField "String", "NODE_TESTNET_URL", apiUrlProps["NODE_TESTNET_URL"]
buildConfigField "String", "INDEXER_MAINNET_URL", apiUrlProps["INDEXER_MAINNET_URL"]
Expand Down
4 changes: 4 additions & 0 deletions app/src/main/java/com/algorand/android/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,10 @@ class MainActivity :
override fun onBrowseDappsClick() {
handleBrowseDappsClick()
}

override fun onStakingClick() {
nav(HomeNavigationDirections.actionGlobalStakingFragment())
}
})
}

Expand Down
21 changes: 21 additions & 0 deletions app/src/main/java/com/algorand/android/MainViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,27 @@ class MainViewModel @Inject constructor(
}
}

fun onStakingButtonClick() {
viewModelScope.launch {
mainActivityEventTracker.logQuickActionSwapButtonClickEvent()
var swapNavDirection: NavDirections? = null
swapNavigationDestinationHelper.getSwapNavigationDestination(
onNavToIntroduction = {
swapNavDirection = HomeNavigationDirections.actionGlobalSwapIntroductionNavigation()
},
onNavToAccountSelection = {
swapNavDirection = HomeNavigationDirections.actionGlobalSwapAccountSelectionNavigation()
},
onNavToSwap = { accountAddress ->
swapNavDirection = HomeNavigationDirections.actionGlobalSwapNavigation(accountAddress)
}
)
swapNavDirection?.let { direction ->
_swapNavigationResultFlow.emit(Event(direction))
}
}
}

private fun initializeTutorial() {
viewModelScope.launch {
tutorialUseCase.initializeTutorial()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,14 @@ class CoreActionsTabBarView @JvmOverloads constructor(
init {
with(binding) {
coreActionsButton.setOnClickListener { onCoreActionsButtonClick() }
sendButton.setOnClickListener { listener?.onSendClick() }
// sendButton.setOnClickListener { listener?.onSendClick() }
receiveButton.setOnClickListener { listener?.onReceiveClick() }
buySellButton.setOnClickListener { listener?.onBuySellClick() }
scanQrButton.setOnClickListener { listener?.onScanQRClick() }
// scanQrButton.setOnClickListener { listener?.onScanQRClick() }
swapButton.setOnClickListener { listener?.onSwapClick() }
browseDAppsButton.setOnClickListener { listener?.onBrowseDappsClick() }
backgroundColorView.setOnClickListener { startHidingAnimation() }
stakingButton.setOnClickListener { listener?.onStakingClick() }
}
}

Expand Down Expand Up @@ -108,5 +109,6 @@ class CoreActionsTabBarView @JvmOverloads constructor(
fun onCoreActionsClick(isCoreActionsOpen: Boolean)
fun onSwapClick()
fun onBrowseDappsClick()
fun onStakingClick()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class DeviceIdUseCase @Inject constructor(
private val getActiveNodeUseCase: GetActiveNodeUseCase
) {

suspend fun getSelectedNodeDeviceId(): String? {
fun getSelectedNodeDeviceId(): String? {
return when (getSelectedNetworkSlug()) {
MAINNET_NETWORK_SLUG -> userDeviceIdRepository.getMainnetDeviceId()
TESTNET_NETWORK_SLUG -> userDeviceIdRepository.getTestnetDeviceId()
Expand All @@ -42,7 +42,7 @@ class DeviceIdUseCase @Inject constructor(
}
}

suspend fun setSelectedNodeDeviceId(deviceId: String?) {
fun setSelectedNodeDeviceId(deviceId: String?) {
when (getSelectedNetworkSlug()) {
MAINNET_NETWORK_SLUG -> userDeviceIdRepository.setMainnetDeviceId(deviceId)
TESTNET_NETWORK_SLUG -> userDeviceIdRepository.setTestnetDeviceId(deviceId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ class PeraMobileWebInterface private constructor(val listener: WebInterfaceListe
fun handleTokenDetailActionButtonClick(jsonEncodedPayload: String) {}
fun getDeviceId() {}
fun openSystemBrowser(jsonEncodedPayload: String) {}
fun getAuthorizedAddresses() {}
fun closePeraCards() {}
}

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ import com.google.gson.Gson

@Suppress("MaxLineLength")
const val JAVASCRIPT_PERACONNECT = "function setupPeraConnectObserver(){const e=new MutationObserver(()=>{const t=document.getElementById(\"pera-wallet-connect-modal-wrapper\"),e=document.getElementById(\"pera-wallet-redirect-modal-wrapper\");if(e&&e.remove(),t){const o=t.getElementsByTagName(\"pera-wallet-connect-modal\");let e=\"\";if(o&&o[0]&&o[0].shadowRoot){const r=o[0].shadowRoot.querySelector(\"pera-wallet-modal-touch-screen-mode\").shadowRoot.querySelector(\"#pera-wallet-connect-modal-touch-screen-mode-launch-pera-wallet-button\");r&&(e=r.getAttribute(\"href\"))}else{const n=t.getElementsByClassName(\"pera-wallet-connect-modal-touch-screen-mode__launch-pera-wallet-button\");n&&(e=n[0].getAttribute(\"href\"))}e&&(e=e.replace(/&browser=\\w+/,\"\"),window.open(e)),t.remove()}});e.disconnect(),e.observe(document.body,{childList:!0,subtree:!0})}setupPeraConnectObserver();"
@Suppress("MaxLineLength")
const val JAVASCRIPT_NAVIGATION = "!function(t){function e(t){setTimeout((function(){window.webkit.messageHandlers.navigation.postMessage(t)}),0)}function n(n){return function(){return e(\"other\"),n.apply(t,arguments)}}t.pushState=n(t.pushState),t.replaceState=n(t.replaceState),window.addEventListener(\"popstate\",(function(){e(\"backforward\")}))}(window.history);"

private const val BROWSER_FAVORITE_BUTTON_CLICK_ACTION = "handleBrowserFavoriteButtonClick"
private const val GET_DEVICE_ID_ACTION = "getDeviceId"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,11 @@ class AccountsFragment : DaggerBaseFragment(R.layout.fragment_accounts),
override fun onAddAccountClick() {
this@AccountsFragment.onAddAccountClick()
}

override fun onStakingClick() {
// TODO refactor with a better name for logging
nav(AccountsFragmentDirections.actionAccountsFragmentToStakingFragment())
}
}

private val accountAdapter: AccountAdapter = AccountAdapter(accountAdapterListener = accountAdapterListener)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ class AccountAdapter(
override fun onScanQrClick() {
accountAdapterListener.onScanQrClick()
}

override fun onStakingClick() {
accountAdapterListener.onStakingClick()
}
}

override fun getItemViewType(position: Int): Int {
Expand Down Expand Up @@ -141,6 +145,7 @@ class AccountAdapter(
fun onBackupBannerActionButtonClick()
fun onBuySellClick()
fun onSendClick()
fun onStakingClick()
fun onSwapClick()
fun onScanQrClick()
fun onSortClick()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class AccountsQuickActionsViewHolder(
override fun bind(item: BaseAccountListItem) {
if (item !is BaseAccountListItem.QuickActionsItem) return
with(binding) {
buySellButton.setOnClickListener { listener.onBuySellClick() }
stakingButton.setOnClickListener { listener.onStakingClick() }
sendButton.setOnClickListener { listener.onSendClick() }
swapButton.apply {
isSelected = item.isSwapButtonSelected
Expand All @@ -41,6 +41,7 @@ class AccountsQuickActionsViewHolder(
fun onSendClick()
fun onSwapClick()
fun onScanQrClick()
fun onStakingClick()
}

companion object {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Copyright 2022 Pera Wallet, LDA
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/

package com.algorand.android.modules.perawebview

fun interface GetAuthorizedAddressesWebMessage {
suspend operator fun invoke(): String
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright 2022 Pera Wallet, LDA
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/

package com.algorand.android.modules.perawebview

import com.algorand.android.modules.peraserializer.PeraSerializer
import com.algorand.android.usecase.AccountAlgoAmountUseCase
import com.algorand.android.usecase.GetLocalAccountsUseCase
import com.google.crypto.tink.subtle.Base64
import javax.inject.Inject

class GetAuthorizedAddressesWebMessagesUseCase @Inject constructor(
private val localAccountsUseCase: GetLocalAccountsUseCase,
private val peraSerializer: PeraSerializer,
private val peraWebMessageBuilder: PeraWebMessageBuilder,
private val accountAlgoAmountUseCase: AccountAlgoAmountUseCase
) : GetAuthorizedAddressesWebMessage {

override suspend fun invoke(): String {
val addressNameMap = getAddressNameMap()
val messagePayload = getMessagePayload(addressNameMap)
return peraWebMessageBuilder.buildMessage(PeraWebMessageAction.GET_AUTHORIZED_ADDRESSES, messagePayload)
}

private fun getAddressNameMap(): List<Map<String, String>> {
val localAccounts = localAccountsUseCase.getLocalAccountsThatCanSignTransaction()
val sortedAddressAlgoBalanceMap = localAccounts.map {
it to accountAlgoAmountUseCase.getAccountAlgoAmount(it.address).amount
}.sortedByDescending { (_, algoBalance) -> algoBalance }
return sortedAddressAlgoBalanceMap.map { (account, _) ->
mapOf(account.address to account.name)
}
}

private fun getMessagePayload(addressNameMap: List<Map<String, String>>): String {
return Base64.encode(peraSerializer.toJson(addressNameMap).toByteArray())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Copyright 2022 Pera Wallet, LDA
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/

package com.algorand.android.modules.perawebview

fun interface GetDeviceIdWebMessage {
operator fun invoke(): String?
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright 2022 Pera Wallet, LDA
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/

package com.algorand.android.modules.perawebview

import com.algorand.android.deviceregistration.domain.usecase.DeviceIdUseCase
import javax.inject.Inject

class GetDeviceIdWebMessageUseCase @Inject constructor(
private val deviceIdUseCase: DeviceIdUseCase,
private val peraWebMessageBuilder: PeraWebMessageBuilder
) : GetDeviceIdWebMessage {

override fun invoke(): String? {
val deviceId = deviceIdUseCase.getSelectedNodeDeviceId() ?: return null
return peraWebMessageBuilder.buildMessage(PeraWebMessageAction.GET_DEVICE_ID, deviceId)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Copyright 2022 Pera Wallet, LDA
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/

package com.algorand.android.modules.perawebview

fun interface ParseOpenSystemBrowserUrl {
operator fun invoke(jsonPayload: String): String?
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright 2022 Pera Wallet, LDA
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/

package com.algorand.android.modules.perawebview

import com.algorand.android.discover.common.ui.model.OpenSystemBrowserRequest
import com.algorand.android.modules.peraserializer.PeraSerializer
import javax.inject.Inject

class ParseOpenSystemBrowserUrlUseCase @Inject constructor(
private val peraSerializer: PeraSerializer
) : ParseOpenSystemBrowserUrl {

override fun invoke(jsonPayload: String): String? {
return peraSerializer.fromJson(jsonPayload, OpenSystemBrowserRequest::class.java)?.url
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright 2022 Pera Wallet, LDA
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/

package com.algorand.android.modules.perawebview

enum class PeraWebMessageAction(val key: String) {
GET_AUTHORIZED_ADDRESSES("getAuthorizedAddresses"),
GET_DEVICE_ID("getDeviceId")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Copyright 2022 Pera Wallet, LDA
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/

package com.algorand.android.modules.perawebview

interface PeraWebMessageBuilder {
fun buildMessage(action: PeraWebMessageAction, payload: String): String
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright 2022 Pera Wallet, LDA
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/

package com.algorand.android.modules.perawebview

import com.algorand.android.modules.perawebview.model.PeraWebMessage
import com.algorand.android.modules.peraserializer.PeraSerializer
import javax.inject.Inject

class PeraWebMessageBuilderImpl @Inject constructor(
private val peraSerializer: PeraSerializer
) : PeraWebMessageBuilder {

override fun buildMessage(action: PeraWebMessageAction, payload: String): String {
val messagePayload = getMessagePayload(action, payload)
val messageJson = peraSerializer.toJson(messagePayload)
return "handleMessage('$messageJson')"
}

private fun getMessagePayload(action: PeraWebMessageAction, payload: String): PeraWebMessage {
return PeraWebMessage(
action = action.key,
payload = payload
)
}
}
Loading

0 comments on commit 0a90b90

Please sign in to comment.