Skip to content

Commit

Permalink
Merge pull request #32 from WalletConnect/feat/ui-feedback
Browse files Browse the repository at this point in the history
Implementing UI feedback
  • Loading branch information
radeknovis authored Nov 16, 2023
2 parents 6905726 + f2dd444 commit 8fc186e
Show file tree
Hide file tree
Showing 45 changed files with 534 additions and 320 deletions.
3 changes: 3 additions & 0 deletions Sample/Example/ComponentLibraryView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ struct ComponentLibraryView: View {
NavigationLink(destination: W3MListItemButtonStylePreviewView()) {
Text("W3MListItemButtonStyle")
}
NavigationLink(destination: ToastViewPreviewView()) {
Text("ToastView")
}
}
.listStyle(.plain)
#endif
Expand Down
2 changes: 1 addition & 1 deletion Sample/Example/ExampleApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ struct ExampleApp: App {
description: "Web3Modal DApp sample",
url: "wallet.connect",
icons: ["https://avatars.githubusercontent.com/u/37784886"],
redirect: .init(native: "", universal: "")
redirect: .init(native: "w3mdapp://", universal: nil)
)

let projectId = Secrets.load().projectID
Expand Down
7 changes: 7 additions & 0 deletions Sample/Example/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@
<string>Atlantis would use Bonjour Service to discover Proxyman app from your local network.</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>w3mdapp</string>
</dict>
</array>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>metamask</string>
Expand Down
52 changes: 30 additions & 22 deletions Sources/Web3Modal/Components/AccountButton.swift
Original file line number Diff line number Diff line change
Expand Up @@ -144,14 +144,17 @@ struct AccountButtonStyle: ButtonStyle {
}

public struct AccountButton: View {
var store: Store
let store: Store
let blockchainApiInteractor: BlockchainAPIInteractor

public init() {
self.store = .shared
self.blockchainApiInteractor = BlockchainAPIInteractor(store: .shared)
}

init(store: Store = .shared) {
init(store: Store = .shared, blockchainApiInteractor: BlockchainAPIInteractor) {
self.store = store
self.blockchainApiInteractor = blockchainApiInteractor
}

public var body: some View {
Expand All @@ -168,7 +171,7 @@ public struct AccountButton: View {
func fetchIdentity() {
Task { @MainActor in
do {
try await BlockchainAPIInteractor(store: store).getIdentity()
try await blockchainApiInteractor.getIdentity()
} catch {
store.toast = .init(style: .error, message: "Failed to fetch identity")
}
Expand All @@ -178,7 +181,7 @@ public struct AccountButton: View {
func fetchBalance() {
Task { @MainActor in
do {
try await BlockchainAPIInteractor(store: store).getBalance()
try await blockchainApiInteractor.getBalance()
} catch {
store.toast = .init(style: .error, message: "Failed to fetch balance")
}
Expand All @@ -195,32 +198,37 @@ public struct AccountButtonPreviewView: View {
let store = Store()
store.balance = balance
store.session = .stub

Web3Modal.configure(
projectId: "",
metadata: .init(
name: "",
description: "",
url: "",
icons: [],
redirect: .init(native: "", universal: "")
)
)


return store
}

static let blockchainInteractor = { () -> BlockchainAPIInteractor in
MockBlockchainAPIInteractor()
}

public var body: some View {
VStack {
AccountButton(store: AccountButtonPreviewView.store(1.23))
AccountButton(
store: AccountButtonPreviewView.store(1.23),
blockchainApiInteractor: MockBlockchainAPIInteractor()
)

AccountButton(store: AccountButtonPreviewView.store(nil))
AccountButton(
store: AccountButtonPreviewView.store(nil),
blockchainApiInteractor: MockBlockchainAPIInteractor()
)

AccountButton(store: AccountButtonPreviewView.store(1.23))
.disabled(true)
AccountButton(
store: AccountButtonPreviewView.store(1.23),
blockchainApiInteractor: MockBlockchainAPIInteractor()
)
.disabled(true)

AccountButton(store: AccountButtonPreviewView.store(nil))
.disabled(true)
AccountButton(
store: AccountButtonPreviewView.store(nil),
blockchainApiInteractor: MockBlockchainAPIInteractor()
)
.disabled(true)

Button(action: {}, label: {})
.buttonStyle(
Expand Down
16 changes: 14 additions & 2 deletions Sources/Web3Modal/Core/BlockchainAPIInteractor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import HTTPClient

import JSONRPC

final class BlockchainAPIInteractor: ObservableObject {
private let store: Store
class BlockchainAPIInteractor: ObservableObject {
let store: Store

init(store: Store = .shared) {
self.store = store
Expand Down Expand Up @@ -123,3 +123,15 @@ extension Decimal {
return self / weiFactor
}
}

#if DEBUG
class MockBlockchainAPIInteractor: BlockchainAPIInteractor {
override func getIdentity() async throws {
// no-op
}

override func getBalance() async throws {
// no-op
}
}
#endif
31 changes: 16 additions & 15 deletions Sources/Web3Modal/Core/W3MAPIInteractor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ final class W3MAPIInteractor: ObservableObject {

private let entriesPerPage: Int = 40

var page: Int = 0
var totalPage: Int = .max
var totalEntries: Int = 0

init(
Expand All @@ -27,22 +25,26 @@ final class W3MAPIInteractor: ObservableObject {
}

if search.isEmpty {
page = min(page + 1, totalPage)
store.currentPage = min(store.currentPage + 1, store.totalPages)
}

let params = Web3ModalAPI.GetWalletsParams(
page: search.isEmpty ? store.currentPage : 1,
entries: search.isEmpty ? entriesPerPage : 100,
search: search,
projectId: Web3Modal.config.projectId,
metadata: Web3Modal.config.metadata,
recommendedIds: Web3Modal.config.recommendedWalletIds,
excludedIds: Web3Modal.config.excludedWalletIds
)

print(#function, search, params.page, params.entries)

let httpClient = HTTPNetworkClient(host: "api.web3modal.com")
let response = try await httpClient.request(
GetWalletsResponse.self,
at: Web3ModalAPI.getWallets(
params: .init(
page: search.isEmpty ? page : 1,
entries: search.isEmpty ? entriesPerPage : 100,
search: search,
projectId: Web3Modal.config.projectId,
metadata: Web3Modal.config.metadata,
recommendedIds: Web3Modal.config.recommendedWalletIds,
excludedIds: Web3Modal.config.excludedWalletIds
)
params: params
)
)

Expand All @@ -60,13 +62,12 @@ final class W3MAPIInteractor: ObservableObject {
self.store.searchedWallets = wallets
} else {
self.store.searchedWallets = []
self.store.wallets.append(contentsOf: wallets)
self.store.wallets.formUnion(wallets)
self.totalEntries = response.count
self.totalPage = Int(ceil(Double(response.count) / Double(entriesPerPage)))
self.store.totalPages = Int(ceil(Double(response.count) / Double(entriesPerPage)))
}

self.isLoading = false
self.objectWillChange.send()
}
}

Expand Down
46 changes: 29 additions & 17 deletions Sources/Web3Modal/Core/Web3Modal.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ public class Web3Modal {
if let session = client.getSessions().first {
Store.shared.session = session


if let blockchain = session.accounts.first?.blockchain {
let matchingChain = ChainPresets.ethChains.first(where: {
$0.chainNamespace == blockchain.namespace && $0.chainReference == blockchain.reference
Expand All @@ -65,6 +64,8 @@ public class Web3Modal {
}

private(set) static var config: Config!

private(set) static var viewModel: Web3ModalViewModel!

private init() {}

Expand All @@ -88,10 +89,23 @@ public class Web3Modal {
recommendedWalletIds: recommendedWalletIds,
excludedWalletIds: excludedWalletIds
)

Task {
let interactor = W3MAPIInteractor()

let store = Store.shared
let router = Router()
let w3mApiInteractor = W3MAPIInteractor(store: store)
let signInteractor = SignInteractor(store: store)
let blockchainApiInteractor = BlockchainAPIInteractor(store: store)
let interactor = W3MAPIInteractor()

Web3Modal.viewModel = Web3ModalViewModel(
router: router,
store: store,
w3mApiInteractor: w3mApiInteractor,
signInteractor: signInteractor,
blockchainApiInteractor: blockchainApiInteractor
)

Task {
try? await interactor.fetchWalletImages(for: Store.shared.recentWallets)
try? await interactor.fetchAllWalletMetadata()
try? await interactor.fetchFeaturedWallets()
Expand All @@ -114,43 +128,41 @@ public class Web3Modal {

#if canImport(UIKit)

extension Web3Modal {

public static func addChainPreset(_ chain: Chain) {
public extension Web3Modal {
static func addChainPreset(_ chain: Chain) {
ChainPresets.ethChains.append(chain)
}

public static func selectChain(_ chain: Chain) {
static func selectChain(_ chain: Chain) {
Store.shared.selectedChain = chain
}

public static func selectChain(from presentingViewController: UIViewController? = nil) {
static func selectChain(from presentingViewController: UIViewController? = nil) {
guard let vc = presentingViewController ?? topViewController() else {
assertionFailure("No controller found for presenting modal")
return
}

_ = Web3Modal.instance

let router = Router()
router.setRoute(Router.NetworkSwitchSubpage.selectChain)

let modal = Web3ModalSheetController(router: router)
Web3Modal.viewModel.router.setRoute(Router.NetworkSwitchSubpage.selectChain)

let modal = Web3ModalSheetController(router: Web3Modal.viewModel.router)
vc.present(modal, animated: true)
}

public static func present(from presentingViewController: UIViewController? = nil) {
static func present(from presentingViewController: UIViewController? = nil) {
guard let vc = presentingViewController ?? topViewController() else {
assertionFailure("No controller found for presenting modal")
return
}

_ = Web3Modal.instance

let router = Router()
router.setRoute(Store.shared.session != nil ? Router.AccountSubpage.profile : Router.ConnectingSubpage.connectWallet)
Web3Modal.viewModel.router.setRoute(Store.shared.session != nil ? Router.AccountSubpage.profile : Router.ConnectingSubpage.connectWallet)

let modal = Web3ModalSheetController(router: router)
let modal = Web3ModalSheetController(router: Web3Modal.viewModel.router)
vc.present(modal, animated: true)
}

Expand Down Expand Up @@ -231,7 +243,7 @@ public struct SessionParams {

return SessionParams(
requiredNamespaces: [:],
optionalNamespaces: namespaces.merging(optionalNamespaces, uniquingKeysWith: { old, new in old }),
optionalNamespaces: namespaces.merging(optionalNamespaces, uniquingKeysWith: { old, _ in old }),
sessionProperties: nil
)
}()
Expand Down
2 changes: 1 addition & 1 deletion Sources/Web3Modal/Screens/AccountView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ struct AccountView: View {

Button {
UIPasteboard.general.string = store.session?.accounts.first?.address
store.toast = .init(style: .info, message: "Address copied")
store.toast = .init(style: .success, message: "Address copied")
} label: {
Image.LargeCopy
.resizable()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ struct NetworkDetailView: View {
.frame(width: 80, height: 80)
.clipShape(Polygon(count: 6, relativeCornerRadius: 0.25))
.cornerRadius(Radius.m)
.overlay(alignment: .bottomTrailing) {
Image.ToastError
.padding(2)
.background(Color.Background125)
.clipShape(Circle())
.opacity(viewModel.switchFailed ? 1 : 0)
}

if !viewModel.switchFailed {
DrawingProgressView(shape: .hexagon, color: .Blue100, lineWidth: 3, isAnimating: .constant(true))
Expand Down
Loading

0 comments on commit 8fc186e

Please sign in to comment.