diff --git a/.github/workflows/ci_build.yml b/.github/workflows/ci_build.yml new file mode 100644 index 0000000..f989787 --- /dev/null +++ b/.github/workflows/ci_build.yml @@ -0,0 +1,98 @@ +name: Flutter Build + +on: + push: + workflow_dispatch: + +env: + FLUTTER_VERSION: '3.19.3' + +jobs: + setup: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + platform: 'android' + target-platform: 'android-arm64' + - os: ubuntu-latest + platform: 'linux' + - os: windows-latest + platform: 'windows' + - os: macos-14 + platform: 'ios' + - os: macos-14 + platform: 'macos' + steps: + - uses: actions/checkout@v4 + + + - name: Install Flutter SDK + uses: hughware/flutter-action@v1.0.0 + with: + flutter-version: ${{ env.FLUTTER_VERSION }} + cache: true + cache-key: flutter-sdk-${{ runner.os }}-${{ env.FLUTTER_VERSION }} + + - run: flutter pub get + + - name: Build for Android + if: matrix.platform == 'android' + run: flutter build apk --release --target-platform ${{ matrix.target-platform }} + + + - name: Build for Linux + if: matrix.platform == 'linux' + run: | + sudo apt-get update -y + sudo apt-get install -y ninja-build libgtk-3-dev + flutter build linux --release + + - name: Build for Windows + if: matrix.platform == 'windows' + run: flutter build windows --release + + - name: Build for iOS + if: matrix.platform == 'ios' + run: flutter build ios --release --no-codesign + + - name: Build for macOS + if: matrix.platform == 'macos' + run: flutter build macos --release + + - name: Upload Artifact for Android + if: matrix.platform == 'android' + uses: actions/upload-artifact@v4 + with: + name: android-app + path: build/app/outputs/flutter-apk/app-release.apk + + - name: Upload Artifact for Linux + if: matrix.platform == 'linux' + uses: actions/upload-artifact@v4 + with: + name: linux-app + path: build/linux/*/release/bundle + + - name: Upload Artifact for Windows + if: matrix.platform == 'windows' + uses: actions/upload-artifact@v4 + with: + name: windows-app + path: build/windows/x64/runner/Release/* + + - name: Upload Artifact for iOS + if: matrix.platform == 'ios' + uses: actions/upload-artifact@v4 + with: + name: ios-app + path: build/ios/iphoneos/*.app + + - name: Upload Artifact for macOS + if: matrix.platform == 'macos' + uses: actions/upload-artifact@v4 + with: + name: macos-app + path: build/macos/Build/Products/Release/*.app diff --git a/LICENSE b/LICENSE index c5e29ed..3d276ce 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2023 molihuan +Copyright (c) 2023-2024 molihuan Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index accd3cb..7f909f3 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ # 我们会一直维护这个软件,除非江水为竭🌊,冬雷震震⚡,没有Star⭐。直至时间的尽头🕑。 - +## 右上角给项目一个Star(小星星),你的支持是我更新的唯一动力。 # HL视频笔记📒 @@ -25,7 +25,7 @@ 特点:一键视频截屏插入笔记;在笔记上插入视频节点,点击视频节点跳转到视频指定时间点;笔记中插入图片,音频,视频;支持手写笔记;支持录音;多端联动(例如:电脑看视频,平板写笔记,点击平板截屏按钮可一键在笔记中插入电脑视频截图);支持插件系统,安装插件,扩展自定义功能;导出笔记为pdf;在pdf上做笔记;视频支持Bilibili,YouTube; -### 右上角给项目一个Star(小星星),你的支持是我更新的唯一动力。 + ### 一个人是孤独的,我们非常需要你!诚挚地邀请你上我们的贼船🏴‍☠️! ##### 加入我们吧!无论你是否会写代码,都可加入我们! diff --git a/doc/md/zh_CN/DevelopmentEnvironment.md b/doc/md/zh_CN/DevelopmentEnvironment.md index 3584043..5499ac1 100644 --- a/doc/md/zh_CN/DevelopmentEnvironment.md +++ b/doc/md/zh_CN/DevelopmentEnvironment.md @@ -54,6 +54,8 @@ • Edge (web) • edge • web-javascript • Microsoft Edge 114.0.1823.82 (unsupported) ``` + + ## 常用命令 ```shell @@ -72,3 +74,11 @@ flutter build apk --split-per-abi flutter build ios --release ``` +## 注意在编译一些依赖时需要用到rust请安装并配置好rust + +```sh +rustup 1.27.1 (54dd3d00f 2024-04-24) +info: This is the version for the rustup toolchain manager, not the rustc compiler. +info: The currently active `rustc` version is `rustc 1.78.0 (9b00956e5 2024-04-29) +``` + diff --git a/lib/common/store/global_store.dart b/lib/common/store/global_store.dart new file mode 100644 index 0000000..842b297 --- /dev/null +++ b/lib/common/store/global_store.dart @@ -0,0 +1,5 @@ +class GlobalStore{ + // 数据存储 + // 所有笔记配置位置列表 + static const String DATASTORE_KEY_NOTE_CFG_POS_LIST = "molihuan_note_DATASTORE_KEY_NOTE_CFG_POS_LIST"; +} \ No newline at end of file diff --git a/lib/common/utils/common_tool.dart b/lib/common/utils/common_tool.dart index 1b67c28..5abab58 100644 --- a/lib/common/utils/common_tool.dart +++ b/lib/common/utils/common_tool.dart @@ -4,15 +4,43 @@ import 'package:flutter/material.dart'; typedef String StrCallbackStr(String value); typedef void CallbackStr(String value); typedef String StrCallback(); - -typedef Widget WgetCallback(); +typedef bool BoolCallback(); /// 异步方法 typedef Future FStrCallbackStr(String value); typedef Future FCallbackStr(String value); typedef Future FStrCallback(); +typedef Widget WgetCallback(); + class CommonTool { + + Widget conditionalWidget(BoolCallback boolCallback, Widget widget) { + bool condition = boolCallback(); + return condition ? widget : Visibility(visible: false, child: widget); + } + + /// 获取父位置 + static String getParentPos(String path) { + // 如果路径以斜杠结尾,先去掉斜杠 + if (path.endsWith('/')) { + path = path.substring(0, path.length - 1); + } + + // 使用字符串匹配找到最后一个斜杠的位置 + int lastSlashIndex = path.lastIndexOf('/'); + + // 如果找不到斜杠,或者斜杠在第一个位置,表示当前路径已经是根路径,直接返回原路径 + if (lastSlashIndex <= 0) { + return path; + } + + // 截取路径字符串,获取上一级路径 + return path.substring(0, lastSlashIndex); + } + + + ///String转Duration static Duration str2Duration(String durationString) { List parts = durationString.split(':'); @@ -37,6 +65,7 @@ class CommonTool { } ///获取当前时间 + ///2024_05_12_22_36_37_1715524597897 static String getCurrentTime() { DateTime dateTime = DateTime.now(); final formattedDate = @@ -48,21 +77,21 @@ class CommonTool { } ///获取上一级url - static String? getParentUrl(String url) { - if (url.isEmpty) { - return null; - } - - ///如果是以路径分隔符结尾则去除最后的路径分隔符 - if (url.endsWith("/")) { - url = url.substring(0, url.length - 1); - } - - if (!url.contains("/")) { - return null; - } - - int endIndex = url.lastIndexOf("/"); - return url.substring(0, endIndex); - } + // static String? getParentUrl(String url) { + // if (url.isEmpty) { + // return null; + // } + // + // ///如果是以路径分隔符结尾则去除最后的路径分隔符 + // if (url.endsWith("/")) { + // url = url.substring(0, url.length - 1); + // } + // + // if (!url.contains("/")) { + // return null; + // } + // + // int endIndex = url.lastIndexOf("/"); + // return url.substring(0, endIndex); + // } } diff --git a/lib/common/utils/file_tool.dart b/lib/common/utils/file_tool.dart index c55ad52..6a7b3a0 100644 --- a/lib/common/utils/file_tool.dart +++ b/lib/common/utils/file_tool.dart @@ -5,10 +5,9 @@ import 'dart:typed_data'; import 'package:external_path/external_path.dart'; import 'package:note/common/utils/common_tool.dart'; import 'package:note/common/utils/platform_tool.dart'; -import 'package:note/models/note/base_note.dart'; -import 'package:note/models/note/note_route_msg.dart'; -import 'package:note/models/r_source.dart'; -import 'package:note/models/read_media.dart'; + +import 'package:note/models/note_model/base_note.dart'; + import 'package:package_info_plus/package_info_plus.dart'; import 'package:path/path.dart' as path; import 'package:path/path.dart'; @@ -16,6 +15,68 @@ import 'package:path/path.dart'; class FileTool { static const String DIR_DEFAULT_NOTE_PROJECT = "NoteProject"; + static loadNoteFile(){ + + } + + static bool deleteAll(String path) { + Directory folder = Directory(path); + if (folder.existsSync()) { + folder.deleteSync(recursive: true); + return true; + } else { + print('文件夹不存在'); + return false; + } + } + + static Future?> readJsonFile(String filePath) async { + try { + // 读取文件内容 + File file = File(filePath); + String content = await file.readAsString(); + + // 将文件内容解析为 JSON + Map? jsonData = json.decode(content); + return jsonData; + } catch (error) { + print('读取文件时出现错误:$error'); + return null; + } + } + + static Future writeFile(String filePath, String content) async { + try { + // 创建文件 + File file = File(filePath); + // 写入内容 + await file.writeAsString(content); + return true; + } catch (error) { + return false; + } + } + + static Future writeMapToFile(String filePath, Map map) async { + try { + // 将 Map 转换为 JSON 格式的字符串 + String jsonString = jsonEncode(map); + + // 创建文件 + File file = File(filePath); + + // 写入内容 + await file.writeAsString(jsonString); + + print('文件创建成功并写入内容。'); + return true; + } catch (error) { + print('写入文件时出现错误:$error'); + return false; + } + } + +/////////////////////////////////////////////////////////////////////////// static bool deleteFiles(String folderPath) { Directory folder = Directory(folderPath); if (folder.existsSync()) { @@ -44,11 +105,10 @@ class FileTool { try { /// 将图片数据写入文件 await imageFile.writeAsBytes(imageBytes); - /// 返回保存的图片路径 return absolutePath; } catch (e) { - print('保存图片出错:$e'); + print('保存图片出错:$e'); return null; } } @@ -133,11 +193,11 @@ class FileTool { } /// 把文件转换为json - static Map? readJson(String filePath) { + static Map? readJson(String filePath) { final file = File(filePath); try { var jsonString = file.readAsStringSync(); - Map jsonObj = jsonDecode(jsonString); + Map jsonObj = jsonDecode(jsonString); return jsonObj; } catch (e) { print('readJson err: $e'); @@ -190,44 +250,39 @@ class FileTool { /// 创建笔记项目 static Future createNoteProjectFile( - BaseNote baseNote, String readMedia) async { - var noteRouteMsg = baseNote.noteRouteMsg; + BaseNote baseNote) async { //TODO 判断权限是否足够 - //判断指定文件是否存在 - if (fileExists(noteRouteMsg.noteFilePosition)) { - return noteRouteMsg.noteFilePosition; + //判断笔记内容文件是否存在 + if (fileExists(baseNote.noteDataPos)) { + return baseNote.noteDataPos; } - //资源分类 List resourceClass = [ - noteRouteMsg.noteImgDirPosition!, - noteRouteMsg.noteConfigDirPosition!, - noteRouteMsg.noteVideoDirPosition!, - noteRouteMsg.notePdfDirPosition!, + baseNote.noteImgPos, + baseNote.noteVideoPos, + baseNote.noteAudioPos, + baseNote.notePdfPos, + baseNote.noteMarkdownPos, + baseNote.noteTxtPos, ]; - + ///创建文件夹 for (String dir in resourceClass) { Directory(dir).createSync(recursive: true); - if (dir == NotePositionConstant.dirConfig.v) {} } + ///初始化笔记内容并写入文件(这里应该提供统一的保存接口,saveRes,本地应该实现写入本地文件,网络应该实现请求保存接口) + bool createResult=await writeFile(baseNote.noteDataPos, '[{"insert":" "}]'); - ///设置阅读媒介的类型,本地、网络 - ///设置阅读媒介 - Map content = { - ReadMedia.flag + Rsource.flag: SourceType.LOCAL.name, - ReadMedia.flag: readMedia, - }; - writeJson(noteRouteMsg.noteBaseConfigFilePosition!, mapContent: content); - - bool createResult = - createFile(noteRouteMsg.noteFilePosition, context: '[{"insert":" "}]'); - if (createResult) { - return noteRouteMsg.noteFilePosition; + if (createResult == false){ + return null; } - return null; + ///保存配置文件(这里应该提供统一的保存接口,saveRes,本地应该实现写入本地文件,网络应该实现请求保存接口) + writeJson(baseNote.noteCfgPos, mapContent: baseNote.toJson()); + + return baseNote.noteDataPos; + } ///获取上一级路径 diff --git a/lib/dao/data_manager.dart b/lib/dao/data_manager.dart new file mode 100644 index 0000000..2fd7202 --- /dev/null +++ b/lib/dao/data_manager.dart @@ -0,0 +1,75 @@ +import 'package:common_utils/common_utils.dart'; +import 'package:nb_utils/nb_utils.dart'; +import 'package:note/common/store/global_store.dart'; +import 'package:note/common/utils/file_tool.dart'; +import 'package:note/models/note_model/base_note.dart'; + +class DataManager{ + static const DATASTORE_KEY_EDITOR_SHOW_MORE_TOOLBAR_BTN = "molihuan_note_DATASTORE_KEY_EDITOR_SHOW_MORE_TOOLBAR_BTN"; + + static Future setShowMoreToolbarBtn(bool value){ + return setValue(DATASTORE_KEY_EDITOR_SHOW_MORE_TOOLBAR_BTN, value); + } + static bool getShowMoreToolbarBtn(){ + return getBoolAsync(DATASTORE_KEY_EDITOR_SHOW_MORE_TOOLBAR_BTN); + } + + ///设置笔记配置位置列表 + static Future setNoteCfgPosList(List list){ + return setValue(GlobalStore.DATASTORE_KEY_NOTE_CFG_POS_LIST, list); + } + static Future setNoteCfgPosListByNote(List list){ + List? noteCfgPosList = []; + for(var note in list){ + noteCfgPosList.add(note.noteCfgPos); + } + return setNoteCfgPosList(noteCfgPosList); + } + ///获取笔记配置位置列表 + static List? getNoteCfgPosList(){ + List? noteCfgPosList = getStringListAsync(GlobalStore.DATASTORE_KEY_NOTE_CFG_POS_LIST); + LogUtil.d("获取到的笔记列表为:$noteCfgPosList"); + return noteCfgPosList; + } + + static Future> getNoteList() async { + List noteList=[]; + List? noteCfgPosList = getNoteCfgPosList(); + + if(noteCfgPosList == null){ + return noteList; + } + + for(var noteCfgPos in noteCfgPosList){ + var noteJson = await FileTool.readJsonFile(noteCfgPos); + if (noteJson!=null){ + var baseNote = BaseNote.fromJson(noteJson); + print(baseNote); + noteList.add(baseNote); + } + } + + return noteList; + } + ///添加一个笔记配置 + static Future addNoteCfgPos(List list,String noteCfgPos) async { + list.add(noteCfgPos); + return setNoteCfgPosList(list); + } + + static Future addNoteCfgPosByNote(List list,BaseNote baseNote) async { + list.add(baseNote); + return setNoteCfgPosListByNote(list); + } + ///删除一个笔记配置 + static Future removeNoteCfgPos(List list,String noteCfgPos) async { + list.remove(noteCfgPos); + return setNoteCfgPosList(list); + } + + static Future removeNoteCfgPosByNote(List list,BaseNote baseNote) async { + list.remove(baseNote); + return setNoteCfgPosListByNote(list); + } + +} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index e4a94a4..3e422e7 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,3 +1,4 @@ +import 'package:common_utils/common_utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get_navigation/src/root/get_material_app.dart'; @@ -15,7 +16,9 @@ Future main() async { ///init nb_utils await initialize(); - print('初始化完毕'); + + LogUtil.init(isDebug: true); + runApp(MyApp()); } @@ -32,11 +35,11 @@ class MyApp extends StatelessWidget { ), debugShowCheckedModeBanner: false, - // 初始路由 + /// 初始路由 initialRoute: AppPages.INITIAL, - // 所有的页面 + /// 所有的页面 getPages: AppPages.routes, - //国际化 + ///国际化 locale: TranslationService.locale, fallbackLocale: TranslationService.fallbackLocale, translations: TranslationService(), diff --git a/lib/middlewares/shelf/service/shelf_service.dart b/lib/middlewares/shelf/service/shelf_service.dart deleted file mode 100644 index d298595..0000000 --- a/lib/middlewares/shelf/service/shelf_service.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'package:shelf/shelf.dart'; -import 'package:shelf/shelf_io.dart' as io; - -class ShelfService { - void run() { - var handler = - const Pipeline().addMiddleware(logRequests()).addHandler(_echoRequest); - //监听所以地址 - io.serve(handler, '0.0.0.0', 8080).then((server) { - print('Serving at http://${server.address.host}:${server.port}'); - }); - } - - Response _echoRequest(Request request) { - return Response.ok(request.requestedUri.toString()); - } -} diff --git a/lib/models/note/base_note.dart b/lib/models/note/base_note.dart deleted file mode 100644 index 33e8bf8..0000000 --- a/lib/models/note/base_note.dart +++ /dev/null @@ -1,151 +0,0 @@ -import 'package:note/models/r_source.dart'; -import 'package:note/models/read_media.dart'; - -import 'note_route_msg.dart'; - -/** - * --noteName1 - * --noteName1.hl - * --resource - * --img(存放图片、截图) - * --config(是什么模式的笔记,存放白板数据) - * --video(存放视频) - * --pdf(存放pdf) - */ - -class BaseNote { - BaseNote({ - required this.readMedia, - required this.noteSourceType, - required this.noteRouteMsg, - required this.noteTitle, - required this.noteDescription, - this.noteCreateTime, - required this.noteUpdateTime, - this.noteCover, - }); - - static const String flag = "BaseNote"; - - ///笔记类型 - ///阅读媒介 - ReadMedia readMedia; - - ///笔记来源(本地、网络) - SourceType noteSourceType; - - ///笔记路由信息 - NoteRouteMsg noteRouteMsg; - - ///展示信息 - static const String noteTitleKey = "noteTitle"; - String noteTitle; - static const String noteDescriptionKey = "noteDescription"; - String noteDescription; - static const String noteCreateTimeKey = "noteCreateTime"; - DateTime? noteCreateTime; - static const String noteUpdateTimeKey = "noteUpdateTime"; - DateTime noteUpdateTime; - - ///封面 - static const String noteCoverKey = "noteCover"; - String? noteCover; - - Map toJson() { - return { - ReadMedia.flag: { - ReadMediaType.flag: readMedia.readMediaType.index, - Rsource.flag: { - Rsource.vkey: readMedia.rsource.v, - SourceType.flag: readMedia.rsource.sourceType.index - } - }, - SourceType.flag: noteSourceType.index, - NoteRouteMsg.flag: { - NoteRouteMsg.noteFilePositionKey: noteRouteMsg.noteFilePosition, - NoteRouteMsg.noteProjectPositionKey: noteRouteMsg.noteProjectPosition, - NoteRouteMsg.noteResourceDirPositionKey: - noteRouteMsg.noteResourceDirPosition, - NoteRouteMsg.noteConfigDirPositionKey: - noteRouteMsg.noteConfigDirPosition, - NoteRouteMsg.noteImgDirPositionKey: noteRouteMsg.noteImgDirPosition, - NoteRouteMsg.noteVideoDirPositionKey: noteRouteMsg.noteVideoDirPosition, - NoteRouteMsg.notePdfDirPositionKey: noteRouteMsg.notePdfDirPosition, - NoteRouteMsg.noteBaseConfigFilePositionKey: - noteRouteMsg.noteBaseConfigFilePosition, - }, - BaseNote.noteTitleKey: noteTitle, - BaseNote.noteDescriptionKey: noteDescription, - BaseNote.noteCreateTimeKey: noteCreateTime?.toString(), - BaseNote.noteUpdateTimeKey: noteUpdateTime.toString(), - BaseNote.noteCoverKey: noteCover, - }; - } - - factory BaseNote.fromJson(Map json) { - final readMediaJson = json[ReadMedia.flag]; - final readMediaRsourceJson = readMediaJson[Rsource.flag]; - ReadMedia readMedia = ReadMedia( - rsource: Rsource( - sourceType: - SourceType.values[readMediaRsourceJson[SourceType.flag]], - v: readMediaRsourceJson[Rsource.vkey]), - readMediaType: ReadMediaType.values[readMediaJson[ReadMediaType.flag]]); - - SourceType noteSourceType = SourceType.values[json[SourceType.flag]]; - - final noteRouteMsgJson = json[NoteRouteMsg.flag]; - - NoteRouteMsg noteRouteMsg = NoteRouteMsg( - noteFilePosition: noteRouteMsgJson[NoteRouteMsg.noteFilePositionKey], - noteProjectPosition: - noteRouteMsgJson[NoteRouteMsg.noteProjectPositionKey], - noteResourceDirPosition: - noteRouteMsgJson[NoteRouteMsg.noteResourceDirPositionKey], - noteConfigDirPosition: - noteRouteMsgJson[NoteRouteMsg.noteConfigDirPositionKey], - noteImgDirPosition: noteRouteMsgJson[NoteRouteMsg.noteImgDirPositionKey], - noteVideoDirPosition: - noteRouteMsgJson[NoteRouteMsg.noteVideoDirPositionKey], - notePdfDirPosition: noteRouteMsgJson[NoteRouteMsg.notePdfDirPositionKey], - noteBaseConfigFilePosition: - noteRouteMsgJson[NoteRouteMsg.noteBaseConfigFilePositionKey], - ); - - DateTime? noteCreateTime; - - DateTime noteUpdateTime = - DateTime.tryParse(json[BaseNote.noteUpdateTimeKey]) ?? DateTime.now(); - - return BaseNote( - readMedia: readMedia, - noteSourceType: noteSourceType, - noteRouteMsg: noteRouteMsg, - noteTitle: json[BaseNote.noteTitleKey], - noteDescription: json[BaseNote.noteDescriptionKey], - noteCreateTime: noteCreateTime, - noteUpdateTime: noteUpdateTime, - noteCover: json[BaseNote.noteCoverKey]); - } - - R callSwitch({ - required F txtCallback, - required F videoCallback, - required F pdfCallback, - required F audioCallback, - required F markdownCallback, - }) { - switch (readMedia.readMediaType) { - case ReadMediaType.txt: - return txtCallback(this); - case ReadMediaType.video: - return videoCallback(this); - case ReadMediaType.pdf: - return pdfCallback(this); - case ReadMediaType.audio: - return audioCallback(this); - case ReadMediaType.markdown: - return markdownCallback(this); - } - } -} diff --git a/lib/models/note/impl/http_note.dart b/lib/models/note/impl/http_note.dart deleted file mode 100644 index 5ce285b..0000000 --- a/lib/models/note/impl/http_note.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'package:note/models/note/base_note.dart'; -import 'package:note/models/note/impl/note_http_msg.dart'; -import 'package:note/models/r_source.dart'; - -class HttpNote extends BaseNote { - HttpNote({ - required super.readMedia, - required super.noteTitle, - required super.noteDescription, - required super.noteUpdateTime, - super.noteCreateTime, - required this.noteFileUrl, - }) : super( - noteSourceType: SourceType.HTTP, - noteRouteMsg: NoteHttpMsg(noteFileUrl: noteFileUrl)); - String noteFileUrl; -} diff --git a/lib/models/note/impl/local_note.dart b/lib/models/note/impl/local_note.dart deleted file mode 100644 index 024b7ec..0000000 --- a/lib/models/note/impl/local_note.dart +++ /dev/null @@ -1,18 +0,0 @@ -import 'package:note/models/note/base_note.dart'; -import 'package:note/models/note/impl/note_path_msg.dart'; -import 'package:note/models/r_source.dart'; - -class LocalNote extends BaseNote { - LocalNote({ - required super.readMedia, - required super.noteTitle, - required super.noteDescription, - required super.noteUpdateTime, - super.noteCreateTime, - required this.noteFilePath, - }) : super( - noteSourceType: SourceType.LOCAL, - noteRouteMsg: NotePathMsg(noteFilePath: noteFilePath), - ); - String noteFilePath; -} diff --git a/lib/models/note/impl/note_http_msg.dart b/lib/models/note/impl/note_http_msg.dart deleted file mode 100644 index 2595089..0000000 --- a/lib/models/note/impl/note_http_msg.dart +++ /dev/null @@ -1,39 +0,0 @@ -import 'package:note/common/utils/common_tool.dart'; -import 'package:note/models/note/note_route_msg.dart'; -import 'package:path/path.dart'; - -///笔记url路径信息 -class NoteHttpMsg extends NoteRouteMsg { - NoteHttpMsg({ - required this.noteFileUrl, - super.noteProjectPosition, - super.noteConfigDirPosition, - super.noteImgDirPosition, - super.notePdfDirPosition, - super.noteResourceDirPosition, - super.noteVideoDirPosition, - }) : super(noteFilePosition: noteFileUrl) { - noteProjectPosition ??= CommonTool.getParentUrl(noteFileUrl); - if (noteProjectPosition == null) { - return; - } - - noteResourceDirPosition ??= - join(noteProjectPosition!, NotePositionConstant.dirResource.v); - - noteConfigDirPosition ??= - join(noteResourceDirPosition!, NotePositionConstant.dirConfig.v); - - noteImgDirPosition ??= - join(noteResourceDirPosition!, NotePositionConstant.dirImg.v); - - noteVideoDirPosition ??= - join(noteResourceDirPosition!, NotePositionConstant.dirVideo.v); - - notePdfDirPosition ??= - join(noteResourceDirPosition!, NotePositionConstant.dirPdf.v); - } - - ///笔记文件的路径 - String noteFileUrl; -} diff --git a/lib/models/note/impl/note_path_msg.dart b/lib/models/note/impl/note_path_msg.dart deleted file mode 100644 index 4a12bf5..0000000 --- a/lib/models/note/impl/note_path_msg.dart +++ /dev/null @@ -1,42 +0,0 @@ -import 'package:note/common/utils/file_tool.dart'; -import 'package:note/models/note/note_route_msg.dart'; -import 'package:path/path.dart'; - -///笔记路径信息 -class NotePathMsg extends NoteRouteMsg { - NotePathMsg({ - required this.noteFilePath, - super.noteProjectPosition, - super.noteConfigDirPosition, - super.noteImgDirPosition, - super.notePdfDirPosition, - super.noteResourceDirPosition, - super.noteVideoDirPosition, - super.noteBaseConfigFilePosition, - }) : super(noteFilePosition: noteFilePath) { - noteProjectPosition ??= FileTool.getParentPath(noteFilePath); - if (noteProjectPosition == null) { - return; - } - noteResourceDirPosition ??= - join(noteProjectPosition!, NotePositionConstant.dirResource.v); - - noteConfigDirPosition ??= - join(noteResourceDirPosition!, NotePositionConstant.dirConfig.v); - - noteImgDirPosition ??= - join(noteResourceDirPosition!, NotePositionConstant.dirImg.v); - - noteVideoDirPosition ??= - join(noteResourceDirPosition!, NotePositionConstant.dirVideo.v); - - notePdfDirPosition ??= - join(noteResourceDirPosition!, NotePositionConstant.dirPdf.v); - - noteBaseConfigFilePosition ??= - join(noteConfigDirPosition!, NotePositionConstant.fileBaseConfig.v); - } - - ///笔记文件的路径 - String noteFilePath; -} diff --git a/lib/models/note/impl/note_ws_msg.dart b/lib/models/note/impl/note_ws_msg.dart deleted file mode 100644 index cdcca75..0000000 --- a/lib/models/note/impl/note_ws_msg.dart +++ /dev/null @@ -1,39 +0,0 @@ -import 'package:note/common/utils/common_tool.dart'; -import 'package:note/models/note/note_route_msg.dart'; -import 'package:path/path.dart'; - -///笔记url路径信息 -class NoteWsMsg extends NoteRouteMsg { - NoteWsMsg({ - required this.noteFileUrl, - super.noteProjectPosition, - super.noteConfigDirPosition, - super.noteImgDirPosition, - super.notePdfDirPosition, - super.noteResourceDirPosition, - super.noteVideoDirPosition, - }) : super(noteFilePosition: noteFileUrl) { - noteProjectPosition ??= CommonTool.getParentUrl(noteFileUrl); - if (noteProjectPosition == null) { - return; - } - - noteResourceDirPosition ??= - join(noteProjectPosition!, NotePositionConstant.dirResource.v); - - noteConfigDirPosition ??= - join(noteResourceDirPosition!, NotePositionConstant.dirConfig.v); - - noteImgDirPosition ??= - join(noteResourceDirPosition!, NotePositionConstant.dirImg.v); - - noteVideoDirPosition ??= - join(noteResourceDirPosition!, NotePositionConstant.dirVideo.v); - - notePdfDirPosition ??= - join(noteResourceDirPosition!, NotePositionConstant.dirPdf.v); - } - - ///笔记文件的路径 - String noteFileUrl; -} diff --git a/lib/models/note/impl/web_socket_note.dart b/lib/models/note/impl/web_socket_note.dart deleted file mode 100644 index dc12dd5..0000000 --- a/lib/models/note/impl/web_socket_note.dart +++ /dev/null @@ -1,18 +0,0 @@ -import 'package:note/models/note/base_note.dart'; -import 'package:note/models/note/impl/note_http_msg.dart'; -import 'package:note/models/note/impl/note_ws_msg.dart'; -import 'package:note/models/r_source.dart'; - -class WebSocketNote extends BaseNote { - WebSocketNote({ - required super.readMedia, - required super.noteTitle, - required super.noteDescription, - required super.noteUpdateTime, - super.noteCreateTime, - required this.noteFileUrl, - }) : super( - noteSourceType: SourceType.WEB_SOCKET, - noteRouteMsg: NoteWsMsg(noteFileUrl: noteFileUrl)); - String noteFileUrl; -} diff --git a/lib/models/note/note_route_msg.dart b/lib/models/note/note_route_msg.dart deleted file mode 100644 index 7947e31..0000000 --- a/lib/models/note/note_route_msg.dart +++ /dev/null @@ -1,58 +0,0 @@ -class tt { - String vv = "1"; -} - -///笔记路由信息 -class NoteRouteMsg { - NoteRouteMsg({ - required this.noteFilePosition, - this.noteProjectPosition, - this.noteResourceDirPosition, - this.noteConfigDirPosition, - this.noteImgDirPosition, - this.noteVideoDirPosition, - this.notePdfDirPosition, - this.noteBaseConfigFilePosition, - }); - - static const String flag = "NoteRouteMsg"; - - ///笔记文件的路径 - static const String noteFilePositionKey = "noteFilePosition"; - String noteFilePosition; - - ///笔记父文件夹路径 - static const String noteProjectPositionKey = "noteProjectPosition"; - String? noteProjectPosition; - static const String noteResourceDirPositionKey = "noteResourceDirPosition"; - String? noteResourceDirPosition; - static const String noteConfigDirPositionKey = "noteConfigDirPosition"; - String? noteConfigDirPosition; - static const String noteImgDirPositionKey = "noteImgDirPosition"; - String? noteImgDirPosition; - static const String noteVideoDirPositionKey = "noteVideoDirPosition"; - String? noteVideoDirPosition; - static const String notePdfDirPositionKey = "notePdfDirPosition"; - String? notePdfDirPosition; - static const String noteBaseConfigFilePositionKey = - "noteBaseConfigFilePosition"; - String? noteBaseConfigFilePosition; -} - -///笔记路径常量 -enum NotePositionConstant { - dirImg(v: "img"), - dirConfig(v: "config"), - dirVideo(v: "video"), - dirPdf(v: "pdf"), - dirResource(v: "resource"), - suffixHL(v: ".hl"), - fileBaseConfig(v: "BaseConfig.json"); - - const NotePositionConstant({required this.v}); - - static const String flag = "NotePositionConstant"; - - ///value - final String v; -} diff --git a/lib/models/note_model/base_note.dart b/lib/models/note_model/base_note.dart new file mode 100644 index 0000000..34eca89 --- /dev/null +++ b/lib/models/note_model/base_note.dart @@ -0,0 +1,181 @@ +import 'package:flutter/material.dart'; +import 'package:note/common/utils/common_tool.dart'; + +/** + * --noteProjectName1 + * --data + * --noteProjectName1.cfg + * --resource + * --img(存放图片、截图) + * --video(存放视频) + * --audio(音频) + * --pdf(存放pdf) + * --markdown + * --txt + * --doc + */ + +class BaseNote { + ///标识用于json传输转换 + static const String flag = "BaseNote"; + + /// 笔记依赖媒体来源: 本地、http、websocket + SourceType noteDependMediaSourceType; + /// 笔记依赖媒体类型:video、audio、pdf、markdown、txt、doc + MediaType noteDependMediaType; + /// 笔记依赖媒体的位置 + String noteDependMediaPos; + + + /// 笔记来源: 本地、http、websocket + SourceType noteSourceType; + /// 配置位置, + String noteCfgPos; + /// 项目位置,由noteCfgPos确定 + late String noteProjectPos; + /// 笔记内容数据位置,由noteCfgPos确定 + late String noteDataPos; + /// 资源位置,由noteCfgPos确定 + late String noteResourcePos; + /// 图片资源位置,由noteResourcePos确定 + late String noteImgPos; + /// 视频资源位置,由noteResourcePos确定 + late String noteVideoPos; + /// 音频资源位置,由noteResourcePos确定 + late String noteAudioPos; + /// pdf资源位置,由noteResourcePos确定 + late String notePdfPos; + /// markdown资源位置,由noteResourcePos确定 + late String noteMarkdownPos; + /// txt资源位置,由noteResourcePos确定 + late String noteTxtPos; + + + /// 笔记标题 + String noteTitle; + /// 笔记描述 + String noteDescription; + /// 笔记创建时间 + DateTime? noteCreateTime; + /// 笔记更新时间 + DateTime? noteUpdateTime; + /// 笔记封面 + String? noteCover; + + BaseNote({ + this.noteDependMediaSourceType = SourceType.LOCAL, + this.noteDependMediaType = MediaType.VIDEO, + required this.noteDependMediaPos, + this.noteSourceType = SourceType.LOCAL, + required this.noteCfgPos, + required this.noteTitle, + this.noteDescription = "", + this.noteCreateTime, + this.noteUpdateTime, + this.noteCover, + }){ + noteUpdateTime = DateTime.now(); + noteProjectPos = CommonTool.getParentPos(noteCfgPos); + noteDataPos = "$noteProjectPos/data"; + noteResourcePos = "$noteProjectPos/resource"; + noteImgPos = "$noteResourcePos/img"; + noteVideoPos = "$noteResourcePos/video"; + noteAudioPos = "$noteResourcePos/audio"; + notePdfPos = "$noteResourcePos/pdf"; + noteMarkdownPos = "$noteResourcePos/markdown"; + noteTxtPos = "$noteResourcePos/txt"; + + + } + + + Map toJson() { + return { + 'noteDependMediaSourceType': noteDependMediaSourceType.toString().split('.').last, + 'noteDependMediaType': noteDependMediaType.toString().split('.').last, + 'noteDependMediaPos': noteDependMediaPos, + 'noteSourceType': noteSourceType.toString().split('.').last, + 'noteCfgPos': noteCfgPos, + 'noteTitle': noteTitle, + 'noteDescription': noteDescription, + 'noteCreateTime': noteCreateTime?.toIso8601String(), + 'noteUpdateTime': noteUpdateTime?.toIso8601String(), + 'noteCover': noteCover, + 'noteProjectPos': noteProjectPos, + 'noteDataPos': noteDataPos, + 'noteResourcePos': noteResourcePos, + 'noteImgPos': noteImgPos, + 'noteVideoPos': noteVideoPos, + 'noteAudioPos': noteAudioPos, + 'notePdfPos': notePdfPos, + 'noteMarkdownPos': noteMarkdownPos, + 'noteTxtPos': noteTxtPos, + }; + } + + static BaseNote fromJson(Map json) { + return BaseNote( + noteDependMediaSourceType: SourceType.parseSourceType(json['noteDependMediaSourceType']), + noteDependMediaType: MediaType.parseMediaType(json['noteDependMediaType']), + noteDependMediaPos: json['noteDependMediaPos'], + noteSourceType: SourceType.parseSourceType(json['noteSourceType']), + noteCfgPos: json['noteCfgPos'], + noteTitle: json['noteTitle'], + noteDescription: json['noteDescription'], + noteCreateTime: json['noteCreateTime'] != null ? DateTime.parse(json['noteCreateTime']) : null, + noteUpdateTime: DateTime.parse(json['noteUpdateTime']), + noteCover: json['noteCover'], + ); + } + + + + +} +///媒体类型 +enum MediaType { + VIDEO, + AUDIO, + PDF, + MARKDOWN, + TXT; + + static MediaType parseMediaType(String mediaTypeString) { + switch (mediaTypeString) { + case 'VIDEO': + return MediaType.VIDEO; + case 'AUDIO': + return MediaType.AUDIO; + case 'PDF': + return MediaType.PDF; + case 'MARKDOWN': + return MediaType.MARKDOWN; + case 'TXT': + return MediaType.TXT; + default: + throw ArgumentError('Invalid media type: $mediaTypeString'); + } + } +} +///来源类型 +enum SourceType { + ///本地 + LOCAL, + ///包括http和https + HTTP, + WEBSOCKET; + + static SourceType parseSourceType(String sourceTypeString) { + switch (sourceTypeString) { + case 'LOCAL': + return SourceType.LOCAL; + case 'HTTP': + return SourceType.HTTP; + case 'WEBSOCKET': + return SourceType.WEBSOCKET; + default: + throw ArgumentError('Invalid source type: $sourceTypeString'); + } + } + +} \ No newline at end of file diff --git a/lib/models/r_source.dart b/lib/models/r_source.dart deleted file mode 100644 index 2e87b04..0000000 --- a/lib/models/r_source.dart +++ /dev/null @@ -1,49 +0,0 @@ -///资源类型 -enum SourceType { - ///本地 - LOCAL, - - ///包括http和https - HTTP, - WEB_SOCKET; - - static const String flag = "SourceType"; -} - -typedef bool BoolFuncRsource(Rsource rsource); -typedef int IntFuncRsource(Rsource rsource); -typedef String StrFuncRsource(Rsource rsource); -typedef Object ObjFuncRsource(Rsource rsource); -typedef dynamic DynamicFuncRsource(Rsource rsource); - -///资源为本地还是远程的封装类 -///[T]为值的类型 -class Rsource { - Rsource({required this.sourceType, required this.v}); - - static const String flag = "Rsource"; - - ///资源类型:本地、网络 - SourceType sourceType; - - ///值 - static const String vkey = "v"; - T v; - - ///[R]返回值 - ///[F]回调方法类型,且其返回值必须为 [R] - ///[T]值的类型 - R callSwitch rsource)>( - {required F localCallback, - required F httpCallback, - required F webSocketCallback}) { - switch (sourceType) { - case SourceType.LOCAL: - return localCallback(this); - case SourceType.HTTP: - return httpCallback(this); - case SourceType.WEB_SOCKET: - return webSocketCallback(this); - } - } -} diff --git a/lib/models/read_media.dart b/lib/models/read_media.dart deleted file mode 100644 index ca0424f..0000000 --- a/lib/models/read_media.dart +++ /dev/null @@ -1,25 +0,0 @@ -import 'package:note/models/r_source.dart'; - -///阅读媒介 -class ReadMedia { - ReadMedia({required this.rsource, required this.readMediaType}); - - static const String flag = "ReadMedia"; - - ///是否本地、网络 - Rsource rsource; - - ///阅读媒介的类型 - ReadMediaType readMediaType; -} - -///笔记类型 -enum ReadMediaType { - txt, - video, - pdf, - audio, - markdown; - - static const String flag = "ReadMediaType"; -} diff --git a/lib/pages/home/controller.dart b/lib/pages/home/controller.dart index 5d86e96..ac10c3a 100644 --- a/lib/pages/home/controller.dart +++ b/lib/pages/home/controller.dart @@ -1,12 +1,15 @@ -import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; +import 'dart:io'; + +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; import 'package:get/get.dart'; -import 'package:nb_utils/nb_utils.dart'; +import 'package:note/common/store/global_store.dart'; import 'package:note/common/utils/file_tool.dart'; -import 'package:note/models/note/base_note.dart'; -import 'package:note/models/note/impl/local_note.dart'; -import 'package:note/models/note/note_route_msg.dart'; -import 'package:note/models/r_source.dart'; -import 'package:note/models/read_media.dart'; +import 'package:note/dao/data_manager.dart'; + +import 'package:note/models/note_model/base_note.dart'; +import 'package:note/routes/app_pages.dart'; + import 'package:path/path.dart'; import 'index.dart'; @@ -14,130 +17,118 @@ import 'index.dart'; class HomeController extends GetxController { final state = HomeState(); - late final noteDataList = state.noteDataList; - - static const String NOTE_LIST_PREFIX = "NoteList-"; + static const KEY_NOTE_CFG_POS_LIST = GlobalStore.DATASTORE_KEY_NOTE_CFG_POS_LIST; ///添加一个笔记到列表中 - Future addToNodeList(BaseNote baseNote) async { - String targetKey = HomeController.NOTE_LIST_PREFIX + - baseNote.noteRouteMsg.noteFilePosition; - - ///判断SP中是否存在key - bool exiteKey = sharedPreferences.containsKey(targetKey); - if (exiteKey) { + Future addNote(BaseNote baseNote) async { + ///持久化笔记到SP中,这里会更新UI + bool result=await DataManager.addNoteCfgPosByNote(state.noteDataList, baseNote); + if (result == false){ return false; } - - ///持久化笔记到SP中 - bool saveResult = await setValue(targetKey, baseNote.toJson()); - - if (!saveResult) { - return false; - } - - ///更新UI - noteDataList.add(baseNote); return true; } ///删除一个笔记从列表中 - Future delToNodeList(BaseNote baseNote) async { - String targetKey = HomeController.NOTE_LIST_PREFIX + - baseNote.noteRouteMsg.noteFilePosition; - - ///判断SP中是否存在key - bool exiteKey = sharedPreferences.containsKey(targetKey); - if (!exiteKey) { + Future removeNote(BaseNote baseNote) async { + ///删除本地文件 + bool result = FileTool.deleteAll(baseNote.noteProjectPos); + if (result == false){ return false; } - - ///删除本地文件 - FileTool.deleteFiles(baseNote.noteRouteMsg.noteProjectPosition!); - ///删除SP中的记录 - var resu = await removeKey(targetKey); - - ///更新UI - noteDataList.remove(baseNote); - + result = await DataManager.removeNoteCfgPosByNote(state.noteDataList, baseNote); + if (result == false){ + return false; + } return true; } - ///获取本地的笔记列表 - List getLocalNodeDataList() { - List noteKeyList = - getMatchingSharedPrefKeys(HomeController.NOTE_LIST_PREFIX); - noteDataList.clear(); - noteKeyList.forEach((noteKey) { - var noteJson = getJSONAsync(noteKey); - var baseNote = BaseNote.fromJson(noteJson); - print(baseNote); - noteDataList.add(baseNote); - }); - return noteDataList; + ///获取笔记列表 + Future> getNoteDataList() async { + state.noteDataList.clear(); + state.noteDataList.addAll(await DataManager.getNoteList()); + LogUtil.e(state.noteDataList); + return state.noteDataList; } ///创建笔记项目 ///[noteProjectPosition]笔记项目的位置 - ///[noteProjectName]笔记项目的名称 + ///[noteTitle]笔记项目的名称 ///[readSource]阅读媒介 - BaseNote? createNoteProject( - String noteProjectName, - Rsource noteProjectPosition, - ReadMedia readMedia, - ) { + Future createNoteProject( + String noteTitle, + String noteProjectPos, + String noteDependMediaPos, + ) async { + ///实例化笔记对象 + BaseNote baseNote= BaseNote(noteDependMediaPos: noteDependMediaPos, + noteCfgPos: noteProjectPos+"/$noteTitle.cfg", + noteTitle: noteTitle); + + //判断笔记内容文件是否存在 + if (FileTool.fileExists(baseNote.noteDataPos)) { + Get.snackbar("创建错误", "当前目录下已有笔记,无法创建。"); + return; + } + + List resourceClass = [ + baseNote.noteImgPos, + baseNote.noteVideoPos, + baseNote.noteAudioPos, + baseNote.notePdfPos, + baseNote.noteMarkdownPos, + baseNote.noteTxtPos, + ]; + ///创建文件夹 + for (String dir in resourceClass) { + Directory(dir).createSync(recursive: true); + } + ///初始化笔记内容并写入文件(这里应该提供统一的保存接口,saveRes,本地应该实现写入本地文件,网络应该实现请求保存接口) + bool result = await FileTool.writeFile(baseNote.noteDataPos, '[{"insert":""}]'); + if (result == false){ + return; + } + + ///保存配置文件(这里应该提供统一的保存接口,saveRes,本地应该实现写入本地文件,网络应该实现请求保存接口) + result = await FileTool.writeMapToFile(baseNote.noteCfgPos, baseNote.toJson()); + if (result == false){ + return; + } + ///在记录中添加笔记 + result = await addNote(baseNote); + + if(result==false){ + return; + } + + Get.toNamed(AppRoutes.VideoNote, arguments: { + BaseNote.flag: baseNote, + }); + + } + ///打开笔记项目 + Future openNoteProject( + String noteCfgPos, + ) async { late BaseNote baseNote; - noteProjectPosition.callSwitch)>( - localCallback: (rsource) { - ///项目位置在本地 - - String noteFileName = noteProjectName + NotePositionConstant.suffixHL.v; - String noteFilePath = - join(noteProjectPosition.v, noteProjectName, noteFileName); - - ///实例化路径信息 - baseNote = LocalNote( - readMedia: readMedia, - noteTitle: noteProjectName, - noteDescription: '', - noteUpdateTime: DateTime.now(), - noteFilePath: noteFilePath); - - readMedia.rsource.callSwitch)>( - localCallback: (rsource) async { - ///阅读媒介在本地 - ///获取媒体源 - String readMediaPath = readMedia.rsource.v; - - var result = - await FileTool.createNoteProjectFile(baseNote, readMediaPath); - if (result == null) { - SmartDialog.showToast("创建笔记项目失败"); - return; - } - }, - httpCallback: (rsource) {}, - webSocketCallback: (rsource) {}); - - return true; - }, - httpCallback: (rsource) { - ///未实现 - return false; - }, - webSocketCallback: (rsource) { - return false; - }, - ); - return baseNote; + var noteJson = await FileTool.readJsonFile(noteCfgPos); + if (noteJson!=null){ + baseNote = BaseNote.fromJson(noteJson); + print(baseNote); + } + + Get.toNamed(AppRoutes.VideoNote, arguments: { + BaseNote.flag: baseNote, + }); } /// 在 widget 内存中分配后立即调用。 @override void onInit() { super.onInit(); + getNoteDataList(); } /// 在 onInit() 之后调用 1 帧。这是进入的理想场所 diff --git a/lib/pages/home/state.dart b/lib/pages/home/state.dart index 1d39981..d48d847 100644 --- a/lib/pages/home/state.dart +++ b/lib/pages/home/state.dart @@ -1,5 +1,6 @@ import 'package:get/get.dart'; -import 'package:note/models/note/base_note.dart'; +import 'package:note/models/note_model/base_note.dart'; + class HomeState { //创建视频笔记类型 diff --git a/lib/pages/home/widgets/dialogs/create_note_video_dialog.dart b/lib/pages/home/widgets/dialogs/create_note_video_dialog.dart index 3dc43f0..ca41256 100644 --- a/lib/pages/home/widgets/dialogs/create_note_video_dialog.dart +++ b/lib/pages/home/widgets/dialogs/create_note_video_dialog.dart @@ -2,9 +2,8 @@ import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:getwidget/getwidget.dart'; -import 'package:note/models/note/base_note.dart'; -import 'package:note/models/r_source.dart'; -import 'package:note/models/read_media.dart'; +import 'package:note/models/note_model/base_note.dart'; + import 'package:note/routes/app_pages.dart'; import '../../index.dart'; @@ -24,11 +23,11 @@ class CreateNoteVideoDialog extends GetView { String? videoPath; String? videoUrl; - final TextEditingController noteNameEditController = TextEditingController(); - final TextEditingController noteSavePathEditController = + final TextEditingController noteTitleEditCtrl = TextEditingController(); + final TextEditingController noteProjectParentPosEditCtrl = TextEditingController(); - final TextEditingController videoPathEditController = TextEditingController(); - final TextEditingController videoUrlEditController = TextEditingController(); + final TextEditingController noteVideoPosEditCtrl = TextEditingController(); + final TextEditingController noteVideoUrlPosEditCtrl = TextEditingController(); @override Widget build(BuildContext context) { @@ -51,7 +50,7 @@ class CreateNoteVideoDialog extends GetView { Padding( padding: const EdgeInsets.only(bottom: 10), child: GFTextField( - controller: noteNameEditController, + controller: noteTitleEditCtrl, decoration: InputDecoration( border: OutlineInputBorder( borderSide: BorderSide(width: 1, color: Colors.grey), @@ -67,7 +66,7 @@ class CreateNoteVideoDialog extends GetView { children: [ Expanded( child: GFTextField( - controller: noteSavePathEditController, + controller: noteProjectParentPosEditCtrl, decoration: InputDecoration( border: OutlineInputBorder( borderSide: @@ -85,7 +84,7 @@ class CreateNoteVideoDialog extends GetView { await FilePicker.platform.getDirectoryPath(); if (selectedDirectory != null) { - noteSavePathEditController.text = selectedDirectory; + noteProjectParentPosEditCtrl.text = selectedDirectory; } }, text: "选择", @@ -116,7 +115,7 @@ class CreateNoteVideoDialog extends GetView { }, children: [ GFTextField( - controller: videoPathEditController, + controller: noteVideoPosEditCtrl, decoration: InputDecoration( border: OutlineInputBorder( borderSide: BorderSide(width: 1, color: Colors.grey), @@ -137,7 +136,7 @@ class CreateNoteVideoDialog extends GetView { if (result != null) { PlatformFile file = result.files.first; print('文件路径: ${file.path}'); - videoPathEditController.text = file.path ?? ""; + noteVideoPosEditCtrl.text = file.path ?? ""; } else { // 用户取消了选择文件操作 } @@ -159,7 +158,7 @@ class CreateNoteVideoDialog extends GetView { }, children: [ GFTextField( - controller: videoUrlEditController, + controller: noteVideoUrlPosEditCtrl, decoration: InputDecoration( border: OutlineInputBorder( borderSide: BorderSide(width: 1, color: Colors.grey), @@ -175,34 +174,19 @@ class CreateNoteVideoDialog extends GetView { ), actions: [ TextButton( + child: Text('创建'), onPressed: () async { Navigator.of(context).pop(); - //创建笔记文件 - String noteSavePath = noteSavePathEditController.text; - - String noteProjectName = noteNameEditController.text; - String videoSource = videoSourceType == VideoSourceType.LOCAL - ? videoPathEditController.text - : videoUrlEditController.text; + String projectParentPos = noteProjectParentPosEditCtrl.text; + String noteTitle = noteTitleEditCtrl.text; + String noteVideoPos = noteVideoPosEditCtrl.text; + String projectPos = "$projectParentPos/$noteTitle"; - BaseNote? baseNote = await controller.createNoteProject( - noteProjectName, - Rsource(sourceType: SourceType.LOCAL, v: noteSavePath), - ReadMedia( - rsource: Rsource( - sourceType: SourceType.LOCAL, v: videoSource), - readMediaType: ReadMediaType.video)); + //创建笔记项目 + controller.createNoteProject(noteTitle,projectPos,noteVideoPos); - if (baseNote == null) { - return; - } - - Get.toNamed(AppRoutes.VideoNote, arguments: { - BaseNote.flag: baseNote, - }); }, - child: Text('创建'), ), TextButton( onPressed: () { diff --git a/lib/pages/home/widgets/dialogs/open_note_video_dialog.dart b/lib/pages/home/widgets/dialogs/open_note_video_dialog.dart index 6a8ab83..ad584fd 100644 --- a/lib/pages/home/widgets/dialogs/open_note_video_dialog.dart +++ b/lib/pages/home/widgets/dialogs/open_note_video_dialog.dart @@ -4,10 +4,8 @@ import 'package:get/get.dart'; import 'package:getwidget/getwidget.dart'; import 'package:note/common/utils/file_tool.dart'; import 'package:note/common/utils/platform_tool.dart'; -import 'package:note/models/note/base_note.dart'; -import 'package:note/models/note/impl/local_note.dart'; -import 'package:note/models/r_source.dart'; -import 'package:note/models/read_media.dart'; +import 'package:note/models/note_model/base_note.dart'; + import 'package:note/routes/app_pages.dart'; import '../../index.dart'; @@ -22,7 +20,7 @@ class OpenNoteVideoDialog extends GetView { final localExpansionTileController = ExpansionTileController(); final networkExpansionTileController = ExpansionTileController(); - final TextEditingController noteFilePathEditController = + final TextEditingController noteCfgPosEditCtrl = TextEditingController(); final TextEditingController noteFileUrlEditController = TextEditingController(); @@ -55,7 +53,7 @@ class OpenNoteVideoDialog extends GetView { }, children: [ GFTextField( - controller: noteFilePathEditController, + controller: noteCfgPosEditCtrl, decoration: InputDecoration( border: OutlineInputBorder( borderSide: BorderSide(width: 1, color: Colors.grey), @@ -76,7 +74,7 @@ class OpenNoteVideoDialog extends GetView { if (result != null) { PlatformFile file = result.files.first; print('path: ${file.path}'); - noteFilePathEditController.text = file.path ?? ""; + noteCfgPosEditCtrl.text = file.path ?? ""; } }, other: () async { // 选择本地视频文件 @@ -85,7 +83,7 @@ class OpenNoteVideoDialog extends GetView { if (result != null) { PlatformFile file = result.files.first; print('path: ${file.path}'); - noteFilePathEditController.text = file.path ?? ""; + noteCfgPosEditCtrl.text = file.path ?? ""; } }); }, @@ -122,82 +120,14 @@ class OpenNoteVideoDialog extends GetView { ), actions: [ TextButton( + child: Text('打开'), onPressed: () { Navigator.of(context).pop(); - // String noteFileSource = noteFileSourceType == FileSourceType.LOCAL - // ? noteFilePathEditController.text - // : noteFileUrlEditController.text; - - String noteFilePath = noteFilePathEditController.text; - - BaseNote baseNote; - switch (noteFileSourceType) { - case SourceType.LOCAL: - baseNote = LocalNote( - noteTitle: '', - noteDescription: '', - noteUpdateTime: DateTime.now(), - noteFilePath: noteFilePath, - readMedia: ReadMedia( - rsource: Rsource( - sourceType: SourceType.LOCAL, v: ""), - readMediaType: ReadMediaType.video)); - break; - - case SourceType.HTTP: - baseNote = LocalNote( - noteTitle: '', - noteDescription: '', - noteUpdateTime: DateTime.now(), - noteFilePath: noteFilePath, - readMedia: ReadMedia( - rsource: Rsource( - sourceType: SourceType.LOCAL, v: ""), - readMediaType: ReadMediaType.video)); - break; - case SourceType.WEB_SOCKET: - baseNote = LocalNote( - noteTitle: '', - noteDescription: '', - noteUpdateTime: DateTime.now(), - noteFilePath: noteFilePath, - readMedia: ReadMedia( - rsource: Rsource( - sourceType: SourceType.LOCAL, v: ""), - readMediaType: ReadMediaType.video)); - } + String noteCfgPos = noteCfgPosEditCtrl.text; + controller.openNoteProject(noteCfgPos); - ///读取json - var jsonObj = FileTool.readJson( - baseNote.noteRouteMsg.noteBaseConfigFilePosition!)!; - - ///获取阅读媒介的值 - String mediaSource = jsonObj[ReadMedia.flag + Rsource.flag]; - String mediaValues = jsonObj[ReadMedia.flag]; - - if (mediaSource == SourceType.LOCAL.name) { - baseNote.readMedia = ReadMedia( - rsource: Rsource( - sourceType: SourceType.LOCAL, v: mediaValues), - readMediaType: ReadMediaType.video); - } else if (mediaSource == SourceType.HTTP.name) { - baseNote.readMedia = ReadMedia( - rsource: Rsource( - sourceType: SourceType.HTTP, v: mediaValues), - readMediaType: ReadMediaType.video); - } else if (mediaSource == SourceType.WEB_SOCKET.name) { - baseNote.readMedia = ReadMedia( - rsource: Rsource( - sourceType: SourceType.WEB_SOCKET, v: mediaValues), - readMediaType: ReadMediaType.video); - } - - // - Get.toNamed(AppRoutes.VideoNote, arguments: { - BaseNote.flag: baseNote, - }); }, - child: Text('打开'), + ), TextButton( onPressed: () { diff --git a/lib/pages/home/widgets/home_appbar.dart b/lib/pages/home/widgets/home_appbar.dart index 599ff4c..34ae26e 100644 --- a/lib/pages/home/widgets/home_appbar.dart +++ b/lib/pages/home/widgets/home_appbar.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:getwidget/getwidget.dart'; import 'package:note/pages/main/controller.dart'; - +/// 主页的AppBar class HomeAppbar extends AppBar { @override _HomeAppbarState createState() => _HomeAppbarState(); diff --git a/lib/pages/home/widgets/home_float_btn.dart b/lib/pages/home/widgets/home_float_btn.dart index 1d8998a..2e2c300 100644 --- a/lib/pages/home/widgets/home_float_btn.dart +++ b/lib/pages/home/widgets/home_float_btn.dart @@ -1,9 +1,14 @@ +import 'dart:io'; + import 'package:flutter/material.dart'; import 'package:flutter_speed_dial/flutter_speed_dial.dart'; import 'package:get/get.dart'; +import 'package:note/common/utils/common_tool.dart'; +import 'package:note/common/utils/file_tool.dart'; import 'package:note/pages/home/widgets/dialogs/create_note_video_dialog.dart'; import 'package:note/pages/home/widgets/dialogs/open_note_video_dialog.dart'; +import '../../../models/note_model/base_note.dart'; import '../index.dart'; class HomeFloatBtn extends GetView { @@ -19,7 +24,17 @@ class HomeFloatBtn extends GetView { SpeedDialChild( child: Icon(Icons.picture_as_pdf_outlined), label: '从pdf创建', - onTap: () {}), + onTap: () { + // var note=BaseNote(noteDependMediaPos: 'E:/1.mp4', noteCfgPos: 'E:/桌面/资源/2.cfg', noteTitle: '666', noteUpdateTime: DateTime.now(),); + // print(note.toJson().toString()); + // FileTool.writeJson(note.noteCfgPos,mapContent: note.toJson()); + + + // var st=FileTool.readJson("E:/桌面/资源/2.cfg")!; + // var nott=BaseNote.fromJson(st); + // print(nott.toJson()); + + }), SpeedDialChild( child: Icon(Icons.live_tv), label: '从视频创建', diff --git a/lib/pages/home/widgets/note_list.dart b/lib/pages/home/widgets/note_list.dart index bafc960..6b57b46 100644 --- a/lib/pages/home/widgets/note_list.dart +++ b/lib/pages/home/widgets/note_list.dart @@ -2,38 +2,28 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:getwidget/getwidget.dart'; import 'package:note/common/utils/common_tool.dart'; -import 'package:note/models/note/base_note.dart'; +import 'package:note/models/note_model/base_note.dart'; + import 'package:note/pages/home/controller.dart'; import 'package:note/routes/app_pages.dart'; - +///笔记列表 class NoteList extends GetView { NoteList({Key? key}) : super(key: key); final homeController = Get.find(); late var homeState = homeController.state; - late var noteDataList = homeController.getLocalNodeDataList(); + late var noteDataList = homeState.noteDataList; @override Widget build(BuildContext context) { - // controller.state.noteDataList; - // var txtLocalNote = LocalNote( - // readMedia: ReadMedia( - // rsource: Rsource(sourceType: SourceType.LOCAL, v: ""), - // readMediaType: ReadMediaType.txt), - // noteFilePath: "", - // noteTitle: 'txtLocalNote', - // noteDescription: 'txtLocalNote', - // noteUpdateTime: DateTime.now()); - // List noteDataList = [ - // txtLocalNote, - // ]; + return Obx(() => ListView.builder( - itemCount: noteDataList.length, + itemCount:noteDataList.length, itemBuilder: (context, index) { final noteDataItem = noteDataList[index]; final formattedTime = - CommonTool.getFormattedTime(noteDataItem.noteUpdateTime); + CommonTool.getFormattedTime(noteDataItem.noteUpdateTime!); return GestureDetector( onTap: () { @@ -52,9 +42,8 @@ class NoteList extends GetView { TextButton( onPressed: () async { Navigator.pop(context); - ///删除本地文件 - homeController.delToNodeList(noteDataList[index]); + homeController.removeNote(noteDataList[index]); }, child: Text('确定'), ), diff --git a/lib/pages/my/view.dart b/lib/pages/my/view.dart index 74ab5b1..703f610 100644 --- a/lib/pages/my/view.dart +++ b/lib/pages/my/view.dart @@ -3,13 +3,9 @@ import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:getwidget/getwidget.dart'; import 'package:nb_utils/nb_utils.dart'; -import 'package:note/middlewares/shelf/service/shelf_service.dart'; import 'package:note/middlewares/websocket/client/socket_client.dart'; import 'package:note/middlewares/websocket/service/socket_service.dart'; -import 'package:note/models/note/base_note.dart'; -import 'package:note/models/note/impl/local_note.dart'; -import 'package:note/models/r_source.dart'; -import 'package:note/models/read_media.dart'; + import 'index.dart'; @@ -23,8 +19,6 @@ class MyPage extends GetView { GFButton( text: "开启shelf服务", onPressed: () async { - var service = ShelfService(); - service.run(); }), GFButton( text: "开启socket服务", @@ -48,22 +42,22 @@ class MyPage extends GetView { GFButton( text: "保存", onPressed: () async { - BaseNote baseNote = LocalNote( - readMedia: ReadMedia( - rsource: - Rsource(sourceType: SourceType.LOCAL, v: ""), - readMediaType: ReadMediaType.video), - noteTitle: "标题", - noteDescription: '描述', - noteUpdateTime: DateTime.now(), - noteFilePath: "路径"); - - await setValue("key", [ - // baseNote.noteType, - baseNote.noteTitle, - baseNote.noteUpdateTime.toString(), - baseNote.noteRouteMsg.noteFilePosition - ]); + // BaseNote baseNote = LocalNote( + // readMedia: ReadMedia( + // rsource: + // Rsource(sourceType: SourceType.LOCAL, v: ""), + // readMediaType: ReadMediaType.video), + // noteTitle: "标题", + // noteDescription: '描述', + // noteUpdateTime: DateTime.now(), + // noteFilePath: "路径"); + // + // await setValue("key", [ + // // baseNote.noteType, + // baseNote.noteTitle, + // baseNote.noteUpdateTime.toString(), + // baseNote.noteRouteMsg.noteFilePosition + // ]); }), GFButton( text: "读取", diff --git a/lib/pages/videonote/controller/quill_text_controller.dart b/lib/pages/videonote/controller/quill_text_controller.dart index 21ae500..fce5d9f 100644 --- a/lib/pages/videonote/controller/quill_text_controller.dart +++ b/lib/pages/videonote/controller/quill_text_controller.dart @@ -3,6 +3,7 @@ import 'dart:convert'; import 'dart:io'; import 'dart:ui'; +import 'package:common_utils/common_utils.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_quill/flutter_quill.dart'; @@ -13,16 +14,17 @@ import 'package:get/get.dart'; import 'package:nb_utils/nb_utils.dart'; import 'package:note/common/utils/common_tool.dart'; import 'package:note/common/utils/file_tool.dart'; -import 'package:note/models/note/base_note.dart'; -import 'package:note/models/note/impl/local_note.dart'; -import 'package:note/models/r_source.dart'; -import 'package:note/models/read_media.dart'; +import 'package:note/dao/data_manager.dart'; + +import 'package:note/models/note_model/base_note.dart'; + import 'package:note/pages/home/controller.dart'; import 'package:note/pages/videonote/controller/multi_split_controller.dart'; import 'package:note/pages/videonote/controller/video_player_controller.dart'; import 'package:note/pages/videonote/widgets/dialogs/insert_image_dialog.dart'; import 'package:note/pages/videonote/widgets/link_blockembed.dart'; - +import 'package:note/pages/videonote/widgets/my_quill_toolbar.dart'; +///选择类型 enum _SelectionType { none, word, @@ -32,49 +34,62 @@ enum _SelectionType { ///状态 class QuillTextState { /// 笔记 - final _baseNote = Rx(LocalNote( - readMedia: ReadMedia( - rsource: Rsource(sourceType: SourceType.LOCAL, v: ""), - readMediaType: ReadMediaType.video), - noteFilePath: "", - noteTitle: 'videoLocalNote', - noteDescription: 'videoLocalNote', - noteUpdateTime: DateTime.now())); - - set baseNote(value) => _baseNote.value = value; - - BaseNote get baseNote => _baseNote.value; + final _baseNote = BaseNote(noteDependMediaPos: '/root/baseNote/1.mp4', noteCfgPos: '/root/baseNote/1.cfg', noteTitle: '').obs; + + // set baseNote(value) => _baseNote.value = value; + // + // BaseNote get baseNote => _baseNote.value; + + setBaseNote(value){ + _baseNote.value = value; + } + BaseNote getBaseNote(){ + return _baseNote.value; + } + Rx getBaseNoteRx(){ + return _baseNote; + } + + ///是否显示更多toolbar按钮 + final _showMoreToolbarBtn = DataManager.getShowMoreToolbarBtn().obs; + + set showMoreToolbarBtn(value) => _showMoreToolbarBtn.value = value; + + bool get showMoreToolbarBtn => _showMoreToolbarBtn.value; } ///富文本控制器 class QuillTextController extends GetxController { - ///空内容 - // static const String EMPTY_DOCUMENT = '[{"insert":" "}]'; final state = QuillTextState(); + final videoPlayerController = Get.find(); - late final noteRouteMsg = state.baseNote.noteRouteMsg; + final _editorFocusNode = FocusNode(); + //创建富文本控制器 + late QuillController quillController = QuillController.basic(); + ///工具栏 + late MyQuillToolbar quillToolbar = MyQuillToolbar(quillController: quillController, focusNode: _editorFocusNode); //创建富文本编辑器 late final QuillEditor quillEditor = buildQuillEditor(); - //创建富文本控制器 - late QuillController quillController = loadNoteFileData(); - - final FocusNode _focusNode = FocusNode(); - - Timer? _selectAllTimer; - _SelectionType _selectionType = _SelectionType.none; - //获取笔记 BaseNote? getBaseNote() { Map? arguments = getArguments(); if (arguments == null) { return null; } - BaseNote baseNote = arguments[BaseNote.flag] as BaseNote; + BaseNote baseNote; + try{ + baseNote = arguments[BaseNote.flag] as BaseNote; + }catch(e){ + LogUtil.e("无法转换为BaseNote"); + return null; + } + + state.setBaseNote(baseNote); return baseNote; } @@ -89,72 +104,38 @@ class QuillTextController extends GetxController { } /// 加载笔记数据 - QuillController loadNoteFileData({BaseNote? baseNote}) { - baseNote = baseNote ?? getBaseNote(); - - if (baseNote == null) { - quillController = QuillController.basic(); - return quillController; - } - state.baseNote = baseNote; - - final homeController = Get.find(); - - ///持久化笔记到SP中 - homeController.addToNodeList(baseNote); - - print("获取持久化的note"); - - print(getStringAsync(HomeController.NOTE_LIST_PREFIX + - baseNote.noteRouteMsg.noteFilePosition)); + Document? loadNoteDataFile(String filePath){ + File noteDataFile = File(filePath); - final noteFile = File(baseNote.noteRouteMsg.noteFilePosition); try { - var contents = noteFile.readAsStringSync(); + var contents = noteDataFile.readAsStringSync(); var json = jsonDecode(contents); - final doc = Document.fromJson(json); - print("读取到的hl源文件为:$contents"); - print("json转换后:$json"); - quillController = QuillController( - document: doc, selection: const TextSelection.collapsed(offset: 0)); + Document doc = Document.fromJson(json); + LogUtil.d("读取到的笔记数据源文件为:$contents"); + LogUtil.d("转换json后:$json"); + return doc; } catch (error) { - print('读取文件错误,文件不是Delta格式:$error'); - quillController = QuillController.basic(); - // final doc = Document()..insert(0, '读取文件错误,文件不是Delta格式'); - // quillController = QuillController( - // document: doc, selection: const TextSelection.collapsed(offset: 0)); + LogUtil.e('读取文件错误,文件不是Delta格式:$error'); + return null; } - return quillController; } ///保存笔记 bool saveNote() { var deltaJson = quillController.document.toDelta().toJson(); - print(deltaJson); - String jsonString = jsonEncode(deltaJson); - - final file = File(noteRouteMsg.noteFilePosition); + final file = File(state.getBaseNote().noteDataPos); + LogUtil.d("保存位置:${file.absolute}"); + LogUtil.d("保存数据为:$deltaJson"); try { file.writeAsStringSync(jsonString); return true; } catch (e) { - print('文件写入失败: $e'); + LogUtil.d('保存数据失败: $e'); return false; } } - /// 复制粘贴图片(网络) - Future _onImagePaste(Uint8List imageBytes) async { - // Saves the image to applications directory - String imgDir = noteRouteMsg.noteImgDirPosition!; - String fileName = CommonTool.getCurrentTime() + ".jpeg"; - var allPath = await FileTool.saveImage(imageBytes, imgDir, fileName); - - print("_onImagePaste:保存路径" + allPath!); - return allPath; - } - /// 插入视频节点 void insertVideoAnchor(QuillController quillController) { Duration currentDuration = videoPlayerController.getCurrentDuration(); @@ -188,13 +169,6 @@ class QuillTextController extends GetxController { /// 插入自定义链接 void insertLinkBlockEmbed(QuillController controller, String string, void Function() linkBlockEmbedClick) { - // controller.document.insert(controller.selection.extentOffset, '\n'); - // controller.updateSelection( - // TextSelection.collapsed( - // offset: controller.selection.extentOffset + 1, - // ), - // ChangeSource.LOCAL, - // ); controller.document.insert( controller.selection.extentOffset, @@ -217,34 +191,36 @@ class QuillTextController extends GetxController { ); } - /// 三击 - bool _onTripleClickSelection() { - final controller = quillController!; + /// 复制粘贴图片(网络) + Future _onImagePaste(Uint8List imageBytes) async { + String imgDir = state.getBaseNote().noteImgPos; + String imgName = CommonTool.getCurrentTime() + ".jpeg"; + String? imgFilePath = await FileTool.saveImage(imageBytes, imgDir, imgName); + if (imgFilePath == null){ + return null; + } + LogUtil.d("图片保存路径为:$imgFilePath"); + return imgFilePath; + } + /// 也是三次点击的部分 + Timer? _selectAllTimer; + _SelectionType _selectionType = _SelectionType.none; + /// 三次点击 + bool _onTripleClickSelection() { + final controller = quillController; _selectAllTimer?.cancel(); _selectAllTimer = null; - // If you want to select all text after paragraph, uncomment this line - // if (_selectionType == _SelectionType.line) { - // final selection = TextSelection( - // baseOffset: 0, - // extentOffset: controller.document.length, - // ); - - // controller.updateSelection(selection, ChangeSource.REMOTE); - - // _selectionType = _SelectionType.none; - - // return true; - // } - if (controller.selection.isCollapsed) { _selectionType = _SelectionType.none; } if (_selectionType == _SelectionType.none) { _selectionType = _SelectionType.word; - _startTripleClickTimer(); + _selectAllTimer = Timer(const Duration(milliseconds: 900), () { + _selectionType = _SelectionType.none; + }); return false; } @@ -259,122 +235,22 @@ class QuillTextController extends GetxController { baseOffset: offset, extentOffset: offset + length, ); - controller.updateSelection(selection, ChangeSource.remote); - - // _selectionType = _SelectionType.line; - _selectionType = _SelectionType.none; - - _startTripleClickTimer(); - + _selectAllTimer = Timer(const Duration(milliseconds: 900), () { + _selectionType = _SelectionType.none; + }); return true; } - return false; } - void _startTripleClickTimer() { - _selectAllTimer = Timer(const Duration(milliseconds: 900), () { - _selectionType = _SelectionType.none; - }); - } - - /// 是否为桌面 - bool _isDesktop() => !kIsWeb && !Platform.isAndroid && !Platform.isIOS; - - /// 构建富文本工具栏 - QuillToolbar buildQuillToolbar(BuildContext context) { - List customQuillCustomButtons = [ - IconButton( - icon: Icon(Icons.screenshot), - onPressed: () async { - insertVideoAnchor(quillController); - String imgDir = noteRouteMsg.noteImgDirPosition!; - - videoPlayerController.videoScreenShot(imgDir, (absolutePath) { - insertImageBlockEmbed(absolutePath); - }); - }), - IconButton( - icon: Icon(Icons.flag), - onPressed: () { - insertVideoAnchor(quillController); - }), - IconButton( - icon: Icon(Icons.image), - onPressed: () { - showDialog( - context: context, - barrierDismissible: false, - builder: (BuildContext context) => InsertImageDialog(), - ); - }), - IconButton( - icon: Icon(Icons.movie_creation), onPressed: () {}), - IconButton( - icon: Icon(Icons.photo_camera), onPressed: () {}), - IconButton( - icon: Icon(Icons.find_in_page), onPressed: () {}), - IconButton(icon: Icon(Icons.mic), onPressed: () {}), - IconButton( - icon: Icon(Icons.music_note), onPressed: () {}), - IconButton( - icon: Icon(Icons.live_tv), onPressed: () {}), - IconButton( - icon: Icon(Icons.unarchive_outlined), - onPressed: () { - final msc = Get.find(); - msc.setAxis(Axis.vertical); - }), - IconButton( - icon: Icon(Icons.save), - onPressed: () { - bool result = saveNote(); - if (result) { - SmartDialog.showToast('保存成功'); - } else { - SmartDialog.showToast('保存失败'); - } - }), - ]; - - var toolbar = QuillToolbar( - configurations: QuillToolbarConfigurations( - sharedConfigurations:QuillSharedConfigurations() - ), - child: Wrap( - children: customQuillCustomButtons, - ), - ); - if (kIsWeb) { - toolbar = QuillToolbar( - configurations: QuillToolbarConfigurations( - sharedConfigurations:QuillSharedConfigurations() - ), - child: Wrap( - children: customQuillCustomButtons, - ), - ); - } - if (_isDesktop()) { - toolbar = QuillToolbar( - configurations: QuillToolbarConfigurations( - sharedConfigurations:QuillSharedConfigurations() - ), - child: Wrap( - children: customQuillCustomButtons, - ), - ); - } - return toolbar; - } - /// When inserting an image OnImageInsertCallback get onImageInsert { return (image, controller) async {}; } + final FocusNode _focusNode = FocusNode(); /** * 构建富文本编辑器 */ @@ -451,10 +327,24 @@ class QuillTextController extends GetxController { return quillEditor; } + void setNoteContent({BaseNote? baseNote}) { + baseNote = baseNote ?? getBaseNote(); + if (baseNote==null){ + return ; + } + + Document? doc = loadNoteDataFile(baseNote.noteDataPos); + if (doc==null){ + return ; + } + quillController.document = doc; + } + /// 在 widget 内存中分配后立即调用,这和Widget build(BuildContext context)异步,不适合初始化一些耗时操作。 @override Future onInit() async { super.onInit(); + setNoteContent(); } /// 在 onInit() 之后调用 1 帧。这是进入的理想场所 diff --git a/lib/pages/videonote/controller/video_player_controller.dart b/lib/pages/videonote/controller/video_player_controller.dart index cbd5e6e..87fd675 100644 --- a/lib/pages/videonote/controller/video_player_controller.dart +++ b/lib/pages/videonote/controller/video_player_controller.dart @@ -6,7 +6,8 @@ import 'package:media_kit/media_kit.dart'; import 'package:media_kit_video/media_kit_video.dart'; import 'package:note/common/utils/common_tool.dart'; import 'package:note/common/utils/file_tool.dart'; -import 'package:note/models/note/base_note.dart'; +import 'package:note/models/note_model/base_note.dart'; + class VideoPlayerController extends GetxController { late Duration currentDuration; @@ -33,7 +34,7 @@ class VideoPlayerController extends GetxController { } BaseNote baseNote = arguments[BaseNote.flag] as BaseNote; - return baseNote.readMedia.rsource.v; + return baseNote.noteDependMediaPos; } ///获取传入页面的参数 diff --git a/lib/pages/videonote/widgets/dialogs/insert_image_dialog.dart b/lib/pages/videonote/widgets/dialogs/insert_image_dialog.dart index 5753705..9b76268 100644 --- a/lib/pages/videonote/widgets/dialogs/insert_image_dialog.dart +++ b/lib/pages/videonote/widgets/dialogs/insert_image_dialog.dart @@ -4,7 +4,8 @@ import 'package:get/get.dart'; import 'package:getwidget/components/button/gf_button.dart'; import 'package:getwidget/components/text_field/gf_text_field.dart'; import 'package:getwidget/size/gf_size.dart'; -import 'package:note/models/r_source.dart'; +import 'package:note/models/note_model/base_note.dart'; + import 'package:note/pages/videonote/controller/quill_text_controller.dart'; class InsertImageDialog extends GetView { diff --git a/lib/pages/videonote/widgets/my_quill_toolbar.dart b/lib/pages/videonote/widgets/my_quill_toolbar.dart new file mode 100644 index 0000000..5c279ca --- /dev/null +++ b/lib/pages/videonote/widgets/my_quill_toolbar.dart @@ -0,0 +1,456 @@ +import 'dart:io' as io show File; + +import 'package:flutter/material.dart'; + +import 'package:flutter_quill/extensions.dart' show isAndroid, isIOS, isWeb; +import 'package:flutter_quill/flutter_quill.dart'; +import 'package:flutter_quill_extensions/flutter_quill_extensions.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; +import 'package:get/get.dart'; +import 'package:get/get_core/src/get_main.dart'; +import 'package:google_fonts/google_fonts.dart'; + +import 'package:image_cropper/image_cropper.dart'; +import 'package:note/dao/data_manager.dart'; +import 'package:note/pages/videonote/controller/quill_text_controller.dart'; +import 'package:note/pages/videonote/controller/video_player_controller.dart'; +import 'package:note/pages/videonote/widgets/link_blockembed.dart'; +import 'package:path/path.dart' as path; +import 'package:path_provider/path_provider.dart' + show getApplicationDocumentsDirectory; + +import 'dialogs/insert_image_dialog.dart'; + + + +class MyQuillToolbar extends StatelessWidget { + MyQuillToolbar({ + required this.quillController, + required this.focusNode, + super.key, + }); + + final QuillController quillController; + final FocusNode focusNode; + final videoPlayerController = Get.find(); + final quillTextController = Get.find(); + + Future onImageInsertWithCropping( + String image, + QuillController controller, + BuildContext context, + ) async { + final croppedFile = await ImageCropper().cropImage( + sourcePath: image, + aspectRatioPresets: [ + CropAspectRatioPreset.square, + CropAspectRatioPreset.ratio3x2, + CropAspectRatioPreset.original, + CropAspectRatioPreset.ratio4x3, + CropAspectRatioPreset.ratio16x9 + ], + uiSettings: [ + AndroidUiSettings( + toolbarTitle: 'Cropper', + toolbarColor: Colors.deepOrange, + toolbarWidgetColor: Colors.white, + initAspectRatio: CropAspectRatioPreset.original, + lockAspectRatio: false, + ), + IOSUiSettings( + title: 'Cropper', + ), + WebUiSettings( + context: context, + ), + ], + ); + final newImage = croppedFile?.path; + if (newImage == null) { + return; + } + if (isWeb()) { + controller.insertImageBlock(imageSource: newImage); + return; + } + final newSavedImage = await saveImage(io.File(newImage)); + controller.insertImageBlock(imageSource: newSavedImage); + } + + Future onImageInsert(String image, QuillController controller) async { + if (isWeb() || isHttpBasedUrl(image)) { + controller.insertImageBlock(imageSource: image); + return; + } + final newSavedImage = await saveImage(io.File(image)); + controller.insertImageBlock(imageSource: newSavedImage); + } + + /// For mobile platforms it will copies the picked file from temporary cache + /// to applications directory + /// + /// for desktop platforms, it will do the same but from user files this time + Future saveImage(io.File file) async { + final appDocDir = await getApplicationDocumentsDirectory(); + final fileExt = path.extension(file.path); + final newFileName = '${DateTime.now().toIso8601String()}$fileExt'; + final newPath = path.join( + appDocDir.path, + newFileName, + ); + final copiedFile = await file.copy(newPath); + return copiedFile.path; + } + + @override + Widget build(BuildContext context) { + return QuillToolbar( + child: Wrap(children: [ + Obx(() { + return Visibility( + visible: quillTextController.state.showMoreToolbarBtn, + child: + IconButton( + icon: const Icon( + Icons.width_normal, + ), + onPressed: (){ + quillTextController.state.showMoreToolbarBtn = false; + DataManager.setShowMoreToolbarBtn(false); + }, + ), + ); + }), + + + Obx(() { + return Visibility( + visible: quillTextController.state.showMoreToolbarBtn, + child: QuillToolbarHistoryButton( + isUndo: true, + controller: quillController, + ),); + }), + Obx(() { + return Visibility( + visible: quillTextController.state.showMoreToolbarBtn, + child: + QuillToolbarHistoryButton( + isUndo: false, + controller: quillController, + ), + ); + }), + + IconButton( + tooltip: "截屏", + icon: Icon(Icons.screenshot), + onPressed: () async { + quillTextController.insertVideoAnchor(quillController); + String imgDir =quillTextController.state.getBaseNote().noteImgPos; + videoPlayerController.videoScreenShot(imgDir, (absolutePath) { + quillTextController.insertImageBlockEmbed(absolutePath); + }); + }), + IconButton( + tooltip: "插入时间点", + icon: Icon(Icons.add_alarm_rounded), + onPressed: () { + quillTextController.insertVideoAnchor(quillController); + }), + IconButton( + tooltip: "插入图片", + icon: Icon(Icons.image), + onPressed: () { + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => InsertImageDialog(), + ); + }), + Obx(() { + return Visibility( + visible: quillTextController.state.showMoreToolbarBtn, + child: + IconButton( + tooltip: "插入照片", + icon: Icon(Icons.photo_camera), onPressed: () {}), + ); + }), + + + IconButton( + tooltip: "插入音频", + icon: Icon(Icons.music_note), onPressed: () {}), + + Obx(() { + return Visibility( + visible: quillTextController.state.showMoreToolbarBtn, + child: + IconButton( + tooltip: "插入录音", + icon: Icon(Icons.mic), onPressed: () {}), + ); + }), + Obx(() { + return Visibility( + visible: quillTextController.state.showMoreToolbarBtn, + child: + IconButton( + tooltip: "插入视频", + icon: Icon(Icons.movie_creation), onPressed: () {}), + ); + }), + Obx(() { + return Visibility( + visible: quillTextController.state.showMoreToolbarBtn, + child: + IconButton( + tooltip: "文本查找", + icon: Icon(Icons.find_in_page), onPressed: () {}), + ); + }), + Obx(() { + return Visibility( + visible: quillTextController.state.showMoreToolbarBtn, + child: + IconButton( + tooltip: "导出", + icon: Icon(Icons.unarchive_outlined), + onPressed: () { + // final msc = Get.find(); + // msc.setAxis(Axis.vertical); + }), + ); + }), + + IconButton( + tooltip: "保存", + icon: Icon(Icons.save), + onPressed: () { + bool result = quillTextController.saveNote(); + if (result) { + SmartDialog.showToast('保存成功'); + } else { + SmartDialog.showToast('保存失败'); + } + }), + Obx(() { + return Visibility( + visible: quillTextController.state.showMoreToolbarBtn, + child: + QuillToolbarToggleStyleButton( + options: const QuillToolbarToggleStyleButtonOptions(), + controller: quillController, + attribute: Attribute.bold, + ), + ); + }), + + Obx(() { + return Visibility( + visible: quillTextController.state.showMoreToolbarBtn, + child: + QuillToolbarToggleStyleButton( + options: const QuillToolbarToggleStyleButtonOptions(), + controller: quillController, + attribute: Attribute.italic, + ), + ); + }), + + Obx(() { + return Visibility( + visible: quillTextController.state.showMoreToolbarBtn, + child: + QuillToolbarToggleStyleButton( + controller: quillController, + attribute: Attribute.underline, + ), + ); + }), + Obx(() { + return Visibility( + visible: quillTextController.state.showMoreToolbarBtn, + child: + QuillToolbarToggleStyleButton( + controller: quillController, + attribute: Attribute.subscript, + ), + ); + }), + Obx(() { + return Visibility( + visible: quillTextController.state.showMoreToolbarBtn, + child: + QuillToolbarToggleStyleButton( + controller: quillController, + attribute: Attribute.superscript, + ), + ); + }), + + Obx(() { + return Visibility( + visible: quillTextController.state.showMoreToolbarBtn, + child: + QuillToolbarClearFormatButton( + controller: quillController, + ), + ); + }), + + + const VerticalDivider(), + Obx(() { + return Visibility( + visible: quillTextController.state.showMoreToolbarBtn, + child: + QuillToolbarColorButton( + controller: quillController, + isBackground: false, + ), + ); + }), + + Obx(() { + return Visibility( + visible: quillTextController.state.showMoreToolbarBtn, + child: + QuillToolbarColorButton( + controller: quillController, + isBackground: true, + ), + ); + }), + + + const VerticalDivider(), + QuillToolbarSelectHeaderStyleDropdownButton( + controller: quillController, + options: QuillToolbarSelectHeaderStyleDropdownButtonOptions( + attributes:[ + Attribute.h1, + Attribute.h2, + Attribute.h3, + Attribute.h4, + Attribute.h5, + Attribute.h6, + Attribute.header, + ] + ), + ), + QuillToolbarFontFamilyButton( + controller: quillController, + options: QuillToolbarFontFamilyButtonOptions( + rawItemsMap:{ + 'Amatic': GoogleFonts.amaticSc().fontFamily!, + 'Annie': GoogleFonts.annieUseYourTelescope().fontFamily!, + 'Formal': GoogleFonts.petitFormalScript().fontFamily!, + 'Roboto': GoogleFonts.roboto().fontFamily! + } + ), + ), + + + const VerticalDivider(), + QuillToolbarToggleCheckListButton( + controller: quillController, + ), + + QuillToolbarToggleStyleButton( + controller: quillController, + attribute: Attribute.ol, + ), + QuillToolbarToggleStyleButton( + controller: quillController, + attribute: Attribute.ul, + ), + QuillToolbarToggleStyleButton( + controller: quillController, + attribute: Attribute.leftAlignment, + ), + QuillToolbarToggleStyleButton( + controller: quillController, + attribute: Attribute.centerAlignment, + ), + QuillToolbarToggleStyleButton( + controller: quillController, + attribute: Attribute.rightAlignment, + ), + QuillToolbarToggleStyleButton( + controller: quillController, + attribute: Attribute.justifyAlignment, + ), + + Obx(() { + return Visibility( + visible: quillTextController.state.showMoreToolbarBtn, + child: + QuillToolbarToggleStyleButton( + controller: quillController, + attribute: Attribute.inlineCode, + ), + ); + }), + + + Obx(() { + return Visibility( + visible: quillTextController.state.showMoreToolbarBtn, + child: + QuillToolbarToggleStyleButton( + controller: quillController, + attribute: Attribute.blockQuote, + ), + ); + }), + Obx(() { + return Visibility( + visible: quillTextController.state.showMoreToolbarBtn, + child: + QuillToolbarIndentButton( + controller: quillController, + isIncrease: true, + ), + ); + }), + Obx(() { + return Visibility( + visible: quillTextController.state.showMoreToolbarBtn, + child: + QuillToolbarIndentButton( + controller: quillController, + isIncrease: false, + ), + ); + }), + + const VerticalDivider(), + Obx(() { + return Visibility( + visible: quillTextController.state.showMoreToolbarBtn, + child: + QuillToolbarLinkStyleButton(controller: quillController), + ); + }), + Obx(() { + return Visibility( + visible: !quillTextController.state.showMoreToolbarBtn, + child: + IconButton( + tooltip: "更多按钮", + icon: Icon(Icons.dashboard_customize), onPressed: () { + quillTextController.state.showMoreToolbarBtn = true; + DataManager.setShowMoreToolbarBtn(true); + }), + ); + }), + + ], + ), + configurations: QuillToolbarConfigurations(), + ); + + } +} diff --git a/lib/pages/videonote/widgets/note_area.dart b/lib/pages/videonote/widgets/note_area.dart index 5c253d1..39ba52a 100644 --- a/lib/pages/videonote/widgets/note_area.dart +++ b/lib/pages/videonote/widgets/note_area.dart @@ -1,46 +1,33 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_quill/flutter_quill.dart'; import 'package:note/pages/videonote/widgets/base_video_note_view.dart'; class NoteArea extends BaseVideoNoteView { NoteArea({Key? key}) : super(key: key) {} - late QuillToolbar quillToolbar; - - Future initData(BuildContext context) async { - ///构建quillToolbar - quillToolbar = quillTextController.buildQuillToolbar(context); - } @override Widget build(BuildContext context) { - initData(context); - - return buildQuillView(); - } - - Widget buildQuillView() { - return Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - kIsWeb - ? Expanded( - child: Container( - padding: - const EdgeInsets.symmetric(vertical: 16, horizontal: 8), - child: quillToolbar, - )) - : Container(child: quillToolbar), - Expanded( - flex: 15, + return Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + kIsWeb + ? Expanded( child: Container( - color: Colors.white, - // padding: const EdgeInsets.only(left: 5, right: 5), - child: quillTextController.quillEditor, - ), + padding: + const EdgeInsets.symmetric(vertical: 16, horizontal: 8), + child: controller.quillToolbar, + )) + : Container(child: controller.quillToolbar), + Expanded( + flex: 15, + child: Container( + color: Colors.white, + // padding: const EdgeInsets.only(left: 5, right: 5), + child: quillTextController.quillEditor, ), - ], - ); + ), + ], + ); } } diff --git a/pubspec.lock b/pubspec.lock index fe751e5..5b8e105 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -185,6 +185,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "1.18.0" + common_utils: + dependency: "direct main" + description: + name: common_utils + sha256: c26884339b13ff99b0739e56f4b02090c84054ed9dd3a045435cd24e7b99c2c1 + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.0" connectivity_plus: dependency: transitive description: @@ -265,6 +273,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "0.7.10" + decimal: + dependency: transitive + description: + name: decimal + sha256: "24a261d5d5c87e86c7651c417a5dbdf8bcd7080dd592533910e8d0505a279f21" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.3.3" device_info_plus: dependency: transitive description: @@ -660,6 +676,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "2.1.2" + google_fonts: + dependency: "direct main" + description: + name: google_fonts + sha256: b1ac0fe2832c9cc95e5e88b57d627c5e68c223b9657f4b96e1487aa9098c7b82 + url: "https://pub.flutter-io.cn" + source: hosted + version: "6.2.1" graphs: dependency: transitive description: @@ -716,6 +740,30 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "4.1.7" + image_cropper: + dependency: "direct main" + description: + name: image_cropper + sha256: f4bad5ed2dfff5a7ce0dfbad545b46a945c702bb6182a921488ef01ba7693111 + url: "https://pub.flutter-io.cn" + source: hosted + version: "5.0.1" + image_cropper_for_web: + dependency: transitive + description: + name: image_cropper_for_web + sha256: "865d798b5c9d826f1185b32e5d0018c4183ddb77b7b82a931e1a06aa3b74974e" + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.0.0" + image_cropper_platform_interface: + dependency: transitive + description: + name: image_cropper_platform_interface + sha256: ee160d686422272aa306125f3b6fb1c1894d9b87a5e20ed33fa008e7285da11e + url: "https://pub.flutter-io.cn" + source: hosted + version: "5.0.0" image_picker: dependency: transitive description: @@ -860,14 +908,6 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "2.1.1" - logger: - dependency: "direct main" - description: - name: logger - sha256: "8c94b8c219e7e50194efc8771cd0e9f10807d8d3e219af473d89b06cc2ee4e04" - url: "https://pub.flutter-io.cn" - source: hosted - version: "2.2.0" logging: dependency: transitive description: @@ -1212,6 +1252,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "3.2.1" + rational: + dependency: transitive + description: + name: rational + sha256: ba58e9e18df9abde280e8b10051e4bce85091e41e8e7e411b6cde2e738d357cf + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.2.2" responsive_framework: dependency: "direct main" description: @@ -1333,7 +1381,7 @@ packages: source: hosted version: "2.3.2" shelf: - dependency: "direct main" + dependency: transitive description: name: shelf sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 @@ -1739,4 +1787,4 @@ packages: version: "9.0.0" sdks: dart: ">=3.3.0 <4.0.0" - flutter: ">=3.19.0" + flutter: ">=3.19.2" diff --git a/pubspec.yaml b/pubspec.yaml index b39d2b2..e59bfbb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -29,7 +29,9 @@ dependencies: #富文本编辑器组件 flutter_quill: ^9.3.10 flutter_quill_extensions: ^9.3.10 + google_fonts: ^6.2.1 #路由组件 + #https://github.com/jonataslaw/getx/blob/master/README.zh-cn.md get: ^4.6.6 #持久化组件 # shared_preferences: ^2.2.1 @@ -45,6 +47,7 @@ dependencies: #权限组件 permission_handler: ^11.0.0 #吐司弹窗框架 + #https://pub-web.flutter-io.cn/packages/flutter_smart_dialog flutter_smart_dialog: ^4.9.5+1 #分享 # share_plus: ^9.0.0 @@ -52,7 +55,7 @@ dependencies: # device_info_plus: ^9.0.3 package_info_plus: ^4.2.0 #日志 - logger: ^2.0.1 +# logger: ^2.0.1 #打开url # url_launcher: ^6.1.12 #崩溃信息 @@ -69,6 +72,8 @@ dependencies: # extended_image: 8.0.2 # 图片裁剪 # crop_image: ^1.0.11 + image_cropper: ^5.0.1 + #录音 # record: ^5.0.1 #插件系统 @@ -90,7 +95,10 @@ dependencies: #代码编辑 # flutter_code_editor: ^0.3.1 #工具类 包含shared_preferences + #https://github.com/bhoominn/nb_utils nb_utils: ^7.0.2 + #https://github.com/Sky24n/common_utils + common_utils: ^2.1.0 #网格视图布局组件 flutter_staggered_grid_view: ^0.7.0 #上拉下拉刷新 @@ -106,7 +114,7 @@ dependencies: # 设置UI # settings_ui: ^2.0.2 #服务器组件 - shelf: ^1.4.1 +# shelf: ^1.4.1 #websocket 跨端通信 web_socket_channel: ^2.4.0 # socket_io_client: ^2.0.3+1 diff --git a/script/pack_android.bat b/script/pack_android.bat new file mode 100644 index 0000000..caba5b0 --- /dev/null +++ b/script/pack_android.bat @@ -0,0 +1,6 @@ +@echo off +cd .. + +@REM 打包android脚本 + +flutter build apk --split-per-abi \ No newline at end of file diff --git a/script/pack_ios.sh b/script/pack_ios.sh new file mode 100644 index 0000000..d3c14a6 --- /dev/null +++ b/script/pack_ios.sh @@ -0,0 +1,2 @@ +cd .. +flutter build ios --release \ No newline at end of file diff --git a/script/pack_mac.sh b/script/pack_mac.sh new file mode 100644 index 0000000..9955e47 --- /dev/null +++ b/script/pack_mac.sh @@ -0,0 +1,2 @@ +cd .. +flutter build macos \ No newline at end of file diff --git a/script/pack_windows.bat b/script/pack_windows.bat new file mode 100644 index 0000000..56f15a1 --- /dev/null +++ b/script/pack_windows.bat @@ -0,0 +1,6 @@ +@echo off +cd .. + +@REM 打包windows脚本 + +flutter build windows \ No newline at end of file diff --git a/test/t1.dart b/test/t1.dart index e69de29..7f78af6 100644 --- a/test/t1.dart +++ b/test/t1.dart @@ -0,0 +1,3 @@ +main(){ + print("object"); +} \ No newline at end of file