@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,268 @@
|
|
|
1
|
+
# ๐จ Phase 3: Logic Build (Per Feature) โ Android
|
|
2
|
+
|
|
3
|
+
> **Zoom Level:** 3 โ Code Implementation
|
|
4
|
+
> **Goal:** Code logic behind the APPROVED UI shell for ONE feature.
|
|
5
|
+
> **Input:** Approved Blueprint + Working UI Shell from Phase 2.
|
|
6
|
+
> **Output:** Feature fully wired โ UI + logic connected.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## โ
PREREQUISITES
|
|
11
|
+
|
|
12
|
+
Before writing ANY logic code, confirm:
|
|
13
|
+
- [ ] Phase 0 App Map: approved
|
|
14
|
+
- [ ] Phase 1 Architecture Blueprint: approved
|
|
15
|
+
- [ ] Phase 2 Contracts: approved for THIS feature
|
|
16
|
+
- [ ] Phase 2 UI Shell: approved, runs in Preview/device
|
|
17
|
+
|
|
18
|
+
> โ ๏ธ If UI is not approved yet, STOP. Go back to Phase 2.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## ๐ Implementation Order
|
|
23
|
+
|
|
24
|
+
### 3.1: Domain Layer
|
|
25
|
+
|
|
26
|
+
Implement from contracts defined in Phase 2:
|
|
27
|
+
|
|
28
|
+
1. **Models** โ data classes (already drafted in 2.2, now create actual files)
|
|
29
|
+
2. **Repository interfaces** โ (already drafted in 2.3, create files)
|
|
30
|
+
3. **UseCases** โ implement invoke() with repository calls
|
|
31
|
+
|
|
32
|
+
```kotlin
|
|
33
|
+
class LoginUseCase @Inject constructor(
|
|
34
|
+
private val authRepository: AuthRepository
|
|
35
|
+
) {
|
|
36
|
+
suspend operator fun invoke(email: String, password: String): Result<User> {
|
|
37
|
+
return authRepository.login(email, password)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### 3.2: Data Layer
|
|
43
|
+
|
|
44
|
+
1. **DTOs** โ @Serializable data classes matching API JSON
|
|
45
|
+
2. **API interfaces** โ Retrofit with correct annotations
|
|
46
|
+
3. **Room entities + DAOs** (if applicable)
|
|
47
|
+
4. **DataStore** setup (if applicable)
|
|
48
|
+
5. **Repository implementation** โ offline-first pattern
|
|
49
|
+
|
|
50
|
+
```kotlin
|
|
51
|
+
class AuthRepositoryImpl @Inject constructor(
|
|
52
|
+
private val api: AuthApi,
|
|
53
|
+
private val tokenStore: TokenDataStore
|
|
54
|
+
) : AuthRepository {
|
|
55
|
+
|
|
56
|
+
override suspend fun login(email: String, password: String): Result<User> {
|
|
57
|
+
return runCatching {
|
|
58
|
+
val response = api.login(LoginRequest(email, password))
|
|
59
|
+
tokenStore.saveToken(response.accessToken)
|
|
60
|
+
response.user.toDomain()
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
override fun isLoggedIn(): Flow<Boolean> {
|
|
65
|
+
return tokenStore.tokenFlow.map { it.isNotEmpty() }
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 3.3: DI Module
|
|
71
|
+
|
|
72
|
+
```kotlin
|
|
73
|
+
@Module
|
|
74
|
+
@InstallIn(SingletonComponent::class)
|
|
75
|
+
abstract class RepositoryModule {
|
|
76
|
+
@Binds
|
|
77
|
+
abstract fun bindAuthRepository(impl: AuthRepositoryImpl): AuthRepository
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### 3.4: ViewModel
|
|
82
|
+
|
|
83
|
+
Implement using UiState + Events + Actions from Phase 2.6:
|
|
84
|
+
|
|
85
|
+
```kotlin
|
|
86
|
+
@HiltViewModel
|
|
87
|
+
class LoginViewModel @Inject constructor(
|
|
88
|
+
private val loginUseCase: LoginUseCase
|
|
89
|
+
) : ViewModel() {
|
|
90
|
+
|
|
91
|
+
private val _uiState = MutableStateFlow(LoginUiState())
|
|
92
|
+
val uiState = _uiState.asStateFlow()
|
|
93
|
+
|
|
94
|
+
private val _events = MutableSharedFlow<LoginEvent>()
|
|
95
|
+
val events = _events.asSharedFlow()
|
|
96
|
+
|
|
97
|
+
fun onAction(action: LoginAction) {
|
|
98
|
+
when (action) {
|
|
99
|
+
is LoginAction.UpdateEmail -> _uiState.update { it.copy(email = action.email) }
|
|
100
|
+
is LoginAction.UpdatePassword -> _uiState.update { it.copy(password = action.password) }
|
|
101
|
+
LoginAction.TogglePasswordVisibility -> _uiState.update {
|
|
102
|
+
it.copy(isPasswordVisible = !it.isPasswordVisible)
|
|
103
|
+
}
|
|
104
|
+
LoginAction.Submit -> login()
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
private fun login() {
|
|
109
|
+
viewModelScope.launch {
|
|
110
|
+
_uiState.update { it.copy(isLoading = true, error = null) }
|
|
111
|
+
loginUseCase(uiState.value.email, uiState.value.password)
|
|
112
|
+
.onSuccess { user -> _events.emit(LoginEvent.NavigateToHome(user)) }
|
|
113
|
+
.onFailure { e -> _uiState.update { it.copy(error = e.message, isLoading = false) } }
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### 3.5: Wire UI โ Logic โญ (NOT "code new UI")
|
|
120
|
+
|
|
121
|
+
> **This step does NOT create new UI.** The UI already exists from Phase 2.8.
|
|
122
|
+
> Only CONNECT the existing UI shell to the real ViewModel.
|
|
123
|
+
|
|
124
|
+
**Changes needed on the UI shell:**
|
|
125
|
+
|
|
126
|
+
```kotlin
|
|
127
|
+
// Phase 2 code stays as the STATELESS "Content" composable (for Preview):
|
|
128
|
+
@Composable
|
|
129
|
+
fun LoginScreenContent(
|
|
130
|
+
uiState: LoginUiState = LoginUiState(),
|
|
131
|
+
onAction: (LoginAction) -> Unit = {}
|
|
132
|
+
) {
|
|
133
|
+
// ... all UI code from Phase 2.8 โ DO NOT MODIFY
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// ADD a NEW wrapper that wires ViewModel:
|
|
137
|
+
@Composable
|
|
138
|
+
fun LoginScreen(
|
|
139
|
+
viewModel: LoginViewModel = hiltViewModel(),
|
|
140
|
+
onNavigateToHome: () -> Unit
|
|
141
|
+
) {
|
|
142
|
+
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
|
|
143
|
+
|
|
144
|
+
LaunchedEffect(Unit) {
|
|
145
|
+
viewModel.events.collect { event ->
|
|
146
|
+
when (event) {
|
|
147
|
+
is LoginEvent.NavigateToHome -> onNavigateToHome()
|
|
148
|
+
is LoginEvent.ShowSnackbar -> { /* snackbar */ }
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Delegate to stateless content composable
|
|
154
|
+
LoginScreenContent(
|
|
155
|
+
uiState = uiState,
|
|
156
|
+
onAction = viewModel::onAction
|
|
157
|
+
)
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**Wire Checklist:**
|
|
162
|
+
- [ ] Replace hardcoded defaults โ ViewModel state
|
|
163
|
+
- [ ] Connect UI actions โ ViewModel.onAction()
|
|
164
|
+
- [ ] Bind navigation events
|
|
165
|
+
- [ ] Connect loading/error states
|
|
166
|
+
- [ ] Previews still work (they use the stateless Content composable)
|
|
167
|
+
|
|
168
|
+
### 3.6: Integration Test โญ
|
|
169
|
+
|
|
170
|
+
Verify UI + logic end-to-end:
|
|
171
|
+
|
|
172
|
+
```markdown
|
|
173
|
+
### ๐งช Integration: [Feature]
|
|
174
|
+
|
|
175
|
+
Functional:
|
|
176
|
+
- [ ] API calls succeed, data displays on UI
|
|
177
|
+
- [ ] Loading state shows/hides at right time
|
|
178
|
+
- [ ] Error state displays correct message
|
|
179
|
+
- [ ] Navigation works as expected
|
|
180
|
+
- [ ] Form validation works
|
|
181
|
+
|
|
182
|
+
Data:
|
|
183
|
+
- [ ] Request format matches original app
|
|
184
|
+
- [ ] Response parses correctly
|
|
185
|
+
- [ ] Token/session stored properly
|
|
186
|
+
- [ ] Crypto output matches original (if applicable)
|
|
187
|
+
|
|
188
|
+
Edge Cases:
|
|
189
|
+
- [ ] Empty input handling
|
|
190
|
+
- [ ] Network error handling
|
|
191
|
+
- [ ] Back navigation
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## ๐ CRYPTO UTILS (Special Handling)
|
|
197
|
+
|
|
198
|
+
If the feature involves encryption/hashing:
|
|
199
|
+
|
|
200
|
+
1. Read Smali carefully โ exact algorithm, padding, encoding
|
|
201
|
+
2. Implement in Kotlin โ preserve exact input/output
|
|
202
|
+
3. Unit test IMMEDIATELY with known pairs
|
|
203
|
+
|
|
204
|
+
```kotlin
|
|
205
|
+
object CryptoUtils {
|
|
206
|
+
fun hashMd5(input: String): String {
|
|
207
|
+
val md = MessageDigest.getInstance("MD5")
|
|
208
|
+
return md.digest(input.toByteArray())
|
|
209
|
+
.joinToString("") { "%02x".format(it) }
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// MANDATORY test
|
|
214
|
+
class CryptoUtilsTest {
|
|
215
|
+
@Test
|
|
216
|
+
fun `md5 matches original app output`() {
|
|
217
|
+
assertEquals("expected_hash", CryptoUtils.hashMd5("known_input"))
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
> โ ๏ธ Crypto functions MUST produce identical output. Any mismatch breaks server communication.
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## โ
Checkpoint
|
|
227
|
+
|
|
228
|
+
```markdown
|
|
229
|
+
## โ
Feature Complete: [Feature Name]
|
|
230
|
+
|
|
231
|
+
### Files created:
|
|
232
|
+
- domain/model/User.kt
|
|
233
|
+
- domain/repository/AuthRepository.kt
|
|
234
|
+
- domain/usecase/LoginUseCase.kt
|
|
235
|
+
- data/remote/api/AuthApi.kt
|
|
236
|
+
- data/remote/dto/LoginRequest.kt, LoginResponse.kt
|
|
237
|
+
- data/repository/AuthRepositoryImpl.kt
|
|
238
|
+
- di/RepositoryModule.kt
|
|
239
|
+
- presentation/screens/auth/LoginViewModel.kt
|
|
240
|
+
- presentation/screens/auth/LoginScreen.kt โ wired (from Phase 2)
|
|
241
|
+
- presentation/screens/auth/LoginUiState.kt
|
|
242
|
+
|
|
243
|
+
### Tests:
|
|
244
|
+
- [ ] Crypto utils verified (if applicable)
|
|
245
|
+
- [ ] API contract matches original
|
|
246
|
+
- [ ] UI + Logic e2e works
|
|
247
|
+
|
|
248
|
+
### โญ๏ธ Next Feature: [Name]
|
|
249
|
+
โ Return to Phase 2 (Blueprint + UI Design)
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## ๐ Feature Loop
|
|
255
|
+
|
|
256
|
+
```
|
|
257
|
+
Phase 2 (Blueprint + UI for Feature X) โ GATE โ Phase 3 (Logic for X) โ Checkpoint
|
|
258
|
+
โ
|
|
259
|
+
Phase 2 (Blueprint + UI for Feature Y) โ GATE โ Phase 3 (Logic for Y) โ Checkpoint
|
|
260
|
+
โ
|
|
261
|
+
... (repeat for all features from Architecture Build Order)
|
|
262
|
+
โ
|
|
263
|
+
Phase 4: Final Parity Check & Quality Gate
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
*Phase 3: Logic Build โ Wire logic behind approved UI*
|