Merge branch 'release/2.1.0'

This commit is contained in:
Max 2025-12-17 12:51:01 +08:00
commit 9335f4fddb
40 changed files with 2974 additions and 1604 deletions

11
CHANGELOG.md Normal file
View File

@ -0,0 +1,11 @@
## 2.1.0
- Feat: 支持配置 `font_package` 以支持从其他包加载字体。
- Refactor: 优化生成的代码结构,使用私有工厂方法减少代码体积。
- Refactor: 统一 `fontFamily` 常量定义。
## 2.0.0
- Feat: 重构为 Dart CLI 工具。
- Feat: 支持 YAML 配置文件。
- Feat: 优化代码生成逻辑。

483
README.md
View File

@ -1,339 +1,202 @@
# YX Icon Fonts
学习官OA系统图标字体库基于iconfont.ttf和iconfont.json生成的Flutter图标库
从 iconfont.json 生成 Flutter IconData 常量的 Dart CLI 工具
## 特性
- 🎨 包含50+个精心设计的图标
- 📱 支持Flutter应用
- 🎯 类型安全的图标使用
- 📦 轻量级,无额外依赖
- 🔧 易于集成和使用
- ⚡ 自动化生成脚本
- 🎨 解析 iconfont.cn 导出的 JSON 文件
- 📝 生成类型安全的 Flutter IconData 常量
- ⚙️ YAML 配置文件支持
- 🏗️ 自定义类名和输出路径
- 📚 自动生成文档注释
## 安装
在您的`pubspec.yaml`文件中添加依赖:
在您的 Flutter 项目的 `pubspec.yaml` 中添加为开发依赖:
```yaml
dependencies:
yx_icon_fonts: ^1.0.0
dev_dependencies:
yx_icon_fonts:
git:
url: https://gitea.23544.com/wangyang/yx_icon_fonts_flutter
ref: v2.0.0
```
然后运行:
```bash
flutter pub get
dart pub get
```
## 使用方法
## 快速开始
### 基本用法
### 1. 初始化配置文件
```bash
dart run yx_icon_fonts init
```
这将在项目根目录创建 `icon_generator_config.yaml` 配置模板。
### 2. 准备资源文件
从 [iconfont.cn](https://www.iconfont.cn/) 下载您的图标项目,将以下文件放到项目中:
- `iconfont.ttf` - 字体文件
- `iconfont.json` - 图标配置文件
### 3. 配置 pubspec.yaml
`pubspec.yaml` 中注册字体:
```yaml
flutter:
fonts:
- family: iconfont
fonts:
- asset: assets/fonts/iconfont.ttf
```
### 4. 编辑配置文件
修改 `icon_generator_config.yaml`
```yaml
input:
font_file: "assets/fonts/iconfont.ttf"
json_file: "assets/fonts/iconfont.json"
font_family: "iconfont"
output:
file_path: "lib/generated/icons.dart"
class_name: "AppIcons"
```
### 5. 生成代码
```bash
dart run yx_icon_fonts generate
```
### 6. 使用生成的图标
```dart
import 'package:flutter/material.dart';
import 'package:yx_icon_fonts/yx_icon_fonts.dart';
import 'package:your_app/generated/icons.dart';
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Icon(
YXIconFonts.iconMsgContacts,
size: 24,
color: Colors.blue,
);
}
// 在 Widget 中使用
Icon(AppIcons.iconHome, size: 24, color: Colors.blue)
// 在 IconButton 中使用
IconButton(
icon: Icon(AppIcons.iconSettings),
onPressed: () {},
)
```
## 命令参考
### help - 显示帮助
```bash
dart run yx_icon_fonts help
```
### init - 初始化配置
```bash
# 创建配置文件
dart run yx_icon_fonts init
# 强制覆盖已存在的配置文件
dart run yx_icon_fonts init --force
```
### generate - 生成代码
```bash
# 使用默认配置文件
dart run yx_icon_fonts generate
# 指定配置文件
dart run yx_icon_fonts generate --config my_config.yaml
# 详细输出
dart run yx_icon_fonts generate --verbose
```
## 配置选项
完整的配置选项请参考 [icon_generator_config.template.yaml](./icon_generator_config.template.yaml)。
### generator 配置
| 选项 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| name | string | "Icon Generator" | 生成器名称,用于代码注释 |
| version | string | "1.0" | 版本号 |
| author | string | "" | 作者信息 |
### input 配置
| 选项 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| font_file | string | "assets/fonts/iconfont.ttf" | 字体文件路径 |
| json_file | string | "assets/fonts/iconfont.json" | JSON 配置文件路径 |
| font_family | string | "iconfont" | 字体家族名称 |
### output 配置
| 选项 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| file_path | string | "lib/generated/icons.dart" | 输出文件路径 |
| class_name | string | "AppIcons" | 生成的类名 |
| generate_docs | bool | true | 是否生成文档注释 |
| use_const_constructor | bool | true | 是否使用 const 构造函数 |
## 生成的代码示例
```dart
// ignore_for_file: constant_identifier_names
// ============================================
// 此文件由 yx_icon_fonts 自动生成,请勿手动修改
// 生成时间: 2025-01-01 12:00
// 图标数量: 50
// ============================================
import 'package:flutter/widgets.dart';
/// MyApp Icons 图标常量
class AppIcons {
AppIcons._();
// 统一的 IconData 构造方法
static const _icon = _IconDataFactory._();
/// icon_home (U+E600)
static final IconData iconHome = _icon(0xe600);
// ... 更多图标
}
/// 内部 IconData 工厂类
class _IconDataFactory {
const _IconDataFactory._();
static const String _fontFamily = 'iconfont';
IconData call(int codePoint) => IconData(codePoint, fontFamily: _fontFamily);
}
```
### 使用YXIcon组件
## 从 v1.x 迁移
```dart
import 'package:flutter/material.dart';
import 'package:yx_icon_fonts/yx_icon_fonts.dart';
v2.0 版本将 yx_icon_fonts 从 Flutter 库转换为了 CLI 工具。主要变化:
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return YXIcon(
YXIconFonts.iconMsgContacts,
size: 24,
color: Colors.blue,
);
}
}
```
1. **安装方式变化**:从 `dependencies` 改为 `dev_dependencies`
2. **资源文件位置**:字体和 JSON 文件现在放在使用项目中,而非库中
3. **配置方式**:使用 YAML 配置文件,支持自定义类名和路径
### 在AppBar中使用
```dart
AppBar(
title: Text('我的应用'),
actions: [
IconButton(
icon: Icon(YXIconFonts.iconMsgSearch),
onPressed: () {
// 搜索操作
},
),
],
)
```
## 可用图标
### 消息相关图标
- `YXIconFonts.iconMsgContacts` - 联系人
- `YXIconFonts.iconMsgViedo` - 视频
- `YXIconFonts.iconMsgSearch` - 搜索
- `YXIconFonts.iconMsgCall` - 通话
- `YXIconFonts.iconMsgPhoto` - 照片
- `YXIconFonts.iconMsgImg` - 图片
- `YXIconFonts.iconMsgFile` - 文件
### 箭头相关图标
- `YXIconFonts.icon32Arrowright` - 右箭头32
- `YXIconFonts.icon44Arrowleft` - 左箭头44
- `YXIconFonts.icon44Arrowright` - 右箭头44
- `YXIconFonts.icon24Arrowleft` - 左箭头24
- `YXIconFonts.icon24Arrowdown` - 下箭头24
- `YXIconFonts.icon44Arrowright1` - 右箭头44(1)
### 编辑相关图标
- `YXIconFonts.icon44Edit` - 编辑44
- `YXIconFonts.icon24Edit` - 编辑24
- `YXIconFonts.icon36Editline` - 编辑线36
### 个人中心相关图标
- `YXIconFonts.icon44MePassword` - 密码
- `YXIconFonts.icon44MeHelp` - 帮助
- `YXIconFonts.icon44MeVersion` - 版本
- `YXIconFonts.icon44MePrivacy` - 隐私
- `YXIconFonts.icon44MeUser` - 用户
- `YXIconFonts.icon44MeSafe` - 安全
- `YXIconFonts.icon44MePhone` - 手机
### 功能图标
- `YXIconFonts.icon32Filter` - 筛选
- `YXIconFonts.icon36Question` - 问题
- `YXIconFonts.icon36Onlysee` - 仅查看
- `YXIconFonts.icon36Hint` - 提示
- `YXIconFonts.icon24Switch` - 切换
### 操作图标
- `YXIconFonts.icon44Delete` - 删除44
- `YXIconFonts.icon36Delete` - 删除36
- `YXIconFonts.icon24Delete` - 删除24
- `YXIconFonts.icon44More` - 更多
- `YXIconFonts.icon44More2` - 更多2
- `YXIconFonts.icon24Copy` - 复制
- `YXIconFonts.icon44Share` - 分享
- `YXIconFonts.icon44Calendar` - 日历
### 添加相关图标
- `YXIconFonts.icon24Add` - 添加24
- `YXIconFonts.icon24Plus` - 加号
- `YXIconFonts.icon44Add` - 添加44
- `YXIconFonts.icon32Add` - 添加32
### 消息功能图标
- `YXIconFonts.icon56Msgadd` - 消息添加
- `YXIconFonts.icon56Msgface` - 消息表情
- `YXIconFonts.icon56Msgvoice` - 消息语音
### 其他图标
- `YXIconFonts.icon36Team` - 团队
- `YXIconFonts.icon32Student` - 学生
- `YXIconFonts.icon44Keyboard` - 键盘
- `YXIconFonts.icon24Minus` - 减号
- `YXIconFonts.icon44Quitlite` - 退出轻量
- `YXIconFonts.icon32Quit` - 退出32
- `YXIconFonts.icon44Quit` - 退出44
## 示例
运行示例应用查看所有图标:
```bash
cd example
flutter run
```
## 自定义
### 修改图标大小
```dart
Icon(
YXIconFonts.iconMsgContacts,
size: 48, // 自定义大小
)
```
### 修改图标颜色
```dart
Icon(
YXIconFonts.iconMsgContacts,
color: Colors.red, // 自定义颜色
)
```
### 在主题中使用
```dart
Theme(
data: Theme.of(context).copyWith(
iconTheme: IconThemeData(
color: Colors.blue,
size: 24,
),
),
child: Icon(YXIconFonts.iconMsgContacts),
)
```
## 开发
### 自动化生成脚本
项目提供了 `generate.sh` 脚本来自动化图标数据的生成过程。
#### 脚本功能
- 🔄 自动生成图标数据文件 (`lib/src/yx_icon_fonts_data.dart`)
- 📝 自动生成示例文件 (`example/lib/icons.dart`)
- ✅ 错误检查和验证
- 🎨 彩色输出和进度提示
#### 使用方法
```bash
# 生成所有文件(默认)
./generate.sh
# 只生成图标数据
./generate.sh icons
# 只生成示例文件
./generate.sh example
# 显示帮助信息
./generate.sh help
```
#### 脚本选项
| 选项 | 功能 | 生成文件 |
|------|------|----------|
| `all` (默认) | 生成所有文件 | `lib/src/yx_icon_fonts_data.dart` + `example/lib/icons.dart` |
| `icons` | 只生成图标数据 | `lib/src/yx_icon_fonts_data.dart` |
| `example` | 只生成示例文件 | `example/lib/icons.dart` |
| `help` | 显示帮助信息 | - |
#### 使用示例
```bash
# 首次使用,确保脚本有执行权限
chmod +x generate.sh
# 生成所有文件
./generate.sh
# 只更新图标数据(当修改了 iconfont.json 时)
./generate.sh icons
# 只更新示例文件(当修改了图标数据时)
./generate.sh example
```
#### 脚本输出示例
```
开始生成所有文件...
正在生成图标数据...
✅ 图标数据生成完成
正在生成示例文件...
✅ 示例文件生成完成
✅ 所有文件生成完成!
```
### 项目结构
```
yx_icon_fonts/
├── lib/
│ ├── yx_icon_fonts.dart # 主库文件
│ ├── main.dart # 库入口文件
│ └── src/
│ ├── yx_icon_data.dart # 图标数据类
│ ├── yx_icon.dart # 图标组件
│ └── yx_icon_fonts_data.dart # 图标常量定义(自动生成)
├── fonts/
│ └── iconfont.ttf # 字体文件
├── scripts/
│ ├── generate_icons.dart # 图标数据生成脚本
│ ├── generate_example.dart # 示例文件生成脚本
│ └── utils.dart # 共享工具函数
├── example/
│ └── lib/
│ ├── main.dart # 示例应用
│ └── icons.dart # 示例图标文件(自动生成)
├── generate.sh # 自动化生成脚本
├── iconfont.json # 图标配置数据
├── pubspec.yaml # 包配置
└── README.md # 项目文档
```
### 更新图标
1. 替换 `fonts/iconfont.ttf` 文件
2. 更新 `iconfont.json` 文件
3. 运行生成脚本:
```bash
./generate.sh icons
```
4. 更新版本号
### 开发工作流
1. **修改图标源文件**
- 更新 `fonts/iconfont.ttf`
- 更新 `iconfont.json`
2. **生成代码**
```bash
./generate.sh
```
3. **测试**
```bash
flutter analyze
flutter test
cd example && flutter run
```
4. **发布**
```bash
flutter pub publish
```
## 许可证
## License
MIT License
## 贡献
欢迎提交Issue和Pull Request
## 更新日志
### 1.0.0
- 初始版本
- 包含50+个图标
- 支持Flutter 3.0+
- 添加自动化生成脚本
- 优化项目结构和文档

View File

@ -1,6 +1,17 @@
include: package:lints/recommended.yaml
include: package:very_good_analysis/analysis_options.yaml
analyzer:
exclude:
- temp_font_awesome/**
- temp_font_awesome/**/*
- generate/**
- example/**
linter:
rules:
# 允许在生成的代码中使用常量标识符命名
constant_identifier_names: false
# 允许单行过长(生成的代码可能较长)
lines_longer_than_80_chars: false
# 允许公共成员不写文档
public_member_api_docs: false

71
bin/main.dart Normal file
View File

@ -0,0 +1,71 @@
#!/usr/bin/env dart
import 'dart:io';
import 'package:logging/logging.dart';
import 'package:yx_icon_fonts/yx_icon_fonts.dart';
/// YX Icon Fonts CLI
///
///
/// - iconfont.json
/// - Flutter IconData
/// -
///
/// 使
/// `dart run yx_icon_fonts <command> [options]`
///
///
/// - generate:
/// - init:
/// - help:
/// - version:
Future<void> main(List<String> arguments) async {
setupLogging(level: Level.ALL);
//
var resolvedArgs = arguments;
if (resolvedArgs.isEmpty) {
_showWelcome();
resolvedArgs = ['help'];
}
//
if (resolvedArgs.contains('--version') || resolvedArgs.contains('-v')) {
_showVersion();
return;
}
// 使 CLI
final cli = IconFontsCLI();
final exitCode = await cli.run(resolvedArgs);
// 退
exit(exitCode);
}
///
void _showWelcome() {
appLogger
..info('🎨 欢迎使用 YX Icon Fonts CLI 工具!')
..info('这是一个强大的图标字体代码生成工具,可以帮助您:')
..info(' 📋 解析 iconfont.json 文件')
..info(' 🛠️ 生成 Flutter IconData 常量')
..info(' 📁 自定义输出路径和类名')
..info('使用 --help 查看详细帮助信息');
}
///
void _showVersion() {
appLogger
..info('🎨 YX Icon Fonts CLI v2.0.0')
..info('构建信息:')
..info(' - Dart SDK: ${Platform.version}')
..info(' - 平台: ${Platform.operatingSystem}')
..info('特性:')
..info(' ✨ YAML 配置文件支持')
..info(' 🏗️ 模块化架构设计')
..info(' 🚀 快速代码生成')
..info(' 📝 自定义类名和路径')
..info('更多信息请访问: https://gitea.23544.com/wangyang/yx_icon_fonts_flutter');
}

8
bin/yx_icon_fonts.dart Normal file
View File

@ -0,0 +1,8 @@
#!/usr/bin/env dart
// YX Icon Fonts CLI
//
// `dart run yx_icon_fonts`
import 'main.dart' as entry;
void main(List<String> arguments) => entry.main(arguments);

View File

@ -0,0 +1,541 @@
{
"id": "4944890",
"name": "劝学APP-学习官OA系统",
"font_family": "iconfont",
"css_prefix_text": "",
"description": "劝学APP-学习官OA系统图标",
"glyphs": [
{
"icon_id": "46349152",
"name": "icon_32_clean",
"font_class": "icon_32_clean",
"unicode": "e660",
"unicode_decimal": 58976
},
{
"icon_id": "46348938",
"name": "icon_36_viewhistory",
"font_class": "icon_36_viewhistory",
"unicode": "e65f",
"unicode_decimal": 58975
},
{
"icon_id": "46205256",
"name": "icon_36_revoke",
"font_class": "icon_36_revoke",
"unicode": "e65e",
"unicode_decimal": 58974
},
{
"icon_id": "46077069",
"name": "icon_30_edit",
"font_class": "icon_30_edit",
"unicode": "e65b",
"unicode_decimal": 58971
},
{
"icon_id": "46077068",
"name": "icon_24_copy2",
"font_class": "icon_24_copy2",
"unicode": "e65c",
"unicode_decimal": 58972
},
{
"icon_id": "46077067",
"name": "icon_30_delete",
"font_class": "icon_30_delete",
"unicode": "e65d",
"unicode_decimal": 58973
},
{
"icon_id": "46077053",
"name": "icon_36_add",
"font_class": "icon_36_add",
"unicode": "e65a",
"unicode_decimal": 58970
},
{
"icon_id": "46076927",
"name": "icon_32_location",
"font_class": "icon_32_location",
"unicode": "e659",
"unicode_decimal": 58969
},
{
"icon_id": "46076827",
"name": "icon_24_mypoints",
"font_class": "icon_24_mypoints",
"unicode": "e657",
"unicode_decimal": 58967
},
{
"icon_id": "45986664",
"name": "icon_44_me_about",
"font_class": "icon_44_me_about",
"unicode": "e656",
"unicode_decimal": 58966
},
{
"icon_id": "45986657",
"name": "icon_44_me_pointsmall",
"font_class": "icon_44_me_pointsmall",
"unicode": "e658",
"unicode_decimal": 58968
},
{
"icon_id": "45876267",
"name": "icon_44_search",
"font_class": "icon_44_search",
"unicode": "e655",
"unicode_decimal": 58965
},
{
"icon_id": "45855059",
"name": "icon_36_clear_people",
"font_class": "icon_36_clear_people",
"unicode": "e654",
"unicode_decimal": 58964
},
{
"icon_id": "45530506",
"name": "icon_44_me_log_out",
"font_class": "icon_44_me_log_out",
"unicode": "e652",
"unicode_decimal": 58962
},
{
"icon_id": "45530507",
"name": "icon_44_me_switch",
"font_class": "icon_44_me_switch",
"unicode": "e653",
"unicode_decimal": 58963
},
{
"icon_id": "45513436",
"name": "icon_44_wechat_share_white",
"font_class": "icon_44_wechat_share_white",
"unicode": "e651",
"unicode_decimal": 58961
},
{
"icon_id": "45513173",
"name": "icon_32_publish",
"font_class": "icon_32_publish",
"unicode": "e64e",
"unicode_decimal": 58958
},
{
"icon_id": "45513174",
"name": "icon_32_close",
"font_class": "icon_32_close",
"unicode": "e64f",
"unicode_decimal": 58959
},
{
"icon_id": "45513172",
"name": "icon_32_output",
"font_class": "icon_32_output",
"unicode": "e650",
"unicode_decimal": 58960
},
{
"icon_id": "45500127",
"name": "icon_24_download",
"font_class": "icon_24_download",
"unicode": "e64d",
"unicode_decimal": 58957
},
{
"icon_id": "45492400",
"name": "icon_voice_pause",
"font_class": "icon_voice_pause",
"unicode": "e64b",
"unicode_decimal": 58955
},
{
"icon_id": "45492399",
"name": "icon_voice",
"font_class": "icon_voice",
"unicode": "e64c",
"unicode_decimal": 58956
},
{
"icon_id": "45263171",
"name": "icon_subtract",
"font_class": "icon_subtract",
"unicode": "e64a",
"unicode_decimal": 58954
},
{
"icon_id": "45214203",
"name": "icon_44_edit",
"font_class": "icon_44_edit",
"unicode": "e648",
"unicode_decimal": 58952
},
{
"icon_id": "45214202",
"name": "icon_44_delete",
"font_class": "icon_44_delete",
"unicode": "e649",
"unicode_decimal": 58953
},
{
"icon_id": "45160662",
"name": "icon_44_cancel_account",
"font_class": "icon_44_cancel_account",
"unicode": "e647",
"unicode_decimal": 58951
},
{
"icon_id": "45103313",
"name": "icon_24_search",
"font_class": "icon_24_search",
"unicode": "e646",
"unicode_decimal": 58950
},
{
"icon_id": "45037865",
"name": "icon_24_up",
"font_class": "icon_24_up",
"unicode": "e645",
"unicode_decimal": 58949
},
{
"icon_id": "44661359",
"name": "icon_msg_contacts",
"font_class": "icon_msg_contacts",
"unicode": "e644",
"unicode_decimal": 58948
},
{
"icon_id": "44659960",
"name": "icon_msg_video",
"font_class": "icon_msg_video",
"unicode": "e63e",
"unicode_decimal": 58942
},
{
"icon_id": "44659959",
"name": "icon_msg_search",
"font_class": "icon_msg_search",
"unicode": "e63f",
"unicode_decimal": 58943
},
{
"icon_id": "44659958",
"name": "icon_msg_call",
"font_class": "icon_msg_call",
"unicode": "e640",
"unicode_decimal": 58944
},
{
"icon_id": "44659956",
"name": "icon_msg_photo",
"font_class": "icon_msg_photo",
"unicode": "e641",
"unicode_decimal": 58945
},
{
"icon_id": "44659957",
"name": "icon_msg_img",
"font_class": "icon_msg_img",
"unicode": "e642",
"unicode_decimal": 58946
},
{
"icon_id": "44659955",
"name": "icon_msg_file",
"font_class": "icon_msg_file",
"unicode": "e643",
"unicode_decimal": 58947
},
{
"icon_id": "44625643",
"name": "icon_32_arrow_right",
"font_class": "icon_32_arrow_right",
"unicode": "e61d",
"unicode_decimal": 58909
},
{
"icon_id": "44625452",
"name": "icon_44_me_password",
"font_class": "icon_44_me_password",
"unicode": "e639",
"unicode_decimal": 58937
},
{
"icon_id": "44625448",
"name": "icon_44_me_help",
"font_class": "icon_44_me_help",
"unicode": "e63a",
"unicode_decimal": 58938
},
{
"icon_id": "44625447",
"name": "icon_24_minus",
"font_class": "icon_24_minus",
"unicode": "e63b",
"unicode_decimal": 58939
},
{
"icon_id": "44625450",
"name": "icon_36_team",
"font_class": "icon_36_team",
"unicode": "e63c",
"unicode_decimal": 58940
},
{
"icon_id": "44625446",
"name": "icon_32_filter",
"font_class": "icon_32_filter",
"unicode": "e63d",
"unicode_decimal": 58941
},
{
"icon_id": "44625458",
"name": "icon_44_quit_lite",
"font_class": "icon_44_quit_lite",
"unicode": "e631",
"unicode_decimal": 58929
},
{
"icon_id": "44625459",
"name": "icon_44_me_version",
"font_class": "icon_44_me_version",
"unicode": "e632",
"unicode_decimal": 58930
},
{
"icon_id": "44625456",
"name": "icon_36_question",
"font_class": "icon_36_question",
"unicode": "e633",
"unicode_decimal": 58931
},
{
"icon_id": "44625457",
"name": "icon_44_me_privacy",
"font_class": "icon_44_me_privacy",
"unicode": "e634",
"unicode_decimal": 58932
},
{
"icon_id": "44625455",
"name": "icon_44_more2",
"font_class": "icon_44_more2",
"unicode": "e635",
"unicode_decimal": 58933
},
{
"icon_id": "44625453",
"name": "icon_36_only_see",
"font_class": "icon_36_only_see",
"unicode": "e636",
"unicode_decimal": 58934
},
{
"icon_id": "44625454",
"name": "icon_44_me_user",
"font_class": "icon_44_me_user",
"unicode": "e637",
"unicode_decimal": 58935
},
{
"icon_id": "44625461",
"name": "icon_44_me_safe",
"font_class": "icon_44_me_safe",
"unicode": "e62c",
"unicode_decimal": 58924
},
{
"icon_id": "44625460",
"name": "icon_44_me_phone",
"font_class": "icon_44_me_phone",
"unicode": "e62d",
"unicode_decimal": 58925
},
{
"icon_id": "44625445",
"name": "icon_24_copy",
"font_class": "icon_24_copy",
"unicode": "e62e",
"unicode_decimal": 58926
},
{
"icon_id": "44625444",
"name": "icon_32_quit",
"font_class": "icon_32_quit",
"unicode": "e630",
"unicode_decimal": 58928
},
{
"icon_id": "44572509",
"name": "icon_44_calendar",
"font_class": "icon_44_calendar",
"unicode": "e626",
"unicode_decimal": 58918
},
{
"icon_id": "44572496",
"name": "icon_32_student",
"font_class": "icon_32_student",
"unicode": "e627",
"unicode_decimal": 58919
},
{
"icon_id": "44572501",
"name": "icon_36_delete",
"font_class": "icon_36_delete",
"unicode": "e628",
"unicode_decimal": 58920
},
{
"icon_id": "44572505",
"name": "icon_44_more",
"font_class": "icon_44_more",
"unicode": "e629",
"unicode_decimal": 58921
},
{
"icon_id": "44572502",
"name": "icon_44_arrow_left",
"font_class": "icon_44_arrow_left",
"unicode": "e62a",
"unicode_decimal": 58922
},
{
"icon_id": "44572499",
"name": "icon_36_edit_line",
"font_class": "icon_36_edit_line",
"unicode": "e62b",
"unicode_decimal": 58923
},
{
"icon_id": "44572515",
"name": "icon_44_arrow_right",
"font_class": "icon_44_arrow_right",
"unicode": "e622",
"unicode_decimal": 58914
},
{
"icon_id": "44572507",
"name": "icon_24_delete",
"font_class": "icon_24_delete",
"unicode": "e623",
"unicode_decimal": 58915
},
{
"icon_id": "44572513",
"name": "icon_56_msg_add",
"font_class": "icon_56_msg_add",
"unicode": "e624",
"unicode_decimal": 58916
},
{
"icon_id": "44572511",
"name": "icon_56_msg_face",
"font_class": "icon_56_msg_face",
"unicode": "e625",
"unicode_decimal": 58917
},
{
"icon_id": "44572516",
"name": "icon_56_msg_voice",
"font_class": "icon_56_msg_voice",
"unicode": "e616",
"unicode_decimal": 58902
},
{
"icon_id": "44572514",
"name": "icon_44_share",
"font_class": "icon_44_share",
"unicode": "e615",
"unicode_decimal": 58901
},
{
"icon_id": "44572500",
"name": "icon_36_hint",
"font_class": "icon_36_hint",
"unicode": "e613",
"unicode_decimal": 58899
},
{
"icon_id": "44572510",
"name": "icon_24_add",
"font_class": "icon_24_add",
"unicode": "e617",
"unicode_decimal": 58903
},
{
"icon_id": "44572512",
"name": "icon_24_plus",
"font_class": "icon_24_plus",
"unicode": "e618",
"unicode_decimal": 58904
},
{
"icon_id": "44572508",
"name": "icon_44_keyboard",
"font_class": "icon_44_keyboard",
"unicode": "e614",
"unicode_decimal": 58900
},
{
"icon_id": "44572506",
"name": "icon_44_quit",
"font_class": "icon_44_quit",
"unicode": "e619",
"unicode_decimal": 58905
},
{
"icon_id": "44572504",
"name": "icon_44_add",
"font_class": "icon_44_add",
"unicode": "e61a",
"unicode_decimal": 58906
},
{
"icon_id": "44572495",
"name": "icon_24_switch",
"font_class": "icon_24_switch",
"unicode": "e61b",
"unicode_decimal": 58907
},
{
"icon_id": "44572503",
"name": "icon_44_arrow_down_line",
"font_class": "icon_44_arrow_down_line",
"unicode": "e61c",
"unicode_decimal": 58908
},
{
"icon_id": "44572493",
"name": "icon_24_arrow_right",
"font_class": "icon_24_arrow_right",
"unicode": "e61e",
"unicode_decimal": 58910
},
{
"icon_id": "44572498",
"name": "icon_32_add",
"font_class": "icon_32_add",
"unicode": "e61f",
"unicode_decimal": 58911
},
{
"icon_id": "44572494",
"name": "icon_24_edit",
"font_class": "icon_24_edit",
"unicode": "e620",
"unicode_decimal": 58912
},
{
"icon_id": "44572492",
"name": "icon_24_arrow_down",
"font_class": "icon_24_arrow_down",
"unicode": "e621",
"unicode_decimal": 58913
}
]
}

Binary file not shown.

View File

@ -0,0 +1,23 @@
# 图标字体生成器配置文件
# 用于生成 Flutter IconData 常量
generator:
name: "Example App Icons"
version: "1.0"
author: "Example"
input:
# 字体文件路径
font_file: "assets/fonts/iconfont.ttf"
# JSON 配置文件路径
json_file: "assets/fonts/iconfont.json"
# 字体家族名称
font_family: "iconfont"
output:
# 生成的 Dart 文件路径
file_path: "lib/generated/icons.dart"
# 生成的类名
class_name: "AppIcons"
# 是否生成文档注释
generate_docs: true

View File

@ -1,24 +1,9 @@
import 'package:flutter/widgets.dart';
///
///
///
class ExampleIcon implements Comparable {
///
class ExampleIcon {
const ExampleIcon(this.iconData, this.title);
final IconData iconData;
final String title;
ExampleIcon(this.iconData, this.title);
@override
String toString() => 'ExampleIcon{iconData: $iconData, title: $title}';
@override
bool operator ==(Object other) =>
identical(this, other) || other is ExampleIcon && runtimeType == other.runtimeType && iconData == other.iconData && title == other.title;
@override
int get hashCode => iconData.hashCode ^ title.hashCode;
@override
int compareTo(other) => title.compareTo(other.title);
}

View File

@ -0,0 +1,261 @@
// ignore_for_file: constant_identifier_names
// ============================================
// yx_icon_fonts
// : 2025-12-17 11:07
// : 76
// ============================================
import 'package:flutter/widgets.dart';
/// Example App Icons
///
/// Flutter Icon 使
///
/// :
/// ```dart
/// Icon(AppIcons.iconName, size: 24)
/// ```
class AppIcons {
AppIcons._();
// IconData
static const _icon = _IconDataFactory._();
/// icon_32_clean (U+E660)
static final IconData icon32Clean = _icon(0xe660);
/// icon_36_viewhistory (U+E65F)
static final IconData icon36Viewhistory = _icon(0xe65f);
/// icon_36_revoke (U+E65E)
static final IconData icon36Revoke = _icon(0xe65e);
/// icon_30_edit (U+E65B)
static final IconData icon30Edit = _icon(0xe65b);
/// icon_24_copy2 (U+E65C)
static final IconData icon24Copy2 = _icon(0xe65c);
/// icon_30_delete (U+E65D)
static final IconData icon30Delete = _icon(0xe65d);
/// icon_36_add (U+E65A)
static final IconData icon36Add = _icon(0xe65a);
/// icon_32_location (U+E659)
static final IconData icon32Location = _icon(0xe659);
/// icon_24_mypoints (U+E657)
static final IconData icon24Mypoints = _icon(0xe657);
/// icon_44_me_about (U+E656)
static final IconData icon44MeAbout = _icon(0xe656);
/// icon_44_me_pointsmall (U+E658)
static final IconData icon44MePointsmall = _icon(0xe658);
/// icon_44_search (U+E655)
static final IconData icon44Search = _icon(0xe655);
/// icon_36_clear_people (U+E654)
static final IconData icon36ClearPeople = _icon(0xe654);
/// icon_44_me_log_out (U+E652)
static final IconData icon44MeLogOut = _icon(0xe652);
/// icon_44_me_switch (U+E653)
static final IconData icon44MeSwitch = _icon(0xe653);
/// icon_44_wechat_share_white (U+E651)
static final IconData icon44WechatShareWhite = _icon(0xe651);
/// icon_32_publish (U+E64E)
static final IconData icon32Publish = _icon(0xe64e);
/// icon_32_close (U+E64F)
static final IconData icon32Close = _icon(0xe64f);
/// icon_32_output (U+E650)
static final IconData icon32Output = _icon(0xe650);
/// icon_24_download (U+E64D)
static final IconData icon24Download = _icon(0xe64d);
/// icon_voice_pause (U+E64B)
static final IconData iconVoicePause = _icon(0xe64b);
/// icon_voice (U+E64C)
static final IconData iconVoice = _icon(0xe64c);
/// icon_subtract (U+E64A)
static final IconData iconSubtract = _icon(0xe64a);
/// icon_44_edit (U+E648)
static final IconData icon44Edit = _icon(0xe648);
/// icon_44_delete (U+E649)
static final IconData icon44Delete = _icon(0xe649);
/// icon_44_cancel_account (U+E647)
static final IconData icon44CancelAccount = _icon(0xe647);
/// icon_24_search (U+E646)
static final IconData icon24Search = _icon(0xe646);
/// icon_24_up (U+E645)
static final IconData icon24Up = _icon(0xe645);
/// icon_msg_contacts (U+E644)
static final IconData iconMsgContacts = _icon(0xe644);
/// icon_msg_video (U+E63E)
static final IconData iconMsgVideo = _icon(0xe63e);
/// icon_msg_search (U+E63F)
static final IconData iconMsgSearch = _icon(0xe63f);
/// icon_msg_call (U+E640)
static final IconData iconMsgCall = _icon(0xe640);
/// icon_msg_photo (U+E641)
static final IconData iconMsgPhoto = _icon(0xe641);
/// icon_msg_img (U+E642)
static final IconData iconMsgImg = _icon(0xe642);
/// icon_msg_file (U+E643)
static final IconData iconMsgFile = _icon(0xe643);
/// icon_32_arrow_right (U+E61D)
static final IconData icon32ArrowRight = _icon(0xe61d);
/// icon_44_me_password (U+E639)
static final IconData icon44MePassword = _icon(0xe639);
/// icon_44_me_help (U+E63A)
static final IconData icon44MeHelp = _icon(0xe63a);
/// icon_24_minus (U+E63B)
static final IconData icon24Minus = _icon(0xe63b);
/// icon_36_team (U+E63C)
static final IconData icon36Team = _icon(0xe63c);
/// icon_32_filter (U+E63D)
static final IconData icon32Filter = _icon(0xe63d);
/// icon_44_quit_lite (U+E631)
static final IconData icon44QuitLite = _icon(0xe631);
/// icon_44_me_version (U+E632)
static final IconData icon44MeVersion = _icon(0xe632);
/// icon_36_question (U+E633)
static final IconData icon36Question = _icon(0xe633);
/// icon_44_me_privacy (U+E634)
static final IconData icon44MePrivacy = _icon(0xe634);
/// icon_44_more2 (U+E635)
static final IconData icon44More2 = _icon(0xe635);
/// icon_36_only_see (U+E636)
static final IconData icon36OnlySee = _icon(0xe636);
/// icon_44_me_user (U+E637)
static final IconData icon44MeUser = _icon(0xe637);
/// icon_44_me_safe (U+E62C)
static final IconData icon44MeSafe = _icon(0xe62c);
/// icon_44_me_phone (U+E62D)
static final IconData icon44MePhone = _icon(0xe62d);
/// icon_24_copy (U+E62E)
static final IconData icon24Copy = _icon(0xe62e);
/// icon_32_quit (U+E630)
static final IconData icon32Quit = _icon(0xe630);
/// icon_44_calendar (U+E626)
static final IconData icon44Calendar = _icon(0xe626);
/// icon_32_student (U+E627)
static final IconData icon32Student = _icon(0xe627);
/// icon_36_delete (U+E628)
static final IconData icon36Delete = _icon(0xe628);
/// icon_44_more (U+E629)
static final IconData icon44More = _icon(0xe629);
/// icon_44_arrow_left (U+E62A)
static final IconData icon44ArrowLeft = _icon(0xe62a);
/// icon_36_edit_line (U+E62B)
static final IconData icon36EditLine = _icon(0xe62b);
/// icon_44_arrow_right (U+E622)
static final IconData icon44ArrowRight = _icon(0xe622);
/// icon_24_delete (U+E623)
static final IconData icon24Delete = _icon(0xe623);
/// icon_56_msg_add (U+E624)
static final IconData icon56MsgAdd = _icon(0xe624);
/// icon_56_msg_face (U+E625)
static final IconData icon56MsgFace = _icon(0xe625);
/// icon_56_msg_voice (U+E616)
static final IconData icon56MsgVoice = _icon(0xe616);
/// icon_44_share (U+E615)
static final IconData icon44Share = _icon(0xe615);
/// icon_36_hint (U+E613)
static final IconData icon36Hint = _icon(0xe613);
/// icon_24_add (U+E617)
static final IconData icon24Add = _icon(0xe617);
/// icon_24_plus (U+E618)
static final IconData icon24Plus = _icon(0xe618);
/// icon_44_keyboard (U+E614)
static final IconData icon44Keyboard = _icon(0xe614);
/// icon_44_quit (U+E619)
static final IconData icon44Quit = _icon(0xe619);
/// icon_44_add (U+E61A)
static final IconData icon44Add = _icon(0xe61a);
/// icon_24_switch (U+E61B)
static final IconData icon24Switch = _icon(0xe61b);
/// icon_44_arrow_down_line (U+E61C)
static final IconData icon44ArrowDownLine = _icon(0xe61c);
/// icon_24_arrow_right (U+E61E)
static final IconData icon24ArrowRight = _icon(0xe61e);
/// icon_32_add (U+E61F)
static final IconData icon32Add = _icon(0xe61f);
/// icon_24_edit (U+E620)
static final IconData icon24Edit = _icon(0xe620);
/// icon_24_arrow_down (U+E621)
static final IconData icon24ArrowDown = _icon(0xe621);
}
/// IconData
class _IconDataFactory {
const _IconDataFactory._();
static const String _fontFamily = 'iconfont';
IconData call(int codePoint) => IconData(codePoint, fontFamily: _fontFamily);
}

View File

@ -1,113 +1,112 @@
import 'package:yx_icon_fonts/yx_icon_fonts.dart';
import 'package:yx_icon_fonts_example/example_icon.dart';
import 'package:yx_icon_fonts_example/generated/icons.dart';
//
// 使 AppIcons
final icons = <ExampleIcon>[
//
ExampleIcon(YXIconFonts.icon32Clean, 'icon 32 clean'),
ExampleIcon(YXIconFonts.icon36Viewhistory, 'icon 36 viewhistory'),
ExampleIcon(YXIconFonts.icon36Revoke, 'icon 36 revoke'),
ExampleIcon(YXIconFonts.icon32Location, 'icon 32 location'),
ExampleIcon(YXIconFonts.icon24Mypoints, 'icon 24 mypoints'),
ExampleIcon(YXIconFonts.icon44Search, 'icon 44 search'),
ExampleIcon(YXIconFonts.icon36ClearPeople, 'icon 36 clear people'),
ExampleIcon(YXIconFonts.icon32Publish, 'icon 32 publish'),
ExampleIcon(YXIconFonts.icon32Close, 'icon 32 close'),
ExampleIcon(YXIconFonts.icon32Output, 'icon 32 output'),
ExampleIcon(YXIconFonts.icon24Download, 'icon 24 download'),
ExampleIcon(YXIconFonts.iconVoicePause, 'icon voice pause'),
ExampleIcon(YXIconFonts.iconVoice, 'icon voice'),
ExampleIcon(YXIconFonts.iconSubtract, 'icon subtract'),
ExampleIcon(YXIconFonts.icon44CancelAccount, 'icon 44 cancel account'),
ExampleIcon(YXIconFonts.icon24Search, 'icon 24 search'),
ExampleIcon(YXIconFonts.icon24Up, 'icon 24 up'),
ExampleIcon(YXIconFonts.icon24Minus, 'icon 24 minus'),
ExampleIcon(YXIconFonts.icon36OnlySee, 'icon 36 only see'),
ExampleIcon(YXIconFonts.icon24Plus, 'icon 24 plus'),
ExampleIcon(AppIcons.icon32Clean, 'icon 32 clean'),
ExampleIcon(AppIcons.icon36Viewhistory, 'icon 36 viewhistory'),
ExampleIcon(AppIcons.icon36Revoke, 'icon 36 revoke'),
ExampleIcon(AppIcons.icon32Location, 'icon 32 location'),
ExampleIcon(AppIcons.icon24Mypoints, 'icon 24 mypoints'),
ExampleIcon(AppIcons.icon44Search, 'icon 44 search'),
ExampleIcon(AppIcons.icon36ClearPeople, 'icon 36 clear people'),
ExampleIcon(AppIcons.icon32Publish, 'icon 32 publish'),
ExampleIcon(AppIcons.icon32Close, 'icon 32 close'),
ExampleIcon(AppIcons.icon32Output, 'icon 32 output'),
ExampleIcon(AppIcons.icon24Download, 'icon 24 download'),
ExampleIcon(AppIcons.iconVoicePause, 'icon voice pause'),
ExampleIcon(AppIcons.iconVoice, 'icon voice'),
ExampleIcon(AppIcons.iconSubtract, 'icon subtract'),
ExampleIcon(AppIcons.icon44CancelAccount, 'icon 44 cancel account'),
ExampleIcon(AppIcons.icon24Search, 'icon 24 search'),
ExampleIcon(AppIcons.icon24Up, 'icon 24 up'),
ExampleIcon(AppIcons.icon24Minus, 'icon 24 minus'),
ExampleIcon(AppIcons.icon36OnlySee, 'icon 36 only see'),
ExampleIcon(AppIcons.icon24Plus, 'icon 24 plus'),
//
ExampleIcon(YXIconFonts.icon30Edit, 'icon 30 edit'),
ExampleIcon(YXIconFonts.icon44Edit, 'icon 44 edit'),
ExampleIcon(YXIconFonts.icon36EditLine, 'icon 36 edit line'),
ExampleIcon(YXIconFonts.icon24Edit, 'icon 24 edit'),
ExampleIcon(AppIcons.icon30Edit, 'icon 30 edit'),
ExampleIcon(AppIcons.icon44Edit, 'icon 44 edit'),
ExampleIcon(AppIcons.icon36EditLine, 'icon 36 edit line'),
ExampleIcon(AppIcons.icon24Edit, 'icon 24 edit'),
//
ExampleIcon(YXIconFonts.icon24Copy2, 'icon 24 copy2'),
ExampleIcon(YXIconFonts.icon24Copy, 'icon 24 copy'),
ExampleIcon(AppIcons.icon24Copy2, 'icon 24 copy2'),
ExampleIcon(AppIcons.icon24Copy, 'icon 24 copy'),
//
ExampleIcon(YXIconFonts.icon30Delete, 'icon 30 delete'),
ExampleIcon(YXIconFonts.icon44Delete, 'icon 44 delete'),
ExampleIcon(YXIconFonts.icon36Delete, 'icon 36 delete'),
ExampleIcon(YXIconFonts.icon24Delete, 'icon 24 delete'),
ExampleIcon(AppIcons.icon30Delete, 'icon 30 delete'),
ExampleIcon(AppIcons.icon44Delete, 'icon 44 delete'),
ExampleIcon(AppIcons.icon36Delete, 'icon 36 delete'),
ExampleIcon(AppIcons.icon24Delete, 'icon 24 delete'),
//
ExampleIcon(YXIconFonts.icon36Add, 'icon 36 add'),
ExampleIcon(YXIconFonts.icon24Add, 'icon 24 add'),
ExampleIcon(YXIconFonts.icon44Add, 'icon 44 add'),
ExampleIcon(YXIconFonts.icon32Add, 'icon 32 add'),
ExampleIcon(AppIcons.icon36Add, 'icon 36 add'),
ExampleIcon(AppIcons.icon24Add, 'icon 24 add'),
ExampleIcon(AppIcons.icon44Add, 'icon 44 add'),
ExampleIcon(AppIcons.icon32Add, 'icon 32 add'),
//
ExampleIcon(YXIconFonts.icon44MeAbout, 'icon 44 me about'),
ExampleIcon(YXIconFonts.icon44MePointsmall, 'icon 44 me pointsmall'),
ExampleIcon(YXIconFonts.icon44MeLogOut, 'icon 44 me log out'),
ExampleIcon(YXIconFonts.icon44MeSwitch, 'icon 44 me switch'),
ExampleIcon(YXIconFonts.icon44MePassword, 'icon 44 me password'),
ExampleIcon(YXIconFonts.icon44MeHelp, 'icon 44 me help'),
ExampleIcon(YXIconFonts.icon44MeVersion, 'icon 44 me version'),
ExampleIcon(YXIconFonts.icon44MePrivacy, 'icon 44 me privacy'),
ExampleIcon(YXIconFonts.icon44MeUser, 'icon 44 me user'),
ExampleIcon(YXIconFonts.icon44MeSafe, 'icon 44 me safe'),
ExampleIcon(YXIconFonts.icon44MePhone, 'icon 44 me phone'),
ExampleIcon(AppIcons.icon44MeAbout, 'icon 44 me about'),
ExampleIcon(AppIcons.icon44MePointsmall, 'icon 44 me pointsmall'),
ExampleIcon(AppIcons.icon44MeLogOut, 'icon 44 me log out'),
ExampleIcon(AppIcons.icon44MeSwitch, 'icon 44 me switch'),
ExampleIcon(AppIcons.icon44MePassword, 'icon 44 me password'),
ExampleIcon(AppIcons.icon44MeHelp, 'icon 44 me help'),
ExampleIcon(AppIcons.icon44MeVersion, 'icon 44 me version'),
ExampleIcon(AppIcons.icon44MePrivacy, 'icon 44 me privacy'),
ExampleIcon(AppIcons.icon44MeUser, 'icon 44 me user'),
ExampleIcon(AppIcons.icon44MeSafe, 'icon 44 me safe'),
ExampleIcon(AppIcons.icon44MePhone, 'icon 44 me phone'),
//
ExampleIcon(YXIconFonts.icon44WechatShareWhite, 'icon 44 wechat share white'),
ExampleIcon(YXIconFonts.icon44Share, 'icon 44 share'),
ExampleIcon(AppIcons.icon44WechatShareWhite, 'icon 44 wechat share white'),
ExampleIcon(AppIcons.icon44Share, 'icon 44 share'),
//
ExampleIcon(YXIconFonts.iconMsgContacts, 'icon msg contacts'),
ExampleIcon(YXIconFonts.iconMsgVideo, 'icon msg video'),
ExampleIcon(YXIconFonts.iconMsgSearch, 'icon msg search'),
ExampleIcon(YXIconFonts.iconMsgCall, 'icon msg call'),
ExampleIcon(YXIconFonts.iconMsgPhoto, 'icon msg photo'),
ExampleIcon(YXIconFonts.iconMsgImg, 'icon msg img'),
ExampleIcon(YXIconFonts.iconMsgFile, 'icon msg file'),
ExampleIcon(YXIconFonts.icon56MsgAdd, 'icon 56 msg add'),
ExampleIcon(YXIconFonts.icon56MsgFace, 'icon 56 msg face'),
ExampleIcon(YXIconFonts.icon56MsgVoice, 'icon 56 msg voice'),
ExampleIcon(AppIcons.iconMsgContacts, 'icon msg contacts'),
ExampleIcon(AppIcons.iconMsgVideo, 'icon msg video'),
ExampleIcon(AppIcons.iconMsgSearch, 'icon msg search'),
ExampleIcon(AppIcons.iconMsgCall, 'icon msg call'),
ExampleIcon(AppIcons.iconMsgPhoto, 'icon msg photo'),
ExampleIcon(AppIcons.iconMsgImg, 'icon msg img'),
ExampleIcon(AppIcons.iconMsgFile, 'icon msg file'),
ExampleIcon(AppIcons.icon56MsgAdd, 'icon 56 msg add'),
ExampleIcon(AppIcons.icon56MsgFace, 'icon 56 msg face'),
ExampleIcon(AppIcons.icon56MsgVoice, 'icon 56 msg voice'),
//
ExampleIcon(YXIconFonts.icon32ArrowRight, 'icon 32 arrow right'),
ExampleIcon(YXIconFonts.icon44ArrowLeft, 'icon 44 arrow left'),
ExampleIcon(YXIconFonts.icon44ArrowRight, 'icon 44 arrow right'),
ExampleIcon(YXIconFonts.icon44ArrowDownLine, 'icon 44 arrow down line'),
ExampleIcon(YXIconFonts.icon24ArrowRight, 'icon 24 arrow right'),
ExampleIcon(YXIconFonts.icon24ArrowDown, 'icon 24 arrow down'),
ExampleIcon(AppIcons.icon32ArrowRight, 'icon 32 arrow right'),
ExampleIcon(AppIcons.icon44ArrowLeft, 'icon 44 arrow left'),
ExampleIcon(AppIcons.icon44ArrowRight, 'icon 44 arrow right'),
ExampleIcon(AppIcons.icon44ArrowDownLine, 'icon 44 arrow down line'),
ExampleIcon(AppIcons.icon24ArrowRight, 'icon 24 arrow right'),
ExampleIcon(AppIcons.icon24ArrowDown, 'icon 24 arrow down'),
//
ExampleIcon(YXIconFonts.icon36Team, 'icon 36 team'),
ExampleIcon(YXIconFonts.icon32Student, 'icon 32 student'),
ExampleIcon(AppIcons.icon36Team, 'icon 36 team'),
ExampleIcon(AppIcons.icon32Student, 'icon 32 student'),
//
ExampleIcon(YXIconFonts.icon32Filter, 'icon 32 filter'),
ExampleIcon(YXIconFonts.icon36Question, 'icon 36 question'),
ExampleIcon(YXIconFonts.icon36Hint, 'icon 36 hint'),
ExampleIcon(YXIconFonts.icon24Switch, 'icon 24 switch'),
ExampleIcon(AppIcons.icon32Filter, 'icon 32 filter'),
ExampleIcon(AppIcons.icon36Question, 'icon 36 question'),
ExampleIcon(AppIcons.icon36Hint, 'icon 36 hint'),
ExampleIcon(AppIcons.icon24Switch, 'icon 24 switch'),
// 退
ExampleIcon(YXIconFonts.icon44QuitLite, 'icon 44 quit lite'),
ExampleIcon(YXIconFonts.icon32Quit, 'icon 32 quit'),
ExampleIcon(YXIconFonts.icon44Quit, 'icon 44 quit'),
ExampleIcon(AppIcons.icon44QuitLite, 'icon 44 quit lite'),
ExampleIcon(AppIcons.icon32Quit, 'icon 32 quit'),
ExampleIcon(AppIcons.icon44Quit, 'icon 44 quit'),
//
ExampleIcon(YXIconFonts.icon44More2, 'icon 44 more2'),
ExampleIcon(YXIconFonts.icon44More, 'icon 44 more'),
ExampleIcon(AppIcons.icon44More2, 'icon 44 more2'),
ExampleIcon(AppIcons.icon44More, 'icon 44 more'),
//
ExampleIcon(YXIconFonts.icon44Calendar, 'icon 44 calendar'),
ExampleIcon(AppIcons.icon44Calendar, 'icon 44 calendar'),
//
ExampleIcon(YXIconFonts.icon44Keyboard, 'icon 44 keyboard'),
ExampleIcon(AppIcons.icon44Keyboard, 'icon 44 keyboard'),
];

View File

@ -1,6 +1,5 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:yx_icon_fonts/yx_icon_fonts.dart';
import 'package:yx_icon_fonts_example/icons.dart';
void main() {
@ -35,12 +34,18 @@ class YXIconFontsGalleryHome extends StatefulWidget {
}
class _YXIconFontsGalleryHomeState extends State<YXIconFontsGalleryHome> {
var _searchTerm = "";
var _searchTerm = '';
var _isSearching = false;
@override
Widget build(BuildContext context) {
final filteredIcons = icons.where((icon) => _searchTerm.isEmpty || icon.title.toLowerCase().contains(_searchTerm.toLowerCase())).toList();
final filteredIcons = icons
.where(
(icon) =>
_searchTerm.isEmpty ||
icon.title.toLowerCase().contains(_searchTerm.toLowerCase()),
)
.toList();
return Scaffold(
appBar: _isSearching ? _searchBar(context) : _titleBar(),
@ -69,7 +74,7 @@ class _YXIconFontsGalleryHomeState extends State<YXIconFontsGalleryHome> {
alignment: Alignment.center,
child: Hero(
tag: icon,
child: YXIcon(
child: Icon(
icon.iconData,
size: 100,
),
@ -83,7 +88,7 @@ class _YXIconFontsGalleryHomeState extends State<YXIconFontsGalleryHome> {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Hero(tag: icon, child: YXIcon(icon.iconData)),
Hero(tag: icon, child: Icon(icon.iconData)),
Container(
padding: const EdgeInsets.only(top: 16.0),
child: Text(
@ -92,7 +97,7 @@ class _YXIconFontsGalleryHomeState extends State<YXIconFontsGalleryHome> {
color: Colors.black,
),
),
)
),
],
),
);
@ -103,7 +108,7 @@ class _YXIconFontsGalleryHomeState extends State<YXIconFontsGalleryHome> {
onPressed: () {
setState(() {
_isSearching = !_isSearching;
if (!_isSearching) _searchTerm = "";
if (!_isSearching) _searchTerm = '';
});
},
child: Icon(_isSearching ? Icons.close : Icons.search),
@ -133,7 +138,7 @@ class _YXIconFontsGalleryHomeState extends State<YXIconFontsGalleryHome> {
onPressed: () {
setState(() {
_isSearching = false;
_searchTerm = "";
_searchTerm = '';
});
},
),

View File

@ -99,6 +99,14 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.0"
logging:
dependency: transitive
description:
name: logging
sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.3.0"
matcher:
dependency: transitive
description:
@ -200,13 +208,21 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "15.0.2"
yaml:
dependency: transitive
description:
name: yaml
sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.1.3"
yx_icon_fonts:
dependency: "direct main"
dependency: "direct dev"
description:
path: ".."
relative: true
source: path
version: "1.0.5"
version: "2.0.0"
sdks:
dart: ">=3.8.0-0 <4.0.0"
flutter: ">=3.18.0-18.0.pre.54"

View File

@ -10,13 +10,20 @@ environment:
dependencies:
flutter:
sdk: flutter
dev_dependencies:
flutter_lints: ^3.0.0
flutter_test:
sdk: flutter
# CLI 代码生成工具
yx_icon_fonts:
path: ../
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^3.0.0
flutter:
uses-material-design: true
# 字体配置
fonts:
- family: iconfont
fonts:
- asset: assets/fonts/iconfont.ttf

View File

@ -1,158 +0,0 @@
#!/bin/bash
# YX Icon Fonts 生成脚本
# 用于生成图标数据和示例文件
set -e # 遇到错误时退出
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 打印带颜色的消息
print_info() {
echo -e "${BLUE} $1${NC}"
}
print_success() {
echo -e "${GREEN}$1${NC}"
}
print_warning() {
echo -e "${YELLOW}⚠️ $1${NC}"
}
print_error() {
echo -e "${RED}$1${NC}"
}
# 检查 Dart 是否安装
check_dart() {
if ! command -v dart &> /dev/null; then
print_error "Dart 未安装或不在 PATH 中"
exit 1
fi
}
# 检查必要文件是否存在
check_files() {
if [ ! -f "iconfont.json" ]; then
print_error "找不到 iconfont.json 文件"
exit 1
fi
if [ ! -f "scripts/generate_icons.dart" ]; then
print_error "找不到 scripts/generate_icons.dart 文件"
exit 1
fi
if [ ! -f "scripts/generate_example.dart" ]; then
print_error "找不到 scripts/generate_example.dart 文件"
exit 1
fi
if [ ! -f "scripts/generate_wrapper.dart" ]; then
print_error "找不到 scripts/generate_wrapper.dart 文件"
exit 1
fi
}
# 生成图标数据
generate_icons() {
print_info "正在生成图标数据..."
dart scripts/generate_icons.dart
print_success "图标数据生成完成"
}
# 生成示例文件
generate_example() {
print_info "正在生成示例文件..."
dart scripts/generate_example.dart
print_success "示例文件生成完成"
}
# 生成外部封装文件
generate_wrapper() {
print_info "正在生成外部封装文件..."
dart scripts/generate_wrapper.dart
print_success "外部封装文件生成完成"
}
# 生成所有文件
generate_all() {
print_info "开始生成所有文件..."
echo
generate_icons
echo
generate_wrapper
echo
generate_example
echo
print_success "所有文件生成完成!"
}
# 显示帮助信息
show_help() {
echo "YX Icon Fonts 生成脚本"
echo
echo "用法: $0 [选项]"
echo
echo "选项:"
echo " icons 只生成图标数据 (lib/src/yx_icon_fonts_data.dart)"
echo " wrapper 只生成外部封装文件 (generate/icons.dart)"
echo " example 只生成示例文件 (example/lib/icons.dart)"
echo " all 生成所有文件 (默认)"
echo " help 显示此帮助信息"
echo
echo "示例:"
echo " $0 # 生成所有文件"
echo " $0 icons # 只生成图标数据"
echo " $0 wrapper # 只生成外部封装文件"
echo " $0 example # 只生成示例文件"
echo
}
# 主函数
main() {
local action=${1:-all}
case $action in
"icons")
check_dart
check_files
generate_icons
;;
"wrapper")
check_dart
check_files
generate_wrapper
;;
"example")
check_dart
check_files
generate_example
;;
"all")
check_dart
check_files
generate_all
;;
"help"|"-h"|"--help")
show_help
;;
*)
print_error "未知选项: $action"
echo
show_help
exit 1
;;
esac
}
# 运行主函数
main "$@"

View File

@ -0,0 +1,57 @@
# 图标字体生成器配置文件模板
# 复制此文件到您的项目根目录,重命名为 icon_generator_config.yaml
# 并根据需要修改配置
# 生成器信息
generator:
# 项目名称(用于生成的代码注释)
name: "MyApp Icons"
# 版本
version: "1.0"
# 作者
author: "Your Name"
# 输入配置
input:
# 字体文件路径(相对于项目根目录)
# 这个文件从 iconfont.cn 下载
font_file: "assets/fonts/iconfont.ttf"
# JSON 配置文件路径(从 iconfont.cn 下载)
# 包含所有图标的 unicode 编码和名称
json_file: "assets/fonts/iconfont.json"
# 字体家族名称
# 需要与 pubspec.yaml 中 flutter.fonts 配置的 family 一致
# 例如:
# flutter:
# fonts:
# - family: iconfont
# fonts:
# - asset: assets/fonts/iconfont.ttf
font_family: "iconfont"
# 字体包名(可选)
# 如果字体文件位于另一个 package 中,请指定包名
# font_package: "my_icons_package"
# 输出配置
output:
# 生成的 Dart 文件路径
# 建议放在 lib/generated/ 目录下,并添加到 .gitignore
file_path: "lib/generated/icons.dart"
# 生成的类名
# 使用时: Icon(AppIcons.iconName, size: 24)
class_name: "AppIcons"
# 是否生成文档注释
# 设为 true 会为每个图标生成 Unicode 说明
generate_docs: true
# 是否使用 const 构造函数
use_const_constructor: true
# 包导入路径(可选)
# 如果需要在生成的文件中添加特定的 package 导入
# package_import: "package:my_app/common/icons.dart"

View File

@ -1,20 +0,0 @@
import 'package:flutter/material.dart';
void main() {
runApp(const MainApp());
}
class MainApp extends StatelessWidget {
const MainApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: Scaffold(
body: Center(
child: Text('Hello World!'),
),
),
);
}
}

View File

@ -0,0 +1,172 @@
import 'dart:io';
import 'package:logging/logging.dart';
import 'package:yx_icon_fonts/src/commands/base_command.dart';
import 'package:yx_icon_fonts/src/commands/generate_command.dart';
import 'package:yx_icon_fonts/src/commands/init_command.dart';
import 'package:yx_icon_fonts/src/utils/string_helper.dart';
/// YX Icon Fonts CLI
///
/// 使 CLI
class IconFontsCLI {
IconFontsCLI() {
_registerCommands();
}
static final Logger _logger = Logger('IconFontsCLI');
final Map<String, BaseCommand> _commands = {};
///
void _registerCommands() {
_registerCommand(GenerateCommand());
_registerCommand(InitCommand());
}
///
void _registerCommand(BaseCommand command) {
_commands[command.name] = command;
}
/// CLI
Future<int> run(List<String> arguments) async {
try {
_showBanner();
if (arguments.isEmpty ||
arguments.first == 'help' ||
arguments.first == '--help') {
_showHelp();
return 0;
}
final commandName = arguments.first;
final commandArgs =
arguments.length > 1 ? arguments.sublist(1) : <String>[];
//
if (commandName == 'version' || commandName == '--version') {
_showVersion();
return 0;
}
//
final command = _commands[commandName];
if (command == null) {
_logger
..severe('❌ 未知命令: $commandName')
..info('');
_showAvailableCommands();
return 1;
}
//
if (commandArgs.contains('--help') || commandArgs.contains('-h')) {
command.showHelp();
return 0;
}
//
final stopwatch = Stopwatch()..start();
final exitCode = await command.execute(commandArgs);
stopwatch.stop();
//
if (exitCode == 0) {
_logger
..info('')
..info(
'⏱️ 总耗时: ${StringHelper.formatDuration(stopwatch.elapsed)}',
);
}
return exitCode;
} on Exception catch (error, stackTrace) {
_logger
..severe('❌ 应用程序错误: $error')
..severe('堆栈跟踪: $stackTrace');
return 1;
}
}
///
void _showBanner() {
_logger
..info('')
..info('🎨 YX Icon Fonts 代码生成器 v2.0')
..info('=====================================')
..info('从 iconfont.json 生成 Flutter IconData 常量')
..info('');
}
///
void _showHelp() {
_logger
..info('用法: dart run yx_icon_fonts <命令> [选项]')
..info('')
..info('支持 YAML 配置文件,可自定义输出路径和类名。')
..info('');
_showAvailableCommands();
_showGlobalOptions();
_showExamples();
}
///
void _showAvailableCommands() {
_logger
..info('📋 可用命令:')
..info('');
for (final command in _commands.values) {
_logger.info(' ${command.name.padRight(12)} ${command.description}');
}
_logger
..info(' help 显示帮助信息')
..info(' version 显示版本信息')
..info('');
}
///
void _showGlobalOptions() {
_logger
..info('🔧 全局选项:')
..info(' -h, --help 显示帮助信息')
..info(' --version 显示版本信息')
..info('');
}
/// 使
void _showExamples() {
_logger
..info('💡 使用示例:')
..info('')
..info(' # 初始化配置文件')
..info(' dart run yx_icon_fonts init')
..info('')
..info(' # 生成图标代码')
..info(' dart run yx_icon_fonts generate')
..info('')
..info(' # 使用指定配置文件')
..info(' dart run yx_icon_fonts generate --config my_config.yaml')
..info('')
..info(' # 查看命令帮助')
..info(' dart run yx_icon_fonts generate --help')
..info('');
}
///
void _showVersion() {
_logger
..info('YX Icon Fonts CLI v2.0.0')
..info('构建于: ${DateTime.now().toIso8601String()}')
..info('Dart SDK: ${Platform.version}')
..info('')
..info('功能特性:')
..info('- 🎨 从 iconfont.json 生成代码')
..info('- 📝 YAML 配置文件支持')
..info('- 🏗️ 自定义类名和输出路径')
..info('- 📚 自动生成文档注释')
..info('');
}
}

View File

@ -0,0 +1,63 @@
import 'package:logging/logging.dart';
///
///
/// CLI
abstract class BaseCommand {
///
String get name;
///
String get description;
///
Logger get logger => Logger(name);
///
///
/// 退0 0
Future<int> execute(List<String> arguments);
///
void showHelp() {
logger
..info('命令: $name')
..info('描述: $description')
..info('')
..info('用法: dart run yx_icon_fonts $name [选项]')
..info('')
..info('选项:');
showOptions();
}
///
void showOptions() {
logger.info(' -h, --help 显示帮助信息');
}
///
String? getOption(List<String> arguments, String name, {String? shortName}) {
for (var i = 0; i < arguments.length; i++) {
final arg = arguments[i];
if (arg == '--$name' || (shortName != null && arg == '-$shortName')) {
if (i + 1 < arguments.length) {
return arguments[i + 1];
}
}
if (arg.startsWith('--$name=')) {
return arg.substring('--$name='.length);
}
}
return null;
}
///
bool hasFlag(List<String> arguments, String name, {String? shortName}) {
for (final arg in arguments) {
if (arg == '--$name' || (shortName != null && arg == '-$shortName')) {
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,83 @@
import 'package:yx_icon_fonts/src/commands/base_command.dart';
import 'package:yx_icon_fonts/src/config/config_loader.dart';
import 'package:yx_icon_fonts/src/generator/icon_generator.dart';
import 'package:yx_icon_fonts/src/utils/logger.dart';
import 'package:yx_icon_fonts/src/utils/string_helper.dart';
///
///
///
class GenerateCommand extends BaseCommand {
@override
String get name => 'generate';
@override
String get description => '从 iconfont.json 生成 Flutter IconData 常量';
@override
void showOptions() {
super.showOptions();
logger
..info(' -c, --config <path> 指定配置文件路径 '
'(默认: icon_generator_config.yaml)')
..info(' -v, --verbose 显示详细输出');
}
@override
Future<int> execute(List<String> arguments) async {
try {
//
final configPath = getOption(arguments, 'config', shortName: 'c');
final verbose = hasFlag(arguments, 'verbose', shortName: 'v');
if (verbose) {
appLogger.info('🔍 详细模式已启用');
}
//
appLogger.progress('正在加载配置...');
final config = ConfigLoader.load(configPath: configPath);
if (verbose) {
appLogger
..info('📋 配置信息:')
..info(' - 输入文件: ${config.input.jsonFile}')
..info(' - 字体家族: ${config.input.fontFamily}')
..info(' - 输出文件: ${config.output.filePath}')
..info(' - 类名: ${config.output.className}');
}
//
final generator = IconGenerator(config: config);
final result = await generator.generate();
if (result.success) {
appLogger
..success('代码生成成功!')
..info('')
..info('📁 输出文件: ${result.outputPath}')
..stats('共生成 ${result.iconCount} 个图标常量');
if (result.duration != null) {
appLogger.info(
'⏱️ 耗时: ${StringHelper.formatDuration(result.duration!)}',
);
}
return 0;
} else {
appLogger.severe('❌ 生成失败: ${result.error}');
return 1;
}
} on ConfigNotFoundException catch (e) {
appLogger
..severe('${e.message}')
..info('')
..info('💡 提示: 运行 "dart run yx_icon_fonts init" 创建配置文件');
return 1;
} on Exception catch (e) {
appLogger.severe('❌ 发生错误: $e');
return 1;
}
}
}

View File

@ -0,0 +1,107 @@
import 'dart:io';
import 'package:path/path.dart' as path;
import 'package:yx_icon_fonts/src/commands/base_command.dart';
import 'package:yx_icon_fonts/src/config/config_loader.dart';
import 'package:yx_icon_fonts/src/utils/logger.dart';
///
///
///
class InitCommand extends BaseCommand {
@override
String get name => 'init';
@override
String get description => '创建配置文件模板';
@override
void showOptions() {
super.showOptions();
logger
..info(' -f, --force 强制覆盖已存在的配置文件')
..info(' -o, --output <path> 指定配置文件输出路径');
}
@override
Future<int> execute(List<String> arguments) async {
try {
final force = hasFlag(arguments, 'force', shortName: 'f');
final outputPath = getOption(arguments, 'output', shortName: 'o');
final configPath = outputPath ??
path.join(
Directory.current.path,
ConfigLoader.defaultConfigFileName,
);
//
if (File(configPath).existsSync() && !force) {
appLogger
..warning('⚠️ 配置文件已存在: $configPath')
..info('')
..info('💡 使用 --force 选项覆盖现有文件');
return 1;
}
//
appLogger.progress('正在创建配置文件...');
File(configPath).writeAsStringSync(_configTemplate);
appLogger
..success('配置文件创建成功!')
..info('')
..info('📁 配置文件: $configPath')
..info('')
..info('📝 下一步:')
..info(' 1. 编辑配置文件,设置输入输出路径')
..info(' 2. 运行 "dart run yx_icon_fonts generate" 生成代码');
return 0;
} on Exception catch (e) {
appLogger.severe('❌ 发生错误: $e');
return 1;
}
}
///
static const String _configTemplate = '''
#
# yx_icon_fonts init
#
generator:
name: "MyApp Icons"
version: "1.0"
author: "Your Name"
#
input:
#
font_file: "assets/fonts/iconfont.ttf"
# JSON iconfont.cn
json_file: "assets/fonts/iconfont.json"
# pubspec.yaml
font_family: "iconfont"
#
# package
# font_package: "my_icons_package"
#
output:
# Dart
file_path: "lib/generated/icons.dart"
#
class_name: "AppIcons"
#
generate_docs: true
# 使 const
use_const_constructor: true
''';
}

View File

@ -0,0 +1,103 @@
import 'dart:io';
import 'package:path/path.dart' as path;
import 'package:yaml/yaml.dart';
import 'package:yx_icon_fonts/src/config/generator_config.dart';
///
///
/// YAML
class ConfigLoader {
///
static const String defaultConfigFileName = 'icon_generator_config.yaml';
///
///
/// [configPath] null 使
/// [workingDir]
static GeneratorConfig load({
String? configPath,
String? workingDir,
}) {
final directory = workingDir ?? Directory.current.path;
final filePath = configPath ?? path.join(directory, defaultConfigFileName);
final file = File(filePath);
if (!file.existsSync()) {
throw ConfigNotFoundException(
'配置文件不存在: $filePath\n'
'请运行 "dart run yx_icon_fonts init" 创建配置文件',
);
}
try {
final content = file.readAsStringSync();
final yamlMap = loadYaml(content) as YamlMap?;
if (yamlMap == null) {
throw ConfigParseException('配置文件为空或格式错误');
}
// YamlMap Map<String, dynamic>
final map = _convertYamlMap(yamlMap);
return GeneratorConfig.fromMap(map);
} on YamlException catch (e) {
throw ConfigParseException('YAML 解析错误: ${e.message}');
}
}
///
static bool exists({String? configPath, String? workingDir}) {
final directory = workingDir ?? Directory.current.path;
final filePath = configPath ?? path.join(directory, defaultConfigFileName);
return File(filePath).existsSync();
}
/// YamlMap Map<String, dynamic>
static Map<String, dynamic> _convertYamlMap(YamlMap yamlMap) {
final result = <String, dynamic>{};
for (final key in yamlMap.keys) {
final value = yamlMap[key];
if (value is YamlMap) {
result[key.toString()] = _convertYamlMap(value);
} else if (value is YamlList) {
result[key.toString()] = _convertYamlList(value);
} else {
result[key.toString()] = value;
}
}
return result;
}
/// YamlList List<dynamic>
static List<dynamic> _convertYamlList(YamlList yamlList) {
return yamlList.map((item) {
if (item is YamlMap) {
return _convertYamlMap(item);
} else if (item is YamlList) {
return _convertYamlList(item);
}
return item;
}).toList();
}
}
///
class ConfigNotFoundException implements Exception {
ConfigNotFoundException(this.message);
final String message;
@override
String toString() => 'ConfigNotFoundException: $message';
}
///
class ConfigParseException implements Exception {
ConfigParseException(this.message);
final String message;
@override
String toString() => 'ConfigParseException: $message';
}

View File

@ -0,0 +1,178 @@
//
//
//
///
class GeneratorConfig {
const GeneratorConfig({
required this.generator,
required this.input,
required this.output,
});
/// Map
factory GeneratorConfig.fromMap(Map<String, dynamic> map) {
return GeneratorConfig(
generator: GeneratorInfo.fromMap(
map['generator'] as Map<String, dynamic>? ?? {},
),
input: InputConfig.fromMap(
map['input'] as Map<String, dynamic>? ?? {},
),
output: OutputConfig.fromMap(
map['output'] as Map<String, dynamic>? ?? {},
),
);
}
///
factory GeneratorConfig.defaults() {
return GeneratorConfig(
generator: GeneratorInfo.defaults(),
input: InputConfig.defaults(),
output: OutputConfig.defaults(),
);
}
///
final GeneratorInfo generator;
///
final InputConfig input;
///
final OutputConfig output;
@override
String toString() {
return 'GeneratorConfig(generator: $generator, input: $input, '
'output: $output)';
}
}
///
class GeneratorInfo {
const GeneratorInfo({
required this.name,
this.version = '1.0',
this.author = '',
});
factory GeneratorInfo.fromMap(Map<String, dynamic> map) {
return GeneratorInfo(
name: map['name'] as String? ?? 'Icon Generator',
version: map['version'] as String? ?? '1.0',
author: map['author'] as String? ?? '',
);
}
factory GeneratorInfo.defaults() {
return const GeneratorInfo(name: 'Icon Generator');
}
///
final String name;
///
final String version;
///
final String author;
@override
String toString() => 'GeneratorInfo(name: $name, version: $version)';
}
///
class InputConfig {
const InputConfig({
required this.fontFile,
required this.jsonFile,
required this.fontFamily,
this.fontPackage,
});
factory InputConfig.fromMap(Map<String, dynamic> map) {
return InputConfig(
fontFile: map['font_file'] as String? ?? 'assets/fonts/iconfont.ttf',
jsonFile: map['json_file'] as String? ?? 'assets/fonts/iconfont.json',
fontFamily: map['font_family'] as String? ?? 'iconfont',
fontPackage: map['font_package'] as String?,
);
}
factory InputConfig.defaults() {
return const InputConfig(
fontFile: 'assets/fonts/iconfont.ttf',
jsonFile: 'assets/fonts/iconfont.json',
fontFamily: 'iconfont',
);
}
///
final String fontFile;
/// JSON
final String jsonFile;
///
final String fontFamily;
///
final String? fontPackage;
@override
String toString() {
return 'InputConfig(fontFile: $fontFile, jsonFile: $jsonFile, '
'fontFamily: $fontFamily, fontPackage: $fontPackage)';
}
}
///
class OutputConfig {
const OutputConfig({
required this.filePath,
required this.className,
this.generateDocs = true,
this.useConstConstructor = true,
this.packageImport,
});
factory OutputConfig.fromMap(Map<String, dynamic> map) {
return OutputConfig(
filePath: map['file_path'] as String? ?? 'lib/generated/icons.dart',
className: map['class_name'] as String? ?? 'AppIcons',
generateDocs: map['generate_docs'] as bool? ?? true,
useConstConstructor: map['use_const_constructor'] as bool? ?? true,
packageImport: map['package_import'] as String?,
);
}
factory OutputConfig.defaults() {
return const OutputConfig(
filePath: 'lib/generated/icons.dart',
className: 'AppIcons',
);
}
/// Dart
final String filePath;
///
final String className;
///
final bool generateDocs;
/// 使 const
final bool useConstConstructor;
/// part of
final String? packageImport;
@override
String toString() {
return 'OutputConfig(filePath: $filePath, className: $className, '
'generateDocs: $generateDocs)';
}
}

View File

@ -0,0 +1,159 @@
import 'package:yx_icon_fonts/src/config/generator_config.dart';
import 'package:yx_icon_fonts/src/generator/icon_parser.dart';
import 'package:yx_icon_fonts/src/utils/string_helper.dart';
/// Dart
///
/// Flutter IconData
class DartCodeBuilder {
const DartCodeBuilder({
required this.config,
required this.meta,
});
///
final GeneratorConfig config;
///
final IconFontMeta meta;
/// Dart
String build() {
final buffer = StringBuffer()
//
.._writeHeader(meta)
//
.._writeImports()
//
.._writeClass(config, meta);
return buffer.toString();
}
}
extension _StringBufferExt on StringBuffer {
///
void _writeHeader(IconFontMeta meta) {
final now = DateTime.now();
final timestamp = '${now.year}-${_pad(now.month)}-${_pad(now.day)} '
'${_pad(now.hour)}:${_pad(now.minute)}';
this
..writeln('// ignore_for_file: constant_identifier_names')
..writeln()
..writeln('// ============================================')
..writeln('// 此文件由 yx_icon_fonts 自动生成,请勿手动修改')
..writeln('// 生成时间: $timestamp')
..writeln('// 图标数量: ${meta.icons.length}')
..writeln('// ============================================')
..writeln();
}
String _pad(int n) => n.toString().padLeft(2, '0');
///
void _writeImports() {
this
..writeln("import 'package:flutter/widgets.dart';")
..writeln();
}
///
void _writeClass(GeneratorConfig config, IconFontMeta meta) {
final className = config.output.className;
final fontFamily = config.input.fontFamily;
final fontPackage = config.input.fontPackage;
final generateDocs = config.output.generateDocs;
if (generateDocs) {
this
..writeln('/// ${config.generator.name} 图标常量')
..writeln('///')
..writeln(
'/// 包含所有图标的常量定义,可以直接在 Flutter 的 Icon 组件中使用',
)
..writeln('///')
..writeln('/// 示例:')
..writeln('/// ```dart')
..writeln('/// Icon($className.iconName, size: 24)')
..writeln('/// ```');
}
this
..writeln('class $className {')
..writeln(' $className._();')
..writeln();
if (!config.output.useConstConstructor) {
// _icon
this
..writeln(' // 统一的 IconData 构造方法')
..writeln(' static const _icon = _IconDataFactory._();')
..writeln();
}
//
for (final icon in meta.icons) {
_writeIconConstant(
icon,
generateDocs: generateDocs,
useConst: config.output.useConstConstructor,
fontFamily: fontFamily,
fontPackage: fontPackage,
);
}
this
..writeln('}')
..writeln();
if (!config.output.useConstConstructor) {
final hasPackage = fontPackage != null;
// IconData
this
..writeln('/// 内部 IconData 工厂类')
..writeln('class _IconDataFactory {')
..writeln(' const _IconDataFactory._();')
..writeln()
..writeln(" static const String _fontFamily = '$fontFamily';")
..writeln(
hasPackage
? " static const String _fontPackage = '$fontPackage';"
: '',
)
..writeln()
..writeln(
' IconData call(int codePoint) => '
"IconData(codePoint, fontFamily: _fontFamily${hasPackage ? ', fontPackage: _fontPackage' : ''});",
)
..writeln('}');
}
}
///
void _writeIconConstant(
IconInfo icon, {
required bool generateDocs,
required bool useConst,
required String fontFamily,
String? fontPackage,
}) {
final constantName = StringHelper.toLegalDartName(icon.fontClass);
if (generateDocs) {
writeln(' /// ${icon.name} (U+${icon.unicode.toUpperCase()})');
}
if (useConst) {
final packageParam =
fontPackage != null ? ", fontPackage: '$fontPackage'" : '';
writeln(
" static const IconData $constantName = IconData(0x${icon.unicode}, fontFamily: '$fontFamily'$packageParam);",
);
} else {
writeln(
' static final IconData $constantName = _icon(0x${icon.unicode});',
);
}
}
}

View File

@ -0,0 +1,119 @@
import 'package:yx_icon_fonts/src/config/generator_config.dart';
import 'package:yx_icon_fonts/src/generator/dart_code_builder.dart';
import 'package:yx_icon_fonts/src/generator/icon_parser.dart';
import 'package:yx_icon_fonts/src/utils/file_helper.dart';
import 'package:yx_icon_fonts/src/utils/logger.dart';
///
///
///
class IconGenerator {
IconGenerator({
required this.config,
this.workingDir,
});
///
final GeneratorConfig config;
///
final String? workingDir;
///
IconFontMeta? _meta;
///
IconFontMeta? get meta => _meta;
///
Future<GenerationResult> generate() async {
final stopwatch = Stopwatch()..start();
try {
// 1. JSON
appLogger.progress('正在解析图标配置文件...');
final jsonPath = FileHelper.resolvePropertyPath(
config.input.jsonFile,
workingDir: workingDir,
);
if (!FileHelper.fileExists(jsonPath)) {
return GenerationResult(
success: false,
error: '图标配置文件不存在: $jsonPath',
);
}
_meta = IconParser.parseFile(jsonPath);
appLogger
..stats('解析完成: 找到 ${_meta!.icons.length} 个图标')
// 2.
..progress('正在生成 Dart 代码...');
final builder = DartCodeBuilder(
config: config,
meta: _meta!,
);
final code = builder.build();
// 3.
final outputPath = FileHelper.resolvePropertyPath(
config.output.filePath,
workingDir: workingDir,
);
appLogger.progress('正在写入文件: $outputPath');
FileHelper.writeFile(outputPath, code);
stopwatch.stop();
return GenerationResult(
success: true,
outputPath: outputPath,
iconCount: _meta!.icons.length,
duration: stopwatch.elapsed,
);
} on Exception catch (e) {
stopwatch.stop();
return GenerationResult(
success: false,
error: e.toString(),
duration: stopwatch.elapsed,
);
}
}
}
///
class GenerationResult {
const GenerationResult({
required this.success,
this.outputPath,
this.iconCount = 0,
this.error,
this.duration,
});
///
final bool success;
///
final String? outputPath;
///
final int iconCount;
///
final String? error;
///
final Duration? duration;
@override
String toString() {
if (success) {
return 'GenerationResult(success: true, icons: $iconCount, '
'path: $outputPath)';
}
return 'GenerationResult(success: false, error: $error)';
}
}

View File

@ -0,0 +1,109 @@
import 'package:yx_icon_fonts/src/utils/file_helper.dart';
///
class IconInfo {
const IconInfo({
required this.iconId,
required this.name,
required this.fontClass,
required this.unicode,
required this.unicodeDecimal,
});
/// JSON Map
factory IconInfo.fromJson(Map<String, dynamic> json) {
return IconInfo(
iconId: json['icon_id']?.toString() ?? '',
name: json['name'] as String? ?? '',
fontClass: json['font_class'] as String? ?? '',
unicode: json['unicode'] as String? ?? '',
unicodeDecimal: json['unicode_decimal'] as int? ?? 0,
);
}
/// ID
final String iconId;
///
final String name;
/// CSS
final String fontClass;
/// Unicode
final String unicode;
/// Unicode
final int unicodeDecimal;
@override
String toString() => 'IconInfo(name: $name, unicode: $unicode)';
}
///
class IconFontMeta {
const IconFontMeta({
required this.id,
required this.name,
required this.fontFamily,
required this.cssPrefix,
required this.description,
required this.icons,
});
/// JSON Map
factory IconFontMeta.fromJson(Map<String, dynamic> json) {
final glyphs = json['glyphs'] as List<dynamic>? ?? [];
return IconFontMeta(
id: json['id']?.toString() ?? '',
name: json['name'] as String? ?? '',
fontFamily: json['font_family'] as String? ?? 'iconfont',
cssPrefix: json['css_prefix_text'] as String? ?? '',
description: json['description'] as String? ?? '',
icons: glyphs
.map((g) => IconInfo.fromJson(g as Map<String, dynamic>))
.toList(),
);
}
/// ID
final String id;
///
final String name;
///
final String fontFamily;
/// CSS
final String cssPrefix;
///
final String description;
///
final List<IconInfo> icons;
@override
String toString() => 'IconFontMeta(name: $name, fontFamily: $fontFamily, '
'icons: ${icons.length})';
}
///
///
/// iconfont.json
class IconParser {
///
IconParser._();
///
static IconFontMeta parseFile(String jsonFilePath) {
final jsonData = FileHelper.readJsonFile(jsonFilePath);
return IconFontMeta.fromJson(jsonData);
}
/// Map
static IconFontMeta parseMap(Map<String, dynamic> jsonData) {
return IconFontMeta.fromJson(jsonData);
}
}

View File

@ -0,0 +1,90 @@
import 'dart:convert';
import 'dart:io';
import 'package:path/path.dart' as path;
///
class FileHelper {
///
FileHelper._();
/// JSON
static Map<String, dynamic> readJsonFile(String filePath) {
final file = File(filePath);
if (!file.existsSync()) {
throw FileNotFoundException('文件不存在: $filePath');
}
try {
final content = file.readAsStringSync();
return json.decode(content) as Map<String, dynamic>;
} on FormatException catch (e) {
throw FileParseException('JSON 解析错误: ${e.message}');
}
}
///
///
///
static void writeFile(String filePath, String content) {
final file = File(filePath);
final directory = file.parent;
//
if (!directory.existsSync()) {
directory.createSync(recursive: true);
}
file.writeAsStringSync(content);
}
///
static bool fileExists(String filePath) {
return File(filePath).existsSync();
}
///
static String resolvePropertyPath(String relativePath, {String? workingDir}) {
final directory = workingDir ?? Directory.current.path;
if (path.isAbsolute(relativePath)) {
return relativePath;
}
return path.join(directory, relativePath);
}
///
static String getDirectoryPath(String filePath) {
return path.dirname(filePath);
}
///
static String getFileNameWithoutExtension(String filePath) {
return path.basenameWithoutExtension(filePath);
}
///
static String getFileName(String filePath) {
return path.basename(filePath);
}
}
///
class FileNotFoundException implements Exception {
FileNotFoundException(this.message);
final String message;
@override
String toString() => 'FileNotFoundException: $message';
}
///
class FileParseException implements Exception {
FileParseException(this.message);
final String message;
@override
String toString() => 'FileParseException: $message';
}

41
lib/src/utils/logger.dart Normal file
View File

@ -0,0 +1,41 @@
import 'dart:io';
import 'package:logging/logging.dart';
///
final Logger appLogger = Logger('YXIconFonts');
///
void setupLogging({Level level = Level.INFO}) {
Logger.root.level = level;
Logger.root.onRecord.listen((record) {
if (record.level >= Level.SEVERE) {
stderr.writeln(record.message);
} else {
stdout.writeln(record.message);
}
});
}
///
extension LoggerExtension on Logger {
/// 绿
void success(String message) {
info('$message');
}
///
void progress(String message) {
info('$message');
}
///
void done(String message) {
info('$message');
}
///
void stats(String message) {
info('📊 $message');
}
}

View File

@ -0,0 +1,66 @@
///
///
///
class StringHelper {
///
StringHelper._();
/// 线
///
/// icon_32_clean -> icon32Clean
static String toCamelCase(String input) {
//
final processedInput = input
.replaceAll('-', '_')
.replaceAll('+', 'plus')
.replaceAll('(', '')
.replaceAll(')', '')
.replaceAll(' ', '');
final parts = processedInput.split('_');
if (parts.isEmpty) return input;
final firstPart = parts[0];
final remainingParts = parts.skip(1).map((part) {
if (part.isEmpty) return '';
return part[0].toUpperCase() + part.substring(1);
}).join();
return firstPart + remainingParts;
}
/// Dart
///
/// 线
static String toLegalDartName(String input) {
var name = toCamelCase(input);
// 线
if (name.isNotEmpty && RegExp('^[0-9]').hasMatch(name[0])) {
name = '_$name';
}
// 线
return name.replaceAll(RegExp('[^a-zA-Z0-9_]'), '');
}
/// PascalCase
///
/// icon_class -> IconClass
static String toPascalCase(String input) {
final camelCase = toCamelCase(input);
if (camelCase.isEmpty) return camelCase;
return camelCase[0].toUpperCase() + camelCase.substring(1);
}
///
static String formatDuration(Duration duration) {
if (duration.inMinutes > 0) {
return '${duration.inMinutes}m ${duration.inSeconds % 60}s';
} else if (duration.inSeconds > 0) {
return '${duration.inSeconds}.${(duration.inMilliseconds % 1000) ~/ 100}s';
} else {
return '${duration.inMilliseconds}ms';
}
}
}

View File

@ -1,118 +0,0 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
/// OA系统图标组件
///
/// OA系统图标设计的组件
/// 使 Flutter Icon 使 YXIcon
class YXIcon extends StatelessWidget {
///
///
/// [icon] YXIconData IconData
/// [size]
/// [color]
/// [semanticLabel]
/// [textDirection]
/// [shadows]
const YXIcon(
this.icon, {
super.key,
this.size,
this.color,
this.semanticLabel,
this.textDirection,
this.shadows,
});
///
///
/// YXIconData IconData
final IconData? icon;
///
final double? size;
///
final Color? color;
///
final String? semanticLabel;
///
final TextDirection? textDirection;
///
final List<Shadow>? shadows;
@override
Widget build(BuildContext context) {
assert(this.textDirection != null || debugCheckHasDirectionality(context));
final TextDirection textDirection = this.textDirection ?? Directionality.of(context);
final IconThemeData iconTheme = IconTheme.of(context);
final double? iconSize = size ?? iconTheme.size;
final List<Shadow>? iconShadows = shadows ?? iconTheme.shadows;
if (icon == null) {
return Semantics(
label: semanticLabel,
child: SizedBox(width: iconSize, height: iconSize),
);
}
final double iconOpacity = iconTheme.opacity ?? 1.0;
Color iconColor = color ?? iconTheme.color!;
if (iconOpacity != 1.0) {
iconColor = iconColor.withValues(alpha: iconColor.a * iconOpacity);
}
Widget iconWidget = RichText(
overflow: TextOverflow.visible,
textDirection: textDirection,
text: TextSpan(
text: String.fromCharCode(icon!.codePoint),
style: TextStyle(
inherit: false,
color: iconColor,
fontSize: iconSize,
fontFamily: icon!.fontFamily,
package: icon!.fontPackage,
shadows: iconShadows,
),
),
);
if (icon!.matchTextDirection) {
switch (textDirection) {
case TextDirection.rtl:
iconWidget = Transform(
transform: Matrix4.identity()..scale(-1.0, 1.0, 1.0),
alignment: Alignment.center,
transformHitTests: false,
child: iconWidget,
);
break;
case TextDirection.ltr:
break;
}
}
return Semantics(
label: semanticLabel,
child: ExcludeSemantics(
child: iconWidget,
),
);
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(IconDataProperty('icon', icon, ifNull: '<empty>', showName: false));
properties.add(DoubleProperty('size', size, defaultValue: null));
properties.add(ColorProperty('color', color, defaultValue: null));
properties.add(IterableProperty<Shadow>('shadows', shadows, defaultValue: null));
}
}

View File

@ -1,15 +0,0 @@
import 'package:flutter/widgets.dart';
/// OA系统图标数据类
///
/// IconData
class YXIconData extends IconData {
///
///
/// [codePoint] Unicode码点
const YXIconData(super.codePoint)
: super(
fontFamily: 'iconfont',
fontPackage: 'yx_icon_fonts',
);
}

View File

@ -1,392 +0,0 @@
import 'package:flutter/widgets.dart';
import 'yx_icon_data.dart';
/// OA系统图标字体数据
///
/// Flutter Icon 使
/// 使 YXIcon
class YXIconFonts {
//
YXIconFonts._();
/// icon_32_clean
///
/// Unicode: e660
static const IconData icon32Clean = YXIconData(0xe660);
/// icon_36_viewhistory
///
/// Unicode: e65f
static const IconData icon36Viewhistory = YXIconData(0xe65f);
/// icon_36_revoke
///
/// Unicode: e65e
static const IconData icon36Revoke = YXIconData(0xe65e);
/// icon_30_edit
///
/// Unicode: e65b
static const IconData icon30Edit = YXIconData(0xe65b);
/// icon_24_copy2
///
/// Unicode: e65c
static const IconData icon24Copy2 = YXIconData(0xe65c);
/// icon_30_delete
///
/// Unicode: e65d
static const IconData icon30Delete = YXIconData(0xe65d);
/// icon_36_add
///
/// Unicode: e65a
static const IconData icon36Add = YXIconData(0xe65a);
/// icon_32_location
///
/// Unicode: e659
static const IconData icon32Location = YXIconData(0xe659);
/// icon_24_mypoints
///
/// Unicode: e657
static const IconData icon24Mypoints = YXIconData(0xe657);
/// icon_44_me_about
///
/// Unicode: e656
static const IconData icon44MeAbout = YXIconData(0xe656);
/// icon_44_me_pointsmall
///
/// Unicode: e658
static const IconData icon44MePointsmall = YXIconData(0xe658);
/// icon_44_search
///
/// Unicode: e655
static const IconData icon44Search = YXIconData(0xe655);
/// icon_36_clear_people
///
/// Unicode: e654
static const IconData icon36ClearPeople = YXIconData(0xe654);
/// icon_44_me_log_out
///
/// Unicode: e652
static const IconData icon44MeLogOut = YXIconData(0xe652);
/// icon_44_me_switch
///
/// Unicode: e653
static const IconData icon44MeSwitch = YXIconData(0xe653);
/// icon_44_wechat_share_white
///
/// Unicode: e651
static const IconData icon44WechatShareWhite = YXIconData(0xe651);
/// icon_32_publish
///
/// Unicode: e64e
static const IconData icon32Publish = YXIconData(0xe64e);
/// icon_32_close
///
/// Unicode: e64f
static const IconData icon32Close = YXIconData(0xe64f);
/// icon_32_output
///
/// Unicode: e650
static const IconData icon32Output = YXIconData(0xe650);
/// icon_24_download
///
/// Unicode: e64d
static const IconData icon24Download = YXIconData(0xe64d);
/// icon_voice_pause
///
/// Unicode: e64b
static const IconData iconVoicePause = YXIconData(0xe64b);
/// icon_voice
///
/// Unicode: e64c
static const IconData iconVoice = YXIconData(0xe64c);
/// icon_subtract
///
/// Unicode: e64a
static const IconData iconSubtract = YXIconData(0xe64a);
/// icon_44_edit
///
/// Unicode: e648
static const IconData icon44Edit = YXIconData(0xe648);
/// icon_44_delete
///
/// Unicode: e649
static const IconData icon44Delete = YXIconData(0xe649);
/// icon_44_cancel_account
///
/// Unicode: e647
static const IconData icon44CancelAccount = YXIconData(0xe647);
/// icon_24_search
///
/// Unicode: e646
static const IconData icon24Search = YXIconData(0xe646);
/// icon_24_up
///
/// Unicode: e645
static const IconData icon24Up = YXIconData(0xe645);
/// icon_msg_contacts
///
/// Unicode: e644
static const IconData iconMsgContacts = YXIconData(0xe644);
/// icon_msg_video
///
/// Unicode: e63e
static const IconData iconMsgVideo = YXIconData(0xe63e);
/// icon_msg_search
///
/// Unicode: e63f
static const IconData iconMsgSearch = YXIconData(0xe63f);
/// icon_msg_call
///
/// Unicode: e640
static const IconData iconMsgCall = YXIconData(0xe640);
/// icon_msg_photo
///
/// Unicode: e641
static const IconData iconMsgPhoto = YXIconData(0xe641);
/// icon_msg_img
///
/// Unicode: e642
static const IconData iconMsgImg = YXIconData(0xe642);
/// icon_msg_file
///
/// Unicode: e643
static const IconData iconMsgFile = YXIconData(0xe643);
/// icon_32_arrow_right
///
/// Unicode: e61d
static const IconData icon32ArrowRight = YXIconData(0xe61d);
/// icon_44_me_password
///
/// Unicode: e639
static const IconData icon44MePassword = YXIconData(0xe639);
/// icon_44_me_help
///
/// Unicode: e63a
static const IconData icon44MeHelp = YXIconData(0xe63a);
/// icon_24_minus
///
/// Unicode: e63b
static const IconData icon24Minus = YXIconData(0xe63b);
/// icon_36_team
///
/// Unicode: e63c
static const IconData icon36Team = YXIconData(0xe63c);
/// icon_32_filter
///
/// Unicode: e63d
static const IconData icon32Filter = YXIconData(0xe63d);
/// icon_44_quit_lite
///
/// Unicode: e631
static const IconData icon44QuitLite = YXIconData(0xe631);
/// icon_44_me_version
///
/// Unicode: e632
static const IconData icon44MeVersion = YXIconData(0xe632);
/// icon_36_question
///
/// Unicode: e633
static const IconData icon36Question = YXIconData(0xe633);
/// icon_44_me_privacy
///
/// Unicode: e634
static const IconData icon44MePrivacy = YXIconData(0xe634);
/// icon_44_more2
///
/// Unicode: e635
static const IconData icon44More2 = YXIconData(0xe635);
/// icon_36_only_see
///
/// Unicode: e636
static const IconData icon36OnlySee = YXIconData(0xe636);
/// icon_44_me_user
///
/// Unicode: e637
static const IconData icon44MeUser = YXIconData(0xe637);
/// icon_44_me_safe
///
/// Unicode: e62c
static const IconData icon44MeSafe = YXIconData(0xe62c);
/// icon_44_me_phone
///
/// Unicode: e62d
static const IconData icon44MePhone = YXIconData(0xe62d);
/// icon_24_copy
///
/// Unicode: e62e
static const IconData icon24Copy = YXIconData(0xe62e);
/// icon_32_quit
///
/// Unicode: e630
static const IconData icon32Quit = YXIconData(0xe630);
/// icon_44_calendar
///
/// Unicode: e626
static const IconData icon44Calendar = YXIconData(0xe626);
/// icon_32_student
///
/// Unicode: e627
static const IconData icon32Student = YXIconData(0xe627);
/// icon_36_delete
///
/// Unicode: e628
static const IconData icon36Delete = YXIconData(0xe628);
/// icon_44_more
///
/// Unicode: e629
static const IconData icon44More = YXIconData(0xe629);
/// icon_44_arrow_left
///
/// Unicode: e62a
static const IconData icon44ArrowLeft = YXIconData(0xe62a);
/// icon_36_edit_line
///
/// Unicode: e62b
static const IconData icon36EditLine = YXIconData(0xe62b);
/// icon_44_arrow_right
///
/// Unicode: e622
static const IconData icon44ArrowRight = YXIconData(0xe622);
/// icon_24_delete
///
/// Unicode: e623
static const IconData icon24Delete = YXIconData(0xe623);
/// icon_56_msg_add
///
/// Unicode: e624
static const IconData icon56MsgAdd = YXIconData(0xe624);
/// icon_56_msg_face
///
/// Unicode: e625
static const IconData icon56MsgFace = YXIconData(0xe625);
/// icon_56_msg_voice
///
/// Unicode: e616
static const IconData icon56MsgVoice = YXIconData(0xe616);
/// icon_44_share
///
/// Unicode: e615
static const IconData icon44Share = YXIconData(0xe615);
/// icon_36_hint
///
/// Unicode: e613
static const IconData icon36Hint = YXIconData(0xe613);
/// icon_24_add
///
/// Unicode: e617
static const IconData icon24Add = YXIconData(0xe617);
/// icon_24_plus
///
/// Unicode: e618
static const IconData icon24Plus = YXIconData(0xe618);
/// icon_44_keyboard
///
/// Unicode: e614
static const IconData icon44Keyboard = YXIconData(0xe614);
/// icon_44_quit
///
/// Unicode: e619
static const IconData icon44Quit = YXIconData(0xe619);
/// icon_44_add
///
/// Unicode: e61a
static const IconData icon44Add = YXIconData(0xe61a);
/// icon_24_switch
///
/// Unicode: e61b
static const IconData icon24Switch = YXIconData(0xe61b);
/// icon_44_arrow_down_line
///
/// Unicode: e61c
static const IconData icon44ArrowDownLine = YXIconData(0xe61c);
/// icon_24_arrow_right
///
/// Unicode: e61e
static const IconData icon24ArrowRight = YXIconData(0xe61e);
/// icon_32_add
///
/// Unicode: e61f
static const IconData icon32Add = YXIconData(0xe61f);
/// icon_24_edit
///
/// Unicode: e620
static const IconData icon24Edit = YXIconData(0xe620);
/// icon_24_arrow_down
///
/// Unicode: e621
static const IconData icon24ArrowDown = YXIconData(0xe621);
}

View File

@ -1,26 +1,48 @@
library yx_icon_fonts;
//
export 'src/yx_icon.dart';
export 'src/yx_icon_data.dart';
export 'src/yx_icon_fonts_data.dart';
/// OA系统图标字体库
/// YX Icon Fonts -
///
/// OA系统的图标字体支持
/// iconfont.json Flutter IconData
///
/// ## 使
///
/// ```dart
/// // 使 YXIcon
/// YXIcon(YXIconFonts.iconMsgContacts, size: 24, color: Colors.blue)
///
/// // 使 Flutter Icon
/// Icon(YXIconFonts.iconMsgContacts, size: 24, color: Colors.blue)
///
/// // IconButton 使
/// IconButton(
/// icon: YXIcon(YXIconFonts.iconMsgContacts),
/// onPressed: () {},
/// )
/// 1. dev_dependencies:
/// ```yaml
/// dev_dependencies:
/// yx_icon_fonts:
/// git:
/// url: https://gitea.23544.com/wangyang/yx_icon_fonts_flutter
/// ```
///
/// 2. :
/// ```bash
/// dart run yx_icon_fonts init
/// ```
///
/// 3. `icon_generator_config.yaml`
///
/// 4. :
/// ```bash
/// dart run yx_icon_fonts generate
/// ```
library yx_icon_fonts;
// CLI
export 'src/cli/icon_fonts_cli.dart';
//
export 'src/commands/base_command.dart';
export 'src/commands/generate_command.dart';
export 'src/commands/init_command.dart';
//
export 'src/config/config_loader.dart';
export 'src/config/generator_config.dart';
//
export 'src/generator/dart_code_builder.dart';
export 'src/generator/icon_generator.dart';
export 'src/generator/icon_parser.dart';
//
export 'src/utils/file_helper.dart';
export 'src/utils/logger.dart';
export 'src/utils/string_helper.dart';

View File

@ -1,6 +1,30 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
_fe_analyzer_shared:
dependency: transitive
description:
name: _fe_analyzer_shared
sha256: "5b7468c326d2f8a4f630056404ca0d291ade42918f4a3c6233618e724f39da8e"
url: "https://pub.flutter-io.cn"
source: hosted
version: "92.0.0"
analyzer:
dependency: transitive
description:
name: analyzer
sha256: "70e4b1ef8003c64793a9e268a551a82869a8a96f39deb73dea28084b0e8bf75e"
url: "https://pub.flutter-io.cn"
source: hosted
version: "9.0.0"
args:
dependency: transitive
description:
name: args
sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.7.0"
async:
dependency: transitive
description:
@ -17,22 +41,14 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.2"
characters:
cli_config:
dependency: transitive
description:
name: characters
sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
name: cli_config
sha256: ac20a183a07002b700f0c25e61b7ee46b23c309d76ab7b7640a028f18e4d99ec
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.4.0"
clock:
dependency: transitive
description:
name: clock
sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.1.2"
version: "0.2.0"
collection:
dependency: transitive
description:
@ -41,64 +57,86 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.19.1"
fake_async:
convert:
dependency: transitive
description:
name: fake_async
sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
name: convert
sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.3.3"
flutter:
version: "3.1.2"
coverage:
dependency: transitive
description:
name: coverage
sha256: "5da775aa218eaf2151c721b16c01c7676fbfdd99cebba2bf64e8b807a28ff94d"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.15.0"
crypto:
dependency: transitive
description:
name: crypto
sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.7"
file:
dependency: transitive
description:
name: file
sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
url: "https://pub.flutter-io.cn"
source: hosted
version: "7.0.1"
frontend_server_client:
dependency: transitive
description:
name: frontend_server_client
sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694
url: "https://pub.flutter-io.cn"
source: hosted
version: "4.0.0"
glob:
dependency: transitive
description:
name: glob
sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.3"
http_multi_server:
dependency: transitive
description:
name: http_multi_server
sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.2.2"
http_parser:
dependency: transitive
description:
name: http_parser
sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
url: "https://pub.flutter-io.cn"
source: hosted
version: "4.1.2"
io:
dependency: transitive
description:
name: io
sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.5"
logging:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
flutter_lints:
dependency: "direct dev"
description:
name: flutter_lints
sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1"
name: logging
sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.2"
flutter_test:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
leak_tracker:
dependency: transitive
description:
name: leak_tracker
sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de"
url: "https://pub.flutter-io.cn"
source: hosted
version: "11.0.2"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.10"
leak_tracker_testing:
dependency: transitive
description:
name: leak_tracker_testing
sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.2"
lints:
dependency: transitive
description:
name: lints
sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.0"
version: "1.3.0"
matcher:
dependency: transitive
description:
@ -107,14 +145,6 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.12.17"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.11.1"
meta:
dependency: transitive
description:
@ -123,19 +153,102 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.16.0"
path:
mime:
dependency: transitive
description:
name: mime
sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.0"
node_preamble:
dependency: transitive
description:
name: node_preamble
sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.2"
package_config:
dependency: transitive
description:
name: package_config
sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.2.0"
path:
dependency: "direct main"
description:
name: path
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.9.1"
sky_engine:
pool:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
description:
name: pool
sha256: "978783255c543aa3586a1b3c21f6e9d720eb315376a915872c61ef8b5c20177d"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.5.2"
pub_semver:
dependency: transitive
description:
name: pub_semver
sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.2.0"
shelf:
dependency: transitive
description:
name: shelf
sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.4.2"
shelf_packages_handler:
dependency: transitive
description:
name: shelf_packages_handler
sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e"
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.2"
shelf_static:
dependency: transitive
description:
name: shelf_static
sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.1.3"
shelf_web_socket:
dependency: transitive
description:
name: shelf_web_socket
sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925"
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.0"
source_map_stack_trace:
dependency: transitive
description:
name: source_map_stack_trace
sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.2"
source_maps:
dependency: transitive
description:
name: source_maps
sha256: "190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812"
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.10.13"
source_span:
dependency: transitive
description:
@ -176,22 +289,46 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.2.2"
test:
dependency: "direct dev"
description:
name: test
sha256: "77cc98ea27006c84e71a7356cf3daf9ddbde2d91d84f77dbfe64cf0e4d9611ae"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.28.0"
test_api:
dependency: transitive
description:
name: test_api
sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00"
sha256: "19a78f63e83d3a61f00826d09bc2f60e191bf3504183c001262be6ac75589fb8"
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.7.6"
vector_math:
version: "0.7.8"
test_core:
dependency: transitive
description:
name: vector_math
sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
name: test_core
sha256: f1072617a6657e5fc09662e721307f7fb009b4ed89b19f47175d11d5254a62d4
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.2.0"
version: "0.6.14"
typed_data:
dependency: transitive
description:
name: typed_data
sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.4.0"
very_good_analysis:
dependency: "direct dev"
description:
name: very_good_analysis
sha256: "1fb637c0022034b1f19ea2acb42a3603cbd8314a470646a59a2fb01f5f3a8629"
url: "https://pub.flutter-io.cn"
source: hosted
version: "6.0.0"
vm_service:
dependency: transitive
description:
@ -200,6 +337,53 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "15.0.2"
watcher:
dependency: transitive
description:
name: watcher
sha256: f52385d4f73589977c80797e60fe51014f7f2b957b5e9a62c3f6ada439889249
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.2.0"
web:
dependency: transitive
description:
name: web
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.1.1"
web_socket:
dependency: transitive
description:
name: web_socket
sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.1"
web_socket_channel:
dependency: transitive
description:
name: web_socket_channel
sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.3"
webkit_inspection_protocol:
dependency: transitive
description:
name: webkit_inspection_protocol
sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.2.1"
yaml:
dependency: "direct main"
description:
name: yaml
sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.1.3"
sdks:
dart: ">=3.8.0-0 <4.0.0"
flutter: ">=3.18.0-18.0.pre.54"
dart: ">=3.9.0 <4.0.0"

View File

@ -1,23 +1,25 @@
name: yx_icon_fonts
description: 学习官OA系统图标字体库基于iconfont.ttf和iconfont.json生成
version: 1.0.7
description: 图标字体代码生成器 - 从 iconfont.json 生成 Flutter IconData 常量
version: 2.1.0
homepage: https://gitea.23544.com/wangyang/yx_icon_fonts_flutter
environment:
sdk: '>=3.0.0 <4.0.0'
flutter: ">=3.0.0"
# 可执行命令配置
# 使用方式dart run yx_icon_fonts generate
# 或者使用别名dart run yx_icon_fonts:yx_icon_fonts
executables:
yx_icon_fonts: main
dependencies:
flutter:
sdk: flutter
# 日志
logging: ^1.3.0
# 路径处理
path: ^1.9.1
# YAML 解析
yaml: ^3.1.3
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^3.0.0
flutter:
fonts:
- family: iconfont
fonts:
- asset: fonts/iconfont.ttf
test: ^1.24.0
very_good_analysis: ^6.0.0

View File

@ -1,96 +0,0 @@
import 'dart:io';
import 'utils.dart';
///
///
/// 使
/// dart scripts/generate_example.dart
void main() {
final iconData = readIconFontJson();
final glyphs = getGlyphs(iconData);
// YXIconFonts
final definedIcons = getDefinedIconNames();
// icons.dart
_generateIconsFile(glyphs, definedIcons);
print('✅ 成功生成示例应用文件');
print('📁 生成的文件:');
print(' - example/lib/icons.dart');
}
/// icons.dart
void _generateIconsFile(List<dynamic> glyphs, Set<String> definedIcons) {
final buffer = StringBuffer();
buffer.writeln("import 'package:yx_icon_fonts/yx_icon_fonts.dart';");
buffer.writeln("import 'package:yx_icon_fonts_example/example_icon.dart';");
buffer.writeln();
buffer.writeln("// 此文件由脚本自动生成!");
buffer.writeln();
buffer.writeln("final icons = <ExampleIcon>[");
//
final categories = <String, List<Map<String, dynamic>>>{};
for (final glyph in glyphs) {
final name = glyph['font_class'] as String;
final unicodeDecimal = glyph['unicode_decimal'] as int;
String category = '其他图标';
if (name.contains('msg')) {
category = '消息相关图标';
} else if (name.contains('arrow')) {
category = '箭头相关图标';
} else if (name.contains('edit')) {
category = '编辑相关图标';
} else if (name.contains('me_')) {
category = '个人中心相关图标';
} else if (name.contains('team') || name.contains('student')) {
category = '团队和用户相关图标';
} else if (name.contains('filter') || name.contains('question') || name.contains('onlysee') || name.contains('hint') || name.contains('switch')) {
category = '功能图标';
} else if (name.contains('delete')) {
category = '删除相关图标';
} else if (name.contains('more')) {
category = '更多和菜单相关图标';
} else if (name.contains('quit')) {
category = '退出相关图标';
} else if (name.contains('copy')) {
category = '复制相关图标';
} else if (name.contains('calendar')) {
category = '日历相关图标';
} else if (name.contains('share')) {
category = '分享相关图标';
} else if (name.contains('add') || name.contains('+')) {
category = '添加相关图标';
} else if (name.contains('keyboard')) {
category = '键盘相关图标';
} else if (name.contains('-')) {
category = '特殊字符图标';
}
categories.putIfAbsent(category, () => []);
categories[category]!.add({
'name': name,
'unicodeDecimal': unicodeDecimal,
});
}
//
for (final category in categories.keys) {
buffer.writeln(" // $category");
for (final icon in categories[category]!) {
final name = icon['name'] as String;
final camelCaseName = toLegalDartName(name);
if (!definedIcons.contains(camelCaseName)) continue; //
final displayName = _getDisplayName(name);
buffer.writeln(" ExampleIcon(YXIconFonts.$camelCaseName, '$displayName'),");
}
buffer.writeln();
}
buffer.writeln("];");
final file = File('example/lib/icons.dart');
file.writeAsStringSync(buffer.toString());
}
///
String _getDisplayName(String name) {
return name.replaceAll('_', ' ');
}

View File

@ -1,48 +0,0 @@
import 'dart:io';
import 'utils.dart';
///
///
/// iconfont.json Dart
void main() {
final iconData = readIconFontJson();
final icons = getGlyphs(iconData);
final StringBuffer buffer = StringBuffer();
//
buffer.writeln("import 'package:flutter/widgets.dart';");
buffer.writeln("import 'yx_icon_data.dart';");
buffer.writeln();
buffer.writeln("/// 学习官OA系统图标字体数据");
buffer.writeln("/// ");
buffer.writeln("/// 包含所有图标的常量定义,可以直接在 Flutter 的 Icon 组件中使用");
buffer.writeln("/// 也可以使用专门的 YXIcon 组件");
buffer.writeln("class YXIconFonts {");
buffer.writeln(" // 私有构造函数,防止实例化");
buffer.writeln(" YXIconFonts._();");
buffer.writeln();
//
for (final Map<String, dynamic> icon in icons) {
final String name = icon['name'] as String;
final String unicode = icon['unicode'] as String;
//
final String camelCaseName = toCamelCase(name);
//
buffer.writeln(" /// $name 图标");
buffer.writeln(" /// ");
buffer.writeln(" /// Unicode: $unicode");
buffer.writeln(" static const IconData $camelCaseName = YXIconData(0x$unicode);");
buffer.writeln();
}
buffer.writeln("}");
//
final File outputFile = File('lib/src/yx_icon_fonts_data.dart');
outputFile.writeAsStringSync(buffer.toString());
print('✅ 图标数据文件生成成功: [32m${outputFile.path} [0m');
print('📊 共生成 ${icons.length} 个图标常量');
}

View File

@ -1,144 +0,0 @@
import 'dart:io';
import 'utils.dart';
/// 使
///
/// iconfont.json FontIcons
/// icons.dart
void main() {
final iconData = readIconFontJson();
final glyphs = getGlyphs(iconData);
final definedIcons = getDefinedIconNames();
_generateWrapperFile(glyphs, definedIcons);
print('✅ 外部图标封装文件生成成功: \x1B[32mgenerate/icons.dart\x1B[0m');
print('📊 共生成 ${definedIcons.length} 个图标常量');
}
/// icons.dart
void _generateWrapperFile(List<dynamic> glyphs, Set<String> definedIcons) {
final buffer = StringBuffer();
//
buffer.writeln("// ignore_for_file: constant_identifier_names");
buffer.writeln();
buffer.writeln("import 'package:flutter/material.dart';");
buffer.writeln("import 'package:yx_icon_fonts/yx_icon_fonts.dart';");
buffer.writeln();
buffer.writeln("class FontIcons {");
buffer.writeln(" // 私有构造函数,防止实例化");
buffer.writeln(" FontIcons._();");
buffer.writeln();
//
final categories = _categorizeIcons(glyphs, definedIcons);
//
final categoryOrder = [
'其他图标',
'编辑相关图标',
'删除相关图标',
'个人中心相关图标',
'消息相关图标',
'箭头相关图标',
'特殊字符图标',
'团队和用户相关图标',
'功能图标',
'退出相关图标',
'更多和菜单相关图标',
'复制相关图标',
'日历相关图标',
'分享相关图标',
'添加相关图标',
'键盘相关图标',
];
//
for (final category in categoryOrder) {
if (categories.containsKey(category) && categories[category]!.isNotEmpty) {
buffer.writeln(" // $category");
for (final iconName in categories[category]!) {
buffer.writeln(" static const IconData $iconName = YXIconFonts.$iconName;");
}
buffer.writeln();
}
}
buffer.writeln("}");
// generate
final dir = Directory('generate');
if (!dir.existsSync()) {
dir.createSync(recursive: true);
}
//
final file = File('generate/icons.dart');
file.writeAsStringSync(buffer.toString());
}
///
Map<String, List<String>> _categorizeIcons(List<dynamic> glyphs, Set<String> definedIcons) {
final categories = <String, List<String>>{};
for (final glyph in glyphs) {
final name = glyph['font_class'] as String;
final camelCaseName = toLegalDartName(name);
//
if (!definedIcons.contains(camelCaseName)) continue;
//
String category = _getCategory(name);
categories.putIfAbsent(category, () => []);
categories[category]!.add(camelCaseName);
}
return categories;
}
///
String _getCategory(String name) {
final lowerName = name.toLowerCase();
if (lowerName.contains('edit')) {
return '编辑相关图标';
} else if (lowerName.contains('delete')) {
return '删除相关图标';
} else if (lowerName.contains('me_')) {
return '个人中心相关图标';
} else if (lowerName.contains('msg')) {
return '消息相关图标';
} else if (lowerName.contains('arrow')) {
return '箭头相关图标';
} else if (lowerName == '24_-' || lowerName.contains('subtract')) {
return '特殊字符图标';
} else if (lowerName.contains('team') || lowerName.contains('student')) {
return '团队和用户相关图标';
} else if (lowerName.contains('filter') ||
lowerName.contains('question') ||
lowerName.contains('onlysee') ||
lowerName.contains('hint') ||
lowerName.contains('switch')) {
return '功能图标';
} else if (lowerName.contains('quit')) {
return '退出相关图标';
} else if (lowerName.contains('more')) {
return '更多和菜单相关图标';
} else if (lowerName.contains('copy')) {
return '复制相关图标';
} else if (lowerName.contains('calendar')) {
return '日历相关图标';
} else if (lowerName.contains('share')) {
return '分享相关图标';
} else if (lowerName.contains('add') || lowerName.contains('+') || lowerName.contains('plus')) {
return '添加相关图标';
} else if (lowerName.contains('keyboard')) {
return '键盘相关图标';
} else {
return '其他图标';
}
}

View File

@ -1,48 +0,0 @@
import 'dart:convert';
import 'dart:io';
/// iconfont.json Map
Map<String, dynamic> readIconFontJson([String path = 'iconfont.json']) {
final file = File(path);
if (!file.existsSync()) {
throw Exception('未找到 $path 文件');
}
final content = file.readAsStringSync();
return json.decode(content) as Map<String, dynamic>;
}
/// glyphs
List<dynamic> getGlyphs(Map<String, dynamic> iconData) {
return iconData['glyphs'] as List<dynamic>;
}
/// 线 Dart
String toCamelCase(String input) {
String processedInput = input.replaceAll('-', '_').replaceAll('+', 'plus').replaceAll('(', '').replaceAll(')', '').replaceAll(' ', '');
final List<String> parts = processedInput.split('_');
if (parts.isEmpty) return input;
final String firstPart = parts[0];
final String remainingParts = parts.skip(1).map((part) => part.isNotEmpty ? part[0].toUpperCase() + part.substring(1) : '').join();
return firstPart + remainingParts;
}
/// Dart
String toLegalDartName(String input) {
String name = toCamelCase(input);
// 线
if (name.isNotEmpty && RegExp(r'^[0-9]').hasMatch(name[0])) {
name = '_$name';
}
// 线
name = name.replaceAll(RegExp(r'[^a-zA-Z0-9_]'), '');
return name;
}
/// Dart static const IconData xxx = ...
Set<String> getDefinedIconNames([String path = 'lib/src/yx_icon_fonts_data.dart']) {
final file = File(path);
if (!file.existsSync()) return {};
final content = file.readAsStringSync();
final reg = RegExp(r'static const IconData (\w+) =');
return reg.allMatches(content).map((m) => m.group(1)!).toSet();
}

View File

@ -1,29 +1,82 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:test/test.dart';
import 'package:yx_icon_fonts/yx_icon_fonts.dart';
void main() {
group('YXIconFonts', () {
test('should have valid icon data', () {
//
expect(YXIconFonts.iconMsgContacts, isNotNull);
expect(YXIconFonts.iconMsgContacts.codePoint, isA<int>());
expect(YXIconFonts.iconMsgContacts.fontFamily, equals('iconfont'));
group('StringHelper', () {
test('toCamelCase converts underscore to camelCase', () {
expect(StringHelper.toCamelCase('icon_32_clean'), equals('icon32Clean'));
expect(
StringHelper.toCamelCase('icon_msg_contacts'),
equals('iconMsgContacts'),
);
});
test('should create YXIcon widget', () {
// YXIcon
final icon = YXIcon(YXIconFonts.iconMsgContacts);
expect(icon, isNotNull);
expect(icon.icon, equals(YXIconFonts.iconMsgContacts));
test('toLegalDartName handles numeric prefix', () {
expect(StringHelper.toLegalDartName('32_icon'), equals('_32Icon'));
});
test('should have multiple icons defined', () {
//
expect(YXIconFonts.iconMsgContacts, isNotNull);
expect(YXIconFonts.iconMsgSearch, isNotNull);
expect(YXIconFonts.icon44Edit, isNotNull);
expect(YXIconFonts.icon44Delete, isNotNull);
expect(YXIconFonts.icon44Add, isNotNull);
test('toPascalCase converts to PascalCase', () {
expect(StringHelper.toPascalCase('icon_class'), equals('IconClass'));
});
});
group('GeneratorConfig', () {
test('fromMap creates config from map', () {
final map = {
'generator': {'name': 'Test'},
'input': {
'font_file': 'test.ttf',
'json_file': 'test.json',
'font_family': 'test',
},
'output': {
'file_path': 'lib/icons.dart',
'class_name': 'TestIcons',
},
};
final config = GeneratorConfig.fromMap(map);
expect(config.generator.name, equals('Test'));
expect(config.input.fontFile, equals('test.ttf'));
expect(config.input.jsonFile, equals('test.json'));
expect(config.output.filePath, equals('lib/icons.dart'));
expect(config.output.className, equals('TestIcons'));
});
test('defaults creates default config', () {
final config = GeneratorConfig.defaults();
expect(config.input.fontFamily, equals('iconfont'));
expect(config.output.className, equals('AppIcons'));
expect(config.output.generateDocs, isTrue);
});
});
group('IconParser', () {
test('parseMap parses icon font metadata', () {
final jsonData = {
'id': '123',
'name': 'Test Font',
'font_family': 'testfont',
'glyphs': [
{
'icon_id': '1',
'name': 'icon_test',
'font_class': 'icon_test',
'unicode': 'e600',
'unicode_decimal': 58880,
},
],
};
final meta = IconParser.parseMap(jsonData);
expect(meta.name, equals('Test Font'));
expect(meta.fontFamily, equals('testfont'));
expect(meta.icons.length, equals(1));
expect(meta.icons.first.name, equals('icon_test'));
expect(meta.icons.first.unicode, equals('e600'));
});
});
}