Skip to content

Commit

Permalink
iconfont 类代码生成器
Browse files Browse the repository at this point in the history
  • Loading branch information
toly1994328 committed Feb 25, 2023
1 parent 10b58dd commit 0f69501
Show file tree
Hide file tree
Showing 21 changed files with 777 additions and 145 deletions.
49 changes: 0 additions & 49 deletions assets/iconfont/icon_builder.dart

This file was deleted.

Binary file modified assets/iconfont/iconfont.ttf
Binary file not shown.
2 changes: 1 addition & 1 deletion lib/app/navigation/desk_ui/unit_desk_navigation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class _UnitDeskNavigationState extends State<UnitDeskNavigation> {
onItemClick: _onItemClick, itemData: {
//底栏图标
"组件集录": TolyIcon.icon_layout, "收藏集录": TolyIcon.icon_star,
"绘制集录": Icons.palette, "代码生成": Icons.widgets,
"绘制集录": Icons.palette, "代码生成": TolyIcon.icon_fast,
"要点集录": TolyIcon.icon_bug,
},
),
Expand Down
44 changes: 32 additions & 12 deletions lib/code_gen/code_gen_page.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import 'dart:io';

import 'package:file_selector/file_selector.dart';
import 'package:flutter/material.dart';
import 'package:flutter_unit/code_gen/icon_font_gen/icon_font_gen_page.dart';

import 'class_generator.dart';
import 'desk_widget_top_bar.dart';
Expand All @@ -22,6 +21,7 @@ class CodeGenPage extends StatefulWidget {
class _CodeGenPageState extends State<CodeGenPage> {

TextEditingController _dirPath = TextEditingController();
final PageController _ctrl = PageController();
int selectIndex = 0;

final List<String> selectData = [
Expand Down Expand Up @@ -50,12 +50,30 @@ class _CodeGenPageState extends State<CodeGenPage> {
children: [
DeskCodeGenTopBar(
onTapGen: _doGen,
onTabPressed: (int value) {},
onTabPressed: (int value) {
_ctrl.jumpToPage(value);
},
),
Expanded(child: Center(
child: Text(
'敬请期待'
),
Expanded(child: PageView(
controller:_ctrl,
children: [
IconFontGenPage(),
Center(
child: Text(
'敬请期待'
),
),
Center(
child: Text(
'敬请期待'
),
),
Center(
child: Text(
'敬请期待'
),
)
],
)),
if(false)
Padding(
Expand All @@ -64,11 +82,11 @@ class _CodeGenPageState extends State<CodeGenPage> {
children: [
GestureDetector(
onTap: () async{
final String? directoryPath = await getDirectoryPath();
if (directoryPath != null) {
print("====$directoryPath=========");
_dirPath.text = directoryPath;
}
// final String? directoryPath = await getDirectoryPath();
// if (directoryPath != null) {
// print("====$directoryPath=========");
// _dirPath.text = directoryPath;
// }
},
child: Icon(Icons.file_copy_outlined)),
SizedBox(width: 20,),
Expand Down Expand Up @@ -124,6 +142,8 @@ class _CodeGenPageState extends State<CodeGenPage> {
clazz1.write2File(Directory(_dirPath.text));
}
}


}

class GenInput extends StatelessWidget {
Expand Down
9 changes: 2 additions & 7 deletions lib/code_gen/desk_widget_top_bar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class DeskCodeGenTopBar extends StatefulWidget {
class _DeskCodeGenTopBarState extends State<DeskCodeGenTopBar> with SingleTickerProviderStateMixin {
late TabController tabController;

static const List<String> _tabs = ['数据类', 'IconFont', '状态管理', 'Json 解析',];
static const List<String> _tabs = ['IconFont', '数据类' , '状态管理', 'Json 解析',];

@override
void initState() {
Expand Down Expand Up @@ -62,12 +62,7 @@ class _DeskCodeGenTopBarState extends State<DeskCodeGenTopBar> with SingleTicke
),
),
Spacer(),
ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 0,
shape: StadiumBorder()
),
onPressed: widget.onTapGen, child: Text('生成代码')),

const SizedBox(width: 20,),
WindowButtons(),
],
Expand Down
36 changes: 36 additions & 0 deletions lib/code_gen/icon_font_gen/gen_message_action.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@

import 'package:app_config/app_config.dart';
import 'package:flutter/material.dart';



class GenMessageAction extends StatelessWidget {
final VoidCallback onGen;
const GenMessageAction({Key? key, required this.onGen}) : super(key: key);

@override
Widget build(BuildContext context) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(child: Text(
'使用方式:\n1. 在 iconfont.cn 挑选图标,加入项目,下载压缩包。\n2. 选择 Flutter 项目地址,配置资源、产物文件位置。\n3. 点击生成代码按钮,即可生成相关代码。',
style: TextStyle(
color: Theme.of(context).primaryColor,fontWeight: FontWeight.bold),)),
ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 0,
shape: const StadiumBorder()
),
onPressed:onGen, child: Wrap(
crossAxisAlignment: WrapCrossAlignment.center,
spacing: 4,
children: [
Icon(TolyIcon.icon_fast,size: 16,),
const Text('生成代码',style: TextStyle(height: 1,fontSize: 12),),
],
)),
],
);
}
}
148 changes: 148 additions & 0 deletions lib/code_gen/icon_font_gen/icon_font_class_parser.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import 'dart:convert';
import 'dart:io';
import 'package:archive/archive_io.dart';

import 'icon_font_gen_config.dart';
import 'package:path/path.dart' as path;

class IconFontClassParser{

void gen(IconFontGenConfig config){
final inputStream = InputFileStream(config.srcZip);
// 将压缩包有用资源解压到目标文件
final archive = ZipDecoder().decodeBuffer(inputStream);
for (var file in archive.files) {
if (file.isFile) {
if (file.name.endsWith('.ttf')) {
final outputStream = OutputFileStream(config.ttfDistPath);
file.writeContent(outputStream);
outputStream.close();
}
if (file.name.endsWith('.json')) {
dynamic data = file.content;
String jsonContent = utf8.decode(data);
String resultCode = parser(jsonContent,config.fontFamily);
File distFile = File(config.distFilePath);
if(!distFile.existsSync()){
distFile.createSync(recursive: true);
}
distFile.writeAsStringSync(resultCode);
setYaml(config);
}
}
}
}

String parser(String input,String fontFamily){
dynamic map = json.decode(input);
List<dynamic> glyphs = map['glyphs'] as List<dynamic>;
String code = '';
for(int i=0;i<glyphs.length;i++){
String fieldName = glyphs[i]['font_class'];
String unicode = glyphs[i]['unicode'];
String lineCode = """static const IconData $fieldName = IconData(0x$unicode, fontFamily: "$fontFamily");\n""";
code+=lineCode;
}

String result =
"""
import 'package:flutter/widgets.dart';
// Power By 张风捷特烈--- Generated file. Do not edit.
// 欢迎支持: https://github.com/toly1994328/FlutterUnit
class $fontFamily {
$fontFamily._();
$code
}
""";
return result;
}

// 修改 pubspec.yaml
void setYaml(IconFontGenConfig config){
String familyName = config.fontFamily;
String fontAssetsDist = config.yamlAssetDist;
final String filePath = path.join(config.projectPath,'pubspec.yaml');
// final String filePath = r'E:\Projects\Flutter\FlutterUnit\pubspec.yaml';

File pubspecFile = File(filePath);

List<String> lines = pubspecFile.readAsLinesSync();

RegExp fontsRegex = RegExp(r'^ fonts:',multiLine: true);
bool hasFonts = fontsRegex.hasMatch(lines.join('\n'));

if(!hasFonts){
// 当前没有 fonts 节点,需要添加到 flutter 节点下
int index = lines.indexWhere((e) => e.startsWith('flutter:'));
List<String> fonts = [
' fonts:',
' - family: $familyName',
' fonts:',
' - asset: $fontAssetsDist',
];

lines.insertAll(index+1, fonts);
pubspecFile.writeAsStringSync(lines.join('\n'));
return;
}
// 存在 fonts 节点,查询 family ,有没有当前字体图标
bool hasTargetFamily = false;
RegExp regExp = RegExp(r'^ +- family: +(\w+)');

for(int i=0;i<lines.length;i++){
String line = lines[i];
if(line.startsWith(regExp)){
String family = regExp.allMatches(line).first.group(1)??'';
if(family == familyName){
hasTargetFamily = true;
break;
}
}
}
if(!hasTargetFamily){
int index = lines.indexWhere((e) => e.startsWith(fontsRegex));
List<String> fonts = [
' - family: $familyName',
' fonts:',
' - asset: $fontAssetsDist',
];
lines.insertAll(index+1, fonts);
pubspecFile.writeAsStringSync(lines.join('\n'));
return;
}
}

// // 修改 pubspec.yaml
// void setYaml(IconFontGenConfig config){
// String fontFamily = config.fontFamily;
// String assets = config.assetsDist.replaceAll('\\', '/');
//
// final String filePath = path.join(config.projectPath,'pubspec.yaml');
// File pubspecFile = File(filePath);
// final String pubspec = pubspecFile.readAsStringSync();
// final doc = loadYaml(pubspec);
// final modifiableDoc = getModifiableNode(doc);
//
// YamlList? fontsList = doc['flutter']['fonts'] as YamlList?;
// if(fontsList == null){
// // 新文件,没有配置 fonts 节点
// modifiableDoc['flutter']['fonts'] = YamlMap.wrap({
// 'family': fontFamily,
// 'fonts':YamlList.wrap([YamlMap.wrap({'asset':'$assets/iconfont.ttf'})])
// });
// }else{
// final modifiableList = getModifiableNode(fontsList);
// modifiableList.removeWhere((e) => e['family'] == fontFamily);
// modifiableList.add(
// YamlMap.wrap({
// 'family': fontFamily,
// 'fonts':YamlList.wrap([YamlMap.wrap({'asset':'$assets/iconfont.ttf'})])
// })
// );
// modifiableDoc['flutter']['fonts'] = modifiableList;
// }
// final targetYaml = toYamlString(modifiableDoc);
// pubspecFile.writeAsStringSync(targetYaml);
// }

}
47 changes: 47 additions & 0 deletions lib/code_gen/icon_font_gen/icon_font_gen_config.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import 'package:path/path.dart' as path;

class IconFontGenConfig {
final String srcZip;
final String projectPath;
final String assetsDist;
final String fileDist;

IconFontGenConfig({
this.srcZip = '',
this.projectPath = '',
String? assetsDist,
String? fileDist,
}) : fileDist = fileDist ?? 'lib${spa}app${spa}gen${spa}toly_icon.dart',
assetsDist = assetsDist ?? 'assets${spa}iconfont';

static String get spa => path.separator;

String get distFilePath => path.join(projectPath, fileDist);

String get distAssetsDir => path.join(projectPath, assetsDist);

String get ttfDistPath => path.join(distAssetsDir, path.basenameWithoutExtension(fileDist)+".ttf");

String get yamlAssetDist => assetsDist.replaceAll('\\', '/')+"/"+path.basename(ttfDistPath);

String get fontFamily => path
.basenameWithoutExtension(fileDist)
.split('_')
.map((e) => e[0].toUpperCase() + e.substring(1,))
.join('');

factory IconFontGenConfig.fromJson(Map<String, dynamic> map) {
return IconFontGenConfig(
srcZip: map['srcZip'] ?? '',
projectPath: map['projectPath'] ?? '',
assetsDist: map["assetsDist"] ?? '',
fileDist: map["fileDist"] ?? '');
}

Map<String, dynamic> toJson() => {
'srcZip': srcZip,
'projectPath': projectPath,
'assetsDist': assetsDist,
'fileDist': fileDist,
};
}
Loading

0 comments on commit 0f69501

Please sign in to comment.