diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000..33a5fb4 --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,6 @@ +include: package:lints/recommended.yaml + +analyzer: + exclude: + - temp_font_awesome/** + - temp_font_awesome/**/* diff --git a/example/.gitignore b/example/.gitignore new file mode 100644 index 0000000..79c113f --- /dev/null +++ b/example/.gitignore @@ -0,0 +1,45 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.build/ +.buildlog/ +.history +.svn/ +.swiftpm/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.pub-cache/ +.pub/ +/build/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/example/.metadata b/example/.metadata new file mode 100644 index 0000000..cca80bc --- /dev/null +++ b/example/.metadata @@ -0,0 +1,30 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "8defaa71a77c16e8547abdbfad2053ce3a6e2d5b" + channel: "stable" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 8defaa71a77c16e8547abdbfad2053ce3a6e2d5b + base_revision: 8defaa71a77c16e8547abdbfad2053ce3a6e2d5b + - platform: ios + create_revision: 8defaa71a77c16e8547abdbfad2053ce3a6e2d5b + base_revision: 8defaa71a77c16e8547abdbfad2053ce3a6e2d5b + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/example/README.md b/example/README.md new file mode 100644 index 0000000..b374f0e --- /dev/null +++ b/example/README.md @@ -0,0 +1,3 @@ +# yx_icon_fonts_example + +A new Flutter project. diff --git a/example/analysis_options.yaml b/example/analysis_options.yaml new file mode 100644 index 0000000..f9b3034 --- /dev/null +++ b/example/analysis_options.yaml @@ -0,0 +1 @@ +include: package:flutter_lints/flutter.yaml diff --git a/example/lib/example_icon.dart b/example/lib/example_icon.dart new file mode 100644 index 0000000..02b5322 --- /dev/null +++ b/example/lib/example_icon.dart @@ -0,0 +1,24 @@ +import 'package:flutter/widgets.dart'; + +/// 示例图标类 +/// +/// 用于在示例应用中展示图标 +class ExampleIcon implements Comparable { + 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); +} diff --git a/example/lib/icons.dart b/example/lib/icons.dart new file mode 100644 index 0000000..9792d3f --- /dev/null +++ b/example/lib/icons.dart @@ -0,0 +1,85 @@ +import 'package:yx_icon_fonts/yx_icon_fonts.dart'; +import 'package:yx_icon_fonts_example/example_icon.dart'; + +// 此文件由脚本自动生成! + +final icons = [ + // 消息相关图标 + ExampleIcon(YXIconFonts.iconMsgContacts, 'icon msg contacts'), + ExampleIcon(YXIconFonts.iconMsgViedo, 'icon msg viedo'), + 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 msgadd'), + ExampleIcon(YXIconFonts.icon56Msgface, 'icon 56 msgface'), + ExampleIcon(YXIconFonts.icon56Msgvoice, 'icon 56 msgvoice'), + + // 箭头相关图标 + ExampleIcon(YXIconFonts.icon32Arrowright, 'icon 32 arrowright'), + ExampleIcon(YXIconFonts.icon44Arrowleft, 'icon 44 arrowleft'), + ExampleIcon(YXIconFonts.icon44Arrowright, 'icon 44 arrowright'), + ExampleIcon(YXIconFonts.icon24Arrowleft, 'icon 24 arrowleft'), + ExampleIcon(YXIconFonts.icon24Arrowdown, 'icon 24 arrowdown'), + + // 编辑相关图标 + ExampleIcon(YXIconFonts.icon44Edit, 'icon 44 edit'), + ExampleIcon(YXIconFonts.icon36Editline, 'icon 36 editline'), + ExampleIcon(YXIconFonts.icon24Edit, 'icon 24 edit'), + + // 个人中心相关图标 + 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(YXIconFonts.icon24, 'icon 24 -'), + + // 团队和用户相关图标 + ExampleIcon(YXIconFonts.icon36Team, 'icon 36 team'), + ExampleIcon(YXIconFonts.icon32Student, 'icon 32 student'), + + // 功能图标 + ExampleIcon(YXIconFonts.icon32Filter, 'icon 32 filter'), + ExampleIcon(YXIconFonts.icon36Question, 'icon 36 question'), + ExampleIcon(YXIconFonts.icon36Onlysee, 'icon 36 onlysee'), + ExampleIcon(YXIconFonts.icon36Hint, 'icon 36 hint'), + ExampleIcon(YXIconFonts.icon24Switch, 'icon 24 switch'), + + // 退出相关图标 + ExampleIcon(YXIconFonts.icon44Quitlite, 'icon 44 quitlite'), + ExampleIcon(YXIconFonts.icon32Quit, 'icon 32 quit'), + ExampleIcon(YXIconFonts.icon44Quit, 'icon 44 quit'), + + // 更多和菜单相关图标 + ExampleIcon(YXIconFonts.icon44More2, 'icon 44 more2'), + ExampleIcon(YXIconFonts.icon44More, 'icon 44 more'), + + // 复制相关图标 + ExampleIcon(YXIconFonts.icon24Copy, 'icon 24 copy'), + + // 删除相关图标 + ExampleIcon(YXIconFonts.icon44Delete, 'icon 44 delete'), + ExampleIcon(YXIconFonts.icon36Delete, 'icon 36 delete'), + ExampleIcon(YXIconFonts.icon24Delete, 'icon 24 delete'), + + // 日历相关图标 + ExampleIcon(YXIconFonts.icon44Calendar, 'icon 44 calendar'), + + // 分享相关图标 + ExampleIcon(YXIconFonts.icon44Share, 'icon 44 share'), + + // 添加相关图标 + ExampleIcon(YXIconFonts.icon24Add, 'icon 24 add'), + ExampleIcon(YXIconFonts.icon44Add, 'icon 44 add'), + ExampleIcon(YXIconFonts.icon32Add, 'icon 32 add'), + + // 键盘相关图标 + ExampleIcon(YXIconFonts.icon44Keyboard, 'icon 44 keyboard'), + +]; diff --git a/example/lib/main.dart b/example/lib/main.dart new file mode 100644 index 0000000..834ed4e --- /dev/null +++ b/example/lib/main.dart @@ -0,0 +1,142 @@ +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() { + runApp(const YXIconFontsGalleryApp()); +} + +/// YX Icon Fonts 图标库展示应用 +class YXIconFontsGalleryApp extends StatelessWidget { + const YXIconFontsGalleryApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'YX Icon Fonts Gallery', + theme: ThemeData.light().copyWith( + iconTheme: const IconThemeData(size: 36.0, color: Colors.black87), + textTheme: const TextTheme( + bodyMedium: TextStyle(fontSize: 16.0, color: Colors.black87), + ), + ), + home: const YXIconFontsGalleryHome(), + ); + } +} + +/// 主页面 +class YXIconFontsGalleryHome extends StatefulWidget { + const YXIconFontsGalleryHome({super.key}); + + @override + State createState() => _YXIconFontsGalleryHomeState(); +} + +class _YXIconFontsGalleryHomeState extends State { + var _searchTerm = ""; + var _isSearching = false; + + @override + Widget build(BuildContext context) { + final filteredIcons = icons.where((icon) => _searchTerm.isEmpty || icon.title.toLowerCase().contains(_searchTerm.toLowerCase())).toList(); + + return Scaffold( + appBar: _isSearching ? _searchBar(context) : _titleBar(), + body: Scrollbar( + thumbVisibility: kIsWeb, + child: GridView.builder( + itemCount: filteredIcons.length, + gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: 180, + ), + itemBuilder: (context, index) { + final icon = filteredIcons[index]; + + return InkWell( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (BuildContext context) { + return GestureDetector( + onTap: () { + Navigator.of(context).pop(); + }, + child: Container( + color: Colors.white, + alignment: Alignment.center, + child: Hero( + tag: icon, + child: YXIcon( + icon.iconData, + size: 100, + ), + ), + ), + ); + }, + ), + ); + }, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Hero(tag: icon, child: YXIcon(icon.iconData)), + Container( + padding: const EdgeInsets.only(top: 16.0), + child: Text( + icon.title, + style: Theme.of(context).textTheme.labelSmall?.copyWith( + color: Colors.black, + ), + ), + ) + ], + ), + ); + }, + ), + ), + floatingActionButton: FloatingActionButton( + onPressed: () { + setState(() { + _isSearching = !_isSearching; + if (!_isSearching) _searchTerm = ""; + }); + }, + child: Icon(_isSearching ? Icons.close : Icons.search), + ), + ); + } + + PreferredSizeWidget _titleBar() { + return AppBar( + title: const Text('YX Icon Fonts Gallery'), + ); + } + + PreferredSizeWidget _searchBar(BuildContext context) { + return AppBar( + title: TextField( + autofocus: true, + decoration: const InputDecoration(hintText: '搜索图标...'), + onChanged: (value) { + setState(() { + _searchTerm = value; + }); + }, + ), + leading: IconButton( + icon: const Icon(Icons.arrow_back), + onPressed: () { + setState(() { + _isSearching = false; + _searchTerm = ""; + }); + }, + ), + ); + } +} diff --git a/example/pubspec.lock b/example/pubspec.lock new file mode 100644 index 0000000..a630b43 --- /dev/null +++ b/example/pubspec.lock @@ -0,0 +1,212 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + async: + dependency: transitive + description: + name: async + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.13.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.2" + characters: + dependency: transitive + description: + name: characters + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + 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" + collection: + dependency: transitive + description: + name: collection + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.19.1" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.3.3" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1" + 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: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" + url: "https://pub.flutter-io.cn" + source: hosted + version: "10.0.9" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.0.9" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.0.1" + lints: + dependency: transitive + description: + name: lints + sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.0.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + 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: + name: meta + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.16.0" + path: + dependency: transitive + description: + name: path + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.9.1" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + source_span: + dependency: transitive + description: + name: source_span + sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.10.1" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.12.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.4" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.4.1" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.2.2" + test_api: + dependency: transitive + description: + name: test_api + sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.7.4" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 + url: "https://pub.flutter-io.cn" + source: hosted + version: "15.0.0" + yx_icon_fonts: + dependency: "direct main" + description: + path: ".." + relative: true + source: path + version: "1.0.0" +sdks: + dart: ">=3.7.0-0 <4.0.0" + flutter: ">=3.18.0-18.0.pre.54" diff --git a/example/pubspec.yaml b/example/pubspec.yaml new file mode 100644 index 0000000..6ded487 --- /dev/null +++ b/example/pubspec.yaml @@ -0,0 +1,22 @@ +name: yx_icon_fonts_example +description: 学习官OA系统图标字体库示例应用 +publish_to: 'none' + +version: 1.0.0+1 + +environment: + sdk: '>=3.0.0 <4.0.0' + +dependencies: + flutter: + sdk: flutter + yx_icon_fonts: + path: ../ + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^3.0.0 + +flutter: + uses-material-design: true \ No newline at end of file diff --git a/fonts/iconfont.ttf b/fonts/iconfont.ttf new file mode 100644 index 0000000..c964ade Binary files /dev/null and b/fonts/iconfont.ttf differ diff --git a/generate.sh b/generate.sh new file mode 100644 index 0000000..affeca0 --- /dev/null +++ b/generate.sh @@ -0,0 +1,137 @@ +#!/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 +} + +# 生成图标数据 +generate_icons() { + print_info "正在生成图标数据..." + dart scripts/generate_icons.dart + print_success "图标数据生成完成" +} + +# 生成示例文件 +generate_example() { + print_info "正在生成示例文件..." + dart scripts/generate_example.dart + print_success "示例文件生成完成" +} + +# 生成所有文件 +generate_all() { + print_info "开始生成所有文件..." + echo + + generate_icons + 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 " example 只生成示例文件 (example/lib/icons.dart)" + echo " all 生成所有文件 (默认)" + echo " help 显示此帮助信息" + echo + echo "示例:" + echo " $0 # 生成所有文件" + echo " $0 icons # 只生成图标数据" + echo " $0 example # 只生成示例文件" + echo +} + +# 主函数 +main() { + local action=${1:-all} + + case $action in + "icons") + check_dart + check_files + generate_icons + ;; + "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 "$@" \ No newline at end of file diff --git a/iconfont.json b/iconfont.json new file mode 100644 index 0000000..4c26519 --- /dev/null +++ b/iconfont.json @@ -0,0 +1,359 @@ +{ + "id": "4944890", + "name": "学习官OA系统", + "font_family": "iconfont", + "css_prefix_text": "", + "description": "学习官OA系统图标", + "glyphs": [ + { + "icon_id": "44661359", + "name": "icon_msg_contacts", + "font_class": "icon_msg_contacts", + "unicode": "e644", + "unicode_decimal": 58948 + }, + { + "icon_id": "44659960", + "name": "icon_msg_viedo", + "font_class": "icon_msg_viedo", + "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_arrowright", + "font_class": "icon_32_arrowright", + "unicode": "e61d", + "unicode_decimal": 58909 + }, + { + "icon_id": "44625451", + "name": "icon_44_edit", + "font_class": "icon_44_edit", + "unicode": "e638", + "unicode_decimal": 58936 + }, + { + "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_-", + "font_class": "icon_24_-", + "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_quitlite", + "font_class": "icon_44_quitlite", + "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_onlysee", + "font_class": "icon_36_onlysee", + "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": "44625449", + "name": "icon_44_delete", + "font_class": "icon_44_delete", + "unicode": "e62f", + "unicode_decimal": 58927 + }, + { + "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_arrowleft", + "font_class": "icon_44_arrowleft", + "unicode": "e62a", + "unicode_decimal": 58922 + }, + { + "icon_id": "44572499", + "name": "icon_36_editline", + "font_class": "icon_36_editline", + "unicode": "e62b", + "unicode_decimal": 58923 + }, + { + "icon_id": "44572515", + "name": "icon_44_arrowright", + "font_class": "icon_44_arrowright", + "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_msgadd", + "font_class": "icon_56_msgadd", + "unicode": "e624", + "unicode_decimal": 58916 + }, + { + "icon_id": "44572511", + "name": "icon_56_msgface", + "font_class": "icon_56_msgface", + "unicode": "e625", + "unicode_decimal": 58917 + }, + { + "icon_id": "44572516", + "name": "icon_56_msgvoice", + "font_class": "icon_56_msgvoice", + "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_+", + "font_class": "a-icon_24_", + "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_arrowright(1)", + "font_class": "a-icon_44_arrowright1", + "unicode": "e61c", + "unicode_decimal": 58908 + }, + { + "icon_id": "44572493", + "name": "icon_24_arrowleft", + "font_class": "icon_24_arrowleft", + "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_arrowdown", + "font_class": "icon_24_arrowdown", + "unicode": "e621", + "unicode_decimal": 58913 + } + ] +} diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..a725658 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,20 @@ +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!'), + ), + ), + ); + } +} diff --git a/lib/src/yx_icon.dart b/lib/src/yx_icon.dart new file mode 100644 index 0000000..dac3271 --- /dev/null +++ b/lib/src/yx_icon.dart @@ -0,0 +1,118 @@ +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? 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? 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: '', showName: false)); + properties.add(DoubleProperty('size', size, defaultValue: null)); + properties.add(ColorProperty('color', color, defaultValue: null)); + properties.add(IterableProperty('shadows', shadows, defaultValue: null)); + } +} diff --git a/lib/src/yx_icon_data.dart b/lib/src/yx_icon_data.dart new file mode 100644 index 0000000..9ea9930 --- /dev/null +++ b/lib/src/yx_icon_data.dart @@ -0,0 +1,15 @@ +import 'package:flutter/widgets.dart'; + +/// 学习官OA系统图标数据类 +/// +/// 继承自 IconData,提供统一的图标数据接口 +class YXIconData extends IconData { + /// 创建图标数据实例 + /// + /// [codePoint] Unicode码点 + const YXIconData(super.codePoint) + : super( + fontFamily: 'iconfont', + fontPackage: 'yx_icon_fonts', + ); +} diff --git a/lib/src/yx_icon_fonts_data.dart b/lib/src/yx_icon_fonts_data.dart new file mode 100644 index 0000000..053329b --- /dev/null +++ b/lib/src/yx_icon_fonts_data.dart @@ -0,0 +1,262 @@ +import 'package:flutter/widgets.dart'; +import 'yx_icon_data.dart'; + +/// 学习官OA系统图标字体数据 +/// +/// 包含所有图标的常量定义,可以直接在 Flutter 的 Icon 组件中使用 +/// 也可以使用专门的 YXIcon 组件 +class YXIconFonts { + // 私有构造函数,防止实例化 + YXIconFonts._(); + + /// icon_msg_contacts 图标 + /// + /// Unicode: e644 + static const IconData iconMsgContacts = YXIconData(0xe644); + + /// icon_msg_viedo 图标 + /// + /// Unicode: e63e + static const IconData iconMsgViedo = 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_arrowright 图标 + /// + /// Unicode: e61d + static const IconData icon32Arrowright = YXIconData(0xe61d); + + /// icon_44_edit 图标 + /// + /// Unicode: e638 + static const IconData icon44Edit = YXIconData(0xe638); + + /// 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_- 图标 + /// + /// Unicode: e63b + static const IconData icon24 = 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_quitlite 图标 + /// + /// 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_onlysee 图标 + /// + /// 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_44_delete 图标 + /// + /// Unicode: e62f + static const IconData icon44Delete = YXIconData(0xe62f); + + /// 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_arrowleft 图标 + /// + /// Unicode: e62a + static const IconData icon44Arrowleft = YXIconData(0xe62a); + + /// icon_36_editline 图标 + /// + /// Unicode: e62b + static const IconData icon36Editline = YXIconData(0xe62b); + + /// icon_44_arrowright 图标 + /// + /// Unicode: e622 + static const IconData icon44Arrowright = YXIconData(0xe622); + + /// icon_24_delete 图标 + /// + /// Unicode: e623 + static const IconData icon24Delete = YXIconData(0xe623); + + /// icon_56_msgadd 图标 + /// + /// Unicode: e624 + static const IconData icon56Msgadd = YXIconData(0xe624); + + /// icon_56_msgface 图标 + /// + /// Unicode: e625 + static const IconData icon56Msgface = YXIconData(0xe625); + + /// icon_56_msgvoice 图标 + /// + /// 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_+ 图标 + /// + /// 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_arrowright(1) 图标 + /// + /// Unicode: e61c + static const IconData icon44Arrowright1 = YXIconData(0xe61c); + + /// icon_24_arrowleft 图标 + /// + /// Unicode: e61e + static const IconData icon24Arrowleft = 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_arrowdown 图标 + /// + /// Unicode: e621 + static const IconData icon24Arrowdown = YXIconData(0xe621); + +} diff --git a/lib/yx_icon_fonts.dart b/lib/yx_icon_fonts.dart new file mode 100644 index 0000000..9e7ef30 --- /dev/null +++ b/lib/yx_icon_fonts.dart @@ -0,0 +1,26 @@ +library yx_icon_fonts; + +// 导出所有公共组件和类 +export 'src/yx_icon.dart'; +export 'src/yx_icon_data.dart'; +export 'src/yx_icon_fonts_data.dart'; + +/// 学习官OA系统图标字体库 +/// +/// 提供学习官OA系统的图标字体支持,包含所有图标常量和组件 +/// +/// ## 使用方法 +/// +/// ```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: () {}, +/// ) +/// ``` diff --git a/pubspec.lock b/pubspec.lock new file mode 100644 index 0000000..f490b88 --- /dev/null +++ b/pubspec.lock @@ -0,0 +1,205 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + async: + dependency: transitive + description: + name: async + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.13.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.2" + characters: + dependency: transitive + description: + name: characters + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + 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" + collection: + dependency: transitive + description: + name: collection + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.19.1" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.3.3" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1" + 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: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" + url: "https://pub.flutter-io.cn" + source: hosted + version: "10.0.9" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.0.9" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.0.1" + lints: + dependency: transitive + description: + name: lints + sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.0.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + 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: + name: meta + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.16.0" + path: + dependency: transitive + description: + name: path + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.9.1" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + source_span: + dependency: transitive + description: + name: source_span + sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.10.1" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.12.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.4" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.4.1" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.2.2" + test_api: + dependency: transitive + description: + name: test_api + sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.7.4" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 + url: "https://pub.flutter-io.cn" + source: hosted + version: "15.0.0" +sdks: + dart: ">=3.7.0-0 <4.0.0" + flutter: ">=3.18.0-18.0.pre.54" diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 0000000..8ac2fd8 --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,23 @@ +name: yx_icon_fonts +description: 学习官OA系统图标字体库,基于iconfont.ttf和iconfont.json生成 +version: 1.0.0 +homepage: https://github.com/your-username/yx_icon_fonts + +environment: + sdk: '>=3.0.0 <4.0.0' + flutter: ">=3.0.0" + +dependencies: + flutter: + sdk: flutter + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^3.0.0 + +flutter: + fonts: + - family: iconfont + fonts: + - asset: fonts/iconfont.ttf \ No newline at end of file diff --git a/scripts/generate_example.dart b/scripts/generate_example.dart new file mode 100644 index 0000000..bb13ccc --- /dev/null +++ b/scripts/generate_example.dart @@ -0,0 +1,96 @@ +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 glyphs, Set 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 = ["); + + // 按类别分组图标 + final categories = >>{}; + 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('_', ' '); +} diff --git a/scripts/generate_icons.dart b/scripts/generate_icons.dart new file mode 100644 index 0000000..9a2f500 --- /dev/null +++ b/scripts/generate_icons.dart @@ -0,0 +1,48 @@ +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 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} 个图标常量'); +} diff --git a/scripts/utils.dart b/scripts/utils.dart new file mode 100644 index 0000000..96d1abc --- /dev/null +++ b/scripts/utils.dart @@ -0,0 +1,48 @@ +import 'dart:convert'; +import 'dart:io'; + +/// 读取 iconfont.json 文件,返回解析后的 Map +Map 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; +} + +/// 获取 glyphs 列表 +List getGlyphs(Map iconData) { + return iconData['glyphs'] as List; +} + +/// 下划线转驼峰命名,并处理常见特殊字符,保证 Dart 标识符合法 +String toCamelCase(String input) { + String processedInput = input.replaceAll('-', '_').replaceAll('+', 'plus').replaceAll('(', '').replaceAll(')', '').replaceAll(' ', ''); + final List 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 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(); +} diff --git a/test/yx_icon_fonts_test.dart b/test/yx_icon_fonts_test.dart new file mode 100644 index 0000000..318dc02 --- /dev/null +++ b/test/yx_icon_fonts_test.dart @@ -0,0 +1,29 @@ +import 'package:flutter_test/flutter_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()); + expect(YXIconFonts.iconMsgContacts.fontFamily, equals('iconfont')); + }); + + test('should create YXIcon widget', () { + // 测试 YXIcon 组件创建 + final icon = YXIcon(YXIconFonts.iconMsgContacts); + expect(icon, isNotNull); + expect(icon.icon, equals(YXIconFonts.iconMsgContacts)); + }); + + 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); + }); + }); +}