-
Notifications
You must be signed in to change notification settings - Fork 90
feat: add EFP (Ethereum Follow Protocol) addresses to address book #19195
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
base: master
Are you sure you want to change the base?
Conversation
Jenkins BuildsClick to see older builds (11)
|
|
Wow, nice job at a first glance! Pls rebase to get rid of the conflicts |
jrainville
left a comment
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.
Midway review. I checked all Nim files for now.
Great job! I think the biggest things are the loading props/events are not used. Also, there are way too many info logs 😅
Can you trim most of them down and maybe switch some of them to debug
src/app/modules/main/wallet_section/following_addresses/controller.nim
Outdated
Show resolved
Hide resolved
src/app/modules/main/wallet_section/following_addresses/controller.nim
Outdated
Show resolved
Hide resolved
src/app/modules/main/wallet_section/following_addresses/controller.nim
Outdated
Show resolved
Hide resolved
src/app/modules/main/wallet_section/following_addresses/controller.nim
Outdated
Show resolved
Hide resolved
src/app/modules/main/wallet_section/following_addresses/model.nim
Outdated
Show resolved
Hide resolved
src/app/modules/main/wallet_section/following_addresses/module.nim
Outdated
Show resolved
Hide resolved
src/app/modules/main/wallet_section/following_addresses/controller.nim
Outdated
Show resolved
Hide resolved
jrainville
left a comment
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.
Super nice job! I finished reviewing. I found no big problem in the QML, though it is less my area of expertise, so let's see what the experts say 😄
| id: noFollowingAddresses | ||
| Layout.fillWidth: true | ||
| Layout.preferredHeight: 44 | ||
| visible: RootStore.followingAddresses.count === 0 |
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 we're moving away from using Singleton stores. It makes it hard to test and use the components in Sotrybook.
To "fix" this, just add a property at the top and pass the needed property from the store in the 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.
Oh, I see that the existing components already use RootStore like that. I'll wait to see what the others say, since it seems the other components need refactoring anyway
| } | ||
|
|
||
| // Full-width divider above pagination (extends beyond content padding) | ||
| Rectangle { |
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 we already have a component for Separators. @caybro @noeliaSD @micieslak please help here
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.
Yeah, Separator but it's not very useful in this context
caybro
left a comment
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.
Great job! Just a couple of comments, mostly regarding some good QML practices and component structure
ui/app/AppLayouts/Wallet/controls/FollowingAddressesDelegate.qml
Outdated
Show resolved
Hide resolved
ui/app/AppLayouts/Wallet/controls/FollowingAddressesDelegate.qml
Outdated
Show resolved
Hide resolved
ui/app/AppLayouts/Wallet/controls/FollowingAddressesDelegate.qml
Outdated
Show resolved
Hide resolved
ui/app/AppLayouts/Wallet/panels/WalletFollowingAddressesHeader.qml
Outdated
Show resolved
Hide resolved
|
@caybro thanks for the feedback, I've made your recommended changes and rebased ontop of the latest commits. |
jrainville
left a comment
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.
Looks good from my side!
I haven't tested manually though
| self.allCollectiblesModule.load() | ||
| info "wallet-section: loading assetsModule" | ||
| self.assetsModule.load() | ||
| info "wallet-section: loading savedAddressesModule" |
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 info logs here can be removed as well
6407be9 to
a4a17bc
Compare
|
@caybro can you please re-review this PR? Let's get it merged |
|
I have updated the branch with latest upstream commits, and resolved a status-go conflict. |
caybro
left a comment
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.
Keep up the good work, we're getting there 💪
| import "../stores" | ||
| import ".." | ||
|
|
||
| import AppLayouts.Wallet.stores as WalletStores |
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.
You definitely don't need all those imports :)
| property var activeNetworks | ||
|
|
||
| readonly property int maxHeight: 341 | ||
| height: implicitHeight > maxHeight ? maxHeight : implicitHeight |
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.
Don't set maxHeight or height at all, the menu will figure it out
|
|
||
| StatusAction { | ||
| text: { | ||
| var savedAddr = WalletStores.RootStore.getSavedAddress(root.address) |
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.
You should extract the savedAddr, isSaved etc.. as a readonly property of this StatusAction, and evaluate it only once, instead of multiple times for each property here
|
|
||
| font.weight: Font.Medium | ||
| textPosition: StatusBaseButton.TextPosition.Left | ||
| textColor: Theme.palette.primaryColor1 |
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 these 3 props are the default already
| id: listView | ||
| objectName: "FollowingAddressesView_followingAddresses" | ||
| anchors.fill: parent | ||
| spacing: 8 |
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.
| spacing: 8 | |
| spacing: Theme.halfPadding |
| property string lastReloadedTime | ||
|
|
||
| /* Indicates whether the content is being loaded */ | ||
| property bool loading |
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.
required
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.
hmm, required is helpful when no value makes no sense and there is no good default value and e.g. component would be rendered incorrectly because of that. In this case required is not needed imo.
| BlockchainExplorersMenu { | ||
| id: blockchainExplorersMenu | ||
| flatNetworks: root.activeNetworks | ||
| onNetworkClicked: { |
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.
| onNetworkClicked: { | |
| onNetworkClicked: (shortname, isTestnet) => { |
| visible: !!root.name | ||
| enabled: root.showButtons | ||
| type: StatusRoundButton.Type.Quinary | ||
| radius: 8 |
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.
| radius: 8 | |
| radius: Theme.radius |
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.
and above too
| } | ||
|
|
||
| title: name | ||
| objectName: name || "followingAddressDelegate" |
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.
You usually don't set it here, but rather inside the (List)view, here it's kinda useless
| import "../stores" | ||
| import ".." | ||
|
|
||
| import AppLayouts.Wallet.stores as WalletStores |
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.
Again, all those imports needed?
@caybro thank you, will address asap |
|
@caveman-eth we've sent you an invite for collaboration in |
micieslak
left a comment
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.
That's huge, nice work! Definitely good job.
I left some comments mainly regarding qml code structure. I think the doc that may help a lot there is our guide: https://github.com/status-im/status-desktop/blob/master/guidelines/QML_ARCHITECTURE_GUIDE.md
Thanks!
| property string lastReloadedTime | ||
|
|
||
| /* Indicates whether the content is being loaded */ | ||
| property bool loading |
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.
hmm, required is helpful when no value makes no sense and there is no good default value and e.g. component would be rendered incorrectly because of that. In this case required is not needed imo.
| StatusListItem { | ||
| id: root | ||
|
|
||
| property SharedStores.NetworkConnectionStore networkConnectionStore |
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.
Please don't make low-level UI components like delegates dependent directly on stores. Please refer to https://github.com/status-im/status-desktop/blob/master/guidelines/QML_ARCHITECTURE_GUIDE.md#stores for details.
| import shared.popups | ||
| import shared.stores as SharedStores | ||
|
|
||
| import "../popups" |
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.
Please use identified module imports whenever possible.
| id: root | ||
|
|
||
| property SharedStores.NetworkConnectionStore networkConnectionStore | ||
| property var activeNetworks |
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.
As a model it should be named activeNetworksModel and ideally there should be description of expected roles and their types in the comment.
| property var tags | ||
| property string avatar | ||
|
|
||
| property int usage: FollowingAddressesDelegate.Usage.Delegate |
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.
Instead of introducing usage method, it would be cleaner to expose clicked signal and externalize that differentiation from that component.
|
|
||
| readonly property bool isAddressSaved: { | ||
| savedAddressesVersion | ||
| var savedAddr = WalletStores.RootStore.getSavedAddress(root.address) |
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.
Please don't use that singleton store there. Delegates should not rely on delegates at all.
Btw, the singleton stores are intended to be refactored to non-singleton components soon.
Probably the easiest option here is to externalize that property (adding top level property isAddressSaved and resolving it externally). It will allow removing from there Connections object as well.
| icon.name: d.isAddressSaved ? "star-icon" : "star-icon-outline" | ||
| enabled: !d.isAddressSaved | ||
| onClicked: { | ||
| var nameToUse = root.ensName || root.address |
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.
please use "modern" js (const/let instead of var)
| property alias starButton: starButton | ||
|
|
||
| signal openSendModal(string recipient) | ||
| signal menuRequested(var menuModel) |
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.
please don't "pack" parametes into signle model. It's shorter but harder to read and maintain. Please use explicit list of parameters with their own types and names.
|
|
||
| StatusAction { | ||
| text: { | ||
| var savedAddr = WalletStores.RootStore.getSavedAddress(root.address) |
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.
Please use const/let consistently in the whole pr.
| } | ||
| objectName: "addToSavedAddressesAction" | ||
| enabled: { | ||
| var savedAddr = WalletStores.RootStore.getSavedAddress(root.address) |
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 WalletStore.RootStore is a singleton right now (probably the last one) and will be refactored soon. Because of that, please take this store via public API of that that component (and others as well) and inside the component use it as a regular, non-singleton object.
micieslak
left a comment
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.
One more quite important thing I forgot in previous comments.
For UI development we use our internal tool Storybook. The UI components have their own "pages" there where are instantiated in separation. It speeds up development and further maintenance. I'd love if you could add pages for the components you created. Thanks!
|
@caybro @micieslak thank you for your reviews, I've pushed your suggestions now, I appreciate the comments. let me know if I've missed anything :) |
Introduces support for EFP following addresses throughout the wallet app, including backend RPCs, service layer, controller, model, and QML UI integration. Adds new modules, views, delegates, and updates wallet section logic to display and manage onchain friends from EFP, with ENS and avatar support. Also updates SavedAddressesDelegate to handle EFP addresses and refines wallet header and layout for the new section.
…ing addresses Cleans up excessive debug logging and removes unused loading state and cache checks from the following addresses modules and service. Updates the QML views to simplify loading indicators and ensures data is loaded when the user navigates to the following addresses page. Update status-go submodule to latest commit
Extracted FollowingAddressMenu into a separate QML component and updated FollowingAddressesDelegate to use a menuRequested signal for menu actions. Improved property requirements and data flow in FollowingAddresses and FollowingAddressesView, and updated connections for refreshing and updating following addresses. Minor UI text adjustment in WalletFollowingAddressesHeader and code cleanup in RootStore. This refactor improves modularity, maintainability, and clarity of the following addresses feature.
Eliminated info log statements from the load() method in the wallet_section module to reduce console output and clean up the code.
Refactors FollowingAddresses components to use injected rootStore and activeNetworksModel, improving testability and modularity. Adds storybook pages for FollowingAddressMenu, FollowingAddressesDelegate, and FollowingAddressesView for interactive testing and development. Updates RootStore stubs and related stores to support new signals and mock data. Improves pagination, event handling, and UI consistency in the following addresses workflow.
|
@caveman-eth I'm checking with infra team why CI only triggered partially |
@igor-sirotin Ok thanks. I also don't have read perms for jenkins, so I can't see why its the checks are failing. |
What does the PR do
Adds a new "Following Addresses" tab to the wallet that displays onchain followings from the Ethereum Follow Protocol (EFP). Users can view, search, and save their EFP followings directly in Status.
Issue: #18686
Status-go dependency: status-im/status-go#7052
Features:
Technical implementation:
following_addressservice module in Nim with async RPC task handlingFollowingAddressesView- extendsRightTabBaseViewwith custom headerWalletFollowingAddressesHeader- custom header component matching SavedAddresses patternFollowingAddresses- main content component with search and paginationFollowingAddressesDelegate- individual address list itemSavedAddressActivityPopupandSavedAddressesDelegateto support following addressesAffected areas
Architecture compliance
My PR is consistent with this document: QML Architecture Guidelines
Screencapture of the functionality
Video: https://streamable.com/3y4s1f
Image:

Impact on end user
Before:
After:
How to test
Risk
Low risk. New feature with no modifications to existing wallet functionality.