openuispec 0.2.8 → 0.2.10
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/README.md +50 -385
- package/cli/index.ts +77 -1
- package/cli/init.ts +9 -4
- package/docs/cli.md +160 -0
- package/docs/file-formats.md +84 -0
- package/examples/taskflow/generated/ios/TaskFlow/project.yml +5 -0
- package/examples/todo-orbit/generated/ios/Todo Orbit/TodoOrbit.xcodeproj/project.pbxproj +45 -6
- package/examples/todo-orbit/generated/ios/Todo Orbit/TodoOrbit.xcodeproj/xcshareddata/xcschemes/TodoOrbit.xcscheme +89 -0
- package/examples/todo-orbit/generated/ios/Todo Orbit/project.yml +13 -6
- package/mcp-server/index.ts +94 -3
- package/mcp-server/screenshot-android.ts +199 -65
- package/mcp-server/screenshot-ios.ts +242 -30
- package/mcp-server/screenshot.ts +80 -0
- package/package.json +1 -1
package/cli/init.ts
CHANGED
|
@@ -558,7 +558,7 @@ const JSON_MCP_PATHS = [
|
|
|
558
558
|
const CODEX_CONFIG_PATH = join(".codex", "config.toml");
|
|
559
559
|
const CODEX_MCP_BLOCK = `\n[mcp_servers.openuispec]\ncommand = "openuispec"\nargs = ["mcp"]\n`;
|
|
560
560
|
|
|
561
|
-
function configureCodexMcp(cwd: string, quiet: boolean):
|
|
561
|
+
function configureCodexMcp(cwd: string, quiet: boolean): boolean {
|
|
562
562
|
const codexDir = join(cwd, ".codex");
|
|
563
563
|
|
|
564
564
|
const configPath = join(codexDir, "config.toml");
|
|
@@ -572,18 +572,22 @@ function configureCodexMcp(cwd: string, quiet: boolean): void {
|
|
|
572
572
|
|
|
573
573
|
if (content.includes("[mcp_servers.openuispec]")) {
|
|
574
574
|
if (!quiet) console.log(` skip ${CODEX_CONFIG_PATH} (openuispec MCP already configured)`);
|
|
575
|
-
return;
|
|
575
|
+
return false;
|
|
576
576
|
}
|
|
577
577
|
|
|
578
578
|
if (!existsSync(codexDir)) mkdirSync(codexDir);
|
|
579
579
|
writeFileSync(configPath, content + CODEX_MCP_BLOCK);
|
|
580
580
|
if (!quiet) console.log(` ${content ? "update" : "create"} ${CODEX_CONFIG_PATH} (MCP server configured)`);
|
|
581
|
+
return true;
|
|
581
582
|
} catch {
|
|
582
583
|
if (!quiet) console.log(` skip ${CODEX_CONFIG_PATH} (could not configure MCP server)`);
|
|
584
|
+
return false;
|
|
583
585
|
}
|
|
584
586
|
}
|
|
585
587
|
|
|
586
588
|
function configureMcp(cwd: string, showRestart: boolean, quiet: boolean = false): void {
|
|
589
|
+
let changed = false;
|
|
590
|
+
|
|
587
591
|
for (const relPath of JSON_MCP_PATHS) {
|
|
588
592
|
const configPath = join(cwd, relPath);
|
|
589
593
|
|
|
@@ -611,6 +615,7 @@ function configureMcp(cwd: string, showRestart: boolean, quiet: boolean = false)
|
|
|
611
615
|
config.mcpServers.openuispec = { ...EXPECTED_MCP_CONFIG };
|
|
612
616
|
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
613
617
|
if (!quiet) console.log(` ${existing ? "update" : "create"} ${relPath} (MCP server configured)`);
|
|
618
|
+
changed = true;
|
|
614
619
|
} else {
|
|
615
620
|
if (!quiet) console.log(` skip ${relPath} (openuispec MCP already configured)`);
|
|
616
621
|
}
|
|
@@ -620,9 +625,9 @@ function configureMcp(cwd: string, showRestart: boolean, quiet: boolean = false)
|
|
|
620
625
|
}
|
|
621
626
|
|
|
622
627
|
// Codex: .codex/config.toml (TOML format)
|
|
623
|
-
configureCodexMcp(cwd, quiet);
|
|
628
|
+
if (configureCodexMcp(cwd, quiet)) changed = true;
|
|
624
629
|
|
|
625
|
-
if (showRestart) console.log(`\n Restart your AI coding agent to activate the MCP server.`);
|
|
630
|
+
if (showRestart && changed) console.log(`\n Restart your AI coding agent to activate the MCP server.`);
|
|
626
631
|
|
|
627
632
|
// Clean up stale .claude.json MCP config from older versions
|
|
628
633
|
const claudeJsonPath = join(cwd, ".claude.json");
|
package/docs/cli.md
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# CLI & MCP Tools Reference
|
|
2
|
+
|
|
3
|
+
All MCP tools have equivalent CLI commands. The MCP server is used by AI coding agents automatically; the CLI is for manual use and scripts.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
`openuispec init` and `openuispec update-rules` automatically configure MCP for all supported agents:
|
|
8
|
+
|
|
9
|
+
| Agent | Config file | Created automatically |
|
|
10
|
+
|-------|------------|----------------------|
|
|
11
|
+
| **Claude Code** | `.mcp.json` | Always |
|
|
12
|
+
| **Codex** | `.codex/config.toml` | Always |
|
|
13
|
+
| **VS Code / Copilot** | `.vscode/mcp.json` | If `.vscode/` exists |
|
|
14
|
+
| **Gemini CLI** | `.gemini/settings.json` | If `.gemini/` exists |
|
|
15
|
+
|
|
16
|
+
Manual setup (if needed):
|
|
17
|
+
|
|
18
|
+
**Claude Code** (`.mcp.json`), **VS Code / Copilot** (`.vscode/mcp.json`), **Gemini CLI** (`.gemini/settings.json`):
|
|
19
|
+
```json
|
|
20
|
+
{
|
|
21
|
+
"mcpServers": {
|
|
22
|
+
"openuispec": {
|
|
23
|
+
"command": "openuispec",
|
|
24
|
+
"args": ["mcp"]
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**Codex** (`.codex/config.toml`):
|
|
31
|
+
```toml
|
|
32
|
+
[mcp_servers.openuispec]
|
|
33
|
+
command = "openuispec"
|
|
34
|
+
args = ["mcp"]
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Or run directly: `openuispec mcp`
|
|
38
|
+
|
|
39
|
+
## MCP Tools
|
|
40
|
+
|
|
41
|
+
| Tool | When | What it does |
|
|
42
|
+
|------|------|-------------|
|
|
43
|
+
| `openuispec_spec_types` | Before creating spec files | Lists all available spec types with descriptions |
|
|
44
|
+
| `openuispec_spec_schema` | Before creating/editing spec files | Returns the full JSON schema for a specific spec type |
|
|
45
|
+
| `openuispec_prepare` | Before UI code generation | Returns spec context, platform config, generation constraints |
|
|
46
|
+
| `openuispec_read_specs` | Before and after generation | Loads spec file contents — the authoritative source |
|
|
47
|
+
| `openuispec_check` | After generation | Schema validation + concrete audit checklist. Optional `screens`/`contracts` params scope the audit |
|
|
48
|
+
| `openuispec_validate` | After spec edits | Schema-only validation, optionally filtered by group |
|
|
49
|
+
| `openuispec_drift` | Before updates | Detect spec drift since last snapshot, with semantic explanation |
|
|
50
|
+
| `openuispec_status` | Anytime | Cross-target summary: baselines, drift, next steps |
|
|
51
|
+
| `openuispec_get_screen` | Incremental edits | Get a single screen spec by name |
|
|
52
|
+
| `openuispec_get_contract` | Incremental edits | Get a single contract spec, optionally filtered to one variant |
|
|
53
|
+
| `openuispec_get_tokens` | Incremental edits | Get tokens for a specific category |
|
|
54
|
+
| `openuispec_get_locale` | Incremental edits | Get a single locale file, optionally filtered to specific keys |
|
|
55
|
+
| `openuispec_screenshot` | Visual verification | Screenshot the web app at a route via headless browser |
|
|
56
|
+
| `openuispec_screenshot_android` | Visual verification | Screenshot Android app on emulator. Works with any project via `project_dir` |
|
|
57
|
+
| `openuispec_screenshot_ios` | Visual verification | Screenshot iOS app on Simulator via XCUITest. Works with any project via `project_dir` |
|
|
58
|
+
|
|
59
|
+
The server includes **protocol-level instructions** that trigger on UI-related requests independently of CLAUDE.md rules.
|
|
60
|
+
|
|
61
|
+
## CLI Commands
|
|
62
|
+
|
|
63
|
+
### Workflow
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
openuispec init # Scaffold a new spec project
|
|
67
|
+
openuispec init --defaults # Non-interactive with unconfirmed defaults
|
|
68
|
+
openuispec init --no-configure-targets # Skip target stack setup
|
|
69
|
+
openuispec update-rules # Update AI rules to match installed version
|
|
70
|
+
openuispec configure-target <t> [--defaults] # Configure target stack
|
|
71
|
+
openuispec validate [group...] [--json] # Validate spec files
|
|
72
|
+
openuispec validate semantic # Semantic cross-reference linting
|
|
73
|
+
openuispec status [--json] # Cross-target baseline/drift status
|
|
74
|
+
openuispec drift --target <t> --explain # Explain semantic spec drift
|
|
75
|
+
openuispec prepare --target <t> [--json] # Build the target work bundle
|
|
76
|
+
openuispec check --target <t> [--json] # Composite validation + prepare readiness
|
|
77
|
+
openuispec drift --snapshot --target <t> # Snapshot current state + git baseline
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Spec access
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
openuispec read-specs [paths...] # Read spec file contents as JSON
|
|
84
|
+
openuispec get-screen <name> # Get a single screen spec (YAML)
|
|
85
|
+
openuispec get-contract <name> [--variant v] # Get a contract spec
|
|
86
|
+
openuispec get-tokens <category> # Get tokens for a category (YAML)
|
|
87
|
+
openuispec get-locale <locale> [--keys k1,k2] # Get a locale file (JSON)
|
|
88
|
+
openuispec spec-types # List available spec types
|
|
89
|
+
openuispec spec-schema <type> # Get JSON schema for a spec type
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Screenshots
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
# Single captures
|
|
96
|
+
openuispec screenshot --route /home [--theme dark] [--output-dir dir]
|
|
97
|
+
openuispec screenshot-android [--project-dir path] [--screen name] [--module name] [--route deeplink]
|
|
98
|
+
openuispec screenshot-ios [--project-dir path] [--screen name] [--scheme name] [--bundle-id id]
|
|
99
|
+
|
|
100
|
+
# Batch — build once, capture many
|
|
101
|
+
openuispec screenshot-web-batch --config captures.json [--theme dark] [--output-dir dir]
|
|
102
|
+
openuispec screenshot-android-batch --config captures.json [--project-dir path] [--module name]
|
|
103
|
+
openuispec screenshot-ios-batch --config captures.json [--project-dir path] [--scheme name] [--bundle-id id]
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Screenshot tools work with **any** project — use `--project-dir` to skip manifest lookup.
|
|
107
|
+
|
|
108
|
+
| Param | Android | iOS | Purpose |
|
|
109
|
+
|-------|---------|-----|---------|
|
|
110
|
+
| `--project-dir` | yes | yes | Point directly at project root |
|
|
111
|
+
| `--module` | yes | -- | Override app module name (default: auto-detect) |
|
|
112
|
+
| `--scheme` | -- | yes | Override Xcode scheme (default: auto-detect) |
|
|
113
|
+
| `--bundle-id` | -- | yes | Override bundle ID (default: auto-detect) |
|
|
114
|
+
| `--route` | yes | -- | Deep link URI for navigation |
|
|
115
|
+
| `--nav` | yes | yes | UI tap steps, comma-separated |
|
|
116
|
+
| `--theme` | yes | yes | Force light or dark mode |
|
|
117
|
+
| `--device` | -- | yes | Simulator device name |
|
|
118
|
+
| `--output-dir` | yes | yes | Save screenshot to directory |
|
|
119
|
+
|
|
120
|
+
### Batch config
|
|
121
|
+
|
|
122
|
+
All batch commands accept `--config captures.json`. The JSON file has the same structure for all platforms:
|
|
123
|
+
|
|
124
|
+
```json
|
|
125
|
+
{
|
|
126
|
+
"project_dir": "path/to/project",
|
|
127
|
+
"output_dir": "screenshots",
|
|
128
|
+
"theme": "light",
|
|
129
|
+
"captures": [
|
|
130
|
+
{ "screen": "home", "route": "/home", "wait_for": 3000 },
|
|
131
|
+
{ "screen": "settings", "nav": ["Settings"], "wait_for": 5000 }
|
|
132
|
+
]
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Each capture supports:
|
|
137
|
+
- `screen`: output filename stem (required)
|
|
138
|
+
- `route`: deep link URI (Android) or URL path (web)
|
|
139
|
+
- `nav`: array of visible-text tap steps after launch (Android, iOS)
|
|
140
|
+
- `wait_for`: per-capture wait time in ms
|
|
141
|
+
- `selector`: CSS selector to screenshot a specific element (web only)
|
|
142
|
+
- `full_page`: capture full scrollable page (web only)
|
|
143
|
+
|
|
144
|
+
## Target Update Workflow
|
|
145
|
+
|
|
146
|
+
When a shared spec change needs to be applied to a target:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
openuispec validate
|
|
150
|
+
openuispec validate semantic
|
|
151
|
+
openuispec status
|
|
152
|
+
openuispec drift --target ios --explain
|
|
153
|
+
openuispec prepare --target ios
|
|
154
|
+
# update the ios implementation
|
|
155
|
+
openuispec drift --snapshot --target ios
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
- `prepare` runs in `bootstrap` mode for first-time generation and `update` mode after a snapshot exists
|
|
159
|
+
- `drift --snapshot` is bookkeeping — it does not prove code matches the spec, and requires the output directory to exist
|
|
160
|
+
- Run `openuispec status` between targets to see what still needs updating
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# File Formats & Schemas
|
|
2
|
+
|
|
3
|
+
Every file type has a corresponding JSON Schema in `schema/`. **Read the schema before creating or editing a file** — do not guess the structure.
|
|
4
|
+
|
|
5
|
+
## File type reference
|
|
6
|
+
|
|
7
|
+
| File | Schema | Root key | Example |
|
|
8
|
+
|------|--------|----------|---------|
|
|
9
|
+
| `openuispec.yaml` | `openuispec.schema.json` | `spec_version` | [openuispec.yaml](../examples/taskflow/openuispec/openuispec.yaml) |
|
|
10
|
+
| `screens/*.yaml` | `screen.schema.json` | `<screen_id>` | [home.yaml](../examples/taskflow/openuispec/screens/home.yaml) |
|
|
11
|
+
| `flows/*.yaml` | `flow.schema.json` | `<flow_id>` | [create_task.yaml](../examples/taskflow/openuispec/flows/create_task.yaml) |
|
|
12
|
+
| `platform/*.yaml` | `platform.schema.json` | `platform` | [ios.yaml](../examples/taskflow/openuispec/platform/ios.yaml) |
|
|
13
|
+
| `locales/*.json` | `locale.schema.json` | (object) | [en.json](../examples/taskflow/openuispec/locales/en.json) |
|
|
14
|
+
| `contracts/<name>.yaml` | `contract.schema.json` | `<contract_name>` | [input_field.yaml](../examples/taskflow/openuispec/contracts/input_field.yaml) |
|
|
15
|
+
| `contracts/x_*.yaml` | `custom-contract.schema.json` | `<x_name>` | [x_media_player.yaml](../examples/taskflow/openuispec/contracts/x_media_player.yaml) |
|
|
16
|
+
| `tokens/color.yaml` | `tokens/color.schema.json` | `color` | [color.yaml](../examples/taskflow/openuispec/tokens/color.yaml) |
|
|
17
|
+
| `tokens/typography.yaml` | `tokens/typography.schema.json` | `typography` | [typography.yaml](../examples/taskflow/openuispec/tokens/typography.yaml) |
|
|
18
|
+
| `tokens/spacing.yaml` | `tokens/spacing.schema.json` | `spacing` | [spacing.yaml](../examples/taskflow/openuispec/tokens/spacing.yaml) |
|
|
19
|
+
| `tokens/elevation.yaml` | `tokens/elevation.schema.json` | `elevation` | [elevation.yaml](../examples/taskflow/openuispec/tokens/elevation.yaml) |
|
|
20
|
+
| `tokens/motion.yaml` | `tokens/motion.schema.json` | `motion` | [motion.yaml](../examples/taskflow/openuispec/tokens/motion.yaml) |
|
|
21
|
+
| `tokens/layout.yaml` | `tokens/layout.schema.json` | `layout` | [layout.yaml](../examples/taskflow/openuispec/tokens/layout.yaml) |
|
|
22
|
+
| `tokens/themes.yaml` | `tokens/themes.schema.json` | `themes` | [themes.yaml](../examples/taskflow/openuispec/tokens/themes.yaml) |
|
|
23
|
+
| `tokens/icons.yaml` | `tokens/icons.schema.json` | `icons` | [icons.yaml](../examples/taskflow/openuispec/tokens/icons.yaml) |
|
|
24
|
+
|
|
25
|
+
Every token file **must** have a single root wrapper key matching its type:
|
|
26
|
+
|
|
27
|
+
```yaml
|
|
28
|
+
# Correct — tokens/color.yaml
|
|
29
|
+
color:
|
|
30
|
+
brand:
|
|
31
|
+
primary: ...
|
|
32
|
+
|
|
33
|
+
# Wrong — missing root key
|
|
34
|
+
brand:
|
|
35
|
+
primary: ...
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Shared interactive state roles
|
|
39
|
+
|
|
40
|
+
Interactive contracts may optionally express state-specific visual roles inside their token maps with a nested `states:` object. This lets generators use explicit roles for `default`, `active`, `selected`, `pressed`, `focused`, `disabled`, `loading`, and `error` states.
|
|
41
|
+
|
|
42
|
+
Allowed visual role keys: `background`, `text`, `icon`, `border`, `badge_background`, `badge_text`.
|
|
43
|
+
|
|
44
|
+
When `states:` is omitted, generators fall back to the token values defined at that level plus the base contract semantics.
|
|
45
|
+
|
|
46
|
+
## Output directories
|
|
47
|
+
|
|
48
|
+
By default, drift stores state in `generated/<target>/<project>/`. To point targets to your actual code directories:
|
|
49
|
+
|
|
50
|
+
```yaml
|
|
51
|
+
generation:
|
|
52
|
+
targets: [ios, android, web]
|
|
53
|
+
output_dir:
|
|
54
|
+
web: "../web-ui/"
|
|
55
|
+
android: "../kmp-ui/"
|
|
56
|
+
ios: "../kmp-ui/iosApp/"
|
|
57
|
+
code_roots:
|
|
58
|
+
backend: "../api/"
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Paths are relative to `openuispec.yaml`. The `.openuispec-state.json` file records spec file hashes plus the git baseline commit metadata.
|
|
62
|
+
|
|
63
|
+
- If `api.endpoints` are declared, `generation.code_roots.backend` is required
|
|
64
|
+
- `generation.extra_rules` can hold project-wide generation conventions
|
|
65
|
+
- `drift --snapshot` requires that target output directory to already exist
|
|
66
|
+
|
|
67
|
+
## Spec sections overview
|
|
68
|
+
|
|
69
|
+
| Section | What it defines |
|
|
70
|
+
|---------|----------------|
|
|
71
|
+
| 1. Philosophy | Core principles: semantic, constrained, contract-driven, AI-first |
|
|
72
|
+
| 2. Document structure | Project layout and root manifest |
|
|
73
|
+
| 3. Token layer | Color, typography, spacing, elevation, motion, layout, themes, icons |
|
|
74
|
+
| 4. Component contracts | 7 behavioral families |
|
|
75
|
+
| 5. Screen composition | Contract-based layouts, adaptive layout system |
|
|
76
|
+
| 6. Navigation flows | Multi-screen journeys with transitions and progress |
|
|
77
|
+
| 7. Platform adaptation | Per-target overrides for iOS, Android, Web |
|
|
78
|
+
| 8. AI generation contract | Compliance levels (MUST/SHOULD/MAY), validation, drift detection |
|
|
79
|
+
| 9. Action system | 14 action types, composition, optimistic updates |
|
|
80
|
+
| 10. Data binding & state | Sources, paths, format expressions, reactivity, caching |
|
|
81
|
+
| 11. Internationalization | Locale files, `$t:` references, ICU MessageFormat, RTL |
|
|
82
|
+
| 12. Custom contract extensions | `x_` prefixed domain-specific contracts |
|
|
83
|
+
| 13. Form validation | Validation rules, field dependencies, cross-field checks |
|
|
84
|
+
| 14. Development workflow | Dual-workflow model, drift detection, spec as sync layer |
|
|
@@ -19,16 +19,19 @@
|
|
|
19
19
|
BC38D8705D84A35CA4597319 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB44040683A902497C58A015 /* SettingsView.swift */; };
|
|
20
20
|
C48B6CB49E4975FA1F6E375B /* TaskEditorSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18F27CD847E25814CF020BD2 /* TaskEditorSheet.swift */; };
|
|
21
21
|
C6106B18861BE3E491DF43E2 /* RecurringRuleSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2ECC34C8FF28EDDC9779648 /* RecurringRuleSheet.swift */; };
|
|
22
|
+
F1510F7B66940A31758A2561 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = BEE6DEA10F74F9459C452D3F /* Localizable.strings */; };
|
|
22
23
|
/* End PBXBuildFile section */
|
|
23
24
|
|
|
24
25
|
/* Begin PBXFileReference section */
|
|
25
26
|
1549DC459C5275175F9C14DA /* SchedulePreviewView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SchedulePreviewView.swift; sourceTree = "<group>"; };
|
|
26
27
|
18F27CD847E25814CF020BD2 /* TaskEditorSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskEditorSheet.swift; sourceTree = "<group>"; };
|
|
28
|
+
2B9B6454B5BB98B387C7B5C4 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = "<group>"; };
|
|
27
29
|
39885C677159185FF63FD439 /* TasksHomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TasksHomeView.swift; sourceTree = "<group>"; };
|
|
28
30
|
44D5BC7160E201639C3BB553 /* AppModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppModel.swift; sourceTree = "<group>"; };
|
|
29
31
|
4ED01AC556A631AD84466AB3 /* TrendChartView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrendChartView.swift; sourceTree = "<group>"; };
|
|
30
32
|
557759E88A2388894FA0C7BB /* TodoOrbit.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = TodoOrbit.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
31
33
|
6998ADDB28617F993A8C0457 /* TodoOrbitApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TodoOrbitApp.swift; sourceTree = "<group>"; };
|
|
34
|
+
6E3C87FA6CD54B76AEB1E84A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
|
|
32
35
|
7A697422498544CC5739C094 /* Charts.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Charts.framework; path = System/Library/Frameworks/Charts.framework; sourceTree = SDKROOT; };
|
|
33
36
|
8888C94EDF738EA4F84E3F63 /* AnalyticsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsView.swift; sourceTree = "<group>"; };
|
|
34
37
|
BB44040683A902497C58A015 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
|
|
@@ -86,6 +89,7 @@
|
|
|
86
89
|
20A8D65D5A36A0A1D83FC83B = {
|
|
87
90
|
isa = PBXGroup;
|
|
88
91
|
children = (
|
|
92
|
+
4E25DE308842C29211993157 /* Resources */,
|
|
89
93
|
F8B6569F634112DBF4BA31A0 /* TodoOrbit */,
|
|
90
94
|
2076B302B77DCDE399DBA8FE /* Frameworks */,
|
|
91
95
|
004F5B8035C988C3C942C7B6 /* Products */,
|
|
@@ -102,6 +106,14 @@
|
|
|
102
106
|
path = Components;
|
|
103
107
|
sourceTree = "<group>";
|
|
104
108
|
};
|
|
109
|
+
4E25DE308842C29211993157 /* Resources */ = {
|
|
110
|
+
isa = PBXGroup;
|
|
111
|
+
children = (
|
|
112
|
+
BEE6DEA10F74F9459C452D3F /* Localizable.strings */,
|
|
113
|
+
);
|
|
114
|
+
path = Resources;
|
|
115
|
+
sourceTree = "<group>";
|
|
116
|
+
};
|
|
105
117
|
59DB494C80FF64B9BB3FD8AF /* Models */ = {
|
|
106
118
|
isa = PBXGroup;
|
|
107
119
|
children = (
|
|
@@ -149,6 +161,7 @@
|
|
|
149
161
|
buildConfigurationList = 8F4D2BE44A3854271D9C066F /* Build configuration list for PBXNativeTarget "TodoOrbit" */;
|
|
150
162
|
buildPhases = (
|
|
151
163
|
6918283D91B9066E2F9DADD5 /* Sources */,
|
|
164
|
+
EBFB738E78B6AF48E8771031 /* Resources */,
|
|
152
165
|
56326A91B4B75B21E246160E /* Frameworks */,
|
|
153
166
|
);
|
|
154
167
|
buildRules = (
|
|
@@ -179,6 +192,7 @@
|
|
|
179
192
|
knownRegions = (
|
|
180
193
|
Base,
|
|
181
194
|
en,
|
|
195
|
+
ru,
|
|
182
196
|
);
|
|
183
197
|
mainGroup = 20A8D65D5A36A0A1D83FC83B;
|
|
184
198
|
minimizedProjectReferenceProxies = 1;
|
|
@@ -192,6 +206,17 @@
|
|
|
192
206
|
};
|
|
193
207
|
/* End PBXProject section */
|
|
194
208
|
|
|
209
|
+
/* Begin PBXResourcesBuildPhase section */
|
|
210
|
+
EBFB738E78B6AF48E8771031 /* Resources */ = {
|
|
211
|
+
isa = PBXResourcesBuildPhase;
|
|
212
|
+
buildActionMask = 2147483647;
|
|
213
|
+
files = (
|
|
214
|
+
F1510F7B66940A31758A2561 /* Localizable.strings in Resources */,
|
|
215
|
+
);
|
|
216
|
+
runOnlyForDeploymentPostprocessing = 0;
|
|
217
|
+
};
|
|
218
|
+
/* End PBXResourcesBuildPhase section */
|
|
219
|
+
|
|
195
220
|
/* Begin PBXSourcesBuildPhase section */
|
|
196
221
|
6918283D91B9066E2F9DADD5 /* Sources */ = {
|
|
197
222
|
isa = PBXSourcesBuildPhase;
|
|
@@ -213,6 +238,18 @@
|
|
|
213
238
|
};
|
|
214
239
|
/* End PBXSourcesBuildPhase section */
|
|
215
240
|
|
|
241
|
+
/* Begin PBXVariantGroup section */
|
|
242
|
+
BEE6DEA10F74F9459C452D3F /* Localizable.strings */ = {
|
|
243
|
+
isa = PBXVariantGroup;
|
|
244
|
+
children = (
|
|
245
|
+
6E3C87FA6CD54B76AEB1E84A /* en */,
|
|
246
|
+
2B9B6454B5BB98B387C7B5C4 /* ru */,
|
|
247
|
+
);
|
|
248
|
+
name = Localizable.strings;
|
|
249
|
+
sourceTree = "<group>";
|
|
250
|
+
};
|
|
251
|
+
/* End PBXVariantGroup section */
|
|
252
|
+
|
|
216
253
|
/* Begin XCBuildConfiguration section */
|
|
217
254
|
24892C5AA9CE821A3653389E /* Debug */ = {
|
|
218
255
|
isa = XCBuildConfiguration;
|
|
@@ -265,14 +302,15 @@
|
|
|
265
302
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
|
266
303
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
|
267
304
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
|
305
|
+
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
|
268
306
|
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
|
269
307
|
MTL_FAST_MATH = YES;
|
|
270
308
|
ONLY_ACTIVE_ARCH = YES;
|
|
271
|
-
PRODUCT_NAME =
|
|
309
|
+
PRODUCT_NAME = TodoOrbit;
|
|
272
310
|
SDKROOT = iphoneos;
|
|
273
311
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
|
274
312
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
|
275
|
-
SWIFT_VERSION = 5.
|
|
313
|
+
SWIFT_VERSION = 5.0;
|
|
276
314
|
};
|
|
277
315
|
name = Debug;
|
|
278
316
|
};
|
|
@@ -286,13 +324,13 @@
|
|
|
286
324
|
INFOPLIST_KEY_CFBundleDisplayName = "Todo Orbit";
|
|
287
325
|
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
|
288
326
|
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
|
289
|
-
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
|
290
327
|
LD_RUNPATH_SEARCH_PATHS = (
|
|
291
328
|
"$(inherited)",
|
|
292
329
|
"@executable_path/Frameworks",
|
|
293
330
|
);
|
|
294
331
|
PRODUCT_BUNDLE_IDENTIFIER = uz.rsteam.generated.todoorbit;
|
|
295
332
|
SDKROOT = iphoneos;
|
|
333
|
+
SWIFT_VERSION = 5.1;
|
|
296
334
|
TARGETED_DEVICE_FAMILY = "1,2";
|
|
297
335
|
};
|
|
298
336
|
name = Release;
|
|
@@ -307,13 +345,13 @@
|
|
|
307
345
|
INFOPLIST_KEY_CFBundleDisplayName = "Todo Orbit";
|
|
308
346
|
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
|
309
347
|
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
|
310
|
-
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
|
311
348
|
LD_RUNPATH_SEARCH_PATHS = (
|
|
312
349
|
"$(inherited)",
|
|
313
350
|
"@executable_path/Frameworks",
|
|
314
351
|
);
|
|
315
352
|
PRODUCT_BUNDLE_IDENTIFIER = uz.rsteam.generated.todoorbit;
|
|
316
353
|
SDKROOT = iphoneos;
|
|
354
|
+
SWIFT_VERSION = 5.1;
|
|
317
355
|
TARGETED_DEVICE_FAMILY = "1,2";
|
|
318
356
|
};
|
|
319
357
|
name = Debug;
|
|
@@ -363,13 +401,14 @@
|
|
|
363
401
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
|
364
402
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
|
365
403
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
|
404
|
+
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
|
366
405
|
MTL_ENABLE_DEBUG_INFO = NO;
|
|
367
406
|
MTL_FAST_MATH = YES;
|
|
368
|
-
PRODUCT_NAME =
|
|
407
|
+
PRODUCT_NAME = TodoOrbit;
|
|
369
408
|
SDKROOT = iphoneos;
|
|
370
409
|
SWIFT_COMPILATION_MODE = wholemodule;
|
|
371
410
|
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
|
372
|
-
SWIFT_VERSION = 5.
|
|
411
|
+
SWIFT_VERSION = 5.0;
|
|
373
412
|
};
|
|
374
413
|
name = Release;
|
|
375
414
|
};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<Scheme
|
|
3
|
+
LastUpgradeVersion = "1430"
|
|
4
|
+
version = "1.7">
|
|
5
|
+
<BuildAction
|
|
6
|
+
parallelizeBuildables = "YES"
|
|
7
|
+
buildImplicitDependencies = "YES"
|
|
8
|
+
runPostActionsOnFailure = "NO">
|
|
9
|
+
<BuildActionEntries>
|
|
10
|
+
<BuildActionEntry
|
|
11
|
+
buildForTesting = "YES"
|
|
12
|
+
buildForRunning = "YES"
|
|
13
|
+
buildForProfiling = "YES"
|
|
14
|
+
buildForArchiving = "YES"
|
|
15
|
+
buildForAnalyzing = "YES">
|
|
16
|
+
<BuildableReference
|
|
17
|
+
BuildableIdentifier = "primary"
|
|
18
|
+
BlueprintIdentifier = "8573DE2D9477FA23E2648D4F"
|
|
19
|
+
BuildableName = "TodoOrbit.app"
|
|
20
|
+
BlueprintName = "TodoOrbit"
|
|
21
|
+
ReferencedContainer = "container:TodoOrbit.xcodeproj">
|
|
22
|
+
</BuildableReference>
|
|
23
|
+
</BuildActionEntry>
|
|
24
|
+
</BuildActionEntries>
|
|
25
|
+
</BuildAction>
|
|
26
|
+
<TestAction
|
|
27
|
+
buildConfiguration = "Debug"
|
|
28
|
+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
|
29
|
+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
|
30
|
+
shouldUseLaunchSchemeArgsEnv = "YES"
|
|
31
|
+
onlyGenerateCoverageForSpecifiedTargets = "NO">
|
|
32
|
+
<MacroExpansion>
|
|
33
|
+
<BuildableReference
|
|
34
|
+
BuildableIdentifier = "primary"
|
|
35
|
+
BlueprintIdentifier = "8573DE2D9477FA23E2648D4F"
|
|
36
|
+
BuildableName = "TodoOrbit.app"
|
|
37
|
+
BlueprintName = "TodoOrbit"
|
|
38
|
+
ReferencedContainer = "container:TodoOrbit.xcodeproj">
|
|
39
|
+
</BuildableReference>
|
|
40
|
+
</MacroExpansion>
|
|
41
|
+
<Testables>
|
|
42
|
+
</Testables>
|
|
43
|
+
</TestAction>
|
|
44
|
+
<LaunchAction
|
|
45
|
+
buildConfiguration = "Debug"
|
|
46
|
+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
|
47
|
+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
|
48
|
+
launchStyle = "0"
|
|
49
|
+
useCustomWorkingDirectory = "NO"
|
|
50
|
+
ignoresPersistentStateOnLaunch = "NO"
|
|
51
|
+
debugDocumentVersioning = "YES"
|
|
52
|
+
debugServiceExtension = "internal"
|
|
53
|
+
allowLocationSimulation = "YES">
|
|
54
|
+
<BuildableProductRunnable
|
|
55
|
+
runnableDebuggingMode = "0">
|
|
56
|
+
<BuildableReference
|
|
57
|
+
BuildableIdentifier = "primary"
|
|
58
|
+
BlueprintIdentifier = "8573DE2D9477FA23E2648D4F"
|
|
59
|
+
BuildableName = "TodoOrbit.app"
|
|
60
|
+
BlueprintName = "TodoOrbit"
|
|
61
|
+
ReferencedContainer = "container:TodoOrbit.xcodeproj">
|
|
62
|
+
</BuildableReference>
|
|
63
|
+
</BuildableProductRunnable>
|
|
64
|
+
</LaunchAction>
|
|
65
|
+
<ProfileAction
|
|
66
|
+
buildConfiguration = "Release"
|
|
67
|
+
shouldUseLaunchSchemeArgsEnv = "YES"
|
|
68
|
+
savedToolIdentifier = ""
|
|
69
|
+
useCustomWorkingDirectory = "NO"
|
|
70
|
+
debugDocumentVersioning = "YES">
|
|
71
|
+
<BuildableProductRunnable
|
|
72
|
+
runnableDebuggingMode = "0">
|
|
73
|
+
<BuildableReference
|
|
74
|
+
BuildableIdentifier = "primary"
|
|
75
|
+
BlueprintIdentifier = "8573DE2D9477FA23E2648D4F"
|
|
76
|
+
BuildableName = "TodoOrbit.app"
|
|
77
|
+
BlueprintName = "TodoOrbit"
|
|
78
|
+
ReferencedContainer = "container:TodoOrbit.xcodeproj">
|
|
79
|
+
</BuildableReference>
|
|
80
|
+
</BuildableProductRunnable>
|
|
81
|
+
</ProfileAction>
|
|
82
|
+
<AnalyzeAction
|
|
83
|
+
buildConfiguration = "Debug">
|
|
84
|
+
</AnalyzeAction>
|
|
85
|
+
<ArchiveAction
|
|
86
|
+
buildConfiguration = "Release"
|
|
87
|
+
revealArchiveInOrganizer = "YES">
|
|
88
|
+
</ArchiveAction>
|
|
89
|
+
</Scheme>
|
|
@@ -1,25 +1,32 @@
|
|
|
1
1
|
name: TodoOrbit
|
|
2
2
|
options:
|
|
3
3
|
bundleIdPrefix: uz.rsteam.generated
|
|
4
|
+
deploymentTarget:
|
|
5
|
+
iOS: "17.0"
|
|
4
6
|
settings:
|
|
5
7
|
base:
|
|
6
|
-
|
|
8
|
+
PRODUCT_NAME: TodoOrbit
|
|
7
9
|
targets:
|
|
8
10
|
TodoOrbit:
|
|
9
11
|
type: application
|
|
10
12
|
platform: iOS
|
|
11
|
-
deploymentTarget: "17.0"
|
|
12
13
|
sources:
|
|
13
14
|
- path: Sources/TodoOrbit
|
|
14
|
-
resources:
|
|
15
15
|
- path: Resources
|
|
16
|
+
buildPhase: resources
|
|
16
17
|
settings:
|
|
17
18
|
base:
|
|
18
|
-
PRODUCT_BUNDLE_IDENTIFIER: uz.rsteam.generated.todoorbit
|
|
19
19
|
GENERATE_INFOPLIST_FILE: YES
|
|
20
20
|
INFOPLIST_KEY_CFBundleDisplayName: Todo Orbit
|
|
21
|
-
INFOPLIST_KEY_UILaunchScreen_Generation:
|
|
22
|
-
INFOPLIST_KEY_UIApplicationSceneManifest_Generation:
|
|
21
|
+
INFOPLIST_KEY_UILaunchScreen_Generation: true
|
|
22
|
+
INFOPLIST_KEY_UIApplicationSceneManifest_Generation: true
|
|
23
|
+
SWIFT_VERSION: 5.10
|
|
24
|
+
PRODUCT_BUNDLE_IDENTIFIER: uz.rsteam.generated.todoorbit
|
|
23
25
|
DEVELOPMENT_ASSET_PATHS: "\"Sources/TodoOrbit/Preview Content\""
|
|
24
26
|
dependencies:
|
|
25
27
|
- sdk: Charts.framework
|
|
28
|
+
schemes:
|
|
29
|
+
TodoOrbit:
|
|
30
|
+
build:
|
|
31
|
+
targets:
|
|
32
|
+
TodoOrbit: all
|