-
Notifications
You must be signed in to change notification settings - Fork 925
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(wallet): Implemented show all networks assets #17615
Conversation
- Implementing multi chain show balance (#27333) - Refactor network selector screen to show new "All network" (#27074) - Implemented multi-chain price and asset data collection (#27333) - Show overlapping network icon on Portfolio and Asset selection screens (#27333) - Show asset graph data for different networks and assets (#28748) - Fixed unwanted duplicate removal from list (#28506) - Fix balance issue for incoming asset - Reduce latency by separating P3A calls - Fixed edit visible asset to select assets - Fixed edit visible assets list for all network to show default assets in "edit visible assets" when all networks is selected (until all network is supported) - Updated portfolio, edit, view assets list UI list to show asset and network details from "All network" view - Fix AssetDetails activity to use passed network - Fixed AccountDetails activity issue with network - Tested and added available icons for networks/native assets, logged issue for missing assets (#28798) - Fix account list on asset details on AssetDetails screen - Fixed cached NFTs after unlock wallet (#28301) - Fixing asset graph data when multiple assets are shown - Fix nested network list is instantly closed after selection (click) and improve selection (#27614) - ERC721 NFTs with different token identifiers may show incorrect balance (#28627) - Implement All networks list sort order - Fix Buy, Send, Swap flows for selected multi-chain view token - Fix crash with test network with new flow - Ux: Show full network name on click on Edit visible via click popup - Clear balance with network switching - Clean up and refactoring to reuse
Please don't combine if possible a huge amount of issues in one PR in the future. It would be hard to fix something in case of failure of one of the issues when verifying it, as it could be dependent or the worse case if we need to revert the whole PR(in that case everything has to be reverted). Plus to the above it's harder for reviewers to catch up with all of the issues and trying to understand what is going on. |
😱 Reviewing 1200 LOC PR is every developer's worst nightmare. |
Multi-chain is a feature and many things in the codebase had to be fixed to support this if you look thoroughly.
brave-core/android/java/org/chromium/chrome/browser/crypto_wallet/fragments/PortfolioFragment.java Lines 316 to 321 in 38ab4b2
Please feel free to discuss anything as I am using some new APIs with sophisticated flow so LMK if I can help with anything. |
@Pavneet-Sing so there is no way to split it and it has all be in a single PR and in a single commit right? |
I can move brave/brave-browser#28748 brave-core/android/java/org/chromium/chrome/browser/crypto_wallet/util/PortfolioHelper.java Lines 256 to 263 in 38ab4b2
brave-core/android/java/org/chromium/chrome/browser/crypto_wallet/fragments/PortfolioFragment.java Lines 316 to 321 in 38ab4b2
changes in a separate PR. These are not big changes (linked the changes above) but yes, can be separated into a different PR. LMK know if it will help to move these two in a separate PR. Other than brave/brave-browser#27074 and brave/brave-browser#27333, rest of the changes are small. Selector issue was fixed automatically. brave/brave-browser#28506 is related to moving code to brave-core/android/java/org/chromium/chrome/browser/crypto_wallet/util/TokenUtils.java Line 128 in 38ab4b2
|
Sorry for the drive by comment, but this comment came off as lacking in courtesy and I had to comment...
It doesn't matter how great a reviewer is, if you have a very big commit that mixes several concerns, it will not be reviewed properly. It is not a matter of reviewer experience. It is up to the person creating pull requests to split up a pull request's concerns into multiple digestible commits. The author should create a story with their commits and have 1 concern per commit. What's more is that when combining multiple things it makes them inseparable. Maybe 1 concern of many needs special attention and needs an uplift. It could be cherry-picked if it was split up correctly, but cannot if it is buried in a big set of other changes. Some sources, but it's not hard to find more:
|
@Pavneet-Sing , there's no need. I'm always up for a challenge. Please don't take it the wrong way, small PRs should always be preferable, when I noticed the LOC were over a thousand it was natural for me expressing that as a candid observation. At the end of the day, honest feedback is an invaluable tool that will make us better developers. I hope it didn't make you feel bad or anything, as your comment sounded a bit harsh. I just wanted to help. I'm going to finish soon an initial review round 😀 |
* View <=> NetworkSelection state only with All Networks option. | ||
* @param key as identifier to bind local state of NetworkSelection with the view. If null then | ||
* use global/default network selection mode. | ||
^ IMP: Should only be called if the wallet is setup and unlocked |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
^ IMP: Should only be called if the wallet is setup and unlocked | |
* IMP: Should only be called if the wallet is set up and unlocked. |
@@ -212,22 +260,27 @@ public void refreshNetworks() { | |||
init(); | |||
} | |||
|
|||
static void getAllNetworks(JsonRpcService jsonRpcService, List<Integer> supportedCoins, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
public
? Or package private for a reason?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
package accessible only, if there is no modifier then it is default
|
||
double thisPrice = Utils.getOrDefault(assetPrices, | ||
mAsset.symbol.toLowerCase( | ||
Locale.getDefault()), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: For the sake of consistency, let's switch to Locale.ENGLISH
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These parts are just auto formatted and didn't touched though have used and updated for the other parts. will update
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These parts are just auto formatted and didn't touched
I'm well aware, I hope you don't mind if I suggest minor improvements; feel free to skip them if they become too much.
Thank you for making the codebase better, I'm a huge supported of the Boy Scout rule: https://biratkirat.medium.com/step-8-the-boy-scout-rule-robert-c-martin-uncle-bob-9ac839778385
for (AccountInfo accountInfo : accountInfos) { | ||
final String accountAddressLower = | ||
accountInfo.address.toLowerCase( | ||
Locale.getDefault()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here,
for the sake of consistency, let's switch to Locale.ENGLISH
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
}); | ||
}); | ||
final String fiatBalanceString = String.format( | ||
Locale.getDefault(), "$%,.2f", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here,
for the sake of consistency, let's switch to Locale.ENGLISH
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -102,23 +109,96 @@ public Double getMostRecentFiatSum() { | |||
return Double.valueOf(mFiatHistory[mFiatHistory.length - 1].price); | |||
} | |||
|
|||
public void fetchAllAssetsAndDetails(Callbacks.Callback1<PortfolioHelper> callback) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method is really hard to read. Is there anything that can be done to make it more maintainable and easier to follow?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cc @SergeyZhukovsky for thoughts, if we should split this and what's should be the ideal length of a method as this was mostly picked form the existing implementation.
resetResultData(); | ||
if (mActivity.get() == null || mSelectedNetworks.isEmpty()) return; | ||
int totalNetworks = mSelectedNetworks.size(); | ||
AtomicInteger resCount = new AtomicInteger(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why the use of an atomic integer? Aren't the callbacks always in the main thread?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
because cannot use local variable as it is being used within the callback and don't wanna use a global variable to avoid logical complexity so this is a decent solution.
* @return true if Fragment UI can be updated otherwise false | ||
*/ | ||
public static boolean canUpdateFragmentUi(Fragment frag) { | ||
return !(frag.isRemoving() || frag.getActivity() == null || frag.isDetached() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would switch isRemoving
in favor of isRemovingParent
, it's safer as it checks also for the parent ancestors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's only for fragment itself not for the container or parent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fine 👍 Better explains that in the Javadoc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The function name itself explains what it does and I already added javadoc for you specially that should be enough. No need to add info about isRemovingParent
as it is not related and needed. Would suggest to add minor or subjective review as nits because there are often many than the crucial ones.
/** | ||
* 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. | ||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❤️
StringBuilder builder = new StringBuilder(); | ||
for (int i = 0; i < items.length; i++) { | ||
String item = items[i]; | ||
if (TextUtils.isEmpty(item)) continue; | ||
builder.append(item).append(separator); | ||
} | ||
// Delete separator after the last value | ||
builder.deleteCharAt(builder.length() - 1); | ||
return builder.toString(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's make this more elegant using Java streams.
if (items == null) return "";
can remain, but the rest can be optimized into a single line:
return Arrays.stream(items).collect(Collectors.joining(Character.toString(separator)));
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wanna delete the separator at last, and your code doesn't check for nulls or empty.
BTW, the focus is not on refactoring things to streams. Probably just use it where it is more suitable but should not be enforced.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand your answer.
I didn't add a filter
to the chain as I just wanted to suggest a more elegant way, and give you the idea. Not sure about you mention the focus on refactoring the code using streams.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I explained clearly but here's more info.
I have started using streams because now we can https://bravesoftware.slack.com/archives/C03MMJ4CHEZ/p1675178531068709 but this does not mean this we should use this everywhere possible to replace the existing working solution. Plus I also wanted to remove the char at last and the above solution is easy and more efficient than streams.
It's also good practice to not recommend partial or incomplete solutions without information. I think it is better to add subjective suggestions as nit and would recommend the same to separate important vs subjective feedbacks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the feedback and further elaboration @Pavneet-Sing.
I completely agree with what you said about the use of Java streams.
It's important to remember that we're all human, and suggestions may not always be perfect, but that should not deter us from constructive criticism. It provides invaluable insights!
Code reviews have many purposes, not only merging the code back to the main branch. They are an invaluable opportunity to discuss many things, just to name a few:
- Provide feedback and suggestions
- Creating connections with other team members
- Raising awareness of current coding styles and best practices
All of this becomes extremely hard (or impossible) if feedback is not accepted gracefully or (even worse) when the answers become rude. Demonstrating a courteous and receptive attitude towards feedback is crucial for a productive and harmonious workplace.
Really! I couldn't stress this point enough, we should try to be excellent to each other, and being courteous with those who review your code is the foundation for a fully functional team.
Let's continue with this offline, feedback is an essential part of the development process, it plays a crucial part, but discussing it in PR comments may not be appropriate.
It's better to continue these conversations offline to prevent clogging up the PR comments section. Once again, thanks for your valuable input!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't deny the feedback or anything that you've mentioned above with a long paragraph and details, which often not needed. been seeing this patterns many times. The extra details was provided because it was asked.
I just clearly explained that we should not be tempted to use streams and should not enforce this in review, especially with partial solutions and without full understanding. Applying streams here would be an overkill. Would suggest the same to take things more gracefully.
I have been following the practices based on past PRs at brave to move forward quickly as often preferred. As I mentioned above, this was back and forth fixes so hard to maintain a history. Maintaining PR history is good but I personally don't like to add random or partial commits but will do it for big PRs if that's what we prefer now. I will split this PR into 3-4 parts tomorrow. brave/brave-browser#27074 will be in a |
I don't think I suggested to add random or partial commits. I did ask that you be courteous instead of defensive in review feedback, and that you split up concerns logically in a pull request in a way that makes sense to the reviewer and tells a story. Covering one major concern per commit when possible. |
As mentioned above, this solutions were implemented in iterations/fragments while implementing the other parts to test and move with the All network implementation. Random/partial commits was regarding this. will never do it. |
Resolves brave/brave-browser#27074
Resolves brave/brave-browser#27333
Resolves brave/brave-browser#28506
Resolves brave/brave-browser#28748
Resolves brave/brave-browser#28627
Resolves brave/brave-browser#28301
Resolves brave/brave-browser#27614
Submitter Checklist:
QA/Yes
orQA/No
;release-notes/include
orrelease-notes/exclude
;OS/...
) to the associated issuenpm run test -- brave_browser_tests
,npm run test -- brave_unit_tests
wikinpm run lint
,npm run presubmit
wiki,npm run gn_check
,npm run tslint
git rebase master
(if needed)Reviewer Checklist:
gn
After-merge Checklist:
changes has landed on
Test Plan:
multi-chain.webm
Additional: