Skip to content

Commit

Permalink
PERA-747 :: Immersve feature work (with feature flag off) (perawallet#9)
Browse files Browse the repository at this point in the history
  • Loading branch information
mitsinsar authored Nov 9, 2024
1 parent aa31b78 commit e3a4743
Show file tree
Hide file tree
Showing 57 changed files with 1,659 additions and 35 deletions.
6 changes: 6 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ android {
buildConfigField "String", "DISCOVER_VERSION", "\"${discoverVersions.staging}\""
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", "CARDS_URL", '"https://cards-mobile-staging.perawallet.app"'
buildConfigField "String", "MELD_URL", '"https://mainnet.staging.api.perawallet.app/v1/onramp-services/meld/redirect-to-fluidmoney/?walletAddress="'
buildConfigField "String", "NODE_MAINNET_URL", apiUrlProps["NODE_MAINNET_URL"]
buildConfigField "String", "NODE_TESTNET_URL", apiUrlProps["NODE_TESTNET_URL"]
Expand Down Expand Up @@ -157,6 +158,7 @@ android {
buildConfigField "String", "DISCOVER_VERSION", "\"${discoverVersions.prod}\""
buildConfigField "String", "DISCOVER_URL", '"https://discover-mobile.perawallet.app/"'
buildConfigField "String", "DISCOVER_BROWSE_DAPP_URL", '"https://discover-mobile.perawallet.app/main/browser"'
buildConfigField "String", "CARDS_URL", '"https://cards-mobile.perawallet.app"'
buildConfigField "String", "MELD_URL", '"https://mainnet.api.perawallet.app/v1/onramp-services/meld/redirect-to-fluidmoney/?walletAddress="'
buildConfigField "String", "NODE_MAINNET_URL", apiUrlProps["NODE_MAINNET_URL"]
buildConfigField "String", "NODE_TESTNET_URL", apiUrlProps["NODE_TESTNET_URL"]
Expand Down Expand Up @@ -254,6 +256,9 @@ dependencies {
implementation libs.hilt.android.dagger
ksp libs.hilt.android.compiler
ksp libs.hilt.androidx
implementation(platform(libs.koin.bom))
implementation libs.koin.core
implementation libs.koin.android

implementation libs.glide.image
ksp libs.glide.compiler
Expand Down Expand Up @@ -295,6 +300,7 @@ dependencies {
testImplementation libs.kotlinx.coroutines.test
testImplementation libs.kotlin.test
testImplementation libs.junit
testImplementation libs.mockito
androidTestImplementation libs.room.testing
androidTestImplementation libs.runner
androidTestImplementation libs.espresso.core
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* 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

import androidx.lifecycle.ViewModel
import com.algorand.common.remoteconfig.domain.usecase.IsFeatureToggleEnabled
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow

@HiltViewModel
class CoreActionsTabBarViewModel @Inject constructor(
private val isFeatureToggleEnabled: IsFeatureToggleEnabled
) : ViewModel() {

private val _viewState = MutableStateFlow<ViewState>(ViewState.Idle)
val viewState get() = _viewState.asStateFlow()

fun initViewState() {
val isCardsToggleEnabled = isFeatureToggleEnabled(CARDS_BUTTON_TOGGLE)
_viewState.value = ViewState.Content(isCardsToggleEnabled)
}

sealed interface ViewState {
data object Idle : ViewState
data class Content(val isCardsVisible: Boolean) : ViewState
}

private companion object {
const val CARDS_BUTTON_TOGGLE = "enable_immersve"
}
}
17 changes: 14 additions & 3 deletions app/src/main/java/com/algorand/android/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ class MainActivity :
AlertDialogDelegation by AlertDialogDelegationImpl() {

val mainViewModel: MainViewModel by viewModels()
private val coreActionsTabBarViewModel: CoreActionsTabBarViewModel by viewModels()
private val walletConnectViewModel: WalletConnectViewModel by viewModels()
private val qrScannerViewModel: QrScannerViewModel by viewModels()

Expand Down Expand Up @@ -242,7 +243,7 @@ class MainActivity :

private val walletConnectUrlHandlerListener = object : WalletConnectUrlHandler.Listener {
override fun onValidWalletConnectUrl(url: String) {
showProgress()
if (!isBasePeraWebViewFragmentActive()) showProgress()
walletConnectViewModel.connectToSessionByUrl(url)
}

Expand Down Expand Up @@ -508,6 +509,11 @@ class MainActivity :
flow = firebaseTokenManager.firebaseTokenResultFlow,
collection = firebaseTokenResultCollector
)

collectLatestOnLifecycle(
flow = coreActionsTabBarViewModel.viewState,
collection = { binding.coreActionsTabBarView.initViewState(it) }
)
}

private fun navigateToConnectionIssueBottomSheet() {
Expand Down Expand Up @@ -581,9 +587,9 @@ class MainActivity :
}
}

override fun onNewIntent(intent: Intent?) {
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
val pendingIntent = intent?.getSafeParcelableExtra<Intent?>(DEEPLINK_AND_NAVIGATION_INTENT)
val pendingIntent = intent.getSafeParcelableExtra<Intent?>(DEEPLINK_AND_NAVIGATION_INTENT)
pendingIntentKeeper.setPendingIntent(pendingIntent)
handlePendingIntent()
}
Expand Down Expand Up @@ -643,6 +649,7 @@ class MainActivity :
}

private fun setupCoreActionsTabBarView() {
coreActionsTabBarViewModel.initViewState()
binding.coreActionsTabBarView.setListener(object : CoreActionsTabBarView.Listener {
override fun onSendClick() {
firebaseAnalytics.logTapSend()
Expand Down Expand Up @@ -678,6 +685,10 @@ class MainActivity :
override fun onBrowseDappsClick() {
handleBrowseDappsClick()
}

override fun onCardsClick() {
nav(HomeNavigationDirections.actionGlobalCardsFragment())
}
})
}

Expand Down
8 changes: 8 additions & 0 deletions app/src/main/java/com/algorand/android/core/PeraApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@ import android.content.res.Configuration
import androidx.appcompat.app.AppCompatDelegate
import androidx.lifecycle.ProcessLifecycleOwner
import androidx.multidex.MultiDex
import com.algorand.android.koin.KoinInitializer
import com.algorand.android.migration.MigrationManager
import com.algorand.android.modules.autolockmanager.ui.AutoLockManager
import com.algorand.android.modules.firebase.token.FirebaseTokenManager
import com.algorand.android.modules.pendingintentkeeper.ui.PendingIntentKeeper
import com.algorand.android.utils.coremanager.ApplicationStatusObserver
import com.algorand.android.utils.preference.getSavedThemePreference
import com.google.firebase.FirebaseApp
import dagger.hilt.android.HiltAndroidApp
import javax.inject.Inject

Expand Down Expand Up @@ -62,6 +64,8 @@ open class PeraApp : Application() {

override fun onCreate() {
super.onCreate()
KoinInitializer.initKoin(this)
initializeFirebase()
migrationManager.makeMigrations()

AppCompatDelegate.setDefaultNightMode(sharedPref.getSavedThemePreference().convertToSystemAbbr())
Expand All @@ -71,6 +75,10 @@ open class PeraApp : Application() {
bindActivityLifecycleAwareComponents()
}

private fun initializeFirebase() {
FirebaseApp.initializeApp(this)
}

private fun initializeWalletConnect() {
walletConnectInitializer.initialize(this, ProcessLifecycleOwner.get().lifecycle)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ package com.algorand.android.customviews
import android.content.Context
import android.util.AttributeSet
import androidx.constraintlayout.motion.widget.MotionLayout
import androidx.core.view.isVisible
import com.algorand.android.CoreActionsTabBarViewModel
import com.algorand.android.CoreActionsTabBarViewModel.ViewState.Content
import com.algorand.android.CoreActionsTabBarViewModel.ViewState.Idle
import com.algorand.android.R
import com.algorand.android.databinding.CustomCoreActionsTabBarBinding
import com.algorand.android.utils.viewbinding.viewBinding
Expand All @@ -40,6 +44,7 @@ class CoreActionsTabBarView @JvmOverloads constructor(
scanQrButton.setOnClickListener { listener?.onScanQRClick() }
swapButton.setOnClickListener { listener?.onSwapClick() }
browseDAppsButton.setOnClickListener { listener?.onBrowseDappsClick() }
cardsButton.setOnClickListener { listener?.onCardsClick() }
backgroundColorView.setOnClickListener { startHidingAnimation() }
}
}
Expand Down Expand Up @@ -68,6 +73,13 @@ class CoreActionsTabBarView @JvmOverloads constructor(
binding.browseDAppsButton.isEnabled = isEnabled
}

fun initViewState(viewState: CoreActionsTabBarViewModel.ViewState) {
when (viewState) {
is Content -> binding.cardsButton.isVisible = viewState.isCardsVisible
Idle -> binding.cardsButton.visibility = GONE
}
}

private fun startHidingAnimation() {
transitionToStart()
isCoreActionsOpened = false
Expand Down Expand Up @@ -108,5 +120,6 @@ class CoreActionsTabBarView @JvmOverloads constructor(
fun onCoreActionsClick(isCoreActionsOpen: Boolean)
fun onSwapClick()
fun onBrowseDappsClick()
fun onCardsClick()
}
}
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 Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,25 @@ class PeraMobileWebInterface private constructor(val listener: WebInterfaceListe
listener.openSystemBrowser(jsonEncodedPayload)
}

@JavascriptInterface
fun getAuthorizedAddresses(jsonEncodedPayload: String) {
listener.getAuthorizedAddresses()
}

@JavascriptInterface
fun closePeraCards(message: String) {
listener.closePeraCards()
}

interface WebInterfaceListener {
fun pushTokenDetailScreen(jsonEncodedPayload: String) {}
fun pushDappViewerScreen(jsonEncodedPayload: String) {}
fun pushNewScreen(jsonEncodedPayload: String) {}
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,8 @@ 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
36 changes: 36 additions & 0 deletions app/src/main/java/com/algorand/android/koin/KoinHiltModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* 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.koin

import com.algorand.common.remoteconfig.domain.usecase.InitializeOperationalToggles
import com.algorand.common.remoteconfig.domain.usecase.IsFeatureToggleEnabled
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import org.koin.java.KoinJavaComponent.getKoin

@Module
@InstallIn(SingletonComponent::class)
object KoinHiltModule {

@Provides
fun provideInitializeOperationalToggles(): InitializeOperationalToggles {
return getKoin().get()
}

@Provides
fun provideIsFeatureToggleEnabled(): IsFeatureToggleEnabled {
return getKoin().get()
}
}
33 changes: 33 additions & 0 deletions app/src/main/java/com/algorand/android/koin/KoinInitializer.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* 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.koin

import com.algorand.android.BuildConfig
import com.algorand.android.core.PeraApp
import com.algorand.common.remoteconfig.di.remoteConfigModule
import org.koin.android.ext.koin.androidContext
import org.koin.android.ext.koin.androidLogger
import org.koin.core.context.startKoin

object KoinInitializer {

fun initKoin(app: PeraApp) {
startKoin {
if (BuildConfig.DEBUG) {
androidLogger()
}
androidContext(app)
modules(remoteConfigModule)
}
}
}
Loading

0 comments on commit e3a4743

Please sign in to comment.