Skip to content

Commit 2c7fe59

Browse files
feat: Add Privy-based login screens (Main, Other Socials, Wallet Selection)
Co-Authored-By: DAR <shoei0205@gmail.com>
1 parent 56ab2df commit 2c7fe59

9 files changed

Lines changed: 762 additions & 9 deletions

File tree

.github/workflows/build-and-test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ jobs:
6262
options:
6363
bundleIdPrefix: com.pocket
6464
deploymentTarget:
65-
iOS: "16.0"
65+
iOS: "17.0"
6666
targets:
6767
PocketApp:
6868
type: application

Package.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,23 @@ import PackageDescription
44
let package = Package(
55
name: "Pocket",
66
platforms: [
7-
.iOS(.v16)
7+
.iOS(.v17)
88
],
99
products: [
1010
.library(
1111
name: "Pocket",
1212
targets: ["Pocket"]
1313
),
1414
],
15+
dependencies: [
16+
.package(url: "https://github.com/privy-io/privy-ios", from: "1.0.0"),
17+
],
1518
targets: [
1619
.target(
1720
name: "Pocket",
21+
dependencies: [
22+
.product(name: "PrivySDK", package: "privy-ios"),
23+
],
1824
path: "Pocket/Sources"
1925
),
2026
]

Pocket/Sources/Extensions/Color+Theme.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,11 @@ extension Color {
2020
static let pocketPrimaryText = Color.white
2121
static let pocketSecondaryText = Color(red: 0.55, green: 0.55, blue: 0.60)
2222
static let pocketTertiaryText = Color(red: 0.40, green: 0.40, blue: 0.45)
23+
24+
// MARK: - Login Sheet Colors
25+
static let loginSheetBackground = Color(red: 0.10, green: 0.10, blue: 0.12)
26+
static let loginButtonBackground = Color(red: 0.18, green: 0.18, blue: 0.20)
27+
static let loginButtonBorder = Color(red: 0.25, green: 0.25, blue: 0.28)
28+
static let loginButtonHighlight = Color(red: 0.20, green: 0.20, blue: 0.23)
29+
static let loginIconBackground = Color(red: 0.22, green: 0.22, blue: 0.25)
2330
}

Pocket/Sources/PocketApp.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ import SwiftUI
22

33
@main
44
struct PocketApp: App {
5+
@StateObject private var authViewModel = AuthViewModel()
6+
57
var body: some Scene {
68
WindowGroup {
7-
WelcomeView()
9+
WelcomeView(authViewModel: authViewModel)
810
.preferredColorScheme(.dark)
911
}
1012
}
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
import SwiftUI
2+
import Combine
3+
4+
// MARK: - Login Sheet Page
5+
enum LoginSheetPage {
6+
case main
7+
case otherSocials
8+
case walletSelection
9+
}
10+
11+
// MARK: - Auth State
12+
enum AuthState {
13+
case unauthenticated
14+
case authenticating
15+
case authenticated
16+
}
17+
18+
// MARK: - Wallet Option
19+
struct WalletOption: Identifiable {
20+
let id = UUID()
21+
let name: String
22+
let iconName: String
23+
let chains: [ChainType]
24+
25+
enum ChainType {
26+
case ethereum
27+
case solana
28+
case multichain
29+
}
30+
}
31+
32+
class AuthViewModel: ObservableObject {
33+
// MARK: - Published Properties
34+
@Published var showLoginSheet = false
35+
@Published var currentPage: LoginSheetPage = .main
36+
@Published var authState: AuthState = .unauthenticated
37+
@Published var emailInput: String = ""
38+
@Published var isEmailValid: Bool = false
39+
@Published var isLoading: Bool = false
40+
@Published var errorMessage: String?
41+
42+
// MARK: - Wallet Options
43+
let walletOptions: [WalletOption] = [
44+
WalletOption(name: "MetaMask", iconName: "metamask", chains: [.ethereum]),
45+
WalletOption(name: "Coinbase Wallet", iconName: "coinbase", chains: [.ethereum]),
46+
WalletOption(name: "Rainbow", iconName: "rainbow", chains: [.ethereum]),
47+
WalletOption(name: "Base", iconName: "base", chains: [.ethereum]),
48+
WalletOption(name: "1inch Wallet", iconName: "1inch", chains: [.ethereum, .solana])
49+
]
50+
51+
// MARK: - Privy Configuration
52+
// Configure via environment or Secrets.xcconfig
53+
private let privyAppId: String = {
54+
// Load from Info.plist or environment
55+
Bundle.main.object(forInfoDictionaryKey: "PRIVY_APP_ID") as? String ?? ""
56+
}()
57+
58+
// MARK: - Actions
59+
func showLogin() {
60+
currentPage = .main
61+
showLoginSheet = true
62+
}
63+
64+
func dismissLogin() {
65+
showLoginSheet = false
66+
currentPage = .main
67+
emailInput = ""
68+
errorMessage = nil
69+
}
70+
71+
func navigateToOtherSocials() {
72+
withAnimation(.easeInOut(duration: 0.3)) {
73+
currentPage = .otherSocials
74+
}
75+
}
76+
77+
func navigateToWalletSelection() {
78+
withAnimation(.easeInOut(duration: 0.3)) {
79+
currentPage = .walletSelection
80+
}
81+
}
82+
83+
func navigateBack() {
84+
withAnimation(.easeInOut(duration: 0.3)) {
85+
currentPage = .main
86+
}
87+
}
88+
89+
func validateEmail() {
90+
let pattern = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}"
91+
let predicate = NSPredicate(format: "SELF MATCHES %@", pattern)
92+
isEmailValid = predicate.evaluate(with: emailInput)
93+
}
94+
95+
// MARK: - Auth Methods (Privy SDK integration points)
96+
97+
func loginWithMetaMask() {
98+
isLoading = true
99+
// TODO: Integrate with Privy SDK
100+
// privy.externalWallet.connect(provider: .metamask)
101+
DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in
102+
self?.isLoading = false
103+
}
104+
}
105+
106+
func loginWithEmail() {
107+
guard isEmailValid else { return }
108+
isLoading = true
109+
// TODO: Integrate with Privy SDK
110+
// try await privy.email.sendCode(to: emailInput)
111+
DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in
112+
self?.isLoading = false
113+
}
114+
}
115+
116+
func loginWithGoogle() {
117+
isLoading = true
118+
// TODO: Integrate with Privy SDK
119+
// try await privy.google.login()
120+
DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in
121+
self?.isLoading = false
122+
}
123+
}
124+
125+
func loginWithTwitter() {
126+
isLoading = true
127+
// TODO: Integrate with Privy SDK
128+
// try await privy.twitter.login()
129+
DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in
130+
self?.isLoading = false
131+
}
132+
}
133+
134+
func loginWithDiscord() {
135+
isLoading = true
136+
// TODO: Integrate with Privy SDK
137+
// try await privy.discord.login()
138+
DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in
139+
self?.isLoading = false
140+
}
141+
}
142+
143+
func loginWithTelegram() {
144+
isLoading = true
145+
// TODO: Integrate with Privy SDK
146+
// try await privy.telegram.login()
147+
DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in
148+
self?.isLoading = false
149+
}
150+
}
151+
152+
func connectWallet(_ wallet: WalletOption) {
153+
isLoading = true
154+
// TODO: Integrate with Privy SDK
155+
// privy.externalWallet.connect(provider: wallet)
156+
DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in
157+
self?.isLoading = false
158+
}
159+
}
160+
}

0 commit comments

Comments
 (0)