Skip to content

Commit

Permalink
feat(wallet): Refactor network selector for multi chain
Browse files Browse the repository at this point in the history
- Add support for "All networks" option
- Add support for independent network selection
- Fix selection animation lag
  • Loading branch information
Pavneet-Sing committed Dec 13, 2022
1 parent fee84e2 commit 8ce6e11
Show file tree
Hide file tree
Showing 13 changed files with 780 additions and 109 deletions.
4 changes: 4 additions & 0 deletions android/brave_java_sources.gni
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ brave_java_sources = [
"../../brave/android/java/org/chromium/chrome/browser/app/domain/DappsModel.java",
"../../brave/android/java/org/chromium/chrome/browser/app/domain/KeyringModel.java",
"../../brave/android/java/org/chromium/chrome/browser/app/domain/NetworkModel.java",
"../../brave/android/java/org/chromium/chrome/browser/app/domain/NetworkSelectorModel.java",
"../../brave/android/java/org/chromium/chrome/browser/app/domain/SendModel.java",
"../../brave/android/java/org/chromium/chrome/browser/app/domain/SwapModel.java",
"../../brave/android/java/org/chromium/chrome/browser/app/domain/WalletModel.java",
Expand Down Expand Up @@ -145,6 +146,7 @@ brave_java_sources = [
"../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/permission/BraveDappPermissionPromptDialog.java",
"../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/permission/BravePermissionAccountsListAdapter.java",
"../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/presenters/Amount.java",
"../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/presenters/NetworkInfoPresenter.java",
"../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/presenters/SolanaInstructionPresenter.java",
"../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/util/AccountsPermissionsHelper.java",
"../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/util/AddressUtils.java",
Expand All @@ -155,9 +157,11 @@ brave_java_sources = [
"../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/util/BalanceHelper.java",
"../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/util/Blockies.java",
"../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/util/ItemOffsetDecoration.java",
"../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/util/JavaUtils.java",
"../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/util/KeystoreHelper.java",
"../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/util/NavigationItem.java",
"../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/util/NetworkResponsesCollector.java",
"../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/util/NetworkUtils.java",
"../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/util/ParsedTransaction.java",
"../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/util/ParsedTransactionFees.java",
"../../brave/android/java/org/chromium/chrome/browser/crypto_wallet/util/PendingTxHelper.java",
Expand Down
10 changes: 10 additions & 0 deletions android/java/org/chromium/chrome/browser/app/BraveActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

package org.chromium.chrome.browser.app;

import static org.chromium.chrome.browser.app.domain.NetworkSelectorModel.Mode.DEFAULT_WALLET_NETWORK;
import static org.chromium.chrome.browser.crypto_wallet.activities.NetworkSelectorActivity.NETWORK_SELECTOR_MODE;
import static org.chromium.ui.base.ViewUtils.dpToPx;

import android.annotation.SuppressLint;
Expand Down Expand Up @@ -92,6 +94,7 @@
import org.chromium.chrome.browser.DormantUsersEngagementDialogFragment;
import org.chromium.chrome.browser.InternetConnection;
import org.chromium.chrome.browser.LaunchIntentDispatcher;
import org.chromium.chrome.browser.app.domain.NetworkSelectorModel;
import org.chromium.chrome.browser.app.domain.WalletModel;
import org.chromium.chrome.browser.bookmarks.TabBookmarker;
import org.chromium.chrome.browser.brave_news.models.FeedItemsCard;
Expand Down Expand Up @@ -1227,8 +1230,15 @@ public void viewOnBlockExplorer(String address, @CoinType.EnumType int coinType)

// should only be called if the wallet is setup and unlocked
public void openNetworkSelection() {
openNetworkSelection(DEFAULT_WALLET_NETWORK);
}

// should only be called if the wallet is setup and unlocked
public void openNetworkSelection(NetworkSelectorModel.Mode mode) {
Intent braveNetworkSelectionIntent = new Intent(this, NetworkSelectorActivity.class);
braveNetworkSelectionIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
// Either in global or local network selection mode
braveNetworkSelectionIntent.putExtra(NETWORK_SELECTOR_MODE, mode);
startActivity(braveNetworkSelectionIntent);
}

Expand Down
111 changes: 98 additions & 13 deletions android/java/org/chromium/chrome/browser/app/domain/NetworkModel.java
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/* Copyright (c) 2022 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */

package org.chromium.chrome.browser.app.domain;

import android.content.Context;
Expand All @@ -17,13 +22,16 @@
import org.chromium.brave_wallet.mojom.NetworkInfo;
import org.chromium.chrome.browser.crypto_wallet.activities.BuySendSwapActivity;
import org.chromium.chrome.browser.crypto_wallet.model.CryptoAccountTypeInfo;
import org.chromium.chrome.browser.crypto_wallet.util.JavaUtils;
import org.chromium.chrome.browser.crypto_wallet.util.NetworkResponsesCollector;
import org.chromium.chrome.browser.crypto_wallet.util.Utils;
import org.chromium.chrome.browser.crypto_wallet.util.WalletConstants;
import org.chromium.chrome.browser.util.Triple;
import org.chromium.mojo.bindings.Callbacks;
import org.chromium.mojo.system.MojoException;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class NetworkModel implements JsonRpcServiceObserver {
Expand All @@ -41,6 +49,9 @@ public class NetworkModel implements JsonRpcServiceObserver {
_mChainNetworkAllNetwork;
private final Context mContext;
private final MediatorLiveData<String[]> _mCustomNetworkIds;
private final MediatorLiveData<List<NetworkInfo>> _mPrimaryNetworks;
private final MediatorLiveData<List<NetworkInfo>> _mSecondaryNetworks;
private NetworkSelectorModel mNetworkSelectorModel;
public final LiveData<String[]> mCustomNetworkIds;
public LiveData<NetworkInfo> mNeedToCreateAccountForNetwork;
public final LiveData<Triple<String, NetworkInfo, NetworkInfo[]>> mChainNetworkAllNetwork;
Expand All @@ -49,6 +60,8 @@ public class NetworkModel implements JsonRpcServiceObserver {
public final LiveData<NetworkInfo[]> mDefaultCoinCryptoNetworks;
public final LiveData<NetworkInfo[]> mCryptoNetworks;
public final LiveData<NetworkInfo> mDefaultNetwork;
public final LiveData<List<NetworkInfo>> mPrimaryNetworks;
public final LiveData<List<NetworkInfo>> mSecondaryNetworks;

public NetworkModel(JsonRpcService jsonRpcService, CryptoSharedData sharedData,
CryptoSharedActions cryptoSharedActions, Context context) {
Expand All @@ -74,7 +87,12 @@ public NetworkModel(JsonRpcService jsonRpcService, CryptoSharedData sharedData,
_mCustomNetworkIds = new MediatorLiveData<>();
_mCustomNetworkIds.postValue(new String[0]);
mCustomNetworkIds = _mCustomNetworkIds;
_mPrimaryNetworks = new MediatorLiveData<>();
mPrimaryNetworks = _mPrimaryNetworks;
_mSecondaryNetworks = new MediatorLiveData<>();
mSecondaryNetworks = _mSecondaryNetworks;
jsonRpcService.addObserver(this);
mNetworkSelectorModel = new NetworkSelectorModel(this, mContext);
_mPairChainAndNetwork.setValue(Pair.create("", new NetworkInfo[] {}));
_mPairChainAndNetwork.addSource(_mChainId, chainId -> {
_mPairChainAndNetwork.setValue(
Expand Down Expand Up @@ -124,6 +142,38 @@ public NetworkModel(JsonRpcService jsonRpcService, CryptoSharedData sharedData,
mJsonRpcService.getCustomNetworks(
coinType, customNetworks -> { _mCustomNetworkIds.postValue(customNetworks); });
});
_mPrimaryNetworks.addSource(mCryptoNetworks, networkInfos -> {
List<NetworkInfo> primaryNws = new ArrayList<>();
for (NetworkInfo networkInfo : networkInfos) {
if (WalletConstants.SUPPORTED_TOP_LEVEL_CHAIN_IDS.contains(networkInfo.chainId)) {
primaryNws.add(networkInfo);
}
}
_mPrimaryNetworks.postValue(primaryNws);
});
_mSecondaryNetworks.addSource(mCryptoNetworks, networkInfos -> {
List<NetworkInfo> primaryNws = new ArrayList<>();
for (NetworkInfo networkInfo : networkInfos) {
if (!WalletConstants.SUPPORTED_TOP_LEVEL_CHAIN_IDS.contains(networkInfo.chainId)
&& !WalletConstants.KNOWN_TEST_CHAIN_IDS.contains(networkInfo.chainId)) {
primaryNws.add(networkInfo);
}
}
_mSecondaryNetworks.postValue(primaryNws);
});
}

/**
* Create a network model to handle default wallet network selector events
* @return mNetworkSelectorModel object in DEFAULT_WALLET_NETWORK mode
*/
public NetworkSelectorModel openNetworkSelectorModel() {
return openNetworkSelectorModel(NetworkSelectorModel.Mode.DEFAULT_WALLET_NETWORK);
}

public NetworkSelectorModel openNetworkSelectorModel(NetworkSelectorModel.Mode mode) {
mNetworkSelectorModel.updateSelectorMode(mode);
return mNetworkSelectorModel;
}

public void setAccountInfosFromKeyRingModel(
Expand Down Expand Up @@ -176,19 +226,9 @@ public void init() {

public void setNetworkWithAccountCheck(
NetworkInfo networkToBeSetAsSelected, Callbacks.Callback1<Boolean> callback) {
List<AccountInfo> accountInfos = mSharedData.getAccounts().getValue();
boolean hasAccountOfNetworkType = false;
for (AccountInfo accountInfo : accountInfos) {
hasAccountOfNetworkType = accountInfo.coin == networkToBeSetAsSelected.coin;
if (hasAccountOfNetworkType) {
break;
}
}
NetworkInfo selectedNetwork = _mDefaultNetwork.getValue();
if (selectedNetwork != null
&& selectedNetwork.chainId.equals(networkToBeSetAsSelected.chainId)
&& selectedNetwork.coin == networkToBeSetAsSelected.coin)
return;
if (isSameNetwork(networkToBeSetAsSelected, selectedNetwork)) return;
boolean hasAccountOfNetworkType = hasAccountOfNetworkType(networkToBeSetAsSelected);
if (hasAccountOfNetworkType) {
mJsonRpcService.setNetwork(
networkToBeSetAsSelected.chainId, networkToBeSetAsSelected.coin, isSelected -> {
Expand Down Expand Up @@ -245,10 +285,55 @@ private NetworkInfo[] stripDebugNetwork(Context context, NetworkInfo[] networkIn
networkInfosFiltered.add(networkInfo);
}
}
return networkInfosFiltered.toArray(new NetworkInfo[networkInfosFiltered.size()]);
return networkInfosFiltered.toArray(new NetworkInfo[0]);
}
}

List<NetworkInfo> getSubTestNetworks(NetworkInfo networkInfo) {
NetworkInfo[] cryptoNws = _mCryptoNetworks.getValue();
if (cryptoNws == null || cryptoNws.length == 0
|| !WalletConstants.SUPPORTED_TOP_LEVEL_CHAIN_IDS.contains(networkInfo.chainId))
return Collections.emptyList();
List<NetworkInfo> list = new ArrayList<>();
for (NetworkInfo info : cryptoNws) {
if (WalletConstants.KNOWN_TEST_CHAIN_IDS.contains(info.chainId)
&& networkInfo.coin == info.coin && networkInfo.symbol.equals(info.symbol)
&& !isCustomChain(info.chainId)) {
list.add(info);
}
}
return list;
}

private boolean isCustomChain(String netWorkChainId) {
String[] customNetworkChains = JavaUtils.safeVal(_mCustomNetworkIds.getValue());
for (String chain : customNetworkChains) {
if (chain.equals(netWorkChainId)) {
return true;
}
}
return false;
}

boolean hasAccountOfNetworkType(NetworkInfo networkToBeSetAsSelected) {
List<AccountInfo> accountInfos = mSharedData.getAccounts().getValue();
boolean hasAccountOfNetworkType = false;
for (AccountInfo accountInfo : accountInfos) {
hasAccountOfNetworkType = accountInfo.coin == networkToBeSetAsSelected.coin;
if (hasAccountOfNetworkType) {
break;
}
}
return hasAccountOfNetworkType;
}

private boolean isSameNetwork(
NetworkInfo networkToBeSetAsSelected, NetworkInfo selectedNetwork) {
return selectedNetwork != null
&& selectedNetwork.chainId.equals(networkToBeSetAsSelected.chainId)
&& selectedNetwork.coin == networkToBeSetAsSelected.coin;
}

@Override
public void chainChangedEvent(String chainId, int coin) {
_mChainId.postValue(chainId);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/* Copyright (c) 2022 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */

package org.chromium.chrome.browser.app.domain;

import android.content.Context;

import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Transformations;

import org.chromium.brave_wallet.mojom.NetworkInfo;
import org.chromium.chrome.browser.crypto_wallet.presenters.NetworkInfoPresenter;
import org.chromium.chrome.browser.crypto_wallet.util.NetworkUtils;
import org.chromium.mojo.bindings.Callbacks;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
* NetworkSelectorModel handles the selector of network for either global or local network
* selection.
* {@link NetworkSelectorModel#mMode} acts as a switch between global or local network selection
* live data events. Local selection can be observed via {@link
* NetworkSelectorModel#mSelectedNetwork} and global via {@link NetworkModel#mDefaultNetwork}
*/
public class NetworkSelectorModel {
private final Context mContext;
private final NetworkModel mNetworkModel;
private final MutableLiveData<NetworkInfo> _mLocalSelectedNetwork;
private Mode mMode;
public LiveData<List<NetworkInfoPresenter>> mPrimaryNetworks;
public LiveData<List<NetworkInfoPresenter>> mSecondaryNetworks;
public final LiveData<NetworkInfo> mSelectedNetwork;

public NetworkSelectorModel(Mode mode, NetworkModel networkModel, Context context) {
mMode = mode;
if (mMode == null) {
mMode = Mode.LOCAL_NETWORK_FILTER;
}
mNetworkModel = networkModel;
mContext = context;
_mLocalSelectedNetwork = new MutableLiveData<>();
mSelectedNetwork = _mLocalSelectedNetwork;
init();
}

public NetworkSelectorModel(NetworkModel networkModel, Context context) {
this(Mode.DEFAULT_WALLET_NETWORK, networkModel, context);
}

public void init() {
if (mMode == Mode.DEFAULT_WALLET_NETWORK) {
_mLocalSelectedNetwork.postValue(mNetworkModel.mDefaultNetwork.getValue());
} else if (mMode == Mode.LOCAL_NETWORK_FILTER) {
_mLocalSelectedNetwork.postValue(NetworkUtils.getAllNetworkOption(mContext));
}
mPrimaryNetworks = Transformations.map(mNetworkModel.mPrimaryNetworks, networkInfos -> {
List<NetworkInfoPresenter> list = new ArrayList<>();
if (mMode == Mode.LOCAL_NETWORK_FILTER) {
list.add(0,
new NetworkInfoPresenter(NetworkUtils.getAllNetworkOption(mContext), true,
Collections.emptyList()));
}
for (NetworkInfo networkInfo : networkInfos) {
list.add(new NetworkInfoPresenter(
networkInfo, true, mNetworkModel.getSubTestNetworks(networkInfo)));
}
return list;
});
mSecondaryNetworks = Transformations.map(mNetworkModel.mSecondaryNetworks, networkInfos -> {
List<NetworkInfoPresenter> list = new ArrayList<>();
for (NetworkInfo networkInfo : networkInfos) {
list.add(new NetworkInfoPresenter(networkInfo, false, Collections.emptyList()));
}
return list;
});
}

/**
* Reset the mode
* DEFAULT_WALLET_NETWORK for global wallet network
* LOCAL_NETWORK_FILTER for only onscreen network selection via "mSelectedNetwork"
* @param mode to set selected network
*/
public void updateSelectorMode(Mode mode) {
this.mMode = mode;
init();
}

public void setNetworkWithAccountCheck(
NetworkInfo networkToBeSetAsSelected, Callbacks.Callback1<Boolean> callback) {
boolean hasAccountOfNetworkType =
mNetworkModel.hasAccountOfNetworkType(networkToBeSetAsSelected);
if (!hasAccountOfNetworkType && mMode == Mode.DEFAULT_WALLET_NETWORK) {
// Delegate to network model to handle account creation flow
mNetworkModel.setNetworkWithAccountCheck(networkToBeSetAsSelected, isSet -> {
callback.call(isSet);
if (isSet) {
_mLocalSelectedNetwork.postValue(networkToBeSetAsSelected);
}
});
return;
}
if (mMode == Mode.LOCAL_NETWORK_FILTER) {
_mLocalSelectedNetwork.postValue(networkToBeSetAsSelected);
callback.call(true);
}
}

/**
* Mode to update either global network or {@link NetworkSelectorModel#mSelectedNetwork}
* network.
*/
public enum Mode { DEFAULT_WALLET_NETWORK, LOCAL_NETWORK_FILTER }
}
Loading

0 comments on commit 8ce6e11

Please sign in to comment.