@leejungkiin/awkit 1.0.5 β 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/VERSION +1 -1
- package/package.json +2 -2
- package/skills/smali-to-kotlin/SKILL.md +85 -331
- package/skills/smali-to-kotlin/phase-0-discovery.md +129 -0
- package/skills/smali-to-kotlin/phase-1-architecture.md +157 -0
- package/skills/smali-to-kotlin/phase-2-blueprint-ui.md +347 -0
- package/skills/smali-to-kotlin/phase-3-logic-build.md +268 -0
- package/skills/smali-to-swift/SKILL.md +91 -532
- package/skills/smali-to-swift/phase-0-discovery.md +154 -0
- package/skills/smali-to-swift/phase-1-architecture.md +173 -0
- package/skills/smali-to-swift/phase-2-blueprint-ui.md +348 -0
- package/skills/smali-to-swift/phase-3-logic-build.md +312 -0
- package/workflows/mobile/reverse-android-build.md +119 -79
- package/workflows/mobile/reverse-android-design.md +10 -7
- package/workflows/mobile/reverse-android.md +52 -46
- package/workflows/mobile/reverse-ios-build.md +161 -50
- package/workflows/mobile/reverse-ios-design.md +10 -1
- package/workflows/mobile/reverse-ios.md +49 -37
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# π Phase 0: Discovery (Satellite View) β iOS
|
|
2
|
+
|
|
3
|
+
> **Zoom Level:** 0 β ToΓ n cαΊ£nh
|
|
4
|
+
> **Goal:** Understand the app: structure, frameworks, components, screen flow.
|
|
5
|
+
> **Output:** App Map document.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## β OUTPUT RULE
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
β
ALLOWED: Diagrams, tables, lists, reports
|
|
13
|
+
β
ALLOWED: Shell commands for scanning
|
|
14
|
+
β BLOCKED: Any Swift code
|
|
15
|
+
β BLOCKED: Any implementation decisions (those come in Phase 1)
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## π Sub-steps
|
|
21
|
+
|
|
22
|
+
### 0.1: Scan IPA Structure
|
|
23
|
+
|
|
24
|
+
Verify decrypted IPA output:
|
|
25
|
+
```
|
|
26
|
+
Payload/App.app/
|
|
27
|
+
βββ App # Mach-O binary
|
|
28
|
+
βββ Info.plist # App metadata
|
|
29
|
+
βββ Frameworks/ # Embedded frameworks
|
|
30
|
+
β βββ SomeSDK.framework/
|
|
31
|
+
β βββ libswiftCore.dylib
|
|
32
|
+
βββ Assets.car # Compiled asset catalog
|
|
33
|
+
βββ Base.lproj/ # Storyboards / XIBs (compiled)
|
|
34
|
+
βββ *.momd # Core Data models
|
|
35
|
+
βββ [other resources]
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### 0.2: Framework Scanner
|
|
39
|
+
|
|
40
|
+
Scan ALL dependencies before any coding:
|
|
41
|
+
|
|
42
|
+
1. **Scan `Frameworks/` directory:**
|
|
43
|
+
```
|
|
44
|
+
Frameworks/Alamofire.framework β Alamofire (network)
|
|
45
|
+
Frameworks/SDWebImage.framework β SDWebImage (image)
|
|
46
|
+
Frameworks/Realm.framework β Realm (database)
|
|
47
|
+
Frameworks/FBSDKCoreKit.framework β Facebook SDK
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
2. **Scan class-dump headers for imports:**
|
|
51
|
+
```
|
|
52
|
+
#import <AFNetworking/...> β AFNetworking
|
|
53
|
+
#import <Masonry/...> β Masonry (auto-layout)
|
|
54
|
+
@import Firebase; β Firebase SDK
|
|
55
|
+
@import GoogleMobileAds; β AdMob
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
3. **Check Mach-O linked frameworks:**
|
|
59
|
+
```bash
|
|
60
|
+
otool -L Payload/App.app/App | grep -v /System | grep -v /usr/lib
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
4. **Check embedded dylibs:**
|
|
64
|
+
```bash
|
|
65
|
+
find Payload/App.app -name "*.dylib" -o -name "*.framework" | sort
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
5. **Check for CocoaPods / SPM markers:**
|
|
69
|
+
```
|
|
70
|
+
Pods/ directory β was using CocoaPods
|
|
71
|
+
.package.resolved β was using SPM
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
See `framework-patterns.md` for comprehensive detection patterns.
|
|
75
|
+
|
|
76
|
+
### 0.3: Info.plist & Entitlements Analysis
|
|
77
|
+
|
|
78
|
+
Extract from `Info.plist`:
|
|
79
|
+
|
|
80
|
+
1. Bundle ID (`CFBundleIdentifier`)
|
|
81
|
+
2. Display Name
|
|
82
|
+
3. Min Deployment Target
|
|
83
|
+
4. Permissions (Privacy keys):
|
|
84
|
+
```
|
|
85
|
+
NSCameraUsageDescription β Camera
|
|
86
|
+
NSPhotoLibraryUsageDescription β Photo Library
|
|
87
|
+
NSLocationWhenInUseUsageDescription β Location
|
|
88
|
+
NSMicrophoneUsageDescription β Microphone
|
|
89
|
+
```
|
|
90
|
+
5. URL Schemes (deep links)
|
|
91
|
+
6. Capabilities from entitlements:
|
|
92
|
+
```
|
|
93
|
+
com.apple.developer.associated-domains β Universal Links
|
|
94
|
+
aps-environment β Push Notifications
|
|
95
|
+
com.apple.developer.in-app-payments β Apple Pay
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### 0.4: Class Structure Analysis
|
|
99
|
+
|
|
100
|
+
From class-dump headers:
|
|
101
|
+
|
|
102
|
+
1. **Entry points:** AppDelegate, SceneDelegate
|
|
103
|
+
2. **Root ViewController:** Tab bar? Navigation?
|
|
104
|
+
3. **Major ViewControllers** β future SwiftUI screens
|
|
105
|
+
4. **Model classes** β domain models
|
|
106
|
+
5. **Network managers** β API client
|
|
107
|
+
6. **Singleton/manager classes** β services to extract
|
|
108
|
+
|
|
109
|
+
### 0.5: Screen Flow Map
|
|
110
|
+
|
|
111
|
+
```mermaid
|
|
112
|
+
graph LR
|
|
113
|
+
Launch --> Login
|
|
114
|
+
Login --> MainTab
|
|
115
|
+
MainTab --> Home
|
|
116
|
+
MainTab --> Search
|
|
117
|
+
MainTab --> Profile
|
|
118
|
+
Home --> Detail
|
|
119
|
+
Profile --> Settings
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### 0.6: Complexity Estimate
|
|
123
|
+
|
|
124
|
+
| Area | Rating | Notes |
|
|
125
|
+
|------|--------|-------|
|
|
126
|
+
| Data Layer | βββββ | [N] APIs, [N] Core Data entities |
|
|
127
|
+
| Core Logic | βββββ | [N] crypto utils, [N] formatters |
|
|
128
|
+
| UI Screens | βββββ | [N] screens, [N] complex views |
|
|
129
|
+
| SDK Integration | βββββ | [N] third-party, [N] native dylibs |
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## π Output: App Map
|
|
134
|
+
|
|
135
|
+
Document all findings in structured format (adapt from Android `templates/app-map.md`).
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## β
Gate
|
|
140
|
+
|
|
141
|
+
```
|
|
142
|
+
"πΊοΈ App Map xong. Anh review:
|
|
143
|
+
- [N] screens detected
|
|
144
|
+
- [N] frameworks found ([N] reuse, [N] replace)
|
|
145
|
+
- [N] native dylibs
|
|
146
|
+
- Complexity: [Low/Medium/High]
|
|
147
|
+
|
|
148
|
+
CΓ³ gΓ¬ cαΊ§n Δiα»u chα»nh khΓ΄ng?
|
|
149
|
+
β OK β Phase 1 (Architecture Design)"
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
*Phase 0: Discovery β Know your target before you build*
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# ποΈ Phase 1: Architecture (District View) β iOS
|
|
2
|
+
|
|
3
|
+
> **Zoom Level:** 1 β Architecture Design
|
|
4
|
+
> **Goal:** Design overall architecture with UI-First build order. NO code bodies.
|
|
5
|
+
> **Input:** Completed App Map from Phase 0.
|
|
6
|
+
> **Output:** Architecture Blueprint document.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## β OUTPUT RULE
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
β
ALLOWED: Architecture diagrams, layer maps, feature-to-file mapping, API endpoint tables
|
|
14
|
+
β
ALLOWED: File paths, module names, dependency lists
|
|
15
|
+
β οΈ ALLOWED: Package.swift skeleton (dependencies only)
|
|
16
|
+
β BLOCKED: Function bodies, implementation details, actual Swift code
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## π Sub-steps
|
|
22
|
+
|
|
23
|
+
### 1.1: Layer Design
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
βββββββββββββββββββββββββββββββββββββββ
|
|
27
|
+
β Presentation β
|
|
28
|
+
β βββ Screens/ ([N] screens) β
|
|
29
|
+
β βββ Navigation/ (NavigationStack) β
|
|
30
|
+
β βββ Theme/ (Design system) β
|
|
31
|
+
β βββ Components/ (Shared views) β
|
|
32
|
+
βββββββββββββββββββββββββββββββββββββββ€
|
|
33
|
+
β Domain β
|
|
34
|
+
β βββ Models/ ([N] business models) β
|
|
35
|
+
β βββ Repositories/ ([N] protocols) β
|
|
36
|
+
β βββ UseCases/ ([N] use cases) β
|
|
37
|
+
βββββββββββββββββββββββββββββββββββββββ€
|
|
38
|
+
β Data β
|
|
39
|
+
β βββ Network/ ([N] API endpoints) β
|
|
40
|
+
β βββ Local/ (SwiftData, Keychain) β
|
|
41
|
+
β βββ Repositories/ (implementations) β
|
|
42
|
+
βββββββββββββββββββββββββββββββββββββββ€
|
|
43
|
+
β DI / Utilities β
|
|
44
|
+
β βββ Container, extensions, crypto β
|
|
45
|
+
βββββββββββββββββββββββββββββββββββββββ
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 1.2: Feature β File Mapping
|
|
49
|
+
|
|
50
|
+
| Feature | Domain Model | Repository Protocol | UseCase | Screen | ViewModel |
|
|
51
|
+
|---------|-------------|-------------------|---------|--------|-----------|
|
|
52
|
+
| Auth | User, Token | AuthRepository | LoginUC | LoginScreen | AuthVM |
|
|
53
|
+
| Home | Feed | HomeRepository | GetFeedUC | HomeScreen | HomeVM |
|
|
54
|
+
| ... | ... | ... | ... | ... | ... |
|
|
55
|
+
|
|
56
|
+
### 1.3: API Endpoint Inventory
|
|
57
|
+
|
|
58
|
+
| # | Method | Endpoint | Auth | Request | Response | Notes |
|
|
59
|
+
|---|--------|----------|------|---------|----------|-------|
|
|
60
|
+
| 1 | POST | /auth/login | No | email, pwd | JWT | - |
|
|
61
|
+
| 2 | GET | /users/me | Bearer | - | User | - |
|
|
62
|
+
|
|
63
|
+
**How to find in headers/disassembly:**
|
|
64
|
+
```objc
|
|
65
|
+
// class-dump output
|
|
66
|
+
- (void)requestWithURL:(NSURL *)url completion:(void (^)(id, NSError *))completion;
|
|
67
|
+
// Look for string constants with "https://" or "api/"
|
|
68
|
+
// Hopper: search for NSURLSession, dataTaskWithRequest
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### 1.4: Data Schema Inventory
|
|
72
|
+
|
|
73
|
+
| Model | Key Fields | Source | Storage |
|
|
74
|
+
|-------|-----------|--------|---------|
|
|
75
|
+
| User | id, name, email, avatar | API | SwiftData + Memory |
|
|
76
|
+
| Settings | theme, language | Local | UserDefaults |
|
|
77
|
+
|
|
78
|
+
### 1.5: Project Structure
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
App/
|
|
82
|
+
βββ App.swift # @main entry point
|
|
83
|
+
βββ AppDelegate.swift # UIKit lifecycle (for SDK init)
|
|
84
|
+
βββ Info.plist
|
|
85
|
+
βββ Assets.xcassets/
|
|
86
|
+
βββ DI/
|
|
87
|
+
β βββ AppContainer.swift
|
|
88
|
+
βββ Data/
|
|
89
|
+
β βββ Network/
|
|
90
|
+
β β βββ APIClient.swift
|
|
91
|
+
β β βββ Endpoints/
|
|
92
|
+
β β βββ DTOs/
|
|
93
|
+
β βββ Local/
|
|
94
|
+
β β βββ SwiftDataModels/
|
|
95
|
+
β β βββ KeychainService.swift
|
|
96
|
+
β β βββ UserDefaultsKeys.swift
|
|
97
|
+
β βββ Repositories/
|
|
98
|
+
βββ Domain/
|
|
99
|
+
β βββ Models/
|
|
100
|
+
β βββ Repositories/ # Protocols
|
|
101
|
+
β βββ UseCases/
|
|
102
|
+
βββ Presentation/
|
|
103
|
+
β βββ Navigation/
|
|
104
|
+
β βββ Theme/
|
|
105
|
+
β βββ Components/
|
|
106
|
+
β βββ Screens/
|
|
107
|
+
β βββ Launch/
|
|
108
|
+
β βββ Auth/
|
|
109
|
+
β βββ Home/
|
|
110
|
+
β βββ [feature]/
|
|
111
|
+
βββ Utilities/
|
|
112
|
+
β βββ Extensions/
|
|
113
|
+
β βββ Crypto/
|
|
114
|
+
β βββ Helpers/
|
|
115
|
+
βββ Resources/
|
|
116
|
+
βββ Localizable.xcstrings
|
|
117
|
+
βββ Fonts/
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### 1.6: Build Order (UI-First) β
|
|
121
|
+
|
|
122
|
+
> **IMPORTANT:** UI-First build order β design and approve UI before coding logic.
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
Foundation (one-time):
|
|
126
|
+
1. π’ Xcode project setup + Theme/Design System
|
|
127
|
+
2. π’ Navigation structure (NavigationStack, TabView)
|
|
128
|
+
3. π’ DI Container skeleton
|
|
129
|
+
|
|
130
|
+
Per Feature (repeat for each):
|
|
131
|
+
4. π Blueprint: Contracts (models, protocols, use cases, state)
|
|
132
|
+
5. π¨ UI Shell: Visual implementation + Resource extraction
|
|
133
|
+
6. π¦ GATE: User approve UI
|
|
134
|
+
7. π¨ Logic: Domain β Data β ViewModel β Wire UI
|
|
135
|
+
8. π§ͺ Test: Integration + Parity
|
|
136
|
+
|
|
137
|
+
Final (one-time):
|
|
138
|
+
9. π¦ SDK Integration + Native libs
|
|
139
|
+
10. β
Full Parity Check
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### 1.7: Tech Stack Decisions
|
|
143
|
+
|
|
144
|
+
| Decision | Choice | Rationale |
|
|
145
|
+
|----------|--------|-----------|
|
|
146
|
+
| Image Loading | Kingfisher | Mature, async, cache |
|
|
147
|
+
| State Management | @Observable | iOS 17+ native |
|
|
148
|
+
| Package Manager | SPM | Apple-native, modern |
|
|
149
|
+
| ... | ... | ... |
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## π Output: Architecture Blueprint
|
|
154
|
+
|
|
155
|
+
Structured document with all sections above.
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## β
Gate
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
"ποΈ Architecture Blueprint xong.
|
|
163
|
+
Build order: UI-First per feature.
|
|
164
|
+
Anh muα»n bαΊ―t ΔαΊ§u tα»« feature nΓ o?
|
|
165
|
+
Em suggest: [Feature X] vì [reason]."
|
|
166
|
+
|
|
167
|
+
β User picks feature β Phase 2 (Blueprint + UI Design)
|
|
168
|
+
β User wants changes β Adjust architecture
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
*Phase 1: Architecture β Design before you build, UI before logic*
|
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
# π Phase 2: Blueprint + UI Design (Per Feature) β iOS
|
|
2
|
+
|
|
3
|
+
> **Zoom Level:** 2 β Feature Detail
|
|
4
|
+
> **Goal:** Design contracts AND code UI visual shell for ONE feature.
|
|
5
|
+
> **Input:** Architecture Blueprint (Phase 1) + user's chosen feature.
|
|
6
|
+
> **Output:** Approved contracts + Working SwiftUI shell with mock data.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## β OUTPUT RULE
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
PART A β Contracts (signatures only):
|
|
14
|
+
β
Protocol definitions, struct/enum types
|
|
15
|
+
β
APIClient endpoint definitions (signature only, no body)
|
|
16
|
+
β
ViewState struct, ViewAction enum
|
|
17
|
+
β Function body implementations (use fatalError("TODO"))
|
|
18
|
+
|
|
19
|
+
PART B β UI (visual code):
|
|
20
|
+
β
Full SwiftUI code for screen
|
|
21
|
+
β
Hardcoded mock data (using ViewState from Part A)
|
|
22
|
+
β
Real resources (icons, colors, images extracted in 2.7)
|
|
23
|
+
β
#Preview for ALL states (normal, loading, error, empty)
|
|
24
|
+
β Real ViewModel connection β use parameter defaults
|
|
25
|
+
β Real API calls
|
|
26
|
+
β Business logic
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## π Sub-steps
|
|
32
|
+
|
|
33
|
+
### 2.1: Deep Source Reading
|
|
34
|
+
|
|
35
|
+
Read class-dump headers + Hopper pseudo-code for the chosen feature.
|
|
36
|
+
|
|
37
|
+
**What to extract:**
|
|
38
|
+
- Class hierarchy (@interface, @protocol)
|
|
39
|
+
- Property declarations β model fields
|
|
40
|
+
- Method signatures β API contracts
|
|
41
|
+
- String constants β URLs, keys
|
|
42
|
+
- Delegate/callback patterns β async contract signatures
|
|
43
|
+
|
|
44
|
+
**ObjC Header Quick Ref:**
|
|
45
|
+
```objc
|
|
46
|
+
@interface ClassName : SuperClass <Protocol1, Protocol2>
|
|
47
|
+
@property (nonatomic, copy) NSString *name; // β let name: String
|
|
48
|
+
@property (nonatomic, strong) NSArray *items; // β let items: [Item]
|
|
49
|
+
@property (nonatomic, assign) BOOL isActive; // β let isActive: Bool
|
|
50
|
+
@property (nullable, nonatomic, copy) NSString *bio; // β let bio: String?
|
|
51
|
+
- (void)fetchDataWithCompletion:(void (^)(id, NSError *))completion;
|
|
52
|
+
// β func fetchData() async throws -> Data
|
|
53
|
+
@end
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
See `objc-reading-guide.md` for comprehensive guide.
|
|
57
|
+
|
|
58
|
+
### 2.2: Domain Model Contracts
|
|
59
|
+
|
|
60
|
+
```swift
|
|
61
|
+
// Domain model
|
|
62
|
+
struct User: Identifiable, Sendable {
|
|
63
|
+
let id: String
|
|
64
|
+
let fullName: String
|
|
65
|
+
let email: String
|
|
66
|
+
let avatarURL: URL?
|
|
67
|
+
let isVerified: Bool
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// DTO (from API)
|
|
71
|
+
struct UserDTO: Codable {
|
|
72
|
+
let userId: String
|
|
73
|
+
let fullName: String
|
|
74
|
+
let email: String
|
|
75
|
+
let avatarUrl: String?
|
|
76
|
+
let isVerified: Bool
|
|
77
|
+
|
|
78
|
+
enum CodingKeys: String, CodingKey {
|
|
79
|
+
case userId = "user_id"
|
|
80
|
+
case fullName = "full_name"
|
|
81
|
+
case email
|
|
82
|
+
case avatarUrl = "avatar_url"
|
|
83
|
+
case isVerified = "is_verified"
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
func toDomain() -> User {
|
|
87
|
+
User(id: userId, fullName: fullName, email: email,
|
|
88
|
+
avatarURL: avatarUrl.flatMap(URL.init), isVerified: isVerified)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### 2.3: Repository Contract
|
|
94
|
+
|
|
95
|
+
```swift
|
|
96
|
+
protocol AuthRepository: Sendable {
|
|
97
|
+
func login(email: String, password: String) async throws -> User
|
|
98
|
+
func register(name: String, email: String, password: String) async throws -> User
|
|
99
|
+
func logout() async
|
|
100
|
+
func isLoggedIn() -> Bool
|
|
101
|
+
func currentUser() async -> User?
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### 2.4: API Contract
|
|
106
|
+
|
|
107
|
+
```swift
|
|
108
|
+
enum AuthEndpoint {
|
|
109
|
+
case login(email: String, password: String)
|
|
110
|
+
case register(name: String, email: String, password: String)
|
|
111
|
+
case currentUser
|
|
112
|
+
|
|
113
|
+
var path: String { /* ... */ }
|
|
114
|
+
var method: HTTPMethod { /* ... */ }
|
|
115
|
+
// Signature only, no URLRequest body yet
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### 2.5: UseCase Signatures
|
|
120
|
+
|
|
121
|
+
```swift
|
|
122
|
+
struct LoginUseCase {
|
|
123
|
+
private let authRepo: AuthRepository
|
|
124
|
+
|
|
125
|
+
func execute(email: String, password: String) async throws -> User {
|
|
126
|
+
fatalError("TODO: implement in Phase 3")
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### 2.6: UI State Design
|
|
132
|
+
|
|
133
|
+
```swift
|
|
134
|
+
// State
|
|
135
|
+
struct LoginViewState {
|
|
136
|
+
var email: String = ""
|
|
137
|
+
var password: String = ""
|
|
138
|
+
var isLoading: Bool = false
|
|
139
|
+
var error: String? = nil
|
|
140
|
+
var isPasswordVisible: Bool = false
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Actions (user interactions)
|
|
144
|
+
enum LoginAction {
|
|
145
|
+
case updateEmail(String)
|
|
146
|
+
case updatePassword(String)
|
|
147
|
+
case togglePasswordVisibility
|
|
148
|
+
case submit
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Events (one-time navigation/alerts)
|
|
152
|
+
enum LoginEvent {
|
|
153
|
+
case navigateToHome
|
|
154
|
+
case showError(String)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Mock data for Preview
|
|
158
|
+
extension LoginViewState {
|
|
159
|
+
static let normal = LoginViewState(email: "user@example.com")
|
|
160
|
+
static let loading = LoginViewState(isLoading: true)
|
|
161
|
+
static let error = LoginViewState(error: "Invalid credentials")
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### 2.7: Resource Extraction β (Before UI code!)
|
|
166
|
+
|
|
167
|
+
> **Why here?** UI code (2.8) needs real assets. If resources come later, UI will be full of placeholders β defeating the purpose of visual parity.
|
|
168
|
+
|
|
169
|
+
**Process:**
|
|
170
|
+
1. Extract from `Assets.car` (use `acextract` or screen captures)
|
|
171
|
+
2. Extract from IPA bundle: png, pdf, json, fonts
|
|
172
|
+
3. Copy ONLY needed resources to new Xcode project `Assets.xcassets`
|
|
173
|
+
4. Map string tables to `Localizable.xcstrings`
|
|
174
|
+
|
|
175
|
+
**Output:**
|
|
176
|
+
```markdown
|
|
177
|
+
### π¦ Resources for [Screen]
|
|
178
|
+
- Images: [list from Assets.xcassets]
|
|
179
|
+
- Colors: [list β add to Color extension or asset catalog]
|
|
180
|
+
- Strings: [list β add to Localizable.xcstrings]
|
|
181
|
+
- Fonts: [custom fonts if any]
|
|
182
|
+
β
All accessible in SwiftUI
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### 2.8: UI Implementation β Visual Shell β
|
|
186
|
+
|
|
187
|
+
> **Goal:** Code the screen with HARDCODED mock data. Pixel-perfect visual parity with original app.
|
|
188
|
+
|
|
189
|
+
**Rules:**
|
|
190
|
+
```
|
|
191
|
+
β
MUST DO:
|
|
192
|
+
- Use ViewState from 2.6 (hardcode sample values as defaults)
|
|
193
|
+
- Use REAL resources extracted in 2.7
|
|
194
|
+
- Display ALL visual elements from original app
|
|
195
|
+
- Match: spacing, font size, colors, icon placement
|
|
196
|
+
- Code ALL states: normal, loading, error, empty
|
|
197
|
+
- Create #Preview for each state
|
|
198
|
+
|
|
199
|
+
β MUST NOT:
|
|
200
|
+
- Connect real ViewModel (use parameter defaults)
|
|
201
|
+
- Call real APIs
|
|
202
|
+
- Code business logic
|
|
203
|
+
- Use DI/injection
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
**Pattern β Stateless View:**
|
|
207
|
+
```swift
|
|
208
|
+
struct LoginScreenContent: View {
|
|
209
|
+
var state: LoginViewState = .normal // Hardcoded default
|
|
210
|
+
var onAction: (LoginAction) -> Void = { _ in } // No-op default
|
|
211
|
+
|
|
212
|
+
var body: some View {
|
|
213
|
+
VStack(spacing: 24) {
|
|
214
|
+
// Logo β real resource from 2.7
|
|
215
|
+
Image("app_logo")
|
|
216
|
+
.resizable()
|
|
217
|
+
.frame(width: 120, height: 120)
|
|
218
|
+
|
|
219
|
+
Spacer().frame(height: 24)
|
|
220
|
+
|
|
221
|
+
// Email
|
|
222
|
+
TextField("Email", text: .constant(state.email))
|
|
223
|
+
.textFieldStyle(.roundedBorder)
|
|
224
|
+
.keyboardType(.emailAddress)
|
|
225
|
+
.textContentType(.emailAddress)
|
|
226
|
+
|
|
227
|
+
// Password with toggle
|
|
228
|
+
HStack {
|
|
229
|
+
if state.isPasswordVisible {
|
|
230
|
+
TextField("Password", text: .constant(state.password))
|
|
231
|
+
} else {
|
|
232
|
+
SecureField("Password", text: .constant(state.password))
|
|
233
|
+
}
|
|
234
|
+
Button { onAction(.togglePasswordVisibility) } label: {
|
|
235
|
+
Image(systemName: state.isPasswordVisible ? "eye.slash" : "eye")
|
|
236
|
+
.foregroundColor(.secondary)
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
.textFieldStyle(.roundedBorder)
|
|
240
|
+
|
|
241
|
+
// Login Button
|
|
242
|
+
Button { onAction(.submit) } label: {
|
|
243
|
+
if state.isLoading {
|
|
244
|
+
ProgressView()
|
|
245
|
+
.tint(.white)
|
|
246
|
+
} else {
|
|
247
|
+
Text("Login")
|
|
248
|
+
.fontWeight(.semibold)
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
.frame(maxWidth: .infinity, minHeight: 50)
|
|
252
|
+
.background(Color.accentColor)
|
|
253
|
+
.foregroundColor(.white)
|
|
254
|
+
.cornerRadius(12)
|
|
255
|
+
.disabled(state.isLoading)
|
|
256
|
+
|
|
257
|
+
// Error
|
|
258
|
+
if let error = state.error {
|
|
259
|
+
Text(error)
|
|
260
|
+
.foregroundColor(.red)
|
|
261
|
+
.font(.caption)
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
.padding(24)
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// ===== PREVIEWS =====
|
|
269
|
+
#Preview("Normal") {
|
|
270
|
+
LoginScreenContent(state: .normal)
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
#Preview("Loading") {
|
|
274
|
+
LoginScreenContent(state: .loading)
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
#Preview("Error") {
|
|
278
|
+
LoginScreenContent(state: .error)
|
|
279
|
+
}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### 2.9: Visual Parity Check β
|
|
283
|
+
|
|
284
|
+
Compare UI shell with original app screenshot:
|
|
285
|
+
|
|
286
|
+
```markdown
|
|
287
|
+
### πΈ Visual Parity: [Screen Name]
|
|
288
|
+
|
|
289
|
+
Layout:
|
|
290
|
+
- [ ] Structure matches original (components, sections)
|
|
291
|
+
- [ ] Spacing between elements correct
|
|
292
|
+
- [ ] Alignment matches
|
|
293
|
+
|
|
294
|
+
Styling:
|
|
295
|
+
- [ ] Colors match (background, text, buttons, header)
|
|
296
|
+
- [ ] Typography matches (font size, weight)
|
|
297
|
+
- [ ] Icons/images correct and positioned
|
|
298
|
+
- [ ] Borders, shadows, rounded corners
|
|
299
|
+
|
|
300
|
+
States:
|
|
301
|
+
- [ ] Normal state displays correctly
|
|
302
|
+
- [ ] Loading state β progress in right position
|
|
303
|
+
- [ ] Error state β error message shows properly
|
|
304
|
+
- [ ] Empty state β guidance shown
|
|
305
|
+
|
|
306
|
+
Platform:
|
|
307
|
+
- [ ] iOS conventions followed (safe area, etc.)
|
|
308
|
+
- [ ] Dynamic Type support
|
|
309
|
+
- [ ] Looks good on different iPhone sizes
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
## π Output: Feature Blueprint + UI
|
|
315
|
+
|
|
316
|
+
Structured document with contracts + screen screenshots.
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## β
Gate (MANDATORY)
|
|
321
|
+
|
|
322
|
+
```
|
|
323
|
+
"π Blueprint + UI cho [Feature] xong:
|
|
324
|
+
|
|
325
|
+
π Contracts:
|
|
326
|
+
- [N] domain models
|
|
327
|
+
- [N] repository protocols
|
|
328
|
+
- [N] use case signatures
|
|
329
|
+
- [N] API endpoints
|
|
330
|
+
|
|
331
|
+
π¨ UI:
|
|
332
|
+
- [Screen] implemented with mock data
|
|
333
|
+
- Resources: [N] images, [N] strings, [N] colors
|
|
334
|
+
- Previews: [N] states (normal, loading, error, empty)
|
|
335
|
+
|
|
336
|
+
πΈ Visual Parity: [OK / cαΊ§n chα»nh X, Y, Z]
|
|
337
|
+
|
|
338
|
+
Anh xem UI + contracts α»n khΓ΄ng?
|
|
339
|
+
β β
Approve β Phase 3 (Logic Build)
|
|
340
|
+
β π¨ Adjust UI β fix then re-check
|
|
341
|
+
β π Adjust contracts β revise blueprint"
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
> β οΈ **DO NOT proceed to Phase 3 until user approves BOTH UI and contracts.**
|
|
345
|
+
|
|
346
|
+
---
|
|
347
|
+
|
|
348
|
+
*Phase 2: Blueprint + UI Design β See it before you code it*
|