Skip to content
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

[W3M] UI + Sign integration #843

Merged
merged 2 commits into from
May 17, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ final class ImportPresenter: ObservableObject {
self.router = router
}

@MainActor
func didPressWeb3Modal() async throws {
router.presentWeb3Modal()
}

@MainActor
func didPressImport() async throws {
guard let importAccount = ImportAccount(input: input)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import UIKit
import Web3Modal
import WalletConnectPairing

final class ImportRouter {

Expand All @@ -9,6 +11,19 @@ final class ImportRouter {
init(app: Application) {
self.app = app
}

func presentWeb3Modal() {
Web3ModalSheetController(
projectId: InputConfig.projectId,
metadata: AppMetadata(
name: "Showcase App",
description: "Showcase description",
url: "example.wallet",
icons: ["https://avatars.githubusercontent.com/u/37784886"]
),
webSocketFactory: DefaultSocketFactory()
).present(from: viewController)
}

func presentChat(importAccount: ImportAccount) {
MainModule.create(app: app, importAccount: importAccount).present()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,15 @@ struct ImportView: View {

Spacer()

BrandButton(title: "Ok, done" ) {
try await presenter.didPressImport()
VStack {

BrandButton(title: "Web3Modal") {
try await presenter.didPressWeb3Modal()
}

BrandButton(title: "Ok, done" ) {
try await presenter.didPressImport()
}
}
.padding(16.0)
}
Expand Down
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ let package = Package(
dependencies: ["WalletConnectUtils", "WalletConnectNetworking"]),
.target(
name: "Web3Modal",
dependencies: ["QRCode"]),
dependencies: ["QRCode", "WalletConnectSign"]),
.testTarget(
name: "WalletConnectSignTests",
dependencies: ["WalletConnectSign", "WalletConnectUtils", "TestingUtils", "WalletConnectVerify"]),
Expand Down
11 changes: 10 additions & 1 deletion Sources/WalletConnectRelay/BundleFinder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,16 @@ extension Foundation.Bundle {
Bundle(for: BundleFinder.self).resourceURL,

// For command-line tools.
Bundle.main.bundleURL
Bundle.main.bundleURL,

// One of these should be used when building SwiftUI Previews
Bundle(for: BundleFinder.self).resourceURL?
.deletingLastPathComponent()
.deletingLastPathComponent()
.deletingLastPathComponent(),
Bundle(for: BundleFinder.self).resourceURL?
.deletingLastPathComponent()
.deletingLastPathComponent()
]

for candidate in candidates {
Expand Down
58 changes: 58 additions & 0 deletions Sources/Web3Modal/Extensions/Color.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import SwiftUI

extension Color {
static let foreground1 = Color("foreground1", bundle: .module)
static let foreground2 = Color("foreground2", bundle: .module)
static let foreground3 = Color("foreground3", bundle: .module)
static let foregroundInverse = Color("foregroundInverse", bundle: .module)
static let background1 = Color("background1", bundle: .module)
static let background2 = Color("background2", bundle: .module)
static let background3 = Color("background3", bundle: .module)
static let negative = Color("negative", bundle: .module)
static let thickOverlay = Color("thickOverlay", bundle: .module)
static let thinOverlay = Color("thinOverlay", bundle: .module)
static let accent = Color("accent", bundle: .module)
}

@available(iOS 15.0, *)
struct Color_Previews: PreviewProvider {
static var allColors: [(String, Color)] {
[
("foreground1", Color("foreground1", bundle: .module)),
("foreground2", Color("foreground2", bundle: .module)),
("foreground3", Color("foreground3", bundle: .module)),
("foregroundInverse", Color("foregroundInverse", bundle: .module)),
("background1", Color("background1", bundle: .module)),
("background2", Color("background2", bundle: .module)),
("background3", Color("background3", bundle: .module)),
("negative", Color("negative", bundle: .module)),
("thickOverlay", Color("thickOverlay", bundle: .module)),
("thinOverlay", Color("thinOverlay", bundle: .module)),
("accent", Color("accent", bundle: .module)),
]
}

static var previews: some View {
VStack {
let columns = [
GridItem(.adaptive(minimum: 150)),
]

LazyVGrid(columns: columns, alignment: .leading) {
ForEach(allColors, id: \.1) { name, color in

VStack(alignment: .leading) {
RoundedRectangle(cornerRadius: 12)
.fill(color)
.frame(width: 62, height: 62)

Text(name).bold()
}
.font(.footnote)
}
}
}
.padding()
.previewLayout(.sizeThatFits)
}
}
18 changes: 18 additions & 0 deletions Sources/Web3Modal/Extensions/View+RoundedCorners.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import SwiftUI

extension View {
func cornerRadius(_ radius: CGFloat, corners: UIRectCorner) -> some View {
clipShape( RoundedCorner(radius: radius, corners: corners) )
}
}

struct RoundedCorner: Shape {

var radius: CGFloat = .infinity
var corners: UIRectCorner = .allCorners

func path(in rect: CGRect) -> Path {
let path = UIBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
return Path(path.cgPath)
}
}
Original file line number Diff line number Diff line change
@@ -1,36 +1,51 @@
import SwiftUI
import WalletConnectPairing

public struct Web3ModalContainerView: View {
public struct ModalContainerView: View {

@Environment(\.presentationMode) var presentationMode

@State var showModal: Bool = false

public init() {

let projectId: String
let metadata: AppMetadata
let webSocketFactory: WebSocketFactory

public init(projectId: String, metadata: AppMetadata, webSocketFactory: WebSocketFactory) {
self.projectId = projectId
self.metadata = metadata
self.webSocketFactory = webSocketFactory
}

public var body: some View {

VStack(spacing: 0) {

Color.black.opacity(0.3)
Color.thickOverlay
.colorScheme(.light)
.onTapGesture {
withAnimation {
showModal = false
}
}

if showModal {
Web3ModalSheet(destination: .welcome, isShown: $showModal)
ModalSheet(
viewModel: .init(
isShown: $showModal,
projectId: projectId,
interactor: .init(projectId: projectId, metadata: metadata, webSocketFactory: webSocketFactory)
))
.transition(.move(edge: .bottom))
.animation(.spring(), value: showModal)
}
}
.edgesIgnoringSafeArea(.all)
.onChangeBackported(of: showModal, perform: { newValue in
if newValue == false {
dismiss()
withAnimation {
dismiss()
}
}
})
.onAppear {
Expand All @@ -47,5 +62,3 @@ public struct Web3ModalContainerView: View {
}
}
}


47 changes: 47 additions & 0 deletions Sources/Web3Modal/Modal/ModalInteractor.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import WalletConnectPairing
import WalletConnectSign
import Combine
import WalletConnectNetworking

extension ModalSheet {
final class Interactor {
let projectId: String
let metadata: AppMetadata
let socketFactory: WebSocketFactory

lazy var sessionsPublisher: AnyPublisher<[Session], Never> = Sign.instance.sessionsPublisher

init(projectId: String, metadata: AppMetadata, webSocketFactory: WebSocketFactory) {
self.projectId = projectId
self.metadata = metadata
self.socketFactory = webSocketFactory

Pair.configure(metadata: metadata)
Networking.configure(projectId: projectId, socketFactory: socketFactory)
}

// func getListings() async throws -> [Listing] {
// let listingResponse = try await ExplorerApi.live().getMobileListings(projectId)
// return listingResponse.listings.values.compactMap { $0 }
// }

func connect() async throws -> WalletConnectURI {

let uri = try await Pair.instance.create()

let methods: Set<String> = ["eth_sendTransaction", "personal_sign", "eth_signTypedData"]
let blockchains: Set<Blockchain> = [Blockchain("eip155:1")!, Blockchain("eip155:137")!]
let namespaces: [String: ProposalNamespace] = [
"eip155": ProposalNamespace(
chains: blockchains,
methods: methods,
events: []
)
]

try await Sign.instance.connect(requiredNamespaces: namespaces, topic: uri.topic)

return uri
}
}
}
51 changes: 51 additions & 0 deletions Sources/Web3Modal/Modal/ModalSheet+Previews.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#if DEBUG

import SwiftUI
import WalletConnectPairing

class WebSocketMock: WebSocketConnecting {
var request: URLRequest = .init(url: URL(string: "wss://relay.walletconnect.com")!)

var onText: ((String) -> Void)?
var onConnect: (() -> Void)?
var onDisconnect: ((Error?) -> Void)?
var sendCallCount: Int = 0
var isConnected: Bool = false

func connect() {}
func disconnect() {}
func write(string: String, completion: (() -> Void)?) {}
}

class WebSocketFactoryMock: WebSocketFactory {
func create(with url: URL) -> WebSocketConnecting {
WebSocketMock()
}
}

struct ModalSheet_Previews: PreviewProvider {
static let projectId = "9bfe94c9cbf74aaa0597094ef561f703"
static let metadata = AppMetadata(
name: "Showcase App",
description: "Showcase description",
url: "example.wallet",
icons: ["https://avatars.githubusercontent.com/u/37784886"]
)

static var previews: some View {
ModalSheet(
viewModel: .init(
isShown: .constant(true),
projectId: projectId,
interactor: .init(
projectId: projectId,
metadata: metadata,
webSocketFactory: WebSocketFactoryMock()
)
)
)
.previewLayout(.sizeThatFits)
}
}

#endif
Loading