Skip to content

Commit

Permalink
Add all network selector support (#17725)
Browse files Browse the repository at this point in the history
* feat(wallet): add network selector support for "All Networks"

* update network selector activity and portfolio fragment

* helper methods and clean up
  • Loading branch information
Pavneet Singh authored Mar 24, 2023
1 parent 11d7482 commit d174ed8
Show file tree
Hide file tree
Showing 8 changed files with 189 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

public class CryptoModel {
private TxService mTxService;
Expand Down Expand Up @@ -387,6 +388,14 @@ public List<CryptoAccountTypeInfo> getSupportedCryptoAccountTypes() {
return CryptoModel.this.getSupportedCryptoAccountTypes();
}

@Override
public List<Integer> getSupportedCryptoCoins() {
return getSupportedCryptoAccountTypes()
.stream()
.map(CryptoAccountTypeInfo::getCoinType)
.collect(Collectors.toList());
}

@Override
public LiveData<List<AccountInfo>> getAccounts() {
return mAccountInfosFromKeyRingModel;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/* Copyright (c) 2023 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 @@ -16,5 +21,6 @@ public interface CryptoSharedData {
LiveData<Integer> getCoinTypeLd();
String[] getEnabledKeyrings();
List<CryptoAccountTypeInfo> getSupportedCryptoAccountTypes();
List<Integer> getSupportedCryptoCoins();
LiveData<List<AccountInfo>> getAccounts();
}
104 changes: 86 additions & 18 deletions android/java/org/chromium/chrome/browser/app/domain/NetworkModel.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
import android.text.TextUtils;
import android.util.Pair;

import androidx.annotation.NonNull;
import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MediatorLiveData;
import androidx.lifecycle.MutableLiveData;
Expand All @@ -24,6 +28,7 @@
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.NetworkUtils;
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;
Expand All @@ -33,7 +38,11 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class NetworkModel implements JsonRpcServiceObserver {
private JsonRpcService mJsonRpcService;
Expand All @@ -52,7 +61,7 @@ public class NetworkModel implements JsonRpcServiceObserver {
private final MediatorLiveData<String[]> _mCustomNetworkIds;
private final MediatorLiveData<List<NetworkInfo>> _mPrimaryNetworks;
private final MediatorLiveData<List<NetworkInfo>> _mSecondaryNetworks;
private NetworkSelectorModel mNetworkSelectorModel;
private Map<String, NetworkSelectorModel> mNetworkSelectorMap;
public final LiveData<String[]> mCustomNetworkIds;
public LiveData<NetworkInfo> mNeedToCreateAccountForNetwork;
public final LiveData<Triple<String, NetworkInfo, List<NetworkInfo>>> mChainNetworkAllNetwork;
Expand Down Expand Up @@ -93,7 +102,7 @@ public NetworkModel(JsonRpcService jsonRpcService, CryptoSharedData sharedData,
_mSecondaryNetworks = new MediatorLiveData<>();
mSecondaryNetworks = _mSecondaryNetworks;
jsonRpcService.addObserver(this);
mNetworkSelectorModel = new NetworkSelectorModel(this, mContext);
mNetworkSelectorMap = new HashMap<>();
_mPairChainAndNetwork.setValue(Pair.create("", Collections.emptyList()));
_mPairChainAndNetwork.addSource(_mChainId, chainId -> {
_mPairChainAndNetwork.setValue(
Expand All @@ -107,8 +116,7 @@ public NetworkModel(JsonRpcService jsonRpcService, CryptoSharedData sharedData,
List<NetworkInfo> cryptoNetworks = chainIdAndInfosPair.second;
if (chainId == null || cryptoNetworks == null) return;
for (NetworkInfo networkInfo : cryptoNetworks) {
if (networkInfo.chainId.equals(chainId)
&& sharedData.getCoinType() == networkInfo.coin) {
if (networkInfo.chainId.equals(chainId)) {
_mDefaultNetwork.postValue(networkInfo);
break;
}
Expand All @@ -133,11 +141,19 @@ public NetworkModel(JsonRpcService jsonRpcService, CryptoSharedData sharedData,
});

_mChainNetworkAllNetwork.addSource(_mDefaultNetwork, networkInfo -> {
NetworkInfo currNetwork = null;
if (_mChainNetworkAllNetwork.getValue() != null) {
currNetwork = _mChainNetworkAllNetwork.getValue().second;
}
if (currNetwork != null && networkInfo != null
&& NetworkUtils.Filters.isSameNetwork(currNetwork, networkInfo)) {
return;
}
_mChainNetworkAllNetwork.postValue(
Triple.create(networkInfo.chainId, networkInfo, _mCryptoNetworks.getValue()));
});
_mChainNetworkAllNetwork.addSource(_mCryptoNetworks, networkInfos -> {
String chainId = _mChainId.getValue();
String chainId = null;
NetworkInfo networkInfo = _mDefaultNetwork.getValue();
if (networkInfo != null) {
chainId = networkInfo.chainId;
Expand Down Expand Up @@ -174,12 +190,43 @@ public NetworkModel(JsonRpcService jsonRpcService, CryptoSharedData sharedData,
* @return mNetworkSelectorModel object in DEFAULT_WALLET_NETWORK mode
*/
public NetworkSelectorModel openNetworkSelectorModel() {
return openNetworkSelectorModel(NetworkSelectorModel.Mode.DEFAULT_WALLET_NETWORK);
return new NetworkSelectorModel(this, mContext);
}

public NetworkSelectorModel openNetworkSelectorModel(NetworkSelectorModel.Mode mode) {
mNetworkSelectorModel.updateSelectorMode(mode);
return mNetworkSelectorModel;
/**
* Create a network model to handle either default or local state (onscreen e.g. {@link
* org.chromium.chrome.browser.crypto_wallet.fragments.PortfolioFragment}). Local network
* selection can be used by many views so make sure to use the same key which acts as a contract
* between the view and the selection activity.
* @param key acts as a binding key between caller and selection activity.
* @param mode to handle network selection event globally or locally.
* @param lifecycle to auto remove network-selection objects.
* @return NetworkSelectorModel object.
*/
public NetworkSelectorModel openNetworkSelectorModel(
String key, NetworkSelectorModel.Mode mode, Lifecycle lifecycle) {
NetworkSelectorModel networkSelectorModel;
if (key == null) {
return new NetworkSelectorModel(mode, this, mContext);
} else if (mNetworkSelectorMap.containsKey(key)) {
// Use existing NetworkSelector object to show the previously selected network
networkSelectorModel = mNetworkSelectorMap.get(key);
if (networkSelectorModel != null && mode != networkSelectorModel.getMode()) {
networkSelectorModel.updateSelectorMode(mode);
}
} else {
networkSelectorModel = new NetworkSelectorModel(mode, this, mContext);
mNetworkSelectorMap.put(key, networkSelectorModel);
}
if (lifecycle != null) {
lifecycle.addObserver(new DefaultLifecycleObserver() {
@Override
public void onDestroy(@NonNull LifecycleOwner owner) {
mNetworkSelectorMap.remove(key);
}
});
}
return networkSelectorModel;
}

public void setAccountInfosFromKeyRingModel(
Expand Down Expand Up @@ -214,22 +261,27 @@ public void refreshNetworks() {
init();
}

static void getAllNetworks(JsonRpcService jsonRpcService, List<Integer> supportedCoins,
Callbacks.Callback1<Set<NetworkInfo>> callback) {
if (jsonRpcService == null) {
callback.call(Collections.emptySet());
return;
}

NetworkResponsesCollector networkResponsesCollector =
new NetworkResponsesCollector(jsonRpcService, supportedCoins);
networkResponsesCollector.getNetworks(networkInfos -> { callback.call(networkInfos); });
}

public void init() {
synchronized (mLock) {
if (mJsonRpcService == null) {
return;
}

List<Integer> coins = new ArrayList<>();
for (CryptoAccountTypeInfo cryptoAccountTypeInfo :
mSharedData.getSupportedCryptoAccountTypes()) {
coins.add(cryptoAccountTypeInfo.getCoinType());
}
NetworkResponsesCollector networkResponsesCollector =
new NetworkResponsesCollector(mJsonRpcService, coins);
networkResponsesCollector.getNetworks(networkInfos -> {
getAllNetworks(mJsonRpcService, mSharedData.getSupportedCryptoCoins(), allNetworks -> {
_mCryptoNetworks.postValue(
stripDebugNetwork(mContext, new ArrayList<>(networkInfos)));
stripDebugNetwork(mContext, new ArrayList<>(allNetworks)));
});
}
}
Expand All @@ -252,6 +304,11 @@ public void setNetworkWithAccountCheck(
}
}

public void setNetworkWithAccountCheck(String chainId, Callbacks.Callback1<Boolean> callback) {
NetworkInfo networkToBeSetAsSelected = getNetwork(chainId);
setNetworkWithAccountCheck(networkToBeSetAsSelected, callback);
}

public void setNetwork(
NetworkInfo networkToBeSetAsSelected, Callbacks.Callback1<Boolean> callback) {
mJsonRpcService.setNetwork(
Expand Down Expand Up @@ -284,6 +341,17 @@ public List<NetworkInfo> stripNoBuySwapNetworks(
return networkInfosFiltered;
}

public NetworkInfo getNetwork(String chainId) {
if (TextUtils.isEmpty(chainId)) return null;
List<NetworkInfo> cryptoNws = JavaUtils.safeVal(_mCryptoNetworks.getValue());
for (NetworkInfo info : cryptoNws) {
if (info.chainId.equals(chainId)) {
return info;
}
}
return null;
}

private List<NetworkInfo> stripDebugNetwork(Context context, List<NetworkInfo> networkInfos) {
if ((context.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
return networkInfos;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,22 @@
public class NetworkSelectorModel {
private final Context mContext;
private final NetworkModel mNetworkModel;
private final MutableLiveData<NetworkInfo> _mLocalSelectedNetwork;
private final MutableLiveData<NetworkInfo> _mSelectedNetwork;
private Mode mMode;
public LiveData<List<NetworkInfoPresenter>> mPrimaryNetworks;
public LiveData<List<NetworkInfoPresenter>> mSecondaryNetworks;
public final LiveData<NetworkInfo> mSelectedNetwork;
private final LiveData<NetworkInfo> mSelectedNetwork;
private String mSelectedChainId;

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

Expand All @@ -54,9 +55,11 @@ public NetworkSelectorModel(NetworkModel networkModel, Context context) {

public void init() {
if (mMode == Mode.DEFAULT_WALLET_NETWORK) {
_mLocalSelectedNetwork.postValue(mNetworkModel.mDefaultNetwork.getValue());
_mSelectedNetwork.postValue(mNetworkModel.mDefaultNetwork.getValue());
} else if (mMode == Mode.LOCAL_NETWORK_FILTER) {
_mLocalSelectedNetwork.postValue(NetworkUtils.getAllNetworkOption(mContext));
if (mSelectedChainId == null) {
_mSelectedNetwork.postValue(NetworkUtils.getAllNetworkOption(mContext));
}
}
mPrimaryNetworks = Transformations.map(mNetworkModel.mPrimaryNetworks, networkInfos -> {
List<NetworkInfoPresenter> list = new ArrayList<>();
Expand All @@ -69,13 +72,15 @@ public void init() {
list.add(new NetworkInfoPresenter(
networkInfo, true, mNetworkModel.getSubTestNetworks(networkInfo)));
}
updateLocalNetwork(networkInfos, mSelectedChainId);
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()));
}
updateLocalNetwork(networkInfos, mSelectedChainId);
return list;
});
}
Expand All @@ -93,23 +98,46 @@ public void updateSelectorMode(Mode mode) {

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;
// Default/Global wallet network does not support "All Networks"
if (!networkToBeSetAsSelected.chainId.equals(
NetworkUtils.getAllNetworkOption(mContext).chainId)) {
boolean hasAccountOfNetworkType =
mNetworkModel.hasAccountOfNetworkType(networkToBeSetAsSelected);
if (!hasAccountOfNetworkType || mMode == Mode.DEFAULT_WALLET_NETWORK) {
// Delegate to network model to handle account creation flow if required
mNetworkModel.setNetworkWithAccountCheck(networkToBeSetAsSelected, isSet -> {
callback.call(isSet);
if (isSet) {
_mSelectedNetwork.postValue(networkToBeSetAsSelected);
}
});
return;
}
}
if (mMode == Mode.LOCAL_NETWORK_FILTER) {
_mLocalSelectedNetwork.postValue(networkToBeSetAsSelected);
_mSelectedNetwork.postValue(networkToBeSetAsSelected);
callback.call(true);
}
}

public LiveData<NetworkInfo> getSelectedNetwork() {
if (mMode == Mode.DEFAULT_WALLET_NETWORK) {
return mNetworkModel.mDefaultNetwork;
} else {
return mSelectedNetwork;
}
}

public Mode getMode() {
return mMode;
}

private void updateLocalNetwork(List<NetworkInfo> networkInfos, String chainId) {
NetworkInfo networkInfo = NetworkUtils.findNetwork(networkInfos, chainId);
if (networkInfo != null) {
_mSelectedNetwork.postValue(networkInfo);
}
}

public enum Mode { DEFAULT_WALLET_NETWORK, LOCAL_NETWORK_FILTER }
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@
import org.chromium.chrome.browser.crypto_wallet.model.WalletListItemModel;
import org.chromium.chrome.browser.crypto_wallet.observers.ApprovedTxObserver;
import org.chromium.chrome.browser.crypto_wallet.util.AddressUtils;
import org.chromium.chrome.browser.crypto_wallet.util.AssetUtils;
import org.chromium.chrome.browser.crypto_wallet.util.JavaUtils;
import org.chromium.chrome.browser.crypto_wallet.util.TokenUtils;
import org.chromium.chrome.browser.crypto_wallet.util.Utils;
Expand Down Expand Up @@ -136,7 +135,7 @@ public enum ActivityType {
SWAP(2);

private int value;
private static Map map = new HashMap<>();
private static final Map<Integer, ActivityType> map = new HashMap<>();

private ActivityType(int value) {
this.value = value;
Expand All @@ -149,7 +148,7 @@ private ActivityType(int value) {
}

public static ActivityType valueOf(int activityType) {
return (ActivityType) map.get(activityType);
return map.get(activityType);
}

public int getValue() {
Expand Down
Loading

0 comments on commit d174ed8

Please sign in to comment.