mta-mcp 3.16.0 → 3.16.2
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/flutter.agent.md +10 -8
- package/dist/index.js +116 -37
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/troubleshooting/flutter/component-/351/200/232/347/224/250/345/214/226/346/217/220/345/217/226.md +2 -2
- package/troubleshooting/flutter/sketch-/345/233/276/346/240/207/345/260/272/345/257/270.md +2 -2
- package/troubleshooting/flutter/svg-/345/220/253/350/203/214/346/231/257/350/267/257/345/276/204.md +6 -4
- package/troubleshooting/flutter/svg-/346/234/252/345/261/205/344/270/255.md +3 -3
- package/troubleshooting/flutter/svg-/351/242/234/350/211/262/345/274/202/345/270/270.md +3 -3
- package/ui/sketch/mta-measure.sketchplugin/Contents/Sketch/measure.js +35 -17
package/package.json
CHANGED
|
@@ -116,7 +116,7 @@ class TipCardConfig {
|
|
|
116
116
|
titleColor: Color(0xFFFF9800),
|
|
117
117
|
contentColor: Color(0xFFB45309),
|
|
118
118
|
buttonShadowColor: Color(0x40FF9800),
|
|
119
|
-
iconPath: '
|
|
119
|
+
iconPath: '<asset-dir>/warning_icon.svg',
|
|
120
120
|
);
|
|
121
121
|
|
|
122
122
|
/// Error: #f4433614 (8%透明), border #ffcacaff
|
|
@@ -126,7 +126,7 @@ class TipCardConfig {
|
|
|
126
126
|
titleColor: Color(0xFFF44336),
|
|
127
127
|
contentColor: Color(0xFFCA4F57),
|
|
128
128
|
buttonShadowColor: Color(0x40D0121B),
|
|
129
|
-
iconPath: '
|
|
129
|
+
iconPath: '<asset-dir>/error_icon.svg',
|
|
130
130
|
);
|
|
131
131
|
|
|
132
132
|
static TipCardConfig fromType(TipCardType type) {
|
|
@@ -83,14 +83,14 @@ extractIconInternalSize('Frame Name');
|
|
|
83
83
|
```dart
|
|
84
84
|
// ✅ 使用内部图形的实际尺寸
|
|
85
85
|
SvgPicture.asset(
|
|
86
|
-
'
|
|
86
|
+
'<asset-dir>/recipient.svg',
|
|
87
87
|
width: 15.0, // 14.7 取整
|
|
88
88
|
height: 15.0,
|
|
89
89
|
)
|
|
90
90
|
|
|
91
91
|
// ❌ 错误:使用外层 Group 尺寸
|
|
92
92
|
SvgPicture.asset(
|
|
93
|
-
'
|
|
93
|
+
'<asset-dir>/recipient.svg',
|
|
94
94
|
width: 22.0, // 这是 Group 尺寸,图标会偏大
|
|
95
95
|
height: 22.0,
|
|
96
96
|
)
|
package/troubleshooting/flutter/svg-/345/220/253/350/203/214/346/231/257/350/267/257/345/276/204.md
CHANGED
|
@@ -111,13 +111,13 @@ selection.forEach(layer => {
|
|
|
111
111
|
|
|
112
112
|
```bash
|
|
113
113
|
# 1. 查看文件大小:纯图标通常 < 3KB
|
|
114
|
-
ls -lh
|
|
114
|
+
ls -lh <asset-dir>/ic_face_id.svg
|
|
115
115
|
|
|
116
116
|
# 2. 搜索是否含圆形元素
|
|
117
|
-
grep -c "<circle\|fill-opacity"
|
|
117
|
+
grep -c "<circle\|fill-opacity" <asset-dir>/ic_face_id.svg
|
|
118
118
|
|
|
119
119
|
# 3. 检查 viewBox 是否等于图标本身尺寸(如 60×60)
|
|
120
|
-
grep "viewBox"
|
|
120
|
+
grep "viewBox" <asset-dir>/ic_face_id.svg
|
|
121
121
|
```
|
|
122
122
|
|
|
123
123
|
### Flutter 代码中的正确用法
|
|
@@ -134,7 +134,7 @@ Container(
|
|
|
134
134
|
child: Center(
|
|
135
135
|
// SVG 只含纯图标路径,不含圆形背景
|
|
136
136
|
child: SvgPicture.asset(
|
|
137
|
-
'
|
|
137
|
+
'<asset-dir>/ic_face_id.svg',
|
|
138
138
|
width: 60,
|
|
139
139
|
height: 60,
|
|
140
140
|
),
|
|
@@ -142,6 +142,8 @@ Container(
|
|
|
142
142
|
)
|
|
143
143
|
```
|
|
144
144
|
|
|
145
|
+
其中 <asset-dir> 表示当前项目的实际素材目录。
|
|
146
|
+
|
|
145
147
|
---
|
|
146
148
|
|
|
147
149
|
## 📝 验证检查清单
|
|
@@ -91,7 +91,7 @@ SizedBox(
|
|
|
91
91
|
height: 16,
|
|
92
92
|
child: Center(
|
|
93
93
|
child: SvgPicture.asset(
|
|
94
|
-
'
|
|
94
|
+
'<asset-dir>/recipient_chevron_right.svg',
|
|
95
95
|
width: 6,
|
|
96
96
|
height: 8,
|
|
97
97
|
),
|
|
@@ -99,7 +99,7 @@ SizedBox(
|
|
|
99
99
|
)
|
|
100
100
|
|
|
101
101
|
// ❌ 错误 - 直接把 6×8 箭头按 16×16 渲染,视觉会偏大
|
|
102
|
-
SvgPicture.asset('
|
|
102
|
+
SvgPicture.asset('<asset-dir>/recipient_chevron_right.svg', width: 16, height: 16)
|
|
103
103
|
```
|
|
104
104
|
|
|
105
105
|
---
|
|
@@ -113,7 +113,7 @@ SvgPicture.asset('assets/icons/recipient_chevron_right.svg', width: 16, height:
|
|
|
113
113
|
2. **验证导出的 viewBox**
|
|
114
114
|
```bash
|
|
115
115
|
# 检查 SVG 文件的 viewBox
|
|
116
|
-
|
|
116
|
+
head -3 <asset-dir>/arrow.svg
|
|
117
117
|
# 应该看到 viewBox="0 0 12 12" 而非 viewBox="0 0 6 3"
|
|
118
118
|
```
|
|
119
119
|
|
|
@@ -53,7 +53,7 @@ SvgPicture.asset(
|
|
|
53
53
|
```dart
|
|
54
54
|
// ✅ 不使用 colorFilter,保留 SVG 原有颜色和透明度
|
|
55
55
|
SvgPicture.asset(
|
|
56
|
-
'
|
|
56
|
+
'<asset-dir>/dropdown_arrow.svg',
|
|
57
57
|
width: 12,
|
|
58
58
|
height: 12,
|
|
59
59
|
// 不传 colorFilter
|
|
@@ -65,14 +65,14 @@ SvgPicture.asset(
|
|
|
65
65
|
```dart
|
|
66
66
|
// ✅ sketch_measure 已判定保留原色
|
|
67
67
|
SvgPicture.asset(
|
|
68
|
-
'
|
|
68
|
+
'<asset-dir>/recipient_chevron_right.svg',
|
|
69
69
|
width: 6,
|
|
70
70
|
height: 8,
|
|
71
71
|
)
|
|
72
72
|
|
|
73
73
|
// ❌ 错误 - preserve 模式又二次染色
|
|
74
74
|
SvgPicture.asset(
|
|
75
|
-
'
|
|
75
|
+
'<asset-dir>/recipient_chevron_right.svg',
|
|
76
76
|
width: 6,
|
|
77
77
|
height: 8,
|
|
78
78
|
colorFilter: ColorFilter.mode(AppColors.textDarkTertiary, BlendMode.srcIn),
|
|
@@ -2500,17 +2500,33 @@ function buildManualExportedBitmapAssetCandidates(layer) {
|
|
|
2500
2500
|
var rawName = String(layer && layer.name ? layer.name : '').trim();
|
|
2501
2501
|
if (rawName) {
|
|
2502
2502
|
var exactName = rawName.replace(/[\\/]/g, '-').replace(/\s+/g, ' ').trim();
|
|
2503
|
-
if (exactName)
|
|
2503
|
+
if (exactName) {
|
|
2504
|
+
pushUniqueAssetCandidate(candidates, exactName + '@4x.png');
|
|
2505
|
+
pushUniqueAssetCandidate(candidates, exactName + '_icon@4x.png');
|
|
2506
|
+
pushUniqueAssetCandidate(candidates, exactName + '.png');
|
|
2507
|
+
}
|
|
2504
2508
|
}
|
|
2505
2509
|
|
|
2506
2510
|
var sanitizedName = buildLayerAssetBaseName(layer, 'image');
|
|
2507
2511
|
if (sanitizedName) {
|
|
2512
|
+
pushUniqueAssetCandidate(candidates, sanitizedName + '@4x.png');
|
|
2508
2513
|
pushUniqueAssetCandidate(candidates, sanitizedName + '_icon@4x.png');
|
|
2514
|
+
pushUniqueAssetCandidate(candidates, sanitizedName + '.png');
|
|
2509
2515
|
}
|
|
2510
2516
|
|
|
2511
2517
|
return candidates;
|
|
2512
2518
|
}
|
|
2513
2519
|
|
|
2520
|
+
function buildBitmapLookupCandidates(layer, sharedBitmapName) {
|
|
2521
|
+
var candidates = buildManualExportedBitmapAssetCandidates(layer);
|
|
2522
|
+
if (sharedBitmapName) {
|
|
2523
|
+
pushUniqueAssetCandidate(candidates, sharedBitmapName + '.png');
|
|
2524
|
+
pushUniqueAssetCandidate(candidates, sharedBitmapName + '@4x.png');
|
|
2525
|
+
pushUniqueAssetCandidate(candidates, sharedBitmapName + '_icon@4x.png');
|
|
2526
|
+
}
|
|
2527
|
+
return candidates;
|
|
2528
|
+
}
|
|
2529
|
+
|
|
2514
2530
|
function normalizeSharedAssetName(name) {
|
|
2515
2531
|
return String(name || '')
|
|
2516
2532
|
.toLowerCase()
|
|
@@ -2803,7 +2819,7 @@ function measureRecursively(layer, depth, parentFrame, siblings) {
|
|
|
2803
2819
|
|
|
2804
2820
|
if (element.isIcon) {
|
|
2805
2821
|
element.iconAssetFileName = buildLayerAssetFileName(layer, 'icon', 'svg');
|
|
2806
|
-
element.iconExportPath =
|
|
2822
|
+
element.iconExportPath = element.iconAssetFileName;
|
|
2807
2823
|
element.iconSketchName = layer.name;
|
|
2808
2824
|
if (looksLikeSvgExportCandidate(layer)) {
|
|
2809
2825
|
var svgExport = exportLayerToSvgMarkup(layer, element.iconAssetFileName);
|
|
@@ -2819,7 +2835,7 @@ function measureRecursively(layer, depth, parentFrame, siblings) {
|
|
|
2819
2835
|
element.iconSvgExportSkipped = '该图层包含常规文本或位图,不适合作为纯 SVG 图标导出';
|
|
2820
2836
|
}
|
|
2821
2837
|
element.iconPathWarning = '优先使用插件返回的真实 SVG(iconSvgMarkup/flutterSvgCode)。' +
|
|
2822
|
-
'
|
|
2838
|
+
'若需要落盘文件,请放入项目现有素材目录并保留建议文件名 ' + element.iconAssetFileName + '。禁止用 Icons.xxx 替代——SVG 不存在时必须报错,不得静默降级。';
|
|
2823
2839
|
// 提取 Icon 内容边界 (区分容器尺寸 vs 内容尺寸)
|
|
2824
2840
|
if (layer.type === 'Group' && layer.layers) {
|
|
2825
2841
|
var bounds = extractIconContentBounds(layer);
|
|
@@ -2868,7 +2884,7 @@ function measureRecursively(layer, depth, parentFrame, siblings) {
|
|
|
2868
2884
|
effectiveColor
|
|
2869
2885
|
);
|
|
2870
2886
|
} else {
|
|
2871
|
-
element.flutterSvgCode = 'SvgPicture.asset(\'
|
|
2887
|
+
element.flutterSvgCode = 'SvgPicture.asset(\'<asset-path>/' + element.iconAssetFileName + '\' /* TODO: 将真实 SVG 放入项目素材目录并替换占位路径 */, width: ' + iw + ', height: ' + ih + ', colorFilter: ColorFilter.mode(' + effectiveColor + ', BlendMode.srcIn),)';
|
|
2872
2888
|
}
|
|
2873
2889
|
}
|
|
2874
2890
|
} else if (element.iconSvgMarkup) {
|
|
@@ -2979,38 +2995,40 @@ function measureRecursively(layer, depth, parentFrame, siblings) {
|
|
|
2979
2995
|
if (nativeImgFills && nativeImgFills[0] && nativeImgFills[0].hex) {
|
|
2980
2996
|
element.imageInfo.nativeTint = formatNativeColor(nativeImgFills[0]);
|
|
2981
2997
|
}
|
|
2982
|
-
element.imageInfo.note = '此图层为嵌入式位图(Bitmap)。若它是 icon/button/arrow
|
|
2998
|
+
element.imageInfo.note = '此图层为嵌入式位图(Bitmap)。若它是 icon/button/arrow 等图标类位图,先在项目素材目录中按图层文件名主体查找现有高倍率 PNG(例如 xxx@4x.png);找到即直接复用。只有明确缺失时才补导 PNG,禁止再把 Bitmap 伪装成 SVG。';
|
|
2983
2999
|
// 生成 Image.asset 代码片段,开发者直接复制使用
|
|
2984
3000
|
var bitmapW = Math.round(layer.frame.width);
|
|
2985
3001
|
var bitmapH = Math.round(layer.frame.height);
|
|
2986
|
-
var manualBitmapCandidates =
|
|
3002
|
+
var manualBitmapCandidates = buildManualExportedBitmapAssetCandidates(layer);
|
|
2987
3003
|
var manualBitmapName = manualBitmapCandidates.length > 0 ? manualBitmapCandidates[0] : null;
|
|
2988
|
-
var sharedBitmapName =
|
|
3004
|
+
var sharedBitmapName = resolveSharedBitmapAssetBaseName(layer);
|
|
3005
|
+
var bitmapLookupCandidates = buildBitmapLookupCandidates(layer, sharedBitmapName);
|
|
2989
3006
|
var bitmapName = sharedBitmapName || buildLayerAssetBaseName(layer, 'image');
|
|
2990
3007
|
var bitmapFileName = manualBitmapName || (bitmapName + '.png');
|
|
2991
3008
|
element.imageInfo.reuseMode = element.isIcon
|
|
2992
|
-
? '
|
|
3009
|
+
? 'project-asset-search-first'
|
|
2993
3010
|
: (sharedBitmapName ? 'shared-canonical' : 'page-local');
|
|
2994
3011
|
if (sharedBitmapName && !element.isIcon) {
|
|
2995
3012
|
element.imageInfo.reuseKey = sharedBitmapName;
|
|
2996
3013
|
}
|
|
2997
3014
|
element.imageInfo.bitmapFileName = bitmapFileName;
|
|
2998
|
-
element.imageInfo.bitmapExportPath =
|
|
3015
|
+
element.imageInfo.bitmapExportPath = bitmapFileName;
|
|
2999
3016
|
element.imageInfo.exportScaleVariants = element.isIcon ? ['@4x'] : ['1.0x', '2.0x', '3.0x'];
|
|
3017
|
+
if (bitmapLookupCandidates.length > 0) {
|
|
3018
|
+
element.imageInfo.lookupCandidates = bitmapLookupCandidates;
|
|
3019
|
+
}
|
|
3000
3020
|
if (element.isIcon) {
|
|
3001
|
-
element.imageInfo.
|
|
3002
|
-
element.imageInfo.
|
|
3003
|
-
element.imageInfo.pathWarning = '先在 assets/icons/ 中按设计稿图层名查找用户手工导出的 @4x PNG。优先候选: ' + manualBitmapCandidates.join(' / ') + '。找到即直接复用,不要再推导 SVG 或继续生成新的 page-local PNG。';
|
|
3004
|
-
element.imageInfo.exportHint = '若 assets/icons/ 中缺少对应图标,请由用户手动从设计稿导出 PNG 到 assets/icons/,文件名优先使用 ' + bitmapFileName + '。';
|
|
3021
|
+
element.imageInfo.pathWarning = '先在项目素材目录中按设计稿图层名主体查找用户手工导出的高倍率 PNG。优先候选: ' + manualBitmapCandidates.join(' / ') + '。文件名匹配重点看 xxx 主体,@4x 只是倍率后缀。找到即直接复用,不要再推导 SVG 或继续生成新的 page-local PNG。';
|
|
3022
|
+
element.imageInfo.exportHint = '若项目素材目录中缺少对应图标,请由用户手动从设计稿导出 PNG,并沿用建议文件名主体 ' + bitmapName + '(例如 ' + bitmapName + '.png 或 ' + bitmapName + '@4x.png)。';
|
|
3005
3023
|
} else {
|
|
3006
3024
|
element.imageInfo.pathWarning = sharedBitmapName
|
|
3007
|
-
? '
|
|
3025
|
+
? '检测到重复出现的共享位图图标。先按设计稿图层原名或文件名主体查找现有资源(优先候选: ' + bitmapLookupCandidates.join(' / ') + ');若项目已做运行时规范化,再复用 canonical 文件名 ' + bitmapName + '.png。禁止把 Help / Customer Service 等语义相近位图互换。'
|
|
3008
3026
|
: '⚠️ 位图资源必须从当前画板局部导出并使用 page-local 文件名,禁止继续复用其它页面的旧 PNG。';
|
|
3009
3027
|
element.imageInfo.exportHint = sharedBitmapName
|
|
3010
|
-
? 'Sketch 导出命令:
|
|
3011
|
-
: 'Sketch 导出命令: File > Export Layers > 选择此图层 > 格式 PNG
|
|
3028
|
+
? 'Sketch 导出命令: 先确认项目素材目录中是否已存在设计稿原名或同主体导出文件;若需要生成运行时稳定路径,可复制为 ' + bitmapName + '.png,并保持像素内容与设计导出一致。'
|
|
3029
|
+
: 'Sketch 导出命令: File > Export Layers > 选择此图层 > 格式 PNG;输出目录遵循当前项目约定,若仍走多倍率目录流程再补齐同目录 2.0x/3.0x。';
|
|
3012
3030
|
}
|
|
3013
|
-
element.flutterImageCode = 'Image.asset(\'
|
|
3031
|
+
element.flutterImageCode = 'Image.asset(\'<asset-path>/' + bitmapFileName + '\', width: ' + bitmapW + ', height: ' + bitmapH + ', filterQuality: FilterQuality.high, isAntiAlias: true,)';
|
|
3014
3032
|
}
|
|
3015
3033
|
|
|
3016
3034
|
// Symbol Instance — override 真实值
|