From 7971e7de859f8c68b1551244c1fa26a9dce38ecc Mon Sep 17 00:00:00 2001 From: Alexander Lisovik Date: Tue, 6 Dec 2022 13:59:00 +0100 Subject: [PATCH 01/14] Extract wallet app for chat auth + architecture adjustments --- .../ApplicationLayer/AppDelegate.swift | 19 + .../ApplicationLayer/Application.swift | 16 + .../Configurator/AppearanceConfigurator.swift | 19 + .../ApplicationConfigurator.swift | 16 + .../Configurator/Configurator.swift | 9 + .../Configurator/MigrationConfigurator.swift | 9 + .../Configurator/ThirdPartyConfigurator.swift | 21 + .../ApplicationLayer/SceneDelegate.swift | 43 ++ .../Common/Components/BrandButton.swift | 20 + .../Common/Components/InputView.swift | 28 + .../Common/Components/TextFieldView.swift | 50 ++ .../Common/Extensions/SwiftUI/View.swift | 17 + .../Common/Extensions/UIKit/String.swift | 8 + .../Common/Extensions/UIKit/UIColor.swift | 20 + .../Extensions/UIKit/UIViewController.swift | 51 ++ .../Common/Helpers/UIPasteboardWrapper.swift | 15 + Example/ChatWallet/Common/InputConfig.swift | 12 + Example/ChatWallet/Common/Style/Color.swift | 32 ++ Example/ChatWallet/Common/Types/Types.swift | 3 + .../Common/VIPER/SceneViewController.swift | 87 +++ .../AccountStorage/AccountStorage.swift | 21 + .../Chat/AccountNameResolver.swift | 23 + .../DomainLayer/Chat/ChatService.swift | 67 +++ .../DomainLayer/Chat/RegisterService.swift | 15 + .../SocketFactory/SocketFactory.swift | 11 + .../AccentColor.colorset/Contents.json | 11 + .../AppIcon.appiconset/Contents.json | 116 ++++ .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 0 -> 909 bytes .../Icon-App-20x20@2x-1.png | Bin 0 -> 1706 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 0 -> 1706 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 0 -> 2303 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 0 -> 1247 bytes .../Icon-App-29x29@2x-1.png | Bin 0 -> 2260 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 0 -> 2260 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 0 -> 3370 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 0 -> 1706 bytes .../Icon-App-40x40@2x-1.png | Bin 0 -> 3211 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 0 -> 3211 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 0 -> 4313 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 0 -> 4313 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 0 -> 6262 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 0 -> 2990 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 0 -> 5312 bytes .../Icon-App-83.5x83.5@2x.png | Bin 0 -> 6074 bytes .../AppIcon.appiconset/ItunesArtwork@2x.png | Bin 0 -> 39006 bytes .../Other/Assets.xcassets/Contents.json | 6 + Example/ChatWallet/Other/Info.plist | 45 ++ .../AuthRequest/AuthRequestInteractor.swift | 17 + .../AuthRequest/AuthRequestModule.swift | 19 + .../AuthRequest/AuthRequestPresenter.swift | 56 ++ .../AuthRequest/AuthRequestRouter.swift | 16 + .../Wallet/AuthRequest/AuthRequestView.swift | 54 ++ .../Wallet/Scan/ScanInteractor.swift | 3 + .../Wallet/Scan/ScanModule.swift | 22 + .../Wallet/Scan/ScanPresenter.swift | 48 ++ .../Wallet/Scan/ScanRouter.swift | 12 + .../Wallet/Scan/ScanView.swift | 19 + .../Wallet/Scan/Views/ScanQR.swift | 39 ++ .../Wallet/Scan/Views/ScanQRView.swift | 187 +++++++ .../Wallet/Scan/Views/ScanTargetView.swift | 87 +++ .../Wallet/Wallet/WalletInteractor.swift | 67 +++ .../Wallet/Wallet/WalletModule.swift | 16 + .../Wallet/Wallet/WalletPresenter.swift | 21 + .../Wallet/Wallet/WalletRouter.swift | 28 + .../Wallet/Wallet/WalletView.swift | 65 +++ Example/ExampleApp.xcodeproj/project.pbxproj | 499 +++++++++++++++++- 66 files changed, 2084 insertions(+), 1 deletion(-) create mode 100644 Example/ChatWallet/ApplicationLayer/AppDelegate.swift create mode 100644 Example/ChatWallet/ApplicationLayer/Application.swift create mode 100644 Example/ChatWallet/ApplicationLayer/Configurator/AppearanceConfigurator.swift create mode 100644 Example/ChatWallet/ApplicationLayer/Configurator/ApplicationConfigurator.swift create mode 100644 Example/ChatWallet/ApplicationLayer/Configurator/Configurator.swift create mode 100644 Example/ChatWallet/ApplicationLayer/Configurator/MigrationConfigurator.swift create mode 100644 Example/ChatWallet/ApplicationLayer/Configurator/ThirdPartyConfigurator.swift create mode 100644 Example/ChatWallet/ApplicationLayer/SceneDelegate.swift create mode 100644 Example/ChatWallet/Common/Components/BrandButton.swift create mode 100644 Example/ChatWallet/Common/Components/InputView.swift create mode 100644 Example/ChatWallet/Common/Components/TextFieldView.swift create mode 100644 Example/ChatWallet/Common/Extensions/SwiftUI/View.swift create mode 100644 Example/ChatWallet/Common/Extensions/UIKit/String.swift create mode 100644 Example/ChatWallet/Common/Extensions/UIKit/UIColor.swift create mode 100644 Example/ChatWallet/Common/Extensions/UIKit/UIViewController.swift create mode 100644 Example/ChatWallet/Common/Helpers/UIPasteboardWrapper.swift create mode 100644 Example/ChatWallet/Common/InputConfig.swift create mode 100644 Example/ChatWallet/Common/Style/Color.swift create mode 100644 Example/ChatWallet/Common/Types/Types.swift create mode 100644 Example/ChatWallet/Common/VIPER/SceneViewController.swift create mode 100644 Example/ChatWallet/DomainLayer/AccountStorage/AccountStorage.swift create mode 100644 Example/ChatWallet/DomainLayer/Chat/AccountNameResolver.swift create mode 100644 Example/ChatWallet/DomainLayer/Chat/ChatService.swift create mode 100644 Example/ChatWallet/DomainLayer/Chat/RegisterService.swift create mode 100644 Example/ChatWallet/DomainLayer/SocketFactory/SocketFactory.swift create mode 100644 Example/ChatWallet/Other/Assets.xcassets/AccentColor.colorset/Contents.json create mode 100644 Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png create mode 100644 Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x-1.png create mode 100644 Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png create mode 100644 Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png create mode 100644 Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png create mode 100644 Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x-1.png create mode 100644 Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png create mode 100644 Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png create mode 100644 Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png create mode 100644 Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x-1.png create mode 100644 Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png create mode 100644 Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png create mode 100644 Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png create mode 100644 Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png create mode 100644 Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png create mode 100644 Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png create mode 100644 Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png create mode 100644 Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png create mode 100644 Example/ChatWallet/Other/Assets.xcassets/Contents.json create mode 100644 Example/ChatWallet/Other/Info.plist create mode 100644 Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestInteractor.swift create mode 100644 Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestModule.swift create mode 100644 Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestPresenter.swift create mode 100644 Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestRouter.swift create mode 100644 Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestView.swift create mode 100644 Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanInteractor.swift create mode 100644 Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanModule.swift create mode 100644 Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanPresenter.swift create mode 100644 Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanRouter.swift create mode 100644 Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanView.swift create mode 100644 Example/ChatWallet/PresentationLayer/Wallet/Scan/Views/ScanQR.swift create mode 100644 Example/ChatWallet/PresentationLayer/Wallet/Scan/Views/ScanQRView.swift create mode 100644 Example/ChatWallet/PresentationLayer/Wallet/Scan/Views/ScanTargetView.swift create mode 100644 Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletInteractor.swift create mode 100644 Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletModule.swift create mode 100644 Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletPresenter.swift create mode 100644 Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletRouter.swift create mode 100644 Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletView.swift diff --git a/Example/ChatWallet/ApplicationLayer/AppDelegate.swift b/Example/ChatWallet/ApplicationLayer/AppDelegate.swift new file mode 100644 index 000000000..43d099d07 --- /dev/null +++ b/Example/ChatWallet/ApplicationLayer/AppDelegate.swift @@ -0,0 +1,19 @@ +import UIKit + +@main +final class AppDelegate: UIResponder, UIApplicationDelegate { + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + // Override point for customization after application launch. + print("lala") + return true + } + + // MARK: UISceneSession Lifecycle + func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { + let sceneConfig: UISceneConfiguration = UISceneConfiguration(name: nil, sessionRole: connectingSceneSession.role) + sceneConfig.delegateClass = SceneDelegate.self + return sceneConfig + } + + func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {} +} diff --git a/Example/ChatWallet/ApplicationLayer/Application.swift b/Example/ChatWallet/ApplicationLayer/Application.swift new file mode 100644 index 000000000..292062b5f --- /dev/null +++ b/Example/ChatWallet/ApplicationLayer/Application.swift @@ -0,0 +1,16 @@ +import Foundation +import WalletConnectChat + +final class Application { + lazy var chatService: ChatService = { + return ChatService(client: Chat.instance) + }() + + lazy var accountStorage: AccountStorage = { + return AccountStorage(defaults: .standard) + }() + + lazy var registerService: RegisterService = { + return RegisterService(chatService: chatService) + }() +} diff --git a/Example/ChatWallet/ApplicationLayer/Configurator/AppearanceConfigurator.swift b/Example/ChatWallet/ApplicationLayer/Configurator/AppearanceConfigurator.swift new file mode 100644 index 000000000..5ad69dfb5 --- /dev/null +++ b/Example/ChatWallet/ApplicationLayer/Configurator/AppearanceConfigurator.swift @@ -0,0 +1,19 @@ +import UIKit + +struct AppearanceConfigurator: Configurator { + + func configure() { + let appearance = UINavigationBarAppearance() + appearance.backgroundColor = .w_background + appearance.shadowColor = .clear + appearance.titleTextAttributes = [ + .foregroundColor: UIColor.w_foreground + ] + + UINavigationBar.appearance().standardAppearance = appearance + UINavigationBar.appearance().scrollEdgeAppearance = appearance + UINavigationBar.appearance().compactAppearance = appearance + + UIApplication.currentWindow.overrideUserInterfaceStyle = .dark + } +} diff --git a/Example/ChatWallet/ApplicationLayer/Configurator/ApplicationConfigurator.swift b/Example/ChatWallet/ApplicationLayer/Configurator/ApplicationConfigurator.swift new file mode 100644 index 000000000..980cb6783 --- /dev/null +++ b/Example/ChatWallet/ApplicationLayer/Configurator/ApplicationConfigurator.swift @@ -0,0 +1,16 @@ +import Combine + +struct ApplicationConfigurator: Configurator { + + private var publishers = Set() + + private let app: Application + + init(app: Application) { + self.app = app + } + + func configure() { + WalletModule.create(app: app).present() + } +} diff --git a/Example/ChatWallet/ApplicationLayer/Configurator/Configurator.swift b/Example/ChatWallet/ApplicationLayer/Configurator/Configurator.swift new file mode 100644 index 000000000..2eb6d30cb --- /dev/null +++ b/Example/ChatWallet/ApplicationLayer/Configurator/Configurator.swift @@ -0,0 +1,9 @@ +protocol Configurator { + func configure() +} + +extension Array where Element == Configurator { + func configure() { + forEach { $0.configure() } + } +} diff --git a/Example/ChatWallet/ApplicationLayer/Configurator/MigrationConfigurator.swift b/Example/ChatWallet/ApplicationLayer/Configurator/MigrationConfigurator.swift new file mode 100644 index 000000000..db8d18c9e --- /dev/null +++ b/Example/ChatWallet/ApplicationLayer/Configurator/MigrationConfigurator.swift @@ -0,0 +1,9 @@ +struct MigrationConfigurator: Configurator { + let app: Application + + init(app: Application) { + self.app = app + } + + func configure() {} +} diff --git a/Example/ChatWallet/ApplicationLayer/Configurator/ThirdPartyConfigurator.swift b/Example/ChatWallet/ApplicationLayer/Configurator/ThirdPartyConfigurator.swift new file mode 100644 index 000000000..a8936517a --- /dev/null +++ b/Example/ChatWallet/ApplicationLayer/Configurator/ThirdPartyConfigurator.swift @@ -0,0 +1,21 @@ +import WalletConnectNetworking +import WalletConnectPairing +import Auth + +struct ThirdPartyConfigurator: Configurator { + + func configure() { + Networking.configure(projectId: InputConfig.projectId, socketFactory: SocketFactory()) + Pair.configure( + metadata: AppMetadata( + name: "Showcase App", + description: "Showcase description", + url: "example.wallet", + icons: ["https://avatars.githubusercontent.com/u/37784886"] + )) + + Auth.configure( + account: Account("eip155:1:0xe5EeF1368781911d265fDB6946613dA61915a501")! + ) + } +} diff --git a/Example/ChatWallet/ApplicationLayer/SceneDelegate.swift b/Example/ChatWallet/ApplicationLayer/SceneDelegate.swift new file mode 100644 index 000000000..f05da13c4 --- /dev/null +++ b/Example/ChatWallet/ApplicationLayer/SceneDelegate.swift @@ -0,0 +1,43 @@ +import UIKit +import Auth +import WalletConnectPairing + +final class SceneDelegate: UIResponder, UIWindowSceneDelegate { + var window: UIWindow? + + private let app = Application() + + private var configurators: [Configurator] { + return [ + MigrationConfigurator(app: app), + ThirdPartyConfigurator(), + ApplicationConfigurator(app: app), + AppearanceConfigurator() + ] + } + + func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { + let sceneConfig: UISceneConfiguration = UISceneConfiguration(name: nil, sessionRole: connectingSceneSession.role) + sceneConfig.delegateClass = SceneDelegate.self + return sceneConfig + } + + func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { + guard let windowScene = (scene as? UIWindowScene) else { return } + + window = UIWindow(windowScene: windowScene) + window?.makeKeyAndVisible() + + print("Lolo") + configurators.configure() + } + + func scene(_ scene: UIScene, openURLContexts URLContexts: Set) { + guard let context = URLContexts.first else { return } + + let uri = context.url.absoluteString.replacingOccurrences(of: "showcase://wc?uri=", with: "") + Task { + try await Pair.instance.pair(uri: WalletConnectURI(string: uri)!) + } + } +} diff --git a/Example/ChatWallet/Common/Components/BrandButton.swift b/Example/ChatWallet/Common/Components/BrandButton.swift new file mode 100644 index 000000000..85c02f614 --- /dev/null +++ b/Example/ChatWallet/Common/Components/BrandButton.swift @@ -0,0 +1,20 @@ +import SwiftUI + +struct BrandButton: View { + let title: String + let action: () -> Void + + var body: some View { + Button(action: { action() }, label: { + Text(title) + .foregroundColor(.w_foreground) + .font(.system(size: 20, weight: .bold)) + }) + .frame(maxWidth: .infinity) + .frame(height: 56) + .background( + Capsule() + .foregroundColor(.w_greenForground) + ) + } +} diff --git a/Example/ChatWallet/Common/Components/InputView.swift b/Example/ChatWallet/Common/Components/InputView.swift new file mode 100644 index 000000000..059f9ac6a --- /dev/null +++ b/Example/ChatWallet/Common/Components/InputView.swift @@ -0,0 +1,28 @@ +import SwiftUI + +struct InputView: View { + + let title: String + let text: Binding + let action: () -> Void + + var body: some View { + ZStack { + TextField(title, text: text) + .disableAutocorrection(true) + .frame(minHeight: 44.0) + .padding(EdgeInsets(top: 0, leading: 16, bottom: 0, trailing: 16)) + .background( + Capsule() + .foregroundColor(.w_secondaryBackground) + ) + .overlay( + Capsule() + .stroke(Color.w_tertiaryBackground, lineWidth: 0.5) + ) + .onSubmit { + action() + } + } + } +} diff --git a/Example/ChatWallet/Common/Components/TextFieldView.swift b/Example/ChatWallet/Common/Components/TextFieldView.swift new file mode 100644 index 000000000..da266d34f --- /dev/null +++ b/Example/ChatWallet/Common/Components/TextFieldView.swift @@ -0,0 +1,50 @@ +import SwiftUI + +struct TextFieldView: View { + + let title: String + let placeholder: String + let input: Binding + + private var isClearVisible: Bool { + return input.wrappedValue.count > 0 + } + + var body: some View { + VStack(alignment: .leading) { + Text(title) + .font(.subheadline) + .foregroundColor(.w_secondaryForeground) + .padding(.horizontal, 16.0) + + HStack { + TextField(placeholder, text: input) + .font(.body) + .foregroundColor(.w_foreground) + .disableAutocorrection(true) + + if isClearVisible { + Button(action: { didPressClear() }) { + Image(systemName: "xmark.circle.fill") + .frame(width: 17.0, height: 17.0) + } + } + } + .padding(.horizontal, 16.0) + } + .frame(height: 72.0) + .background( + RoundedRectangle(cornerRadius: 14.0) + .foregroundColor(.w_secondaryBackground) + ) + .overlay( + RoundedRectangle(cornerRadius: 14.0) + .stroke(Color.w_tertiaryBackground, lineWidth: 0.5) + ) + .padding(16.0) + } + + private func didPressClear() { + input.wrappedValue = .empty + } +} diff --git a/Example/ChatWallet/Common/Extensions/SwiftUI/View.swift b/Example/ChatWallet/Common/Extensions/SwiftUI/View.swift new file mode 100644 index 000000000..eb830798d --- /dev/null +++ b/Example/ChatWallet/Common/Extensions/SwiftUI/View.swift @@ -0,0 +1,17 @@ +import SwiftUI + +extension View { + func cornerRadius(_ radius: CGFloat, corners: UIRectCorner) -> some View { + clipShape( RoundedCorner(radius: radius, corners: corners) ) + } +} + +struct RoundedCorner: Shape { + let radius: CGFloat + let corners: UIRectCorner + + func path(in rect: CGRect) -> Path { + let path = UIBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius)) + return Path(path.cgPath) + } +} diff --git a/Example/ChatWallet/Common/Extensions/UIKit/String.swift b/Example/ChatWallet/Common/Extensions/UIKit/String.swift new file mode 100644 index 000000000..32161cd7a --- /dev/null +++ b/Example/ChatWallet/Common/Extensions/UIKit/String.swift @@ -0,0 +1,8 @@ +import Foundation + +extension String { + + static var empty: String { + return "" + } +} diff --git a/Example/ChatWallet/Common/Extensions/UIKit/UIColor.swift b/Example/ChatWallet/Common/Extensions/UIKit/UIColor.swift new file mode 100644 index 000000000..1f175e66e --- /dev/null +++ b/Example/ChatWallet/Common/Extensions/UIKit/UIColor.swift @@ -0,0 +1,20 @@ +import UIKit + +extension UIColor { + + convenience init(red: Int, green: Int, blue: Int) { + assert(red >= 0 && red <= 255, "Invalid red component") + assert(green >= 0 && green <= 255, "Invalid green component") + assert(blue >= 0 && blue <= 255, "Invalid blue component") + + self.init(red: CGFloat(red) / 255.0, green: CGFloat(green) / 255.0, blue: CGFloat(blue) / 255.0, alpha: 1.0) + } + + convenience init(rgb: Int) { + self.init( + red: (rgb >> 16) & 0xFF, + green: (rgb >> 8) & 0xFF, + blue: rgb & 0xFF + ) + } +} diff --git a/Example/ChatWallet/Common/Extensions/UIKit/UIViewController.swift b/Example/ChatWallet/Common/Extensions/UIKit/UIViewController.swift new file mode 100644 index 000000000..288355439 --- /dev/null +++ b/Example/ChatWallet/Common/Extensions/UIKit/UIViewController.swift @@ -0,0 +1,51 @@ +import UIKit +import SwiftUI +import StoreKit + +extension UIViewController { + var topController: UIViewController { + var topController = self + while let presentedViewController = topController.presentedViewController { + topController = presentedViewController + } + return topController + } + + func present() { + UIApplication.currentWindow.rootViewController = self + } + + func push(from viewController: UIViewController) { + viewController.navigationController?.pushViewController(self, animated: true) + } + + func present(from viewController: UIViewController) { + viewController.present(self, animated: true, completion: nil) + } + + func pop() { + _ = navigationController?.popViewController(animated: true) + } + + func dismiss() { + dismiss(animated: true, completion: nil) + } + + func popToRoot() { + navigationController?.popToRootViewController(animated: true) + } + + func wrapToNavigationController() -> UINavigationController { + let navigationController = UINavigationController(rootViewController: self) + navigationController.navigationBar.prefersLargeTitles = true + return navigationController + } +} + +extension UIApplication { + static var currentWindow: UIWindow { + return UIApplication.shared.connectedScenes + .compactMap { $0.delegate as? SceneDelegate } + .first!.window! + } +} diff --git a/Example/ChatWallet/Common/Helpers/UIPasteboardWrapper.swift b/Example/ChatWallet/Common/Helpers/UIPasteboardWrapper.swift new file mode 100644 index 000000000..decdc722f --- /dev/null +++ b/Example/ChatWallet/Common/Helpers/UIPasteboardWrapper.swift @@ -0,0 +1,15 @@ +// +// UIPasteboardWrapper.swift +// ChatWallet +// +// Created by Alexander Lisovyk on 06.12.22. +// + +import Foundation +import UIKit + +struct UIPasteboardWrapper { + static var string: String? { + UIPasteboard.general.string + } +} diff --git a/Example/ChatWallet/Common/InputConfig.swift b/Example/ChatWallet/Common/InputConfig.swift new file mode 100644 index 000000000..53931721a --- /dev/null +++ b/Example/ChatWallet/Common/InputConfig.swift @@ -0,0 +1,12 @@ +import Foundation + +struct InputConfig { + + static var projectId: String { + return config(for: "PROJECT_ID")! + } + + private static func config(for key: String) -> String? { + return Bundle.main.object(forInfoDictionaryKey: key) as? String + } +} diff --git a/Example/ChatWallet/Common/Style/Color.swift b/Example/ChatWallet/Common/Style/Color.swift new file mode 100644 index 000000000..3e2ae042b --- /dev/null +++ b/Example/ChatWallet/Common/Style/Color.swift @@ -0,0 +1,32 @@ +import SwiftUI + +extension Color { + static let w_background: Color = Color(UIColor.w_background) + static let w_secondaryBackground: Color = Color(UIColor.w_secondaryBackground) + + static let w_tertiaryBackground: Color = Color(UIColor.w_tertiaryBackground) + + static let w_foreground: Color = Color(UIColor.w_foreground) + static let w_secondaryForeground: Color = Color(UIColor.w_secondaryForeground) + + static let w_purpleBackground: Color = Color(UIColor.w_purpleBackground) + static let w_purpleForeground: Color = Color(UIColor.w_purpleForeground) + + static let w_greenBackground: Color = Color(UIColor.w_greenBackground) + static let w_greenForground: Color = Color(UIColor.w_greenForground) +} + +extension UIColor { + static let w_background: UIColor = UIColor(rgb: 0x141414) + static let w_secondaryBackground: UIColor = UIColor(rgb: 0x272A2A) + static let w_tertiaryBackground: UIColor = UIColor(rgb: 0x3B4040) + + static let w_foreground: UIColor = UIColor.label + static let w_secondaryForeground: UIColor = UIColor(rgb: 0x9EA9A9) + + static let w_purpleBackground: UIColor = UIColor(rgb: 0x794CFF) + static let w_purpleForeground: UIColor = UIColor(rgb: 0x987DE8) + + static let w_greenBackground: UIColor = UIColor(rgb: 0x1B3229) + static let w_greenForground: UIColor = UIColor(rgb: 0x2BEE6C) +} diff --git a/Example/ChatWallet/Common/Types/Types.swift b/Example/ChatWallet/Common/Types/Types.swift new file mode 100644 index 000000000..3df10ee8a --- /dev/null +++ b/Example/ChatWallet/Common/Types/Types.swift @@ -0,0 +1,3 @@ +import WalletConnectUtils + +typealias Account = WalletConnectUtils.Account diff --git a/Example/ChatWallet/Common/VIPER/SceneViewController.swift b/Example/ChatWallet/Common/VIPER/SceneViewController.swift new file mode 100644 index 000000000..0c990baf7 --- /dev/null +++ b/Example/ChatWallet/Common/VIPER/SceneViewController.swift @@ -0,0 +1,87 @@ +import SwiftUI + +enum NavigationBarStyle { + case translucent(UIColor) +} + +protocol SceneViewModel { + var sceneTitle: String? { get } + var largeTitleDisplayMode: UINavigationItem.LargeTitleDisplayMode { get } + var leftBarButtonItem: UIBarButtonItem? { get } + var rightBarButtonItem: UIBarButtonItem? { get } + var navigationBarStyle: NavigationBarStyle { get } + var preferredStatusBarStyle: UIStatusBarStyle { get } + var isNavigationBarTranslucent: Bool { get } + +} + +extension SceneViewModel { + var sceneTitle: String? { + return nil + } + var largeTitleDisplayMode: UINavigationItem.LargeTitleDisplayMode { + return .never + } + var leftBarButtonItem: UIBarButtonItem? { + return .none + } + var rightBarButtonItem: UIBarButtonItem? { + return .none + } + var navigationBarStyle: NavigationBarStyle { + return .translucent(.w_background) + } + var preferredStatusBarStyle: UIStatusBarStyle { + return .default + } + var isNavigationBarTranslucent: Bool { + return true + } +} + +class SceneViewController: UIHostingController { + private let viewModel: ViewModel + + init(viewModel: ViewModel, content: Content) { + self.viewModel = viewModel + super.init(rootView: content) + } + + override var preferredStatusBarStyle: UIStatusBarStyle { + return viewModel.preferredStatusBarStyle + } + + override func viewDidLoad() { + super.viewDidLoad() + setupView() + setupNavigation() + setupNavigationBarStyle() + } + + @objc required dynamic init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +// MARK: Privates +private extension SceneViewController { + func setupView() { + view.backgroundColor = .w_background + } + + func setupNavigation() { + navigationItem.title = viewModel.sceneTitle + navigationItem.backButtonTitle = .empty + navigationItem.largeTitleDisplayMode = viewModel.largeTitleDisplayMode + navigationItem.rightBarButtonItem = viewModel.rightBarButtonItem + navigationItem.leftBarButtonItem = viewModel.leftBarButtonItem + } + + func setupNavigationBarStyle() { + switch viewModel.navigationBarStyle { + case .translucent(let color): + navigationController?.navigationBar.barTintColor = color + navigationController?.navigationBar.isTranslucent = true + } + } +} diff --git a/Example/ChatWallet/DomainLayer/AccountStorage/AccountStorage.swift b/Example/ChatWallet/DomainLayer/AccountStorage/AccountStorage.swift new file mode 100644 index 000000000..ab86a093a --- /dev/null +++ b/Example/ChatWallet/DomainLayer/AccountStorage/AccountStorage.swift @@ -0,0 +1,21 @@ +import Foundation + +final class AccountStorage { + private let defaults: UserDefaults + + init(defaults: UserDefaults) { + self.defaults = defaults + } + + var account: Account? { + get { + guard let value = UserDefaults.standard.string(forKey: "account") else { + return nil + } + return Account(value) + } + set { + UserDefaults.standard.set(newValue?.absoluteString, forKey: "account") + } + } +} diff --git a/Example/ChatWallet/DomainLayer/Chat/AccountNameResolver.swift b/Example/ChatWallet/DomainLayer/Chat/AccountNameResolver.swift new file mode 100644 index 000000000..dc7ac4339 --- /dev/null +++ b/Example/ChatWallet/DomainLayer/Chat/AccountNameResolver.swift @@ -0,0 +1,23 @@ +import Foundation + +struct AccountNameResolver { + + private static var staticMap: [String: String] = [ + "swift.eth": "eip155:1:0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb", + "kotlin.eth": "eip155:2:0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb", + "js.eth": "eip155:3:0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb" + ] + + static func resolveName(_ account: Account) -> String { + return staticMap + .first(where: { $0.value == account.absoluteString })?.key ?? account.absoluteString + } + + static func resolveAccount(_ input: String) -> Account? { + guard let value = staticMap[input.lowercased()] else { + return Account(input) + } + + return Account(value)! + } +} diff --git a/Example/ChatWallet/DomainLayer/Chat/ChatService.swift b/Example/ChatWallet/DomainLayer/Chat/ChatService.swift new file mode 100644 index 000000000..991c06c66 --- /dev/null +++ b/Example/ChatWallet/DomainLayer/Chat/ChatService.swift @@ -0,0 +1,67 @@ +import Foundation +import Combine +import WalletConnectChat +import WalletConnectRelay + +typealias Stream = AsyncPublisher> + +final class ChatService { + + private let client: ChatClient + + init(client: ChatClient) { + self.client = client + } + + var connectionPublisher: Stream { + return client.socketConnectionStatusPublisher.values + } + + var messagePublisher: Stream { + return client.messagePublisher.values + } + + var threadPublisher: Stream { + return client.newThreadPublisher.values + } + + var invitePublisher: Stream { + return client.invitePublisher.values + } + + func getMessages(thread: WalletConnectChat.Thread) async -> [WalletConnectChat.Message] { + await client.getMessages(topic: thread.topic) + } + + func getThreads() async -> [WalletConnectChat.Thread] { + await client.getThreads() + } + + func getInvites(account: Account) async -> [WalletConnectChat.Invite] { + client.getInvites(account: account) + } + + func sendMessage(topic: String, message: String) async throws { + try await client.message(topic: topic, message: message) + } + + func accept(invite: Invite) async throws { + try await client.accept(inviteId: invite.id) + } + + func reject(invite: Invite) async throws { + try await client.reject(inviteId: invite.id) + } + + func invite(peerAccount: Account, message: String, selfAccount: Account) async throws { + try await client.invite(peerAccount: peerAccount, openingMessage: message, account: selfAccount) + } + + func register(account: Account) async throws { + _ = try await client.register(account: account) + } + + func resolve(account: Account) async throws -> String { + return try await client.resolve(account: account) + } +} diff --git a/Example/ChatWallet/DomainLayer/Chat/RegisterService.swift b/Example/ChatWallet/DomainLayer/Chat/RegisterService.swift new file mode 100644 index 000000000..881c94b28 --- /dev/null +++ b/Example/ChatWallet/DomainLayer/Chat/RegisterService.swift @@ -0,0 +1,15 @@ +import Foundation + +final class RegisterService { + + private let chatService: ChatService + + init(chatService: ChatService) { + self.chatService = chatService + } + + func register(account: Account) async { + try! await chatService.register(account: account) + print("Account: \(account.absoluteString) registered") + } +} diff --git a/Example/ChatWallet/DomainLayer/SocketFactory/SocketFactory.swift b/Example/ChatWallet/DomainLayer/SocketFactory/SocketFactory.swift new file mode 100644 index 000000000..d22a5ef48 --- /dev/null +++ b/Example/ChatWallet/DomainLayer/SocketFactory/SocketFactory.swift @@ -0,0 +1,11 @@ +import Foundation +import Starscream +import WalletConnectRelay + +extension WebSocket: WebSocketConnecting { } + +struct SocketFactory: WebSocketFactory { + func create(with url: URL) -> WebSocketConnecting { + return WebSocket(url: url) + } +} diff --git a/Example/ChatWallet/Other/Assets.xcassets/AccentColor.colorset/Contents.json b/Example/ChatWallet/Other/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 000000000..eb8789700 --- /dev/null +++ b/Example/ChatWallet/Other/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Contents.json b/Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..78d34c2c3 --- /dev/null +++ b/Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,116 @@ +{ + "images" : [ + { + "filename" : "Icon-App-20x20@2x.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "filename" : "Icon-App-20x20@3x.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "filename" : "Icon-App-29x29@2x.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "filename" : "Icon-App-29x29@3x.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "filename" : "Icon-App-40x40@2x.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "filename" : "Icon-App-40x40@3x.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "filename" : "Icon-App-60x60@2x.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "filename" : "Icon-App-60x60@3x.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "filename" : "Icon-App-20x20@1x.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "20x20" + }, + { + "filename" : "Icon-App-20x20@2x-1.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "20x20" + }, + { + "filename" : "Icon-App-29x29@1x.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "29x29" + }, + { + "filename" : "Icon-App-29x29@2x-1.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "29x29" + }, + { + "filename" : "Icon-App-40x40@1x.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "40x40" + }, + { + "filename" : "Icon-App-40x40@2x-1.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "40x40" + }, + { + "filename" : "Icon-App-76x76@1x.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "76x76" + }, + { + "filename" : "Icon-App-76x76@2x.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "76x76" + }, + { + "filename" : "Icon-App-83.5x83.5@2x.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "filename" : "ItunesArtwork@2x.png", + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..e8b3b928c6cbe31cb3bd7f8e321c0430cfab8603 GIT binary patch literal 909 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 A0ssI2 literal 0 HcmV?d00001 diff --git a/Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..7f3a702c374a8efe35d793c31a205cffb1b42ecf GIT binary patch literal 1706 zcmV;b237fqP)4Tx0C=2ZU|>>7EGWofVPIg$%_}Jia(7aQh>TKTf5^ZNguD!53<`H2BL+u3tZkNpBf}F%kg#cp$t|bGMq*j!GXy^Qb%A(Blj1mP$U?`<3c;+SR z=_nW(7@9LMfWjQ2`g0&SEE&blAjF#QGcefh|NsC0ZiJZEeg=k(K%HDW5n>t^3=D$Y z3=AiB79!vFuj7ybYLcQH`&9R`L2c>on5W$tWJ|6>3E1rJF?K~#90?U-ALl~ojgzrD|# zxtrrSHboD4874&vi%_EnNmDVEf*^`OdWaycL;~%GgGLu261x~a1Yt-KM0v~W7(!l) z90VO3#u+uKM(3vEoS8Z2?7eze|3Bx9GpD&6p@LZtKj+_$4CDi7n+2>HNhNUtku;0l zNobBiXIxbkNgAwMVcoT19FJSYMfHPji09~*?j7lgWIp{)zzPRHd&U|a!ImKo+u zG(0ldP?Vbr1v3oLA$!nEu$92KXN0Y%JQv!uEk6gMkyO7INI3PZ7nnE>mfdf8a=PiK z>y`jYu ze{{g=y^hmOP*$MZb*%?-EL4=jJrfM&MLM>r6MnlY)VD&?!`M7MBrRQVZ#isO7~!tl z0)Rmv2aQ255V7#(DbMlWVM?ib>_!~sOfoE+VVH5JA#zhjbslQ|6t>m~hZ}|BTqrMw zqnBWNt!Kq-i}QmYoQxh63DQWAB3fdwW}oN8WuYhvs~)yIeP2qu6NLg@P`cr-PYWB5 zcskkc`&-mULRH!ySvDk8G2#>=)E-=}RLm{8aCZne?ani(>u zuQ%1z4Xvkd`K#*Dd|xSK-5-bdTfC^4tTax6hhX)$u_H zw0FbGU7n+tgr6@vHZ6`YxwQZ3?v24P5EBlb`pR*!9mA_(9E zfX{ysHXZYfD^MM6UGU07mggTdy^AuW=C*dh%R4=1t_Tx~pt%$7E`e{Ji4cthU;$6> z*)xF$qZXc>VX+3f5?T??UJ;h>a5Tr%fb%*wVqwck&!%IZlKfzm0wwwI(J{}Klb(px zvEhkrj=}OBj#-^W_ey2Ee@%OdD`a_<=s8)&gE~pp}pDc|~UaVs` zpYVKkLJb)MH+r^|rD^tdp-P?a{vG=%{CP$!fXDr8FxR?Idmo@!aO z+tJXfaB&CS30ODJvSey1UT>C+c`%%?w@!HLpeHY)p6pD(ZF!ogqgE?POAO{$7(Q5J zF~F;PJO}C(KItLhp*R<=_h@-cIOuWk_M?_Xm6_rG5fD^)j)epD!W;WN(Eu{xG@c>> z+@eaudkbuz%fjpXJ$vdD(s?}~;oO9ScNbXZSD0QKnPkvf94a`}AiTEElVjC$#wgs9 zsfKsvTaBHxE42u`dBC&loI;AICzBrDUuc;-d2qNP0j5J9ZWPw+^H`%>{P;A(`gth} zVSuM=TwCqgUaPg(3v5_unKNlt=H{dv zx#;`o8j1|-${$`d|LTD9F{#{{snCag0yK5N9b<-fS%ndNlML5DwsVL5U2IL?7#pg{ z2p2Y@5BK4G^kg#!{s;doi~?pWqk!4UC}6hoH~csBNPfMn>Hq)$07*qoM6N<$f}02$ A0ssI2 literal 0 HcmV?d00001 diff --git a/Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..d38db763f8541059b36d84eb9c4844a1a9ca89da GIT binary patch literal 2303 zcmV4Tx0C=2ZU|>>7EGWofVPIg$%_}Jia(7aQh>TKTf5^ZNguD!53<`H2BL+u3tZkNpBf}F%kg#cp$t|bGMq*j!GXy^Qb%A(Blj1mP$U?`<3c;+SR z=_nW(7@9LMfWjQ2`g0&SEE&blAjF#QGcefh|NsC0ZiJZEeg=k(K%HDW5n>t^3=D$Y z3=AiB79!vFuj7ybYLcQH`&9R`L2c>on5W$tWJ|6>3E2V_Y^K~#90?V5jZRMi#7KlkqD zCkc%Ntr!cn6hY|^3$ZPwPQik^6?z^XdocDI$ZgxqsyI5!4Gm~WZy?ytd z&pqdU&v|cSL`3)inf-q|@LpR5xZJG*T<%r@E_bT{m%CMf%iSu#=C+ckA@bEYsJ0l!>2L^_O!5EAt^;}&P zn(JY1lVQYoI7r>V!GHWm*x4r>Iwib40&!2%)%vN6|9K~RZFK~$ zXn@wM3~Lq|KK~K@kdxA;dP#u8k?0u^b{rOtoDw{N+Ni>WAu}8Z9gll3mV}6bC07~N zE;THhYbMN5j1>*+i8?qu4qLk&&%UO^&8XI>1Q7&Zu(F(%tn=3B`wMYBcE@#wdzV`p zYtnNSV?_Z64)hNS_wRD_4?67uK{NdH zR?C8BQ*@*Y1`Z}ZdRn-r(=i-}hH3=@KU!8(bTpx9-CPfs*F!^%dOR{NoQc6;Ow+lp zO1FS>>8M97jKra_8amo6H_Ryxx**^{NRFNo?(THNJ*bI-=fg$}B%G$@ye9bae8cj2 zhWWD$m(^vCb#4@npB1`K2!A;)oEXyWP-QiP03sH~lbQ*?xZU!pD+`A%s4N9)+&>6! zjlk72H9~=NBjfO)TKN8FEnmMrv(yCFgD%=-bvubL^$WF8cyOg=OEzqma?i9dNw)uBvIo=C7OK z;TvwUYse&~$M3Bf+H-|^cQ zg)19X)PB6%;fZCv1&IW|pO)F}Qn~<$J9PZF7iRFt?z7ZT_p{_b;h}2ciX94m;W`E3U~8J?$qRo`YHS z@YGAf!~0yS_sw25@fR*);qhLV0UO--i)bslt;g|ruS^Pj6dV!h;ZD??x9C#4u!`h`<2|%yi(B=5kv5Bxrr#<`T zTP&;Qo0P8?vne$m!9e@o5bl3o_gXgeJ27ax*6_ee%M-nh-yBf~vtftFNoB*vE=Oa{ zMCid7e0Paq-Hnz_`y8FGYZ_<6dQKail^>fL?397S(EI-_-1of07`>wj-`mC#&@vNF z4{Ng@R$~#kkbn&jTD8>6k|oJKf#9_p(y=SevI>?2>X-1O0@ z!%hnr()IMffbhdVJ4E!BE$mF((_`7Nu>`c=Y`Nn)lZsT-!n3cb@YUylPI#L38L*z7 z``K45Uzj_!?y6v5NJskMo5H<29iGc{D(rO75051@joTJxMk9FL*(Yr5a@1ClQt4b{ z#XW`Fy2kRktEU&)f`K6&=|d;AF-bV6iKLY{1)Hs)Iie99%U20N7h&AfE!5FwX>FN) zWQzh0JNn{j;Rnw-#yqHvK+-P@(^1fTmB15-8d78b{5H#H<`fQF6mS^&pKl3wJ?9ur z=;N8O$9%yx9OvuVql>Zk7<1eUU^%g|2v`&+_n^;py5jJ zqg{^Sarkh9!Y;m|cvt|W1eWylZ{Haw>z?tXXTW6~FJ!Eq0UfLFOyOhYvXXt(lHI=+ z^W3SFV`W=OzddwWD*b*LD{PnS>(ckDec=8BpaNX(Rsk+|s{og~Re;OgD!}D#72tBW Z{{c7J0-wbL?PUM}002ovPDHLkV1gH9Sxx`| literal 0 HcmV?d00001 diff --git a/Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..941819fce212f20c523916380fea9450f0576883 GIT binary patch literal 1247 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 A0ssI2 literal 0 HcmV?d00001 diff --git a/Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x-1.png b/Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x-1.png new file mode 100644 index 0000000000000000000000000000000000000000..5c06655825fc02dee4eeb2e3e3a262f5c5f6d772 GIT binary patch literal 3211 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 literal 0 HcmV?d00001 diff --git a/Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..0fdab5f9586ace7626a8e31c96c5a47240c2912c GIT binary patch literal 4313 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 literal 0 HcmV?d00001 diff --git a/Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..3b88e179c7f015f579ade8b2e29ec59cf5f9f287 GIT binary patch literal 6262 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 z zI?d@jKyE!`s;*^x-9xGzwsi6g_qvv<_QC3KY9yCOI!#G*hICepQ&>gaG0p|V1K6%=)aRzI;H>M&6U>)p&@z2&29 z_t@=^M0?bP(>E>6!e)pw!FgYKDnK=Uw`)4Crh4h_{?R2K0T4_g8Ls*!JS{v&(5~Mu zUU+&a^c=Y#l(w!(9@HB?y{I^+dquxN#-^()t|joyp!I>Nao z>H3#+s-j~mU0SVQ9`ef{QoC=?$cp9fyb!##pBED`?l&Q7>bbAp*8aN4`aulGsDA9j ztJH4+(7A>Z=~!HTKa&+?;k)}cf%|}KnGKtd!E^l|e(K0-ePjd7gM5XXbQ|}Nd^iAR LYHd<)gu?#^lZ&uu literal 0 HcmV?d00001 diff --git a/Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..03bb3d0210da26a6704db58fcae0cce08b92ba02 GIT binary patch literal 5312 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 S63sm)kE5=vqg1b83;iDjP5l%A literal 0 HcmV?d00001 diff --git a/Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png b/Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..f527fe6244244e39e804a088c941e39ce3327f07 GIT binary patch literal 39006 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 literal 0 HcmV?d00001 diff --git a/Example/ChatWallet/Other/Assets.xcassets/Contents.json b/Example/ChatWallet/Other/Assets.xcassets/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/Example/ChatWallet/Other/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Example/ChatWallet/Other/Info.plist b/Example/ChatWallet/Other/Info.plist new file mode 100644 index 000000000..7bd0b9cde --- /dev/null +++ b/Example/ChatWallet/Other/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleIconName + AppIcon + CFBundleURLTypes + + + CFBundleTypeRole + Editor + CFBundleURLSchemes + + showcase + + + + ITSAppUsesNonExemptEncryption + + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + + PROJECT_ID + $(PROJECT_ID) + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + + + + + + diff --git a/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestInteractor.swift b/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestInteractor.swift new file mode 100644 index 000000000..c0c3a8bd3 --- /dev/null +++ b/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestInteractor.swift @@ -0,0 +1,17 @@ +import Foundation +import Auth +import WalletConnectUtils + +final class AuthRequestInteractor { + + func approve(request: AuthRequest) async throws { + let privateKey = Data(hex: "e56da0e170b5e09a8bb8f1b693392c7d56c3739a9c75740fbc558a2877868540") + let signer = MessageSignerFactory.create() + let signature = try signer.sign(message: request.message, privateKey: privateKey, type: .eip191) + try await Auth.instance.respond(requestId: request.id, signature: signature) + } + + func reject(request: AuthRequest) async throws { + try await Auth.instance.reject(requestId: request.id) + } +} diff --git a/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestModule.swift b/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestModule.swift new file mode 100644 index 000000000..230e05bbc --- /dev/null +++ b/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestModule.swift @@ -0,0 +1,19 @@ +import SwiftUI +import Auth + +final class AuthRequestModule { + + @discardableResult + static func create(app: Application, request: AuthRequest) -> UIViewController { + let router = AuthRequestRouter(app: app) + let interactor = AuthRequestInteractor() + let presenter = AuthRequestPresenter(request: request, interactor: interactor, router: router) + let view = AuthRequestView().environmentObject(presenter) + let viewController = SceneViewController(viewModel: presenter, content: view) + + router.viewController = viewController + + return viewController + } + +} diff --git a/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestPresenter.swift b/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestPresenter.swift new file mode 100644 index 000000000..f70700e86 --- /dev/null +++ b/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestPresenter.swift @@ -0,0 +1,56 @@ +import UIKit +import Combine +import Auth + +final class AuthRequestPresenter: ObservableObject { + + private let request: AuthRequest + private let interactor: AuthRequestInteractor + private let router: AuthRequestRouter + private var disposeBag = Set() + + init(request: AuthRequest, interactor: AuthRequestInteractor, router: AuthRequestRouter) { + defer { setupInitialState() } + self.request = request + self.interactor = interactor + self.router = router + } + + var message: String { + return request.message + } + + @MainActor + func approvePressed() async throws { + try await interactor.approve(request: request) + router.dismiss() + } + + @MainActor + func rejectPressed() async throws { + try await interactor.reject(request: request) + router.dismiss() + } +} + +// MARK: SceneViewModel + +extension AuthRequestPresenter: SceneViewModel { + + var sceneTitle: String? { + return "Auth Request" + } + + var largeTitleDisplayMode: UINavigationItem.LargeTitleDisplayMode { + return .always + } +} + +// MARK: Privates + +private extension AuthRequestPresenter { + + func setupInitialState() { + + } +} diff --git a/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestRouter.swift b/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestRouter.swift new file mode 100644 index 000000000..53d3d684e --- /dev/null +++ b/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestRouter.swift @@ -0,0 +1,16 @@ +import UIKit + +final class AuthRequestRouter { + + weak var viewController: UIViewController! + + private let app: Application + + init(app: Application) { + self.app = app + } + + func dismiss() { + viewController.navigationController?.dismiss() + } +} diff --git a/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestView.swift b/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestView.swift new file mode 100644 index 000000000..c8443c337 --- /dev/null +++ b/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestView.swift @@ -0,0 +1,54 @@ +import SwiftUI + +struct AuthRequestView: View { + + @EnvironmentObject var presenter: AuthRequestPresenter + + var body: some View { + VStack(spacing: 16.0) { + HStack { + Text("Message to sign:") + Spacer() + } + + VStack { + Text(presenter.message) + .font(Font.system(size: 13)) + .padding(16.0) + } + .background(Color.white.opacity(0.1)) + .cornerRadius(10) + + HStack(spacing: 16.0) { + Button(action: { Task(priority: .userInitiated) { try await presenter.rejectPressed() }}, label: { + HStack(spacing: 8.0) { + Text("Reject") + .foregroundColor(.w_foreground) + .font(.system(size: 18, weight: .semibold)) + } + }) + .frame(width: 120, height: 44) + .background( + Capsule() + .foregroundColor(.w_purpleForeground) + ) + + Button(action: { Task(priority: .userInitiated) { try await presenter.approvePressed() }}, label: { + HStack(spacing: 8.0) { + Text("Approve") + .foregroundColor(.w_foreground) + .font(.system(size: 18, weight: .semibold)) + } + }) + .frame(width: 120, height: 44) + .background( + Capsule() + .foregroundColor(.w_greenForground) + ) + } + + Spacer() + } + .padding(16.0) + } +} diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanInteractor.swift b/Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanInteractor.swift new file mode 100644 index 000000000..8585d6043 --- /dev/null +++ b/Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanInteractor.swift @@ -0,0 +1,3 @@ +final class ScanInteractor { + +} diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanModule.swift b/Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanModule.swift new file mode 100644 index 000000000..eac6302cd --- /dev/null +++ b/Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanModule.swift @@ -0,0 +1,22 @@ +import SwiftUI + +final class ScanModule { + + @discardableResult + static func create( + app: Application, + onValue: @escaping (String) -> Void, + onError: @escaping (Error) -> Void + ) -> UIViewController { + let router = ScanRouter(app: app) + let interactor = ScanInteractor() + let presenter = ScanPresenter(interactor: interactor, router: router, onValue: onValue, onError: onError) + let view = ScanView().environmentObject(presenter) + let viewController = SceneViewController(viewModel: presenter, content: view) + + router.viewController = viewController + + return viewController + } + +} diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanPresenter.swift b/Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanPresenter.swift new file mode 100644 index 000000000..f36c77456 --- /dev/null +++ b/Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanPresenter.swift @@ -0,0 +1,48 @@ +import UIKit +import Combine + +final class ScanPresenter: ObservableObject { + + private let interactor: ScanInteractor + private let router: ScanRouter + + private var disposeBag = Set() + + let onValue: (String) -> Void + let onError: (Error) -> Void + + init( + interactor: ScanInteractor, + router: ScanRouter, + onValue: @escaping (String) -> Void, + onError: @escaping (Error) -> Void + ) { + defer { setupInitialState() } + self.interactor = interactor + self.router = router + self.onValue = onValue + self.onError = onError + } +} + +// MARK: SceneViewModel + +extension ScanPresenter: SceneViewModel { + + var sceneTitle: String? { + return "Scan URI" + } + + var largeTitleDisplayMode: UINavigationItem.LargeTitleDisplayMode { + return .always + } +} + +// MARK: Privates + +private extension ScanPresenter { + + func setupInitialState() { + + } +} diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanRouter.swift b/Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanRouter.swift new file mode 100644 index 000000000..eef0df5c6 --- /dev/null +++ b/Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanRouter.swift @@ -0,0 +1,12 @@ +import UIKit + +final class ScanRouter { + + weak var viewController: UIViewController! + + private let app: Application + + init(app: Application) { + self.app = app + } +} diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanView.swift b/Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanView.swift new file mode 100644 index 000000000..f8f36e7bb --- /dev/null +++ b/Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanView.swift @@ -0,0 +1,19 @@ +import SwiftUI + +struct ScanView: View { + + @EnvironmentObject var presenter: ScanPresenter + + var body: some View { + ScanQR(onValue: presenter.onValue, onError: presenter.onError) + .ignoresSafeArea() + } +} + +#if DEBUG +struct ScanView_Previews: PreviewProvider { + static var previews: some View { + ScanView() + } +} +#endif diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Scan/Views/ScanQR.swift b/Example/ChatWallet/PresentationLayer/Wallet/Scan/Views/ScanQR.swift new file mode 100644 index 000000000..8b78b3098 --- /dev/null +++ b/Example/ChatWallet/PresentationLayer/Wallet/Scan/Views/ScanQR.swift @@ -0,0 +1,39 @@ +import SwiftUI + +struct ScanQR: UIViewRepresentable { + + class Coordinator: ScanQRViewDelegate { + private let onValue: (String) -> Void + private let onError: (Error) -> Void + + init(onValue: @escaping (String) -> Void, onError: @escaping (Error) -> Void) { + self.onValue = onValue + self.onError = onError + } + + func scanDidDetect(value: String) { + onValue(value) + } + + func scanDidFail(with error: Error) { + onError(error) + } + } + + let onValue: (String) -> Void + let onError: (Error) -> Void + + func makeUIView(context: Context) -> ScanQRView { + let view = ScanQRView() + view.delegate = context.coordinator + return view + } + + func updateUIView(_ uiView: ScanQRView, context: Context) { + + } + + func makeCoordinator() -> Coordinator { + return Coordinator(onValue: onValue, onError: onError) + } +} diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Scan/Views/ScanQRView.swift b/Example/ChatWallet/PresentationLayer/Wallet/Scan/Views/ScanQRView.swift new file mode 100644 index 000000000..08ce85b45 --- /dev/null +++ b/Example/ChatWallet/PresentationLayer/Wallet/Scan/Views/ScanQRView.swift @@ -0,0 +1,187 @@ +import UIKit +import AVFoundation + +protocol ScanQRViewDelegate: AnyObject { + func scanDidDetect(value: String) + func scanDidFail(with error: Error) +} + +final class ScanQRView: UIView { + enum Errors: Error { + case deviceNotFound + } + + weak var delegate: ScanQRViewDelegate? + + private let targetSize = CGSize( + width: UIScreen.main.bounds.width - 32.0, + height: UIScreen.main.bounds.width - 32.0 + ) + + private var videoPreviewLayer: AVCaptureVideoPreviewLayer? + private var captureSession: AVCaptureSession? + + private lazy var borderView: UIView = { + let borderView = ScanTargetView(radius: 24.0, color: .white, strokeWidth: 2.0, length: 36.0) + borderView.alpha = 0.85 + return borderView + }() + + private lazy var bluredView: UIView = { + let blurEffect = UIBlurEffect(style: .dark) + let bluredView = UIVisualEffectView(effect: blurEffect) + bluredView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + bluredView.layer.mask = createMaskLayer() + return bluredView + }() + + override init(frame: CGRect) { + super.init(frame: frame) + + setupView() + startCaptureSession() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func layoutSubviews() { + super.layoutSubviews() + + updateFrames() + updateOrientation() + } + + deinit { + stopCaptureSession() + } +} + +// MARK: AVCaptureMetadataOutputObjectsDelegate + +extension ScanQRView: AVCaptureMetadataOutputObjectsDelegate { + + func metadataOutput(_ metadataOutput: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) { + defer { stopCaptureSession() } + guard + let metadataObject = metadataObjects.first as? AVMetadataMachineReadableCodeObject, + let value = metadataObject.stringValue else { + return + } + delegate?.scanDidDetect(value: value) + } +} + +// MARK: Privates + +private extension ScanQRView { + + private func setupView() { + backgroundColor = .black + + addSubview(bluredView) + addSubview(borderView) + } + + private func createMaskLayer() -> CAShapeLayer { + let maskPath = UIBezierPath(rect: bounds) + let rect = UIBezierPath( + roundedRect: CGRect( + x: center.x - targetSize.height * 0.5, + y: center.y - targetSize.width * 0.5, + width: targetSize.width, + height: targetSize.height + ), + byRoundingCorners: .allCorners, + cornerRadii: CGSize(width: 24.0, height: 24.0) + ) + maskPath.append(rect) + maskPath.usesEvenOddFillRule = true + + let maskLayer = CAShapeLayer() + maskLayer.path = maskPath.cgPath + maskLayer.fillRule = .evenOdd + return maskLayer + } + + private func startCaptureSession() { + DispatchQueue.global().async { [weak self] in + guard let self = self else { return } + + do { + let session = try self.createCaptureSession() + session.startRunning() + self.captureSession = session + + DispatchQueue.main.async { self.setupVideoPreviewLayer(with: session) } + } catch { + DispatchQueue.main.async { self.delegate?.scanDidFail(with: error) } + } + } + } + + private func createCaptureSession() throws -> AVCaptureSession { + guard let captureDevice = AVCaptureDevice.default(for: .video) else { + throw Errors.deviceNotFound + } + + let input = try AVCaptureDeviceInput(device: captureDevice) + + let session = AVCaptureSession() + session.addInput(input) + + let captureMetadataOutput = AVCaptureMetadataOutput() + captureMetadataOutput.setMetadataObjectsDelegate(self, queue: .main) + session.addOutput(captureMetadataOutput) + + captureMetadataOutput.metadataObjectTypes = [.qr] + + return session + } + + private func stopCaptureSession() { + captureSession?.stopRunning() + captureSession = nil + } + + private func setupVideoPreviewLayer(with session: AVCaptureSession) { + let previewLayer = AVCaptureVideoPreviewLayer(session: session) + previewLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill + previewLayer.frame = layer.bounds + videoPreviewLayer = previewLayer + + layer.insertSublayer(previewLayer, at: 0) + } + + private func updateFrames() { + borderView.frame.size = targetSize + borderView.center = center + bluredView.frame = bounds + bluredView.layer.mask = createMaskLayer() + videoPreviewLayer?.frame = layer.bounds + } + + private func updateOrientation() { + guard let connection = videoPreviewLayer?.connection else { + return + } + let previewLayerConnection: AVCaptureConnection = connection + + guard previewLayerConnection.isVideoOrientationSupported else { + return + } + switch UIDevice.current.orientation { + case .portrait: return + previewLayerConnection.videoOrientation = .portrait + case .landscapeRight: + previewLayerConnection.videoOrientation = .landscapeLeft + case .landscapeLeft: return + previewLayerConnection.videoOrientation = .landscapeRight + case .portraitUpsideDown: + previewLayerConnection.videoOrientation = .portraitUpsideDown + default: + previewLayerConnection.videoOrientation = .portrait + } + } +} diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Scan/Views/ScanTargetView.swift b/Example/ChatWallet/PresentationLayer/Wallet/Scan/Views/ScanTargetView.swift new file mode 100644 index 000000000..99bbaaa3e --- /dev/null +++ b/Example/ChatWallet/PresentationLayer/Wallet/Scan/Views/ScanTargetView.swift @@ -0,0 +1,87 @@ +import UIKit + +final class ScanTargetView: UIView { + + private let radius: CGFloat + private let color: UIColor + private let strokeWidth: CGFloat + private let length: CGFloat + + private lazy var shapeLayer: CAShapeLayer = { + let shapeLayer = CAShapeLayer() + shapeLayer.strokeColor = color.cgColor + shapeLayer.fillColor = UIColor.clear.cgColor + shapeLayer.lineWidth = strokeWidth + return shapeLayer + }() + + init(radius: CGFloat, color: UIColor, strokeWidth: CGFloat, length: CGFloat) { + self.radius = radius + self.color = color + self.strokeWidth = strokeWidth + self.length = length + + super.init(frame: .zero) + + setupView() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func layoutSubviews() { + super.layoutSubviews() + shapeLayer.path = targetPath() + } + + private func setupView() { + backgroundColor = .clear + layer.addSublayer(shapeLayer) + } + + private func targetPath() -> CGPath { + let path = UIBezierPath() + path.append(createTopLeft()) + path.append(createTopRight()) + path.append(createBottomLeft()) + path.append(createBottomRight()) + return path.cgPath + } + + private func createTopLeft() -> UIBezierPath { + let topLeft = UIBezierPath() + topLeft.move(to: CGPoint(x: strokeWidth/2, y: radius+length)) + topLeft.addLine(to: CGPoint(x: strokeWidth/2, y: radius)) + topLeft.addQuadCurve(to: CGPoint(x: radius, y: strokeWidth/2), controlPoint: CGPoint(x: strokeWidth/2, y: strokeWidth/2)) + topLeft.addLine(to: CGPoint(x: radius+length, y: strokeWidth/2)) + return topLeft + } + + private func createTopRight() -> UIBezierPath { + let topRight = UIBezierPath() + topRight.move(to: CGPoint(x: frame.width-radius-length, y: strokeWidth/2)) + topRight.addLine(to: CGPoint(x: frame.width-radius, y: strokeWidth/2)) + topRight.addQuadCurve(to: CGPoint(x: frame.width-strokeWidth/2, y: radius), controlPoint: CGPoint(x: frame.width-strokeWidth/2, y: strokeWidth/2)) + topRight.addLine(to: CGPoint(x: frame.width-strokeWidth/2, y: radius+length)) + return topRight + } + + private func createBottomRight() -> UIBezierPath { + let bottomRight = UIBezierPath() + bottomRight.move(to: CGPoint(x: frame.width-strokeWidth/2, y: frame.height-radius-length)) + bottomRight.addLine(to: CGPoint(x: frame.width-strokeWidth/2, y: frame.height-radius)) + bottomRight.addQuadCurve(to: CGPoint(x: frame.width-radius, y: frame.height-strokeWidth/2), controlPoint: CGPoint(x: frame.width-strokeWidth/2, y: frame.height-strokeWidth/2)) + bottomRight.addLine(to: CGPoint(x: frame.width-radius-length, y: frame.height-strokeWidth/2)) + return bottomRight + } + + private func createBottomLeft() -> UIBezierPath { + let bottomLeft = UIBezierPath() + bottomLeft.move(to: CGPoint(x: radius+length, y: frame.height-strokeWidth/2)) + bottomLeft.addLine(to: CGPoint(x: radius, y: frame.height-strokeWidth/2)) + bottomLeft.addQuadCurve(to: CGPoint(x: strokeWidth/2, y: frame.height-radius), controlPoint: CGPoint(x: strokeWidth/2, y: frame.height-strokeWidth/2)) + bottomLeft.addLine(to: CGPoint(x: strokeWidth/2, y: frame.height-radius-length)) + return bottomLeft + } +} diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletInteractor.swift b/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletInteractor.swift new file mode 100644 index 000000000..c7973b7d4 --- /dev/null +++ b/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletInteractor.swift @@ -0,0 +1,67 @@ +import Combine +import Auth +import WalletConnectPairing + +protocol WalletInteractorProtocol { + func onAppear() + func pastePairingUri() async + func scanPairingUri() +} + +final class WalletInteractor: WalletInteractorProtocol { + private var disposeBag = Set() + + private weak var presenter: WalletPresenter? + private let router: WalletRouter + + private var requestPublisher: AnyPublisher { + return Auth.instance.authRequestPublisher + } + + init( + presenter: WalletPresenter, + router: WalletRouter + ) { + self.presenter = presenter + self.router = router + } + + func onAppear() { + requestPublisher.sink { [weak self] request in + self?.router.present(request: request) + }.store(in: &disposeBag) + } + + func pastePairingUri() async { + guard let string = UIPasteboardWrapper.string, + let uri = WalletConnectURI(string: string) + else { + return + } + try? await pair(uri: uri) + } + + func scanPairingUri() { + router.presentScan { [weak self] value in + guard let self, + let uri = WalletConnectURI(string: value) else { + return + } + + Task { + try? await self.pair(uri: uri) + } + self.router.dismiss() + } onError: { [weak self] error in + print(error.localizedDescription) + self?.router.dismiss() + } + } +} + +// MARK: - Private functions +extension WalletInteractor { + private func pair(uri: WalletConnectURI) async throws { + try await Pair.instance.pair(uri: uri) + } +} diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletModule.swift b/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletModule.swift new file mode 100644 index 000000000..420b03271 --- /dev/null +++ b/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletModule.swift @@ -0,0 +1,16 @@ +import SwiftUI + +final class WalletModule { + @discardableResult + static func create(app: Application) -> UIViewController { + let router = WalletRouter(app: app) + let presenter = WalletPresenter() + let interactor = WalletInteractor(presenter: presenter, router: router) + let view = WalletView(interactor: interactor, presenter: presenter) + let viewController = SceneViewController(viewModel: presenter, content: view) + + router.viewController = viewController + + return viewController + } +} diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletPresenter.swift b/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletPresenter.swift new file mode 100644 index 000000000..2122cac48 --- /dev/null +++ b/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletPresenter.swift @@ -0,0 +1,21 @@ +import UIKit +import Combine +import Auth + +final class WalletPresenter: ObservableObject { + private var disposeBag = Set() + + @Published var pastPairingUriText = "Paste pairing URI" + @Published var scanPairingUriText = "Scan pairing URI" +} + +// MARK: - SceneViewModel +extension WalletPresenter: SceneViewModel { + var sceneTitle: String? { + return "Wallet" + } + + var largeTitleDisplayMode: UINavigationItem.LargeTitleDisplayMode { + return .always + } +} diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletRouter.swift b/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletRouter.swift new file mode 100644 index 000000000..0935b5958 --- /dev/null +++ b/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletRouter.swift @@ -0,0 +1,28 @@ +import UIKit +import Auth + +final class WalletRouter { + weak var viewController: UIViewController! + + private let app: Application + + init(app: Application) { + self.app = app + } + + func present(request: AuthRequest) { + AuthRequestModule.create(app: app, request: request) + .wrapToNavigationController() + .present(from: viewController) + } + + func presentScan(onValue: @escaping (String) -> Void, onError: @escaping (Error) -> Void) { + ScanModule.create(app: app, onValue: onValue, onError: onError) + .wrapToNavigationController() + .present(from: viewController) + } + + func dismiss() { + viewController.navigationController?.dismiss() + } +} diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletView.swift b/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletView.swift new file mode 100644 index 000000000..a7a1ffe7e --- /dev/null +++ b/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletView.swift @@ -0,0 +1,65 @@ +import SwiftUI + +struct WalletView: View { + let interactor: WalletInteractorProtocol + @ObservedObject var presenter: WalletPresenter + + var body: some View { + VStack(spacing: 16) { + Button { + Task { + await interactor.pastePairingUri() + } + } label: { + HStack(spacing: 8.0) { + Text(presenter.pastPairingUriText) + .foregroundColor(.w_foreground) + .font(.system(size: 18, weight: .semibold)) + } + .padding(.trailing, 8.0) + } + .frame(width: 200, height: 44) + .background( + Capsule() + .foregroundColor(.w_greenForground) + ) + + Button { + interactor.scanPairingUri() + } label: { + HStack(spacing: 8.0) { + Text(presenter.scanPairingUriText) + .foregroundColor(.w_foreground) + .font(.system(size: 18, weight: .semibold)) + } + .padding(.trailing, 8.0) + } + .frame(width: 200, height: 44) + .background( + Capsule() + .foregroundColor(.w_purpleForeground) + ) + } + .onAppear { + interactor.onAppear() + } + } +} + +#if DEBUG +final class WalletInteractorMock: WalletInteractorProtocol { + func onAppear() {} + func pastePairingUri() async {} + func scanPairingUri() {} +} + +struct WalletView_Previews: PreviewProvider { + static var previews: some View { + let presenter = WalletPresenter() + WalletView( + interactor: WalletInteractorMock(), + presenter: presenter + ) + } +} +#endif diff --git a/Example/ExampleApp.xcodeproj/project.pbxproj b/Example/ExampleApp.xcodeproj/project.pbxproj index 6e5062005..76776cdb1 100644 --- a/Example/ExampleApp.xcodeproj/project.pbxproj +++ b/Example/ExampleApp.xcodeproj/project.pbxproj @@ -191,6 +191,53 @@ A5E22D222840C8D300E36487 /* WalletEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5E22D212840C8D300E36487 /* WalletEngine.swift */; }; A5E22D242840C8DB00E36487 /* SafariEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5E22D232840C8DB00E36487 /* SafariEngine.swift */; }; A5E22D2C2840EAC300E36487 /* XCUIElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5E22D2B2840EAC300E36487 /* XCUIElement.swift */; }; + C56EE222293F55EE004840D1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C56EE221293F55EE004840D1 /* Assets.xcassets */; }; + C56EE240293F566D004840D1 /* ScanQRView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE23F293F566C004840D1 /* ScanQRView.swift */; }; + C56EE241293F566D004840D1 /* WalletModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE22D293F5669004840D1 /* WalletModule.swift */; }; + C56EE242293F566D004840D1 /* ScanPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE23B293F566C004840D1 /* ScanPresenter.swift */; }; + C56EE243293F566D004840D1 /* ScanView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE23A293F566B004840D1 /* ScanView.swift */; }; + C56EE244293F566D004840D1 /* AuthRequestRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE234293F566A004840D1 /* AuthRequestRouter.swift */; }; + C56EE245293F566D004840D1 /* WalletPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE22C293F5668004840D1 /* WalletPresenter.swift */; }; + C56EE246293F566D004840D1 /* ScanRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE239293F566B004840D1 /* ScanRouter.swift */; }; + C56EE247293F566D004840D1 /* ScanModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE237293F566B004840D1 /* ScanModule.swift */; }; + C56EE248293F566D004840D1 /* ScanQR.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE23E293F566C004840D1 /* ScanQR.swift */; }; + C56EE249293F566D004840D1 /* ScanInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE238293F566B004840D1 /* ScanInteractor.swift */; }; + C56EE24A293F566D004840D1 /* AuthRequestModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE235293F566A004840D1 /* AuthRequestModule.swift */; }; + C56EE24B293F566D004840D1 /* AuthRequestPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE233293F566A004840D1 /* AuthRequestPresenter.swift */; }; + C56EE24C293F566D004840D1 /* AuthRequestInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE231293F5669004840D1 /* AuthRequestInteractor.swift */; }; + C56EE24D293F566D004840D1 /* WalletRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE22E293F5669004840D1 /* WalletRouter.swift */; }; + C56EE24E293F566D004840D1 /* WalletInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE22F293F5669004840D1 /* WalletInteractor.swift */; }; + C56EE24F293F566D004840D1 /* WalletView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE22B293F5668004840D1 /* WalletView.swift */; }; + C56EE250293F566D004840D1 /* ScanTargetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE23D293F566C004840D1 /* ScanTargetView.swift */; }; + C56EE251293F566D004840D1 /* AuthRequestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE232293F566A004840D1 /* AuthRequestView.swift */; }; + C56EE255293F569A004840D1 /* Starscream in Frameworks */ = {isa = PBXBuildFile; productRef = C56EE254293F569A004840D1 /* Starscream */; }; + C56EE26F293F56D7004840D1 /* Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE266293F56D6004840D1 /* Types.swift */; }; + C56EE270293F56D7004840D1 /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE26A293F56D6004840D1 /* String.swift */; }; + C56EE271293F56D7004840D1 /* View.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE26E293F56D7004840D1 /* View.swift */; }; + C56EE272293F56D7004840D1 /* TextFieldView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE260293F56D6004840D1 /* TextFieldView.swift */; }; + C56EE273293F56D7004840D1 /* UIColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE26B293F56D6004840D1 /* UIColor.swift */; }; + C56EE274293F56D7004840D1 /* SceneViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE264293F56D6004840D1 /* SceneViewController.swift */; }; + C56EE275293F56D7004840D1 /* InputConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE25D293F56D6004840D1 /* InputConfig.swift */; }; + C56EE276293F56D7004840D1 /* UIViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE26C293F56D6004840D1 /* UIViewController.swift */; }; + C56EE277293F56D7004840D1 /* BrandButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE261293F56D6004840D1 /* BrandButton.swift */; }; + C56EE278293F56D7004840D1 /* InputView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE25F293F56D6004840D1 /* InputView.swift */; }; + C56EE279293F56D7004840D1 /* Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE268293F56D6004840D1 /* Color.swift */; }; + C56EE27B293F56F8004840D1 /* WalletConnectAuth in Frameworks */ = {isa = PBXBuildFile; productRef = C56EE27A293F56F8004840D1 /* WalletConnectAuth */; }; + C56EE27D293F56F8004840D1 /* WalletConnectChat in Frameworks */ = {isa = PBXBuildFile; productRef = C56EE27C293F56F8004840D1 /* WalletConnectChat */; }; + C56EE288293F5757004840D1 /* ThirdPartyConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE286293F5757004840D1 /* ThirdPartyConfigurator.swift */; }; + C56EE289293F5757004840D1 /* Application.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE280293F5757004840D1 /* Application.swift */; }; + C56EE28A293F5757004840D1 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE27F293F5757004840D1 /* AppDelegate.swift */; }; + C56EE28B293F5757004840D1 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE281293F5757004840D1 /* SceneDelegate.swift */; }; + C56EE28C293F5757004840D1 /* Configurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE285293F5757004840D1 /* Configurator.swift */; }; + C56EE28D293F5757004840D1 /* AppearanceConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE287293F5757004840D1 /* AppearanceConfigurator.swift */; }; + C56EE28E293F5757004840D1 /* ApplicationConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE284293F5757004840D1 /* ApplicationConfigurator.swift */; }; + C56EE28F293F5757004840D1 /* MigrationConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE283293F5757004840D1 /* MigrationConfigurator.swift */; }; + C56EE299293F5773004840D1 /* AccountNameResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE296293F5773004840D1 /* AccountNameResolver.swift */; }; + C56EE29A293F5773004840D1 /* AccountStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE298293F5773004840D1 /* AccountStorage.swift */; }; + C56EE29B293F5773004840D1 /* SocketFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE292293F5773004840D1 /* SocketFactory.swift */; }; + C56EE29C293F5773004840D1 /* ChatService.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE295293F5773004840D1 /* ChatService.swift */; }; + C56EE29D293F5773004840D1 /* RegisterService.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE294293F5773004840D1 /* RegisterService.swift */; }; + C56EE2A3293F6BAF004840D1 /* UIPasteboardWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE2A2293F6BAF004840D1 /* UIPasteboardWrapper.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -383,6 +430,52 @@ A5E22D232840C8DB00E36487 /* SafariEngine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariEngine.swift; sourceTree = ""; }; A5E22D2B2840EAC300E36487 /* XCUIElement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCUIElement.swift; sourceTree = ""; }; A5F48A0528E43D3F0034CBFB /* Configuration.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Configuration.xcconfig; path = ../Configuration.xcconfig; sourceTree = ""; }; + C56EE21B293F55ED004840D1 /* ChatWallet.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ChatWallet.app; sourceTree = BUILT_PRODUCTS_DIR; }; + C56EE221293F55EE004840D1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + C56EE22B293F5668004840D1 /* WalletView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletView.swift; sourceTree = ""; }; + C56EE22C293F5668004840D1 /* WalletPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletPresenter.swift; sourceTree = ""; }; + C56EE22D293F5669004840D1 /* WalletModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletModule.swift; sourceTree = ""; }; + C56EE22E293F5669004840D1 /* WalletRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletRouter.swift; sourceTree = ""; }; + C56EE22F293F5669004840D1 /* WalletInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletInteractor.swift; sourceTree = ""; }; + C56EE231293F5669004840D1 /* AuthRequestInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthRequestInteractor.swift; sourceTree = ""; }; + C56EE232293F566A004840D1 /* AuthRequestView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthRequestView.swift; sourceTree = ""; }; + C56EE233293F566A004840D1 /* AuthRequestPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthRequestPresenter.swift; sourceTree = ""; }; + C56EE234293F566A004840D1 /* AuthRequestRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthRequestRouter.swift; sourceTree = ""; }; + C56EE235293F566A004840D1 /* AuthRequestModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthRequestModule.swift; sourceTree = ""; }; + C56EE237293F566B004840D1 /* ScanModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanModule.swift; sourceTree = ""; }; + C56EE238293F566B004840D1 /* ScanInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanInteractor.swift; sourceTree = ""; }; + C56EE239293F566B004840D1 /* ScanRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanRouter.swift; sourceTree = ""; }; + C56EE23A293F566B004840D1 /* ScanView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanView.swift; sourceTree = ""; }; + C56EE23B293F566C004840D1 /* ScanPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanPresenter.swift; sourceTree = ""; }; + C56EE23D293F566C004840D1 /* ScanTargetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanTargetView.swift; sourceTree = ""; }; + C56EE23E293F566C004840D1 /* ScanQR.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanQR.swift; sourceTree = ""; }; + C56EE23F293F566C004840D1 /* ScanQRView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanQRView.swift; sourceTree = ""; }; + C56EE25D293F56D6004840D1 /* InputConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputConfig.swift; sourceTree = ""; }; + C56EE25F293F56D6004840D1 /* InputView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputView.swift; sourceTree = ""; }; + C56EE260293F56D6004840D1 /* TextFieldView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldView.swift; sourceTree = ""; }; + C56EE261293F56D6004840D1 /* BrandButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrandButton.swift; sourceTree = ""; }; + C56EE264293F56D6004840D1 /* SceneViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneViewController.swift; sourceTree = ""; }; + C56EE266293F56D6004840D1 /* Types.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Types.swift; sourceTree = ""; }; + C56EE268293F56D6004840D1 /* Color.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Color.swift; sourceTree = ""; }; + C56EE26A293F56D6004840D1 /* String.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = ""; }; + C56EE26B293F56D6004840D1 /* UIColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIColor.swift; sourceTree = ""; }; + C56EE26C293F56D6004840D1 /* UIViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIViewController.swift; sourceTree = ""; }; + C56EE26E293F56D7004840D1 /* View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = View.swift; sourceTree = ""; }; + C56EE27F293F5757004840D1 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + C56EE280293F5757004840D1 /* Application.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Application.swift; sourceTree = ""; }; + C56EE281293F5757004840D1 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; + C56EE283293F5757004840D1 /* MigrationConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrationConfigurator.swift; sourceTree = ""; }; + C56EE284293F5757004840D1 /* ApplicationConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationConfigurator.swift; sourceTree = ""; }; + C56EE285293F5757004840D1 /* Configurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Configurator.swift; sourceTree = ""; }; + C56EE286293F5757004840D1 /* ThirdPartyConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThirdPartyConfigurator.swift; sourceTree = ""; }; + C56EE287293F5757004840D1 /* AppearanceConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearanceConfigurator.swift; sourceTree = ""; }; + C56EE292293F5773004840D1 /* SocketFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocketFactory.swift; sourceTree = ""; }; + C56EE294293F5773004840D1 /* RegisterService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegisterService.swift; sourceTree = ""; }; + C56EE295293F5773004840D1 /* ChatService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatService.swift; sourceTree = ""; }; + C56EE296293F5773004840D1 /* AccountNameResolver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountNameResolver.swift; sourceTree = ""; }; + C56EE298293F5773004840D1 /* AccountStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountStorage.swift; sourceTree = ""; }; + C56EE29F293F5C4F004840D1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + C56EE2A2293F6BAF004840D1 /* UIPasteboardWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIPasteboardWrapper.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -441,6 +534,16 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + C56EE218293F55ED004840D1 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + C56EE27D293F56F8004840D1 /* WalletConnectChat in Frameworks */, + C56EE255293F569A004840D1 /* Starscream in Frameworks */, + C56EE27B293F56F8004840D1 /* WalletConnectAuth in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -492,6 +595,7 @@ A5A4FC732840C12C00BBEC1E /* UITests */, A5E03DEE286464DB00888481 /* IntegrationTests */, A58E7CE928729F550082D443 /* Showcase */, + C56EE21C293F55ED004840D1 /* ChatWallet */, 764E1D3D26F8D3FC00A1FB15 /* Products */, 764E1D5326F8DAC800A1FB15 /* Frameworks */, 764E1D5626F8DB6000A1FB15 /* WalletConnectSwiftV2 */, @@ -506,6 +610,7 @@ A5A4FC722840C12C00BBEC1E /* UITests.xctest */, A5E03DED286464DB00888481 /* IntegrationTests.xctest */, A58E7CE828729F550082D443 /* Showcase.app */, + C56EE21B293F55ED004840D1 /* ChatWallet.app */, ); name = Products; sourceTree = ""; @@ -1158,6 +1263,234 @@ path = Extensions; sourceTree = ""; }; + C56EE21C293F55ED004840D1 /* ChatWallet */ = { + isa = PBXGroup; + children = ( + C56EE25C293F56D6004840D1 /* Common */, + C56EE27E293F5756004840D1 /* ApplicationLayer */, + C56EE290293F5773004840D1 /* DomainLayer */, + C56EE29E293F577B004840D1 /* PresentationLayer */, + C56EE2A0293F6B10004840D1 /* Other */, + ); + path = ChatWallet; + sourceTree = ""; + }; + C56EE229293F5668004840D1 /* Wallet */ = { + isa = PBXGroup; + children = ( + C56EE236293F566A004840D1 /* Scan */, + C56EE230293F5669004840D1 /* AuthRequest */, + C56EE22A293F5668004840D1 /* Wallet */, + ); + path = Wallet; + sourceTree = ""; + }; + C56EE22A293F5668004840D1 /* Wallet */ = { + isa = PBXGroup; + children = ( + C56EE22D293F5669004840D1 /* WalletModule.swift */, + C56EE22E293F5669004840D1 /* WalletRouter.swift */, + C56EE22F293F5669004840D1 /* WalletInteractor.swift */, + C56EE22C293F5668004840D1 /* WalletPresenter.swift */, + C56EE22B293F5668004840D1 /* WalletView.swift */, + ); + path = Wallet; + sourceTree = ""; + }; + C56EE230293F5669004840D1 /* AuthRequest */ = { + isa = PBXGroup; + children = ( + C56EE235293F566A004840D1 /* AuthRequestModule.swift */, + C56EE233293F566A004840D1 /* AuthRequestPresenter.swift */, + C56EE234293F566A004840D1 /* AuthRequestRouter.swift */, + C56EE231293F5669004840D1 /* AuthRequestInteractor.swift */, + C56EE232293F566A004840D1 /* AuthRequestView.swift */, + ); + path = AuthRequest; + sourceTree = ""; + }; + C56EE236293F566A004840D1 /* Scan */ = { + isa = PBXGroup; + children = ( + C56EE23C293F566C004840D1 /* Views */, + C56EE237293F566B004840D1 /* ScanModule.swift */, + C56EE23B293F566C004840D1 /* ScanPresenter.swift */, + C56EE239293F566B004840D1 /* ScanRouter.swift */, + C56EE238293F566B004840D1 /* ScanInteractor.swift */, + C56EE23A293F566B004840D1 /* ScanView.swift */, + ); + path = Scan; + sourceTree = ""; + }; + C56EE23C293F566C004840D1 /* Views */ = { + isa = PBXGroup; + children = ( + C56EE23E293F566C004840D1 /* ScanQR.swift */, + C56EE23F293F566C004840D1 /* ScanQRView.swift */, + C56EE23D293F566C004840D1 /* ScanTargetView.swift */, + ); + path = Views; + sourceTree = ""; + }; + C56EE25C293F56D6004840D1 /* Common */ = { + isa = PBXGroup; + children = ( + C56EE25D293F56D6004840D1 /* InputConfig.swift */, + C56EE265293F56D6004840D1 /* Types */, + C56EE25E293F56D6004840D1 /* Components */, + C56EE267293F56D6004840D1 /* Style */, + C56EE2A1293F6B9E004840D1 /* Helpers */, + C56EE262293F56D6004840D1 /* Extensions */, + C56EE263293F56D6004840D1 /* VIPER */, + ); + path = Common; + sourceTree = ""; + }; + C56EE25E293F56D6004840D1 /* Components */ = { + isa = PBXGroup; + children = ( + C56EE25F293F56D6004840D1 /* InputView.swift */, + C56EE260293F56D6004840D1 /* TextFieldView.swift */, + C56EE261293F56D6004840D1 /* BrandButton.swift */, + ); + path = Components; + sourceTree = ""; + }; + C56EE262293F56D6004840D1 /* Extensions */ = { + isa = PBXGroup; + children = ( + C56EE26D293F56D6004840D1 /* SwiftUI */, + C56EE269293F56D6004840D1 /* UIKit */, + ); + path = Extensions; + sourceTree = ""; + }; + C56EE263293F56D6004840D1 /* VIPER */ = { + isa = PBXGroup; + children = ( + C56EE264293F56D6004840D1 /* SceneViewController.swift */, + ); + path = VIPER; + sourceTree = ""; + }; + C56EE265293F56D6004840D1 /* Types */ = { + isa = PBXGroup; + children = ( + C56EE266293F56D6004840D1 /* Types.swift */, + ); + path = Types; + sourceTree = ""; + }; + C56EE267293F56D6004840D1 /* Style */ = { + isa = PBXGroup; + children = ( + C56EE268293F56D6004840D1 /* Color.swift */, + ); + path = Style; + sourceTree = ""; + }; + C56EE269293F56D6004840D1 /* UIKit */ = { + isa = PBXGroup; + children = ( + C56EE26C293F56D6004840D1 /* UIViewController.swift */, + C56EE26A293F56D6004840D1 /* String.swift */, + C56EE26B293F56D6004840D1 /* UIColor.swift */, + ); + path = UIKit; + sourceTree = ""; + }; + C56EE26D293F56D6004840D1 /* SwiftUI */ = { + isa = PBXGroup; + children = ( + C56EE26E293F56D7004840D1 /* View.swift */, + ); + path = SwiftUI; + sourceTree = ""; + }; + C56EE27E293F5756004840D1 /* ApplicationLayer */ = { + isa = PBXGroup; + children = ( + C56EE282293F5757004840D1 /* Configurator */, + C56EE280293F5757004840D1 /* Application.swift */, + C56EE27F293F5757004840D1 /* AppDelegate.swift */, + C56EE281293F5757004840D1 /* SceneDelegate.swift */, + ); + path = ApplicationLayer; + sourceTree = ""; + }; + C56EE282293F5757004840D1 /* Configurator */ = { + isa = PBXGroup; + children = ( + C56EE285293F5757004840D1 /* Configurator.swift */, + C56EE286293F5757004840D1 /* ThirdPartyConfigurator.swift */, + C56EE284293F5757004840D1 /* ApplicationConfigurator.swift */, + C56EE283293F5757004840D1 /* MigrationConfigurator.swift */, + C56EE287293F5757004840D1 /* AppearanceConfigurator.swift */, + ); + path = Configurator; + sourceTree = ""; + }; + C56EE290293F5773004840D1 /* DomainLayer */ = { + isa = PBXGroup; + children = ( + C56EE297293F5773004840D1 /* AccountStorage */, + C56EE291293F5773004840D1 /* SocketFactory */, + C56EE293293F5773004840D1 /* Chat */, + ); + path = DomainLayer; + sourceTree = ""; + }; + C56EE291293F5773004840D1 /* SocketFactory */ = { + isa = PBXGroup; + children = ( + C56EE292293F5773004840D1 /* SocketFactory.swift */, + ); + path = SocketFactory; + sourceTree = ""; + }; + C56EE293293F5773004840D1 /* Chat */ = { + isa = PBXGroup; + children = ( + C56EE295293F5773004840D1 /* ChatService.swift */, + C56EE296293F5773004840D1 /* AccountNameResolver.swift */, + C56EE294293F5773004840D1 /* RegisterService.swift */, + ); + path = Chat; + sourceTree = ""; + }; + C56EE297293F5773004840D1 /* AccountStorage */ = { + isa = PBXGroup; + children = ( + C56EE298293F5773004840D1 /* AccountStorage.swift */, + ); + path = AccountStorage; + sourceTree = ""; + }; + C56EE29E293F577B004840D1 /* PresentationLayer */ = { + isa = PBXGroup; + children = ( + C56EE229293F5668004840D1 /* Wallet */, + ); + path = PresentationLayer; + sourceTree = ""; + }; + C56EE2A0293F6B10004840D1 /* Other */ = { + isa = PBXGroup; + children = ( + C56EE221293F55EE004840D1 /* Assets.xcassets */, + C56EE29F293F5C4F004840D1 /* Info.plist */, + ); + path = Other; + sourceTree = ""; + }; + C56EE2A1293F6B9E004840D1 /* Helpers */ = { + isa = PBXGroup; + children = ( + C56EE2A2293F6BAF004840D1 /* UIPasteboardWrapper.swift */, + ); + path = Helpers; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -1276,13 +1609,35 @@ productReference = A5E03DED286464DB00888481 /* IntegrationTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; + C56EE21A293F55ED004840D1 /* ChatWallet */ = { + isa = PBXNativeTarget; + buildConfigurationList = C56EE228293F55EE004840D1 /* Build configuration list for PBXNativeTarget "ChatWallet" */; + buildPhases = ( + C56EE217293F55ED004840D1 /* Sources */, + C56EE218293F55ED004840D1 /* Frameworks */, + C56EE219293F55ED004840D1 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = ChatWallet; + packageProductDependencies = ( + C56EE254293F569A004840D1 /* Starscream */, + C56EE27A293F56F8004840D1 /* WalletConnectAuth */, + C56EE27C293F56F8004840D1 /* WalletConnectChat */, + ); + productName = ChatWallet; + productReference = C56EE21B293F55ED004840D1 /* ChatWallet.app */; + productType = "com.apple.product-type.application"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 764E1D3426F8D3FC00A1FB15 /* Project object */ = { isa = PBXProject; attributes = { - LastSwiftUpdateCheck = 1330; + LastSwiftUpdateCheck = 1410; LastUpgradeCheck = 1250; TargetAttributes = { 764E1D3B26F8D3FC00A1FB15 = { @@ -1300,6 +1655,9 @@ A5E03DEC286464DB00888481 = { CreatedOnToolsVersion = 13.3; }; + C56EE21A293F55ED004840D1 = { + CreatedOnToolsVersion = 14.1; + }; }; }; buildConfigurationList = 764E1D3726F8D3FC00A1FB15 /* Build configuration list for PBXProject "ExampleApp" */; @@ -1325,6 +1683,7 @@ A5A4FC712840C12C00BBEC1E /* UITests */, A5E03DEC286464DB00888481 /* IntegrationTests */, A58E7CE728729F550082D443 /* Showcase */, + C56EE21A293F55ED004840D1 /* ChatWallet */, ); }; /* End PBXProject section */ @@ -1371,6 +1730,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + C56EE219293F55ED004840D1 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C56EE222293F55EE004840D1 /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -1567,6 +1934,56 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + C56EE217293F55ED004840D1 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C56EE29C293F5773004840D1 /* ChatService.swift in Sources */, + C56EE24B293F566D004840D1 /* AuthRequestPresenter.swift in Sources */, + C56EE247293F566D004840D1 /* ScanModule.swift in Sources */, + C56EE272293F56D7004840D1 /* TextFieldView.swift in Sources */, + C56EE28D293F5757004840D1 /* AppearanceConfigurator.swift in Sources */, + C56EE241293F566D004840D1 /* WalletModule.swift in Sources */, + C56EE26F293F56D7004840D1 /* Types.swift in Sources */, + C56EE245293F566D004840D1 /* WalletPresenter.swift in Sources */, + C56EE240293F566D004840D1 /* ScanQRView.swift in Sources */, + C56EE24C293F566D004840D1 /* AuthRequestInteractor.swift in Sources */, + C56EE250293F566D004840D1 /* ScanTargetView.swift in Sources */, + C56EE28F293F5757004840D1 /* MigrationConfigurator.swift in Sources */, + C56EE299293F5773004840D1 /* AccountNameResolver.swift in Sources */, + C56EE271293F56D7004840D1 /* View.swift in Sources */, + C56EE24D293F566D004840D1 /* WalletRouter.swift in Sources */, + C56EE28E293F5757004840D1 /* ApplicationConfigurator.swift in Sources */, + C56EE242293F566D004840D1 /* ScanPresenter.swift in Sources */, + C56EE29D293F5773004840D1 /* RegisterService.swift in Sources */, + C56EE251293F566D004840D1 /* AuthRequestView.swift in Sources */, + C56EE277293F56D7004840D1 /* BrandButton.swift in Sources */, + C56EE28B293F5757004840D1 /* SceneDelegate.swift in Sources */, + C56EE276293F56D7004840D1 /* UIViewController.swift in Sources */, + C56EE275293F56D7004840D1 /* InputConfig.swift in Sources */, + C56EE270293F56D7004840D1 /* String.swift in Sources */, + C56EE279293F56D7004840D1 /* Color.swift in Sources */, + C56EE243293F566D004840D1 /* ScanView.swift in Sources */, + C56EE288293F5757004840D1 /* ThirdPartyConfigurator.swift in Sources */, + C56EE29A293F5773004840D1 /* AccountStorage.swift in Sources */, + C56EE24F293F566D004840D1 /* WalletView.swift in Sources */, + C56EE248293F566D004840D1 /* ScanQR.swift in Sources */, + C56EE289293F5757004840D1 /* Application.swift in Sources */, + C56EE273293F56D7004840D1 /* UIColor.swift in Sources */, + C56EE246293F566D004840D1 /* ScanRouter.swift in Sources */, + C56EE28C293F5757004840D1 /* Configurator.swift in Sources */, + C56EE274293F56D7004840D1 /* SceneViewController.swift in Sources */, + C56EE244293F566D004840D1 /* AuthRequestRouter.swift in Sources */, + C56EE24A293F566D004840D1 /* AuthRequestModule.swift in Sources */, + C56EE278293F56D7004840D1 /* InputView.swift in Sources */, + C56EE249293F566D004840D1 /* ScanInteractor.swift in Sources */, + C56EE28A293F5757004840D1 /* AppDelegate.swift in Sources */, + C56EE2A3293F6BAF004840D1 /* UIPasteboardWrapper.swift in Sources */, + C56EE24E293F566D004840D1 /* WalletInteractor.swift in Sources */, + C56EE29B293F5773004840D1 /* SocketFactory.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ @@ -1986,6 +2403,64 @@ }; name = Release; }; + C56EE226293F55EE004840D1 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = ChatWallet/Other/Info.plist; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 15.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.walletconnect.ChatWallet; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + C56EE227293F55EE004840D1 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = ChatWallet/Other/Info.plist; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 15.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.walletconnect.ChatWallet; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -2043,6 +2518,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + C56EE228293F55EE004840D1 /* Build configuration list for PBXNativeTarget "ChatWallet" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C56EE226293F55EE004840D1 /* Debug */, + C56EE227293F55EE004840D1 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ @@ -2162,6 +2646,19 @@ isa = XCSwiftPackageProductDependency; productName = WalletConnectChat; }; + C56EE254293F569A004840D1 /* Starscream */ = { + isa = XCSwiftPackageProductDependency; + package = A5D85224286333D500DAF5C3 /* XCRemoteSwiftPackageReference "Starscream" */; + productName = Starscream; + }; + C56EE27A293F56F8004840D1 /* WalletConnectAuth */ = { + isa = XCSwiftPackageProductDependency; + productName = WalletConnectAuth; + }; + C56EE27C293F56F8004840D1 /* WalletConnectChat */ = { + isa = XCSwiftPackageProductDependency; + productName = WalletConnectChat; + }; /* End XCSwiftPackageProductDependency section */ }; rootObject = 764E1D3426F8D3FC00A1FB15 /* Project object */; From a830493b6e747c423b8ce07fbec023c58c0189cc Mon Sep 17 00:00:00 2001 From: Alexander Lisovik Date: Thu, 29 Dec 2022 19:20:08 +0100 Subject: [PATCH 02/14] Update wallet UI --- .../ApplicationLayer/AppDelegate.swift | 1 - .../ApplicationLayer/Application.swift | 2 + .../ApplicationConfigurator.swift | 2 +- .../Configurator/ThirdPartyConfigurator.swift | 4 +- .../ApplicationLayer/SceneDelegate.swift | 5 +- .../Common/Components/BrandButton.swift | 20 -- .../Common/Components/InputView.swift | 28 -- .../Common/Components/TextFieldView.swift | 50 --- .../Extensions/UIKit/UIViewController.swift | 8 + .../Common/Helpers/UIPasteboardWrapper.swift | 7 - Example/ChatWallet/Common/InputConfig.swift | 1 - Example/ChatWallet/Common/Style/Color.swift | 30 +- .../connect-template.imageset/Contents.json | 12 + .../connect-template.svg | 3 + .../copy.imageset/Contents.json | 12 + .../Assets.xcassets/copy.imageset/copy.svg | 22 ++ .../forward-shevron.imageset/Contents.json | 15 + .../forward-shevron.svg | 3 + .../foundation.imageset/Contents.json | 12 + .../foundation.imageset/foundation.svg | 12 + .../header.imageset/Contents.json | 12 + .../header.imageset/Visual.svg | 192 +++++++++++ .../scan.imageset/Contents.json | 12 + .../Assets.xcassets/scan.imageset/scan.svg | 32 ++ .../Other/Colors.xcassets/Contents.json | 6 + .../blue100.colorset/Contents.json | 38 +++ .../blue200.colorset/Contents.json | 38 +++ .../cyan-background.colorset/Contents.json | 38 +++ .../Contents.json | 38 +++ .../Contents.json | 38 +++ .../grey100.colorset/Contents.json | 38 +++ .../grey50.colorset/Contents.json | 38 +++ .../grey70.colorset/Contents.json | 38 +++ .../grey8.colorset/Contents.json | 38 +++ .../grey95.colorset/Contents.json | 38 +++ .../light-background.colorset/Contents.json | 38 +++ .../light-blue.colorset/Contents.json | 38 +++ .../Contents.json | 38 +++ .../Contents.json | 38 +++ .../system-gray-light.colorset/Contents.json | 38 +++ .../white-background.colorset/Contents.json | 38 +++ Example/ChatWallet/Other/Info.plist | 2 +- .../AuthRequest/AuthRequestInteractor.swift | 3 +- .../AuthRequest/AuthRequestModule.swift | 3 +- .../AuthRequest/AuthRequestPresenter.swift | 44 ++- .../AuthRequest/AuthRequestRouter.swift | 4 +- .../Wallet/AuthRequest/AuthRequestView.swift | 163 +++++++--- .../ConnectionDetailsInteractor.swift} | 3 +- .../ConnectionDetailsModule.swift | 16 + .../ConnectionDetailsPresenter.swift} | 32 +- .../ConnectionDetailsRouter.swift} | 3 +- .../ConnectionDetailsView.swift | 155 +++++++++ .../Wallet/PasteUri/PasteUriInteractor.swift | 3 + .../Wallet/PasteUri/PasteUriModule.swift} | 17 +- .../Wallet/PasteUri/PasteUriPresenter.swift | 38 +++ .../Wallet/PasteUri/PasteUriRouter.swift} | 3 +- .../Wallet/PasteUri/PasteUriView.swift | 100 ++++++ .../Wallet/Wallet/WalletInteractor.swift | 64 +--- .../Wallet/Wallet/WalletModule.swift | 6 +- .../Wallet/Wallet/WalletPresenter.swift | 76 ++++- .../Wallet/Wallet/WalletRouter.swift | 13 +- .../Wallet/Wallet/WalletView.swift | 119 ++++--- .../Wallet/Welcome/WelcomeInteractor.swift | 3 + .../Wallet/Welcome/WelcomeModule.swift | 16 + .../Wallet/Welcome/WelcomePresenter.swift | 32 ++ .../Wallet/Welcome/WelcomeRouter.swift | 17 + .../Wallet/Welcome/WelcomeView.swift | 57 ++++ Example/ExampleApp.xcodeproj/project.pbxproj | 298 ++++++++---------- .../xcschemes/ChatWallet.xcscheme | 78 +++++ .../ApplicationConfigurator.swift | 2 +- .../SocketFactory/SocketFactory.swift | 9 + .../Chat/Main/MainPresenter.swift | 3 +- .../Chat/Main/MainRouter.swift | 4 - .../Chat/Welcome/WelcomeInteractor.swift | 75 +++++ .../Chat/Welcome/WelcomePresenter.swift | 29 +- .../Chat/Welcome/WelcomeRouter.swift | 4 + .../Chat/Welcome/WelcomeView.swift | 4 +- .../AuthRequest/AuthRequestInteractor.swift | 17 - .../AuthRequest/AuthRequestModule.swift | 19 -- .../AuthRequest/AuthRequestPresenter.swift | 56 ---- .../AuthRequest/AuthRequestRouter.swift | 16 - .../Wallet/AuthRequest/AuthRequestView.swift | 54 ---- .../Wallet/Scan/ScanInteractor.swift | 3 - .../Wallet/Scan/ScanPresenter.swift | 48 --- .../Wallet/Scan/ScanView.swift | 19 -- .../Wallet/Scan/Views/ScanQR.swift | 39 --- .../Wallet/Scan/Views/ScanQRView.swift | 187 ----------- .../Wallet/Scan/Views/ScanTargetView.swift | 87 ----- .../Wallet/Wallet/WalletModule.swift | 18 -- .../Wallet/Wallet/WalletView.swift | 46 --- Example/Showcase/Common/InputConfig.swift | 4 + Example/Showcase/Other/Info.plist | 2 + 92 files changed, 2100 insertions(+), 1124 deletions(-) delete mode 100644 Example/ChatWallet/Common/Components/BrandButton.swift delete mode 100644 Example/ChatWallet/Common/Components/InputView.swift delete mode 100644 Example/ChatWallet/Common/Components/TextFieldView.swift create mode 100644 Example/ChatWallet/Other/Assets.xcassets/connect-template.imageset/Contents.json create mode 100644 Example/ChatWallet/Other/Assets.xcassets/connect-template.imageset/connect-template.svg create mode 100644 Example/ChatWallet/Other/Assets.xcassets/copy.imageset/Contents.json create mode 100644 Example/ChatWallet/Other/Assets.xcassets/copy.imageset/copy.svg create mode 100644 Example/ChatWallet/Other/Assets.xcassets/forward-shevron.imageset/Contents.json create mode 100644 Example/ChatWallet/Other/Assets.xcassets/forward-shevron.imageset/forward-shevron.svg create mode 100644 Example/ChatWallet/Other/Assets.xcassets/foundation.imageset/Contents.json create mode 100644 Example/ChatWallet/Other/Assets.xcassets/foundation.imageset/foundation.svg create mode 100644 Example/ChatWallet/Other/Assets.xcassets/header.imageset/Contents.json create mode 100644 Example/ChatWallet/Other/Assets.xcassets/header.imageset/Visual.svg create mode 100644 Example/ChatWallet/Other/Assets.xcassets/scan.imageset/Contents.json create mode 100644 Example/ChatWallet/Other/Assets.xcassets/scan.imageset/scan.svg create mode 100644 Example/ChatWallet/Other/Colors.xcassets/Contents.json create mode 100644 Example/ChatWallet/Other/Colors.xcassets/blue100.colorset/Contents.json create mode 100644 Example/ChatWallet/Other/Colors.xcassets/blue200.colorset/Contents.json create mode 100644 Example/ChatWallet/Other/Colors.xcassets/cyan-background.colorset/Contents.json create mode 100644 Example/ChatWallet/Other/Colors.xcassets/foreground-negative.colorset/Contents.json create mode 100644 Example/ChatWallet/Other/Colors.xcassets/foreground-positive.colorset/Contents.json create mode 100644 Example/ChatWallet/Other/Colors.xcassets/grey100.colorset/Contents.json create mode 100644 Example/ChatWallet/Other/Colors.xcassets/grey50.colorset/Contents.json create mode 100644 Example/ChatWallet/Other/Colors.xcassets/grey70.colorset/Contents.json create mode 100644 Example/ChatWallet/Other/Colors.xcassets/grey8.colorset/Contents.json create mode 100644 Example/ChatWallet/Other/Colors.xcassets/grey95.colorset/Contents.json create mode 100644 Example/ChatWallet/Other/Colors.xcassets/light-background.colorset/Contents.json create mode 100644 Example/ChatWallet/Other/Colors.xcassets/light-blue.colorset/Contents.json create mode 100644 Example/ChatWallet/Other/Colors.xcassets/light-foreground-negative.colorset/Contents.json create mode 100644 Example/ChatWallet/Other/Colors.xcassets/light-foreground-positive.colorset/Contents.json create mode 100644 Example/ChatWallet/Other/Colors.xcassets/system-gray-light.colorset/Contents.json create mode 100644 Example/ChatWallet/Other/Colors.xcassets/white-background.colorset/Contents.json rename Example/{Showcase/Classes/PresentationLayer/Wallet/Wallet/WalletInteractor.swift => ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsInteractor.swift} (86%) create mode 100644 Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsModule.swift rename Example/{Showcase/Classes/PresentationLayer/Wallet/Wallet/WalletPresenter.swift => ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsPresenter.swift} (69%) rename Example/{Showcase/Classes/PresentationLayer/Wallet/Wallet/WalletRouter.swift => ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsRouter.swift} (94%) create mode 100644 Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsView.swift create mode 100644 Example/ChatWallet/PresentationLayer/Wallet/PasteUri/PasteUriInteractor.swift rename Example/{Showcase/Classes/PresentationLayer/Wallet/Scan/ScanModule.swift => ChatWallet/PresentationLayer/Wallet/PasteUri/PasteUriModule.swift} (51%) create mode 100644 Example/ChatWallet/PresentationLayer/Wallet/PasteUri/PasteUriPresenter.swift rename Example/{Showcase/Classes/PresentationLayer/Wallet/Scan/ScanRouter.swift => ChatWallet/PresentationLayer/Wallet/PasteUri/PasteUriRouter.swift} (84%) create mode 100644 Example/ChatWallet/PresentationLayer/Wallet/PasteUri/PasteUriView.swift create mode 100644 Example/ChatWallet/PresentationLayer/Wallet/Welcome/WelcomeInteractor.swift create mode 100644 Example/ChatWallet/PresentationLayer/Wallet/Welcome/WelcomeModule.swift create mode 100644 Example/ChatWallet/PresentationLayer/Wallet/Welcome/WelcomePresenter.swift create mode 100644 Example/ChatWallet/PresentationLayer/Wallet/Welcome/WelcomeRouter.swift create mode 100644 Example/ChatWallet/PresentationLayer/Wallet/Welcome/WelcomeView.swift create mode 100644 Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/ChatWallet.xcscheme create mode 100644 Example/Showcase/Classes/DomainLayer/SocketFactory/SocketFactory.swift delete mode 100644 Example/Showcase/Classes/PresentationLayer/Wallet/AuthRequest/AuthRequestInteractor.swift delete mode 100644 Example/Showcase/Classes/PresentationLayer/Wallet/AuthRequest/AuthRequestModule.swift delete mode 100644 Example/Showcase/Classes/PresentationLayer/Wallet/AuthRequest/AuthRequestPresenter.swift delete mode 100644 Example/Showcase/Classes/PresentationLayer/Wallet/AuthRequest/AuthRequestRouter.swift delete mode 100644 Example/Showcase/Classes/PresentationLayer/Wallet/AuthRequest/AuthRequestView.swift delete mode 100644 Example/Showcase/Classes/PresentationLayer/Wallet/Scan/ScanInteractor.swift delete mode 100644 Example/Showcase/Classes/PresentationLayer/Wallet/Scan/ScanPresenter.swift delete mode 100644 Example/Showcase/Classes/PresentationLayer/Wallet/Scan/ScanView.swift delete mode 100644 Example/Showcase/Classes/PresentationLayer/Wallet/Scan/Views/ScanQR.swift delete mode 100644 Example/Showcase/Classes/PresentationLayer/Wallet/Scan/Views/ScanQRView.swift delete mode 100644 Example/Showcase/Classes/PresentationLayer/Wallet/Scan/Views/ScanTargetView.swift delete mode 100644 Example/Showcase/Classes/PresentationLayer/Wallet/Wallet/WalletModule.swift delete mode 100644 Example/Showcase/Classes/PresentationLayer/Wallet/Wallet/WalletView.swift diff --git a/Example/ChatWallet/ApplicationLayer/AppDelegate.swift b/Example/ChatWallet/ApplicationLayer/AppDelegate.swift index 43d099d07..821a8f719 100644 --- a/Example/ChatWallet/ApplicationLayer/AppDelegate.swift +++ b/Example/ChatWallet/ApplicationLayer/AppDelegate.swift @@ -4,7 +4,6 @@ import UIKit final class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. - print("lala") return true } diff --git a/Example/ChatWallet/ApplicationLayer/Application.swift b/Example/ChatWallet/ApplicationLayer/Application.swift index 292062b5f..75d475609 100644 --- a/Example/ChatWallet/ApplicationLayer/Application.swift +++ b/Example/ChatWallet/ApplicationLayer/Application.swift @@ -2,6 +2,8 @@ import Foundation import WalletConnectChat final class Application { + var uri: String? + lazy var chatService: ChatService = { return ChatService(client: Chat.instance) }() diff --git a/Example/ChatWallet/ApplicationLayer/Configurator/ApplicationConfigurator.swift b/Example/ChatWallet/ApplicationLayer/Configurator/ApplicationConfigurator.swift index 980cb6783..810260eef 100644 --- a/Example/ChatWallet/ApplicationLayer/Configurator/ApplicationConfigurator.swift +++ b/Example/ChatWallet/ApplicationLayer/Configurator/ApplicationConfigurator.swift @@ -11,6 +11,6 @@ struct ApplicationConfigurator: Configurator { } func configure() { - WalletModule.create(app: app).present() + WelcomeModule.create(app: app).present() } } diff --git a/Example/ChatWallet/ApplicationLayer/Configurator/ThirdPartyConfigurator.swift b/Example/ChatWallet/ApplicationLayer/Configurator/ThirdPartyConfigurator.swift index a8936517a..8e91759dd 100644 --- a/Example/ChatWallet/ApplicationLayer/Configurator/ThirdPartyConfigurator.swift +++ b/Example/ChatWallet/ApplicationLayer/Configurator/ThirdPartyConfigurator.swift @@ -3,7 +3,6 @@ import WalletConnectPairing import Auth struct ThirdPartyConfigurator: Configurator { - func configure() { Networking.configure(projectId: InputConfig.projectId, socketFactory: SocketFactory()) Pair.configure( @@ -15,7 +14,8 @@ struct ThirdPartyConfigurator: Configurator { )) Auth.configure( - account: Account("eip155:1:0xe5EeF1368781911d265fDB6946613dA61915a501")! + account: Account("eip155:1:0xe5EeF1368781911d265fDB6946613dA61915a501")!, + signerFactory: DefaultSignerFactory() ) } } diff --git a/Example/ChatWallet/ApplicationLayer/SceneDelegate.swift b/Example/ChatWallet/ApplicationLayer/SceneDelegate.swift index f05da13c4..76b9b72dd 100644 --- a/Example/ChatWallet/ApplicationLayer/SceneDelegate.swift +++ b/Example/ChatWallet/ApplicationLayer/SceneDelegate.swift @@ -27,15 +27,16 @@ final class SceneDelegate: UIResponder, UIWindowSceneDelegate { window = UIWindow(windowScene: windowScene) window?.makeKeyAndVisible() + + app.uri = connectionOptions.urlContexts.first?.url.absoluteString.replacingOccurrences(of: "chatwallet://wc?uri=", with: "") - print("Lolo") configurators.configure() } func scene(_ scene: UIScene, openURLContexts URLContexts: Set) { guard let context = URLContexts.first else { return } - let uri = context.url.absoluteString.replacingOccurrences(of: "showcase://wc?uri=", with: "") + let uri = context.url.absoluteString.replacingOccurrences(of: "chatwallet://wc?uri=", with: "") Task { try await Pair.instance.pair(uri: WalletConnectURI(string: uri)!) } diff --git a/Example/ChatWallet/Common/Components/BrandButton.swift b/Example/ChatWallet/Common/Components/BrandButton.swift deleted file mode 100644 index 85c02f614..000000000 --- a/Example/ChatWallet/Common/Components/BrandButton.swift +++ /dev/null @@ -1,20 +0,0 @@ -import SwiftUI - -struct BrandButton: View { - let title: String - let action: () -> Void - - var body: some View { - Button(action: { action() }, label: { - Text(title) - .foregroundColor(.w_foreground) - .font(.system(size: 20, weight: .bold)) - }) - .frame(maxWidth: .infinity) - .frame(height: 56) - .background( - Capsule() - .foregroundColor(.w_greenForground) - ) - } -} diff --git a/Example/ChatWallet/Common/Components/InputView.swift b/Example/ChatWallet/Common/Components/InputView.swift deleted file mode 100644 index 059f9ac6a..000000000 --- a/Example/ChatWallet/Common/Components/InputView.swift +++ /dev/null @@ -1,28 +0,0 @@ -import SwiftUI - -struct InputView: View { - - let title: String - let text: Binding - let action: () -> Void - - var body: some View { - ZStack { - TextField(title, text: text) - .disableAutocorrection(true) - .frame(minHeight: 44.0) - .padding(EdgeInsets(top: 0, leading: 16, bottom: 0, trailing: 16)) - .background( - Capsule() - .foregroundColor(.w_secondaryBackground) - ) - .overlay( - Capsule() - .stroke(Color.w_tertiaryBackground, lineWidth: 0.5) - ) - .onSubmit { - action() - } - } - } -} diff --git a/Example/ChatWallet/Common/Components/TextFieldView.swift b/Example/ChatWallet/Common/Components/TextFieldView.swift deleted file mode 100644 index da266d34f..000000000 --- a/Example/ChatWallet/Common/Components/TextFieldView.swift +++ /dev/null @@ -1,50 +0,0 @@ -import SwiftUI - -struct TextFieldView: View { - - let title: String - let placeholder: String - let input: Binding - - private var isClearVisible: Bool { - return input.wrappedValue.count > 0 - } - - var body: some View { - VStack(alignment: .leading) { - Text(title) - .font(.subheadline) - .foregroundColor(.w_secondaryForeground) - .padding(.horizontal, 16.0) - - HStack { - TextField(placeholder, text: input) - .font(.body) - .foregroundColor(.w_foreground) - .disableAutocorrection(true) - - if isClearVisible { - Button(action: { didPressClear() }) { - Image(systemName: "xmark.circle.fill") - .frame(width: 17.0, height: 17.0) - } - } - } - .padding(.horizontal, 16.0) - } - .frame(height: 72.0) - .background( - RoundedRectangle(cornerRadius: 14.0) - .foregroundColor(.w_secondaryBackground) - ) - .overlay( - RoundedRectangle(cornerRadius: 14.0) - .stroke(Color.w_tertiaryBackground, lineWidth: 0.5) - ) - .padding(16.0) - } - - private func didPressClear() { - input.wrappedValue = .empty - } -} diff --git a/Example/ChatWallet/Common/Extensions/UIKit/UIViewController.swift b/Example/ChatWallet/Common/Extensions/UIKit/UIViewController.swift index 288355439..c058d9ef6 100644 --- a/Example/ChatWallet/Common/Extensions/UIKit/UIViewController.swift +++ b/Example/ChatWallet/Common/Extensions/UIKit/UIViewController.swift @@ -22,6 +22,14 @@ extension UIViewController { func present(from viewController: UIViewController) { viewController.present(self, animated: true, completion: nil) } + + func presentFullScreen(from viewController: UIViewController, transparentBackground: Bool = false) { + if transparentBackground { + view.backgroundColor = .clear + } + modalPresentationStyle = .overCurrentContext + viewController.present(self, animated: true, completion: nil) + } func pop() { _ = navigationController?.popViewController(animated: true) diff --git a/Example/ChatWallet/Common/Helpers/UIPasteboardWrapper.swift b/Example/ChatWallet/Common/Helpers/UIPasteboardWrapper.swift index decdc722f..27820ea54 100644 --- a/Example/ChatWallet/Common/Helpers/UIPasteboardWrapper.swift +++ b/Example/ChatWallet/Common/Helpers/UIPasteboardWrapper.swift @@ -1,10 +1,3 @@ -// -// UIPasteboardWrapper.swift -// ChatWallet -// -// Created by Alexander Lisovyk on 06.12.22. -// - import Foundation import UIKit diff --git a/Example/ChatWallet/Common/InputConfig.swift b/Example/ChatWallet/Common/InputConfig.swift index 53931721a..1a4e505cf 100644 --- a/Example/ChatWallet/Common/InputConfig.swift +++ b/Example/ChatWallet/Common/InputConfig.swift @@ -1,7 +1,6 @@ import Foundation struct InputConfig { - static var projectId: String { return config(for: "PROJECT_ID")! } diff --git a/Example/ChatWallet/Common/Style/Color.swift b/Example/ChatWallet/Common/Style/Color.swift index 3e2ae042b..4ed71a5e9 100644 --- a/Example/ChatWallet/Common/Style/Color.swift +++ b/Example/ChatWallet/Common/Style/Color.swift @@ -1,19 +1,23 @@ import SwiftUI extension Color { - static let w_background: Color = Color(UIColor.w_background) - static let w_secondaryBackground: Color = Color(UIColor.w_secondaryBackground) - - static let w_tertiaryBackground: Color = Color(UIColor.w_tertiaryBackground) - - static let w_foreground: Color = Color(UIColor.w_foreground) - static let w_secondaryForeground: Color = Color(UIColor.w_secondaryForeground) - - static let w_purpleBackground: Color = Color(UIColor.w_purpleBackground) - static let w_purpleForeground: Color = Color(UIColor.w_purpleForeground) - - static let w_greenBackground: Color = Color(UIColor.w_greenBackground) - static let w_greenForground: Color = Color(UIColor.w_greenForground) + static let blue100 = Color("blue100") + static let blue200 = Color("blue200") + static let cyanBackround = Color("cyan-background") + static let translucentBackround = Color("translucent-background") + static let whiteBackground = Color("white-background") + static let lightBackground = Color("light-background") + static let grey8 = Color("grey8") + static let grey50 = Color("grey50") + static let grey70 = Color("grey70") + static let grey95 = Color("grey95") + static let grey100 = Color("grey100") + static let lightBlue = Color("light-blue") + static let lightForegroundNegative = Color("light-foreground-negative") + static let foregroundNegative = Color("foreground-negative") + static let lightForegroundPositive = Color("light-foreground-positive") + static let foregroundPositive = Color("foreground-positive") + static let systemGrayLight = Color("system-gray-light") } extension UIColor { diff --git a/Example/ChatWallet/Other/Assets.xcassets/connect-template.imageset/Contents.json b/Example/ChatWallet/Other/Assets.xcassets/connect-template.imageset/Contents.json new file mode 100644 index 000000000..b087841d7 --- /dev/null +++ b/Example/ChatWallet/Other/Assets.xcassets/connect-template.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "connect-template.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Example/ChatWallet/Other/Assets.xcassets/connect-template.imageset/connect-template.svg b/Example/ChatWallet/Other/Assets.xcassets/connect-template.imageset/connect-template.svg new file mode 100644 index 000000000..6295dcc53 --- /dev/null +++ b/Example/ChatWallet/Other/Assets.xcassets/connect-template.imageset/connect-template.svg @@ -0,0 +1,3 @@ + + + diff --git a/Example/ChatWallet/Other/Assets.xcassets/copy.imageset/Contents.json b/Example/ChatWallet/Other/Assets.xcassets/copy.imageset/Contents.json new file mode 100644 index 000000000..4a7bb95ea --- /dev/null +++ b/Example/ChatWallet/Other/Assets.xcassets/copy.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "copy.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Example/ChatWallet/Other/Assets.xcassets/copy.imageset/copy.svg b/Example/ChatWallet/Other/Assets.xcassets/copy.imageset/copy.svg new file mode 100644 index 000000000..7988f4062 --- /dev/null +++ b/Example/ChatWallet/Other/Assets.xcassets/copy.imageset/copy.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/Example/ChatWallet/Other/Assets.xcassets/forward-shevron.imageset/Contents.json b/Example/ChatWallet/Other/Assets.xcassets/forward-shevron.imageset/Contents.json new file mode 100644 index 000000000..92c5c6bf6 --- /dev/null +++ b/Example/ChatWallet/Other/Assets.xcassets/forward-shevron.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "forward-shevron.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "template" + } +} diff --git a/Example/ChatWallet/Other/Assets.xcassets/forward-shevron.imageset/forward-shevron.svg b/Example/ChatWallet/Other/Assets.xcassets/forward-shevron.imageset/forward-shevron.svg new file mode 100644 index 000000000..51ca50897 --- /dev/null +++ b/Example/ChatWallet/Other/Assets.xcassets/forward-shevron.imageset/forward-shevron.svg @@ -0,0 +1,3 @@ + + + diff --git a/Example/ChatWallet/Other/Assets.xcassets/foundation.imageset/Contents.json b/Example/ChatWallet/Other/Assets.xcassets/foundation.imageset/Contents.json new file mode 100644 index 000000000..42d7ff857 --- /dev/null +++ b/Example/ChatWallet/Other/Assets.xcassets/foundation.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "foundation.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Example/ChatWallet/Other/Assets.xcassets/foundation.imageset/foundation.svg b/Example/ChatWallet/Other/Assets.xcassets/foundation.imageset/foundation.svg new file mode 100644 index 000000000..d5568fe23 --- /dev/null +++ b/Example/ChatWallet/Other/Assets.xcassets/foundation.imageset/foundation.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/Example/ChatWallet/Other/Assets.xcassets/header.imageset/Contents.json b/Example/ChatWallet/Other/Assets.xcassets/header.imageset/Contents.json new file mode 100644 index 000000000..53a334d2d --- /dev/null +++ b/Example/ChatWallet/Other/Assets.xcassets/header.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "Visual.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Example/ChatWallet/Other/Assets.xcassets/header.imageset/Visual.svg b/Example/ChatWallet/Other/Assets.xcassets/header.imageset/Visual.svg new file mode 100644 index 000000000..08290c2ae --- /dev/null +++ b/Example/ChatWallet/Other/Assets.xcassets/header.imageset/Visual.svg @@ -0,0 +1,192 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Example/ChatWallet/Other/Assets.xcassets/scan.imageset/Contents.json b/Example/ChatWallet/Other/Assets.xcassets/scan.imageset/Contents.json new file mode 100644 index 000000000..653102307 --- /dev/null +++ b/Example/ChatWallet/Other/Assets.xcassets/scan.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "scan.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Example/ChatWallet/Other/Assets.xcassets/scan.imageset/scan.svg b/Example/ChatWallet/Other/Assets.xcassets/scan.imageset/scan.svg new file mode 100644 index 000000000..9f5649d72 --- /dev/null +++ b/Example/ChatWallet/Other/Assets.xcassets/scan.imageset/scan.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Example/ChatWallet/Other/Colors.xcassets/Contents.json b/Example/ChatWallet/Other/Colors.xcassets/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/Example/ChatWallet/Other/Colors.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Example/ChatWallet/Other/Colors.xcassets/blue100.colorset/Contents.json b/Example/ChatWallet/Other/Colors.xcassets/blue100.colorset/Contents.json new file mode 100644 index 000000000..241e42995 --- /dev/null +++ b/Example/ChatWallet/Other/Colors.xcassets/blue100.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "255", + "green" : "150", + "red" : "51" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xFF", + "green" : "0x96", + "red" : "0x33" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Example/ChatWallet/Other/Colors.xcassets/blue200.colorset/Contents.json b/Example/ChatWallet/Other/Colors.xcassets/blue200.colorset/Contents.json new file mode 100644 index 000000000..437b9e3f0 --- /dev/null +++ b/Example/ChatWallet/Other/Colors.xcassets/blue200.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "242", + "green" : "125", + "red" : "13" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.949", + "green" : "0.490", + "red" : "0.051" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Example/ChatWallet/Other/Colors.xcassets/cyan-background.colorset/Contents.json b/Example/ChatWallet/Other/Colors.xcassets/cyan-background.colorset/Contents.json new file mode 100644 index 000000000..c3e520b1d --- /dev/null +++ b/Example/ChatWallet/Other/Colors.xcassets/cyan-background.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xE5", + "green" : "0xAC", + "red" : "0x00" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xFF", + "green" : "0xC6", + "red" : "0x1A" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Example/ChatWallet/Other/Colors.xcassets/foreground-negative.colorset/Contents.json b/Example/ChatWallet/Other/Colors.xcassets/foreground-negative.colorset/Contents.json new file mode 100644 index 000000000..5fef43462 --- /dev/null +++ b/Example/ChatWallet/Other/Colors.xcassets/foreground-negative.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "103", + "green" : "90", + "red" : "242" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "103", + "green" : "90", + "red" : "242" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Example/ChatWallet/Other/Colors.xcassets/foreground-positive.colorset/Contents.json b/Example/ChatWallet/Other/Colors.xcassets/foreground-positive.colorset/Contents.json new file mode 100644 index 000000000..0e8a8da41 --- /dev/null +++ b/Example/ChatWallet/Other/Colors.xcassets/foreground-positive.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "108", + "green" : "238", + "red" : "43" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.424", + "green" : "0.933", + "red" : "0.169" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Example/ChatWallet/Other/Colors.xcassets/grey100.colorset/Contents.json b/Example/ChatWallet/Other/Colors.xcassets/grey100.colorset/Contents.json new file mode 100644 index 000000000..c8633f3f6 --- /dev/null +++ b/Example/ChatWallet/Other/Colors.xcassets/grey100.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "0.100", + "blue" : "0xFF", + "green" : "0xFF", + "red" : "0xFF" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "0.100", + "blue" : "0x14", + "green" : "0x14", + "red" : "0x14" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Example/ChatWallet/Other/Colors.xcassets/grey50.colorset/Contents.json b/Example/ChatWallet/Other/Colors.xcassets/grey50.colorset/Contents.json new file mode 100644 index 000000000..ec37b029c --- /dev/null +++ b/Example/ChatWallet/Other/Colors.xcassets/grey50.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x86", + "green" : "0x86", + "red" : "0x79" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x86", + "green" : "0x86", + "red" : "0x79" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Example/ChatWallet/Other/Colors.xcassets/grey70.colorset/Contents.json b/Example/ChatWallet/Other/Colors.xcassets/grey70.colorset/Contents.json new file mode 100644 index 000000000..066fa92e6 --- /dev/null +++ b/Example/ChatWallet/Other/Colors.xcassets/grey70.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xA9", + "green" : "0xA9", + "red" : "0x9E" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x86", + "green" : "0x86", + "red" : "0x79" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Example/ChatWallet/Other/Colors.xcassets/grey8.colorset/Contents.json b/Example/ChatWallet/Other/Colors.xcassets/grey8.colorset/Contents.json new file mode 100644 index 000000000..3142df2de --- /dev/null +++ b/Example/ChatWallet/Other/Colors.xcassets/grey8.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x14", + "green" : "0x14", + "red" : "0x14" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xE7", + "green" : "0xE7", + "red" : "0xE4" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Example/ChatWallet/Other/Colors.xcassets/grey95.colorset/Contents.json b/Example/ChatWallet/Other/Colors.xcassets/grey95.colorset/Contents.json new file mode 100644 index 000000000..c32b826d0 --- /dev/null +++ b/Example/ChatWallet/Other/Colors.xcassets/grey95.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xF3", + "green" : "0xF3", + "red" : "0xF1" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x2A", + "green" : "0x2A", + "red" : "0x27" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Example/ChatWallet/Other/Colors.xcassets/light-background.colorset/Contents.json b/Example/ChatWallet/Other/Colors.xcassets/light-background.colorset/Contents.json new file mode 100644 index 000000000..7db3262ea --- /dev/null +++ b/Example/ChatWallet/Other/Colors.xcassets/light-background.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "230", + "green" : "226", + "red" : "226" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "44", + "green" : "42", + "red" : "42" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Example/ChatWallet/Other/Colors.xcassets/light-blue.colorset/Contents.json b/Example/ChatWallet/Other/Colors.xcassets/light-blue.colorset/Contents.json new file mode 100644 index 000000000..914293344 --- /dev/null +++ b/Example/ChatWallet/Other/Colors.xcassets/light-blue.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xF8", + "green" : "0xF1", + "red" : "0xDD" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x47", + "green" : "0x3B", + "red" : "0x15" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Example/ChatWallet/Other/Colors.xcassets/light-foreground-negative.colorset/Contents.json b/Example/ChatWallet/Other/Colors.xcassets/light-foreground-negative.colorset/Contents.json new file mode 100644 index 000000000..5dd72bea9 --- /dev/null +++ b/Example/ChatWallet/Other/Colors.xcassets/light-foreground-negative.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "66", + "green" : "81", + "red" : "240" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "103", + "green" : "90", + "red" : "242" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Example/ChatWallet/Other/Colors.xcassets/light-foreground-positive.colorset/Contents.json b/Example/ChatWallet/Other/Colors.xcassets/light-foreground-positive.colorset/Contents.json new file mode 100644 index 000000000..f06599e88 --- /dev/null +++ b/Example/ChatWallet/Other/Colors.xcassets/light-foreground-positive.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "86", + "green" : "201", + "red" : "29" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "86", + "green" : "201", + "red" : "29" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Example/ChatWallet/Other/Colors.xcassets/system-gray-light.colorset/Contents.json b/Example/ChatWallet/Other/Colors.xcassets/system-gray-light.colorset/Contents.json new file mode 100644 index 000000000..2312e4873 --- /dev/null +++ b/Example/ChatWallet/Other/Colors.xcassets/system-gray-light.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x93", + "green" : "0x8E", + "red" : "0x8E" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x93", + "green" : "0x8E", + "red" : "0x8E" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Example/ChatWallet/Other/Colors.xcassets/white-background.colorset/Contents.json b/Example/ChatWallet/Other/Colors.xcassets/white-background.colorset/Contents.json new file mode 100644 index 000000000..0ba907fa8 --- /dev/null +++ b/Example/ChatWallet/Other/Colors.xcassets/white-background.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "255", + "green" : "255", + "red" : "255" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "30", + "green" : "28", + "red" : "28" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Example/ChatWallet/Other/Info.plist b/Example/ChatWallet/Other/Info.plist index 7bd0b9cde..72d30e44d 100644 --- a/Example/ChatWallet/Other/Info.plist +++ b/Example/ChatWallet/Other/Info.plist @@ -11,7 +11,7 @@ Editor CFBundleURLSchemes - showcase + chatwallet diff --git a/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestInteractor.swift b/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestInteractor.swift index c0c3a8bd3..a5bf87f41 100644 --- a/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestInteractor.swift +++ b/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestInteractor.swift @@ -3,10 +3,9 @@ import Auth import WalletConnectUtils final class AuthRequestInteractor { - func approve(request: AuthRequest) async throws { let privateKey = Data(hex: "e56da0e170b5e09a8bb8f1b693392c7d56c3739a9c75740fbc558a2877868540") - let signer = MessageSignerFactory.create() + let signer = MessageSignerFactory(signerFactory: DefaultSignerFactory()).create() let signature = try signer.sign(message: request.message, privateKey: privateKey, type: .eip191) try await Auth.instance.respond(requestId: request.id, signature: signature) } diff --git a/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestModule.swift b/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestModule.swift index 230e05bbc..b8e05863f 100644 --- a/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestModule.swift +++ b/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestModule.swift @@ -2,12 +2,11 @@ import SwiftUI import Auth final class AuthRequestModule { - @discardableResult static func create(app: Application, request: AuthRequest) -> UIViewController { let router = AuthRequestRouter(app: app) let interactor = AuthRequestInteractor() - let presenter = AuthRequestPresenter(request: request, interactor: interactor, router: router) + let presenter = AuthRequestPresenter(interactor: interactor, router: router, request: request) let view = AuthRequestView().environmentObject(presenter) let viewController = SceneViewController(viewModel: presenter, content: view) diff --git a/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestPresenter.swift b/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestPresenter.swift index f70700e86..41c8770bc 100644 --- a/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestPresenter.swift +++ b/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestPresenter.swift @@ -3,54 +3,48 @@ import Combine import Auth final class AuthRequestPresenter: ObservableObject { - - private let request: AuthRequest private let interactor: AuthRequestInteractor private let router: AuthRequestRouter + + private let request: AuthRequest + var message: String { + return request.message + } + private var disposeBag = Set() - init(request: AuthRequest, interactor: AuthRequestInteractor, router: AuthRequestRouter) { + init( + interactor: AuthRequestInteractor, + router: AuthRequestRouter, + request: AuthRequest + ) { defer { setupInitialState() } - self.request = request self.interactor = interactor self.router = router - } - - var message: String { - return request.message + self.request = request } @MainActor - func approvePressed() async throws { + func onApprove() async throws { try await interactor.approve(request: request) router.dismiss() } @MainActor - func rejectPressed() async throws { + func onReject() async throws { try await interactor.reject(request: request) router.dismiss() } } -// MARK: SceneViewModel - -extension AuthRequestPresenter: SceneViewModel { - - var sceneTitle: String? { - return "Auth Request" - } +// MARK: - Private functions +private extension AuthRequestPresenter { + func setupInitialState() { - var largeTitleDisplayMode: UINavigationItem.LargeTitleDisplayMode { - return .always } } -// MARK: Privates - -private extension AuthRequestPresenter { - - func setupInitialState() { +// MARK: - SceneViewModel +extension AuthRequestPresenter: SceneViewModel { - } } diff --git a/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestRouter.swift b/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestRouter.swift index 53d3d684e..a2d3fbd9d 100644 --- a/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestRouter.swift +++ b/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestRouter.swift @@ -1,7 +1,6 @@ import UIKit final class AuthRequestRouter { - weak var viewController: UIViewController! private let app: Application @@ -9,8 +8,9 @@ final class AuthRequestRouter { init(app: Application) { self.app = app } - + func dismiss() { viewController.navigationController?.dismiss() + UIApplication.shared.open(URL(string: "showcase://")!) } } diff --git a/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestView.swift b/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestView.swift index c8443c337..6fd2380df 100644 --- a/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestView.swift +++ b/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestView.swift @@ -1,54 +1,135 @@ import SwiftUI struct AuthRequestView: View { - @EnvironmentObject var presenter: AuthRequestPresenter - + + @State var text = "" + var body: some View { - VStack(spacing: 16.0) { - HStack { - Text("Message to sign:") - Spacer() - } - + ZStack { + Color.black.opacity(0.6) + VStack { - Text(presenter.message) - .font(Font.system(size: 13)) - .padding(16.0) - } - .background(Color.white.opacity(0.1)) - .cornerRadius(10) + Spacer() + + VStack(spacing: 0) { + Image("header") + .resizable() + .scaledToFit() + + Text("Foundation") + .foregroundColor(.grey8) + .font(.system(size: 22, weight: .bold, design: .rounded)) + .padding(.top, 10) + + Text("would like to connect") + .foregroundColor(.grey8) + .font(.system(size: 22, weight: .medium, design: .rounded)) + + Text("foundation.app") + .foregroundColor(.grey50) + .font(.system(size: 13, weight: .semibold, design: .rounded)) + .multilineTextAlignment(.center) + .lineSpacing(4) + .padding(.top, 8) + + VStack { + VStack(alignment: .leading) { + Text("Message") + .font(.system(size: 15, weight: .semibold, design: .rounded)) + .foregroundColor(.whiteBackground) + .padding(.horizontal, 8) + .padding(.vertical, 5) + .background(Color.grey70) + .cornerRadius(28, corners: .allCorners) + .padding(.leading, 15) + .padding(.top, 9) + + VStack(spacing: 0) { + HStack { + Text("presenter.message") + .foregroundColor(.grey50) + .font(.system(size: 13, weight: .semibold, design: .rounded)) + + Spacer() + } + .padding(.horizontal, 18) + .padding(.vertical, 10) + } + .background(Color.whiteBackground) + .cornerRadius(20, corners: .allCorners) + .padding(.horizontal, 5) + .padding(.bottom, 5) - HStack(spacing: 16.0) { - Button(action: { Task(priority: .userInitiated) { try await presenter.rejectPressed() }}, label: { - HStack(spacing: 8.0) { - Text("Reject") - .foregroundColor(.w_foreground) - .font(.system(size: 18, weight: .semibold)) + } + .background(.thinMaterial) + .cornerRadius(25, corners: .allCorners) } - }) - .frame(width: 120, height: 44) - .background( - Capsule() - .foregroundColor(.w_purpleForeground) - ) - - Button(action: { Task(priority: .userInitiated) { try await presenter.approvePressed() }}, label: { - HStack(spacing: 8.0) { - Text("Approve") - .foregroundColor(.w_foreground) - .font(.system(size: 18, weight: .semibold)) + .padding(.top, 30) + + HStack(spacing: 20) { + Button { + Task(priority: .userInitiated) { try await + presenter.onReject() + } + } label: { + Text("Decline") + .frame(maxWidth: .infinity) + .foregroundColor(.white) + .font(.system(size: 20, weight: .semibold, design: .rounded)) + .padding(.vertical, 11) + .background( + LinearGradient( + gradient: Gradient(colors: [ + .foregroundNegative, + .lightForegroundNegative + ]), + startPoint: .top, endPoint: .bottom) + ) + .cornerRadius(20) + } + .shadow(color: .white.opacity(0.25), radius: 8, y: 2) + + Button { + Task(priority: .userInitiated) { try await + presenter.onApprove() + } + } label: { + Text("Allow") + .frame(maxWidth: .infinity) + .foregroundColor(.white) + .font(.system(size: 20, weight: .semibold, design: .rounded)) + .padding(.vertical, 11) + .background( + LinearGradient( + gradient: Gradient(colors: [ + .foregroundPositive, + .lightForegroundPositive + ]), + startPoint: .top, endPoint: .bottom) + ) + .cornerRadius(20) + } + .shadow(color: .white.opacity(0.25), radius: 8, y: 2) } - }) - .frame(width: 120, height: 44) - .background( - Capsule() - .foregroundColor(.w_greenForground) - ) + .padding(.top, 25) + } + .padding(20) + .background(.ultraThinMaterial) + .cornerRadius(34) + .padding(.horizontal, 10) + + Spacer() } - - Spacer() } - .padding(16.0) + .edgesIgnoringSafeArea(.all) + } +} + +#if DEBUG +struct AuthRequestView_Previews: PreviewProvider { + static var previews: some View { + AuthRequestView() } } +#endif diff --git a/Example/Showcase/Classes/PresentationLayer/Wallet/Wallet/WalletInteractor.swift b/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsInteractor.swift similarity index 86% rename from Example/Showcase/Classes/PresentationLayer/Wallet/Wallet/WalletInteractor.swift rename to Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsInteractor.swift index 7379f18c5..fe9d868c9 100644 --- a/Example/Showcase/Classes/PresentationLayer/Wallet/Wallet/WalletInteractor.swift +++ b/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsInteractor.swift @@ -2,8 +2,7 @@ import Combine import Auth import WalletConnectPairing -final class WalletInteractor { - +final class ConnectionDetailsInteractor { func pair(uri: WalletConnectURI) async throws { try await Pair.instance.pair(uri: uri) } diff --git a/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsModule.swift b/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsModule.swift new file mode 100644 index 000000000..3dbb03006 --- /dev/null +++ b/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsModule.swift @@ -0,0 +1,16 @@ +import SwiftUI + +final class ConnectionDetailsModule { + @discardableResult + static func create(app: Application) -> UIViewController { + let router = ConnectionDetailsRouter(app: app) + let interactor = ConnectionDetailsInteractor() + let presenter = ConnectionDetailsPresenter(interactor: interactor, router: router) + let view = ConnectionDetailsView().environmentObject(presenter) + let viewController = SceneViewController(viewModel: presenter, content: view) + + router.viewController = viewController + + return viewController + } +} diff --git a/Example/Showcase/Classes/PresentationLayer/Wallet/Wallet/WalletPresenter.swift b/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsPresenter.swift similarity index 69% rename from Example/Showcase/Classes/PresentationLayer/Wallet/Wallet/WalletPresenter.swift rename to Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsPresenter.swift index ccf630ca8..7e19962a2 100644 --- a/Example/Showcase/Classes/PresentationLayer/Wallet/Wallet/WalletPresenter.swift +++ b/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsPresenter.swift @@ -2,13 +2,13 @@ import UIKit import Combine import Auth -final class WalletPresenter: ObservableObject { +final class ConnectionDetailsPresenter: ObservableObject { - private let interactor: WalletInteractor - private let router: WalletRouter + private let interactor: ConnectionDetailsInteractor + private let router: ConnectionDetailsRouter private var disposeBag = Set() - init(interactor: WalletInteractor, router: WalletRouter) { + init(interactor: ConnectionDetailsInteractor, router: ConnectionDetailsRouter) { defer { setupInitialState() } self.interactor = interactor self.router = router @@ -32,23 +32,8 @@ final class WalletPresenter: ObservableObject { } } -// MARK: SceneViewModel - -extension WalletPresenter: SceneViewModel { - - var sceneTitle: String? { - return "Wallet" - } - - var largeTitleDisplayMode: UINavigationItem.LargeTitleDisplayMode { - return .always - } -} - -// MARK: Privates - -private extension WalletPresenter { - +// MARK: - Private functions +private extension ConnectionDetailsPresenter { func setupInitialState() { interactor.requestPublisher.sink { [unowned self] request in self.router.present(request: request) @@ -61,3 +46,8 @@ private extension WalletPresenter { } } } + +// MARK: - SceneViewModel +extension ConnectionDetailsPresenter: SceneViewModel { + +} diff --git a/Example/Showcase/Classes/PresentationLayer/Wallet/Wallet/WalletRouter.swift b/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsRouter.swift similarity index 94% rename from Example/Showcase/Classes/PresentationLayer/Wallet/Wallet/WalletRouter.swift rename to Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsRouter.swift index 288f481f8..5b8be58c0 100644 --- a/Example/Showcase/Classes/PresentationLayer/Wallet/Wallet/WalletRouter.swift +++ b/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsRouter.swift @@ -1,8 +1,7 @@ import UIKit import Auth -final class WalletRouter { - +final class ConnectionDetailsRouter { weak var viewController: UIViewController! private let app: Application diff --git a/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsView.swift b/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsView.swift new file mode 100644 index 000000000..b0ff616e0 --- /dev/null +++ b/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsView.swift @@ -0,0 +1,155 @@ +import SwiftUI + +struct ConnectionDetailsView: View { + @EnvironmentObject var presenter: ConnectionDetailsPresenter + + var body: some View { + ScrollView { + VStack(spacing: 0) { + VStack(spacing: 2) { + Image("foundation") + .resizable() + .frame(width: 60, height: 60) + .background(Color.black) + .cornerRadius(30, corners: .allCorners) + .padding(.bottom, 6) + + Text("Foundation") + .foregroundColor(.grey8) + .font(.system(size: 22, weight: .bold, design: .rounded)) + + Text("foundation.app") + .foregroundColor(.grey50) + .font(.system(size: 13, weight: .medium, design: .rounded)) + } + + VStack { + VStack(alignment: .leading) { + Text("IEP155:1") + .font(.system(size: 15, weight: .semibold, design: .rounded)) + .foregroundColor(.whiteBackground) + .padding(.horizontal, 8) + .padding(.vertical, 5) + .background(Color.grey70) + .cornerRadius(28, corners: .allCorners) + .padding(.leading, 15) + .padding(.top, 9) + + VStack(spacing: 0) { + HStack { + Text("Accounts") + .foregroundColor(.grey50) + .font(.system(size: 13, weight: .semibold, design: .rounded)) + + Spacer() + + Button { + // action + } label: { + Text("Add Account") + .foregroundColor(.blue100) + .font(.system(size: 13, weight: .semibold, design: .rounded)) + } + } + .padding(.horizontal, 18) + .padding(.top, 10) + + VStack { + Text("eip:155:1:0xe5eFf13687819212d25665fdB6946613dA6195a501") + .foregroundColor(.cyanBackround) + .font(.system(size: 13, weight: .semibold, design: .rounded)) + .padding(.horizontal, 8) + .padding(.vertical, 3) + .background(Color.cyanBackround.opacity(0.2)) + .cornerRadius(10, corners: .allCorners) + } + .padding(10) + + } + .background(Color.whiteBackground) + .cornerRadius(20, corners: .allCorners) + .padding(.horizontal, 5) + + VStack(spacing: 0) { + HStack { + Text("Methods") + .foregroundColor(.grey50) + .font(.system(size: 13, weight: .semibold, design: .rounded)) + + Spacer() + } + .padding(.horizontal, 18) + .padding(.top, 10) + + VStack { + Text("eip:155:1:0xe5eFf13687819212d25665fdB6946613dA6195a501") + .foregroundColor(.cyanBackround) + .font(.system(size: 13, weight: .semibold, design: .rounded)) + .padding(.horizontal, 8) + .padding(.vertical, 3) + .background(Color.cyanBackround.opacity(0.2)) + .cornerRadius(10, corners: .allCorners) + } + .padding(10) + + } + .background(Color.whiteBackground) + .cornerRadius(20, corners: .allCorners) + .padding(.horizontal, 5) + + VStack(spacing: 0) { + HStack { + Text("Events") + .foregroundColor(.grey50) + .font(.system(size: 13, weight: .semibold, design: .rounded)) + + Spacer() + } + .padding(.horizontal, 18) + .padding(.top, 10) + + VStack { + Text("eip:155:1:0xe5eFf13687819212d25665fdB6946613dA6195a501") + .foregroundColor(.cyanBackround) + .font(.system(size: 13, weight: .regular)) + .padding(.horizontal, 8) + .padding(.vertical, 3) + .background(Color.cyanBackround.opacity(0.2)) + .cornerRadius(10, corners: .allCorners) + } + .padding(10) + + } + .background(Color.whiteBackground) + .cornerRadius(20, corners: .allCorners) + .padding(.horizontal, 5) + .padding(.bottom, 5) + } + .background(Color("grey95")) + .cornerRadius(25, corners: .allCorners) + } + .padding(.horizontal, 20) + .padding(.top, 30) + + Button { + // action + } label: { + Text("Delete") + .foregroundColor(.lightForegroundNegative) + .font(.system(size: 20, weight: .semibold, design: .rounded)) + } + .padding(.top, 20) + + Spacer() + } + } + } +} + +#if DEBUG +struct ConnectionDetailsView_Previews: PreviewProvider { + static var previews: some View { + ConnectionDetailsView() + } +} +#endif diff --git a/Example/ChatWallet/PresentationLayer/Wallet/PasteUri/PasteUriInteractor.swift b/Example/ChatWallet/PresentationLayer/Wallet/PasteUri/PasteUriInteractor.swift new file mode 100644 index 000000000..a489ba4cb --- /dev/null +++ b/Example/ChatWallet/PresentationLayer/Wallet/PasteUri/PasteUriInteractor.swift @@ -0,0 +1,3 @@ +final class PasteUriInteractor { + +} diff --git a/Example/Showcase/Classes/PresentationLayer/Wallet/Scan/ScanModule.swift b/Example/ChatWallet/PresentationLayer/Wallet/PasteUri/PasteUriModule.swift similarity index 51% rename from Example/Showcase/Classes/PresentationLayer/Wallet/Scan/ScanModule.swift rename to Example/ChatWallet/PresentationLayer/Wallet/PasteUri/PasteUriModule.swift index eac6302cd..1f425a710 100644 --- a/Example/Showcase/Classes/PresentationLayer/Wallet/Scan/ScanModule.swift +++ b/Example/ChatWallet/PresentationLayer/Wallet/PasteUri/PasteUriModule.swift @@ -1,22 +1,25 @@ import SwiftUI -final class ScanModule { - +final class PasteUriModule { @discardableResult static func create( app: Application, onValue: @escaping (String) -> Void, onError: @escaping (Error) -> Void ) -> UIViewController { - let router = ScanRouter(app: app) - let interactor = ScanInteractor() - let presenter = ScanPresenter(interactor: interactor, router: router, onValue: onValue, onError: onError) - let view = ScanView().environmentObject(presenter) + let router = PasteUriRouter(app: app) + let interactor = PasteUriInteractor() + let presenter = PasteUriPresenter( + interactor: interactor, + router: router, + onValue: onValue, + onError: onError + ) + let view = PasteUriView().environmentObject(presenter) let viewController = SceneViewController(viewModel: presenter, content: view) router.viewController = viewController return viewController } - } diff --git a/Example/ChatWallet/PresentationLayer/Wallet/PasteUri/PasteUriPresenter.swift b/Example/ChatWallet/PresentationLayer/Wallet/PasteUri/PasteUriPresenter.swift new file mode 100644 index 000000000..cf011016b --- /dev/null +++ b/Example/ChatWallet/PresentationLayer/Wallet/PasteUri/PasteUriPresenter.swift @@ -0,0 +1,38 @@ +import UIKit +import Combine + +final class PasteUriPresenter: ObservableObject { + private let interactor: PasteUriInteractor + private let router: PasteUriRouter + private var disposeBag = Set() + + let onValue: (String) -> Void + let onError: (Error) -> Void + + init( + interactor: PasteUriInteractor, + router: PasteUriRouter, + onValue: @escaping (String) -> Void, + onError: @escaping (Error) -> Void + ) { + defer { + setupInitialState() + } + self.interactor = interactor + self.router = router + self.onValue = onValue + self.onError = onError + } +} + +// MARK: - Private functions +extension PasteUriPresenter { + private func setupInitialState() { + + } +} + +// MARK: - SceneViewModel +extension PasteUriPresenter: SceneViewModel { + +} diff --git a/Example/Showcase/Classes/PresentationLayer/Wallet/Scan/ScanRouter.swift b/Example/ChatWallet/PresentationLayer/Wallet/PasteUri/PasteUriRouter.swift similarity index 84% rename from Example/Showcase/Classes/PresentationLayer/Wallet/Scan/ScanRouter.swift rename to Example/ChatWallet/PresentationLayer/Wallet/PasteUri/PasteUriRouter.swift index eef0df5c6..ac1bb11bb 100644 --- a/Example/Showcase/Classes/PresentationLayer/Wallet/Scan/ScanRouter.swift +++ b/Example/ChatWallet/PresentationLayer/Wallet/PasteUri/PasteUriRouter.swift @@ -1,7 +1,6 @@ import UIKit -final class ScanRouter { - +final class PasteUriRouter { weak var viewController: UIViewController! private let app: Application diff --git a/Example/ChatWallet/PresentationLayer/Wallet/PasteUri/PasteUriView.swift b/Example/ChatWallet/PresentationLayer/Wallet/PasteUri/PasteUriView.swift new file mode 100644 index 000000000..f64b9886e --- /dev/null +++ b/Example/ChatWallet/PresentationLayer/Wallet/PasteUri/PasteUriView.swift @@ -0,0 +1,100 @@ +import SwiftUI + +private enum FocusField: Hashable { + case uriField +} + +struct PasteUriView: View { + @Environment(\.dismiss) var dismiss + + @State var text = "" + + var body: some View { + ZStack { + Color(red: 20/255, green: 20/255, blue: 20/255, opacity: 0.4) + VStack { + Spacer() + VStack(spacing: 6) { + Text("Enter a WalletConnect URI") + .foregroundColor(.grey8) + .font(.system(size: 22, weight: .bold, design: .rounded)) + + Text("To get the URI press the 􀐅 copy to clipboard button in wallet connection interfaces.") + .foregroundColor(.grey50) + .font(.system(size: 15, weight: .medium, design: .rounded)) + .multilineTextAlignment(.center) + .lineSpacing(4) + + ZStack { + RoundedRectangle(cornerRadius: 15) + .fill(Color.whiteBackground) + + HStack { + TextField("wc://a13aef...", text: $text) + //.focused($focusedField, equals: .field) + .padding(.horizontal, 17) + .foregroundColor(.grey50) + .font(.system(size: 17, weight: .regular, design: .rounded)) + + Button { + // + } label: { + Image(systemName: "xmark.circle.fill") + .foregroundColor(.systemGrayLight) + } + .padding(.trailing, 12) + } + } + .frame(height: 44) + .padding(.top, 20) + .ignoresSafeArea(.keyboard) + + Button { + // + } label: { + Text("Connect") + .frame(maxWidth: .infinity) + .foregroundColor(.white) + .font(.system(size: 20, weight: .semibold, design: .rounded)) + .padding(.vertical, 11) + .background( + LinearGradient( + gradient: Gradient(colors: [ + .blue100, + .blue200 + ]), + startPoint: .top, endPoint: .bottom) + ) + .cornerRadius(20) + } + .padding(.top, 20) + .shadow(color: .white.opacity(0.25), radius: 8, y: 2) + + Button { + dismiss() + } label: { + Text("Cancel") + .frame(maxWidth: .infinity) + .foregroundColor(.blue100) + .font(.system(size: 20, weight: .semibold, design: .rounded)) + } + .padding(.top, 20) + } + .padding(20) + .background(Color.lightBackground) + .cornerRadius(34) + .padding(.horizontal, 10) + } + .padding(.bottom, 20) + } + .edgesIgnoringSafeArea(.top) + } +} + +#if DEBUG +struct PasteUriView_Previews: PreviewProvider { + static var previews: some View { + PasteUriView() + } +} +#endif diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletInteractor.swift b/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletInteractor.swift index c7973b7d4..e16c8dec3 100644 --- a/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletInteractor.swift +++ b/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletInteractor.swift @@ -2,66 +2,12 @@ import Combine import Auth import WalletConnectPairing -protocol WalletInteractorProtocol { - func onAppear() - func pastePairingUri() async - func scanPairingUri() -} - -final class WalletInteractor: WalletInteractorProtocol { - private var disposeBag = Set() - - private weak var presenter: WalletPresenter? - private let router: WalletRouter - - private var requestPublisher: AnyPublisher { - return Auth.instance.authRequestPublisher - } - - init( - presenter: WalletPresenter, - router: WalletRouter - ) { - self.presenter = presenter - self.router = router - } - - func onAppear() { - requestPublisher.sink { [weak self] request in - self?.router.present(request: request) - }.store(in: &disposeBag) - } - - func pastePairingUri() async { - guard let string = UIPasteboardWrapper.string, - let uri = WalletConnectURI(string: string) - else { - return - } - try? await pair(uri: uri) - } - - func scanPairingUri() { - router.presentScan { [weak self] value in - guard let self, - let uri = WalletConnectURI(string: value) else { - return - } - - Task { - try? await self.pair(uri: uri) - } - self.router.dismiss() - } onError: { [weak self] error in - print(error.localizedDescription) - self?.router.dismiss() - } +final class WalletInteractor { + func pair(uri: WalletConnectURI) async throws { + try await Pair.instance.pair(uri: uri) } -} -// MARK: - Private functions -extension WalletInteractor { - private func pair(uri: WalletConnectURI) async throws { - try await Pair.instance.pair(uri: uri) + var requestPublisher: AnyPublisher { + return Auth.instance.authRequestPublisher } } diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletModule.swift b/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletModule.swift index 420b03271..534e5f676 100644 --- a/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletModule.swift +++ b/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletModule.swift @@ -4,9 +4,9 @@ final class WalletModule { @discardableResult static func create(app: Application) -> UIViewController { let router = WalletRouter(app: app) - let presenter = WalletPresenter() - let interactor = WalletInteractor(presenter: presenter, router: router) - let view = WalletView(interactor: interactor, presenter: presenter) + let interactor = WalletInteractor() + let presenter = WalletPresenter(interactor: interactor, router: router, uri: app.uri) + let view = WalletView().environmentObject(presenter) let viewController = SceneViewController(viewModel: presenter, content: view) router.viewController = viewController diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletPresenter.swift b/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletPresenter.swift index 2122cac48..c2ef79e03 100644 --- a/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletPresenter.swift +++ b/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletPresenter.swift @@ -3,16 +3,86 @@ import Combine import Auth final class WalletPresenter: ObservableObject { + private let interactor: WalletInteractor + private let router: WalletRouter + + private let uri: String? + private var disposeBag = Set() + + init( + interactor: WalletInteractor, + router: WalletRouter, + uri: String? + ) { + defer { + setupInitialState() + } + self.interactor = interactor + self.router = router + self.uri = uri + } - @Published var pastPairingUriText = "Paste pairing URI" - @Published var scanPairingUriText = "Scan pairing URI" + func onConnection() { + router.presentConnectionDetails() + } + + func onPasteUri() { + router.presentPaste { [weak self] uri in + guard let uri = WalletConnectURI(string: uri) else { + return + } + print(uri) + self?.pair(uri: uri) + + } onError: { [weak self] error in + print(error.localizedDescription) + self?.router.dismiss() + } + } + + func onScanUri() { + router.presentScan { [unowned self] value in + guard let uri = WalletConnectURI(string: value) else { return } + self.pair(uri: uri) + self.router.dismiss() + } onError: { error in + print(error.localizedDescription) + self.router.dismiss() + } + } +} + +// MARK: - Private functions +extension WalletPresenter { + private func setupInitialState() { + interactor.requestPublisher.sink { [unowned self] request in + self.router.present(request: request) + }.store(in: &disposeBag) + + pairFropDapp() + } + + private func pair(uri: WalletConnectURI) { + Task(priority: .high) { [unowned self] in + try await self.interactor.pair(uri: uri) + } + } + + private func pairFropDapp() { + guard let uri = uri, + let walletConnectUri = WalletConnectURI(string: uri) + else { + return + } + pair(uri: walletConnectUri) + } } // MARK: - SceneViewModel extension WalletPresenter: SceneViewModel { var sceneTitle: String? { - return "Wallet" + return "Connections" } var largeTitleDisplayMode: UINavigationItem.LargeTitleDisplayMode { diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletRouter.swift b/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletRouter.swift index 0935b5958..07563d4f0 100644 --- a/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletRouter.swift +++ b/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletRouter.swift @@ -12,8 +12,17 @@ final class WalletRouter { func present(request: AuthRequest) { AuthRequestModule.create(app: app, request: request) - .wrapToNavigationController() - .present(from: viewController) + .presentFullScreen(from: viewController, transparentBackground: true) + } + + func presentPaste(onValue: @escaping (String) -> Void, onError: @escaping (Error) -> Void) { + PasteUriModule.create(app: app, onValue: onValue, onError: onError) + .presentFullScreen(from: viewController, transparentBackground: true) + } + + func presentConnectionDetails() { + ConnectionDetailsModule.create(app: app) + .push(from: viewController) } func presentScan(onValue: @escaping (String) -> Void, onError: @escaping (Error) -> Void) { diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletView.swift b/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletView.swift index a7a1ffe7e..b37592209 100644 --- a/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletView.swift +++ b/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletView.swift @@ -1,65 +1,94 @@ import SwiftUI struct WalletView: View { - let interactor: WalletInteractorProtocol - @ObservedObject var presenter: WalletPresenter + @EnvironmentObject var presenter: WalletPresenter var body: some View { - VStack(spacing: 16) { - Button { - Task { - await interactor.pastePairingUri() + VStack(alignment: .leading, spacing: 16) { + ZStack { + if false { + VStack(spacing: 10) { + Image("connect-template") + + Text("Apps you connect with will appear here. To connect 􀎹 scan or 􀐅 paste the code that’s displayed in the app.") + .foregroundColor(.grey50) + .font(.system(size: 15, weight: .regular, design: .rounded)) + .multilineTextAlignment(.center) + .lineSpacing(4) + } } - } label: { - HStack(spacing: 8.0) { - Text(presenter.pastPairingUriText) - .foregroundColor(.w_foreground) - .font(.system(size: 18, weight: .semibold)) + + VStack { + ScrollView { + connectionView() + connectionView() + connectionView() + connectionView() + } + + HStack(spacing: 20) { + Spacer() + + Button { + presenter.onPasteUri() + } label: { + Image("copy") + .resizable() + .frame(width: 56, height: 56) + } + .shadow(color: .black.opacity(0.25), radius: 8, y: 4) + + Button { + presenter.onScanUri() + } label: { + Image("scan") + .resizable() + .frame(width: 56, height: 56) + } + .shadow(color: .black.opacity(0.25), radius: 8, y: 4) + } } - .padding(.trailing, 8.0) } - .frame(width: 200, height: 44) - .background( - Capsule() - .foregroundColor(.w_greenForground) - ) - - Button { - interactor.scanPairingUri() - } label: { - HStack(spacing: 8.0) { - Text(presenter.scanPairingUriText) - .foregroundColor(.w_foreground) - .font(.system(size: 18, weight: .semibold)) + } + .padding(20) + } + + private func connectionView() -> some View { + Button { + presenter.onConnection() + } label: { + VStack { + HStack(spacing: 10) { + Image("foundation") + .resizable() + .frame(width: 60, height: 60) + .background(Color.black) + .cornerRadius(30, corners: .allCorners) + + VStack(alignment: .leading, spacing: 2) { + Text("Foundation") + .foregroundColor(.grey8) + .font(.system(size: 20, weight: .semibold, design: .rounded)) + + Text("foundation.app") + .foregroundColor(.grey50) + .font(.system(size: 13, weight: .medium, design: .rounded)) + } + + Spacer() + + Image("forward-shevron") + .foregroundColor(.grey8) } - .padding(.trailing, 8.0) } - .frame(width: 200, height: 44) - .background( - Capsule() - .foregroundColor(.w_purpleForeground) - ) - } - .onAppear { - interactor.onAppear() } } } #if DEBUG -final class WalletInteractorMock: WalletInteractorProtocol { - func onAppear() {} - func pastePairingUri() async {} - func scanPairingUri() {} -} - struct WalletView_Previews: PreviewProvider { static var previews: some View { - let presenter = WalletPresenter() - WalletView( - interactor: WalletInteractorMock(), - presenter: presenter - ) + WalletView() } } #endif diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Welcome/WelcomeInteractor.swift b/Example/ChatWallet/PresentationLayer/Wallet/Welcome/WelcomeInteractor.swift new file mode 100644 index 000000000..95934398d --- /dev/null +++ b/Example/ChatWallet/PresentationLayer/Wallet/Welcome/WelcomeInteractor.swift @@ -0,0 +1,3 @@ +final class WelcomeInteractor { + +} diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Welcome/WelcomeModule.swift b/Example/ChatWallet/PresentationLayer/Wallet/Welcome/WelcomeModule.swift new file mode 100644 index 000000000..000f8e651 --- /dev/null +++ b/Example/ChatWallet/PresentationLayer/Wallet/Welcome/WelcomeModule.swift @@ -0,0 +1,16 @@ +import SwiftUI + +final class WelcomeModule { + @discardableResult + static func create(app: Application) -> UIViewController { + let router = WelcomeRouter(app: app) + let interactor = WelcomeInteractor() + let presenter = WelcomePresenter(interactor: interactor, router: router) + let view = WelcomeView().environmentObject(presenter) + let viewController = SceneViewController(viewModel: presenter, content: view) + + router.viewController = viewController + + return viewController + } +} diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Welcome/WelcomePresenter.swift b/Example/ChatWallet/PresentationLayer/Wallet/Welcome/WelcomePresenter.swift new file mode 100644 index 000000000..31381569c --- /dev/null +++ b/Example/ChatWallet/PresentationLayer/Wallet/Welcome/WelcomePresenter.swift @@ -0,0 +1,32 @@ +import UIKit +import Combine + +final class WelcomePresenter: ObservableObject { + private let interactor: WelcomeInteractor + private let router: WelcomeRouter + private var disposeBag = Set() + + init(interactor: WelcomeInteractor, router: WelcomeRouter) { + defer { + setupInitialState() + } + self.interactor = interactor + self.router = router + } + + func onGetStarted() { + router.presentWallet() + } +} + +// MARK: Private functions +extension WelcomePresenter { + private func setupInitialState() { + + } +} + +// MARK: - SceneViewModel +extension WelcomePresenter: SceneViewModel { + +} diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Welcome/WelcomeRouter.swift b/Example/ChatWallet/PresentationLayer/Wallet/Welcome/WelcomeRouter.swift new file mode 100644 index 000000000..9ebd6c7bf --- /dev/null +++ b/Example/ChatWallet/PresentationLayer/Wallet/Welcome/WelcomeRouter.swift @@ -0,0 +1,17 @@ +import UIKit + +final class WelcomeRouter { + weak var viewController: UIViewController! + + private let app: Application + + init(app: Application) { + self.app = app + } + + func presentWallet() { + WalletModule.create(app: app) + .wrapToNavigationController() + .presentFullScreen(from: viewController) + } +} diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Welcome/WelcomeView.swift b/Example/ChatWallet/PresentationLayer/Wallet/Welcome/WelcomeView.swift new file mode 100644 index 000000000..e6bf21b0a --- /dev/null +++ b/Example/ChatWallet/PresentationLayer/Wallet/Welcome/WelcomeView.swift @@ -0,0 +1,57 @@ +import SwiftUI + +struct WelcomeView: View { + @EnvironmentObject var presenter: WelcomePresenter + + @State private var presentWallet = false + + var body: some View { + ZStack { + VStack(spacing: 0) { + Text("Welcome") + .foregroundColor(.grey8) + .font(.system(size: 34, weight: .bold, design: .rounded)) + + Text("We made this Example Wallet App to help developers integrate the WalletConnect SDK and provide an amazing experience to their users.") + .foregroundColor(.grey50) + .font(.system(size: 15, weight: .medium, design: .rounded)) + .multilineTextAlignment(.center) + .lineSpacing(3) + .padding(.top, 10) + + Spacer() + + Button { + presenter.onGetStarted() + } label: { + Text("Get Started") + .frame(maxWidth: .infinity) + .foregroundColor(.white) + .font(.system(size: 20, weight: .semibold, design: .rounded)) + .padding(.vertical, 15) + .background( + LinearGradient( + gradient: Gradient(colors: [ + .blue100, + .blue200 + ]), + startPoint: .top, endPoint: .bottom) + ) + .cornerRadius(20) + } + .padding(.top, 20) + .shadow(color: .white.opacity(0.25), radius: 8, y: 2) + .fullScreenCover(isPresented: $presentWallet, content: WalletView.init) + } + .padding([.horizontal, .vertical], 20) + } + } +} + +#if DEBUG +struct WelcomeView_Previews: PreviewProvider { + static var previews: some View { + WelcomeView() + } +} +#endif diff --git a/Example/ExampleApp.xcodeproj/project.pbxproj b/Example/ExampleApp.xcodeproj/project.pbxproj index 76776cdb1..e423ea719 100644 --- a/Example/ExampleApp.xcodeproj/project.pbxproj +++ b/Example/ExampleApp.xcodeproj/project.pbxproj @@ -64,14 +64,6 @@ A54195A12934BFEF0035AD19 /* EIP191VerifierTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A541959D2934BFEF0035AD19 /* EIP191VerifierTests.swift */; }; A54195A52934E83F0035AD19 /* Web3 in Frameworks */ = {isa = PBXBuildFile; productRef = A54195A42934E83F0035AD19 /* Web3 */; }; A5434023291E6A270068F706 /* SolanaSwift in Frameworks */ = {isa = PBXBuildFile; productRef = A5434022291E6A270068F706 /* SolanaSwift */; }; - A55CAAB028B92AFF00844382 /* ScanModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = A55CAAAB28B92AFF00844382 /* ScanModule.swift */; }; - A55CAAB128B92AFF00844382 /* ScanPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A55CAAAC28B92AFF00844382 /* ScanPresenter.swift */; }; - A55CAAB228B92AFF00844382 /* ScanRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A55CAAAD28B92AFF00844382 /* ScanRouter.swift */; }; - A55CAAB328B92AFF00844382 /* ScanInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = A55CAAAE28B92AFF00844382 /* ScanInteractor.swift */; }; - A55CAAB428B92AFF00844382 /* ScanView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A55CAAAF28B92AFF00844382 /* ScanView.swift */; }; - A55CAAB928B92B4600844382 /* ScanQRView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A55CAAB628B92B4600844382 /* ScanQRView.swift */; }; - A55CAABA28B92B4600844382 /* ScanTargetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A55CAAB728B92B4600844382 /* ScanTargetView.swift */; }; - A55CAABB28B92B4600844382 /* ScanQR.swift in Sources */ = {isa = PBXBuildFile; fileRef = A55CAAB828B92B4600844382 /* ScanQR.swift */; }; A5629AA92876A23100094373 /* ChatService.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5629AA82876A23100094373 /* ChatService.swift */; }; A5629ABD2876CBC000094373 /* ChatListModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5629AB82876CBC000094373 /* ChatListModule.swift */; }; A5629ABE2876CBC000094373 /* ChatListPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5629AB92876CBC000094373 /* ChatListPresenter.swift */; }; @@ -126,16 +118,6 @@ A58E7D452872EE570082D443 /* ContentMessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A58E7D442872EE570082D443 /* ContentMessageView.swift */; }; A58E7D482872EF610082D443 /* MessageViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A58E7D472872EF610082D443 /* MessageViewModel.swift */; }; A59CF4F6292F83D50031A42F /* DefaultSignerFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59CF4F5292F83D50031A42F /* DefaultSignerFactory.swift */; }; - A59EBEF828B54A2A003EDAAF /* AuthRequestModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59EBEF328B54A2A003EDAAF /* AuthRequestModule.swift */; }; - A59EBEF928B54A2A003EDAAF /* AuthRequestPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59EBEF428B54A2A003EDAAF /* AuthRequestPresenter.swift */; }; - A59EBEFA28B54A2A003EDAAF /* AuthRequestRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59EBEF528B54A2A003EDAAF /* AuthRequestRouter.swift */; }; - A59EBEFB28B54A2A003EDAAF /* AuthRequestInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59EBEF628B54A2A003EDAAF /* AuthRequestInteractor.swift */; }; - A59EBEFC28B54A2A003EDAAF /* AuthRequestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59EBEF728B54A2A003EDAAF /* AuthRequestView.swift */; }; - A59F876F28B53EA000A9CD80 /* WalletModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59F876A28B53EA000A9CD80 /* WalletModule.swift */; }; - A59F877028B53EA000A9CD80 /* WalletPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59F876B28B53EA000A9CD80 /* WalletPresenter.swift */; }; - A59F877128B53EA000A9CD80 /* WalletRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59F876C28B53EA000A9CD80 /* WalletRouter.swift */; }; - A59F877228B53EA000A9CD80 /* WalletInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59F876D28B53EA000A9CD80 /* WalletInteractor.swift */; }; - A59F877328B53EA000A9CD80 /* WalletView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59F876E28B53EA000A9CD80 /* WalletView.swift */; }; A59F877628B5462900A9CD80 /* WalletConnectAuth in Frameworks */ = {isa = PBXBuildFile; productRef = A59F877528B5462900A9CD80 /* WalletConnectAuth */; }; A59FAEC928B7B93A002BB66F /* Web3 in Frameworks */ = {isa = PBXBuildFile; productRef = A59FAEC828B7B93A002BB66F /* Web3 */; }; A5A4FC56283CBB7800BBEC1E /* SessionDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5A4FC55283CBB7800BBEC1E /* SessionDetailView.swift */; }; @@ -191,36 +173,46 @@ A5E22D222840C8D300E36487 /* WalletEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5E22D212840C8D300E36487 /* WalletEngine.swift */; }; A5E22D242840C8DB00E36487 /* SafariEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5E22D232840C8DB00E36487 /* SafariEngine.swift */; }; A5E22D2C2840EAC300E36487 /* XCUIElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5E22D2B2840EAC300E36487 /* XCUIElement.swift */; }; + C5133A78294125CC00A8314C /* Web3 in Frameworks */ = {isa = PBXBuildFile; productRef = C5133A77294125CC00A8314C /* Web3 */; }; + C53AA435294124BC008EA57C /* SocketFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = C53AA434294124B3008EA57C /* SocketFactory.swift */; }; + C53AA4362941251C008EA57C /* DefaultSignerFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59CF4F5292F83D50031A42F /* DefaultSignerFactory.swift */; }; + C55D347F295DD7140004314A /* AuthRequestModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D347A295DD7140004314A /* AuthRequestModule.swift */; }; + C55D3480295DD7140004314A /* AuthRequestPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D347B295DD7140004314A /* AuthRequestPresenter.swift */; }; + C55D3481295DD7140004314A /* AuthRequestRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D347C295DD7140004314A /* AuthRequestRouter.swift */; }; + C55D3482295DD7140004314A /* AuthRequestInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D347D295DD7140004314A /* AuthRequestInteractor.swift */; }; + C55D3483295DD7140004314A /* AuthRequestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D347E295DD7140004314A /* AuthRequestView.swift */; }; + C55D3489295DD8CA0004314A /* PasteUriModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D3484295DD8CA0004314A /* PasteUriModule.swift */; }; + C55D348A295DD8CA0004314A /* PasteUriPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D3485295DD8CA0004314A /* PasteUriPresenter.swift */; }; + C55D348B295DD8CA0004314A /* PasteUriRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D3486295DD8CA0004314A /* PasteUriRouter.swift */; }; + C55D348C295DD8CA0004314A /* PasteUriInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D3487295DD8CA0004314A /* PasteUriInteractor.swift */; }; + C55D348D295DD8CA0004314A /* PasteUriView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D3488295DD8CA0004314A /* PasteUriView.swift */; }; + C55D3493295DFA750004314A /* WelcomeModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D348E295DFA750004314A /* WelcomeModule.swift */; }; + C55D3494295DFA750004314A /* WelcomePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D348F295DFA750004314A /* WelcomePresenter.swift */; }; + C55D3495295DFA750004314A /* WelcomeRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D3490295DFA750004314A /* WelcomeRouter.swift */; }; + C55D3496295DFA750004314A /* WelcomeInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D3491295DFA750004314A /* WelcomeInteractor.swift */; }; + C55D3497295DFA750004314A /* WelcomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D3492295DFA750004314A /* WelcomeView.swift */; }; C56EE222293F55EE004840D1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C56EE221293F55EE004840D1 /* Assets.xcassets */; }; C56EE240293F566D004840D1 /* ScanQRView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE23F293F566C004840D1 /* ScanQRView.swift */; }; C56EE241293F566D004840D1 /* WalletModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE22D293F5669004840D1 /* WalletModule.swift */; }; C56EE242293F566D004840D1 /* ScanPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE23B293F566C004840D1 /* ScanPresenter.swift */; }; C56EE243293F566D004840D1 /* ScanView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE23A293F566B004840D1 /* ScanView.swift */; }; - C56EE244293F566D004840D1 /* AuthRequestRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE234293F566A004840D1 /* AuthRequestRouter.swift */; }; C56EE245293F566D004840D1 /* WalletPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE22C293F5668004840D1 /* WalletPresenter.swift */; }; C56EE246293F566D004840D1 /* ScanRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE239293F566B004840D1 /* ScanRouter.swift */; }; C56EE247293F566D004840D1 /* ScanModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE237293F566B004840D1 /* ScanModule.swift */; }; C56EE248293F566D004840D1 /* ScanQR.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE23E293F566C004840D1 /* ScanQR.swift */; }; C56EE249293F566D004840D1 /* ScanInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE238293F566B004840D1 /* ScanInteractor.swift */; }; - C56EE24A293F566D004840D1 /* AuthRequestModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE235293F566A004840D1 /* AuthRequestModule.swift */; }; - C56EE24B293F566D004840D1 /* AuthRequestPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE233293F566A004840D1 /* AuthRequestPresenter.swift */; }; - C56EE24C293F566D004840D1 /* AuthRequestInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE231293F5669004840D1 /* AuthRequestInteractor.swift */; }; C56EE24D293F566D004840D1 /* WalletRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE22E293F5669004840D1 /* WalletRouter.swift */; }; C56EE24E293F566D004840D1 /* WalletInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE22F293F5669004840D1 /* WalletInteractor.swift */; }; C56EE24F293F566D004840D1 /* WalletView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE22B293F5668004840D1 /* WalletView.swift */; }; C56EE250293F566D004840D1 /* ScanTargetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE23D293F566C004840D1 /* ScanTargetView.swift */; }; - C56EE251293F566D004840D1 /* AuthRequestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE232293F566A004840D1 /* AuthRequestView.swift */; }; C56EE255293F569A004840D1 /* Starscream in Frameworks */ = {isa = PBXBuildFile; productRef = C56EE254293F569A004840D1 /* Starscream */; }; C56EE26F293F56D7004840D1 /* Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE266293F56D6004840D1 /* Types.swift */; }; C56EE270293F56D7004840D1 /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE26A293F56D6004840D1 /* String.swift */; }; C56EE271293F56D7004840D1 /* View.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE26E293F56D7004840D1 /* View.swift */; }; - C56EE272293F56D7004840D1 /* TextFieldView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE260293F56D6004840D1 /* TextFieldView.swift */; }; C56EE273293F56D7004840D1 /* UIColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE26B293F56D6004840D1 /* UIColor.swift */; }; C56EE274293F56D7004840D1 /* SceneViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE264293F56D6004840D1 /* SceneViewController.swift */; }; C56EE275293F56D7004840D1 /* InputConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE25D293F56D6004840D1 /* InputConfig.swift */; }; C56EE276293F56D7004840D1 /* UIViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE26C293F56D6004840D1 /* UIViewController.swift */; }; - C56EE277293F56D7004840D1 /* BrandButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE261293F56D6004840D1 /* BrandButton.swift */; }; - C56EE278293F56D7004840D1 /* InputView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE25F293F56D6004840D1 /* InputView.swift */; }; C56EE279293F56D7004840D1 /* Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE268293F56D6004840D1 /* Color.swift */; }; C56EE27B293F56F8004840D1 /* WalletConnectAuth in Frameworks */ = {isa = PBXBuildFile; productRef = C56EE27A293F56F8004840D1 /* WalletConnectAuth */; }; C56EE27D293F56F8004840D1 /* WalletConnectChat in Frameworks */ = {isa = PBXBuildFile; productRef = C56EE27C293F56F8004840D1 /* WalletConnectChat */; }; @@ -238,6 +230,12 @@ C56EE29C293F5773004840D1 /* ChatService.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE295293F5773004840D1 /* ChatService.swift */; }; C56EE29D293F5773004840D1 /* RegisterService.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE294293F5773004840D1 /* RegisterService.swift */; }; C56EE2A3293F6BAF004840D1 /* UIPasteboardWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE2A2293F6BAF004840D1 /* UIPasteboardWrapper.swift */; }; + C5F32A2C2954814200A6476E /* ConnectionDetailsModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5F32A2B2954814200A6476E /* ConnectionDetailsModule.swift */; }; + C5F32A2E2954814A00A6476E /* ConnectionDetailsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5F32A2D2954814A00A6476E /* ConnectionDetailsRouter.swift */; }; + C5F32A302954816100A6476E /* ConnectionDetailsInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5F32A2F2954816100A6476E /* ConnectionDetailsInteractor.swift */; }; + C5F32A322954816C00A6476E /* ConnectionDetailsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5F32A312954816C00A6476E /* ConnectionDetailsPresenter.swift */; }; + C5F32A342954817600A6476E /* ConnectionDetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5F32A332954817600A6476E /* ConnectionDetailsView.swift */; }; + C5F32A362954FE3C00A6476E /* Colors.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C5F32A352954FE3C00A6476E /* Colors.xcassets */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -316,14 +314,6 @@ A541959B2934BFEF0035AD19 /* SignerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignerTests.swift; sourceTree = ""; }; A541959C2934BFEF0035AD19 /* EIP1271VerifierTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EIP1271VerifierTests.swift; sourceTree = ""; }; A541959D2934BFEF0035AD19 /* EIP191VerifierTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EIP191VerifierTests.swift; sourceTree = ""; }; - A55CAAAB28B92AFF00844382 /* ScanModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanModule.swift; sourceTree = ""; }; - A55CAAAC28B92AFF00844382 /* ScanPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanPresenter.swift; sourceTree = ""; }; - A55CAAAD28B92AFF00844382 /* ScanRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanRouter.swift; sourceTree = ""; }; - A55CAAAE28B92AFF00844382 /* ScanInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanInteractor.swift; sourceTree = ""; }; - A55CAAAF28B92AFF00844382 /* ScanView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanView.swift; sourceTree = ""; }; - A55CAAB628B92B4600844382 /* ScanQRView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScanQRView.swift; sourceTree = ""; }; - A55CAAB728B92B4600844382 /* ScanTargetView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScanTargetView.swift; sourceTree = ""; }; - A55CAAB828B92B4600844382 /* ScanQR.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScanQR.swift; sourceTree = ""; }; A5629AA82876A23100094373 /* ChatService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatService.swift; sourceTree = ""; }; A5629AB82876CBC000094373 /* ChatListModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatListModule.swift; sourceTree = ""; }; A5629AB92876CBC000094373 /* ChatListPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatListPresenter.swift; sourceTree = ""; }; @@ -379,16 +369,6 @@ A58E7D442872EE570082D443 /* ContentMessageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentMessageView.swift; sourceTree = ""; }; A58E7D472872EF610082D443 /* MessageViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageViewModel.swift; sourceTree = ""; }; A59CF4F5292F83D50031A42F /* DefaultSignerFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultSignerFactory.swift; sourceTree = ""; }; - A59EBEF328B54A2A003EDAAF /* AuthRequestModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthRequestModule.swift; sourceTree = ""; }; - A59EBEF428B54A2A003EDAAF /* AuthRequestPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthRequestPresenter.swift; sourceTree = ""; }; - A59EBEF528B54A2A003EDAAF /* AuthRequestRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthRequestRouter.swift; sourceTree = ""; }; - A59EBEF628B54A2A003EDAAF /* AuthRequestInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthRequestInteractor.swift; sourceTree = ""; }; - A59EBEF728B54A2A003EDAAF /* AuthRequestView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthRequestView.swift; sourceTree = ""; }; - A59F876A28B53EA000A9CD80 /* WalletModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletModule.swift; sourceTree = ""; }; - A59F876B28B53EA000A9CD80 /* WalletPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletPresenter.swift; sourceTree = ""; }; - A59F876C28B53EA000A9CD80 /* WalletRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletRouter.swift; sourceTree = ""; }; - A59F876D28B53EA000A9CD80 /* WalletInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletInteractor.swift; sourceTree = ""; }; - A59F876E28B53EA000A9CD80 /* WalletView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletView.swift; sourceTree = ""; }; A5A4FC55283CBB7800BBEC1E /* SessionDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionDetailView.swift; sourceTree = ""; }; A5A4FC57283CBB9F00BBEC1E /* SessionDetailViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionDetailViewModel.swift; sourceTree = ""; }; A5A4FC59283CC08600BBEC1E /* SessionNamespaceViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionNamespaceViewModel.swift; sourceTree = ""; }; @@ -430,6 +410,22 @@ A5E22D232840C8DB00E36487 /* SafariEngine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariEngine.swift; sourceTree = ""; }; A5E22D2B2840EAC300E36487 /* XCUIElement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCUIElement.swift; sourceTree = ""; }; A5F48A0528E43D3F0034CBFB /* Configuration.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Configuration.xcconfig; path = ../Configuration.xcconfig; sourceTree = ""; }; + C53AA434294124B3008EA57C /* SocketFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocketFactory.swift; sourceTree = ""; }; + C55D347A295DD7140004314A /* AuthRequestModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthRequestModule.swift; sourceTree = ""; }; + C55D347B295DD7140004314A /* AuthRequestPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthRequestPresenter.swift; sourceTree = ""; }; + C55D347C295DD7140004314A /* AuthRequestRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthRequestRouter.swift; sourceTree = ""; }; + C55D347D295DD7140004314A /* AuthRequestInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthRequestInteractor.swift; sourceTree = ""; }; + C55D347E295DD7140004314A /* AuthRequestView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthRequestView.swift; sourceTree = ""; }; + C55D3484295DD8CA0004314A /* PasteUriModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasteUriModule.swift; sourceTree = ""; }; + C55D3485295DD8CA0004314A /* PasteUriPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasteUriPresenter.swift; sourceTree = ""; }; + C55D3486295DD8CA0004314A /* PasteUriRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasteUriRouter.swift; sourceTree = ""; }; + C55D3487295DD8CA0004314A /* PasteUriInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasteUriInteractor.swift; sourceTree = ""; }; + C55D3488295DD8CA0004314A /* PasteUriView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasteUriView.swift; sourceTree = ""; }; + C55D348E295DFA750004314A /* WelcomeModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeModule.swift; sourceTree = ""; }; + C55D348F295DFA750004314A /* WelcomePresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomePresenter.swift; sourceTree = ""; }; + C55D3490295DFA750004314A /* WelcomeRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeRouter.swift; sourceTree = ""; }; + C55D3491295DFA750004314A /* WelcomeInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeInteractor.swift; sourceTree = ""; }; + C55D3492295DFA750004314A /* WelcomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeView.swift; sourceTree = ""; }; C56EE21B293F55ED004840D1 /* ChatWallet.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ChatWallet.app; sourceTree = BUILT_PRODUCTS_DIR; }; C56EE221293F55EE004840D1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; C56EE22B293F5668004840D1 /* WalletView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletView.swift; sourceTree = ""; }; @@ -437,11 +433,6 @@ C56EE22D293F5669004840D1 /* WalletModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletModule.swift; sourceTree = ""; }; C56EE22E293F5669004840D1 /* WalletRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletRouter.swift; sourceTree = ""; }; C56EE22F293F5669004840D1 /* WalletInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletInteractor.swift; sourceTree = ""; }; - C56EE231293F5669004840D1 /* AuthRequestInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthRequestInteractor.swift; sourceTree = ""; }; - C56EE232293F566A004840D1 /* AuthRequestView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthRequestView.swift; sourceTree = ""; }; - C56EE233293F566A004840D1 /* AuthRequestPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthRequestPresenter.swift; sourceTree = ""; }; - C56EE234293F566A004840D1 /* AuthRequestRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthRequestRouter.swift; sourceTree = ""; }; - C56EE235293F566A004840D1 /* AuthRequestModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthRequestModule.swift; sourceTree = ""; }; C56EE237293F566B004840D1 /* ScanModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanModule.swift; sourceTree = ""; }; C56EE238293F566B004840D1 /* ScanInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanInteractor.swift; sourceTree = ""; }; C56EE239293F566B004840D1 /* ScanRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanRouter.swift; sourceTree = ""; }; @@ -451,9 +442,6 @@ C56EE23E293F566C004840D1 /* ScanQR.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanQR.swift; sourceTree = ""; }; C56EE23F293F566C004840D1 /* ScanQRView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanQRView.swift; sourceTree = ""; }; C56EE25D293F56D6004840D1 /* InputConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputConfig.swift; sourceTree = ""; }; - C56EE25F293F56D6004840D1 /* InputView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputView.swift; sourceTree = ""; }; - C56EE260293F56D6004840D1 /* TextFieldView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldView.swift; sourceTree = ""; }; - C56EE261293F56D6004840D1 /* BrandButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrandButton.swift; sourceTree = ""; }; C56EE264293F56D6004840D1 /* SceneViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneViewController.swift; sourceTree = ""; }; C56EE266293F56D6004840D1 /* Types.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Types.swift; sourceTree = ""; }; C56EE268293F56D6004840D1 /* Color.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Color.swift; sourceTree = ""; }; @@ -476,6 +464,12 @@ C56EE298293F5773004840D1 /* AccountStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountStorage.swift; sourceTree = ""; }; C56EE29F293F5C4F004840D1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; C56EE2A2293F6BAF004840D1 /* UIPasteboardWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIPasteboardWrapper.swift; sourceTree = ""; }; + C5F32A2B2954814200A6476E /* ConnectionDetailsModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionDetailsModule.swift; sourceTree = ""; }; + C5F32A2D2954814A00A6476E /* ConnectionDetailsRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionDetailsRouter.swift; sourceTree = ""; }; + C5F32A2F2954816100A6476E /* ConnectionDetailsInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionDetailsInteractor.swift; sourceTree = ""; }; + C5F32A312954816C00A6476E /* ConnectionDetailsPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionDetailsPresenter.swift; sourceTree = ""; }; + C5F32A332954817600A6476E /* ConnectionDetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionDetailsView.swift; sourceTree = ""; }; + C5F32A352954FE3C00A6476E /* Colors.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Colors.xcassets; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -539,6 +533,7 @@ buildActionMask = 2147483647; files = ( C56EE27D293F56F8004840D1 /* WalletConnectChat in Frameworks */, + C5133A78294125CC00A8314C /* Web3 in Frameworks */, C56EE255293F569A004840D1 /* Starscream in Frameworks */, C56EE27B293F56F8004840D1 /* WalletConnectAuth in Frameworks */, ); @@ -767,33 +762,11 @@ path = Signer; sourceTree = ""; }; - A55CAAAA28B92AF200844382 /* Scan */ = { - isa = PBXGroup; - children = ( - A55CAAB528B92B3200844382 /* Views */, - A55CAAAB28B92AFF00844382 /* ScanModule.swift */, - A55CAAAC28B92AFF00844382 /* ScanPresenter.swift */, - A55CAAAD28B92AFF00844382 /* ScanRouter.swift */, - A55CAAAE28B92AFF00844382 /* ScanInteractor.swift */, - A55CAAAF28B92AFF00844382 /* ScanView.swift */, - ); - path = Scan; - sourceTree = ""; - }; - A55CAAB528B92B3200844382 /* Views */ = { - isa = PBXGroup; - children = ( - A55CAAB828B92B4600844382 /* ScanQR.swift */, - A55CAAB628B92B4600844382 /* ScanQRView.swift */, - A55CAAB728B92B4600844382 /* ScanTargetView.swift */, - ); - path = Views; - sourceTree = ""; - }; A5629AA42876A19D00094373 /* DomainLayer */ = { isa = PBXGroup; children = ( A5C20227287EB342007E3188 /* AccountStorage */, + C53AA433294124B3008EA57C /* SocketFactory */, A5629AEB2877F69C00094373 /* Chat */, ); path = DomainLayer; @@ -962,7 +935,6 @@ A58E7D062872A4390082D443 /* PresentationLayer */ = { isa = PBXGroup; children = ( - A59F876928B53E7800A9CD80 /* Wallet */, A59F876828B53E6400A9CD80 /* Chat */, ); path = PresentationLayer; @@ -1043,18 +1015,6 @@ path = Models; sourceTree = ""; }; - A59EBEFD28B54A2E003EDAAF /* AuthRequest */ = { - isa = PBXGroup; - children = ( - A59EBEF328B54A2A003EDAAF /* AuthRequestModule.swift */, - A59EBEF428B54A2A003EDAAF /* AuthRequestPresenter.swift */, - A59EBEF528B54A2A003EDAAF /* AuthRequestRouter.swift */, - A59EBEF628B54A2A003EDAAF /* AuthRequestInteractor.swift */, - A59EBEF728B54A2A003EDAAF /* AuthRequestView.swift */, - ); - path = AuthRequest; - sourceTree = ""; - }; A59F876828B53E6400A9CD80 /* Chat */ = { isa = PBXGroup; children = ( @@ -1069,28 +1029,6 @@ path = Chat; sourceTree = ""; }; - A59F876928B53E7800A9CD80 /* Wallet */ = { - isa = PBXGroup; - children = ( - A55CAAAA28B92AF200844382 /* Scan */, - A59EBEFD28B54A2E003EDAAF /* AuthRequest */, - A59F877428B53EA500A9CD80 /* Wallet */, - ); - path = Wallet; - sourceTree = ""; - }; - A59F877428B53EA500A9CD80 /* Wallet */ = { - isa = PBXGroup; - children = ( - A59F876A28B53EA000A9CD80 /* WalletModule.swift */, - A59F876B28B53EA000A9CD80 /* WalletPresenter.swift */, - A59F876C28B53EA000A9CD80 /* WalletRouter.swift */, - A59F876D28B53EA000A9CD80 /* WalletInteractor.swift */, - A59F876E28B53EA000A9CD80 /* WalletView.swift */, - ); - path = Wallet; - sourceTree = ""; - }; A5A4FC732840C12C00BBEC1E /* UITests */ = { isa = PBXGroup; children = ( @@ -1263,6 +1201,50 @@ path = Extensions; sourceTree = ""; }; + C53AA433294124B3008EA57C /* SocketFactory */ = { + isa = PBXGroup; + children = ( + C53AA434294124B3008EA57C /* SocketFactory.swift */, + ); + path = SocketFactory; + sourceTree = ""; + }; + C55D3471295DC5F60004314A /* PasteUri */ = { + isa = PBXGroup; + children = ( + C55D3484295DD8CA0004314A /* PasteUriModule.swift */, + C55D3485295DD8CA0004314A /* PasteUriPresenter.swift */, + C55D3486295DD8CA0004314A /* PasteUriRouter.swift */, + C55D3487295DD8CA0004314A /* PasteUriInteractor.swift */, + C55D3488295DD8CA0004314A /* PasteUriView.swift */, + ); + path = PasteUri; + sourceTree = ""; + }; + C55D3474295DCB850004314A /* AuthRequest */ = { + isa = PBXGroup; + children = ( + C55D347A295DD7140004314A /* AuthRequestModule.swift */, + C55D347B295DD7140004314A /* AuthRequestPresenter.swift */, + C55D347C295DD7140004314A /* AuthRequestRouter.swift */, + C55D347D295DD7140004314A /* AuthRequestInteractor.swift */, + C55D347E295DD7140004314A /* AuthRequestView.swift */, + ); + path = AuthRequest; + sourceTree = ""; + }; + C55D3477295DD4AA0004314A /* Welcome */ = { + isa = PBXGroup; + children = ( + C55D348E295DFA750004314A /* WelcomeModule.swift */, + C55D348F295DFA750004314A /* WelcomePresenter.swift */, + C55D3490295DFA750004314A /* WelcomeRouter.swift */, + C55D3491295DFA750004314A /* WelcomeInteractor.swift */, + C55D3492295DFA750004314A /* WelcomeView.swift */, + ); + path = Welcome; + sourceTree = ""; + }; C56EE21C293F55ED004840D1 /* ChatWallet */ = { isa = PBXGroup; children = ( @@ -1278,8 +1260,11 @@ C56EE229293F5668004840D1 /* Wallet */ = { isa = PBXGroup; children = ( + C55D3477295DD4AA0004314A /* Welcome */, + C55D3474295DCB850004314A /* AuthRequest */, + C55D3471295DC5F60004314A /* PasteUri */, + C5F32A2A2954812900A6476E /* ConnectionDetails */, C56EE236293F566A004840D1 /* Scan */, - C56EE230293F5669004840D1 /* AuthRequest */, C56EE22A293F5668004840D1 /* Wallet */, ); path = Wallet; @@ -1297,18 +1282,6 @@ path = Wallet; sourceTree = ""; }; - C56EE230293F5669004840D1 /* AuthRequest */ = { - isa = PBXGroup; - children = ( - C56EE235293F566A004840D1 /* AuthRequestModule.swift */, - C56EE233293F566A004840D1 /* AuthRequestPresenter.swift */, - C56EE234293F566A004840D1 /* AuthRequestRouter.swift */, - C56EE231293F5669004840D1 /* AuthRequestInteractor.swift */, - C56EE232293F566A004840D1 /* AuthRequestView.swift */, - ); - path = AuthRequest; - sourceTree = ""; - }; C56EE236293F566A004840D1 /* Scan */ = { isa = PBXGroup; children = ( @@ -1337,7 +1310,6 @@ children = ( C56EE25D293F56D6004840D1 /* InputConfig.swift */, C56EE265293F56D6004840D1 /* Types */, - C56EE25E293F56D6004840D1 /* Components */, C56EE267293F56D6004840D1 /* Style */, C56EE2A1293F6B9E004840D1 /* Helpers */, C56EE262293F56D6004840D1 /* Extensions */, @@ -1346,16 +1318,6 @@ path = Common; sourceTree = ""; }; - C56EE25E293F56D6004840D1 /* Components */ = { - isa = PBXGroup; - children = ( - C56EE25F293F56D6004840D1 /* InputView.swift */, - C56EE260293F56D6004840D1 /* TextFieldView.swift */, - C56EE261293F56D6004840D1 /* BrandButton.swift */, - ); - path = Components; - sourceTree = ""; - }; C56EE262293F56D6004840D1 /* Extensions */ = { isa = PBXGroup; children = ( @@ -1479,6 +1441,7 @@ children = ( C56EE221293F55EE004840D1 /* Assets.xcassets */, C56EE29F293F5C4F004840D1 /* Info.plist */, + C5F32A352954FE3C00A6476E /* Colors.xcassets */, ); path = Other; sourceTree = ""; @@ -1491,6 +1454,18 @@ path = Helpers; sourceTree = ""; }; + C5F32A2A2954812900A6476E /* ConnectionDetails */ = { + isa = PBXGroup; + children = ( + C5F32A2B2954814200A6476E /* ConnectionDetailsModule.swift */, + C5F32A2D2954814A00A6476E /* ConnectionDetailsRouter.swift */, + C5F32A2F2954816100A6476E /* ConnectionDetailsInteractor.swift */, + C5F32A312954816C00A6476E /* ConnectionDetailsPresenter.swift */, + C5F32A332954817600A6476E /* ConnectionDetailsView.swift */, + ); + path = ConnectionDetails; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -1626,6 +1601,7 @@ C56EE254293F569A004840D1 /* Starscream */, C56EE27A293F56F8004840D1 /* WalletConnectAuth */, C56EE27C293F56F8004840D1 /* WalletConnectChat */, + C5133A77294125CC00A8314C /* Web3 */, ); productName = ChatWallet; productReference = C56EE21B293F55ED004840D1 /* ChatWallet.app */; @@ -1735,6 +1711,7 @@ buildActionMask = 2147483647; files = ( C56EE222293F55EE004840D1 /* Assets.xcassets in Resources */, + C5F32A362954FE3C00A6476E /* Colors.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1821,18 +1798,12 @@ A58E7D0E2872A45B0082D443 /* MainRouter.swift in Sources */, A58E7D432872EE320082D443 /* MessageView.swift in Sources */, A58E7D3F2872E99A0082D443 /* TabPage.swift in Sources */, - A59EBEFB28B54A2A003EDAAF /* AuthRequestInteractor.swift in Sources */, - A59F877228B53EA000A9CD80 /* WalletInteractor.swift in Sources */, A58E7D3C2872D55F0082D443 /* ChatPresenter.swift in Sources */, - A59EBEF928B54A2A003EDAAF /* AuthRequestPresenter.swift in Sources */, A5C2020B287D9DEE007E3188 /* WelcomeModule.swift in Sources */, - A59F876F28B53EA000A9CD80 /* WalletModule.swift in Sources */, A58E7D152872A5410082D443 /* UIViewController.swift in Sources */, - A59EBEF828B54A2A003EDAAF /* AuthRequestModule.swift in Sources */, A58E7D132872A4A80082D443 /* Application.swift in Sources */, A58E7D002872A1050082D443 /* SceneViewController.swift in Sources */, A58E7D242872AB130082D443 /* MainViewController.swift in Sources */, - A59EBEFC28B54A2A003EDAAF /* AuthRequestView.swift in Sources */, A5629AE02876CC6E00094373 /* InviteListRouter.swift in Sources */, A58E7D032872A1630082D443 /* String.swift in Sources */, A58E7D3D2872D55F0082D443 /* ChatView.swift in Sources */, @@ -1842,7 +1813,6 @@ A5629ADE2876CC6E00094373 /* InviteListModule.swift in Sources */, A578FA322873036400AA7720 /* InputView.swift in Sources */, A5C2021B287E1FD8007E3188 /* ImportRouter.swift in Sources */, - A59F877328B53EA000A9CD80 /* WalletView.swift in Sources */, A5629AE42876E6D200094373 /* ThreadViewModel.swift in Sources */, A58E7D0C2872A45B0082D443 /* MainModule.swift in Sources */, A5C2021C287E1FD8007E3188 /* ImportInteractor.swift in Sources */, @@ -1852,44 +1822,34 @@ A5629AE12876CC6E00094373 /* InviteListInteractor.swift in Sources */, A58E7CED28729F550082D443 /* SceneDelegate.swift in Sources */, A5C2020F287D9DEE007E3188 /* WelcomeView.swift in Sources */, - A55CAAB128B92AFF00844382 /* ScanPresenter.swift in Sources */, - A59F877128B53EA000A9CD80 /* WalletRouter.swift in Sources */, A5C20226287EB099007E3188 /* AccountNameResolver.swift in Sources */, A5C2020D287D9DEE007E3188 /* WelcomeRouter.swift in Sources */, - A55CAAB328B92AFF00844382 /* ScanInteractor.swift in Sources */, - A55CAABA28B92B4600844382 /* ScanTargetView.swift in Sources */, A578FA372873D8EE00AA7720 /* UIColor.swift in Sources */, A5C2021D287E1FD8007E3188 /* ImportView.swift in Sources */, A5C2021A287E1FD8007E3188 /* ImportPresenter.swift in Sources */, A5629AE828772A0100094373 /* InviteViewModel.swift in Sources */, - A55CAAB928B92B4600844382 /* ScanQRView.swift in Sources */, A5629AA92876A23100094373 /* ChatService.swift in Sources */, A5C20229287EB34C007E3188 /* AccountStorage.swift in Sources */, A5629AC02876CBC000094373 /* ChatListInteractor.swift in Sources */, - A55CAAB428B92AFF00844382 /* ScanView.swift in Sources */, A5629AE22876CC6E00094373 /* InviteListView.swift in Sources */, A5A8E47F293A1D0000FEB97D /* DefaultSocketFactory.swift in Sources */, A578FA3D2874002400AA7720 /* View.swift in Sources */, A5629AD72876CC5700094373 /* InviteView.swift in Sources */, - A59EBEFA28B54A2A003EDAAF /* AuthRequestRouter.swift in Sources */, - A55CAAB228B92AFF00844382 /* ScanRouter.swift in Sources */, A5C20221287EA5B8007E3188 /* TextFieldView.swift in Sources */, A5A8E480293A1D0000FEB97D /* DefaultSignerFactory.swift in Sources */, A5C2022B287EB89A007E3188 /* WelcomeInteractor.swift in Sources */, A5C2020C287D9DEE007E3188 /* WelcomePresenter.swift in Sources */, A58E7D1D2872A57B0082D443 /* Configurator.swift in Sources */, A58E7D482872EF610082D443 /* MessageViewModel.swift in Sources */, - A59F877028B53EA000A9CD80 /* WalletPresenter.swift in Sources */, A5629AD32876CC5700094373 /* InviteModule.swift in Sources */, A5629AD52876CC5700094373 /* InviteRouter.swift in Sources */, - A55CAABB28B92B4600844382 /* ScanQR.swift in Sources */, A5629ABF2876CBC000094373 /* ChatListRouter.swift in Sources */, - A55CAAB028B92AFF00844382 /* ScanModule.swift in Sources */, A5629AC12876CBC000094373 /* ChatListView.swift in Sources */, A578FA392873FCE000AA7720 /* ChatScrollView.swift in Sources */, A58E7D1E2872A57B0082D443 /* ThirdPartyConfigurator.swift in Sources */, A5629AD42876CC5700094373 /* InvitePresenter.swift in Sources */, A58E7D3A2872D55F0082D443 /* ChatRouter.swift in Sources */, + C53AA435294124BC008EA57C /* SocketFactory.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1939,47 +1899,60 @@ buildActionMask = 2147483647; files = ( C56EE29C293F5773004840D1 /* ChatService.swift in Sources */, - C56EE24B293F566D004840D1 /* AuthRequestPresenter.swift in Sources */, + C53AA4362941251C008EA57C /* DefaultSignerFactory.swift in Sources */, + C55D3480295DD7140004314A /* AuthRequestPresenter.swift in Sources */, + C5F32A2E2954814A00A6476E /* ConnectionDetailsRouter.swift in Sources */, + C55D3482295DD7140004314A /* AuthRequestInteractor.swift in Sources */, C56EE247293F566D004840D1 /* ScanModule.swift in Sources */, - C56EE272293F56D7004840D1 /* TextFieldView.swift in Sources */, C56EE28D293F5757004840D1 /* AppearanceConfigurator.swift in Sources */, C56EE241293F566D004840D1 /* WalletModule.swift in Sources */, C56EE26F293F56D7004840D1 /* Types.swift in Sources */, C56EE245293F566D004840D1 /* WalletPresenter.swift in Sources */, C56EE240293F566D004840D1 /* ScanQRView.swift in Sources */, - C56EE24C293F566D004840D1 /* AuthRequestInteractor.swift in Sources */, C56EE250293F566D004840D1 /* ScanTargetView.swift in Sources */, C56EE28F293F5757004840D1 /* MigrationConfigurator.swift in Sources */, + C55D348B295DD8CA0004314A /* PasteUriRouter.swift in Sources */, + C55D348C295DD8CA0004314A /* PasteUriInteractor.swift in Sources */, C56EE299293F5773004840D1 /* AccountNameResolver.swift in Sources */, + C55D3497295DFA750004314A /* WelcomeView.swift in Sources */, C56EE271293F56D7004840D1 /* View.swift in Sources */, C56EE24D293F566D004840D1 /* WalletRouter.swift in Sources */, + C5F32A342954817600A6476E /* ConnectionDetailsView.swift in Sources */, + C55D348A295DD8CA0004314A /* PasteUriPresenter.swift in Sources */, C56EE28E293F5757004840D1 /* ApplicationConfigurator.swift in Sources */, + C55D347F295DD7140004314A /* AuthRequestModule.swift in Sources */, C56EE242293F566D004840D1 /* ScanPresenter.swift in Sources */, C56EE29D293F5773004840D1 /* RegisterService.swift in Sources */, - C56EE251293F566D004840D1 /* AuthRequestView.swift in Sources */, - C56EE277293F56D7004840D1 /* BrandButton.swift in Sources */, C56EE28B293F5757004840D1 /* SceneDelegate.swift in Sources */, C56EE276293F56D7004840D1 /* UIViewController.swift in Sources */, C56EE275293F56D7004840D1 /* InputConfig.swift in Sources */, + C55D3493295DFA750004314A /* WelcomeModule.swift in Sources */, C56EE270293F56D7004840D1 /* String.swift in Sources */, C56EE279293F56D7004840D1 /* Color.swift in Sources */, + C55D3483295DD7140004314A /* AuthRequestView.swift in Sources */, C56EE243293F566D004840D1 /* ScanView.swift in Sources */, C56EE288293F5757004840D1 /* ThirdPartyConfigurator.swift in Sources */, C56EE29A293F5773004840D1 /* AccountStorage.swift in Sources */, + C55D3495295DFA750004314A /* WelcomeRouter.swift in Sources */, C56EE24F293F566D004840D1 /* WalletView.swift in Sources */, C56EE248293F566D004840D1 /* ScanQR.swift in Sources */, C56EE289293F5757004840D1 /* Application.swift in Sources */, C56EE273293F56D7004840D1 /* UIColor.swift in Sources */, + C5F32A322954816C00A6476E /* ConnectionDetailsPresenter.swift in Sources */, C56EE246293F566D004840D1 /* ScanRouter.swift in Sources */, + C55D3481295DD7140004314A /* AuthRequestRouter.swift in Sources */, C56EE28C293F5757004840D1 /* Configurator.swift in Sources */, + C55D3489295DD8CA0004314A /* PasteUriModule.swift in Sources */, + C55D3494295DFA750004314A /* WelcomePresenter.swift in Sources */, C56EE274293F56D7004840D1 /* SceneViewController.swift in Sources */, - C56EE244293F566D004840D1 /* AuthRequestRouter.swift in Sources */, - C56EE24A293F566D004840D1 /* AuthRequestModule.swift in Sources */, - C56EE278293F56D7004840D1 /* InputView.swift in Sources */, + C55D3496295DFA750004314A /* WelcomeInteractor.swift in Sources */, + C55D348D295DD8CA0004314A /* PasteUriView.swift in Sources */, + C5F32A2C2954814200A6476E /* ConnectionDetailsModule.swift in Sources */, C56EE249293F566D004840D1 /* ScanInteractor.swift in Sources */, C56EE28A293F5757004840D1 /* AppDelegate.swift in Sources */, C56EE2A3293F6BAF004840D1 /* UIPasteboardWrapper.swift in Sources */, C56EE24E293F566D004840D1 /* WalletInteractor.swift in Sources */, + C5F32A302954816100A6476E /* ConnectionDetailsInteractor.swift in Sources */, C56EE29B293F5773004840D1 /* SocketFactory.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -2646,6 +2619,11 @@ isa = XCSwiftPackageProductDependency; productName = WalletConnectChat; }; + C5133A77294125CC00A8314C /* Web3 */ = { + isa = XCSwiftPackageProductDependency; + package = A5AE354528A1A2AC0059AE8A /* XCRemoteSwiftPackageReference "Web3" */; + productName = Web3; + }; C56EE254293F569A004840D1 /* Starscream */ = { isa = XCSwiftPackageProductDependency; package = A5D85224286333D500DAF5C3 /* XCRemoteSwiftPackageReference "Starscream" */; diff --git a/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/ChatWallet.xcscheme b/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/ChatWallet.xcscheme new file mode 100644 index 000000000..ee1b7f26a --- /dev/null +++ b/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/ChatWallet.xcscheme @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Example/Showcase/Classes/ApplicationLayer/Configurator/ApplicationConfigurator.swift b/Example/Showcase/Classes/ApplicationLayer/Configurator/ApplicationConfigurator.swift index a50e9c6e6..810260eef 100644 --- a/Example/Showcase/Classes/ApplicationLayer/Configurator/ApplicationConfigurator.swift +++ b/Example/Showcase/Classes/ApplicationLayer/Configurator/ApplicationConfigurator.swift @@ -11,6 +11,6 @@ struct ApplicationConfigurator: Configurator { } func configure() { - MainModule.create(app: app).present() + WelcomeModule.create(app: app).present() } } diff --git a/Example/Showcase/Classes/DomainLayer/SocketFactory/SocketFactory.swift b/Example/Showcase/Classes/DomainLayer/SocketFactory/SocketFactory.swift new file mode 100644 index 000000000..5df81d8da --- /dev/null +++ b/Example/Showcase/Classes/DomainLayer/SocketFactory/SocketFactory.swift @@ -0,0 +1,9 @@ +import Foundation +import Starscream +import WalletConnectRelay + +struct SocketFactory: WebSocketFactory { + func create(with url: URL) -> WebSocketConnecting { + return WebSocket(url: url) + } +} diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/Main/MainPresenter.swift b/Example/Showcase/Classes/PresentationLayer/Chat/Main/MainPresenter.swift index b61e7dd27..fde2e49fc 100644 --- a/Example/Showcase/Classes/PresentationLayer/Chat/Main/MainPresenter.swift +++ b/Example/Showcase/Classes/PresentationLayer/Chat/Main/MainPresenter.swift @@ -11,8 +11,7 @@ final class MainPresenter { var viewControllers: [UIViewController] { return [ - router.chatViewController, - router.walletViewController + router.chatViewController ] } diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/Main/MainRouter.swift b/Example/Showcase/Classes/PresentationLayer/Chat/Main/MainRouter.swift index d80001361..fdd32686d 100644 --- a/Example/Showcase/Classes/PresentationLayer/Chat/Main/MainRouter.swift +++ b/Example/Showcase/Classes/PresentationLayer/Chat/Main/MainRouter.swift @@ -6,10 +6,6 @@ final class MainRouter { private let app: Application - var walletViewController: UIViewController { - return WalletModule.create(app: app).wrapToNavigationController() - } - var chatViewController: UIViewController { return WelcomeModule.create(app: app) } diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomeInteractor.swift b/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomeInteractor.swift index 8da35b860..40210dbab 100644 --- a/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomeInteractor.swift +++ b/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomeInteractor.swift @@ -1,9 +1,17 @@ import Foundation +import Combine + import WalletConnectRelay +import WalletConnectPairing +import Auth final class WelcomeInteractor { + private var disposeBag = Set() + private let chatService: ChatService private let accountStorage: AccountStorage + + var authClient: AuthClient? init(chatService: ChatService, accountStorage: AccountStorage) { self.chatService = chatService @@ -21,4 +29,71 @@ final class WelcomeInteractor { func trackConnection() -> Stream { return chatService.connectionPublisher } + + func generateUri() async -> WalletConnectURI { + let appPairingClient = makeClient(prefix: "🤡") + return try! await appPairingClient.create() + } + + func makeClient(prefix: String) -> PairingClient { + let keychain = KeychainStorage(serviceIdentifier: "com.walletconnect.sdk") + let keyValueStorage = RuntimeKeyValueStorage() + + let relayLogger = ConsoleLogger(suffix: prefix + " [Relay]", loggingLevel: .debug) + let pairingLogger = ConsoleLogger(suffix: prefix + " [Pairing]", loggingLevel: .debug) + let networkingLogger = ConsoleLogger(suffix: prefix + " [Networking]", loggingLevel: .debug) + let authLogger = ConsoleLogger(suffix: prefix + " [Auth]", loggingLevel: .debug) + + let relayClient = RelayClient( + relayHost: InputConfig.relayHost, + projectId: InputConfig.projectId, + keyValueStorage: RuntimeKeyValueStorage(), + keychainStorage: keychain, + socketFactory: SocketFactory(), + logger: relayLogger + ) + + let networkingClient = NetworkingClientFactory.create( + relayClient: relayClient, + logger: networkingLogger, + keychainStorage: keychain, + keyValueStorage: keyValueStorage + ) + + let pairingClient = PairingClientFactory.create( + logger: pairingLogger, + keyValueStorage: keyValueStorage, + keychainStorage: keychain, + networkingClient: networkingClient + ) + + authClient = AuthClientFactory.create( + metadata: AppMetadata(name: "chatapp", description: "", url: "", icons: [""]), + account: nil, + projectId: InputConfig.projectId, + signerFactory: DefaultSignerFactory(), + networkingClient: networkingClient, + pairingRegisterer: pairingClient + ) + + authClient?.authResponsePublisher.sink { (_, result) in + guard case .success = result else { + return + } + print(result) + } + .store(in: &disposeBag) + + return pairingClient + } +} + +protocol IATProvider { + var iat: String { get } +} + +struct DefaultIATProvider: IATProvider { + var iat: String { + return ISO8601DateFormatter().string(from: Date()) + } } diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomePresenter.swift b/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomePresenter.swift index 28eac8895..12358e009 100644 --- a/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomePresenter.swift +++ b/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomePresenter.swift @@ -1,5 +1,6 @@ import UIKit import Combine +import Auth final class WelcomePresenter: ObservableObject { @@ -22,14 +23,36 @@ final class WelcomePresenter: ObservableObject { } var buttonTitle: String { - return interactor.isAuthorized() ? "Start Messaging" : "Import account" + return interactor.isAuthorized() ? "Start Messaging" : "Connect wallet" } - func didPressImport() { + func didPressImport() async { if let account = interactor.account { router.presentChats(account: account) } else { - router.presentImport() + await authWithWallet() + } + } + + private func authWithWallet() async { + let uri = await interactor.generateUri() + try? await interactor.authClient?.request( + RequestParams( + domain: "example.wallet", + chainId: "eip155:1", + nonce: "32891756", + aud: "https://example.wallet/login", + nbf: nil, + exp: nil, + statement: "I accept the ServiceOrg Terms of Service: https://service.invalid/tos", + requestId: nil, + resources: ["ipfs://bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq/", "https://example.com/my-web2-claim.json"] + ), + topic: uri.topic + ) + + DispatchQueue.main.async { + self.router.openWallet(uri: uri.absoluteString) } } } diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomeRouter.swift b/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomeRouter.swift index 1bc4b9e1f..1c87555f4 100644 --- a/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomeRouter.swift +++ b/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomeRouter.swift @@ -21,4 +21,8 @@ final class WelcomeRouter { .wrapToNavigationController() .present() } + + func openWallet(uri: String) { + UIApplication.shared.open(URL(string: "chatwallet://wc?uri=\(uri)")!) + } } diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomeView.swift b/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomeView.swift index 2d9ba4129..b56ef64e0 100644 --- a/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomeView.swift +++ b/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomeView.swift @@ -32,7 +32,9 @@ struct WelcomeView: View { .multilineTextAlignment(.center) BrandButton(title: presenter.buttonTitle, action: { - presenter.didPressImport() + Task { + await presenter.didPressImport() + } }) Text("By connecting your wallet you agree with our\nTerms of Service") diff --git a/Example/Showcase/Classes/PresentationLayer/Wallet/AuthRequest/AuthRequestInteractor.swift b/Example/Showcase/Classes/PresentationLayer/Wallet/AuthRequest/AuthRequestInteractor.swift deleted file mode 100644 index ce787b638..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Wallet/AuthRequest/AuthRequestInteractor.swift +++ /dev/null @@ -1,17 +0,0 @@ -import Foundation -import Auth -import WalletConnectUtils - -final class AuthRequestInteractor { - - func approve(request: AuthRequest) async throws { - let privateKey = Data(hex: "e56da0e170b5e09a8bb8f1b693392c7d56c3739a9c75740fbc558a2877868540") - let signer = MessageSignerFactory(signerFactory: DefaultSignerFactory()).create() - let signature = try signer.sign(message: request.message, privateKey: privateKey, type: .eip191) - try await Auth.instance.respond(requestId: request.id, signature: signature) - } - - func reject(request: AuthRequest) async throws { - try await Auth.instance.reject(requestId: request.id) - } -} diff --git a/Example/Showcase/Classes/PresentationLayer/Wallet/AuthRequest/AuthRequestModule.swift b/Example/Showcase/Classes/PresentationLayer/Wallet/AuthRequest/AuthRequestModule.swift deleted file mode 100644 index 230e05bbc..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Wallet/AuthRequest/AuthRequestModule.swift +++ /dev/null @@ -1,19 +0,0 @@ -import SwiftUI -import Auth - -final class AuthRequestModule { - - @discardableResult - static func create(app: Application, request: AuthRequest) -> UIViewController { - let router = AuthRequestRouter(app: app) - let interactor = AuthRequestInteractor() - let presenter = AuthRequestPresenter(request: request, interactor: interactor, router: router) - let view = AuthRequestView().environmentObject(presenter) - let viewController = SceneViewController(viewModel: presenter, content: view) - - router.viewController = viewController - - return viewController - } - -} diff --git a/Example/Showcase/Classes/PresentationLayer/Wallet/AuthRequest/AuthRequestPresenter.swift b/Example/Showcase/Classes/PresentationLayer/Wallet/AuthRequest/AuthRequestPresenter.swift deleted file mode 100644 index f70700e86..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Wallet/AuthRequest/AuthRequestPresenter.swift +++ /dev/null @@ -1,56 +0,0 @@ -import UIKit -import Combine -import Auth - -final class AuthRequestPresenter: ObservableObject { - - private let request: AuthRequest - private let interactor: AuthRequestInteractor - private let router: AuthRequestRouter - private var disposeBag = Set() - - init(request: AuthRequest, interactor: AuthRequestInteractor, router: AuthRequestRouter) { - defer { setupInitialState() } - self.request = request - self.interactor = interactor - self.router = router - } - - var message: String { - return request.message - } - - @MainActor - func approvePressed() async throws { - try await interactor.approve(request: request) - router.dismiss() - } - - @MainActor - func rejectPressed() async throws { - try await interactor.reject(request: request) - router.dismiss() - } -} - -// MARK: SceneViewModel - -extension AuthRequestPresenter: SceneViewModel { - - var sceneTitle: String? { - return "Auth Request" - } - - var largeTitleDisplayMode: UINavigationItem.LargeTitleDisplayMode { - return .always - } -} - -// MARK: Privates - -private extension AuthRequestPresenter { - - func setupInitialState() { - - } -} diff --git a/Example/Showcase/Classes/PresentationLayer/Wallet/AuthRequest/AuthRequestRouter.swift b/Example/Showcase/Classes/PresentationLayer/Wallet/AuthRequest/AuthRequestRouter.swift deleted file mode 100644 index 53d3d684e..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Wallet/AuthRequest/AuthRequestRouter.swift +++ /dev/null @@ -1,16 +0,0 @@ -import UIKit - -final class AuthRequestRouter { - - weak var viewController: UIViewController! - - private let app: Application - - init(app: Application) { - self.app = app - } - - func dismiss() { - viewController.navigationController?.dismiss() - } -} diff --git a/Example/Showcase/Classes/PresentationLayer/Wallet/AuthRequest/AuthRequestView.swift b/Example/Showcase/Classes/PresentationLayer/Wallet/AuthRequest/AuthRequestView.swift deleted file mode 100644 index c8443c337..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Wallet/AuthRequest/AuthRequestView.swift +++ /dev/null @@ -1,54 +0,0 @@ -import SwiftUI - -struct AuthRequestView: View { - - @EnvironmentObject var presenter: AuthRequestPresenter - - var body: some View { - VStack(spacing: 16.0) { - HStack { - Text("Message to sign:") - Spacer() - } - - VStack { - Text(presenter.message) - .font(Font.system(size: 13)) - .padding(16.0) - } - .background(Color.white.opacity(0.1)) - .cornerRadius(10) - - HStack(spacing: 16.0) { - Button(action: { Task(priority: .userInitiated) { try await presenter.rejectPressed() }}, label: { - HStack(spacing: 8.0) { - Text("Reject") - .foregroundColor(.w_foreground) - .font(.system(size: 18, weight: .semibold)) - } - }) - .frame(width: 120, height: 44) - .background( - Capsule() - .foregroundColor(.w_purpleForeground) - ) - - Button(action: { Task(priority: .userInitiated) { try await presenter.approvePressed() }}, label: { - HStack(spacing: 8.0) { - Text("Approve") - .foregroundColor(.w_foreground) - .font(.system(size: 18, weight: .semibold)) - } - }) - .frame(width: 120, height: 44) - .background( - Capsule() - .foregroundColor(.w_greenForground) - ) - } - - Spacer() - } - .padding(16.0) - } -} diff --git a/Example/Showcase/Classes/PresentationLayer/Wallet/Scan/ScanInteractor.swift b/Example/Showcase/Classes/PresentationLayer/Wallet/Scan/ScanInteractor.swift deleted file mode 100644 index 8585d6043..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Wallet/Scan/ScanInteractor.swift +++ /dev/null @@ -1,3 +0,0 @@ -final class ScanInteractor { - -} diff --git a/Example/Showcase/Classes/PresentationLayer/Wallet/Scan/ScanPresenter.swift b/Example/Showcase/Classes/PresentationLayer/Wallet/Scan/ScanPresenter.swift deleted file mode 100644 index f36c77456..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Wallet/Scan/ScanPresenter.swift +++ /dev/null @@ -1,48 +0,0 @@ -import UIKit -import Combine - -final class ScanPresenter: ObservableObject { - - private let interactor: ScanInteractor - private let router: ScanRouter - - private var disposeBag = Set() - - let onValue: (String) -> Void - let onError: (Error) -> Void - - init( - interactor: ScanInteractor, - router: ScanRouter, - onValue: @escaping (String) -> Void, - onError: @escaping (Error) -> Void - ) { - defer { setupInitialState() } - self.interactor = interactor - self.router = router - self.onValue = onValue - self.onError = onError - } -} - -// MARK: SceneViewModel - -extension ScanPresenter: SceneViewModel { - - var sceneTitle: String? { - return "Scan URI" - } - - var largeTitleDisplayMode: UINavigationItem.LargeTitleDisplayMode { - return .always - } -} - -// MARK: Privates - -private extension ScanPresenter { - - func setupInitialState() { - - } -} diff --git a/Example/Showcase/Classes/PresentationLayer/Wallet/Scan/ScanView.swift b/Example/Showcase/Classes/PresentationLayer/Wallet/Scan/ScanView.swift deleted file mode 100644 index f8f36e7bb..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Wallet/Scan/ScanView.swift +++ /dev/null @@ -1,19 +0,0 @@ -import SwiftUI - -struct ScanView: View { - - @EnvironmentObject var presenter: ScanPresenter - - var body: some View { - ScanQR(onValue: presenter.onValue, onError: presenter.onError) - .ignoresSafeArea() - } -} - -#if DEBUG -struct ScanView_Previews: PreviewProvider { - static var previews: some View { - ScanView() - } -} -#endif diff --git a/Example/Showcase/Classes/PresentationLayer/Wallet/Scan/Views/ScanQR.swift b/Example/Showcase/Classes/PresentationLayer/Wallet/Scan/Views/ScanQR.swift deleted file mode 100644 index 8b78b3098..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Wallet/Scan/Views/ScanQR.swift +++ /dev/null @@ -1,39 +0,0 @@ -import SwiftUI - -struct ScanQR: UIViewRepresentable { - - class Coordinator: ScanQRViewDelegate { - private let onValue: (String) -> Void - private let onError: (Error) -> Void - - init(onValue: @escaping (String) -> Void, onError: @escaping (Error) -> Void) { - self.onValue = onValue - self.onError = onError - } - - func scanDidDetect(value: String) { - onValue(value) - } - - func scanDidFail(with error: Error) { - onError(error) - } - } - - let onValue: (String) -> Void - let onError: (Error) -> Void - - func makeUIView(context: Context) -> ScanQRView { - let view = ScanQRView() - view.delegate = context.coordinator - return view - } - - func updateUIView(_ uiView: ScanQRView, context: Context) { - - } - - func makeCoordinator() -> Coordinator { - return Coordinator(onValue: onValue, onError: onError) - } -} diff --git a/Example/Showcase/Classes/PresentationLayer/Wallet/Scan/Views/ScanQRView.swift b/Example/Showcase/Classes/PresentationLayer/Wallet/Scan/Views/ScanQRView.swift deleted file mode 100644 index 08ce85b45..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Wallet/Scan/Views/ScanQRView.swift +++ /dev/null @@ -1,187 +0,0 @@ -import UIKit -import AVFoundation - -protocol ScanQRViewDelegate: AnyObject { - func scanDidDetect(value: String) - func scanDidFail(with error: Error) -} - -final class ScanQRView: UIView { - enum Errors: Error { - case deviceNotFound - } - - weak var delegate: ScanQRViewDelegate? - - private let targetSize = CGSize( - width: UIScreen.main.bounds.width - 32.0, - height: UIScreen.main.bounds.width - 32.0 - ) - - private var videoPreviewLayer: AVCaptureVideoPreviewLayer? - private var captureSession: AVCaptureSession? - - private lazy var borderView: UIView = { - let borderView = ScanTargetView(radius: 24.0, color: .white, strokeWidth: 2.0, length: 36.0) - borderView.alpha = 0.85 - return borderView - }() - - private lazy var bluredView: UIView = { - let blurEffect = UIBlurEffect(style: .dark) - let bluredView = UIVisualEffectView(effect: blurEffect) - bluredView.autoresizingMask = [.flexibleWidth, .flexibleHeight] - bluredView.layer.mask = createMaskLayer() - return bluredView - }() - - override init(frame: CGRect) { - super.init(frame: frame) - - setupView() - startCaptureSession() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func layoutSubviews() { - super.layoutSubviews() - - updateFrames() - updateOrientation() - } - - deinit { - stopCaptureSession() - } -} - -// MARK: AVCaptureMetadataOutputObjectsDelegate - -extension ScanQRView: AVCaptureMetadataOutputObjectsDelegate { - - func metadataOutput(_ metadataOutput: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) { - defer { stopCaptureSession() } - guard - let metadataObject = metadataObjects.first as? AVMetadataMachineReadableCodeObject, - let value = metadataObject.stringValue else { - return - } - delegate?.scanDidDetect(value: value) - } -} - -// MARK: Privates - -private extension ScanQRView { - - private func setupView() { - backgroundColor = .black - - addSubview(bluredView) - addSubview(borderView) - } - - private func createMaskLayer() -> CAShapeLayer { - let maskPath = UIBezierPath(rect: bounds) - let rect = UIBezierPath( - roundedRect: CGRect( - x: center.x - targetSize.height * 0.5, - y: center.y - targetSize.width * 0.5, - width: targetSize.width, - height: targetSize.height - ), - byRoundingCorners: .allCorners, - cornerRadii: CGSize(width: 24.0, height: 24.0) - ) - maskPath.append(rect) - maskPath.usesEvenOddFillRule = true - - let maskLayer = CAShapeLayer() - maskLayer.path = maskPath.cgPath - maskLayer.fillRule = .evenOdd - return maskLayer - } - - private func startCaptureSession() { - DispatchQueue.global().async { [weak self] in - guard let self = self else { return } - - do { - let session = try self.createCaptureSession() - session.startRunning() - self.captureSession = session - - DispatchQueue.main.async { self.setupVideoPreviewLayer(with: session) } - } catch { - DispatchQueue.main.async { self.delegate?.scanDidFail(with: error) } - } - } - } - - private func createCaptureSession() throws -> AVCaptureSession { - guard let captureDevice = AVCaptureDevice.default(for: .video) else { - throw Errors.deviceNotFound - } - - let input = try AVCaptureDeviceInput(device: captureDevice) - - let session = AVCaptureSession() - session.addInput(input) - - let captureMetadataOutput = AVCaptureMetadataOutput() - captureMetadataOutput.setMetadataObjectsDelegate(self, queue: .main) - session.addOutput(captureMetadataOutput) - - captureMetadataOutput.metadataObjectTypes = [.qr] - - return session - } - - private func stopCaptureSession() { - captureSession?.stopRunning() - captureSession = nil - } - - private func setupVideoPreviewLayer(with session: AVCaptureSession) { - let previewLayer = AVCaptureVideoPreviewLayer(session: session) - previewLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill - previewLayer.frame = layer.bounds - videoPreviewLayer = previewLayer - - layer.insertSublayer(previewLayer, at: 0) - } - - private func updateFrames() { - borderView.frame.size = targetSize - borderView.center = center - bluredView.frame = bounds - bluredView.layer.mask = createMaskLayer() - videoPreviewLayer?.frame = layer.bounds - } - - private func updateOrientation() { - guard let connection = videoPreviewLayer?.connection else { - return - } - let previewLayerConnection: AVCaptureConnection = connection - - guard previewLayerConnection.isVideoOrientationSupported else { - return - } - switch UIDevice.current.orientation { - case .portrait: return - previewLayerConnection.videoOrientation = .portrait - case .landscapeRight: - previewLayerConnection.videoOrientation = .landscapeLeft - case .landscapeLeft: return - previewLayerConnection.videoOrientation = .landscapeRight - case .portraitUpsideDown: - previewLayerConnection.videoOrientation = .portraitUpsideDown - default: - previewLayerConnection.videoOrientation = .portrait - } - } -} diff --git a/Example/Showcase/Classes/PresentationLayer/Wallet/Scan/Views/ScanTargetView.swift b/Example/Showcase/Classes/PresentationLayer/Wallet/Scan/Views/ScanTargetView.swift deleted file mode 100644 index 99bbaaa3e..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Wallet/Scan/Views/ScanTargetView.swift +++ /dev/null @@ -1,87 +0,0 @@ -import UIKit - -final class ScanTargetView: UIView { - - private let radius: CGFloat - private let color: UIColor - private let strokeWidth: CGFloat - private let length: CGFloat - - private lazy var shapeLayer: CAShapeLayer = { - let shapeLayer = CAShapeLayer() - shapeLayer.strokeColor = color.cgColor - shapeLayer.fillColor = UIColor.clear.cgColor - shapeLayer.lineWidth = strokeWidth - return shapeLayer - }() - - init(radius: CGFloat, color: UIColor, strokeWidth: CGFloat, length: CGFloat) { - self.radius = radius - self.color = color - self.strokeWidth = strokeWidth - self.length = length - - super.init(frame: .zero) - - setupView() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func layoutSubviews() { - super.layoutSubviews() - shapeLayer.path = targetPath() - } - - private func setupView() { - backgroundColor = .clear - layer.addSublayer(shapeLayer) - } - - private func targetPath() -> CGPath { - let path = UIBezierPath() - path.append(createTopLeft()) - path.append(createTopRight()) - path.append(createBottomLeft()) - path.append(createBottomRight()) - return path.cgPath - } - - private func createTopLeft() -> UIBezierPath { - let topLeft = UIBezierPath() - topLeft.move(to: CGPoint(x: strokeWidth/2, y: radius+length)) - topLeft.addLine(to: CGPoint(x: strokeWidth/2, y: radius)) - topLeft.addQuadCurve(to: CGPoint(x: radius, y: strokeWidth/2), controlPoint: CGPoint(x: strokeWidth/2, y: strokeWidth/2)) - topLeft.addLine(to: CGPoint(x: radius+length, y: strokeWidth/2)) - return topLeft - } - - private func createTopRight() -> UIBezierPath { - let topRight = UIBezierPath() - topRight.move(to: CGPoint(x: frame.width-radius-length, y: strokeWidth/2)) - topRight.addLine(to: CGPoint(x: frame.width-radius, y: strokeWidth/2)) - topRight.addQuadCurve(to: CGPoint(x: frame.width-strokeWidth/2, y: radius), controlPoint: CGPoint(x: frame.width-strokeWidth/2, y: strokeWidth/2)) - topRight.addLine(to: CGPoint(x: frame.width-strokeWidth/2, y: radius+length)) - return topRight - } - - private func createBottomRight() -> UIBezierPath { - let bottomRight = UIBezierPath() - bottomRight.move(to: CGPoint(x: frame.width-strokeWidth/2, y: frame.height-radius-length)) - bottomRight.addLine(to: CGPoint(x: frame.width-strokeWidth/2, y: frame.height-radius)) - bottomRight.addQuadCurve(to: CGPoint(x: frame.width-radius, y: frame.height-strokeWidth/2), controlPoint: CGPoint(x: frame.width-strokeWidth/2, y: frame.height-strokeWidth/2)) - bottomRight.addLine(to: CGPoint(x: frame.width-radius-length, y: frame.height-strokeWidth/2)) - return bottomRight - } - - private func createBottomLeft() -> UIBezierPath { - let bottomLeft = UIBezierPath() - bottomLeft.move(to: CGPoint(x: radius+length, y: frame.height-strokeWidth/2)) - bottomLeft.addLine(to: CGPoint(x: radius, y: frame.height-strokeWidth/2)) - bottomLeft.addQuadCurve(to: CGPoint(x: strokeWidth/2, y: frame.height-radius), controlPoint: CGPoint(x: strokeWidth/2, y: frame.height-strokeWidth/2)) - bottomLeft.addLine(to: CGPoint(x: strokeWidth/2, y: frame.height-radius-length)) - return bottomLeft - } -} diff --git a/Example/Showcase/Classes/PresentationLayer/Wallet/Wallet/WalletModule.swift b/Example/Showcase/Classes/PresentationLayer/Wallet/Wallet/WalletModule.swift deleted file mode 100644 index fed9b1307..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Wallet/Wallet/WalletModule.swift +++ /dev/null @@ -1,18 +0,0 @@ -import SwiftUI - -final class WalletModule { - - @discardableResult - static func create(app: Application) -> UIViewController { - let router = WalletRouter(app: app) - let interactor = WalletInteractor() - let presenter = WalletPresenter(interactor: interactor, router: router) - let view = WalletView().environmentObject(presenter) - let viewController = SceneViewController(viewModel: presenter, content: view) - - router.viewController = viewController - - return viewController - } - -} diff --git a/Example/Showcase/Classes/PresentationLayer/Wallet/Wallet/WalletView.swift b/Example/Showcase/Classes/PresentationLayer/Wallet/Wallet/WalletView.swift deleted file mode 100644 index e9469e4b6..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Wallet/Wallet/WalletView.swift +++ /dev/null @@ -1,46 +0,0 @@ -import SwiftUI - -struct WalletView: View { - - @EnvironmentObject var presenter: WalletPresenter - - var body: some View { - VStack(spacing: 16) { - Button(action: { presenter.didPastePairingURI() }, label: { - HStack(spacing: 8.0) { - Text("Paste pairing URI") - .foregroundColor(.w_foreground) - .font(.system(size: 18, weight: .semibold)) - } - .padding(.trailing, 8.0) - }) - .frame(width: 200, height: 44) - .background( - Capsule() - .foregroundColor(.w_greenForground) - ) - - Button(action: { presenter.didScanPairingURI() }, label: { - HStack(spacing: 8.0) { - Text("Scan pairing URI") - .foregroundColor(.w_foreground) - .font(.system(size: 18, weight: .semibold)) - } - .padding(.trailing, 8.0) - }) - .frame(width: 200, height: 44) - .background( - Capsule() - .foregroundColor(.w_purpleForeground) - ) - } - } -} - -#if DEBUG -struct WalletView_Previews: PreviewProvider { - static var previews: some View { - WalletView() - } -} -#endif diff --git a/Example/Showcase/Common/InputConfig.swift b/Example/Showcase/Common/InputConfig.swift index 53931721a..bfbb51956 100644 --- a/Example/Showcase/Common/InputConfig.swift +++ b/Example/Showcase/Common/InputConfig.swift @@ -5,6 +5,10 @@ struct InputConfig { static var projectId: String { return config(for: "PROJECT_ID")! } + + static var relayHost: String { + return config(for: "RELAY_HOST")! + } private static func config(for key: String) -> String? { return Bundle.main.object(forInfoDictionaryKey: key) as? String diff --git a/Example/Showcase/Other/Info.plist b/Example/Showcase/Other/Info.plist index 2b842100f..136371e1c 100644 --- a/Example/Showcase/Other/Info.plist +++ b/Example/Showcase/Other/Info.plist @@ -4,6 +4,8 @@ PROJECT_ID $(PROJECT_ID) + RELAY_HOST + $(RELAY_HOST) CFBundleIconName AppIcon CFBundleURLTypes From 32e48efb491028b5f91d1b7809ca4cf38a4e3746 Mon Sep 17 00:00:00 2001 From: Alexander Lisovik Date: Sun, 1 Jan 2023 23:45:32 +0100 Subject: [PATCH 03/14] Update wallet scan UI --- Configuration.xcconfig | 2 +- .../Configurator/AppearanceConfigurator.swift | 2 - Example/ChatWallet/Common/Style/Color.swift | 2 +- .../grey100.colorset/Contents.json | 4 +- .../AuthRequest/AuthRequestRouter.swift | 2 +- .../Wallet/AuthRequest/AuthRequestView.swift | 2 +- .../ConnectionDetailsView.swift | 251 +++++++++--------- .../Wallet/PasteUri/PasteUriView.swift | 2 + .../Wallet/Scan/ScanModule.swift | 2 - .../Wallet/Scan/ScanPresenter.swift | 24 +- .../Wallet/Scan/ScanRouter.swift | 5 +- .../Wallet/Scan/ScanView.swift | 35 ++- .../Wallet/Scan/Views/ScanQRView.swift | 3 +- .../Wallet/Wallet/WalletView.swift | 78 +++--- .../Wallet/Welcome/WelcomeView.swift | 3 + .../ApplicationLayer/SceneDelegate.swift | 6 +- 16 files changed, 230 insertions(+), 193 deletions(-) diff --git a/Configuration.xcconfig b/Configuration.xcconfig index 15db0fdbc..7f4069cda 100644 --- a/Configuration.xcconfig +++ b/Configuration.xcconfig @@ -1,4 +1,4 @@ RELAY_HOST = relay.walletconnect.com // Uncomment next line and paste your project id. Get this on: https://cloud.walletconnect.com/sign-in -// PROJECT_ID = YOUR_PROJECT_ID +PROJECT_ID = 1012db890ca3cab0c1cdc929fdd657bf diff --git a/Example/ChatWallet/ApplicationLayer/Configurator/AppearanceConfigurator.swift b/Example/ChatWallet/ApplicationLayer/Configurator/AppearanceConfigurator.swift index 5ad69dfb5..793e9a835 100644 --- a/Example/ChatWallet/ApplicationLayer/Configurator/AppearanceConfigurator.swift +++ b/Example/ChatWallet/ApplicationLayer/Configurator/AppearanceConfigurator.swift @@ -13,7 +13,5 @@ struct AppearanceConfigurator: Configurator { UINavigationBar.appearance().standardAppearance = appearance UINavigationBar.appearance().scrollEdgeAppearance = appearance UINavigationBar.appearance().compactAppearance = appearance - - UIApplication.currentWindow.overrideUserInterfaceStyle = .dark } } diff --git a/Example/ChatWallet/Common/Style/Color.swift b/Example/ChatWallet/Common/Style/Color.swift index 4ed71a5e9..b88f03e98 100644 --- a/Example/ChatWallet/Common/Style/Color.swift +++ b/Example/ChatWallet/Common/Style/Color.swift @@ -21,7 +21,7 @@ extension Color { } extension UIColor { - static let w_background: UIColor = UIColor(rgb: 0x141414) + static let w_background = UIColor(named: "grey100")! static let w_secondaryBackground: UIColor = UIColor(rgb: 0x272A2A) static let w_tertiaryBackground: UIColor = UIColor(rgb: 0x3B4040) diff --git a/Example/ChatWallet/Other/Colors.xcassets/grey100.colorset/Contents.json b/Example/ChatWallet/Other/Colors.xcassets/grey100.colorset/Contents.json index c8633f3f6..ee2f44f71 100644 --- a/Example/ChatWallet/Other/Colors.xcassets/grey100.colorset/Contents.json +++ b/Example/ChatWallet/Other/Colors.xcassets/grey100.colorset/Contents.json @@ -4,7 +4,7 @@ "color" : { "color-space" : "srgb", "components" : { - "alpha" : "0.100", + "alpha" : "1.000", "blue" : "0xFF", "green" : "0xFF", "red" : "0xFF" @@ -22,7 +22,7 @@ "color" : { "color-space" : "srgb", "components" : { - "alpha" : "0.100", + "alpha" : "1.000", "blue" : "0x14", "green" : "0x14", "red" : "0x14" diff --git a/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestRouter.swift b/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestRouter.swift index a2d3fbd9d..76e35da11 100644 --- a/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestRouter.swift +++ b/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestRouter.swift @@ -10,7 +10,7 @@ final class AuthRequestRouter { } func dismiss() { - viewController.navigationController?.dismiss() + viewController.dismiss() UIApplication.shared.open(URL(string: "showcase://")!) } } diff --git a/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestView.swift b/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestView.swift index 6fd2380df..a78ccdfa5 100644 --- a/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestView.swift +++ b/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestView.swift @@ -47,7 +47,7 @@ struct AuthRequestView: View { VStack(spacing: 0) { HStack { - Text("presenter.message") + Text(presenter.message) .foregroundColor(.grey50) .font(.system(size: 13, weight: .semibold, design: .rounded)) diff --git a/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsView.swift b/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsView.swift index b0ff616e0..73d119cc5 100644 --- a/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsView.swift +++ b/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsView.swift @@ -4,143 +4,148 @@ struct ConnectionDetailsView: View { @EnvironmentObject var presenter: ConnectionDetailsPresenter var body: some View { - ScrollView { - VStack(spacing: 0) { - VStack(spacing: 2) { - Image("foundation") - .resizable() - .frame(width: 60, height: 60) - .background(Color.black) - .cornerRadius(30, corners: .allCorners) - .padding(.bottom, 6) - - Text("Foundation") - .foregroundColor(.grey8) - .font(.system(size: 22, weight: .bold, design: .rounded)) - - Text("foundation.app") - .foregroundColor(.grey50) - .font(.system(size: 13, weight: .medium, design: .rounded)) - } - - VStack { - VStack(alignment: .leading) { - Text("IEP155:1") - .font(.system(size: 15, weight: .semibold, design: .rounded)) - .foregroundColor(.whiteBackground) - .padding(.horizontal, 8) - .padding(.vertical, 5) - .background(Color.grey70) - .cornerRadius(28, corners: .allCorners) - .padding(.leading, 15) - .padding(.top, 9) + ZStack { + Color.grey100 + .edgesIgnoringSafeArea(.all) + + ScrollView { + VStack(spacing: 0) { + VStack(spacing: 2) { + Image("foundation") + .resizable() + .frame(width: 60, height: 60) + .background(Color.black) + .cornerRadius(30, corners: .allCorners) + .padding(.bottom, 6) - VStack(spacing: 0) { - HStack { - Text("Accounts") - .foregroundColor(.grey50) - .font(.system(size: 13, weight: .semibold, design: .rounded)) - - Spacer() + Text("Foundation") + .foregroundColor(.grey8) + .font(.system(size: 22, weight: .bold, design: .rounded)) + + Text("foundation.app") + .foregroundColor(.grey50) + .font(.system(size: 13, weight: .medium, design: .rounded)) + } + + VStack { + VStack(alignment: .leading) { + Text("IEP155:1") + .font(.system(size: 15, weight: .semibold, design: .rounded)) + .foregroundColor(.whiteBackground) + .padding(.horizontal, 8) + .padding(.vertical, 5) + .background(Color.grey70) + .cornerRadius(28, corners: .allCorners) + .padding(.leading, 15) + .padding(.top, 9) + + VStack(spacing: 0) { + HStack { + Text("Accounts") + .foregroundColor(.grey50) + .font(.system(size: 13, weight: .semibold, design: .rounded)) + + Spacer() + + Button { + // action + } label: { + Text("Add Account") + .foregroundColor(.blue100) + .font(.system(size: 13, weight: .semibold, design: .rounded)) + } + } + .padding(.horizontal, 18) + .padding(.top, 10) - Button { - // action - } label: { - Text("Add Account") - .foregroundColor(.blue100) + VStack { + Text("eip:155:1:0xe5eFf13687819212d25665fdB6946613dA6195a501") + .foregroundColor(.cyanBackround) .font(.system(size: 13, weight: .semibold, design: .rounded)) + .padding(.horizontal, 8) + .padding(.vertical, 3) + .background(Color.cyanBackround.opacity(0.2)) + .cornerRadius(10, corners: .allCorners) } - } - .padding(.horizontal, 18) - .padding(.top, 10) - - VStack { - Text("eip:155:1:0xe5eFf13687819212d25665fdB6946613dA6195a501") - .foregroundColor(.cyanBackround) - .font(.system(size: 13, weight: .semibold, design: .rounded)) - .padding(.horizontal, 8) - .padding(.vertical, 3) - .background(Color.cyanBackround.opacity(0.2)) - .cornerRadius(10, corners: .allCorners) - } - .padding(10) - - } - .background(Color.whiteBackground) - .cornerRadius(20, corners: .allCorners) - .padding(.horizontal, 5) - - VStack(spacing: 0) { - HStack { - Text("Methods") - .foregroundColor(.grey50) - .font(.system(size: 13, weight: .semibold, design: .rounded)) + .padding(10) - Spacer() - } - .padding(.horizontal, 18) - .padding(.top, 10) - - VStack { - Text("eip:155:1:0xe5eFf13687819212d25665fdB6946613dA6195a501") - .foregroundColor(.cyanBackround) - .font(.system(size: 13, weight: .semibold, design: .rounded)) - .padding(.horizontal, 8) - .padding(.vertical, 3) - .background(Color.cyanBackround.opacity(0.2)) - .cornerRadius(10, corners: .allCorners) } - .padding(10) + .background(Color.whiteBackground) + .cornerRadius(20, corners: .allCorners) + .padding(.horizontal, 5) - } - .background(Color.whiteBackground) - .cornerRadius(20, corners: .allCorners) - .padding(.horizontal, 5) - - VStack(spacing: 0) { - HStack { - Text("Events") - .foregroundColor(.grey50) - .font(.system(size: 13, weight: .semibold, design: .rounded)) + VStack(spacing: 0) { + HStack { + Text("Methods") + .foregroundColor(.grey50) + .font(.system(size: 13, weight: .semibold, design: .rounded)) + + Spacer() + } + .padding(.horizontal, 18) + .padding(.top, 10) + + VStack { + Text("eip:155:1:0xe5eFf13687819212d25665fdB6946613dA6195a501") + .foregroundColor(.cyanBackround) + .font(.system(size: 13, weight: .semibold, design: .rounded)) + .padding(.horizontal, 8) + .padding(.vertical, 3) + .background(Color.cyanBackround.opacity(0.2)) + .cornerRadius(10, corners: .allCorners) + } + .padding(10) - Spacer() } - .padding(.horizontal, 18) - .padding(.top, 10) + .background(Color.whiteBackground) + .cornerRadius(20, corners: .allCorners) + .padding(.horizontal, 5) - VStack { - Text("eip:155:1:0xe5eFf13687819212d25665fdB6946613dA6195a501") - .foregroundColor(.cyanBackround) - .font(.system(size: 13, weight: .regular)) - .padding(.horizontal, 8) - .padding(.vertical, 3) - .background(Color.cyanBackround.opacity(0.2)) - .cornerRadius(10, corners: .allCorners) + VStack(spacing: 0) { + HStack { + Text("Events") + .foregroundColor(.grey50) + .font(.system(size: 13, weight: .semibold, design: .rounded)) + + Spacer() + } + .padding(.horizontal, 18) + .padding(.top, 10) + + VStack { + Text("eip:155:1:0xe5eFf13687819212d25665fdB6946613dA6195a501") + .foregroundColor(.cyanBackround) + .font(.system(size: 13, weight: .regular)) + .padding(.horizontal, 8) + .padding(.vertical, 3) + .background(Color.cyanBackround.opacity(0.2)) + .cornerRadius(10, corners: .allCorners) + } + .padding(10) + } - .padding(10) - + .background(Color.whiteBackground) + .cornerRadius(20, corners: .allCorners) + .padding(.horizontal, 5) + .padding(.bottom, 5) } - .background(Color.whiteBackground) - .cornerRadius(20, corners: .allCorners) - .padding(.horizontal, 5) - .padding(.bottom, 5) + .background(Color("grey95")) + .cornerRadius(25, corners: .allCorners) } - .background(Color("grey95")) - .cornerRadius(25, corners: .allCorners) - } - .padding(.horizontal, 20) - .padding(.top, 30) - - Button { - // action - } label: { - Text("Delete") - .foregroundColor(.lightForegroundNegative) - .font(.system(size: 20, weight: .semibold, design: .rounded)) + .padding(.horizontal, 20) + .padding(.top, 30) + + Button { + // action + } label: { + Text("Delete") + .foregroundColor(.lightForegroundNegative) + .font(.system(size: 20, weight: .semibold, design: .rounded)) + } + .padding(.top, 20) + + Spacer() } - .padding(.top, 20) - - Spacer() } } } diff --git a/Example/ChatWallet/PresentationLayer/Wallet/PasteUri/PasteUriView.swift b/Example/ChatWallet/PresentationLayer/Wallet/PasteUri/PasteUriView.swift index f64b9886e..5c1ac8d47 100644 --- a/Example/ChatWallet/PresentationLayer/Wallet/PasteUri/PasteUriView.swift +++ b/Example/ChatWallet/PresentationLayer/Wallet/PasteUri/PasteUriView.swift @@ -12,6 +12,8 @@ struct PasteUriView: View { var body: some View { ZStack { Color(red: 20/255, green: 20/255, blue: 20/255, opacity: 0.4) + .edgesIgnoringSafeArea(.all) + VStack { Spacer() VStack(spacing: 6) { diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanModule.swift b/Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanModule.swift index eac6302cd..cf877ff7c 100644 --- a/Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanModule.swift +++ b/Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanModule.swift @@ -1,7 +1,6 @@ import SwiftUI final class ScanModule { - @discardableResult static func create( app: Application, @@ -18,5 +17,4 @@ final class ScanModule { return viewController } - } diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanPresenter.swift b/Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanPresenter.swift index f36c77456..53ab44c7c 100644 --- a/Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanPresenter.swift +++ b/Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanPresenter.swift @@ -2,7 +2,6 @@ import UIKit import Combine final class ScanPresenter: ObservableObject { - private let interactor: ScanInteractor private let router: ScanRouter @@ -23,26 +22,21 @@ final class ScanPresenter: ObservableObject { self.onValue = onValue self.onError = onError } -} - -// MARK: SceneViewModel - -extension ScanPresenter: SceneViewModel { - - var sceneTitle: String? { - return "Scan URI" - } - - var largeTitleDisplayMode: UINavigationItem.LargeTitleDisplayMode { - return .always + + func dismiss() { + router.dismiss() } } -// MARK: Privates +// MARK: - Private functions private extension ScanPresenter { - func setupInitialState() { } } + +// MARK: - SceneViewModel +extension ScanPresenter: SceneViewModel { + +} diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanRouter.swift b/Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanRouter.swift index eef0df5c6..cdd0e33e2 100644 --- a/Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanRouter.swift +++ b/Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanRouter.swift @@ -1,7 +1,6 @@ import UIKit final class ScanRouter { - weak var viewController: UIViewController! private let app: Application @@ -9,4 +8,8 @@ final class ScanRouter { init(app: Application) { self.app = app } + + func dismiss() { + viewController.dismiss() + } } diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanView.swift b/Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanView.swift index f8f36e7bb..756698bad 100644 --- a/Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanView.swift +++ b/Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanView.swift @@ -1,12 +1,41 @@ import SwiftUI struct ScanView: View { - @EnvironmentObject var presenter: ScanPresenter var body: some View { - ScanQR(onValue: presenter.onValue, onError: presenter.onError) - .ignoresSafeArea() + ZStack { + // ScanQR(onValue: presenter.onValue, onError: presenter.onError) + // .ignoresSafeArea() + ScanQR(onValue: { _ in }, onError: { _ in }) + .ignoresSafeArea() + + VStack { + ZStack { + Text("Scan the code") + .foregroundColor(.white) + .font(.system(size: 20, weight: .semibold, design: .rounded)) + + HStack { + Spacer() + + Button { + presenter.dismiss() + } label: { + Image(systemName: "xmark.circle.fill") + .resizable() + .foregroundColor(.grey95) + .frame(width: 30, height: 30) + } + } + .padding(.trailing, 30) + } + + Spacer() + } + .padding(.top, 24) + } + .navigationBarHidden(true) } } diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Scan/Views/ScanQRView.swift b/Example/ChatWallet/PresentationLayer/Wallet/Scan/Views/ScanQRView.swift index 08ce85b45..165028ad6 100644 --- a/Example/ChatWallet/PresentationLayer/Wallet/Scan/Views/ScanQRView.swift +++ b/Example/ChatWallet/PresentationLayer/Wallet/Scan/Views/ScanQRView.swift @@ -22,8 +22,7 @@ final class ScanQRView: UIView { private var captureSession: AVCaptureSession? private lazy var borderView: UIView = { - let borderView = ScanTargetView(radius: 24.0, color: .white, strokeWidth: 2.0, length: 36.0) - borderView.alpha = 0.85 + let borderView = ScanTargetView(radius: 24.0, color: UIColor(displayP3Red: 184/255, green: 245/255, blue: 61/255, alpha: 1.0), strokeWidth: 7, length: 60) return borderView }() diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletView.swift b/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletView.swift index b37592209..df163fec1 100644 --- a/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletView.swift +++ b/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletView.swift @@ -4,53 +4,55 @@ struct WalletView: View { @EnvironmentObject var presenter: WalletPresenter var body: some View { - VStack(alignment: .leading, spacing: 16) { - ZStack { - if false { - VStack(spacing: 10) { - Image("connect-template") - - Text("Apps you connect with will appear here. To connect 􀎹 scan or 􀐅 paste the code that’s displayed in the app.") - .foregroundColor(.grey50) - .font(.system(size: 15, weight: .regular, design: .rounded)) - .multilineTextAlignment(.center) - .lineSpacing(4) - } - } - - VStack { - ScrollView { - connectionView() - connectionView() - connectionView() - connectionView() + ZStack { + Color.grey100 + .edgesIgnoringSafeArea(.all) + + VStack(alignment: .leading, spacing: 16) { + ZStack { + if false { + VStack(spacing: 10) { + Image("connect-template") + + Text("Apps you connect with will appear here. To connect 􀎹 scan or 􀐅 paste the code that’s displayed in the app.") + .foregroundColor(.grey50) + .font(.system(size: 15, weight: .regular, design: .rounded)) + .multilineTextAlignment(.center) + .lineSpacing(4) + } } - HStack(spacing: 20) { - Spacer() - - Button { - presenter.onPasteUri() - } label: { - Image("copy") - .resizable() - .frame(width: 56, height: 56) + VStack { + ScrollView { + connectionView() } - .shadow(color: .black.opacity(0.25), radius: 8, y: 4) - Button { - presenter.onScanUri() - } label: { - Image("scan") - .resizable() - .frame(width: 56, height: 56) + HStack(spacing: 20) { + Spacer() + + Button { + presenter.onPasteUri() + } label: { + Image("copy") + .resizable() + .frame(width: 56, height: 56) + } + .shadow(color: .black.opacity(0.25), radius: 8, y: 4) + + Button { + presenter.onScanUri() + } label: { + Image("scan") + .resizable() + .frame(width: 56, height: 56) + } + .shadow(color: .black.opacity(0.25), radius: 8, y: 4) } - .shadow(color: .black.opacity(0.25), radius: 8, y: 4) } } } + .padding(20) } - .padding(20) } private func connectionView() -> some View { diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Welcome/WelcomeView.swift b/Example/ChatWallet/PresentationLayer/Wallet/Welcome/WelcomeView.swift index e6bf21b0a..42c65d8e8 100644 --- a/Example/ChatWallet/PresentationLayer/Wallet/Welcome/WelcomeView.swift +++ b/Example/ChatWallet/PresentationLayer/Wallet/Welcome/WelcomeView.swift @@ -7,6 +7,9 @@ struct WelcomeView: View { var body: some View { ZStack { + Color.grey100 + .edgesIgnoringSafeArea(.all) + VStack(spacing: 0) { Text("Welcome") .foregroundColor(.grey8) diff --git a/Example/Showcase/Classes/ApplicationLayer/SceneDelegate.swift b/Example/Showcase/Classes/ApplicationLayer/SceneDelegate.swift index 7681f528a..537e88926 100644 --- a/Example/Showcase/Classes/ApplicationLayer/SceneDelegate.swift +++ b/Example/Showcase/Classes/ApplicationLayer/SceneDelegate.swift @@ -30,8 +30,12 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { guard let context = URLContexts.first else { return } let uri = context.url.absoluteString.replacingOccurrences(of: "showcase://wc?uri=", with: "") + guard let walletConnectUri = WalletConnectURI(string: uri) else { + return + } + Task { - try await Pair.instance.pair(uri: WalletConnectURI(string: uri)!) + try await Pair.instance.pair(uri: walletConnectUri) } } } From 6d177f4d9b3cf5791f88c465107985ae8e763b45 Mon Sep 17 00:00:00 2001 From: Alexander Lisovik Date: Tue, 3 Jan 2023 14:41:13 +0100 Subject: [PATCH 04/14] Update tests, UI, import Web3Wallet --- .../Configurator/ThirdPartyConfigurator.swift | 18 ++++----- .../AuthRequest/AuthRequestInteractor.swift | 9 ++--- .../AuthRequest/AuthRequestModule.swift | 3 +- .../AuthRequest/AuthRequestPresenter.swift | 6 ++- .../AuthRequest/AuthRequestRouter.swift | 1 - .../Wallet/AuthRequest/AuthRequestView.swift | 4 +- .../ConnectionDetailsInteractor.swift | 7 ++-- .../ConnectionDetailsModule.swift | 10 ++++- .../ConnectionDetailsPresenter.swift | 13 ++++++- .../ConnectionDetailsRouter.swift | 2 +- .../ConnectionDetailsView.swift | 24 ++++++++---- .../Wallet/Wallet/WalletInteractor.swift | 22 +++++++---- .../Wallet/Wallet/WalletPresenter.swift | 21 +++++++--- .../Wallet/Wallet/WalletRouter.swift | 7 ++-- .../Wallet/Wallet/WalletView.swift | 39 +++++++++++++------ Example/ExampleApp.xcodeproj/project.pbxproj | 11 +++++- .../Chat/Welcome/WelcomeInteractor.swift | 1 - Sources/Auth/AuthClientProtocol.swift | 1 + .../Sign/SignClientProtocol.swift | 1 + Sources/Web3Wallet/Web3Wallet.swift | 2 +- Sources/Web3Wallet/Web3WalletClient.swift | 14 ++++++- .../Mocks/AuthClientMock.swift | 5 +++ .../Mocks/SignClientMock.swift | 13 ++++++- Tests/Web3WalletTests/Web3WalletTests.swift | 23 ++++++++++- 24 files changed, 181 insertions(+), 76 deletions(-) diff --git a/Example/ChatWallet/ApplicationLayer/Configurator/ThirdPartyConfigurator.swift b/Example/ChatWallet/ApplicationLayer/Configurator/ThirdPartyConfigurator.swift index c48dbc609..fe19bbb99 100644 --- a/Example/ChatWallet/ApplicationLayer/Configurator/ThirdPartyConfigurator.swift +++ b/Example/ChatWallet/ApplicationLayer/Configurator/ThirdPartyConfigurator.swift @@ -1,18 +1,16 @@ import WalletConnectNetworking -import WalletConnectPairing -import Auth +import Web3Wallet struct ThirdPartyConfigurator: Configurator { func configure() { Networking.configure(projectId: InputConfig.projectId, socketFactory: SocketFactory()) - Pair.configure( - metadata: AppMetadata( - name: "Showcase App", - description: "Showcase description", - url: "example.wallet", - icons: ["https://avatars.githubusercontent.com/u/37784886"] - )) - Auth.configure(signerFactory: DefaultSignerFactory()) + let metadata = AppMetadata( + name: "Example Wallet", + description: "wallet description", + url: "example.wallet", + icons: ["https://avatars.githubusercontent.com/u/37784886"] + ) + Web3Wallet.configure(metadata: metadata, signerFactory: DefaultSignerFactory()) } } diff --git a/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestInteractor.swift b/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestInteractor.swift index 7a259c6f4..361d0b8fe 100644 --- a/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestInteractor.swift +++ b/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestInteractor.swift @@ -1,6 +1,5 @@ import Foundation -import Auth -import WalletConnectUtils +import Web3Wallet final class AuthRequestInteractor { private let signer = MessageSignerFactory(signerFactory: DefaultSignerFactory()).create() @@ -13,15 +12,15 @@ final class AuthRequestInteractor { address: account.address, privateKey: privateKey, type: .eip191) - try await Auth.instance.respond(requestId: request.id, signature: signature, from: account) + try await Web3Wallet.instance.respond(requestId: request.id, signature: signature, from: account) } func reject(request: AuthRequest) async throws { - try await Auth.instance.reject(requestId: request.id) + try await Web3Wallet.instance.reject(requestId: request.id) } func formatted(request: AuthRequest) -> String { - return try! Auth.instance.formatMessage( + return try! Web3Wallet.instance.formatMessage( payload: request.payload, address: account.address ) diff --git a/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestModule.swift b/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestModule.swift index b8e05863f..484e7d354 100644 --- a/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestModule.swift +++ b/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestModule.swift @@ -1,5 +1,5 @@ import SwiftUI -import Auth +import Web3Wallet final class AuthRequestModule { @discardableResult @@ -14,5 +14,4 @@ final class AuthRequestModule { return viewController } - } diff --git a/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestPresenter.swift b/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestPresenter.swift index f69f97ea3..56d11f511 100644 --- a/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestPresenter.swift +++ b/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestPresenter.swift @@ -1,12 +1,14 @@ import UIKit import Combine -import Auth + +import Web3Wallet final class AuthRequestPresenter: ObservableObject { private let interactor: AuthRequestInteractor private let router: AuthRequestRouter - private let request: AuthRequest + let request: AuthRequest + var message: String { return interactor.formatted(request: request) } diff --git a/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestRouter.swift b/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestRouter.swift index 76e35da11..d21c62d49 100644 --- a/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestRouter.swift +++ b/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestRouter.swift @@ -11,6 +11,5 @@ final class AuthRequestRouter { func dismiss() { viewController.dismiss() - UIApplication.shared.open(URL(string: "showcase://")!) } } diff --git a/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestView.swift b/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestView.swift index a78ccdfa5..d5fa473ed 100644 --- a/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestView.swift +++ b/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestView.swift @@ -17,7 +17,7 @@ struct AuthRequestView: View { .resizable() .scaledToFit() - Text("Foundation") + Text(presenter.request.payload.domain) .foregroundColor(.grey8) .font(.system(size: 22, weight: .bold, design: .rounded)) .padding(.top, 10) @@ -26,7 +26,7 @@ struct AuthRequestView: View { .foregroundColor(.grey8) .font(.system(size: 22, weight: .medium, design: .rounded)) - Text("foundation.app") + Text(presenter.request.payload.domain) .foregroundColor(.grey50) .font(.system(size: 13, weight: .semibold, design: .rounded)) .multilineTextAlignment(.center) diff --git a/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsInteractor.swift b/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsInteractor.swift index fe9d868c9..6de01c7b5 100644 --- a/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsInteractor.swift +++ b/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsInteractor.swift @@ -1,13 +1,12 @@ import Combine -import Auth -import WalletConnectPairing +import Web3Wallet final class ConnectionDetailsInteractor { func pair(uri: WalletConnectURI) async throws { - try await Pair.instance.pair(uri: uri) + try await Web3Wallet.instance.pair(uri: uri) } var requestPublisher: AnyPublisher { - return Auth.instance.authRequestPublisher + return Web3Wallet.instance.authRequestPublisher } } diff --git a/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsModule.swift b/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsModule.swift index 3dbb03006..d42807d98 100644 --- a/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsModule.swift +++ b/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsModule.swift @@ -1,11 +1,17 @@ import SwiftUI +import Web3Wallet + final class ConnectionDetailsModule { @discardableResult - static func create(app: Application) -> UIViewController { + static func create(app: Application, session: Session) -> UIViewController { let router = ConnectionDetailsRouter(app: app) let interactor = ConnectionDetailsInteractor() - let presenter = ConnectionDetailsPresenter(interactor: interactor, router: router) + let presenter = ConnectionDetailsPresenter( + interactor: interactor, + router: router, + session: session + ) let view = ConnectionDetailsView().environmentObject(presenter) let viewController = SceneViewController(viewModel: presenter, content: view) diff --git a/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsPresenter.swift b/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsPresenter.swift index 7e19962a2..f799e5013 100644 --- a/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsPresenter.swift +++ b/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsPresenter.swift @@ -1,17 +1,26 @@ import UIKit import Combine + import Auth +import Web3Wallet final class ConnectionDetailsPresenter: ObservableObject { - private let interactor: ConnectionDetailsInteractor private let router: ConnectionDetailsRouter + + let session: Session + private var disposeBag = Set() - init(interactor: ConnectionDetailsInteractor, router: ConnectionDetailsRouter) { + init( + interactor: ConnectionDetailsInteractor, + router: ConnectionDetailsRouter, + session: Session + ) { defer { setupInitialState() } self.interactor = interactor self.router = router + self.session = session } func didPastePairingURI() { diff --git a/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsRouter.swift b/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsRouter.swift index 5b8be58c0..eac9622e5 100644 --- a/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsRouter.swift +++ b/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsRouter.swift @@ -1,5 +1,5 @@ import UIKit -import Auth +import Web3Wallet final class ConnectionDetailsRouter { weak var viewController: UIViewController! diff --git a/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsView.swift b/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsView.swift index 73d119cc5..973e002ee 100644 --- a/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsView.swift +++ b/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsView.swift @@ -11,18 +11,26 @@ struct ConnectionDetailsView: View { ScrollView { VStack(spacing: 0) { VStack(spacing: 2) { - Image("foundation") - .resizable() - .frame(width: 60, height: 60) - .background(Color.black) - .cornerRadius(30, corners: .allCorners) - .padding(.bottom, 6) + AsyncImage(url: URL(string: session.peer.icons.first ?? "")) { phase in + if let image = phase.image { + image + .resizable() + .frame(width: 60, height: 60) + .background(Color.black) + .cornerRadius(30, corners: .allCorners) + } else { + Color.black + .frame(width: 60, height: 60) + .cornerRadius(30, corners: .allCorners) + } + } + .padding(.bottom, 6) - Text("Foundation") + Text(presenter.session.peer.name) .foregroundColor(.grey8) .font(.system(size: 22, weight: .bold, design: .rounded)) - Text("foundation.app") + Text(presenter.session.peer.url) .foregroundColor(.grey50) .font(.system(size: 13, weight: .medium, design: .rounded)) } diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletInteractor.swift b/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletInteractor.swift index e16c8dec3..1b921bf81 100644 --- a/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletInteractor.swift +++ b/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletInteractor.swift @@ -1,13 +1,21 @@ import Combine -import Auth -import WalletConnectPairing -final class WalletInteractor { - func pair(uri: WalletConnectURI) async throws { - try await Pair.instance.pair(uri: uri) - } +import Web3Wallet +final class WalletInteractor { var requestPublisher: AnyPublisher { - return Auth.instance.authRequestPublisher + return Web3Wallet.instance.authRequestPublisher + } + + var sessionsPublisher: AnyPublisher<[Session], Never> { + return Web3Wallet.instance.sessionsPublisher + } + + func getSessions() -> [Session] { + return Web3Wallet.instance.getSessions() + } + + func pair(uri: WalletConnectURI) async throws { + try await Web3Wallet.instance.pair(uri: uri) } } diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletPresenter.swift b/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletPresenter.swift index c2ef79e03..b973a5ece 100644 --- a/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletPresenter.swift +++ b/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletPresenter.swift @@ -1,11 +1,14 @@ import UIKit import Combine -import Auth + +import Web3Wallet final class WalletPresenter: ObservableObject { private let interactor: WalletInteractor private let router: WalletRouter + @Published var sessions = [Session]() + private let uri: String? private var disposeBag = Set() @@ -23,8 +26,8 @@ final class WalletPresenter: ObservableObject { self.uri = uri } - func onConnection() { - router.presentConnectionDetails() + func onConnection(session: Session) { + router.presentConnectionDetails(session: session) } func onPasteUri() { @@ -56,9 +59,15 @@ final class WalletPresenter: ObservableObject { // MARK: - Private functions extension WalletPresenter { private func setupInitialState() { - interactor.requestPublisher.sink { [unowned self] request in - self.router.present(request: request) - }.store(in: &disposeBag) + interactor.requestPublisher.sink { [weak self] request in + self?.router.present(request: request) + } + .store(in: &disposeBag) + + interactor.sessionsPublisher.sink { [weak self] sessions in + self?.sessions = sessions + } + .store(in: &disposeBag) pairFropDapp() } diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletRouter.swift b/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletRouter.swift index 07563d4f0..951661eba 100644 --- a/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletRouter.swift +++ b/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletRouter.swift @@ -1,5 +1,6 @@ import UIKit -import Auth + +import Web3Wallet final class WalletRouter { weak var viewController: UIViewController! @@ -20,8 +21,8 @@ final class WalletRouter { .presentFullScreen(from: viewController, transparentBackground: true) } - func presentConnectionDetails() { - ConnectionDetailsModule.create(app: app) + func presentConnectionDetails(session: Session) { + ConnectionDetailsModule.create(app: app, session: session) .push(from: viewController) } diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletView.swift b/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletView.swift index df163fec1..dcf4d7923 100644 --- a/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletView.swift +++ b/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletView.swift @@ -1,4 +1,5 @@ import SwiftUI +import Web3Wallet struct WalletView: View { @EnvironmentObject var presenter: WalletPresenter @@ -10,7 +11,7 @@ struct WalletView: View { VStack(alignment: .leading, spacing: 16) { ZStack { - if false { + if presenter.sessions.isEmpty { VStack(spacing: 10) { Image("connect-template") @@ -23,10 +24,16 @@ struct WalletView: View { } VStack { - ScrollView { - connectionView() + if !presenter.sessions.isEmpty { + ScrollView { + ForEach(presenter.sessions, id: \.peer.name) { session in + connectionView(session: session) + } + } } + Spacer() + HStack(spacing: 20) { Spacer() @@ -55,24 +62,32 @@ struct WalletView: View { } } - private func connectionView() -> some View { + private func connectionView(session: Session) -> some View { Button { - presenter.onConnection() + presenter.onConnection(session: session) } label: { VStack { HStack(spacing: 10) { - Image("foundation") - .resizable() - .frame(width: 60, height: 60) - .background(Color.black) - .cornerRadius(30, corners: .allCorners) + AsyncImage(url: URL(string: session.peer.icons.first ?? "")) { phase in + if let image = phase.image { + image + .resizable() + .frame(width: 60, height: 60) + .background(Color.black) + .cornerRadius(30, corners: .allCorners) + } else { + Color.black + .frame(width: 60, height: 60) + .cornerRadius(30, corners: .allCorners) + } + } VStack(alignment: .leading, spacing: 2) { - Text("Foundation") + Text(session.peer.name) .foregroundColor(.grey8) .font(.system(size: 20, weight: .semibold, design: .rounded)) - Text("foundation.app") + Text(session.peer.url) .foregroundColor(.grey50) .font(.system(size: 13, weight: .medium, design: .rounded)) } diff --git a/Example/ExampleApp.xcodeproj/project.pbxproj b/Example/ExampleApp.xcodeproj/project.pbxproj index 4b4318187..368f92324 100644 --- a/Example/ExampleApp.xcodeproj/project.pbxproj +++ b/Example/ExampleApp.xcodeproj/project.pbxproj @@ -197,6 +197,7 @@ C55D3495295DFA750004314A /* WelcomeRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D3490295DFA750004314A /* WelcomeRouter.swift */; }; C55D3496295DFA750004314A /* WelcomeInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D3491295DFA750004314A /* WelcomeInteractor.swift */; }; C55D3497295DFA750004314A /* WelcomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D3492295DFA750004314A /* WelcomeView.swift */; }; + C55D349929630D440004314A /* Web3Wallet in Frameworks */ = {isa = PBXBuildFile; productRef = C55D349829630D440004314A /* Web3Wallet */; }; C56EE222293F55EE004840D1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C56EE221293F55EE004840D1 /* Assets.xcassets */; }; C56EE240293F566D004840D1 /* ScanQRView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE23F293F566C004840D1 /* ScanQRView.swift */; }; C56EE241293F566D004840D1 /* WalletModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE22D293F5669004840D1 /* WalletModule.swift */; }; @@ -236,13 +237,13 @@ C56EE29C293F5773004840D1 /* ChatService.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE295293F5773004840D1 /* ChatService.swift */; }; C56EE29D293F5773004840D1 /* RegisterService.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE294293F5773004840D1 /* RegisterService.swift */; }; C56EE2A3293F6BAF004840D1 /* UIPasteboardWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE2A2293F6BAF004840D1 /* UIPasteboardWrapper.swift */; }; + C5DD5BE1294E09E3008FD3A4 /* Web3Wallet in Frameworks */ = {isa = PBXBuildFile; productRef = C5DD5BE0294E09E3008FD3A4 /* Web3Wallet */; }; C5F32A2C2954814200A6476E /* ConnectionDetailsModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5F32A2B2954814200A6476E /* ConnectionDetailsModule.swift */; }; C5F32A2E2954814A00A6476E /* ConnectionDetailsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5F32A2D2954814A00A6476E /* ConnectionDetailsRouter.swift */; }; C5F32A302954816100A6476E /* ConnectionDetailsInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5F32A2F2954816100A6476E /* ConnectionDetailsInteractor.swift */; }; C5F32A322954816C00A6476E /* ConnectionDetailsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5F32A312954816C00A6476E /* ConnectionDetailsPresenter.swift */; }; C5F32A342954817600A6476E /* ConnectionDetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5F32A332954817600A6476E /* ConnectionDetailsView.swift */; }; C5F32A362954FE3C00A6476E /* Colors.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C5F32A352954FE3C00A6476E /* Colors.xcassets */; }; - C5DD5BE1294E09E3008FD3A4 /* Web3Wallet in Frameworks */ = {isa = PBXBuildFile; productRef = C5DD5BE0294E09E3008FD3A4 /* Web3Wallet */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -548,6 +549,7 @@ files = ( C56EE27D293F56F8004840D1 /* WalletConnectChat in Frameworks */, C5133A78294125CC00A8314C /* Web3 in Frameworks */, + C55D349929630D440004314A /* Web3Wallet in Frameworks */, C56EE255293F569A004840D1 /* Starscream in Frameworks */, C56EE27B293F56F8004840D1 /* WalletConnectAuth in Frameworks */, ); @@ -1631,6 +1633,7 @@ C56EE27A293F56F8004840D1 /* WalletConnectAuth */, C56EE27C293F56F8004840D1 /* WalletConnectChat */, C5133A77294125CC00A8314C /* Web3 */, + C55D349829630D440004314A /* Web3Wallet */, ); productName = ChatWallet; productReference = C56EE21B293F55ED004840D1 /* ChatWallet.app */; @@ -2668,6 +2671,10 @@ package = A5AE354528A1A2AC0059AE8A /* XCRemoteSwiftPackageReference "Web3" */; productName = Web3; }; + C55D349829630D440004314A /* Web3Wallet */ = { + isa = XCSwiftPackageProductDependency; + productName = Web3Wallet; + }; C56EE254293F569A004840D1 /* Starscream */ = { isa = XCSwiftPackageProductDependency; package = A5D85224286333D500DAF5C3 /* XCRemoteSwiftPackageReference "Starscream" */; @@ -2680,7 +2687,7 @@ C56EE27C293F56F8004840D1 /* WalletConnectChat */ = { isa = XCSwiftPackageProductDependency; productName = WalletConnectChat; - }; + }; C5DD5BE0294E09E3008FD3A4 /* Web3Wallet */ = { isa = XCSwiftPackageProductDependency; productName = Web3Wallet; diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomeInteractor.swift b/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomeInteractor.swift index 40210dbab..0ddc53aec 100644 --- a/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomeInteractor.swift +++ b/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomeInteractor.swift @@ -69,7 +69,6 @@ final class WelcomeInteractor { authClient = AuthClientFactory.create( metadata: AppMetadata(name: "chatapp", description: "", url: "", icons: [""]), - account: nil, projectId: InputConfig.projectId, signerFactory: DefaultSignerFactory(), networkingClient: networkingClient, diff --git a/Sources/Auth/AuthClientProtocol.swift b/Sources/Auth/AuthClientProtocol.swift index 2604ac2f2..9e1a1fb62 100644 --- a/Sources/Auth/AuthClientProtocol.swift +++ b/Sources/Auth/AuthClientProtocol.swift @@ -6,5 +6,6 @@ public protocol AuthClientProtocol { func formatMessage(payload: AuthPayload, address: String) throws -> String func respond(requestId: RPCID, signature: CacaoSignature, from account: Account) async throws + func reject(requestId: RPCID) async throws func getPendingRequests(account: Account) throws -> [AuthRequest] } diff --git a/Sources/WalletConnectSign/Sign/SignClientProtocol.swift b/Sources/WalletConnectSign/Sign/SignClientProtocol.swift index 933d476ba..d176a0e51 100644 --- a/Sources/WalletConnectSign/Sign/SignClientProtocol.swift +++ b/Sources/WalletConnectSign/Sign/SignClientProtocol.swift @@ -4,6 +4,7 @@ import Combine public protocol SignClientProtocol { var sessionProposalPublisher: AnyPublisher { get } var sessionRequestPublisher: AnyPublisher { get } + var sessionsPublisher: AnyPublisher<[Session], Never> { get } func approve(proposalId: String, namespaces: [String: SessionNamespace]) async throws func reject(proposalId: String, reason: RejectionReason) async throws diff --git a/Sources/Web3Wallet/Web3Wallet.swift b/Sources/Web3Wallet/Web3Wallet.swift index 38eabb617..3fb7bc876 100644 --- a/Sources/Web3Wallet/Web3Wallet.swift +++ b/Sources/Web3Wallet/Web3Wallet.swift @@ -17,7 +17,7 @@ public class Web3Wallet { /// Web3Wallett client instance public static var instance: Web3WalletClient = { guard let config = Web3Wallet.config else { - fatalError("Error - you must call Wallet.configure(_:) before accessing the shared instance.") + fatalError("Error - you must call Web3Wallet.configure(_:) before accessing the shared instance.") } return Web3WalletClientFactory.create( diff --git a/Sources/Web3Wallet/Web3WalletClient.swift b/Sources/Web3Wallet/Web3WalletClient.swift index 196a0a471..43c709b95 100644 --- a/Sources/Web3Wallet/Web3WalletClient.swift +++ b/Sources/Web3Wallet/Web3WalletClient.swift @@ -29,6 +29,13 @@ public class Web3WalletClient { public var authRequestPublisher: AnyPublisher { authClient.authRequestPublisher.eraseToAnyPublisher() } + + /// Publisher that sends sessions on every sessions update + /// + /// Event will be emited on controller and non-controller clients. + public var sessionsPublisher: AnyPublisher<[Session], Never> { + signClient.sessionsPublisher.eraseToAnyPublisher() + } // MARK: - Private Properties private let authClient: AuthClientProtocol @@ -62,6 +69,12 @@ public class Web3WalletClient { public func reject(proposalId: String, reason: RejectionReason) async throws { try await signClient.reject(proposalId: proposalId, reason: reason) } + + /// For wallet to reject authentication request + /// - Parameter requestId: authentication request id + public func reject(requestId: RPCID) async throws { + try await authClient.reject(requestId: requestId) + } /// For the wallet to update session namespaces /// - Parameters: @@ -123,7 +136,6 @@ public class Web3WalletClient { try await signClient.disconnect(topic: topic) } - /// Query sessions /// - Returns: All sessions public func getSessions() -> [Session] { diff --git a/Tests/Web3WalletTests/Mocks/AuthClientMock.swift b/Tests/Web3WalletTests/Mocks/AuthClientMock.swift index 2b5a407f7..3b1a3a68d 100644 --- a/Tests/Web3WalletTests/Mocks/AuthClientMock.swift +++ b/Tests/Web3WalletTests/Mocks/AuthClientMock.swift @@ -5,6 +5,7 @@ import Combine final class AuthClientMock: AuthClientProtocol { var respondCalled = false + var rejectCalled = false private var authRequest: AuthRequest { let requestParams = RequestParams( @@ -37,6 +38,10 @@ final class AuthClientMock: AuthClientProtocol { respondCalled = true } + func reject(requestId: JSONRPC.RPCID) async throws { + rejectCalled = true + } + func getPendingRequests(account: WalletConnectUtils.Account) throws -> [AuthRequest] { return [authRequest] } diff --git a/Tests/Web3WalletTests/Mocks/SignClientMock.swift b/Tests/Web3WalletTests/Mocks/SignClientMock.swift index dacd19109..72ad8f006 100644 --- a/Tests/Web3WalletTests/Mocks/SignClientMock.swift +++ b/Tests/Web3WalletTests/Mocks/SignClientMock.swift @@ -4,6 +4,8 @@ import Combine @testable import WalletConnectSign final class SignClientMock: SignClientProtocol { + + var approveCalled = false var rejectCalled = false var updateCalled = false @@ -25,11 +27,18 @@ final class SignClientMock: SignClientProtocol { ) .publicRepresentation() - return Result.Publisher(sessionProposal).eraseToAnyPublisher() + return Result.Publisher(sessionProposal) + .eraseToAnyPublisher() } var sessionRequestPublisher: AnyPublisher { - return Result.Publisher(request).eraseToAnyPublisher() + return Result.Publisher(request) + .eraseToAnyPublisher() + } + + var sessionsPublisher: AnyPublisher<[WalletConnectSign.Session], Never> { + return Result.Publisher([WalletConnectSign.Session(topic: "", peer: metadata, namespaces: [:], expiryDate: Date())]) + .eraseToAnyPublisher() } func approve(proposalId: String, namespaces: [String : WalletConnectSign.SessionNamespace]) async throws { diff --git a/Tests/Web3WalletTests/Web3WalletTests.swift b/Tests/Web3WalletTests/Web3WalletTests.swift index 5aff74851..7ce173cc5 100644 --- a/Tests/Web3WalletTests/Web3WalletTests.swift +++ b/Tests/Web3WalletTests/Web3WalletTests.swift @@ -69,16 +69,36 @@ final class Web3WalletTests: XCTestCase { } } + func testSessionsCalled() { + var success = false + web3WalletClient.sessionsPublisher.sink { value in + success = true + XCTAssertTrue(true) + } + .store(in: &disposeBag) + + let expectation = expectation(description: "Fail after 0.1s timeout") + let result = XCTWaiter.wait(for: [expectation], timeout: 0.1) + if result == XCTWaiter.Result.timedOut && success == false { + XCTFail() + } + } + func testApproveCalled() async { try! await web3WalletClient.approve(proposalId: "", namespaces: [:]) XCTAssertTrue(signClient.approveCalled) } - func testRejectCalled() async { + func testRejectSessionCalled() async { try! await web3WalletClient.reject(proposalId: "", reason: .userRejected) XCTAssertTrue(signClient.rejectCalled) } + func testRejectAuthRequestCalled() async { + try! await web3WalletClient.reject(requestId: .left("")) + XCTAssertTrue(authClient.rejectCalled) + } + func testUpdateCalled() async { try! await web3WalletClient.update(topic: "", namespaces: [:]) XCTAssertTrue(signClient.updateCalled) @@ -171,4 +191,3 @@ final class Web3WalletTests: XCTestCase { XCTAssertEqual(1, pendingRequests.count) } } - From b1ea6b44183662e6ed9549864fe4a6ebb5317b66 Mon Sep 17 00:00:00 2001 From: Alexander Lisovik Date: Tue, 3 Jan 2023 14:52:27 +0100 Subject: [PATCH 05/14] Rename wallet app --- Example/ExampleApp.xcodeproj/project.pbxproj | 30 +++++++++--------- ...ChatWallet.xcscheme => WalletApp.xcscheme} | 12 +++---- .../Chat/Welcome/WelcomeRouter.swift | 2 +- .../ApplicationLayer/AppDelegate.swift | 0 .../ApplicationLayer/Application.swift | 0 .../Configurator/AppearanceConfigurator.swift | 0 .../ApplicationConfigurator.swift | 0 .../Configurator/Configurator.swift | 0 .../Configurator/MigrationConfigurator.swift | 0 .../Configurator/ThirdPartyConfigurator.swift | 0 .../ApplicationLayer/SceneDelegate.swift | 4 +-- .../Common/Extensions/SwiftUI/View.swift | 0 .../Common/Extensions/UIKit/String.swift | 0 .../Common/Extensions/UIKit/UIColor.swift | 0 .../Extensions/UIKit/UIViewController.swift | 0 .../Common/Helpers/UIPasteboardWrapper.swift | 0 .../Common/InputConfig.swift | 0 .../Common/Style/Color.swift | 0 .../Common/Types/Types.swift | 0 .../Common/VIPER/SceneViewController.swift | 0 .../AccountStorage/AccountStorage.swift | 0 .../Chat/AccountNameResolver.swift | 0 .../DomainLayer/Chat/ChatService.swift | 0 .../DomainLayer/Chat/RegisterService.swift | 0 .../SocketFactory/SocketFactory.swift | 0 .../AccentColor.colorset/Contents.json | 0 .../AppIcon.appiconset/Contents.json | 0 .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin .../Icon-App-20x20@2x-1.png | Bin .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin .../Icon-App-29x29@2x-1.png | Bin .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin .../Icon-App-40x40@2x-1.png | Bin .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin .../Icon-App-83.5x83.5@2x.png | Bin .../AppIcon.appiconset/ItunesArtwork@2x.png | Bin .../Other/Assets.xcassets/Contents.json | 0 .../connect-template.imageset/Contents.json | 0 .../connect-template.svg | 0 .../copy.imageset/Contents.json | 0 .../Assets.xcassets/copy.imageset/copy.svg | 0 .../forward-shevron.imageset/Contents.json | 0 .../forward-shevron.svg | 0 .../foundation.imageset/Contents.json | 0 .../foundation.imageset/foundation.svg | 0 .../header.imageset/Contents.json | 0 .../header.imageset/Visual.svg | 0 .../scan.imageset/Contents.json | 0 .../Assets.xcassets/scan.imageset/scan.svg | 0 .../Other/Colors.xcassets/Contents.json | 0 .../blue100.colorset/Contents.json | 0 .../blue200.colorset/Contents.json | 0 .../cyan-background.colorset/Contents.json | 0 .../Contents.json | 0 .../Contents.json | 0 .../grey100.colorset/Contents.json | 0 .../grey50.colorset/Contents.json | 0 .../grey70.colorset/Contents.json | 0 .../grey8.colorset/Contents.json | 0 .../grey95.colorset/Contents.json | 0 .../light-background.colorset/Contents.json | 0 .../light-blue.colorset/Contents.json | 0 .../Contents.json | 0 .../Contents.json | 0 .../system-gray-light.colorset/Contents.json | 0 .../white-background.colorset/Contents.json | 0 .../Other/Info.plist | 2 +- .../AuthRequest/AuthRequestInteractor.swift | 0 .../AuthRequest/AuthRequestModule.swift | 0 .../AuthRequest/AuthRequestPresenter.swift | 0 .../AuthRequest/AuthRequestRouter.swift | 0 .../Wallet/AuthRequest/AuthRequestView.swift | 0 .../ConnectionDetailsInteractor.swift | 0 .../ConnectionDetailsModule.swift | 0 .../ConnectionDetailsPresenter.swift | 0 .../ConnectionDetailsRouter.swift | 0 .../ConnectionDetailsView.swift | 2 +- .../Wallet/PasteUri/PasteUriInteractor.swift | 0 .../Wallet/PasteUri/PasteUriModule.swift | 0 .../Wallet/PasteUri/PasteUriPresenter.swift | 0 .../Wallet/PasteUri/PasteUriRouter.swift | 0 .../Wallet/PasteUri/PasteUriView.swift | 0 .../Wallet/Scan/ScanInteractor.swift | 0 .../Wallet/Scan/ScanModule.swift | 0 .../Wallet/Scan/ScanPresenter.swift | 0 .../Wallet/Scan/ScanRouter.swift | 0 .../Wallet/Scan/ScanView.swift | 0 .../Wallet/Scan/Views/ScanQR.swift | 0 .../Wallet/Scan/Views/ScanQRView.swift | 0 .../Wallet/Scan/Views/ScanTargetView.swift | 0 .../Wallet/Wallet/WalletInteractor.swift | 0 .../Wallet/Wallet/WalletModule.swift | 0 .../Wallet/Wallet/WalletPresenter.swift | 0 .../Wallet/Wallet/WalletRouter.swift | 0 .../Wallet/Wallet/WalletView.swift | 0 .../Wallet/Welcome/WelcomeInteractor.swift | 0 .../Wallet/Welcome/WelcomeModule.swift | 0 .../Wallet/Welcome/WelcomePresenter.swift | 0 .../Wallet/Welcome/WelcomeRouter.swift | 0 .../Wallet/Welcome/WelcomeView.swift | 0 109 files changed, 26 insertions(+), 26 deletions(-) rename Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/{ChatWallet.xcscheme => WalletApp.xcscheme} (90%) rename Example/{ChatWallet => WalletApp}/ApplicationLayer/AppDelegate.swift (100%) rename Example/{ChatWallet => WalletApp}/ApplicationLayer/Application.swift (100%) rename Example/{ChatWallet => WalletApp}/ApplicationLayer/Configurator/AppearanceConfigurator.swift (100%) rename Example/{ChatWallet => WalletApp}/ApplicationLayer/Configurator/ApplicationConfigurator.swift (100%) rename Example/{ChatWallet => WalletApp}/ApplicationLayer/Configurator/Configurator.swift (100%) rename Example/{ChatWallet => WalletApp}/ApplicationLayer/Configurator/MigrationConfigurator.swift (100%) rename Example/{ChatWallet => WalletApp}/ApplicationLayer/Configurator/ThirdPartyConfigurator.swift (100%) rename Example/{ChatWallet => WalletApp}/ApplicationLayer/SceneDelegate.swift (93%) rename Example/{ChatWallet => WalletApp}/Common/Extensions/SwiftUI/View.swift (100%) rename Example/{ChatWallet => WalletApp}/Common/Extensions/UIKit/String.swift (100%) rename Example/{ChatWallet => WalletApp}/Common/Extensions/UIKit/UIColor.swift (100%) rename Example/{ChatWallet => WalletApp}/Common/Extensions/UIKit/UIViewController.swift (100%) rename Example/{ChatWallet => WalletApp}/Common/Helpers/UIPasteboardWrapper.swift (100%) rename Example/{ChatWallet => WalletApp}/Common/InputConfig.swift (100%) rename Example/{ChatWallet => WalletApp}/Common/Style/Color.swift (100%) rename Example/{ChatWallet => WalletApp}/Common/Types/Types.swift (100%) rename Example/{ChatWallet => WalletApp}/Common/VIPER/SceneViewController.swift (100%) rename Example/{ChatWallet => WalletApp}/DomainLayer/AccountStorage/AccountStorage.swift (100%) rename Example/{ChatWallet => WalletApp}/DomainLayer/Chat/AccountNameResolver.swift (100%) rename Example/{ChatWallet => WalletApp}/DomainLayer/Chat/ChatService.swift (100%) rename Example/{ChatWallet => WalletApp}/DomainLayer/Chat/RegisterService.swift (100%) rename Example/{ChatWallet => WalletApp}/DomainLayer/SocketFactory/SocketFactory.swift (100%) rename Example/{ChatWallet => WalletApp}/Other/Assets.xcassets/AccentColor.colorset/Contents.json (100%) rename Example/{ChatWallet => WalletApp}/Other/Assets.xcassets/AppIcon.appiconset/Contents.json (100%) rename Example/{ChatWallet => WalletApp}/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png (100%) rename Example/{ChatWallet => WalletApp}/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x-1.png (100%) rename Example/{ChatWallet => WalletApp}/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png (100%) rename Example/{ChatWallet => WalletApp}/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png (100%) rename Example/{ChatWallet => WalletApp}/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png (100%) rename Example/{ChatWallet => WalletApp}/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x-1.png (100%) rename Example/{ChatWallet => WalletApp}/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png (100%) rename Example/{ChatWallet => WalletApp}/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png (100%) rename Example/{ChatWallet => WalletApp}/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png (100%) rename Example/{ChatWallet => WalletApp}/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x-1.png (100%) rename Example/{ChatWallet => WalletApp}/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png (100%) rename Example/{ChatWallet => WalletApp}/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png (100%) rename Example/{ChatWallet => WalletApp}/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png (100%) rename Example/{ChatWallet => WalletApp}/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png (100%) rename Example/{ChatWallet => WalletApp}/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png (100%) rename Example/{ChatWallet => WalletApp}/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png (100%) rename Example/{ChatWallet => WalletApp}/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png (100%) rename Example/{ChatWallet => WalletApp}/Other/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png (100%) rename Example/{ChatWallet => WalletApp}/Other/Assets.xcassets/Contents.json (100%) rename Example/{ChatWallet => WalletApp}/Other/Assets.xcassets/connect-template.imageset/Contents.json (100%) rename Example/{ChatWallet => WalletApp}/Other/Assets.xcassets/connect-template.imageset/connect-template.svg (100%) rename Example/{ChatWallet => WalletApp}/Other/Assets.xcassets/copy.imageset/Contents.json (100%) rename Example/{ChatWallet => WalletApp}/Other/Assets.xcassets/copy.imageset/copy.svg (100%) rename Example/{ChatWallet => WalletApp}/Other/Assets.xcassets/forward-shevron.imageset/Contents.json (100%) rename Example/{ChatWallet => WalletApp}/Other/Assets.xcassets/forward-shevron.imageset/forward-shevron.svg (100%) rename Example/{ChatWallet => WalletApp}/Other/Assets.xcassets/foundation.imageset/Contents.json (100%) rename Example/{ChatWallet => WalletApp}/Other/Assets.xcassets/foundation.imageset/foundation.svg (100%) rename Example/{ChatWallet => WalletApp}/Other/Assets.xcassets/header.imageset/Contents.json (100%) rename Example/{ChatWallet => WalletApp}/Other/Assets.xcassets/header.imageset/Visual.svg (100%) rename Example/{ChatWallet => WalletApp}/Other/Assets.xcassets/scan.imageset/Contents.json (100%) rename Example/{ChatWallet => WalletApp}/Other/Assets.xcassets/scan.imageset/scan.svg (100%) rename Example/{ChatWallet => WalletApp}/Other/Colors.xcassets/Contents.json (100%) rename Example/{ChatWallet => WalletApp}/Other/Colors.xcassets/blue100.colorset/Contents.json (100%) rename Example/{ChatWallet => WalletApp}/Other/Colors.xcassets/blue200.colorset/Contents.json (100%) rename Example/{ChatWallet => WalletApp}/Other/Colors.xcassets/cyan-background.colorset/Contents.json (100%) rename Example/{ChatWallet => WalletApp}/Other/Colors.xcassets/foreground-negative.colorset/Contents.json (100%) rename Example/{ChatWallet => WalletApp}/Other/Colors.xcassets/foreground-positive.colorset/Contents.json (100%) rename Example/{ChatWallet => WalletApp}/Other/Colors.xcassets/grey100.colorset/Contents.json (100%) rename Example/{ChatWallet => WalletApp}/Other/Colors.xcassets/grey50.colorset/Contents.json (100%) rename Example/{ChatWallet => WalletApp}/Other/Colors.xcassets/grey70.colorset/Contents.json (100%) rename Example/{ChatWallet => WalletApp}/Other/Colors.xcassets/grey8.colorset/Contents.json (100%) rename Example/{ChatWallet => WalletApp}/Other/Colors.xcassets/grey95.colorset/Contents.json (100%) rename Example/{ChatWallet => WalletApp}/Other/Colors.xcassets/light-background.colorset/Contents.json (100%) rename Example/{ChatWallet => WalletApp}/Other/Colors.xcassets/light-blue.colorset/Contents.json (100%) rename Example/{ChatWallet => WalletApp}/Other/Colors.xcassets/light-foreground-negative.colorset/Contents.json (100%) rename Example/{ChatWallet => WalletApp}/Other/Colors.xcassets/light-foreground-positive.colorset/Contents.json (100%) rename Example/{ChatWallet => WalletApp}/Other/Colors.xcassets/system-gray-light.colorset/Contents.json (100%) rename Example/{ChatWallet => WalletApp}/Other/Colors.xcassets/white-background.colorset/Contents.json (100%) rename Example/{ChatWallet => WalletApp}/Other/Info.plist (97%) rename Example/{ChatWallet => WalletApp}/PresentationLayer/Wallet/AuthRequest/AuthRequestInteractor.swift (100%) rename Example/{ChatWallet => WalletApp}/PresentationLayer/Wallet/AuthRequest/AuthRequestModule.swift (100%) rename Example/{ChatWallet => WalletApp}/PresentationLayer/Wallet/AuthRequest/AuthRequestPresenter.swift (100%) rename Example/{ChatWallet => WalletApp}/PresentationLayer/Wallet/AuthRequest/AuthRequestRouter.swift (100%) rename Example/{ChatWallet => WalletApp}/PresentationLayer/Wallet/AuthRequest/AuthRequestView.swift (100%) rename Example/{ChatWallet => WalletApp}/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsInteractor.swift (100%) rename Example/{ChatWallet => WalletApp}/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsModule.swift (100%) rename Example/{ChatWallet => WalletApp}/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsPresenter.swift (100%) rename Example/{ChatWallet => WalletApp}/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsRouter.swift (100%) rename Example/{ChatWallet => WalletApp}/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsView.swift (98%) rename Example/{ChatWallet => WalletApp}/PresentationLayer/Wallet/PasteUri/PasteUriInteractor.swift (100%) rename Example/{ChatWallet => WalletApp}/PresentationLayer/Wallet/PasteUri/PasteUriModule.swift (100%) rename Example/{ChatWallet => WalletApp}/PresentationLayer/Wallet/PasteUri/PasteUriPresenter.swift (100%) rename Example/{ChatWallet => WalletApp}/PresentationLayer/Wallet/PasteUri/PasteUriRouter.swift (100%) rename Example/{ChatWallet => WalletApp}/PresentationLayer/Wallet/PasteUri/PasteUriView.swift (100%) rename Example/{ChatWallet => WalletApp}/PresentationLayer/Wallet/Scan/ScanInteractor.swift (100%) rename Example/{ChatWallet => WalletApp}/PresentationLayer/Wallet/Scan/ScanModule.swift (100%) rename Example/{ChatWallet => WalletApp}/PresentationLayer/Wallet/Scan/ScanPresenter.swift (100%) rename Example/{ChatWallet => WalletApp}/PresentationLayer/Wallet/Scan/ScanRouter.swift (100%) rename Example/{ChatWallet => WalletApp}/PresentationLayer/Wallet/Scan/ScanView.swift (100%) rename Example/{ChatWallet => WalletApp}/PresentationLayer/Wallet/Scan/Views/ScanQR.swift (100%) rename Example/{ChatWallet => WalletApp}/PresentationLayer/Wallet/Scan/Views/ScanQRView.swift (100%) rename Example/{ChatWallet => WalletApp}/PresentationLayer/Wallet/Scan/Views/ScanTargetView.swift (100%) rename Example/{ChatWallet => WalletApp}/PresentationLayer/Wallet/Wallet/WalletInteractor.swift (100%) rename Example/{ChatWallet => WalletApp}/PresentationLayer/Wallet/Wallet/WalletModule.swift (100%) rename Example/{ChatWallet => WalletApp}/PresentationLayer/Wallet/Wallet/WalletPresenter.swift (100%) rename Example/{ChatWallet => WalletApp}/PresentationLayer/Wallet/Wallet/WalletRouter.swift (100%) rename Example/{ChatWallet => WalletApp}/PresentationLayer/Wallet/Wallet/WalletView.swift (100%) rename Example/{ChatWallet => WalletApp}/PresentationLayer/Wallet/Welcome/WelcomeInteractor.swift (100%) rename Example/{ChatWallet => WalletApp}/PresentationLayer/Wallet/Welcome/WelcomeModule.swift (100%) rename Example/{ChatWallet => WalletApp}/PresentationLayer/Wallet/Welcome/WelcomePresenter.swift (100%) rename Example/{ChatWallet => WalletApp}/PresentationLayer/Wallet/Welcome/WelcomeRouter.swift (100%) rename Example/{ChatWallet => WalletApp}/PresentationLayer/Wallet/Welcome/WelcomeView.swift (100%) diff --git a/Example/ExampleApp.xcodeproj/project.pbxproj b/Example/ExampleApp.xcodeproj/project.pbxproj index 368f92324..8be9c5e25 100644 --- a/Example/ExampleApp.xcodeproj/project.pbxproj +++ b/Example/ExampleApp.xcodeproj/project.pbxproj @@ -437,7 +437,7 @@ C55D3490295DFA750004314A /* WelcomeRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeRouter.swift; sourceTree = ""; }; C55D3491295DFA750004314A /* WelcomeInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeInteractor.swift; sourceTree = ""; }; C55D3492295DFA750004314A /* WelcomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeView.swift; sourceTree = ""; }; - C56EE21B293F55ED004840D1 /* ChatWallet.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ChatWallet.app; sourceTree = BUILT_PRODUCTS_DIR; }; + C56EE21B293F55ED004840D1 /* WalletApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WalletApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; C56EE221293F55EE004840D1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; C56EE22B293F5668004840D1 /* WalletView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletView.swift; sourceTree = ""; }; C56EE22C293F5668004840D1 /* WalletPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletPresenter.swift; sourceTree = ""; }; @@ -606,7 +606,7 @@ A5A4FC732840C12C00BBEC1E /* UITests */, A5E03DEE286464DB00888481 /* IntegrationTests */, A58E7CE928729F550082D443 /* Showcase */, - C56EE21C293F55ED004840D1 /* ChatWallet */, + C56EE21C293F55ED004840D1 /* WalletApp */, 764E1D3D26F8D3FC00A1FB15 /* Products */, 764E1D5326F8DAC800A1FB15 /* Frameworks */, 764E1D5626F8DB6000A1FB15 /* WalletConnectSwiftV2 */, @@ -621,7 +621,7 @@ A5A4FC722840C12C00BBEC1E /* UITests.xctest */, A5E03DED286464DB00888481 /* IntegrationTests.xctest */, A58E7CE828729F550082D443 /* Showcase.app */, - C56EE21B293F55ED004840D1 /* ChatWallet.app */, + C56EE21B293F55ED004840D1 /* WalletApp.app */, ); name = Products; sourceTree = ""; @@ -1272,7 +1272,7 @@ path = Welcome; sourceTree = ""; }; - C56EE21C293F55ED004840D1 /* ChatWallet */ = { + C56EE21C293F55ED004840D1 /* WalletApp */ = { isa = PBXGroup; children = ( C56EE25C293F56D6004840D1 /* Common */, @@ -1281,7 +1281,7 @@ C56EE29E293F577B004840D1 /* PresentationLayer */, C56EE2A0293F6B10004840D1 /* Other */, ); - path = ChatWallet; + path = WalletApp; sourceTree = ""; }; C56EE229293F5668004840D1 /* Wallet */ = { @@ -1615,9 +1615,9 @@ productReference = A5E03DED286464DB00888481 /* IntegrationTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; - C56EE21A293F55ED004840D1 /* ChatWallet */ = { + C56EE21A293F55ED004840D1 /* WalletApp */ = { isa = PBXNativeTarget; - buildConfigurationList = C56EE228293F55EE004840D1 /* Build configuration list for PBXNativeTarget "ChatWallet" */; + buildConfigurationList = C56EE228293F55EE004840D1 /* Build configuration list for PBXNativeTarget "WalletApp" */; buildPhases = ( C56EE217293F55ED004840D1 /* Sources */, C56EE218293F55ED004840D1 /* Frameworks */, @@ -1627,7 +1627,7 @@ ); dependencies = ( ); - name = ChatWallet; + name = WalletApp; packageProductDependencies = ( C56EE254293F569A004840D1 /* Starscream */, C56EE27A293F56F8004840D1 /* WalletConnectAuth */, @@ -1636,7 +1636,7 @@ C55D349829630D440004314A /* Web3Wallet */, ); productName = ChatWallet; - productReference = C56EE21B293F55ED004840D1 /* ChatWallet.app */; + productReference = C56EE21B293F55ED004840D1 /* WalletApp.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ @@ -1691,7 +1691,7 @@ A5A4FC712840C12C00BBEC1E /* UITests */, A5E03DEC286464DB00888481 /* IntegrationTests */, A58E7CE728729F550082D443 /* Showcase */, - C56EE21A293F55ED004840D1 /* ChatWallet */, + C56EE21A293F55ED004840D1 /* WalletApp */, ); }; /* End PBXProject section */ @@ -2421,7 +2421,7 @@ CURRENT_PROJECT_VERSION = 1; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = ChatWallet/Other/Info.plist; + INFOPLIST_FILE = WalletApp/Other/Info.plist; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; @@ -2432,7 +2432,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.walletconnect.ChatWallet; + PRODUCT_BUNDLE_IDENTIFIER = com.walletconnect.walletapp; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; @@ -2450,7 +2450,7 @@ CURRENT_PROJECT_VERSION = 1; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = ChatWallet/Other/Info.plist; + INFOPLIST_FILE = WalletApp/Other/Info.plist; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; @@ -2461,7 +2461,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.walletconnect.ChatWallet; + PRODUCT_BUNDLE_IDENTIFIER = com.walletconnect.walletapp; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; @@ -2526,7 +2526,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - C56EE228293F55EE004840D1 /* Build configuration list for PBXNativeTarget "ChatWallet" */ = { + C56EE228293F55EE004840D1 /* Build configuration list for PBXNativeTarget "WalletApp" */ = { isa = XCConfigurationList; buildConfigurations = ( C56EE226293F55EE004840D1 /* Debug */, diff --git a/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/ChatWallet.xcscheme b/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/WalletApp.xcscheme similarity index 90% rename from Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/ChatWallet.xcscheme rename to Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/WalletApp.xcscheme index ee1b7f26a..036e15875 100644 --- a/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/ChatWallet.xcscheme +++ b/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/WalletApp.xcscheme @@ -15,8 +15,8 @@ @@ -45,8 +45,8 @@ @@ -62,8 +62,8 @@ diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomeRouter.swift b/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomeRouter.swift index 1c87555f4..e69faac65 100644 --- a/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomeRouter.swift +++ b/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomeRouter.swift @@ -23,6 +23,6 @@ final class WelcomeRouter { } func openWallet(uri: String) { - UIApplication.shared.open(URL(string: "chatwallet://wc?uri=\(uri)")!) + UIApplication.shared.open(URL(string: "walletapp://wc?uri=\(uri)")!) } } diff --git a/Example/ChatWallet/ApplicationLayer/AppDelegate.swift b/Example/WalletApp/ApplicationLayer/AppDelegate.swift similarity index 100% rename from Example/ChatWallet/ApplicationLayer/AppDelegate.swift rename to Example/WalletApp/ApplicationLayer/AppDelegate.swift diff --git a/Example/ChatWallet/ApplicationLayer/Application.swift b/Example/WalletApp/ApplicationLayer/Application.swift similarity index 100% rename from Example/ChatWallet/ApplicationLayer/Application.swift rename to Example/WalletApp/ApplicationLayer/Application.swift diff --git a/Example/ChatWallet/ApplicationLayer/Configurator/AppearanceConfigurator.swift b/Example/WalletApp/ApplicationLayer/Configurator/AppearanceConfigurator.swift similarity index 100% rename from Example/ChatWallet/ApplicationLayer/Configurator/AppearanceConfigurator.swift rename to Example/WalletApp/ApplicationLayer/Configurator/AppearanceConfigurator.swift diff --git a/Example/ChatWallet/ApplicationLayer/Configurator/ApplicationConfigurator.swift b/Example/WalletApp/ApplicationLayer/Configurator/ApplicationConfigurator.swift similarity index 100% rename from Example/ChatWallet/ApplicationLayer/Configurator/ApplicationConfigurator.swift rename to Example/WalletApp/ApplicationLayer/Configurator/ApplicationConfigurator.swift diff --git a/Example/ChatWallet/ApplicationLayer/Configurator/Configurator.swift b/Example/WalletApp/ApplicationLayer/Configurator/Configurator.swift similarity index 100% rename from Example/ChatWallet/ApplicationLayer/Configurator/Configurator.swift rename to Example/WalletApp/ApplicationLayer/Configurator/Configurator.swift diff --git a/Example/ChatWallet/ApplicationLayer/Configurator/MigrationConfigurator.swift b/Example/WalletApp/ApplicationLayer/Configurator/MigrationConfigurator.swift similarity index 100% rename from Example/ChatWallet/ApplicationLayer/Configurator/MigrationConfigurator.swift rename to Example/WalletApp/ApplicationLayer/Configurator/MigrationConfigurator.swift diff --git a/Example/ChatWallet/ApplicationLayer/Configurator/ThirdPartyConfigurator.swift b/Example/WalletApp/ApplicationLayer/Configurator/ThirdPartyConfigurator.swift similarity index 100% rename from Example/ChatWallet/ApplicationLayer/Configurator/ThirdPartyConfigurator.swift rename to Example/WalletApp/ApplicationLayer/Configurator/ThirdPartyConfigurator.swift diff --git a/Example/ChatWallet/ApplicationLayer/SceneDelegate.swift b/Example/WalletApp/ApplicationLayer/SceneDelegate.swift similarity index 93% rename from Example/ChatWallet/ApplicationLayer/SceneDelegate.swift rename to Example/WalletApp/ApplicationLayer/SceneDelegate.swift index 76b9b72dd..1fa5738e2 100644 --- a/Example/ChatWallet/ApplicationLayer/SceneDelegate.swift +++ b/Example/WalletApp/ApplicationLayer/SceneDelegate.swift @@ -28,7 +28,7 @@ final class SceneDelegate: UIResponder, UIWindowSceneDelegate { window = UIWindow(windowScene: windowScene) window?.makeKeyAndVisible() - app.uri = connectionOptions.urlContexts.first?.url.absoluteString.replacingOccurrences(of: "chatwallet://wc?uri=", with: "") + app.uri = connectionOptions.urlContexts.first?.url.absoluteString.replacingOccurrences(of: "walletapp://wc?uri=", with: "") configurators.configure() } @@ -36,7 +36,7 @@ final class SceneDelegate: UIResponder, UIWindowSceneDelegate { func scene(_ scene: UIScene, openURLContexts URLContexts: Set) { guard let context = URLContexts.first else { return } - let uri = context.url.absoluteString.replacingOccurrences(of: "chatwallet://wc?uri=", with: "") + let uri = context.url.absoluteString.replacingOccurrences(of: "walletapp://wc?uri=", with: "") Task { try await Pair.instance.pair(uri: WalletConnectURI(string: uri)!) } diff --git a/Example/ChatWallet/Common/Extensions/SwiftUI/View.swift b/Example/WalletApp/Common/Extensions/SwiftUI/View.swift similarity index 100% rename from Example/ChatWallet/Common/Extensions/SwiftUI/View.swift rename to Example/WalletApp/Common/Extensions/SwiftUI/View.swift diff --git a/Example/ChatWallet/Common/Extensions/UIKit/String.swift b/Example/WalletApp/Common/Extensions/UIKit/String.swift similarity index 100% rename from Example/ChatWallet/Common/Extensions/UIKit/String.swift rename to Example/WalletApp/Common/Extensions/UIKit/String.swift diff --git a/Example/ChatWallet/Common/Extensions/UIKit/UIColor.swift b/Example/WalletApp/Common/Extensions/UIKit/UIColor.swift similarity index 100% rename from Example/ChatWallet/Common/Extensions/UIKit/UIColor.swift rename to Example/WalletApp/Common/Extensions/UIKit/UIColor.swift diff --git a/Example/ChatWallet/Common/Extensions/UIKit/UIViewController.swift b/Example/WalletApp/Common/Extensions/UIKit/UIViewController.swift similarity index 100% rename from Example/ChatWallet/Common/Extensions/UIKit/UIViewController.swift rename to Example/WalletApp/Common/Extensions/UIKit/UIViewController.swift diff --git a/Example/ChatWallet/Common/Helpers/UIPasteboardWrapper.swift b/Example/WalletApp/Common/Helpers/UIPasteboardWrapper.swift similarity index 100% rename from Example/ChatWallet/Common/Helpers/UIPasteboardWrapper.swift rename to Example/WalletApp/Common/Helpers/UIPasteboardWrapper.swift diff --git a/Example/ChatWallet/Common/InputConfig.swift b/Example/WalletApp/Common/InputConfig.swift similarity index 100% rename from Example/ChatWallet/Common/InputConfig.swift rename to Example/WalletApp/Common/InputConfig.swift diff --git a/Example/ChatWallet/Common/Style/Color.swift b/Example/WalletApp/Common/Style/Color.swift similarity index 100% rename from Example/ChatWallet/Common/Style/Color.swift rename to Example/WalletApp/Common/Style/Color.swift diff --git a/Example/ChatWallet/Common/Types/Types.swift b/Example/WalletApp/Common/Types/Types.swift similarity index 100% rename from Example/ChatWallet/Common/Types/Types.swift rename to Example/WalletApp/Common/Types/Types.swift diff --git a/Example/ChatWallet/Common/VIPER/SceneViewController.swift b/Example/WalletApp/Common/VIPER/SceneViewController.swift similarity index 100% rename from Example/ChatWallet/Common/VIPER/SceneViewController.swift rename to Example/WalletApp/Common/VIPER/SceneViewController.swift diff --git a/Example/ChatWallet/DomainLayer/AccountStorage/AccountStorage.swift b/Example/WalletApp/DomainLayer/AccountStorage/AccountStorage.swift similarity index 100% rename from Example/ChatWallet/DomainLayer/AccountStorage/AccountStorage.swift rename to Example/WalletApp/DomainLayer/AccountStorage/AccountStorage.swift diff --git a/Example/ChatWallet/DomainLayer/Chat/AccountNameResolver.swift b/Example/WalletApp/DomainLayer/Chat/AccountNameResolver.swift similarity index 100% rename from Example/ChatWallet/DomainLayer/Chat/AccountNameResolver.swift rename to Example/WalletApp/DomainLayer/Chat/AccountNameResolver.swift diff --git a/Example/ChatWallet/DomainLayer/Chat/ChatService.swift b/Example/WalletApp/DomainLayer/Chat/ChatService.swift similarity index 100% rename from Example/ChatWallet/DomainLayer/Chat/ChatService.swift rename to Example/WalletApp/DomainLayer/Chat/ChatService.swift diff --git a/Example/ChatWallet/DomainLayer/Chat/RegisterService.swift b/Example/WalletApp/DomainLayer/Chat/RegisterService.swift similarity index 100% rename from Example/ChatWallet/DomainLayer/Chat/RegisterService.swift rename to Example/WalletApp/DomainLayer/Chat/RegisterService.swift diff --git a/Example/ChatWallet/DomainLayer/SocketFactory/SocketFactory.swift b/Example/WalletApp/DomainLayer/SocketFactory/SocketFactory.swift similarity index 100% rename from Example/ChatWallet/DomainLayer/SocketFactory/SocketFactory.swift rename to Example/WalletApp/DomainLayer/SocketFactory/SocketFactory.swift diff --git a/Example/ChatWallet/Other/Assets.xcassets/AccentColor.colorset/Contents.json b/Example/WalletApp/Other/Assets.xcassets/AccentColor.colorset/Contents.json similarity index 100% rename from Example/ChatWallet/Other/Assets.xcassets/AccentColor.colorset/Contents.json rename to Example/WalletApp/Other/Assets.xcassets/AccentColor.colorset/Contents.json diff --git a/Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Contents.json b/Example/WalletApp/Other/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Contents.json rename to Example/WalletApp/Other/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/Example/WalletApp/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png similarity index 100% rename from Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png rename to Example/WalletApp/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png diff --git a/Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x-1.png b/Example/WalletApp/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x-1.png similarity index 100% rename from Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x-1.png rename to Example/WalletApp/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x-1.png diff --git a/Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/Example/WalletApp/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png similarity index 100% rename from Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png rename to Example/WalletApp/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png diff --git a/Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/Example/WalletApp/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png similarity index 100% rename from Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png rename to Example/WalletApp/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png diff --git a/Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/Example/WalletApp/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png similarity index 100% rename from Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png rename to Example/WalletApp/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png diff --git a/Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x-1.png b/Example/WalletApp/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x-1.png similarity index 100% rename from Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x-1.png rename to Example/WalletApp/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x-1.png diff --git a/Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/Example/WalletApp/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png similarity index 100% rename from Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png rename to Example/WalletApp/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png diff --git a/Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/Example/WalletApp/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png similarity index 100% rename from Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png rename to Example/WalletApp/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png diff --git a/Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/Example/WalletApp/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png similarity index 100% rename from Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png rename to Example/WalletApp/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png diff --git a/Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x-1.png b/Example/WalletApp/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x-1.png similarity index 100% rename from Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x-1.png rename to Example/WalletApp/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x-1.png diff --git a/Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/Example/WalletApp/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png similarity index 100% rename from Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png rename to Example/WalletApp/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png diff --git a/Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/Example/WalletApp/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png similarity index 100% rename from Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png rename to Example/WalletApp/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png diff --git a/Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/Example/WalletApp/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png similarity index 100% rename from Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png rename to Example/WalletApp/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png diff --git a/Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/Example/WalletApp/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png similarity index 100% rename from Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png rename to Example/WalletApp/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png diff --git a/Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/Example/WalletApp/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png similarity index 100% rename from Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png rename to Example/WalletApp/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png diff --git a/Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/Example/WalletApp/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png similarity index 100% rename from Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png rename to Example/WalletApp/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png diff --git a/Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/Example/WalletApp/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png similarity index 100% rename from Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png rename to Example/WalletApp/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png diff --git a/Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png b/Example/WalletApp/Other/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png similarity index 100% rename from Example/ChatWallet/Other/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png rename to Example/WalletApp/Other/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png diff --git a/Example/ChatWallet/Other/Assets.xcassets/Contents.json b/Example/WalletApp/Other/Assets.xcassets/Contents.json similarity index 100% rename from Example/ChatWallet/Other/Assets.xcassets/Contents.json rename to Example/WalletApp/Other/Assets.xcassets/Contents.json diff --git a/Example/ChatWallet/Other/Assets.xcassets/connect-template.imageset/Contents.json b/Example/WalletApp/Other/Assets.xcassets/connect-template.imageset/Contents.json similarity index 100% rename from Example/ChatWallet/Other/Assets.xcassets/connect-template.imageset/Contents.json rename to Example/WalletApp/Other/Assets.xcassets/connect-template.imageset/Contents.json diff --git a/Example/ChatWallet/Other/Assets.xcassets/connect-template.imageset/connect-template.svg b/Example/WalletApp/Other/Assets.xcassets/connect-template.imageset/connect-template.svg similarity index 100% rename from Example/ChatWallet/Other/Assets.xcassets/connect-template.imageset/connect-template.svg rename to Example/WalletApp/Other/Assets.xcassets/connect-template.imageset/connect-template.svg diff --git a/Example/ChatWallet/Other/Assets.xcassets/copy.imageset/Contents.json b/Example/WalletApp/Other/Assets.xcassets/copy.imageset/Contents.json similarity index 100% rename from Example/ChatWallet/Other/Assets.xcassets/copy.imageset/Contents.json rename to Example/WalletApp/Other/Assets.xcassets/copy.imageset/Contents.json diff --git a/Example/ChatWallet/Other/Assets.xcassets/copy.imageset/copy.svg b/Example/WalletApp/Other/Assets.xcassets/copy.imageset/copy.svg similarity index 100% rename from Example/ChatWallet/Other/Assets.xcassets/copy.imageset/copy.svg rename to Example/WalletApp/Other/Assets.xcassets/copy.imageset/copy.svg diff --git a/Example/ChatWallet/Other/Assets.xcassets/forward-shevron.imageset/Contents.json b/Example/WalletApp/Other/Assets.xcassets/forward-shevron.imageset/Contents.json similarity index 100% rename from Example/ChatWallet/Other/Assets.xcassets/forward-shevron.imageset/Contents.json rename to Example/WalletApp/Other/Assets.xcassets/forward-shevron.imageset/Contents.json diff --git a/Example/ChatWallet/Other/Assets.xcassets/forward-shevron.imageset/forward-shevron.svg b/Example/WalletApp/Other/Assets.xcassets/forward-shevron.imageset/forward-shevron.svg similarity index 100% rename from Example/ChatWallet/Other/Assets.xcassets/forward-shevron.imageset/forward-shevron.svg rename to Example/WalletApp/Other/Assets.xcassets/forward-shevron.imageset/forward-shevron.svg diff --git a/Example/ChatWallet/Other/Assets.xcassets/foundation.imageset/Contents.json b/Example/WalletApp/Other/Assets.xcassets/foundation.imageset/Contents.json similarity index 100% rename from Example/ChatWallet/Other/Assets.xcassets/foundation.imageset/Contents.json rename to Example/WalletApp/Other/Assets.xcassets/foundation.imageset/Contents.json diff --git a/Example/ChatWallet/Other/Assets.xcassets/foundation.imageset/foundation.svg b/Example/WalletApp/Other/Assets.xcassets/foundation.imageset/foundation.svg similarity index 100% rename from Example/ChatWallet/Other/Assets.xcassets/foundation.imageset/foundation.svg rename to Example/WalletApp/Other/Assets.xcassets/foundation.imageset/foundation.svg diff --git a/Example/ChatWallet/Other/Assets.xcassets/header.imageset/Contents.json b/Example/WalletApp/Other/Assets.xcassets/header.imageset/Contents.json similarity index 100% rename from Example/ChatWallet/Other/Assets.xcassets/header.imageset/Contents.json rename to Example/WalletApp/Other/Assets.xcassets/header.imageset/Contents.json diff --git a/Example/ChatWallet/Other/Assets.xcassets/header.imageset/Visual.svg b/Example/WalletApp/Other/Assets.xcassets/header.imageset/Visual.svg similarity index 100% rename from Example/ChatWallet/Other/Assets.xcassets/header.imageset/Visual.svg rename to Example/WalletApp/Other/Assets.xcassets/header.imageset/Visual.svg diff --git a/Example/ChatWallet/Other/Assets.xcassets/scan.imageset/Contents.json b/Example/WalletApp/Other/Assets.xcassets/scan.imageset/Contents.json similarity index 100% rename from Example/ChatWallet/Other/Assets.xcassets/scan.imageset/Contents.json rename to Example/WalletApp/Other/Assets.xcassets/scan.imageset/Contents.json diff --git a/Example/ChatWallet/Other/Assets.xcassets/scan.imageset/scan.svg b/Example/WalletApp/Other/Assets.xcassets/scan.imageset/scan.svg similarity index 100% rename from Example/ChatWallet/Other/Assets.xcassets/scan.imageset/scan.svg rename to Example/WalletApp/Other/Assets.xcassets/scan.imageset/scan.svg diff --git a/Example/ChatWallet/Other/Colors.xcassets/Contents.json b/Example/WalletApp/Other/Colors.xcassets/Contents.json similarity index 100% rename from Example/ChatWallet/Other/Colors.xcassets/Contents.json rename to Example/WalletApp/Other/Colors.xcassets/Contents.json diff --git a/Example/ChatWallet/Other/Colors.xcassets/blue100.colorset/Contents.json b/Example/WalletApp/Other/Colors.xcassets/blue100.colorset/Contents.json similarity index 100% rename from Example/ChatWallet/Other/Colors.xcassets/blue100.colorset/Contents.json rename to Example/WalletApp/Other/Colors.xcassets/blue100.colorset/Contents.json diff --git a/Example/ChatWallet/Other/Colors.xcassets/blue200.colorset/Contents.json b/Example/WalletApp/Other/Colors.xcassets/blue200.colorset/Contents.json similarity index 100% rename from Example/ChatWallet/Other/Colors.xcassets/blue200.colorset/Contents.json rename to Example/WalletApp/Other/Colors.xcassets/blue200.colorset/Contents.json diff --git a/Example/ChatWallet/Other/Colors.xcassets/cyan-background.colorset/Contents.json b/Example/WalletApp/Other/Colors.xcassets/cyan-background.colorset/Contents.json similarity index 100% rename from Example/ChatWallet/Other/Colors.xcassets/cyan-background.colorset/Contents.json rename to Example/WalletApp/Other/Colors.xcassets/cyan-background.colorset/Contents.json diff --git a/Example/ChatWallet/Other/Colors.xcassets/foreground-negative.colorset/Contents.json b/Example/WalletApp/Other/Colors.xcassets/foreground-negative.colorset/Contents.json similarity index 100% rename from Example/ChatWallet/Other/Colors.xcassets/foreground-negative.colorset/Contents.json rename to Example/WalletApp/Other/Colors.xcassets/foreground-negative.colorset/Contents.json diff --git a/Example/ChatWallet/Other/Colors.xcassets/foreground-positive.colorset/Contents.json b/Example/WalletApp/Other/Colors.xcassets/foreground-positive.colorset/Contents.json similarity index 100% rename from Example/ChatWallet/Other/Colors.xcassets/foreground-positive.colorset/Contents.json rename to Example/WalletApp/Other/Colors.xcassets/foreground-positive.colorset/Contents.json diff --git a/Example/ChatWallet/Other/Colors.xcassets/grey100.colorset/Contents.json b/Example/WalletApp/Other/Colors.xcassets/grey100.colorset/Contents.json similarity index 100% rename from Example/ChatWallet/Other/Colors.xcassets/grey100.colorset/Contents.json rename to Example/WalletApp/Other/Colors.xcassets/grey100.colorset/Contents.json diff --git a/Example/ChatWallet/Other/Colors.xcassets/grey50.colorset/Contents.json b/Example/WalletApp/Other/Colors.xcassets/grey50.colorset/Contents.json similarity index 100% rename from Example/ChatWallet/Other/Colors.xcassets/grey50.colorset/Contents.json rename to Example/WalletApp/Other/Colors.xcassets/grey50.colorset/Contents.json diff --git a/Example/ChatWallet/Other/Colors.xcassets/grey70.colorset/Contents.json b/Example/WalletApp/Other/Colors.xcassets/grey70.colorset/Contents.json similarity index 100% rename from Example/ChatWallet/Other/Colors.xcassets/grey70.colorset/Contents.json rename to Example/WalletApp/Other/Colors.xcassets/grey70.colorset/Contents.json diff --git a/Example/ChatWallet/Other/Colors.xcassets/grey8.colorset/Contents.json b/Example/WalletApp/Other/Colors.xcassets/grey8.colorset/Contents.json similarity index 100% rename from Example/ChatWallet/Other/Colors.xcassets/grey8.colorset/Contents.json rename to Example/WalletApp/Other/Colors.xcassets/grey8.colorset/Contents.json diff --git a/Example/ChatWallet/Other/Colors.xcassets/grey95.colorset/Contents.json b/Example/WalletApp/Other/Colors.xcassets/grey95.colorset/Contents.json similarity index 100% rename from Example/ChatWallet/Other/Colors.xcassets/grey95.colorset/Contents.json rename to Example/WalletApp/Other/Colors.xcassets/grey95.colorset/Contents.json diff --git a/Example/ChatWallet/Other/Colors.xcassets/light-background.colorset/Contents.json b/Example/WalletApp/Other/Colors.xcassets/light-background.colorset/Contents.json similarity index 100% rename from Example/ChatWallet/Other/Colors.xcassets/light-background.colorset/Contents.json rename to Example/WalletApp/Other/Colors.xcassets/light-background.colorset/Contents.json diff --git a/Example/ChatWallet/Other/Colors.xcassets/light-blue.colorset/Contents.json b/Example/WalletApp/Other/Colors.xcassets/light-blue.colorset/Contents.json similarity index 100% rename from Example/ChatWallet/Other/Colors.xcassets/light-blue.colorset/Contents.json rename to Example/WalletApp/Other/Colors.xcassets/light-blue.colorset/Contents.json diff --git a/Example/ChatWallet/Other/Colors.xcassets/light-foreground-negative.colorset/Contents.json b/Example/WalletApp/Other/Colors.xcassets/light-foreground-negative.colorset/Contents.json similarity index 100% rename from Example/ChatWallet/Other/Colors.xcassets/light-foreground-negative.colorset/Contents.json rename to Example/WalletApp/Other/Colors.xcassets/light-foreground-negative.colorset/Contents.json diff --git a/Example/ChatWallet/Other/Colors.xcassets/light-foreground-positive.colorset/Contents.json b/Example/WalletApp/Other/Colors.xcassets/light-foreground-positive.colorset/Contents.json similarity index 100% rename from Example/ChatWallet/Other/Colors.xcassets/light-foreground-positive.colorset/Contents.json rename to Example/WalletApp/Other/Colors.xcassets/light-foreground-positive.colorset/Contents.json diff --git a/Example/ChatWallet/Other/Colors.xcassets/system-gray-light.colorset/Contents.json b/Example/WalletApp/Other/Colors.xcassets/system-gray-light.colorset/Contents.json similarity index 100% rename from Example/ChatWallet/Other/Colors.xcassets/system-gray-light.colorset/Contents.json rename to Example/WalletApp/Other/Colors.xcassets/system-gray-light.colorset/Contents.json diff --git a/Example/ChatWallet/Other/Colors.xcassets/white-background.colorset/Contents.json b/Example/WalletApp/Other/Colors.xcassets/white-background.colorset/Contents.json similarity index 100% rename from Example/ChatWallet/Other/Colors.xcassets/white-background.colorset/Contents.json rename to Example/WalletApp/Other/Colors.xcassets/white-background.colorset/Contents.json diff --git a/Example/ChatWallet/Other/Info.plist b/Example/WalletApp/Other/Info.plist similarity index 97% rename from Example/ChatWallet/Other/Info.plist rename to Example/WalletApp/Other/Info.plist index 72d30e44d..672603421 100644 --- a/Example/ChatWallet/Other/Info.plist +++ b/Example/WalletApp/Other/Info.plist @@ -11,7 +11,7 @@ Editor CFBundleURLSchemes - chatwallet + walletapp diff --git a/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestInteractor.swift b/Example/WalletApp/PresentationLayer/Wallet/AuthRequest/AuthRequestInteractor.swift similarity index 100% rename from Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestInteractor.swift rename to Example/WalletApp/PresentationLayer/Wallet/AuthRequest/AuthRequestInteractor.swift diff --git a/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestModule.swift b/Example/WalletApp/PresentationLayer/Wallet/AuthRequest/AuthRequestModule.swift similarity index 100% rename from Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestModule.swift rename to Example/WalletApp/PresentationLayer/Wallet/AuthRequest/AuthRequestModule.swift diff --git a/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestPresenter.swift b/Example/WalletApp/PresentationLayer/Wallet/AuthRequest/AuthRequestPresenter.swift similarity index 100% rename from Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestPresenter.swift rename to Example/WalletApp/PresentationLayer/Wallet/AuthRequest/AuthRequestPresenter.swift diff --git a/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestRouter.swift b/Example/WalletApp/PresentationLayer/Wallet/AuthRequest/AuthRequestRouter.swift similarity index 100% rename from Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestRouter.swift rename to Example/WalletApp/PresentationLayer/Wallet/AuthRequest/AuthRequestRouter.swift diff --git a/Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestView.swift b/Example/WalletApp/PresentationLayer/Wallet/AuthRequest/AuthRequestView.swift similarity index 100% rename from Example/ChatWallet/PresentationLayer/Wallet/AuthRequest/AuthRequestView.swift rename to Example/WalletApp/PresentationLayer/Wallet/AuthRequest/AuthRequestView.swift diff --git a/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsInteractor.swift b/Example/WalletApp/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsInteractor.swift similarity index 100% rename from Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsInteractor.swift rename to Example/WalletApp/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsInteractor.swift diff --git a/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsModule.swift b/Example/WalletApp/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsModule.swift similarity index 100% rename from Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsModule.swift rename to Example/WalletApp/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsModule.swift diff --git a/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsPresenter.swift b/Example/WalletApp/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsPresenter.swift similarity index 100% rename from Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsPresenter.swift rename to Example/WalletApp/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsPresenter.swift diff --git a/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsRouter.swift b/Example/WalletApp/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsRouter.swift similarity index 100% rename from Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsRouter.swift rename to Example/WalletApp/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsRouter.swift diff --git a/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsView.swift b/Example/WalletApp/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsView.swift similarity index 98% rename from Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsView.swift rename to Example/WalletApp/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsView.swift index 973e002ee..b9f5520a9 100644 --- a/Example/ChatWallet/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsView.swift +++ b/Example/WalletApp/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsView.swift @@ -11,7 +11,7 @@ struct ConnectionDetailsView: View { ScrollView { VStack(spacing: 0) { VStack(spacing: 2) { - AsyncImage(url: URL(string: session.peer.icons.first ?? "")) { phase in + AsyncImage(url: URL(string: presenter.session.peer.icons.first ?? "")) { phase in if let image = phase.image { image .resizable() diff --git a/Example/ChatWallet/PresentationLayer/Wallet/PasteUri/PasteUriInteractor.swift b/Example/WalletApp/PresentationLayer/Wallet/PasteUri/PasteUriInteractor.swift similarity index 100% rename from Example/ChatWallet/PresentationLayer/Wallet/PasteUri/PasteUriInteractor.swift rename to Example/WalletApp/PresentationLayer/Wallet/PasteUri/PasteUriInteractor.swift diff --git a/Example/ChatWallet/PresentationLayer/Wallet/PasteUri/PasteUriModule.swift b/Example/WalletApp/PresentationLayer/Wallet/PasteUri/PasteUriModule.swift similarity index 100% rename from Example/ChatWallet/PresentationLayer/Wallet/PasteUri/PasteUriModule.swift rename to Example/WalletApp/PresentationLayer/Wallet/PasteUri/PasteUriModule.swift diff --git a/Example/ChatWallet/PresentationLayer/Wallet/PasteUri/PasteUriPresenter.swift b/Example/WalletApp/PresentationLayer/Wallet/PasteUri/PasteUriPresenter.swift similarity index 100% rename from Example/ChatWallet/PresentationLayer/Wallet/PasteUri/PasteUriPresenter.swift rename to Example/WalletApp/PresentationLayer/Wallet/PasteUri/PasteUriPresenter.swift diff --git a/Example/ChatWallet/PresentationLayer/Wallet/PasteUri/PasteUriRouter.swift b/Example/WalletApp/PresentationLayer/Wallet/PasteUri/PasteUriRouter.swift similarity index 100% rename from Example/ChatWallet/PresentationLayer/Wallet/PasteUri/PasteUriRouter.swift rename to Example/WalletApp/PresentationLayer/Wallet/PasteUri/PasteUriRouter.swift diff --git a/Example/ChatWallet/PresentationLayer/Wallet/PasteUri/PasteUriView.swift b/Example/WalletApp/PresentationLayer/Wallet/PasteUri/PasteUriView.swift similarity index 100% rename from Example/ChatWallet/PresentationLayer/Wallet/PasteUri/PasteUriView.swift rename to Example/WalletApp/PresentationLayer/Wallet/PasteUri/PasteUriView.swift diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanInteractor.swift b/Example/WalletApp/PresentationLayer/Wallet/Scan/ScanInteractor.swift similarity index 100% rename from Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanInteractor.swift rename to Example/WalletApp/PresentationLayer/Wallet/Scan/ScanInteractor.swift diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanModule.swift b/Example/WalletApp/PresentationLayer/Wallet/Scan/ScanModule.swift similarity index 100% rename from Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanModule.swift rename to Example/WalletApp/PresentationLayer/Wallet/Scan/ScanModule.swift diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanPresenter.swift b/Example/WalletApp/PresentationLayer/Wallet/Scan/ScanPresenter.swift similarity index 100% rename from Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanPresenter.swift rename to Example/WalletApp/PresentationLayer/Wallet/Scan/ScanPresenter.swift diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanRouter.swift b/Example/WalletApp/PresentationLayer/Wallet/Scan/ScanRouter.swift similarity index 100% rename from Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanRouter.swift rename to Example/WalletApp/PresentationLayer/Wallet/Scan/ScanRouter.swift diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanView.swift b/Example/WalletApp/PresentationLayer/Wallet/Scan/ScanView.swift similarity index 100% rename from Example/ChatWallet/PresentationLayer/Wallet/Scan/ScanView.swift rename to Example/WalletApp/PresentationLayer/Wallet/Scan/ScanView.swift diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Scan/Views/ScanQR.swift b/Example/WalletApp/PresentationLayer/Wallet/Scan/Views/ScanQR.swift similarity index 100% rename from Example/ChatWallet/PresentationLayer/Wallet/Scan/Views/ScanQR.swift rename to Example/WalletApp/PresentationLayer/Wallet/Scan/Views/ScanQR.swift diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Scan/Views/ScanQRView.swift b/Example/WalletApp/PresentationLayer/Wallet/Scan/Views/ScanQRView.swift similarity index 100% rename from Example/ChatWallet/PresentationLayer/Wallet/Scan/Views/ScanQRView.swift rename to Example/WalletApp/PresentationLayer/Wallet/Scan/Views/ScanQRView.swift diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Scan/Views/ScanTargetView.swift b/Example/WalletApp/PresentationLayer/Wallet/Scan/Views/ScanTargetView.swift similarity index 100% rename from Example/ChatWallet/PresentationLayer/Wallet/Scan/Views/ScanTargetView.swift rename to Example/WalletApp/PresentationLayer/Wallet/Scan/Views/ScanTargetView.swift diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletInteractor.swift b/Example/WalletApp/PresentationLayer/Wallet/Wallet/WalletInteractor.swift similarity index 100% rename from Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletInteractor.swift rename to Example/WalletApp/PresentationLayer/Wallet/Wallet/WalletInteractor.swift diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletModule.swift b/Example/WalletApp/PresentationLayer/Wallet/Wallet/WalletModule.swift similarity index 100% rename from Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletModule.swift rename to Example/WalletApp/PresentationLayer/Wallet/Wallet/WalletModule.swift diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletPresenter.swift b/Example/WalletApp/PresentationLayer/Wallet/Wallet/WalletPresenter.swift similarity index 100% rename from Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletPresenter.swift rename to Example/WalletApp/PresentationLayer/Wallet/Wallet/WalletPresenter.swift diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletRouter.swift b/Example/WalletApp/PresentationLayer/Wallet/Wallet/WalletRouter.swift similarity index 100% rename from Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletRouter.swift rename to Example/WalletApp/PresentationLayer/Wallet/Wallet/WalletRouter.swift diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletView.swift b/Example/WalletApp/PresentationLayer/Wallet/Wallet/WalletView.swift similarity index 100% rename from Example/ChatWallet/PresentationLayer/Wallet/Wallet/WalletView.swift rename to Example/WalletApp/PresentationLayer/Wallet/Wallet/WalletView.swift diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Welcome/WelcomeInteractor.swift b/Example/WalletApp/PresentationLayer/Wallet/Welcome/WelcomeInteractor.swift similarity index 100% rename from Example/ChatWallet/PresentationLayer/Wallet/Welcome/WelcomeInteractor.swift rename to Example/WalletApp/PresentationLayer/Wallet/Welcome/WelcomeInteractor.swift diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Welcome/WelcomeModule.swift b/Example/WalletApp/PresentationLayer/Wallet/Welcome/WelcomeModule.swift similarity index 100% rename from Example/ChatWallet/PresentationLayer/Wallet/Welcome/WelcomeModule.swift rename to Example/WalletApp/PresentationLayer/Wallet/Welcome/WelcomeModule.swift diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Welcome/WelcomePresenter.swift b/Example/WalletApp/PresentationLayer/Wallet/Welcome/WelcomePresenter.swift similarity index 100% rename from Example/ChatWallet/PresentationLayer/Wallet/Welcome/WelcomePresenter.swift rename to Example/WalletApp/PresentationLayer/Wallet/Welcome/WelcomePresenter.swift diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Welcome/WelcomeRouter.swift b/Example/WalletApp/PresentationLayer/Wallet/Welcome/WelcomeRouter.swift similarity index 100% rename from Example/ChatWallet/PresentationLayer/Wallet/Welcome/WelcomeRouter.swift rename to Example/WalletApp/PresentationLayer/Wallet/Welcome/WelcomeRouter.swift diff --git a/Example/ChatWallet/PresentationLayer/Wallet/Welcome/WelcomeView.swift b/Example/WalletApp/PresentationLayer/Wallet/Welcome/WelcomeView.swift similarity index 100% rename from Example/ChatWallet/PresentationLayer/Wallet/Welcome/WelcomeView.swift rename to Example/WalletApp/PresentationLayer/Wallet/Welcome/WelcomeView.swift From 3fe886c788348bfb4248753935db0f031cdc6920 Mon Sep 17 00:00:00 2001 From: Alexander Lisovik Date: Tue, 3 Jan 2023 19:20:17 +0100 Subject: [PATCH 06/14] Fix paste uri --- .../Wallet/AuthRequest/AuthRequestRouter.swift | 1 + .../Wallet/PasteUri/PasteUriView.swift | 10 +++++++--- .../Wallet/Wallet/WalletPresenter.swift | 4 ++-- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Example/WalletApp/PresentationLayer/Wallet/AuthRequest/AuthRequestRouter.swift b/Example/WalletApp/PresentationLayer/Wallet/AuthRequest/AuthRequestRouter.swift index d21c62d49..76e35da11 100644 --- a/Example/WalletApp/PresentationLayer/Wallet/AuthRequest/AuthRequestRouter.swift +++ b/Example/WalletApp/PresentationLayer/Wallet/AuthRequest/AuthRequestRouter.swift @@ -11,5 +11,6 @@ final class AuthRequestRouter { func dismiss() { viewController.dismiss() + UIApplication.shared.open(URL(string: "showcase://")!) } } diff --git a/Example/WalletApp/PresentationLayer/Wallet/PasteUri/PasteUriView.swift b/Example/WalletApp/PresentationLayer/Wallet/PasteUri/PasteUriView.swift index 5c1ac8d47..9214f1d2f 100644 --- a/Example/WalletApp/PresentationLayer/Wallet/PasteUri/PasteUriView.swift +++ b/Example/WalletApp/PresentationLayer/Wallet/PasteUri/PasteUriView.swift @@ -7,7 +7,9 @@ private enum FocusField: Hashable { struct PasteUriView: View { @Environment(\.dismiss) var dismiss - @State var text = "" + @EnvironmentObject var presenter: PasteUriPresenter + + @State private var text = "" var body: some View { ZStack { @@ -39,7 +41,7 @@ struct PasteUriView: View { .font(.system(size: 17, weight: .regular, design: .rounded)) Button { - // + text = "" } label: { Image(systemName: "xmark.circle.fill") .foregroundColor(.systemGrayLight) @@ -52,7 +54,8 @@ struct PasteUriView: View { .ignoresSafeArea(.keyboard) Button { - // + presenter.onValue(text) + dismiss() } label: { Text("Connect") .frame(maxWidth: .infinity) @@ -71,6 +74,7 @@ struct PasteUriView: View { } .padding(.top, 20) .shadow(color: .white.opacity(0.25), radius: 8, y: 2) + .disabled(text.isEmpty) Button { dismiss() diff --git a/Example/WalletApp/PresentationLayer/Wallet/Wallet/WalletPresenter.swift b/Example/WalletApp/PresentationLayer/Wallet/Wallet/WalletPresenter.swift index b973a5ece..5de755589 100644 --- a/Example/WalletApp/PresentationLayer/Wallet/Wallet/WalletPresenter.swift +++ b/Example/WalletApp/PresentationLayer/Wallet/Wallet/WalletPresenter.swift @@ -69,7 +69,7 @@ extension WalletPresenter { } .store(in: &disposeBag) - pairFropDapp() + pairFromDapp() } private func pair(uri: WalletConnectURI) { @@ -78,7 +78,7 @@ extension WalletPresenter { } } - private func pairFropDapp() { + private func pairFromDapp() { guard let uri = uri, let walletConnectUri = WalletConnectURI(string: uri) else { From 5c928360b9576a1efab1c5cd3c2c688cbe51ab24 Mon Sep 17 00:00:00 2001 From: Alexander Lisovik Date: Tue, 3 Jan 2023 20:11:43 +0100 Subject: [PATCH 07/14] Small fixes --- Configuration.xcconfig | 1 + .../ApplicationLayer/Configurator/ThirdPartyConfigurator.swift | 1 + 2 files changed, 2 insertions(+) diff --git a/Configuration.xcconfig b/Configuration.xcconfig index 7f4069cda..9bdb86903 100644 --- a/Configuration.xcconfig +++ b/Configuration.xcconfig @@ -2,3 +2,4 @@ RELAY_HOST = relay.walletconnect.com // Uncomment next line and paste your project id. Get this on: https://cloud.walletconnect.com/sign-in PROJECT_ID = 1012db890ca3cab0c1cdc929fdd657bf +// PROJECT_ID = YOUR_PROJECT_ID diff --git a/Example/WalletApp/ApplicationLayer/Configurator/ThirdPartyConfigurator.swift b/Example/WalletApp/ApplicationLayer/Configurator/ThirdPartyConfigurator.swift index fe19bbb99..4aaf7a286 100644 --- a/Example/WalletApp/ApplicationLayer/Configurator/ThirdPartyConfigurator.swift +++ b/Example/WalletApp/ApplicationLayer/Configurator/ThirdPartyConfigurator.swift @@ -11,6 +11,7 @@ struct ThirdPartyConfigurator: Configurator { url: "example.wallet", icons: ["https://avatars.githubusercontent.com/u/37784886"] ) + Web3Wallet.configure(metadata: metadata, signerFactory: DefaultSignerFactory()) } } From 24003eadc9fc9f4a2a42411a9412f131bd868167 Mon Sep 17 00:00:00 2001 From: Alexander Lisovik Date: Tue, 3 Jan 2023 20:16:52 +0100 Subject: [PATCH 08/14] Update configuration --- Configuration.xcconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/Configuration.xcconfig b/Configuration.xcconfig index 9bdb86903..15db0fdbc 100644 --- a/Configuration.xcconfig +++ b/Configuration.xcconfig @@ -1,5 +1,4 @@ RELAY_HOST = relay.walletconnect.com // Uncomment next line and paste your project id. Get this on: https://cloud.walletconnect.com/sign-in -PROJECT_ID = 1012db890ca3cab0c1cdc929fdd657bf // PROJECT_ID = YOUR_PROJECT_ID From f01e3d19b17aba6127dd5604e7d749225c1058f1 Mon Sep 17 00:00:00 2001 From: Alexander Lisovik Date: Thu, 5 Jan 2023 20:53:27 +0100 Subject: [PATCH 09/14] Add session request, PR fixes --- Example/ExampleApp.xcodeproj/project.pbxproj | 78 ++++---- .../Chat/Welcome/WelcomeInteractor.swift | 55 +----- .../ApplicationLayer/Application.swift | 12 -- .../WalletApp/Common/Helpers/TagsView.swift | 105 +++++++++++ .../AccountStorage/AccountStorage.swift | 21 --- .../Chat/AccountNameResolver.swift | 23 --- .../DomainLayer/Chat/ChatService.swift | 67 ------- .../DomainLayer/Chat/RegisterService.swift | 15 -- Example/WalletApp/Other/Info.plist | 2 + .../Wallet/AuthRequest/AuthRequestView.swift | 70 +++---- .../ConnectionDetailsInteractor.swift | 11 +- .../ConnectionDetailsPresenter.swift | 35 +--- .../ConnectionDetailsRouter.swift | 2 +- .../ConnectionDetailsView.swift | 162 +++++++--------- .../SessionRequest/Modela/Proposal.swift | 58 ++++++ .../SessionRequestInteractor.swift | 37 ++++ .../SessionRequest/SessionRequestModule.swift | 22 +++ .../SessionRequestPresenter.swift | 50 +++++ .../SessionRequest/SessionRequestRouter.swift | 15 ++ .../SessionRequest/SessionRequestView.swift | 175 ++++++++++++++++++ .../Wallet/Wallet/WalletInteractor.swift | 4 + .../Wallet/Wallet/WalletPresenter.swift | 7 + .../Wallet/Wallet/WalletRouter.swift | 5 + 23 files changed, 649 insertions(+), 382 deletions(-) create mode 100644 Example/WalletApp/Common/Helpers/TagsView.swift delete mode 100644 Example/WalletApp/DomainLayer/AccountStorage/AccountStorage.swift delete mode 100644 Example/WalletApp/DomainLayer/Chat/AccountNameResolver.swift delete mode 100644 Example/WalletApp/DomainLayer/Chat/ChatService.swift delete mode 100644 Example/WalletApp/DomainLayer/Chat/RegisterService.swift create mode 100644 Example/WalletApp/PresentationLayer/Wallet/SessionRequest/Modela/Proposal.swift create mode 100644 Example/WalletApp/PresentationLayer/Wallet/SessionRequest/SessionRequestInteractor.swift create mode 100644 Example/WalletApp/PresentationLayer/Wallet/SessionRequest/SessionRequestModule.swift create mode 100644 Example/WalletApp/PresentationLayer/Wallet/SessionRequest/SessionRequestPresenter.swift create mode 100644 Example/WalletApp/PresentationLayer/Wallet/SessionRequest/SessionRequestRouter.swift create mode 100644 Example/WalletApp/PresentationLayer/Wallet/SessionRequest/SessionRequestView.swift diff --git a/Example/ExampleApp.xcodeproj/project.pbxproj b/Example/ExampleApp.xcodeproj/project.pbxproj index 8be9c5e25..e8cce5489 100644 --- a/Example/ExampleApp.xcodeproj/project.pbxproj +++ b/Example/ExampleApp.xcodeproj/project.pbxproj @@ -198,6 +198,13 @@ C55D3496295DFA750004314A /* WelcomeInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D3491295DFA750004314A /* WelcomeInteractor.swift */; }; C55D3497295DFA750004314A /* WelcomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D3492295DFA750004314A /* WelcomeView.swift */; }; C55D349929630D440004314A /* Web3Wallet in Frameworks */ = {isa = PBXBuildFile; productRef = C55D349829630D440004314A /* Web3Wallet */; }; + C55D349B2965BC2F0004314A /* TagsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D349A2965BC2F0004314A /* TagsView.swift */; }; + C55D349D2965F8D40004314A /* Proposal.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D349C2965F8D30004314A /* Proposal.swift */; }; + C55D34AE2965FB750004314A /* SessionRequestModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D34A92965FB750004314A /* SessionRequestModule.swift */; }; + C55D34AF2965FB750004314A /* SessionRequestPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D34AA2965FB750004314A /* SessionRequestPresenter.swift */; }; + C55D34B02965FB750004314A /* SessionRequestRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D34AB2965FB750004314A /* SessionRequestRouter.swift */; }; + C55D34B12965FB750004314A /* SessionRequestInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D34AC2965FB750004314A /* SessionRequestInteractor.swift */; }; + C55D34B22965FB750004314A /* SessionRequestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D34AD2965FB750004314A /* SessionRequestView.swift */; }; C56EE222293F55EE004840D1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C56EE221293F55EE004840D1 /* Assets.xcassets */; }; C56EE240293F566D004840D1 /* ScanQRView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE23F293F566C004840D1 /* ScanQRView.swift */; }; C56EE241293F566D004840D1 /* WalletModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE22D293F5669004840D1 /* WalletModule.swift */; }; @@ -231,11 +238,7 @@ C56EE28D293F5757004840D1 /* AppearanceConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE287293F5757004840D1 /* AppearanceConfigurator.swift */; }; C56EE28E293F5757004840D1 /* ApplicationConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE284293F5757004840D1 /* ApplicationConfigurator.swift */; }; C56EE28F293F5757004840D1 /* MigrationConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE283293F5757004840D1 /* MigrationConfigurator.swift */; }; - C56EE299293F5773004840D1 /* AccountNameResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE296293F5773004840D1 /* AccountNameResolver.swift */; }; - C56EE29A293F5773004840D1 /* AccountStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE298293F5773004840D1 /* AccountStorage.swift */; }; C56EE29B293F5773004840D1 /* SocketFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE292293F5773004840D1 /* SocketFactory.swift */; }; - C56EE29C293F5773004840D1 /* ChatService.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE295293F5773004840D1 /* ChatService.swift */; }; - C56EE29D293F5773004840D1 /* RegisterService.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE294293F5773004840D1 /* RegisterService.swift */; }; C56EE2A3293F6BAF004840D1 /* UIPasteboardWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE2A2293F6BAF004840D1 /* UIPasteboardWrapper.swift */; }; C5DD5BE1294E09E3008FD3A4 /* Web3Wallet in Frameworks */ = {isa = PBXBuildFile; productRef = C5DD5BE0294E09E3008FD3A4 /* Web3Wallet */; }; C5F32A2C2954814200A6476E /* ConnectionDetailsModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5F32A2B2954814200A6476E /* ConnectionDetailsModule.swift */; }; @@ -437,6 +440,13 @@ C55D3490295DFA750004314A /* WelcomeRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeRouter.swift; sourceTree = ""; }; C55D3491295DFA750004314A /* WelcomeInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeInteractor.swift; sourceTree = ""; }; C55D3492295DFA750004314A /* WelcomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeView.swift; sourceTree = ""; }; + C55D349A2965BC2F0004314A /* TagsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagsView.swift; sourceTree = ""; }; + C55D349C2965F8D30004314A /* Proposal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Proposal.swift; sourceTree = ""; }; + C55D34A92965FB750004314A /* SessionRequestModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionRequestModule.swift; sourceTree = ""; }; + C55D34AA2965FB750004314A /* SessionRequestPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionRequestPresenter.swift; sourceTree = ""; }; + C55D34AB2965FB750004314A /* SessionRequestRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionRequestRouter.swift; sourceTree = ""; }; + C55D34AC2965FB750004314A /* SessionRequestInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionRequestInteractor.swift; sourceTree = ""; }; + C55D34AD2965FB750004314A /* SessionRequestView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionRequestView.swift; sourceTree = ""; }; C56EE21B293F55ED004840D1 /* WalletApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WalletApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; C56EE221293F55EE004840D1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; C56EE22B293F5668004840D1 /* WalletView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletView.swift; sourceTree = ""; }; @@ -469,10 +479,6 @@ C56EE286293F5757004840D1 /* ThirdPartyConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThirdPartyConfigurator.swift; sourceTree = ""; }; C56EE287293F5757004840D1 /* AppearanceConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearanceConfigurator.swift; sourceTree = ""; }; C56EE292293F5773004840D1 /* SocketFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocketFactory.swift; sourceTree = ""; }; - C56EE294293F5773004840D1 /* RegisterService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegisterService.swift; sourceTree = ""; }; - C56EE295293F5773004840D1 /* ChatService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatService.swift; sourceTree = ""; }; - C56EE296293F5773004840D1 /* AccountNameResolver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountNameResolver.swift; sourceTree = ""; }; - C56EE298293F5773004840D1 /* AccountStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountStorage.swift; sourceTree = ""; }; C56EE29F293F5C4F004840D1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; C56EE2A2293F6BAF004840D1 /* UIPasteboardWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIPasteboardWrapper.swift; sourceTree = ""; }; C5F32A2B2954814200A6476E /* ConnectionDetailsModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionDetailsModule.swift; sourceTree = ""; }; @@ -1272,6 +1278,27 @@ path = Welcome; sourceTree = ""; }; + C55D349E2965FAC30004314A /* SessionRequest */ = { + isa = PBXGroup; + children = ( + C55D34B32965FF750004314A /* Modela */, + C55D34A92965FB750004314A /* SessionRequestModule.swift */, + C55D34AA2965FB750004314A /* SessionRequestPresenter.swift */, + C55D34AB2965FB750004314A /* SessionRequestRouter.swift */, + C55D34AC2965FB750004314A /* SessionRequestInteractor.swift */, + C55D34AD2965FB750004314A /* SessionRequestView.swift */, + ); + path = SessionRequest; + sourceTree = ""; + }; + C55D34B32965FF750004314A /* Modela */ = { + isa = PBXGroup; + children = ( + C55D349C2965F8D30004314A /* Proposal.swift */, + ); + path = Modela; + sourceTree = ""; + }; C56EE21C293F55ED004840D1 /* WalletApp */ = { isa = PBXGroup; children = ( @@ -1287,6 +1314,7 @@ C56EE229293F5668004840D1 /* Wallet */ = { isa = PBXGroup; children = ( + C55D349E2965FAC30004314A /* SessionRequest */, C55D3477295DD4AA0004314A /* Welcome */, C55D3474295DCB850004314A /* AuthRequest */, C55D3471295DC5F60004314A /* PasteUri */, @@ -1422,9 +1450,7 @@ C56EE290293F5773004840D1 /* DomainLayer */ = { isa = PBXGroup; children = ( - C56EE297293F5773004840D1 /* AccountStorage */, C56EE291293F5773004840D1 /* SocketFactory */, - C56EE293293F5773004840D1 /* Chat */, ); path = DomainLayer; sourceTree = ""; @@ -1437,24 +1463,6 @@ path = SocketFactory; sourceTree = ""; }; - C56EE293293F5773004840D1 /* Chat */ = { - isa = PBXGroup; - children = ( - C56EE295293F5773004840D1 /* ChatService.swift */, - C56EE296293F5773004840D1 /* AccountNameResolver.swift */, - C56EE294293F5773004840D1 /* RegisterService.swift */, - ); - path = Chat; - sourceTree = ""; - }; - C56EE297293F5773004840D1 /* AccountStorage */ = { - isa = PBXGroup; - children = ( - C56EE298293F5773004840D1 /* AccountStorage.swift */, - ); - path = AccountStorage; - sourceTree = ""; - }; C56EE29E293F577B004840D1 /* PresentationLayer */ = { isa = PBXGroup; children = ( @@ -1477,6 +1485,7 @@ isa = PBXGroup; children = ( C56EE2A2293F6BAF004840D1 /* UIPasteboardWrapper.swift */, + C55D349A2965BC2F0004314A /* TagsView.swift */, ); path = Helpers; sourceTree = ""; @@ -1933,11 +1942,11 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - C56EE29C293F5773004840D1 /* ChatService.swift in Sources */, C53AA4362941251C008EA57C /* DefaultSignerFactory.swift in Sources */, C55D3480295DD7140004314A /* AuthRequestPresenter.swift in Sources */, C5F32A2E2954814A00A6476E /* ConnectionDetailsRouter.swift in Sources */, C55D3482295DD7140004314A /* AuthRequestInteractor.swift in Sources */, + C55D34B12965FB750004314A /* SessionRequestInteractor.swift in Sources */, C56EE247293F566D004840D1 /* ScanModule.swift in Sources */, C56EE28D293F5757004840D1 /* AppearanceConfigurator.swift in Sources */, C56EE241293F566D004840D1 /* WalletModule.swift in Sources */, @@ -1948,7 +1957,6 @@ C56EE28F293F5757004840D1 /* MigrationConfigurator.swift in Sources */, C55D348B295DD8CA0004314A /* PasteUriRouter.swift in Sources */, C55D348C295DD8CA0004314A /* PasteUriInteractor.swift in Sources */, - C56EE299293F5773004840D1 /* AccountNameResolver.swift in Sources */, C55D3497295DFA750004314A /* WelcomeView.swift in Sources */, C56EE271293F56D7004840D1 /* View.swift in Sources */, C56EE24D293F566D004840D1 /* WalletRouter.swift in Sources */, @@ -1957,7 +1965,6 @@ C56EE28E293F5757004840D1 /* ApplicationConfigurator.swift in Sources */, C55D347F295DD7140004314A /* AuthRequestModule.swift in Sources */, C56EE242293F566D004840D1 /* ScanPresenter.swift in Sources */, - C56EE29D293F5773004840D1 /* RegisterService.swift in Sources */, C56EE28B293F5757004840D1 /* SceneDelegate.swift in Sources */, C56EE276293F56D7004840D1 /* UIViewController.swift in Sources */, C56EE275293F56D7004840D1 /* InputConfig.swift in Sources */, @@ -1967,14 +1974,18 @@ C55D3483295DD7140004314A /* AuthRequestView.swift in Sources */, C56EE243293F566D004840D1 /* ScanView.swift in Sources */, C56EE288293F5757004840D1 /* ThirdPartyConfigurator.swift in Sources */, - C56EE29A293F5773004840D1 /* AccountStorage.swift in Sources */, + C55D34AE2965FB750004314A /* SessionRequestModule.swift in Sources */, + C55D34B02965FB750004314A /* SessionRequestRouter.swift in Sources */, C55D3495295DFA750004314A /* WelcomeRouter.swift in Sources */, C56EE24F293F566D004840D1 /* WalletView.swift in Sources */, + C55D34B22965FB750004314A /* SessionRequestView.swift in Sources */, C56EE248293F566D004840D1 /* ScanQR.swift in Sources */, + C55D349B2965BC2F0004314A /* TagsView.swift in Sources */, C56EE289293F5757004840D1 /* Application.swift in Sources */, C56EE273293F56D7004840D1 /* UIColor.swift in Sources */, C5F32A322954816C00A6476E /* ConnectionDetailsPresenter.swift in Sources */, C56EE246293F566D004840D1 /* ScanRouter.swift in Sources */, + C55D349D2965F8D40004314A /* Proposal.swift in Sources */, C55D3481295DD7140004314A /* AuthRequestRouter.swift in Sources */, C56EE28C293F5757004840D1 /* Configurator.swift in Sources */, C55D3489295DD8CA0004314A /* PasteUriModule.swift in Sources */, @@ -1987,6 +1998,7 @@ C56EE28A293F5757004840D1 /* AppDelegate.swift in Sources */, C56EE2A3293F6BAF004840D1 /* UIPasteboardWrapper.swift in Sources */, C56EE24E293F566D004840D1 /* WalletInteractor.swift in Sources */, + C55D34AF2965FB750004314A /* SessionRequestPresenter.swift in Sources */, C5F32A302954816100A6476E /* ConnectionDetailsInteractor.swift in Sources */, C56EE29B293F5773004840D1 /* SocketFactory.swift in Sources */, ); @@ -2419,6 +2431,7 @@ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = RQ4NX29V75; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = WalletApp/Other/Info.plist; @@ -2448,6 +2461,7 @@ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = RQ4NX29V75; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = WalletApp/Other/Info.plist; diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomeInteractor.swift b/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomeInteractor.swift index 0ddc53aec..8a9d25a57 100644 --- a/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomeInteractor.swift +++ b/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomeInteractor.swift @@ -31,59 +31,8 @@ final class WelcomeInteractor { } func generateUri() async -> WalletConnectURI { - let appPairingClient = makeClient(prefix: "🤡") - return try! await appPairingClient.create() - } - - func makeClient(prefix: String) -> PairingClient { - let keychain = KeychainStorage(serviceIdentifier: "com.walletconnect.sdk") - let keyValueStorage = RuntimeKeyValueStorage() - - let relayLogger = ConsoleLogger(suffix: prefix + " [Relay]", loggingLevel: .debug) - let pairingLogger = ConsoleLogger(suffix: prefix + " [Pairing]", loggingLevel: .debug) - let networkingLogger = ConsoleLogger(suffix: prefix + " [Networking]", loggingLevel: .debug) - let authLogger = ConsoleLogger(suffix: prefix + " [Auth]", loggingLevel: .debug) - - let relayClient = RelayClient( - relayHost: InputConfig.relayHost, - projectId: InputConfig.projectId, - keyValueStorage: RuntimeKeyValueStorage(), - keychainStorage: keychain, - socketFactory: SocketFactory(), - logger: relayLogger - ) - - let networkingClient = NetworkingClientFactory.create( - relayClient: relayClient, - logger: networkingLogger, - keychainStorage: keychain, - keyValueStorage: keyValueStorage - ) - - let pairingClient = PairingClientFactory.create( - logger: pairingLogger, - keyValueStorage: keyValueStorage, - keychainStorage: keychain, - networkingClient: networkingClient - ) - - authClient = AuthClientFactory.create( - metadata: AppMetadata(name: "chatapp", description: "", url: "", icons: [""]), - projectId: InputConfig.projectId, - signerFactory: DefaultSignerFactory(), - networkingClient: networkingClient, - pairingRegisterer: pairingClient - ) - - authClient?.authResponsePublisher.sink { (_, result) in - guard case .success = result else { - return - } - print(result) - } - .store(in: &disposeBag) - - return pairingClient + authClient = Auth.instance + return try! await Pair.instance.create() } } diff --git a/Example/WalletApp/ApplicationLayer/Application.swift b/Example/WalletApp/ApplicationLayer/Application.swift index 75d475609..97fc2aaf6 100644 --- a/Example/WalletApp/ApplicationLayer/Application.swift +++ b/Example/WalletApp/ApplicationLayer/Application.swift @@ -3,16 +3,4 @@ import WalletConnectChat final class Application { var uri: String? - - lazy var chatService: ChatService = { - return ChatService(client: Chat.instance) - }() - - lazy var accountStorage: AccountStorage = { - return AccountStorage(defaults: .standard) - }() - - lazy var registerService: RegisterService = { - return RegisterService(chatService: chatService) - }() } diff --git a/Example/WalletApp/Common/Helpers/TagsView.swift b/Example/WalletApp/Common/Helpers/TagsView.swift new file mode 100644 index 000000000..5e53329cd --- /dev/null +++ b/Example/WalletApp/Common/Helpers/TagsView.swift @@ -0,0 +1,105 @@ +import SwiftUI + +private struct HeightPreferenceKey: PreferenceKey { + static func reduce(value _: inout CGFloat, nextValue _: () -> CGFloat) {} + static var defaultValue: CGFloat = 0 +} + +private struct HeightReaderView: View { + @Binding var binding: CGFloat + + var body: some View { + GeometryReader { geo in + Color.clear + .preference(key: HeightPreferenceKey.self, value: geo.frame(in: .local).size.height) + } + .onPreferenceChange(HeightPreferenceKey.self) { h in + binding = h + } + } +} + +public let tagsViewDefaultItemSpacing: CGFloat = 4 + +public struct TagsView: View { + @Binding var binding: RefreshBinding + let items: [Data] + let itemSpacing: CGFloat + @ViewBuilder let viewMapping: (Data) -> ItemView + + @State private var totalHeight: CGFloat + + public init( + binding: Binding, + items: [Data], + itemSpacing: CGFloat = tagsViewDefaultItemSpacing, + @ViewBuilder viewMapping: @escaping (Data) -> ItemView + ) { + _binding = binding + self.items = items + self.itemSpacing = itemSpacing + self.viewMapping = viewMapping + _totalHeight = State(initialValue: .zero) + } + + public var body: some View { + let stack = VStack { + GeometryReader { geometry in + self.content(in: geometry) + } + } + return Group { + stack.frame(height: totalHeight) + } + } + + private func content(in geometry: GeometryProxy) -> some View { + var width = CGFloat.zero + var height = CGFloat.zero + var lastHeight = CGFloat.zero + let itemCount = items.count + return ZStack(alignment: .topLeading) { + ForEach(Array(items.enumerated()), id: \.offset) { index, item in + viewMapping(item) + .padding([.horizontal, .vertical], itemSpacing) + .alignmentGuide(.leading, computeValue: { d in + if (abs(width - d.width) > geometry.size.width) { + width = 0 + height -= lastHeight + } + lastHeight = d.height + let result = width + if index == itemCount - 1 { + width = 0 + } else { + width -= d.width + } + return result + }) + .alignmentGuide(.top, computeValue: { d in + let result = height + if index == itemCount - 1 { + height = 0 + } + return result + }) + } + } + .background(HeightReaderView(binding: $totalHeight)) + } +} + +public extension TagsView where RefreshBinding == Never? { + init( + items: [Data], + itemSpacing: CGFloat = tagsViewDefaultItemSpacing, + @ViewBuilder viewMapping: @escaping (Data) -> ItemView + ) { + self.init( + binding: .constant(nil), + items: items, + itemSpacing: itemSpacing, + viewMapping: viewMapping + ) + } +} diff --git a/Example/WalletApp/DomainLayer/AccountStorage/AccountStorage.swift b/Example/WalletApp/DomainLayer/AccountStorage/AccountStorage.swift deleted file mode 100644 index ab86a093a..000000000 --- a/Example/WalletApp/DomainLayer/AccountStorage/AccountStorage.swift +++ /dev/null @@ -1,21 +0,0 @@ -import Foundation - -final class AccountStorage { - private let defaults: UserDefaults - - init(defaults: UserDefaults) { - self.defaults = defaults - } - - var account: Account? { - get { - guard let value = UserDefaults.standard.string(forKey: "account") else { - return nil - } - return Account(value) - } - set { - UserDefaults.standard.set(newValue?.absoluteString, forKey: "account") - } - } -} diff --git a/Example/WalletApp/DomainLayer/Chat/AccountNameResolver.swift b/Example/WalletApp/DomainLayer/Chat/AccountNameResolver.swift deleted file mode 100644 index dc7ac4339..000000000 --- a/Example/WalletApp/DomainLayer/Chat/AccountNameResolver.swift +++ /dev/null @@ -1,23 +0,0 @@ -import Foundation - -struct AccountNameResolver { - - private static var staticMap: [String: String] = [ - "swift.eth": "eip155:1:0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb", - "kotlin.eth": "eip155:2:0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb", - "js.eth": "eip155:3:0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb" - ] - - static func resolveName(_ account: Account) -> String { - return staticMap - .first(where: { $0.value == account.absoluteString })?.key ?? account.absoluteString - } - - static func resolveAccount(_ input: String) -> Account? { - guard let value = staticMap[input.lowercased()] else { - return Account(input) - } - - return Account(value)! - } -} diff --git a/Example/WalletApp/DomainLayer/Chat/ChatService.swift b/Example/WalletApp/DomainLayer/Chat/ChatService.swift deleted file mode 100644 index 991c06c66..000000000 --- a/Example/WalletApp/DomainLayer/Chat/ChatService.swift +++ /dev/null @@ -1,67 +0,0 @@ -import Foundation -import Combine -import WalletConnectChat -import WalletConnectRelay - -typealias Stream = AsyncPublisher> - -final class ChatService { - - private let client: ChatClient - - init(client: ChatClient) { - self.client = client - } - - var connectionPublisher: Stream { - return client.socketConnectionStatusPublisher.values - } - - var messagePublisher: Stream { - return client.messagePublisher.values - } - - var threadPublisher: Stream { - return client.newThreadPublisher.values - } - - var invitePublisher: Stream { - return client.invitePublisher.values - } - - func getMessages(thread: WalletConnectChat.Thread) async -> [WalletConnectChat.Message] { - await client.getMessages(topic: thread.topic) - } - - func getThreads() async -> [WalletConnectChat.Thread] { - await client.getThreads() - } - - func getInvites(account: Account) async -> [WalletConnectChat.Invite] { - client.getInvites(account: account) - } - - func sendMessage(topic: String, message: String) async throws { - try await client.message(topic: topic, message: message) - } - - func accept(invite: Invite) async throws { - try await client.accept(inviteId: invite.id) - } - - func reject(invite: Invite) async throws { - try await client.reject(inviteId: invite.id) - } - - func invite(peerAccount: Account, message: String, selfAccount: Account) async throws { - try await client.invite(peerAccount: peerAccount, openingMessage: message, account: selfAccount) - } - - func register(account: Account) async throws { - _ = try await client.register(account: account) - } - - func resolve(account: Account) async throws -> String { - return try await client.resolve(account: account) - } -} diff --git a/Example/WalletApp/DomainLayer/Chat/RegisterService.swift b/Example/WalletApp/DomainLayer/Chat/RegisterService.swift deleted file mode 100644 index 881c94b28..000000000 --- a/Example/WalletApp/DomainLayer/Chat/RegisterService.swift +++ /dev/null @@ -1,15 +0,0 @@ -import Foundation - -final class RegisterService { - - private let chatService: ChatService - - init(chatService: ChatService) { - self.chatService = chatService - } - - func register(account: Account) async { - try! await chatService.register(account: account) - print("Account: \(account.absoluteString) registered") - } -} diff --git a/Example/WalletApp/Other/Info.plist b/Example/WalletApp/Other/Info.plist index 672603421..ef9e6d46f 100644 --- a/Example/WalletApp/Other/Info.plist +++ b/Example/WalletApp/Other/Info.plist @@ -24,6 +24,8 @@ PROJECT_ID $(PROJECT_ID) + NSCameraUsageDescription + Camera access for scanning QR code UIApplicationSceneManifest UIApplicationSupportsMultipleScenes diff --git a/Example/WalletApp/PresentationLayer/Wallet/AuthRequest/AuthRequestView.swift b/Example/WalletApp/PresentationLayer/Wallet/AuthRequest/AuthRequestView.swift index d5fa473ed..93a602fb2 100644 --- a/Example/WalletApp/PresentationLayer/Wallet/AuthRequest/AuthRequestView.swift +++ b/Example/WalletApp/PresentationLayer/Wallet/AuthRequest/AuthRequestView.swift @@ -33,39 +33,7 @@ struct AuthRequestView: View { .lineSpacing(4) .padding(.top, 8) - VStack { - VStack(alignment: .leading) { - Text("Message") - .font(.system(size: 15, weight: .semibold, design: .rounded)) - .foregroundColor(.whiteBackground) - .padding(.horizontal, 8) - .padding(.vertical, 5) - .background(Color.grey70) - .cornerRadius(28, corners: .allCorners) - .padding(.leading, 15) - .padding(.top, 9) - - VStack(spacing: 0) { - HStack { - Text(presenter.message) - .foregroundColor(.grey50) - .font(.system(size: 13, weight: .semibold, design: .rounded)) - - Spacer() - } - .padding(.horizontal, 18) - .padding(.vertical, 10) - } - .background(Color.whiteBackground) - .cornerRadius(20, corners: .allCorners) - .padding(.horizontal, 5) - .padding(.bottom, 5) - - } - .background(.thinMaterial) - .cornerRadius(25, corners: .allCorners) - } - .padding(.top, 30) + authRequestView() HStack(spacing: 20) { Button { @@ -124,6 +92,42 @@ struct AuthRequestView: View { } .edgesIgnoringSafeArea(.all) } + + private func authRequestView() -> some View { + VStack { + VStack(alignment: .leading) { + Text("Message") + .font(.system(size: 15, weight: .semibold, design: .rounded)) + .foregroundColor(.whiteBackground) + .padding(.horizontal, 8) + .padding(.vertical, 5) + .background(Color.grey70) + .cornerRadius(28, corners: .allCorners) + .padding(.leading, 15) + .padding(.top, 9) + + VStack(spacing: 0) { + HStack { + Text(presenter.message) + .foregroundColor(.grey50) + .font(.system(size: 13, weight: .semibold, design: .rounded)) + + Spacer() + } + .padding(.horizontal, 18) + .padding(.vertical, 10) + } + .background(Color.whiteBackground) + .cornerRadius(20, corners: .allCorners) + .padding(.horizontal, 5) + .padding(.bottom, 5) + + } + .background(.thinMaterial) + .cornerRadius(25, corners: .allCorners) + } + .padding(.top, 30) + } } #if DEBUG diff --git a/Example/WalletApp/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsInteractor.swift b/Example/WalletApp/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsInteractor.swift index 6de01c7b5..c9fe17a65 100644 --- a/Example/WalletApp/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsInteractor.swift +++ b/Example/WalletApp/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsInteractor.swift @@ -1,12 +1,17 @@ import Combine + import Web3Wallet final class ConnectionDetailsInteractor { + var requestPublisher: AnyPublisher { + return Web3Wallet.instance.authRequestPublisher + } + func pair(uri: WalletConnectURI) async throws { try await Web3Wallet.instance.pair(uri: uri) } - - var requestPublisher: AnyPublisher { - return Web3Wallet.instance.authRequestPublisher + + func disconnectSession(session: Session) async throws { + try await Web3Wallet.instance.disconnect(topic: session.topic) } } diff --git a/Example/WalletApp/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsPresenter.swift b/Example/WalletApp/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsPresenter.swift index f799e5013..0e5f91bc1 100644 --- a/Example/WalletApp/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsPresenter.swift +++ b/Example/WalletApp/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsPresenter.swift @@ -17,43 +17,28 @@ final class ConnectionDetailsPresenter: ObservableObject { router: ConnectionDetailsRouter, session: Session ) { - defer { setupInitialState() } self.interactor = interactor self.router = router self.session = session } - func didPastePairingURI() { - guard let string = UIPasteboard.general.string, let uri = WalletConnectURI(string: string) else { return } - print(uri) - pair(uri: uri) - } - - func didScanPairingURI() { - router.presentScan { [unowned self] value in - guard let uri = WalletConnectURI(string: value) else { return } - self.pair(uri: uri) - self.router.dismiss() - } onError: { error in - print(error.localizedDescription) - self.router.dismiss() + func onDelete() { + Task { + do { + try await interactor.disconnectSession(session: session) + DispatchQueue.main.async { + self.router.dismiss() + } + } catch { + print(error) + } } } } // MARK: - Private functions private extension ConnectionDetailsPresenter { - func setupInitialState() { - interactor.requestPublisher.sink { [unowned self] request in - self.router.present(request: request) - }.store(in: &disposeBag) - } - func pair(uri: WalletConnectURI) { - Task(priority: .high) { [unowned self] in - try await self.interactor.pair(uri: uri) - } - } } // MARK: - SceneViewModel diff --git a/Example/WalletApp/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsRouter.swift b/Example/WalletApp/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsRouter.swift index eac9622e5..4dcf67cd1 100644 --- a/Example/WalletApp/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsRouter.swift +++ b/Example/WalletApp/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsRouter.swift @@ -23,6 +23,6 @@ final class ConnectionDetailsRouter { } func dismiss() { - viewController.navigationController?.dismiss() + viewController.navigationController?.popViewController(animated: true) } } diff --git a/Example/WalletApp/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsView.swift b/Example/WalletApp/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsView.swift index b9f5520a9..9ce0b6ef7 100644 --- a/Example/WalletApp/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsView.swift +++ b/Example/WalletApp/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsView.swift @@ -35,116 +35,84 @@ struct ConnectionDetailsView: View { .font(.system(size: 13, weight: .medium, design: .rounded)) } - VStack { - VStack(alignment: .leading) { - Text("IEP155:1") - .font(.system(size: 15, weight: .semibold, design: .rounded)) - .foregroundColor(.whiteBackground) - .padding(.horizontal, 8) - .padding(.vertical, 5) - .background(Color.grey70) - .cornerRadius(28, corners: .allCorners) - .padding(.leading, 15) - .padding(.top, 9) - - VStack(spacing: 0) { - HStack { - Text("Accounts") - .foregroundColor(.grey50) - .font(.system(size: 13, weight: .semibold, design: .rounded)) - - Spacer() + ForEach(presenter.session.namespaces.keys.sorted(), id: \.self) { namespace in + VStack { + VStack(alignment: .leading) { + Text(namespace) + .font(.system(size: 15, weight: .semibold, design: .rounded)) + .foregroundColor(.whiteBackground) + .padding(.horizontal, 8) + .padding(.vertical, 5) + .background(Color.grey70) + .cornerRadius(28, corners: .allCorners) + .padding(.leading, 15) + .padding(.top, 9) + + VStack(spacing: 0) { + HStack { + Text("Accounts") + .foregroundColor(.grey50) + .font(.system(size: 13, weight: .semibold, design: .rounded)) + + Spacer() + } + .padding(.horizontal, 18) + .padding(.top, 10) - Button { - // action - } label: { - Text("Add Account") - .foregroundColor(.blue100) + HStack(spacing: 0) { + Text("\(presenter.session.namespaces[namespace]?.accounts.first?.namespace ?? "") : \((presenter.session.namespaces[namespace]?.accounts.first?.reference ?? ""))") + .foregroundColor(.cyanBackround) .font(.system(size: 13, weight: .semibold, design: .rounded)) + .padding(.horizontal, 8) + .padding(.vertical, 3) + .background(Color.cyanBackround.opacity(0.2)) + .cornerRadius(10, corners: .allCorners) + + Spacer() } - } - .padding(.horizontal, 18) - .padding(.top, 10) - - VStack { - Text("eip:155:1:0xe5eFf13687819212d25665fdB6946613dA6195a501") - .foregroundColor(.cyanBackround) - .font(.system(size: 13, weight: .semibold, design: .rounded)) - .padding(.horizontal, 8) - .padding(.vertical, 3) - .background(Color.cyanBackround.opacity(0.2)) - .cornerRadius(10, corners: .allCorners) - } - .padding(10) - - } - .background(Color.whiteBackground) - .cornerRadius(20, corners: .allCorners) - .padding(.horizontal, 5) - - VStack(spacing: 0) { - HStack { - Text("Methods") - .foregroundColor(.grey50) - .font(.system(size: 13, weight: .semibold, design: .rounded)) + .padding(10) - Spacer() } - .padding(.horizontal, 18) - .padding(.top, 10) + .background(Color.whiteBackground) + .cornerRadius(20, corners: .allCorners) + .padding(.horizontal, 5) - VStack { - Text("eip:155:1:0xe5eFf13687819212d25665fdB6946613dA6195a501") - .foregroundColor(.cyanBackround) - .font(.system(size: 13, weight: .semibold, design: .rounded)) - .padding(.horizontal, 8) - .padding(.vertical, 3) - .background(Color.cyanBackround.opacity(0.2)) - .cornerRadius(10, corners: .allCorners) - } - .padding(10) - - } - .background(Color.whiteBackground) - .cornerRadius(20, corners: .allCorners) - .padding(.horizontal, 5) - - VStack(spacing: 0) { - HStack { - Text("Events") - .foregroundColor(.grey50) - .font(.system(size: 13, weight: .semibold, design: .rounded)) + VStack(alignment: .leading, spacing: 0) { + HStack { + Text("Methods") + .foregroundColor(.grey50) + .font(.system(size: 13, weight: .semibold, design: .rounded)) + + Spacer() + } + .padding(.horizontal, 18) + .padding(.top, 10) - Spacer() - } - .padding(.horizontal, 18) - .padding(.top, 10) - - VStack { - Text("eip:155:1:0xe5eFf13687819212d25665fdB6946613dA6195a501") - .foregroundColor(.cyanBackround) - .font(.system(size: 13, weight: .regular)) - .padding(.horizontal, 8) - .padding(.vertical, 3) - .background(Color.cyanBackround.opacity(0.2)) - .cornerRadius(10, corners: .allCorners) + TagsView(items: Array(presenter.session.namespaces[namespace]?.methods ?? [])) { + Text($0) + .foregroundColor(.cyanBackround) + .font(.system(size: 13, weight: .semibold, design: .rounded)) + .padding(.horizontal, 8) + .padding(.vertical, 3) + .background(Color.cyanBackround.opacity(0.2)) + .cornerRadius(10, corners: .allCorners) + } + .padding(10) } - .padding(10) - + .background(Color.whiteBackground) + .cornerRadius(20, corners: .allCorners) + .padding(.horizontal, 5) + .padding(.bottom, 5) } - .background(Color.whiteBackground) - .cornerRadius(20, corners: .allCorners) - .padding(.horizontal, 5) - .padding(.bottom, 5) + .background(Color("grey95")) + .cornerRadius(25, corners: .allCorners) } - .background(Color("grey95")) - .cornerRadius(25, corners: .allCorners) + .padding(.horizontal, 20) + .padding(.top, 30) } - .padding(.horizontal, 20) - .padding(.top, 30) Button { - // action + presenter.onDelete() } label: { Text("Delete") .foregroundColor(.lightForegroundNegative) diff --git a/Example/WalletApp/PresentationLayer/Wallet/SessionRequest/Modela/Proposal.swift b/Example/WalletApp/PresentationLayer/Wallet/SessionRequest/Modela/Proposal.swift new file mode 100644 index 000000000..437feb37b --- /dev/null +++ b/Example/WalletApp/PresentationLayer/Wallet/SessionRequest/Modela/Proposal.swift @@ -0,0 +1,58 @@ +import WalletConnectSign + +struct Proposal { + let proposerName: String + let proposerDescription: String + let proposerURL: String + let iconURL: String + let permissions: [Namespace] + + struct Namespace: Hashable { + let chains: [String] + let methods: [String] + let events: [String] + } + + internal init(proposal: Session.Proposal) { + self.proposerName = proposal.proposer.name + self.proposerDescription = proposal.proposer.description + self.proposerURL = proposal.proposer.url + self.iconURL = proposal.proposer.icons.first ?? "https://avatars.githubusercontent.com/u/37784886" + self.permissions = [ + Namespace( + chains: ["eip155:1"], + methods: ["eth_sendTransaction", "personal_sign", "eth_signTypedData"], + events: ["accountsChanged", "chainChanged"] + ) + ] + } + + internal init(proposerName: String, proposerDescription: String, proposerURL: String, iconURL: String, permissions: [Proposal.Namespace]) { + self.proposerName = proposerName + self.proposerDescription = proposerDescription + self.proposerURL = proposerURL + self.iconURL = iconURL + self.permissions = permissions + } + + static func mock() -> Proposal { + Proposal( + proposerName: "Example name", + proposerDescription: "Example description", + proposerURL: "example.url", + iconURL: "https://avatars.githubusercontent.com/u/37784886", + permissions: [ + Namespace( + chains: ["eip155:1"], + methods: ["eth_sendTransaction", "personal_sign", "eth_signTypedData"], + events: ["accountsChanged", "chainChanged"] + ), + Namespace( + chains: ["cosmos:cosmoshub-2"], + methods: ["cosmos_signDirect", "cosmos_signAmino"], + events: [] + ) + ] + ) + } +} diff --git a/Example/WalletApp/PresentationLayer/Wallet/SessionRequest/SessionRequestInteractor.swift b/Example/WalletApp/PresentationLayer/Wallet/SessionRequest/SessionRequestInteractor.swift new file mode 100644 index 000000000..bdc73d3c1 --- /dev/null +++ b/Example/WalletApp/PresentationLayer/Wallet/SessionRequest/SessionRequestInteractor.swift @@ -0,0 +1,37 @@ +import Foundation + +import Web3Wallet + +final class SessionRequestInteractor { + private let signer = MessageSignerFactory(signerFactory: DefaultSignerFactory()).create() + private let account = Account("eip155:1:0xe5EeF1368781911d265fDB6946613dA61915a501")! + + func approve(proposal: Session.Proposal) async throws { + var sessionNamespaces = [String: SessionNamespace]() + proposal.requiredNamespaces.forEach { + let caip2Namespace = $0.key + let proposalNamespace = $0.value + let accounts = Set(proposalNamespace.chains.compactMap { Account($0.absoluteString + ":\(account.namespace)") }) + + let extensions: [SessionNamespace.Extension]? = proposalNamespace.extensions?.map { element in + let accounts = Set(element.chains.compactMap { Account($0.absoluteString + ":\(account.namespace)") }) + return SessionNamespace.Extension(accounts: accounts, methods: element.methods, events: element.events) + } + let sessionNamespace = SessionNamespace(accounts: accounts, methods: proposalNamespace.methods, events: proposalNamespace.events, extensions: extensions) + sessionNamespaces[caip2Namespace] = sessionNamespace + } + + try await Web3Wallet.instance.approve(proposalId: proposal.id, namespaces: sessionNamespaces) + } + + func reject(proposal: Session.Proposal) async throws { + try await Web3Wallet.instance.reject(proposalId: proposal.id, reason: .userRejected) + } + + func formatted(request: AuthRequest) -> String { + return try! Web3Wallet.instance.formatMessage( + payload: request.payload, + address: account.address + ) + } +} diff --git a/Example/WalletApp/PresentationLayer/Wallet/SessionRequest/SessionRequestModule.swift b/Example/WalletApp/PresentationLayer/Wallet/SessionRequest/SessionRequestModule.swift new file mode 100644 index 000000000..d547d6291 --- /dev/null +++ b/Example/WalletApp/PresentationLayer/Wallet/SessionRequest/SessionRequestModule.swift @@ -0,0 +1,22 @@ +import SwiftUI + +import Web3Wallet + +final class SessionRequestModule { + @discardableResult + static func create(app: Application, proposal: Session.Proposal) -> UIViewController { + let router = SessionRequestRouter(app: app) + let interactor = SessionRequestInteractor() + let presenter = SessionRequestPresenter( + interactor: interactor, + router: router, + proposal: proposal + ) + let view = SessionRequestView().environmentObject(presenter) + let viewController = SceneViewController(viewModel: presenter, content: view) + + router.viewController = viewController + + return viewController + } +} diff --git a/Example/WalletApp/PresentationLayer/Wallet/SessionRequest/SessionRequestPresenter.swift b/Example/WalletApp/PresentationLayer/Wallet/SessionRequest/SessionRequestPresenter.swift new file mode 100644 index 000000000..a32d957fc --- /dev/null +++ b/Example/WalletApp/PresentationLayer/Wallet/SessionRequest/SessionRequestPresenter.swift @@ -0,0 +1,50 @@ +import UIKit +import Combine + +import Web3Wallet + +final class SessionRequestPresenter: ObservableObject { + private let interactor: SessionRequestInteractor + private let router: SessionRequestRouter + + let proposal: Proposal + private let sessionProposal: Session.Proposal + + private var disposeBag = Set() + + init( + interactor: SessionRequestInteractor, + router: SessionRequestRouter, + proposal: Session.Proposal + ) { + defer { setupInitialState() } + self.interactor = interactor + self.router = router + self.proposal = Proposal(proposal: proposal) + self.sessionProposal = proposal + } + + @MainActor + func onApprove() async throws { + try await interactor.approve(proposal: sessionProposal) + router.dismiss() + } + + @MainActor + func onReject() async throws { + try await interactor.reject(proposal: sessionProposal) + router.dismiss() + } +} + +// MARK: - Private functions +private extension SessionRequestPresenter { + func setupInitialState() { + + } +} + +// MARK: - SceneViewModel +extension SessionRequestPresenter: SceneViewModel { + +} diff --git a/Example/WalletApp/PresentationLayer/Wallet/SessionRequest/SessionRequestRouter.swift b/Example/WalletApp/PresentationLayer/Wallet/SessionRequest/SessionRequestRouter.swift new file mode 100644 index 000000000..cb7dff530 --- /dev/null +++ b/Example/WalletApp/PresentationLayer/Wallet/SessionRequest/SessionRequestRouter.swift @@ -0,0 +1,15 @@ +import UIKit + +final class SessionRequestRouter { + weak var viewController: UIViewController! + + private let app: Application + + init(app: Application) { + self.app = app + } + + func dismiss() { + viewController.dismiss() + } +} diff --git a/Example/WalletApp/PresentationLayer/Wallet/SessionRequest/SessionRequestView.swift b/Example/WalletApp/PresentationLayer/Wallet/SessionRequest/SessionRequestView.swift new file mode 100644 index 000000000..6af49c1c9 --- /dev/null +++ b/Example/WalletApp/PresentationLayer/Wallet/SessionRequest/SessionRequestView.swift @@ -0,0 +1,175 @@ +import SwiftUI + +struct SessionRequestView: View { + @EnvironmentObject var presenter: SessionRequestPresenter + + @State var text = "" + + var body: some View { + ZStack { + Color.black.opacity(0.6) + + VStack { + Spacer() + + VStack(spacing: 0) { + Image("header") + .resizable() + .scaledToFit() + + Text(presenter.proposal.proposerName) + .foregroundColor(.grey8) + .font(.system(size: 22, weight: .bold, design: .rounded)) + .padding(.top, 10) + + Text("would like to connect") + .foregroundColor(.grey8) + .font(.system(size: 22, weight: .medium, design: .rounded)) + + Text(presenter.proposal.proposerName) + .foregroundColor(.grey50) + .font(.system(size: 13, weight: .semibold, design: .rounded)) + .multilineTextAlignment(.center) + .lineSpacing(4) + .padding(.top, 8) + + sessionProposalView() + + HStack(spacing: 20) { + Button { + Task(priority: .userInitiated) { try await + presenter.onReject() + } + } label: { + Text("Decline") + .frame(maxWidth: .infinity) + .foregroundColor(.white) + .font(.system(size: 20, weight: .semibold, design: .rounded)) + .padding(.vertical, 11) + .background( + LinearGradient( + gradient: Gradient(colors: [ + .foregroundNegative, + .lightForegroundNegative + ]), + startPoint: .top, endPoint: .bottom) + ) + .cornerRadius(20) + } + .shadow(color: .white.opacity(0.25), radius: 8, y: 2) + + Button { + Task(priority: .userInitiated) { try await + presenter.onApprove() + } + } label: { + Text("Allow") + .frame(maxWidth: .infinity) + .foregroundColor(.white) + .font(.system(size: 20, weight: .semibold, design: .rounded)) + .padding(.vertical, 11) + .background( + LinearGradient( + gradient: Gradient(colors: [ + .foregroundPositive, + .lightForegroundPositive + ]), + startPoint: .top, endPoint: .bottom) + ) + .cornerRadius(20) + } + .shadow(color: .white.opacity(0.25), radius: 8, y: 2) + } + .padding(.top, 25) + } + .padding(20) + .background(.ultraThinMaterial) + .cornerRadius(34) + .padding(.horizontal, 10) + + Spacer() + } + } + .edgesIgnoringSafeArea(.all) + } + + private func sessionProposalView() -> some View { + VStack { + VStack(alignment: .leading) { + Text(presenter.proposal.permissions.first?.chains.first ?? "Chain") + .font(.system(size: 15, weight: .semibold, design: .rounded)) + .foregroundColor(.whiteBackground) + .padding(.horizontal, 8) + .padding(.vertical, 5) + .background(Color.grey70) + .cornerRadius(28, corners: .allCorners) + .padding(.leading, 15) + .padding(.top, 9) + + VStack(spacing: 0) { + HStack { + Text("Methods") + .foregroundColor(.grey50) + .font(.system(size: 13, weight: .semibold, design: .rounded)) + + Spacer() + } + .padding(.horizontal, 18) + .padding(.top, 10) + + TagsView(items: presenter.proposal.permissions.first?.methods ?? []) { + Text($0) + .foregroundColor(.cyanBackround) + .font(.system(size: 13, weight: .semibold, design: .rounded)) + .padding(.horizontal, 8) + .padding(.vertical, 3) + .background(Color.cyanBackround.opacity(0.2)) + .cornerRadius(10, corners: .allCorners) + } + .padding(10) + } + .background(Color.whiteBackground) + .cornerRadius(20, corners: .allCorners) + .padding(.horizontal, 5) + + VStack(spacing: 0) { + HStack { + Text("Events") + .foregroundColor(.grey50) + .font(.system(size: 13, weight: .semibold, design: .rounded)) + + Spacer() + } + .padding(.horizontal, 18) + .padding(.top, 10) + + TagsView(items: presenter.proposal.permissions.first?.events ?? []) { + Text($0) + .foregroundColor(.cyanBackround) + .font(.system(size: 13, weight: .semibold, design: .rounded)) + .padding(.horizontal, 8) + .padding(.vertical, 3) + .background(Color.cyanBackround.opacity(0.2)) + .cornerRadius(10, corners: .allCorners) + } + .padding(10) + } + .background(Color.whiteBackground) + .cornerRadius(20, corners: .allCorners) + .padding(.horizontal, 5) + .padding(.bottom, 5) + } + .background(.thinMaterial) + .cornerRadius(25, corners: .allCorners) + } + .padding(.top, 30) + } +} + +#if DEBUG +struct SessionRequestView_Previews: PreviewProvider { + static var previews: some View { + SessionRequestView() + } +} +#endif diff --git a/Example/WalletApp/PresentationLayer/Wallet/Wallet/WalletInteractor.swift b/Example/WalletApp/PresentationLayer/Wallet/Wallet/WalletInteractor.swift index 1b921bf81..e17234aa5 100644 --- a/Example/WalletApp/PresentationLayer/Wallet/Wallet/WalletInteractor.swift +++ b/Example/WalletApp/PresentationLayer/Wallet/Wallet/WalletInteractor.swift @@ -7,6 +7,10 @@ final class WalletInteractor { return Web3Wallet.instance.authRequestPublisher } + var sessionProposalPublisher: AnyPublisher { + return Web3Wallet.instance.sessionProposalPublisher + } + var sessionsPublisher: AnyPublisher<[Session], Never> { return Web3Wallet.instance.sessionsPublisher } diff --git a/Example/WalletApp/PresentationLayer/Wallet/Wallet/WalletPresenter.swift b/Example/WalletApp/PresentationLayer/Wallet/Wallet/WalletPresenter.swift index 5de755589..24a540b3a 100644 --- a/Example/WalletApp/PresentationLayer/Wallet/Wallet/WalletPresenter.swift +++ b/Example/WalletApp/PresentationLayer/Wallet/Wallet/WalletPresenter.swift @@ -63,12 +63,19 @@ extension WalletPresenter { self?.router.present(request: request) } .store(in: &disposeBag) + + interactor.sessionProposalPublisher.sink { [weak self] proposal in + self?.router.present(proposal: proposal) + } + .store(in: &disposeBag) interactor.sessionsPublisher.sink { [weak self] sessions in self?.sessions = sessions } .store(in: &disposeBag) + sessions = interactor.getSessions() + pairFromDapp() } diff --git a/Example/WalletApp/PresentationLayer/Wallet/Wallet/WalletRouter.swift b/Example/WalletApp/PresentationLayer/Wallet/Wallet/WalletRouter.swift index 951661eba..221f328ce 100644 --- a/Example/WalletApp/PresentationLayer/Wallet/Wallet/WalletRouter.swift +++ b/Example/WalletApp/PresentationLayer/Wallet/Wallet/WalletRouter.swift @@ -16,6 +16,11 @@ final class WalletRouter { .presentFullScreen(from: viewController, transparentBackground: true) } + func present(proposal: Session.Proposal) { + SessionRequestModule.create(app: app, proposal: proposal) + .presentFullScreen(from: viewController, transparentBackground: true) + } + func presentPaste(onValue: @escaping (String) -> Void, onError: @escaping (Error) -> Void) { PasteUriModule.create(app: app, onValue: onValue, onError: onError) .presentFullScreen(from: viewController, transparentBackground: true) From e2697df6362d85d4c174e2914805c0af29193321 Mon Sep 17 00:00:00 2001 From: Alexander Lisovik Date: Fri, 6 Jan 2023 17:02:28 +0100 Subject: [PATCH 10/14] PR comments --- Example/ExampleApp.xcodeproj/project.pbxproj | 34 ++----------------- .../SocketFactory/SocketFactory.swift | 9 ----- .../Chat/Welcome/WelcomeInteractor.swift | 3 -- .../Chat/Welcome/WelcomePresenter.swift | 2 +- .../Extensions/UIKit/UIViewController.swift | 3 -- .../Configurator/ThirdPartyConfigurator.swift | 2 +- .../SocketFactory/SocketFactory.swift | 11 ------ .../ConnectionDetailsPresenter.swift | 4 +++ .../ConnectionDetailsView.swift | 2 +- .../Wallet/PasteUri/PasteUriView.swift | 3 +- .../Wallet/Scan/ScanView.swift | 12 ++++--- .../Wallet/Wallet/WalletView.swift | 2 +- 12 files changed, 19 insertions(+), 68 deletions(-) delete mode 100644 Example/Showcase/Classes/DomainLayer/SocketFactory/SocketFactory.swift delete mode 100644 Example/WalletApp/DomainLayer/SocketFactory/SocketFactory.swift diff --git a/Example/ExampleApp.xcodeproj/project.pbxproj b/Example/ExampleApp.xcodeproj/project.pbxproj index e8cce5489..90aa0e0a4 100644 --- a/Example/ExampleApp.xcodeproj/project.pbxproj +++ b/Example/ExampleApp.xcodeproj/project.pbxproj @@ -180,7 +180,6 @@ A5E22D242840C8DB00E36487 /* SafariEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5E22D232840C8DB00E36487 /* SafariEngine.swift */; }; A5E22D2C2840EAC300E36487 /* XCUIElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5E22D2B2840EAC300E36487 /* XCUIElement.swift */; }; C5133A78294125CC00A8314C /* Web3 in Frameworks */ = {isa = PBXBuildFile; productRef = C5133A77294125CC00A8314C /* Web3 */; }; - C53AA435294124BC008EA57C /* SocketFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = C53AA434294124B3008EA57C /* SocketFactory.swift */; }; C53AA4362941251C008EA57C /* DefaultSignerFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59CF4F5292F83D50031A42F /* DefaultSignerFactory.swift */; }; C55D347F295DD7140004314A /* AuthRequestModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D347A295DD7140004314A /* AuthRequestModule.swift */; }; C55D3480295DD7140004314A /* AuthRequestPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D347B295DD7140004314A /* AuthRequestPresenter.swift */; }; @@ -238,8 +237,8 @@ C56EE28D293F5757004840D1 /* AppearanceConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE287293F5757004840D1 /* AppearanceConfigurator.swift */; }; C56EE28E293F5757004840D1 /* ApplicationConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE284293F5757004840D1 /* ApplicationConfigurator.swift */; }; C56EE28F293F5757004840D1 /* MigrationConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE283293F5757004840D1 /* MigrationConfigurator.swift */; }; - C56EE29B293F5773004840D1 /* SocketFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE292293F5773004840D1 /* SocketFactory.swift */; }; C56EE2A3293F6BAF004840D1 /* UIPasteboardWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE2A2293F6BAF004840D1 /* UIPasteboardWrapper.swift */; }; + C5D4603A29687A5700302C7E /* DefaultSocketFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5629AEF2877F73000094373 /* DefaultSocketFactory.swift */; }; C5DD5BE1294E09E3008FD3A4 /* Web3Wallet in Frameworks */ = {isa = PBXBuildFile; productRef = C5DD5BE0294E09E3008FD3A4 /* Web3Wallet */; }; C5F32A2C2954814200A6476E /* ConnectionDetailsModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5F32A2B2954814200A6476E /* ConnectionDetailsModule.swift */; }; C5F32A2E2954814A00A6476E /* ConnectionDetailsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5F32A2D2954814A00A6476E /* ConnectionDetailsRouter.swift */; }; @@ -424,7 +423,6 @@ A5E22D232840C8DB00E36487 /* SafariEngine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariEngine.swift; sourceTree = ""; }; A5E22D2B2840EAC300E36487 /* XCUIElement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCUIElement.swift; sourceTree = ""; }; A5F48A0528E43D3F0034CBFB /* Configuration.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Configuration.xcconfig; path = ../Configuration.xcconfig; sourceTree = ""; }; - C53AA434294124B3008EA57C /* SocketFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocketFactory.swift; sourceTree = ""; }; C55D347A295DD7140004314A /* AuthRequestModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthRequestModule.swift; sourceTree = ""; }; C55D347B295DD7140004314A /* AuthRequestPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthRequestPresenter.swift; sourceTree = ""; }; C55D347C295DD7140004314A /* AuthRequestRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthRequestRouter.swift; sourceTree = ""; }; @@ -478,7 +476,6 @@ C56EE285293F5757004840D1 /* Configurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Configurator.swift; sourceTree = ""; }; C56EE286293F5757004840D1 /* ThirdPartyConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThirdPartyConfigurator.swift; sourceTree = ""; }; C56EE287293F5757004840D1 /* AppearanceConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearanceConfigurator.swift; sourceTree = ""; }; - C56EE292293F5773004840D1 /* SocketFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocketFactory.swift; sourceTree = ""; }; C56EE29F293F5C4F004840D1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; C56EE2A2293F6BAF004840D1 /* UIPasteboardWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIPasteboardWrapper.swift; sourceTree = ""; }; C5F32A2B2954814200A6476E /* ConnectionDetailsModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionDetailsModule.swift; sourceTree = ""; }; @@ -796,7 +793,6 @@ isa = PBXGroup; children = ( A5C20227287EB342007E3188 /* AccountStorage */, - C53AA433294124B3008EA57C /* SocketFactory */, A5629AEB2877F69C00094373 /* Chat */, ); path = DomainLayer; @@ -1234,14 +1230,6 @@ path = Extensions; sourceTree = ""; }; - C53AA433294124B3008EA57C /* SocketFactory */ = { - isa = PBXGroup; - children = ( - C53AA434294124B3008EA57C /* SocketFactory.swift */, - ); - path = SocketFactory; - sourceTree = ""; - }; C55D3471295DC5F60004314A /* PasteUri */ = { isa = PBXGroup; children = ( @@ -1304,7 +1292,6 @@ children = ( C56EE25C293F56D6004840D1 /* Common */, C56EE27E293F5756004840D1 /* ApplicationLayer */, - C56EE290293F5773004840D1 /* DomainLayer */, C56EE29E293F577B004840D1 /* PresentationLayer */, C56EE2A0293F6B10004840D1 /* Other */, ); @@ -1447,22 +1434,6 @@ path = Configurator; sourceTree = ""; }; - C56EE290293F5773004840D1 /* DomainLayer */ = { - isa = PBXGroup; - children = ( - C56EE291293F5773004840D1 /* SocketFactory */, - ); - path = DomainLayer; - sourceTree = ""; - }; - C56EE291293F5773004840D1 /* SocketFactory */ = { - isa = PBXGroup; - children = ( - C56EE292293F5773004840D1 /* SocketFactory.swift */, - ); - path = SocketFactory; - sourceTree = ""; - }; C56EE29E293F577B004840D1 /* PresentationLayer */ = { isa = PBXGroup; children = ( @@ -1890,7 +1861,6 @@ A58E7D1E2872A57B0082D443 /* ThirdPartyConfigurator.swift in Sources */, A5629AD42876CC5700094373 /* InvitePresenter.swift in Sources */, A58E7D3A2872D55F0082D443 /* ChatRouter.swift in Sources */, - C53AA435294124BC008EA57C /* SocketFactory.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1942,6 +1912,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + C5D4603A29687A5700302C7E /* DefaultSocketFactory.swift in Sources */, C53AA4362941251C008EA57C /* DefaultSignerFactory.swift in Sources */, C55D3480295DD7140004314A /* AuthRequestPresenter.swift in Sources */, C5F32A2E2954814A00A6476E /* ConnectionDetailsRouter.swift in Sources */, @@ -2000,7 +1971,6 @@ C56EE24E293F566D004840D1 /* WalletInteractor.swift in Sources */, C55D34AF2965FB750004314A /* SessionRequestPresenter.swift in Sources */, C5F32A302954816100A6476E /* ConnectionDetailsInteractor.swift in Sources */, - C56EE29B293F5773004840D1 /* SocketFactory.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Example/Showcase/Classes/DomainLayer/SocketFactory/SocketFactory.swift b/Example/Showcase/Classes/DomainLayer/SocketFactory/SocketFactory.swift deleted file mode 100644 index 5df81d8da..000000000 --- a/Example/Showcase/Classes/DomainLayer/SocketFactory/SocketFactory.swift +++ /dev/null @@ -1,9 +0,0 @@ -import Foundation -import Starscream -import WalletConnectRelay - -struct SocketFactory: WebSocketFactory { - func create(with url: URL) -> WebSocketConnecting { - return WebSocket(url: url) - } -} diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomeInteractor.swift b/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomeInteractor.swift index 8a9d25a57..548e47f5e 100644 --- a/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomeInteractor.swift +++ b/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomeInteractor.swift @@ -10,8 +10,6 @@ final class WelcomeInteractor { private let chatService: ChatService private let accountStorage: AccountStorage - - var authClient: AuthClient? init(chatService: ChatService, accountStorage: AccountStorage) { self.chatService = chatService @@ -31,7 +29,6 @@ final class WelcomeInteractor { } func generateUri() async -> WalletConnectURI { - authClient = Auth.instance return try! await Pair.instance.create() } } diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomePresenter.swift b/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomePresenter.swift index 12358e009..0ad6296ee 100644 --- a/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomePresenter.swift +++ b/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomePresenter.swift @@ -36,7 +36,7 @@ final class WelcomePresenter: ObservableObject { private func authWithWallet() async { let uri = await interactor.generateUri() - try? await interactor.authClient?.request( + try? await Auth.instance.request( RequestParams( domain: "example.wallet", chainId: "eip155:1", diff --git a/Example/Showcase/Common/Extensions/UIKit/UIViewController.swift b/Example/Showcase/Common/Extensions/UIKit/UIViewController.swift index 89cacb640..e55dbb821 100644 --- a/Example/Showcase/Common/Extensions/UIKit/UIViewController.swift +++ b/Example/Showcase/Common/Extensions/UIKit/UIViewController.swift @@ -1,9 +1,7 @@ import UIKit import SwiftUI -import StoreKit extension UIViewController { - var topController: UIViewController { var topController = self while let presentedViewController = topController.presentedViewController { @@ -44,7 +42,6 @@ extension UIViewController { } extension UIApplication { - static var currentWindow: UIWindow { return UIApplication.shared.connectedScenes .compactMap { $0.delegate as? SceneDelegate } diff --git a/Example/WalletApp/ApplicationLayer/Configurator/ThirdPartyConfigurator.swift b/Example/WalletApp/ApplicationLayer/Configurator/ThirdPartyConfigurator.swift index 4aaf7a286..25279daaa 100644 --- a/Example/WalletApp/ApplicationLayer/Configurator/ThirdPartyConfigurator.swift +++ b/Example/WalletApp/ApplicationLayer/Configurator/ThirdPartyConfigurator.swift @@ -3,7 +3,7 @@ import Web3Wallet struct ThirdPartyConfigurator: Configurator { func configure() { - Networking.configure(projectId: InputConfig.projectId, socketFactory: SocketFactory()) + Networking.configure(projectId: InputConfig.projectId, socketFactory: DefaultSocketFactory()) let metadata = AppMetadata( name: "Example Wallet", diff --git a/Example/WalletApp/DomainLayer/SocketFactory/SocketFactory.swift b/Example/WalletApp/DomainLayer/SocketFactory/SocketFactory.swift deleted file mode 100644 index d22a5ef48..000000000 --- a/Example/WalletApp/DomainLayer/SocketFactory/SocketFactory.swift +++ /dev/null @@ -1,11 +0,0 @@ -import Foundation -import Starscream -import WalletConnectRelay - -extension WebSocket: WebSocketConnecting { } - -struct SocketFactory: WebSocketFactory { - func create(with url: URL) -> WebSocketConnecting { - return WebSocket(url: url) - } -} diff --git a/Example/WalletApp/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsPresenter.swift b/Example/WalletApp/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsPresenter.swift index 0e5f91bc1..335eed580 100644 --- a/Example/WalletApp/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsPresenter.swift +++ b/Example/WalletApp/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsPresenter.swift @@ -34,6 +34,10 @@ final class ConnectionDetailsPresenter: ObservableObject { } } } + + func accountReference(namespace: String) -> String { + "\(session.namespaces[namespace]?.accounts.first?.namespace ?? ""):\((session.namespaces[namespace]?.accounts.first?.reference ?? ""))" + } } // MARK: - Private functions diff --git a/Example/WalletApp/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsView.swift b/Example/WalletApp/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsView.swift index 9ce0b6ef7..ab82d18a3 100644 --- a/Example/WalletApp/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsView.swift +++ b/Example/WalletApp/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsView.swift @@ -60,7 +60,7 @@ struct ConnectionDetailsView: View { .padding(.top, 10) HStack(spacing: 0) { - Text("\(presenter.session.namespaces[namespace]?.accounts.first?.namespace ?? "") : \((presenter.session.namespaces[namespace]?.accounts.first?.reference ?? ""))") + Text(presenter.accountReference(namespace: namespace)) .foregroundColor(.cyanBackround) .font(.system(size: 13, weight: .semibold, design: .rounded)) .padding(.horizontal, 8) diff --git a/Example/WalletApp/PresentationLayer/Wallet/PasteUri/PasteUriView.swift b/Example/WalletApp/PresentationLayer/Wallet/PasteUri/PasteUriView.swift index 9214f1d2f..7f60086e6 100644 --- a/Example/WalletApp/PresentationLayer/Wallet/PasteUri/PasteUriView.swift +++ b/Example/WalletApp/PresentationLayer/Wallet/PasteUri/PasteUriView.swift @@ -23,7 +23,7 @@ struct PasteUriView: View { .foregroundColor(.grey8) .font(.system(size: 22, weight: .bold, design: .rounded)) - Text("To get the URI press the 􀐅 copy to clipboard button in wallet connection interfaces.") + Text("To get the URI press the copy to clipboard button in wallet connection interfaces.") .foregroundColor(.grey50) .font(.system(size: 15, weight: .medium, design: .rounded)) .multilineTextAlignment(.center) @@ -35,7 +35,6 @@ struct PasteUriView: View { HStack { TextField("wc://a13aef...", text: $text) - //.focused($focusedField, equals: .field) .padding(.horizontal, 17) .foregroundColor(.grey50) .font(.system(size: 17, weight: .regular, design: .rounded)) diff --git a/Example/WalletApp/PresentationLayer/Wallet/Scan/ScanView.swift b/Example/WalletApp/PresentationLayer/Wallet/Scan/ScanView.swift index 756698bad..e04d1204a 100644 --- a/Example/WalletApp/PresentationLayer/Wallet/Scan/ScanView.swift +++ b/Example/WalletApp/PresentationLayer/Wallet/Scan/ScanView.swift @@ -5,10 +5,14 @@ struct ScanView: View { var body: some View { ZStack { - // ScanQR(onValue: presenter.onValue, onError: presenter.onError) - // .ignoresSafeArea() - ScanQR(onValue: { _ in }, onError: { _ in }) - .ignoresSafeArea() + ScanQR(onValue: { value in + presenter.onValue(value) + presenter.dismiss() + }, onError: { error in + presenter.onError(error) + presenter.dismiss() + }) + .ignoresSafeArea() VStack { ZStack { diff --git a/Example/WalletApp/PresentationLayer/Wallet/Wallet/WalletView.swift b/Example/WalletApp/PresentationLayer/Wallet/Wallet/WalletView.swift index dcf4d7923..6cd276a1c 100644 --- a/Example/WalletApp/PresentationLayer/Wallet/Wallet/WalletView.swift +++ b/Example/WalletApp/PresentationLayer/Wallet/Wallet/WalletView.swift @@ -15,7 +15,7 @@ struct WalletView: View { VStack(spacing: 10) { Image("connect-template") - Text("Apps you connect with will appear here. To connect 􀎹 scan or 􀐅 paste the code that’s displayed in the app.") + Text("Apps you connect with will appear here. To connect scan or paste the code that’s displayed in the app.") .foregroundColor(.grey50) .font(.system(size: 15, weight: .regular, design: .rounded)) .multilineTextAlignment(.center) From 832baed7faeaddde609b8476c3ea297879f1dcb5 Mon Sep 17 00:00:00 2001 From: Alexander Lisovik Date: Mon, 9 Jan 2023 17:46:51 +0100 Subject: [PATCH 11/14] Update README with Web3Wallet migration guide --- README.md | 206 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 205 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index bf481bd7a..86c374804 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ![CI develop](https://github.com/WalletConnect/WalletConnectSwiftV2/actions/workflows/ci.yml/badge.svg?branch=develop) Swift implementation of WalletConnect v.2 protocol for native iOS applications. -## Requirements +## Requirements - iOS 13 - XCode 13 - Swift 5 @@ -47,6 +47,210 @@ SIMULATOR_IDENTIFIER = YOUR_SIMULATOR_IDENTIFIER ## Example App open `Example/ExampleApp.xcodeproj` +## Migration guide from SignClient and AuthClient to Web3Wallet + +### Instantiate client + +#### Before +```swift +let metadata = AppMetadata(name: String?, + description: String?, + url: String?, + icons: [String]? +) +Pair.configure(metadata: Metadata) +Auth.configure(signerFactory: SignerFactory) +Networking.configure(projectId: InputConfig.projectId, socketFactory: SocketFactory()) +``` + +#### Now + +You need to configure only `Web3Wallet` instance and `Networking` + +```swift +let metadata = AppMetadata(name: String?, + description: String?, + url: String?, + icons: [String]? +) +Networking.configure(projectId: InputConfig.projectId, socketFactory: SocketFactory()) +Web3Wallet.configure(metadata: metadata, signerFactory: DefaultSignerFactory()) +``` + +### Properties and functions wrappers + +#### Before +```swift + SignClient.sessionProposalPublisher.sink { ... } +``` +#### Now +```swift + Web3WalletClient.sessionProposalPublisher.sink { ... } +``` +--- +#### Before +```swift + SignClient.sessionRequestPublisher.sink { ... } +``` +#### Now +```swift + Web3WalletClient.sessionRequestPublisher.sink { ... } +``` +--- +#### Before +```swift + AuthClient.authRequestPublisher.sink { ... } +``` +#### Now +```swift + Web3WalletClient.authRequestPublisher.sink { ... } +``` +--- +#### Before +```swift + SignClient.sessionsPublisher.sink { ... } +``` +#### Now +```swift + Web3WalletClient.sessionsPublisher.sink { ... } +``` +--- +#### Before +```swift + await SignClient.approve(proposalId: proposalId, namespaces: namespaces) +``` +#### Now +```swift + await Web3WalletClient.approve(proposalId: proposalId, namespaces: namespaces) +``` +--- +#### Before +```swift + await SignClient.reject(proposalId: proposalId, reason: reason) // For the wallet to reject a session proposal. +``` +#### Now +```swift + await Web3WalletClient.reject(proposalId: proposalId, reason: reason) // For the wallet to reject a session proposal. +``` +--- +#### Before +```swift + await AuthClient.reject(requestId: requestId) // For wallet to reject authentication request +``` +#### Now +```swift + await Web3WalletClient.reject(requestId: requestId) // For wallet to reject authentication request +``` +--- +#### Before +```swift + await SignClient.update(topic: topic, namespaces: namespaces) +``` +#### Now +```swift + await Web3WalletClient.update(topic: topic, namespaces: namespaces) +``` +--- +#### Before +```swift + await SignClient.extend(topic: topic) +``` +#### Now +```swift + await Web3WalletClient.extend(topic: topic) +``` +--- +#### Before +```swift + await SignClient.respond(topic: topic, requestId: requestId, response: response) +``` +#### Now +```swift + await Web3WalletClient.respond(topic: topic, requestId: requestId, response: response) +``` +--- +#### Before +```swift + await SignClient.emit(topic: topic, event: event, chainId: chainId) +``` +#### Now +```swift + await Web3WalletClient.emit(topic: topic, event: event, chainId: chainId) +``` +--- +#### Before +```swift + await PairingClient.pair(uri: uri) +``` +#### Now +```swift + await Web3WalletClient.pair(uri: uri) +``` +--- +#### Before +```swift + await SignClient.disconnect(topic: topic) +``` +#### Now +```swift + await Web3WalletClient.disconnect(topic: topic) +``` +--- +#### Before +```swift + SignClient.getSessions() +``` +#### Now +```swift + Web3WalletClient.getSessions() +``` +--- +#### Before +```swift + AuthClient.formatMessage(payload: payload, address: address) +``` +#### Now +```swift + Web3WalletClient.formatMessage(payload: payload, address: address) +``` +--- +#### Before +```swift + await AuthClient.respond(requestId: requestId, signature: signature, from: account) +``` +#### Now +```swift + await Web3WalletClient.respond(requestId: requestId, signature: signature, from: account) +``` +--- +#### Before +```swift + SignClient.getPendingRequests(topic: topic) +``` +#### Now +```swift + Web3WalletClient.getPendingRequests(topic: topic) +``` +--- +#### Before +```swift + SignClient.getSessionRequestRecord(id: id) +``` +#### Now +```swift + Web3WalletClient.getSessionRequestRecord(id: id) +``` +--- +#### Before +```swift + AuthClient.getPendingRequests(account: account) +``` +#### Now +```swift + Web3WalletClient.getPendingRequests(account: account) +``` +--- + ## License Apache 2.0 From 51816511015fe0f6c3e653d53ed92259b10c12b9 Mon Sep 17 00:00:00 2001 From: Alexander Lisovik Date: Tue, 10 Jan 2023 12:20:25 +0100 Subject: [PATCH 12/14] Update README --- README.md | 205 +----------------------------------------------------- 1 file changed, 2 insertions(+), 203 deletions(-) diff --git a/README.md b/README.md index 86c374804..086850e0b 100644 --- a/README.md +++ b/README.md @@ -47,209 +47,8 @@ SIMULATOR_IDENTIFIER = YOUR_SIMULATOR_IDENTIFIER ## Example App open `Example/ExampleApp.xcodeproj` -## Migration guide from SignClient and AuthClient to Web3Wallet - -### Instantiate client - -#### Before -```swift -let metadata = AppMetadata(name: String?, - description: String?, - url: String?, - icons: [String]? -) -Pair.configure(metadata: Metadata) -Auth.configure(signerFactory: SignerFactory) -Networking.configure(projectId: InputConfig.projectId, socketFactory: SocketFactory()) -``` - -#### Now - -You need to configure only `Web3Wallet` instance and `Networking` - -```swift -let metadata = AppMetadata(name: String?, - description: String?, - url: String?, - icons: [String]? -) -Networking.configure(projectId: InputConfig.projectId, socketFactory: SocketFactory()) -Web3Wallet.configure(metadata: metadata, signerFactory: DefaultSignerFactory()) -``` - -### Properties and functions wrappers - -#### Before -```swift - SignClient.sessionProposalPublisher.sink { ... } -``` -#### Now -```swift - Web3WalletClient.sessionProposalPublisher.sink { ... } -``` ---- -#### Before -```swift - SignClient.sessionRequestPublisher.sink { ... } -``` -#### Now -```swift - Web3WalletClient.sessionRequestPublisher.sink { ... } -``` ---- -#### Before -```swift - AuthClient.authRequestPublisher.sink { ... } -``` -#### Now -```swift - Web3WalletClient.authRequestPublisher.sink { ... } -``` ---- -#### Before -```swift - SignClient.sessionsPublisher.sink { ... } -``` -#### Now -```swift - Web3WalletClient.sessionsPublisher.sink { ... } -``` ---- -#### Before -```swift - await SignClient.approve(proposalId: proposalId, namespaces: namespaces) -``` -#### Now -```swift - await Web3WalletClient.approve(proposalId: proposalId, namespaces: namespaces) -``` ---- -#### Before -```swift - await SignClient.reject(proposalId: proposalId, reason: reason) // For the wallet to reject a session proposal. -``` -#### Now -```swift - await Web3WalletClient.reject(proposalId: proposalId, reason: reason) // For the wallet to reject a session proposal. -``` ---- -#### Before -```swift - await AuthClient.reject(requestId: requestId) // For wallet to reject authentication request -``` -#### Now -```swift - await Web3WalletClient.reject(requestId: requestId) // For wallet to reject authentication request -``` ---- -#### Before -```swift - await SignClient.update(topic: topic, namespaces: namespaces) -``` -#### Now -```swift - await Web3WalletClient.update(topic: topic, namespaces: namespaces) -``` ---- -#### Before -```swift - await SignClient.extend(topic: topic) -``` -#### Now -```swift - await Web3WalletClient.extend(topic: topic) -``` ---- -#### Before -```swift - await SignClient.respond(topic: topic, requestId: requestId, response: response) -``` -#### Now -```swift - await Web3WalletClient.respond(topic: topic, requestId: requestId, response: response) -``` ---- -#### Before -```swift - await SignClient.emit(topic: topic, event: event, chainId: chainId) -``` -#### Now -```swift - await Web3WalletClient.emit(topic: topic, event: event, chainId: chainId) -``` ---- -#### Before -```swift - await PairingClient.pair(uri: uri) -``` -#### Now -```swift - await Web3WalletClient.pair(uri: uri) -``` ---- -#### Before -```swift - await SignClient.disconnect(topic: topic) -``` -#### Now -```swift - await Web3WalletClient.disconnect(topic: topic) -``` ---- -#### Before -```swift - SignClient.getSessions() -``` -#### Now -```swift - Web3WalletClient.getSessions() -``` ---- -#### Before -```swift - AuthClient.formatMessage(payload: payload, address: address) -``` -#### Now -```swift - Web3WalletClient.formatMessage(payload: payload, address: address) -``` ---- -#### Before -```swift - await AuthClient.respond(requestId: requestId, signature: signature, from: account) -``` -#### Now -```swift - await Web3WalletClient.respond(requestId: requestId, signature: signature, from: account) -``` ---- -#### Before -```swift - SignClient.getPendingRequests(topic: topic) -``` -#### Now -```swift - Web3WalletClient.getPendingRequests(topic: topic) -``` ---- -#### Before -```swift - SignClient.getSessionRequestRecord(id: id) -``` -#### Now -```swift - Web3WalletClient.getSessionRequestRecord(id: id) -``` ---- -#### Before -```swift - AuthClient.getPendingRequests(account: account) -``` -#### Now -```swift - Web3WalletClient.getPendingRequests(account: account) -``` ---- +## Web3Wallet +Web3Wallet SDK introduces a new interface for all wallets that wraps the Sign and Auth clients internally. Migration guide is available [here](https://github.com/WalletConnect/walletconnect-docs/blob/main/docs/swift/guides/web3wallet-migration.md) ## License From 11ed15b00335b19327a09826780dab847b89e44d Mon Sep 17 00:00:00 2001 From: Artur Guseinov Date: Tue, 10 Jan 2023 16:31:16 +0500 Subject: [PATCH 13/14] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 086850e0b..d7724421b 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ Swift implementation of WalletConnect v.2 protocol for native iOS applications. - [Beginner guide to WalletConnect v2.0 for iOS Developers](https://medium.com/walletconnect/beginner-guide-to-walletconnect-v2-0-for-swift-developers-4534b0975218) - [Protocol Documentation](https://github.com/WalletConnect/walletconnect-specs) - [Glossary](https://docs.walletconnect.com/2.0/introduction/glossary) +- [Migration guide from Sign and Auth to Web3Wallet](https://github.com/WalletConnect/walletconnect-docs/blob/main/docs/swift/guides/web3wallet-migration.md) ## Installation @@ -48,7 +49,8 @@ SIMULATOR_IDENTIFIER = YOUR_SIMULATOR_IDENTIFIER open `Example/ExampleApp.xcodeproj` ## Web3Wallet -Web3Wallet SDK introduces a new interface for all wallets that wraps the Sign and Auth clients internally. Migration guide is available [here](https://github.com/WalletConnect/walletconnect-docs/blob/main/docs/swift/guides/web3wallet-migration.md) +Web3Wallet SDK introduces a new interface for all wallets that wraps the Sign and Auth clients internally. +- [Migration guide from Sign and Auth to Web3Wallet](https://github.com/WalletConnect/walletconnect-docs/blob/main/docs/swift/guides/web3wallet-migration.md) ## License From c7cc625fe301883dd5732768468372f745fc0781 Mon Sep 17 00:00:00 2001 From: flypaper0 Date: Tue, 10 Jan 2023 11:54:08 +0000 Subject: [PATCH 14/14] Set User Agent --- Sources/WalletConnectRelay/PackageConfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/WalletConnectRelay/PackageConfig.json b/Sources/WalletConnectRelay/PackageConfig.json index 18631a482..5d6fcfcfb 100644 --- a/Sources/WalletConnectRelay/PackageConfig.json +++ b/Sources/WalletConnectRelay/PackageConfig.json @@ -1 +1 @@ -{"version": "1.2.0"} +{"version": "1.2.1"}