@maccesar/titools 2.0.7 → 2.2.0
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/{AGENTS-TEMPLATE.md → AGENTS-VERCEL-RESEARCH.md} +16 -18
- package/README.md +250 -168
- package/agents/{ti-researcher.md → ti-pro.md} +10 -10
- package/bin/titools.js +16 -12
- package/lib/cleanup.js +95 -0
- package/lib/commands/agents.js +146 -70
- package/lib/commands/skills.js +349 -0
- package/lib/commands/uninstall.js +189 -154
- package/lib/commands/update.js +104 -21
- package/lib/config.js +26 -20
- package/lib/downloader.js +1 -1
- package/lib/installer.js +37 -97
- package/lib/platform.js +9 -5
- package/lib/prompts/checkboxCancel.js +264 -0
- package/lib/prompts/selectCancel.js +204 -0
- package/lib/symlink.js +19 -7
- package/lib/utils.js +17 -17
- package/package.json +10 -10
- package/skills/alloy-guides/SKILL.md +8 -30
- package/skills/alloy-guides/references/CLI_TASKS.md +14 -24
- package/skills/alloy-guides/references/CONCEPTS.md +5 -25
- package/skills/alloy-guides/references/CONTROLLERS.md +2 -19
- package/skills/alloy-guides/references/MODELS.md +40 -10
- package/skills/alloy-guides/references/PURGETSS.md +1 -11
- package/skills/alloy-guides/references/VIEWS_DYNAMIC.md +8 -14
- package/skills/alloy-guides/references/VIEWS_STYLES.md +14 -25
- package/skills/alloy-guides/references/VIEWS_WITHOUT_CONTROLLERS.md +2 -8
- package/skills/alloy-guides/references/VIEWS_XML.md +29 -40
- package/skills/alloy-guides/references/WIDGETS.md +1 -17
- package/skills/alloy-howtos/SKILL.md +1 -22
- package/skills/alloy-howtos/references/best_practices.md +0 -17
- package/skills/alloy-howtos/references/cli_reference.md +1 -23
- package/skills/alloy-howtos/references/config_files.md +86 -15
- package/skills/alloy-howtos/references/custom_tags.md +14 -13
- package/skills/alloy-howtos/references/debugging_troubleshooting.md +3 -22
- package/skills/alloy-howtos/references/samples.md +4 -14
- package/skills/purgetss/SKILL.md +11 -37
- package/skills/purgetss/references/EXAMPLES.md +106 -17
- package/skills/purgetss/references/animation-system.md +0 -67
- package/skills/purgetss/references/apply-directive.md +0 -18
- package/skills/purgetss/references/arbitrary-values.md +0 -25
- package/skills/purgetss/references/class-index.md +0 -46
- package/skills/purgetss/references/cli-commands.md +0 -41
- package/skills/purgetss/references/configurable-properties.md +0 -55
- package/skills/purgetss/references/custom-rules.md +0 -14
- package/skills/purgetss/references/customization-deep-dive.md +0 -49
- package/skills/purgetss/references/dynamic-component-creation.md +56 -37
- package/skills/purgetss/references/grid-layout.md +0 -32
- package/skills/purgetss/references/icon-fonts.md +0 -50
- package/skills/purgetss/references/installation-setup.md +61 -32
- package/skills/purgetss/references/migration-guide.md +127 -0
- package/skills/purgetss/references/opacity-modifier.md +0 -34
- package/skills/purgetss/references/performance-tips.md +261 -0
- package/skills/purgetss/references/platform-modifiers.md +0 -46
- package/skills/purgetss/references/smart-mappings.md +0 -12
- package/skills/purgetss/references/tikit-components.md +393 -0
- package/skills/purgetss/references/titanium-resets.md +1 -27
- package/skills/purgetss/references/ui-ux-design.md +467 -117
- package/skills/{alloy-expert → ti-expert}/SKILL.md +45 -54
- package/skills/ti-expert/references/alloy-builtins.md +387 -0
- package/skills/{alloy-expert → ti-expert}/references/alloy-structure.md +147 -40
- package/skills/ti-expert/references/anti-patterns.md +90 -0
- package/skills/ti-expert/references/cli-expert.md +109 -0
- package/skills/{alloy-expert → ti-expert}/references/code-conventions.md +182 -49
- package/skills/{alloy-expert → ti-expert}/references/controller-patterns.md +103 -93
- package/skills/{alloy-expert → ti-expert}/references/error-handling.md +12 -12
- package/skills/{alloy-expert → ti-expert}/references/examples.md +144 -85
- package/skills/{alloy-expert → ti-expert}/references/migration-patterns.md +38 -36
- package/skills/{alloy-expert → ti-expert}/references/patterns.md +8 -8
- package/skills/ti-expert/references/performance-listview.md +251 -0
- package/skills/{alloy-expert/references/performance-patterns.md → ti-expert/references/performance-optimization.md} +67 -283
- package/skills/{alloy-expert/references/security-patterns.md → ti-expert/references/security-device.md} +12 -295
- package/skills/ti-expert/references/security-fundamentals.md +284 -0
- package/skills/{alloy-expert → ti-expert}/references/state-management.md +10 -10
- package/skills/ti-expert/references/testing-e2e-ci.md +432 -0
- package/skills/ti-expert/references/testing-unit.md +433 -0
- package/skills/ti-expert/references/theming.md +394 -0
- package/skills/ti-guides/SKILL.md +1 -14
- package/skills/ti-guides/references/advanced-data-and-images.md +126 -10
- package/skills/ti-guides/references/app-distribution.md +48 -10
- package/skills/ti-guides/references/application-frameworks.md +9 -2
- package/skills/ti-guides/references/cli-reference.md +338 -82
- package/skills/ti-guides/references/coding-best-practices.md +14 -4
- package/skills/ti-guides/references/commonjs-advanced.md +103 -6
- package/skills/ti-guides/references/hello-world.md +5 -2
- package/skills/ti-guides/references/hyperloop-native-access.md +439 -46
- package/skills/ti-guides/references/javascript-primer.md +4 -3
- package/skills/ti-guides/references/resources.md +0 -1
- package/skills/ti-guides/references/style-and-conventions.md +57 -9
- package/skills/ti-guides/references/tiapp-config.md +48 -6
- package/skills/ti-howtos/SKILL.md +2 -27
- package/skills/ti-howtos/references/android-platform-deep-dives.md +41 -90
- package/skills/ti-howtos/references/automation-fastlane-appium.md +15 -14
- package/skills/ti-howtos/references/buffer-codec-streams.md +22 -22
- package/skills/ti-howtos/references/cross-platform-development.md +68 -37
- package/skills/ti-howtos/references/debugging-profiling.md +8 -53
- package/skills/ti-howtos/references/extending-titanium.md +12 -51
- package/skills/ti-howtos/references/google-maps-v2.md +30 -29
- package/skills/ti-howtos/references/ios-map-kit.md +19 -25
- package/skills/ti-howtos/references/ios-platform-deep-dives.md +95 -283
- package/skills/ti-howtos/references/local-data-sources.md +45 -37
- package/skills/ti-howtos/references/location-and-maps.md +47 -28
- package/skills/ti-howtos/references/media-apis.md +84 -27
- package/skills/ti-howtos/references/notification-services.md +40 -89
- package/skills/ti-howtos/references/remote-data-sources.md +21 -36
- package/skills/ti-howtos/references/tutorials.md +79 -39
- package/skills/ti-howtos/references/using-modules.md +4 -30
- package/skills/ti-howtos/references/web-content-integration.md +28 -45
- package/skills/ti-howtos/references/webpack-build-pipeline.md +54 -18
- package/skills/ti-ui/SKILL.md +1 -21
- package/skills/ti-ui/references/accessibility-deep-dive.md +71 -25
- package/skills/ti-ui/references/animation-and-matrices.md +0 -47
- package/skills/ti-ui/references/application-structures.md +0 -46
- package/skills/ti-ui/references/custom-fonts-styling.md +9 -57
- package/skills/ti-ui/references/event-handling.md +32 -40
- package/skills/ti-ui/references/gestures.md +0 -40
- package/skills/ti-ui/references/icons-and-splash-screens.md +21 -44
- package/skills/ti-ui/references/layouts-and-positioning.md +47 -39
- package/skills/ti-ui/references/listviews-and-performance.md +187 -73
- package/skills/ti-ui/references/orientation.md +57 -71
- package/skills/ti-ui/references/platform-ui-android.md +114 -48
- package/skills/ti-ui/references/platform-ui-ios.md +63 -38
- package/skills/ti-ui/references/scrolling-views.md +14 -23
- package/skills/ti-ui/references/tableviews.md +6 -56
- package/lib/commands/install.js +0 -188
- package/skills/alloy-expert/references/anti-patterns.md +0 -133
- package/skills/alloy-expert/references/testing.md +0 -872
- package/skills/ti-guides/references/alloy-cli-advanced.md +0 -84
- package/skills/ti-guides/references/alloy-data-mastery.md +0 -29
- package/skills/ti-guides/references/alloy-widgets-and-themes.md +0 -19
- /package/skills/{alloy-expert → ti-expert}/assets/ControllerAutoCleanup.js +0 -0
- /package/skills/{alloy-expert → ti-expert}/references/contracts.md +0 -0
|
@@ -146,8 +146,8 @@ module.exports = new Logger()
|
|
|
146
146
|
|
|
147
147
|
```javascript
|
|
148
148
|
// lib/services/errorHandler.js
|
|
149
|
-
const logger = require('
|
|
150
|
-
const { AppError } = require('
|
|
149
|
+
const logger = require('services/logger')
|
|
150
|
+
const { AppError } = require('core/appError')
|
|
151
151
|
|
|
152
152
|
exports.handleError = function handleError(error, context = {}) {
|
|
153
153
|
// Log the error
|
|
@@ -201,8 +201,8 @@ function _getUserMessage(error) {
|
|
|
201
201
|
|
|
202
202
|
```javascript
|
|
203
203
|
// lib/services/userService.js
|
|
204
|
-
const logger = require('
|
|
205
|
-
const { NetworkError, NotFoundError } = require('
|
|
204
|
+
const logger = require('services/logger')
|
|
205
|
+
const { NetworkError, NotFoundError } = require('core/appError')
|
|
206
206
|
|
|
207
207
|
exports.getUserProfile = async function getUserProfile(userId) {
|
|
208
208
|
logger.info('UserService', 'Fetching user profile', { userId })
|
|
@@ -237,8 +237,8 @@ exports.getUserProfile = async function getUserProfile(userId) {
|
|
|
237
237
|
|
|
238
238
|
```javascript
|
|
239
239
|
// lib/api/client.js
|
|
240
|
-
const logger = require('
|
|
241
|
-
const { NetworkError, AuthError, NotFoundError, ValidationError } = require('
|
|
240
|
+
const logger = require('services/logger')
|
|
241
|
+
const { NetworkError, AuthError, NotFoundError, ValidationError } = require('core/appError')
|
|
242
242
|
|
|
243
243
|
exports.get = async function get(endpoint, params = {}) {
|
|
244
244
|
return new Promise((resolve, reject) => {
|
|
@@ -306,9 +306,9 @@ exports.get = async function get(endpoint, params = {}) {
|
|
|
306
306
|
|
|
307
307
|
```javascript
|
|
308
308
|
// controllers/user/detail.js
|
|
309
|
-
const logger = require('
|
|
310
|
-
const { handleError } = require('
|
|
311
|
-
const { getUserProfile } = require('
|
|
309
|
+
const logger = require('services/logger')
|
|
310
|
+
const { handleError } = require('services/errorHandler')
|
|
311
|
+
const { getUserProfile } = require('services/userService')
|
|
312
312
|
|
|
313
313
|
function init() {
|
|
314
314
|
logger.debug('UserDetail', 'Controller initialized', { userId: $.args.userId })
|
|
@@ -380,7 +380,7 @@ $.cleanup = cleanup
|
|
|
380
380
|
|
|
381
381
|
```javascript
|
|
382
382
|
// alloy.js - Setup global error catching
|
|
383
|
-
const { handleError } = require('
|
|
383
|
+
const { handleError } = require('services/errorHandler')
|
|
384
384
|
|
|
385
385
|
// Catch unhandled errors in production
|
|
386
386
|
if (Ti.App.deployType === 'production') {
|
|
@@ -429,8 +429,8 @@ exports.reportToCrashService = function reportToCrashService(error, context = {}
|
|
|
429
429
|
|
|
430
430
|
```javascript
|
|
431
431
|
// lib/helpers/validator.js
|
|
432
|
-
const { ValidationError } = require('
|
|
433
|
-
const logger = require('
|
|
432
|
+
const { ValidationError } = require('core/appError')
|
|
433
|
+
const logger = require('services/logger')
|
|
434
434
|
|
|
435
435
|
exports.validateEmail = function validateEmail(email) {
|
|
436
436
|
const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Alloy Implementation Examples
|
|
2
2
|
|
|
3
3
|
## API Client Service
|
|
4
4
|
Standard logic for network requests.
|
|
@@ -64,30 +64,26 @@ exports.definition = {
|
|
|
64
64
|
}
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
-
## Fully Styled & Accessible View
|
|
68
|
-
Applying
|
|
67
|
+
## Fully Styled & Accessible View
|
|
68
|
+
Applying TSS styles while maintaining accessibility.
|
|
69
69
|
|
|
70
70
|
```xml
|
|
71
71
|
<!-- views/login.xml -->
|
|
72
72
|
<Alloy>
|
|
73
|
-
<Window
|
|
74
|
-
<Animation id="myAnim" module="purgetss.ui" class="close:opacity-0 duration-500 open:opacity-100" />
|
|
75
|
-
|
|
73
|
+
<Window id="loginWindow">
|
|
76
74
|
<!-- Spacer to center content -->
|
|
77
|
-
<View
|
|
75
|
+
<View id="topSpacer" />
|
|
78
76
|
|
|
79
|
-
<
|
|
77
|
+
<ImageView id="lockIcon" image="/images/lock.png"
|
|
80
78
|
accessibilityLabel="L('login_icon_label')"
|
|
81
79
|
/>
|
|
82
80
|
|
|
83
81
|
<TextField id="email"
|
|
84
|
-
class="border-(1) mx-6 h-12 w-screen rounded-lg border-gray-300 bg-white"
|
|
85
82
|
hintText="L('email_hint')"
|
|
86
83
|
accessibilityLabel="L('email_label')"
|
|
87
84
|
/>
|
|
88
85
|
|
|
89
86
|
<Button id="submit"
|
|
90
|
-
class="bg-primary mx-6 mt-10 h-14 w-screen rounded-xl font-bold text-white"
|
|
91
87
|
title="L('login_button')"
|
|
92
88
|
accessibilityLabel="L('login_button')"
|
|
93
89
|
accessibilityHint="L('login_hint')"
|
|
@@ -95,16 +91,25 @@ Applying PurgeTSS classes while maintaining accessibility.
|
|
|
95
91
|
/>
|
|
96
92
|
|
|
97
93
|
<!-- Spacer to center content -->
|
|
98
|
-
<View
|
|
94
|
+
<View id="bottomSpacer" />
|
|
99
95
|
</Window>
|
|
100
96
|
</Alloy>
|
|
101
97
|
```
|
|
102
98
|
|
|
99
|
+
```tss
|
|
100
|
+
/* styles/login.tss */
|
|
101
|
+
"#loginWindow": { layout: 'vertical', backgroundColor: '#f9fafb' }
|
|
102
|
+
"#topSpacer": { height: Ti.UI.SIZE }
|
|
103
|
+
"#lockIcon": { left: 24, right: 24, bottom: 40, width: 48, height: 48 }
|
|
104
|
+
"#email": { left: 24, right: 24, height: 48, borderRadius: 8, borderWidth: 1, borderColor: '#d1d5db', backgroundColor: '#fff' }
|
|
105
|
+
"#submit": { left: 24, right: 24, top: 40, height: 56, borderRadius: 12, backgroundColor: '#2563eb', color: '#fff', font: { fontWeight: 'bold' } }
|
|
106
|
+
"#bottomSpacer": { height: Ti.UI.SIZE }
|
|
107
|
+
```
|
|
108
|
+
|
|
103
109
|
**Notes:**
|
|
104
|
-
- Use `vertical`
|
|
105
|
-
- Use
|
|
106
|
-
- Use `
|
|
107
|
-
- Use `border-(1)` with parentheses for arbitrary border width
|
|
110
|
+
- Use `layout: 'vertical'` on Window for top-to-bottom content flow
|
|
111
|
+
- Use margins on children for spacing (NOT padding on parent)
|
|
112
|
+
- Use `Ti.UI.FILL` for full-width elements
|
|
108
113
|
|
|
109
114
|
## Cleanup Pattern in Controller
|
|
110
115
|
Critical for memory management and avoiding leaks.
|
|
@@ -128,13 +133,23 @@ function cleanup() {
|
|
|
128
133
|
$.cleanup = cleanup
|
|
129
134
|
```
|
|
130
135
|
|
|
131
|
-
## Animation
|
|
132
|
-
Using
|
|
136
|
+
## Animation Usage
|
|
137
|
+
Using `Ti.UI.createAnimation()` for UI transformations.
|
|
133
138
|
|
|
134
139
|
```javascript
|
|
135
140
|
// Inside any controller
|
|
136
141
|
function shakeError(element) {
|
|
137
|
-
|
|
142
|
+
const shake = Ti.UI.createAnimation({ duration: 50 })
|
|
143
|
+
const offset = 10
|
|
144
|
+
|
|
145
|
+
shake.transform = Ti.UI.createMatrix2D().translate(offset, 0)
|
|
146
|
+
element.animate(shake, () => {
|
|
147
|
+
shake.transform = Ti.UI.createMatrix2D().translate(-offset, 0)
|
|
148
|
+
element.animate(shake, () => {
|
|
149
|
+
shake.transform = Ti.UI.createMatrix2D()
|
|
150
|
+
element.animate(shake)
|
|
151
|
+
})
|
|
152
|
+
})
|
|
138
153
|
}
|
|
139
154
|
```
|
|
140
155
|
|
|
@@ -142,9 +157,9 @@ function shakeError(element) {
|
|
|
142
157
|
|
|
143
158
|
```javascript
|
|
144
159
|
// lib/services/productService.js
|
|
145
|
-
const { productApi } = require('
|
|
146
|
-
const { appStore } = require('
|
|
147
|
-
const logger = require('
|
|
160
|
+
const { productApi } = require('api/productApi')
|
|
161
|
+
const { appStore } = require('services/stateStore')
|
|
162
|
+
const logger = require('services/logger')
|
|
148
163
|
|
|
149
164
|
exports.productService = {
|
|
150
165
|
getAll: async function(filters = {}) {
|
|
@@ -196,18 +211,18 @@ exports.productService = {
|
|
|
196
211
|
```xml
|
|
197
212
|
<!-- views/products/list.xml -->
|
|
198
213
|
<Alloy>
|
|
199
|
-
<Window
|
|
200
|
-
<ListView id="listView"
|
|
214
|
+
<Window id="productsWindow">
|
|
215
|
+
<ListView id="listView">
|
|
201
216
|
<RefreshControl id="refresh" onRefresh="onRefresh" />
|
|
202
217
|
|
|
203
218
|
<Templates>
|
|
204
219
|
<ItemTemplate name="product" height="80">
|
|
205
|
-
<View
|
|
206
|
-
<ImageView bindId="image"
|
|
207
|
-
<View
|
|
208
|
-
<Label bindId="name"
|
|
209
|
-
<Label bindId="price"
|
|
210
|
-
<Label bindId="stock"
|
|
220
|
+
<View id="productRow">
|
|
221
|
+
<ImageView bindId="image" id="productImg" />
|
|
222
|
+
<View id="productInfo">
|
|
223
|
+
<Label bindId="name" id="productName" />
|
|
224
|
+
<Label bindId="price" id="productPrice" />
|
|
225
|
+
<Label bindId="stock" id="productStock" />
|
|
211
226
|
</View>
|
|
212
227
|
</View>
|
|
213
228
|
</ItemTemplate>
|
|
@@ -223,20 +238,28 @@ exports.productService = {
|
|
|
223
238
|
</ListSection>
|
|
224
239
|
</ListView>
|
|
225
240
|
|
|
226
|
-
<Button id="addBtn"
|
|
227
|
-
class="bg-primary rounded-full-14 absolute bottom-6 right-6 shadow-lg"
|
|
228
|
-
onClick="onAddProduct"
|
|
229
|
-
>
|
|
230
|
-
<Label class="fa-solid fa-plus text-xl text-white" />
|
|
231
|
-
</Button>
|
|
241
|
+
<Button id="addBtn" onClick="onAddProduct" title="+" />
|
|
232
242
|
</Window>
|
|
233
243
|
</Alloy>
|
|
234
244
|
```
|
|
235
245
|
|
|
246
|
+
```tss
|
|
247
|
+
/* styles/products/list.tss */
|
|
248
|
+
"#productsWindow": { backgroundColor: '#f9fafb' }
|
|
249
|
+
"#listView": { width: Ti.UI.FILL, height: Ti.UI.FILL }
|
|
250
|
+
"#productRow": { layout: 'horizontal', bottom: 8, height: 80, width: Ti.UI.FILL, backgroundColor: '#fff' }
|
|
251
|
+
"#productImg": { left: 12, width: 64, height: 64, borderRadius: 8 }
|
|
252
|
+
"#productInfo": { layout: 'vertical', left: 12 }
|
|
253
|
+
"#productName": { font: { fontSize: 16, fontWeight: 'semibold' } }
|
|
254
|
+
"#productPrice": { font: { fontSize: 14 }, color: '#16a34a' }
|
|
255
|
+
"#productStock": { font: { fontSize: 12 }, color: '#9ca3af' }
|
|
256
|
+
"#addBtn": { position: 'absolute', bottom: 24, right: 24, width: 56, height: 56, borderRadius: 28, backgroundColor: '#2563eb', color: '#fff', font: { fontSize: 24 } }
|
|
257
|
+
```
|
|
258
|
+
|
|
236
259
|
```javascript
|
|
237
260
|
// controllers/products/list.js
|
|
238
|
-
const { Navigation } = require('
|
|
239
|
-
const { productService } = require('
|
|
261
|
+
const { Navigation } = require('services/navigation')
|
|
262
|
+
const { productService } = require('services/productService')
|
|
240
263
|
|
|
241
264
|
function init() {
|
|
242
265
|
loadProducts()
|
|
@@ -283,39 +306,50 @@ $.cleanup = cleanup
|
|
|
283
306
|
```xml
|
|
284
307
|
<!-- views/contacts/list.xml -->
|
|
285
308
|
<Alloy>
|
|
286
|
-
<Window
|
|
309
|
+
<Window id="contactsWindow">
|
|
287
310
|
<!-- Search and Filter Bar -->
|
|
288
|
-
<View
|
|
311
|
+
<View id="searchFilterBar">
|
|
289
312
|
<SearchBar id="searchBar"
|
|
290
|
-
class="h-10 w-8/12"
|
|
291
313
|
hintText="L('search')"
|
|
292
314
|
showCancel="true"
|
|
293
315
|
/>
|
|
294
316
|
<Button id="filterBtn"
|
|
295
|
-
class="h-10 w-4/12"
|
|
296
317
|
title="L('filter')"
|
|
297
318
|
onClick="showFilters"
|
|
298
319
|
/>
|
|
299
320
|
</View>
|
|
300
321
|
|
|
301
322
|
<!-- Active Filters -->
|
|
302
|
-
<ScrollView id="filterTags"
|
|
323
|
+
<ScrollView id="filterTags">
|
|
303
324
|
<!-- Dynamically populated filter tags -->
|
|
304
325
|
</ScrollView>
|
|
305
326
|
|
|
306
|
-
<ListView id="listView"
|
|
327
|
+
<ListView id="listView">
|
|
307
328
|
<ListSection id="section" />
|
|
308
329
|
</ListView>
|
|
309
330
|
|
|
310
331
|
<!-- Empty State -->
|
|
311
|
-
<View id="emptyState"
|
|
312
|
-
<
|
|
313
|
-
<Label
|
|
332
|
+
<View id="emptyState">
|
|
333
|
+
<ImageView id="emptyIcon" image="/images/search.png" />
|
|
334
|
+
<Label id="emptyLabel" text="L('no_results')" />
|
|
314
335
|
</View>
|
|
315
336
|
</Window>
|
|
316
337
|
</Alloy>
|
|
317
338
|
```
|
|
318
339
|
|
|
340
|
+
```tss
|
|
341
|
+
/* styles/contacts/list.tss */
|
|
342
|
+
"#contactsWindow": { backgroundColor: '#fff' }
|
|
343
|
+
"#searchFilterBar": { layout: 'horizontal', height: 56, width: Ti.UI.FILL, backgroundColor: '#f3f4f6' }
|
|
344
|
+
"#searchBar": { height: 40, width: '66%' }
|
|
345
|
+
"#filterBtn": { height: 40, width: '34%' }
|
|
346
|
+
"#filterTags": { layout: 'horizontal', height: 40, width: Ti.UI.FILL, visible: false }
|
|
347
|
+
"#listView": { width: Ti.UI.FILL, height: Ti.UI.FILL }
|
|
348
|
+
"#emptyState": { layout: 'vertical', width: Ti.UI.FILL, height: Ti.UI.FILL, visible: false }
|
|
349
|
+
"#emptyIcon": { top: 80, width: 64, height: 64 }
|
|
350
|
+
"#emptyLabel": { top: 16, font: { fontSize: 18 }, color: '#6b7280' }
|
|
351
|
+
```
|
|
352
|
+
|
|
319
353
|
```javascript
|
|
320
354
|
// controllers/contacts/list.js
|
|
321
355
|
let allItems = []
|
|
@@ -426,73 +460,70 @@ $.cleanup = cleanup
|
|
|
426
460
|
```xml
|
|
427
461
|
<!-- views/auth/register.xml -->
|
|
428
462
|
<Alloy>
|
|
429
|
-
<Window
|
|
430
|
-
<ScrollView
|
|
431
|
-
<View
|
|
463
|
+
<Window id="registerWindow">
|
|
464
|
+
<ScrollView id="scrollView" contentHeight="Ti.UI.SIZE">
|
|
465
|
+
<View id="formContainer">
|
|
432
466
|
<!-- Logo -->
|
|
433
|
-
<ImageView
|
|
467
|
+
<ImageView id="logo" image="/images/logo.png" />
|
|
434
468
|
|
|
435
469
|
<!-- Title -->
|
|
436
|
-
<Label
|
|
470
|
+
<Label id="titleLabel" text="L('create_account')" />
|
|
437
471
|
|
|
438
472
|
<!-- Name Field -->
|
|
439
|
-
<View
|
|
440
|
-
<Label
|
|
441
|
-
<TextField id="nameField"
|
|
442
|
-
|
|
443
|
-
autocorrect="false"
|
|
473
|
+
<View id="nameGroup">
|
|
474
|
+
<Label id="nameLabel" text="L('full_name')" />
|
|
475
|
+
<TextField id="nameField" autocorrect="false"
|
|
476
|
+
returnKeyType="Ti.UI.RETURNKEY_NEXT"
|
|
444
477
|
/>
|
|
445
|
-
<Label id="nameError"
|
|
478
|
+
<Label id="nameError" />
|
|
446
479
|
</View>
|
|
447
480
|
|
|
448
481
|
<!-- Email Field -->
|
|
449
|
-
<View
|
|
450
|
-
<Label
|
|
482
|
+
<View id="emailGroup">
|
|
483
|
+
<Label id="emailLabel" text="L('email')" />
|
|
451
484
|
<TextField id="emailField"
|
|
452
|
-
|
|
485
|
+
keyboardType="Ti.UI.KEYBOARD_TYPE_EMAIL"
|
|
486
|
+
returnKeyType="Ti.UI.RETURNKEY_NEXT"
|
|
453
487
|
autocapitalization="none"
|
|
454
488
|
/>
|
|
455
|
-
<Label id="emailError"
|
|
489
|
+
<Label id="emailError" />
|
|
456
490
|
</View>
|
|
457
491
|
|
|
458
492
|
<!-- Password Field -->
|
|
459
|
-
<View
|
|
460
|
-
<Label
|
|
461
|
-
<TextField id="passwordField"
|
|
462
|
-
|
|
463
|
-
passwordMask="true"
|
|
493
|
+
<View id="passwordGroup">
|
|
494
|
+
<Label id="passwordLabel" text="L('password')" />
|
|
495
|
+
<TextField id="passwordField" passwordMask="true"
|
|
496
|
+
returnKeyType="Ti.UI.RETURNKEY_NEXT"
|
|
464
497
|
/>
|
|
465
|
-
<Label id="passwordError"
|
|
466
|
-
<Label
|
|
498
|
+
<Label id="passwordError" />
|
|
499
|
+
<Label id="passwordHint" text="L('password_hint')" />
|
|
467
500
|
</View>
|
|
468
501
|
|
|
469
502
|
<!-- Confirm Password -->
|
|
470
|
-
<View
|
|
471
|
-
<Label
|
|
472
|
-
<TextField id="confirmField"
|
|
473
|
-
|
|
474
|
-
passwordMask="true"
|
|
503
|
+
<View id="confirmGroup">
|
|
504
|
+
<Label id="confirmLabel" text="L('confirm_password')" />
|
|
505
|
+
<TextField id="confirmField" passwordMask="true"
|
|
506
|
+
returnKeyType="Ti.UI.RETURNKEY_DONE"
|
|
475
507
|
/>
|
|
476
|
-
<Label id="confirmError"
|
|
508
|
+
<Label id="confirmError" />
|
|
477
509
|
</View>
|
|
478
510
|
|
|
479
511
|
<!-- Terms Checkbox -->
|
|
480
|
-
<View
|
|
481
|
-
<Switch id="termsSwitch"
|
|
482
|
-
<Label
|
|
512
|
+
<View id="termsRow">
|
|
513
|
+
<Switch id="termsSwitch" />
|
|
514
|
+
<Label id="termsLabel" text="L('accept_terms')" />
|
|
483
515
|
</View>
|
|
484
516
|
|
|
485
517
|
<!-- Register Button -->
|
|
486
518
|
<Button id="registerBtn"
|
|
487
|
-
class="bg-primary mx-4 mt-6 h-14 w-screen rounded-xl font-bold text-white"
|
|
488
519
|
title="L('register')"
|
|
489
520
|
onClick="onRegister"
|
|
490
521
|
/>
|
|
491
522
|
|
|
492
523
|
<!-- Login Link -->
|
|
493
|
-
<View
|
|
494
|
-
<Label
|
|
495
|
-
<Label
|
|
524
|
+
<View id="loginRow">
|
|
525
|
+
<Label id="haveAccountLabel" text="L('have_account')" />
|
|
526
|
+
<Label id="loginLink" text="L('login')" onClick="goToLogin" />
|
|
496
527
|
</View>
|
|
497
528
|
</View>
|
|
498
529
|
</ScrollView>
|
|
@@ -500,10 +531,38 @@ $.cleanup = cleanup
|
|
|
500
531
|
</Alloy>
|
|
501
532
|
```
|
|
502
533
|
|
|
534
|
+
```tss
|
|
535
|
+
/* styles/auth/register.tss */
|
|
536
|
+
"#registerWindow": { layout: 'vertical', backgroundColor: '#fff' }
|
|
537
|
+
"#scrollView": { layout: 'vertical', width: Ti.UI.FILL, height: Ti.UI.FILL }
|
|
538
|
+
"#formContainer": { layout: 'vertical', top: 32, height: Ti.UI.SIZE, width: Ti.UI.FILL }
|
|
539
|
+
"#logo": { width: 96, height: 96 }
|
|
540
|
+
"#titleLabel": { top: 24, font: { fontSize: 24, fontWeight: 'bold' } }
|
|
541
|
+
".fieldGroup": { layout: 'vertical', left: 16, right: 16, top: 16, width: Ti.UI.FILL }
|
|
542
|
+
"#nameGroup": { layout: 'vertical', left: 16, right: 16, top: 24, width: Ti.UI.FILL }
|
|
543
|
+
"#emailGroup": { layout: 'vertical', left: 16, right: 16, top: 16, width: Ti.UI.FILL }
|
|
544
|
+
"#passwordGroup": { layout: 'vertical', left: 16, right: 16, top: 16, width: Ti.UI.FILL }
|
|
545
|
+
"#confirmGroup": { layout: 'vertical', left: 16, right: 16, top: 16, width: Ti.UI.FILL }
|
|
546
|
+
"Label": { font: { fontSize: 14 }, color: '#4b5563' }
|
|
547
|
+
"TextField": { top: 4, height: 48, width: Ti.UI.FILL, borderRadius: 8, borderWidth: 1, borderColor: '#d1d5db', paddingLeft: 12 }
|
|
548
|
+
"#nameError": { top: 4, font: { fontSize: 12 }, color: '#ef4444', visible: false }
|
|
549
|
+
"#emailError": { top: 4, font: { fontSize: 12 }, color: '#ef4444', visible: false }
|
|
550
|
+
"#passwordError": { top: 4, font: { fontSize: 12 }, color: '#ef4444', visible: false }
|
|
551
|
+
"#passwordHint": { top: 4, font: { fontSize: 12 }, color: '#9ca3af' }
|
|
552
|
+
"#confirmError": { top: 4, font: { fontSize: 12 }, color: '#ef4444', visible: false }
|
|
553
|
+
"#termsRow": { layout: 'horizontal', left: 16, right: 16, top: 24, width: Ti.UI.FILL }
|
|
554
|
+
"#termsSwitch": { width: 48 }
|
|
555
|
+
"#termsLabel": { left: 8 }
|
|
556
|
+
"#registerBtn": { left: 16, right: 16, top: 24, height: 56, borderRadius: 12, backgroundColor: '#2563eb', color: '#fff', font: { fontWeight: 'bold' } }
|
|
557
|
+
"#loginRow": { layout: 'horizontal', top: 16 }
|
|
558
|
+
"#haveAccountLabel": { font: { fontSize: 14 }, color: '#4b5563' }
|
|
559
|
+
"#loginLink": { left: 4, font: { fontSize: 14 }, color: '#2563eb' }
|
|
560
|
+
```
|
|
561
|
+
|
|
503
562
|
```javascript
|
|
504
563
|
// controllers/auth/register.js
|
|
505
|
-
const { AuthService } = require('
|
|
506
|
-
const { Navigation } = require('
|
|
564
|
+
const { AuthService } = require('services/authService')
|
|
565
|
+
const { Navigation } = require('services/navigation')
|
|
507
566
|
|
|
508
567
|
const validators = {
|
|
509
568
|
name: (value) => {
|
|
@@ -642,7 +701,7 @@ $.cleanup = cleanup
|
|
|
642
701
|
```xml
|
|
643
702
|
<!-- views/main.xml -->
|
|
644
703
|
<Alloy>
|
|
645
|
-
<TabGroup id="tabGroup"
|
|
704
|
+
<TabGroup id="tabGroup">
|
|
646
705
|
|
|
647
706
|
<Tab id="homeTab" title="L('home')" icon="/images/icons/home.png">
|
|
648
707
|
<Require src="tabs/home" />
|
|
@@ -665,7 +724,7 @@ $.cleanup = cleanup
|
|
|
665
724
|
|
|
666
725
|
```javascript
|
|
667
726
|
// controllers/main.js
|
|
668
|
-
const EventBus = require('
|
|
727
|
+
const EventBus = require('services/eventBus')
|
|
669
728
|
const Events = EventBus.Events
|
|
670
729
|
|
|
671
730
|
function init() {
|
|
@@ -4,59 +4,61 @@
|
|
|
4
4
|
|
|
5
5
|
Before migrating, evaluate the current codebase:
|
|
6
6
|
|
|
7
|
-
| Area | Signs of Legacy Code | Target State
|
|
8
|
-
| ----------- | -------------------------------------------------- |
|
|
9
|
-
| Styling |
|
|
10
|
-
| Controllers | 200+ lines, API calls, business logic | Thin orchestrators (<100 lines)
|
|
11
|
-
| Events | `Ti.App.fireEvent` everywhere | Backbone.Events or StateStore
|
|
12
|
-
| Navigation | Direct `Alloy.createController().getView().open()` | Navigation service
|
|
13
|
-
| Data | Scattered `Ti.App.Properties`, no collections | Centralized state + Collections
|
|
7
|
+
| Area | Signs of Legacy Code | Target State |
|
|
8
|
+
| ----------- | -------------------------------------------------- | --------------------------------------------- |
|
|
9
|
+
| Styling | Inline attributes, scattered styles | Organized TSS files (per-controller + global) |
|
|
10
|
+
| Controllers | 200+ lines, API calls, business logic | Thin orchestrators (<100 lines) |
|
|
11
|
+
| Events | `Ti.App.fireEvent` everywhere | Backbone.Events or StateStore |
|
|
12
|
+
| Navigation | Direct `Alloy.createController().getView().open()` | Navigation service |
|
|
13
|
+
| Data | Scattered `Ti.App.Properties`, no collections | Centralized state + Collections |
|
|
14
14
|
|
|
15
|
-
## Phase 1:
|
|
15
|
+
## Phase 1: TSS Organization
|
|
16
16
|
|
|
17
|
-
**Goal**: Migrate from
|
|
17
|
+
**Goal**: Migrate from inline styling and scattered styles to well-organized TSS files.
|
|
18
18
|
|
|
19
|
-
### Step 1:
|
|
19
|
+
### Step 1: Audit Existing Styles
|
|
20
20
|
|
|
21
|
+
Find all inline attributes and consolidate into TSS files:
|
|
21
22
|
```bash
|
|
22
|
-
#
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
# Find inline styling in XML views
|
|
24
|
+
grep -r 'backgroundColor=' app/views/
|
|
25
|
+
grep -r 'font=' app/views/
|
|
26
|
+
grep -r 'color=' app/views/
|
|
25
27
|
```
|
|
26
28
|
|
|
27
|
-
### Step 2:
|
|
29
|
+
### Step 2: Move Inline Attributes to TSS
|
|
28
30
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
```xml
|
|
32
|
+
<!-- BEFORE: Inline attributes -->
|
|
33
|
+
<View id="header" backgroundColor="#fff" height="60" top="0">
|
|
34
|
+
<Label id="title" text="Welcome" color="#333" font="{fontSize:18, fontWeight:'bold'}" />
|
|
35
|
+
</View>
|
|
36
|
+
```
|
|
32
37
|
|
|
33
38
|
```xml
|
|
34
|
-
<!--
|
|
39
|
+
<!-- AFTER: Clean XML + TSS file -->
|
|
35
40
|
<View id="header">
|
|
36
|
-
<Label id="title" text="
|
|
41
|
+
<Label id="title" text="L('welcome')" />
|
|
37
42
|
</View>
|
|
43
|
+
```
|
|
38
44
|
|
|
39
|
-
|
|
45
|
+
```tss
|
|
46
|
+
/* styles/index.tss */
|
|
40
47
|
"#header": { backgroundColor: "#fff", height: 60, top: 0 }
|
|
41
48
|
"#title": { color: "#333", font: { fontSize: 18, fontWeight: "bold" } }
|
|
42
49
|
```
|
|
43
50
|
|
|
44
|
-
|
|
45
|
-
<!-- AFTER: PurgeTSS classes -->
|
|
46
|
-
<View class="top-0 h-16 bg-white">
|
|
47
|
-
<Label class="text-lg font-bold text-gray-800" text="Welcome" />
|
|
48
|
-
</View>
|
|
51
|
+
### Step 3: Organize TSS Structure
|
|
49
52
|
|
|
50
|
-
|
|
53
|
+
1. Use `app.tss` for global styles (shared across all views)
|
|
54
|
+
2. Use per-controller TSS files for view-specific styles
|
|
55
|
+
3. Use class selectors for reusable style patterns:
|
|
56
|
+
```tss
|
|
57
|
+
/* app.tss - Global reusable styles */
|
|
58
|
+
".card": { borderRadius: 12, backgroundColor: '#fff' }
|
|
59
|
+
".btn-primary": { backgroundColor: '#2563eb', color: '#fff', height: 44, borderRadius: 8 }
|
|
51
60
|
```
|
|
52
61
|
|
|
53
|
-
### Step 4: Remove Manual TSS Files
|
|
54
|
-
|
|
55
|
-
Once a view is fully migrated to utility classes:
|
|
56
|
-
1. Remove corresponding entries from `_app.tss`
|
|
57
|
-
2. Delete any controller-specific `.tss` files
|
|
58
|
-
3. Run `purgetss` to regenerate `app.tss`
|
|
59
|
-
|
|
60
62
|
## Phase 2: Service Layer Extraction
|
|
61
63
|
|
|
62
64
|
**Goal**: Move business logic from controllers to services.
|
|
@@ -221,7 +223,7 @@ exports.getStack = function() {
|
|
|
221
223
|
Alloy.createController('detail', { id: 123 }).getView().open()
|
|
222
224
|
|
|
223
225
|
// AFTER: Navigation service (auto cleanup)
|
|
224
|
-
const navigation = require('
|
|
226
|
+
const navigation = require('services/navigation')
|
|
225
227
|
navigation.open('detail', { id: 123 })
|
|
226
228
|
```
|
|
227
229
|
|
|
@@ -252,7 +254,7 @@ const user = JSON.parse(Ti.App.Properties.getString('user'))
|
|
|
252
254
|
|
|
253
255
|
// AFTER: Centralized state
|
|
254
256
|
// In service
|
|
255
|
-
const { appStore } = require('
|
|
257
|
+
const { appStore } = require('services/stateStore')
|
|
256
258
|
appStore.setState({ user })
|
|
257
259
|
|
|
258
260
|
// In any controller
|
|
@@ -263,7 +265,7 @@ const { user } = appStore.getState()
|
|
|
263
265
|
|
|
264
266
|
Recommended sequence to minimize risk:
|
|
265
267
|
|
|
266
|
-
1. **
|
|
268
|
+
1. **TSS Organization** - Visual only, no logic changes
|
|
267
269
|
2. **Service Layer** - Extract logic without changing behavior
|
|
268
270
|
3. **Navigation Service** - Centralize with cleanup
|
|
269
271
|
4. **Event System** - Replace Ti.App events
|
|
@@ -104,10 +104,10 @@ exports.UserRepository = {
|
|
|
104
104
|
|
|
105
105
|
```javascript
|
|
106
106
|
// lib/services/authService.js
|
|
107
|
-
const authApi = require('
|
|
108
|
-
const { TokenStorage } = require('
|
|
109
|
-
const { appStore } = require('
|
|
110
|
-
const { Validator } = require('
|
|
107
|
+
const authApi = require('api/authApi').authApi
|
|
108
|
+
const { TokenStorage } = require('services/tokenStorage')
|
|
109
|
+
const { appStore } = require('services/stateStore')
|
|
110
|
+
const { Validator } = require('helpers/validator')
|
|
111
111
|
|
|
112
112
|
exports.AuthService = {
|
|
113
113
|
async login(email, password) {
|
|
@@ -175,7 +175,7 @@ module.exports.Events = Events
|
|
|
175
175
|
|
|
176
176
|
```javascript
|
|
177
177
|
// controllers/profile.js
|
|
178
|
-
const EventBus = require('
|
|
178
|
+
const EventBus = require('services/eventBus')
|
|
179
179
|
const { Events } = EventBus
|
|
180
180
|
|
|
181
181
|
function init() {
|
|
@@ -339,7 +339,7 @@ $.cleanup = cleanup
|
|
|
339
339
|
|
|
340
340
|
```xml
|
|
341
341
|
<!-- views/products/list.xml -->
|
|
342
|
-
<ListView
|
|
342
|
+
<ListView id="listView">
|
|
343
343
|
<ListSection dataCollection="products">
|
|
344
344
|
<ListItem title="{name}" subtitle="{description}" />
|
|
345
345
|
</ListSection>
|
|
@@ -352,9 +352,9 @@ $.cleanup = cleanup
|
|
|
352
352
|
|
|
353
353
|
```javascript
|
|
354
354
|
// controllers/dashboard.js
|
|
355
|
-
const EventBus = require('
|
|
355
|
+
const EventBus = require('services/eventBus')
|
|
356
356
|
const { Events } = EventBus
|
|
357
|
-
const { appStore } = require('
|
|
357
|
+
const { appStore } = require('services/stateStore')
|
|
358
358
|
|
|
359
359
|
// Store references for cleanup
|
|
360
360
|
let storeUnsubscribe = null
|