From 4f4411fcc3c33055edb4ac4d17b074048e444bf4 Mon Sep 17 00:00:00 2001 From: nyne Date: Sun, 10 Nov 2024 10:38:46 +0800 Subject: [PATCH] sync data using webdav --- assets/translation.json | 16 +- lib/foundation/appdata.dart | 2 + lib/foundation/favorites.dart | 14 +- lib/foundation/log.dart | 7 +- lib/network/app_dio.dart | 10 +- lib/pages/home_page.dart | 130 +++++++++-- lib/pages/settings/app.dart | 141 +++++++++++- lib/pages/settings/settings_page.dart | 1 + lib/utils/data.dart | 14 +- lib/utils/data_sync.dart | 205 ++++++++++++++++++ linux/flutter/generated_plugin_registrant.cc | 8 +- linux/flutter/generated_plugins.cmake | 2 +- macos/Flutter/GeneratedPluginRegistrant.swift | 4 +- pubspec.lock | 25 +++ pubspec.yaml | 4 + .../flutter/generated_plugin_registrant.cc | 6 +- windows/flutter/generated_plugins.cmake | 2 +- 17 files changed, 542 insertions(+), 49 deletions(-) create mode 100644 lib/utils/data_sync.dart diff --git a/assets/translation.json b/assets/translation.json index 92f5bb0..cfcb64d 100644 --- a/assets/translation.json +++ b/assets/translation.json @@ -179,7 +179,13 @@ "Move To First": "移动到最前", "Cancel": "取消", "Paused": "已暂停", - "Pause": "暂停" + "Pause": "暂停", + "Operation": "操作", + "Upload": "上传", + "Saved": "已保存", + "Sync Data": "同步数据", + "Syncing Data": "正在同步数据", + "Data Sync": "数据同步" }, "zh_TW": { "Home": "首頁", @@ -361,6 +367,12 @@ "Move To First": "移動到最前", "Cancel": "取消", "Paused": "已暫停", - "Pause": "暫停" + "Pause": "暫停", + "Operation": "操作", + "Upload": "上傳", + "Saved": "已保存", + "Sync Data": "同步數據", + "Syncing Data": "正在同步數據", + "Data Sync": "數據同步" } } \ No newline at end of file diff --git a/lib/foundation/appdata.dart b/lib/foundation/appdata.dart index eae041e..1d26838 100644 --- a/lib/foundation/appdata.dart +++ b/lib/foundation/appdata.dart @@ -114,6 +114,8 @@ class _Settings with ChangeNotifier { 'enableLongPressToZoom': true, 'checkUpdateOnStart': true, 'limitImageWidth': true, + 'webdav': [], // empty means not configured + 'dataVersion': 0, }; operator [](String key) { diff --git a/lib/foundation/favorites.dart b/lib/foundation/favorites.dart index c50f4ed..4ed1cd1 100644 --- a/lib/foundation/favorites.dart +++ b/lib/foundation/favorites.dart @@ -1,5 +1,6 @@ import 'dart:convert'; +import 'package:flutter/foundation.dart'; import 'package:sqlite3/sqlite3.dart'; import 'package:venera/foundation/appdata.dart'; import 'package:venera/foundation/image_provider/local_favorite_image.dart'; @@ -148,7 +149,7 @@ class FavoriteItemWithFolderInfo extends FavoriteItem { ); } -class LocalFavoritesManager { +class LocalFavoritesManager with ChangeNotifier { factory LocalFavoritesManager() => cache ?? (cache = LocalFavoritesManager._create()); @@ -233,6 +234,7 @@ class LocalFavoritesManager { values (?, ?); """, [folder, order[folder]]); } + notifyListeners(); } int count(String folderName) { @@ -272,6 +274,7 @@ class LocalFavoritesManager { set tags = '$tag,' || tags where id == ? """, [id]); + notifyListeners(); } List allComics() { @@ -324,6 +327,7 @@ class LocalFavoritesManager { primary key (id, type) ); """); + notifyListeners(); return name; } @@ -386,6 +390,7 @@ class LocalFavoritesManager { values (?, ?, ?, ?, ?, ?, ?, ?); """, [...params, minValue(folder) - 1]); } + notifyListeners(); } /// delete a folder @@ -394,6 +399,7 @@ class LocalFavoritesManager { _db.execute(""" drop table "$name"; """); + notifyListeners(); } void deleteComic(String folder, FavoriteItem comic) { @@ -408,6 +414,7 @@ class LocalFavoritesManager { delete from "$folder" where id == ? and type == ?; """, [id, type.value]); + notifyListeners(); } Future clearAll() async { @@ -425,6 +432,7 @@ class LocalFavoritesManager { for (int i = 0; i < newFolder.length; i++) { addComic(folder, newFolder[i], i); } + notifyListeners(); } void rename(String before, String after) { @@ -438,6 +446,7 @@ class LocalFavoritesManager { ALTER TABLE "$before" RENAME TO "$after"; """); + notifyListeners(); } void onReadEnd(String id, ComicType type) async { @@ -475,6 +484,7 @@ class LocalFavoritesManager { """, [newTime, id]); } } + notifyListeners(); } List search(String keyword) { @@ -521,6 +531,7 @@ class LocalFavoritesManager { set tags = ? where id == ?; """, [tags.join(","), id]); + notifyListeners(); } final _cachedFavoritedIds = {}; @@ -560,6 +571,7 @@ class LocalFavoritesManager { comic.id, comic.type.value ]); + notifyListeners(); } String folderToJson(String folder) { diff --git a/lib/foundation/log.dart b/lib/foundation/log.dart index efdda91..ffe051b 100644 --- a/lib/foundation/log.dart +++ b/lib/foundation/log.dart @@ -82,11 +82,12 @@ class Log { addLog(LogLevel.warning, title, content); } - static error(String title, String content, [Object? stackTrace]) { + static error(String title, Object content, [Object? stackTrace]) { + var info = content.toString(); if(stackTrace != null) { - content += "\n${stackTrace.toString()}"; + info += "\n${stackTrace.toString()}"; } - addLog(LogLevel.error, title, content); + addLog(LogLevel.error, title, info); } static void clear() => _logs.clear(); diff --git a/lib/network/app_dio.dart b/lib/network/app_dio.dart index b190994..af21d6f 100644 --- a/lib/network/app_dio.dart +++ b/lib/network/app_dio.dart @@ -108,11 +108,11 @@ class AppDio with DioMixin { AppDio([BaseOptions? options]) { this.options = options ?? BaseOptions(); - interceptors.add(MyLogInterceptor()); httpClientAdapter = RHttpAdapter(const rhttp.ClientSettings()); interceptors.add(CookieManagerSql(SingleInstanceCookieJar.instance!)); interceptors.add(NetworkCacheManager()); interceptors.add(CloudflareInterceptor()); + interceptors.add(MyLogInterceptor()); } static HttpClient createHttpClient() { @@ -211,7 +211,7 @@ class AppDio with DioMixin { class RHttpAdapter implements HttpClientAdapter { rhttp.ClientSettings settings; - RHttpAdapter(this.settings) { + RHttpAdapter([this.settings = const rhttp.ClientSettings()]) { settings = settings.copyWith( redirectSettings: const rhttp.RedirectSettings.limited(5), timeoutSettings: const rhttp.TimeoutSettings( @@ -232,12 +232,6 @@ class RHttpAdapter implements HttpClientAdapter { Stream? requestStream, Future? cancelFuture, ) async { - Log.info( - "Network", - "${options.method} ${options.uri}\n" - "Headers: ${options.headers}\n" - "Data: ${options.data}\n", - ); var res = await rhttp.Rhttp.request( method: switch (options.method) { 'GET' => rhttp.HttpMethod.get, diff --git a/lib/pages/home_page.dart b/lib/pages/home_page.dart index f4c5641..dc22b35 100644 --- a/lib/pages/home_page.dart +++ b/lib/pages/home_page.dart @@ -1,5 +1,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:sliver_tools/sliver_tools.dart'; import 'package:venera/components/components.dart'; import 'package:venera/foundation/app.dart'; import 'package:venera/foundation/comic_source/comic_source.dart'; @@ -17,6 +18,7 @@ import 'package:venera/pages/downloading_page.dart'; import 'package:venera/pages/history_page.dart'; import 'package:venera/pages/search_page.dart'; import 'package:venera/utils/cbz.dart'; +import 'package:venera/utils/data_sync.dart'; import 'package:venera/utils/ext.dart'; import 'package:venera/utils/io.dart'; import 'package:venera/utils/translations.dart'; @@ -32,6 +34,7 @@ class HomePage extends StatelessWidget { slivers: [ SliverPadding(padding: EdgeInsets.only(top: context.padding.top)), const _SearchBar(), + const _SyncDataWidget(), const _History(), const _Local(), const _ComicSourceWidget(), @@ -77,6 +80,97 @@ class _SearchBar extends StatelessWidget { } } +class _SyncDataWidget extends StatefulWidget { + const _SyncDataWidget(); + + @override + State<_SyncDataWidget> createState() => _SyncDataWidgetState(); +} + +class _SyncDataWidgetState extends State<_SyncDataWidget> { + @override + void initState() { + super.initState(); + DataSync().addListener(update); + } + + void update() { + if(mounted) { + setState(() {}); + } + } + + @override + void dispose() { + super.dispose(); + DataSync().removeListener(update); + } + + @override + Widget build(BuildContext context) { + Widget child; + if(!DataSync().isEnabled) { + child = const SliverPadding(padding: EdgeInsets.zero); + } else if (DataSync().isUploading || DataSync().isDownloading) { + child = SliverToBoxAdapter( + child: Container( + margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 8), + decoration: BoxDecoration( + border: Border.all( + color: Theme.of(context).colorScheme.primary, + ), + borderRadius: BorderRadius.circular(8), + ), + child: ListTile( + leading: const Icon(Icons.sync), + title: Text('Syncing Data'.tl), + trailing: const CircularProgressIndicator(strokeWidth: 2) + .fixWidth(18) + .fixHeight(18), + ), + ), + ); + } else { + child = SliverToBoxAdapter( + child: Container( + margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 8), + decoration: BoxDecoration( + border: Border.all( + color: Theme.of(context).colorScheme.outlineVariant, + ), + borderRadius: BorderRadius.circular(8), + ), + child: ListTile( + leading: const Icon(Icons.sync), + title: Text('Sync Data'.tl), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + IconButton( + icon: const Icon(Icons.cloud_upload_outlined), + onPressed: () async { + DataSync().uploadData(); + } + ), + IconButton( + icon: const Icon(Icons.cloud_download_outlined), + onPressed: () async { + DataSync().downloadData(); + } + ), + ], + ), + ), + ), + ); + } + return SliverAnimatedPaintExtent( + duration: const Duration(milliseconds: 200), + child: child, + ); + } +} + class _History extends StatefulWidget { const _History(); @@ -529,14 +623,16 @@ class _ImportComicsWidgetState extends State<_ImportComicsWidget> { await xFile!.saveTo(cache); var comic = await CBZ.import(File(cache)); if (selectedFolder != null) { - LocalFavoritesManager().addComic(selectedFolder!, FavoriteItem( - id: comic.id, - name: comic.title, - coverPath: comic.cover, - author: comic.subtitle, - type: comic.comicType, - tags: comic.tags, - )); + LocalFavoritesManager().addComic( + selectedFolder!, + FavoriteItem( + id: comic.id, + name: comic.title, + coverPath: comic.cover, + author: comic.subtitle, + type: comic.comicType, + tags: comic.tags, + )); } await File(cache).deleteIgnoreError(); } catch (e, s) { @@ -610,14 +706,16 @@ class _ImportComicsWidgetState extends State<_ImportComicsWidget> { for (var comic in comics.values) { LocalManager().add(comic, LocalManager().findValidId(ComicType.local)); if (selectedFolder != null) { - LocalFavoritesManager().addComic(selectedFolder!, FavoriteItem( - id: comic.id, - name: comic.title, - coverPath: comic.cover, - author: comic.subtitle, - type: comic.comicType, - tags: comic.tags, - )); + LocalFavoritesManager().addComic( + selectedFolder!, + FavoriteItem( + id: comic.id, + name: comic.title, + coverPath: comic.cover, + author: comic.subtitle, + type: comic.comicType, + tags: comic.tags, + )); } } context.pop(); diff --git a/lib/pages/settings/app.dart b/lib/pages/settings/app.dart index 4856248..8583135 100644 --- a/lib/pages/settings/app.dart +++ b/lib/pages/settings/app.dart @@ -78,8 +78,7 @@ class _AppSettingsState extends State { appdata.settings['cacheSize'] = int.parse(value); appdata.saveData(); setState(() {}); - CacheManager() - .setLimitSize(appdata.settings['cacheSize']); + CacheManager().setLimitSize(appdata.settings['cacheSize']); return null; }, ); @@ -101,13 +100,12 @@ class _AppSettingsState extends State { callback: () async { var controller = showLoadingDialog(context); var file = await selectFile(ext: ['venera']); - if(file != null) { + if (file != null) { var cacheFile = File(FilePath.join(App.cachePath, "temp.venera")); await file.saveTo(cacheFile.path); try { await importAppData(cacheFile); - } - catch(e, s) { + } catch (e, s) { Log.error("Import data", e.toString(), s); context.showMessage(message: "Failed to import data".tl); } @@ -116,6 +114,13 @@ class _AppSettingsState extends State { }, actionTitle: 'Import'.tl, ).toSliver(), + _CallbackSetting( + title: "Data Sync".tl, + callback: () async { + showPopUpWidget(context, const _WebdavSetting()); + }, + actionTitle: 'Set'.tl, + ).toSliver(), _SettingPartTitle( title: "Log".tl, icon: Icons.error_outline, @@ -271,3 +276,129 @@ class _LogsPageState extends State { saveFile(data: utf8.encode(log), filename: 'log.txt'); } } + +class _WebdavSetting extends StatefulWidget { + const _WebdavSetting(); + + @override + State<_WebdavSetting> createState() => _WebdavSettingState(); +} + +class _WebdavSettingState extends State<_WebdavSetting> { + String url = ""; + String user = ""; + String pass = ""; + + bool isTesting = false; + + bool upload = true; + + @override + void initState() { + super.initState(); + if (appdata.settings['webdav'] is! List) { + appdata.settings['webdav'] = []; + } + var configs = appdata.settings['webdav'] as List; + if (configs.whereType().length != 3) { + return; + } + url = configs[0]; + user = configs[1]; + pass = configs[2]; + } + + @override + Widget build(BuildContext context) { + return PopUpWidgetScaffold( + title: "Webdav", + body: SingleChildScrollView( + child: Column( + children: [ + const SizedBox(height: 12), + TextField( + decoration: const InputDecoration( + labelText: "URL", + border: OutlineInputBorder(), + ), + controller: TextEditingController(text: url), + onChanged: (value) => url = value, + ), + const SizedBox(height: 12), + TextField( + decoration: InputDecoration( + labelText: "Username".tl, + border: const OutlineInputBorder(), + ), + controller: TextEditingController(text: user), + onChanged: (value) => user = value, + ), + const SizedBox(height: 12), + TextField( + decoration: InputDecoration( + labelText: "Password".tl, + border: const OutlineInputBorder(), + ), + controller: TextEditingController(text: pass), + onChanged: (value) => pass = value, + ), + const SizedBox(height: 12), + Row( + children: [ + Text("Operation".tl), + Radio( + groupValue: upload, + value: true, + onChanged: (value) { + setState(() { + upload = value!; + }); + }, + ), + Text("Upload".tl), + Radio( + groupValue: upload, + value: false, + onChanged: (value) { + setState(() { + upload = value!; + }); + }, + ), + Text("Download".tl), + ], + ), + const SizedBox(height: 16), + Center( + child: Button.filled( + isLoading: isTesting, + onPressed: () async { + var oldConfig = appdata.settings['webdav']; + appdata.settings['webdav'] = [url, user, pass]; + setState(() { + isTesting = true; + }); + var testResult = upload + ? await DataSync().uploadData() + : await DataSync().downloadData(); + if (testResult.error) { + setState(() { + isTesting = false; + }); + appdata.settings['webdav'] = oldConfig; + context.showMessage(message: testResult.errorMessage!); + return; + } + appdata.saveData(); + context.showMessage(message: "Saved".tl); + App.rootPop(); + }, + child: Text("Continue".tl), + ), + ) + ], + ).paddingHorizontal(16), + ), + ); + } +} diff --git a/lib/pages/settings/settings_page.dart b/lib/pages/settings/settings_page.dart index f574e4f..d009d89 100644 --- a/lib/pages/settings/settings_page.dart +++ b/lib/pages/settings/settings_page.dart @@ -15,6 +15,7 @@ import 'package:venera/foundation/local.dart'; import 'package:venera/foundation/log.dart'; import 'package:venera/network/app_dio.dart'; import 'package:venera/utils/data.dart'; +import 'package:venera/utils/data_sync.dart'; import 'package:venera/utils/io.dart'; import 'package:venera/utils/translations.dart'; import 'package:yaml/yaml.dart'; diff --git a/lib/utils/data.dart b/lib/utils/data.dart index 486aac8..ec55e9b 100644 --- a/lib/utils/data.dart +++ b/lib/utils/data.dart @@ -1,3 +1,4 @@ +import 'dart:convert'; import 'dart:isolate'; import 'package:venera/foundation/app.dart'; @@ -35,7 +36,7 @@ Future exportAppData() async { return cacheFile; } -Future importAppData(File file) async { +Future importAppData(File file, [bool checkVersion = false]) async { var cacheDirPath = FilePath.join(App.cachePath, 'temp_data'); var cacheDir = Directory(cacheDirPath); await Isolate.run(() { @@ -44,14 +45,21 @@ Future importAppData(File file) async { var historyFile = cacheDir.joinFile("history.db"); var localFavoriteFile = cacheDir.joinFile("local_favorite.db"); var appdataFile = cacheDir.joinFile("appdata.json"); + if(checkVersion && appdataFile.existsSync()) { + var data = jsonDecode(await appdataFile.readAsString()); + var version = data["settings"]["dataVersion"]; + if(version is int && version <= appdata.settings["dataVersion"]) { + return; + } + } if(await historyFile.exists()) { HistoryManager().close(); - await historyFile.copy(FilePath.join(App.dataPath, "history.db")); + historyFile.copySync(FilePath.join(App.dataPath, "history.db")); HistoryManager().init(); } if(await localFavoriteFile.exists()) { LocalFavoritesManager().close(); - await localFavoriteFile.copy(FilePath.join(App.dataPath, "local_favorite.db")); + localFavoriteFile.copySync(FilePath.join(App.dataPath, "local_favorite.db")); LocalFavoritesManager().init(); } if(await appdataFile.exists()) { diff --git a/lib/utils/data_sync.dart b/lib/utils/data_sync.dart new file mode 100644 index 0000000..b277ae5 --- /dev/null +++ b/lib/utils/data_sync.dart @@ -0,0 +1,205 @@ +import 'package:dio/io.dart'; +import 'package:flutter/foundation.dart'; +import 'package:venera/foundation/app.dart'; +import 'package:venera/foundation/appdata.dart'; +import 'package:venera/foundation/comic_source/comic_source.dart'; +import 'package:venera/foundation/favorites.dart'; +import 'package:venera/foundation/history.dart'; +import 'package:venera/foundation/log.dart'; +import 'package:venera/foundation/res.dart'; +import 'package:venera/network/app_dio.dart'; +import 'package:venera/utils/data.dart'; +import 'package:venera/utils/ext.dart'; +import 'package:webdav_client/webdav_client.dart' hide File; + +import 'io.dart'; + +class DataSync with ChangeNotifier { + DataSync._() { + if (isEnabled) { + downloadData(); + } + HistoryManager().addListener(onDataChanged); + LocalFavoritesManager().addListener(onDataChanged); + ComicSource.addListener(onDataChanged); + } + + void onDataChanged() { + if (isEnabled) { + uploadData(); + } + } + + static DataSync? instance; + + factory DataSync() => instance ?? (instance = DataSync._()); + + bool isDownloading = false; + + bool isUploading = false; + + bool haveWaitingTask = false; + + bool get isEnabled { + var config = appdata.settings['webdav']; + return config is List && config.isNotEmpty; + } + + List? _validateConfig() { + var config = appdata.settings['webdav']; + if (config is! List || (config.isNotEmpty && config.length != 3)) { + return null; + } + if (config.whereType().length != 3) { + return null; + } + return List.from(config); + } + + Future> uploadData() async { + if (haveWaitingTask) return const Res(true); + while (isDownloading || isUploading) { + haveWaitingTask = true; + await Future.delayed(const Duration(milliseconds: 100)); + } + haveWaitingTask = false; + isUploading = true; + notifyListeners(); + try { + var config = _validateConfig(); + if (config == null) { + return const Res.error('Invalid WebDAV configuration'); + } + if (config.isEmpty) { + return const Res(true); + } + String url = config[0]; + String user = config[1]; + String pass = config[2]; + + var proxy = await AppDio.getProxy(); + + var client = newClient( + url, + user: user, + password: pass, + adapter: IOHttpClientAdapter( + createHttpClient: () { + return HttpClient() + ..findProxy = (uri) => proxy == null ? "DIRECT" : "PROXY $proxy"; + }, + ), + ); + + try { + await client.ping(); + } catch (e) { + Log.error("Upload Data", 'Failed to connect to WebDAV server'); + return const Res.error('Failed to connect to WebDAV server'); + } + + try { + appdata.settings['dataVersion']++; + await appdata.saveData(); + var data = await exportAppData(); + var time = + (DateTime.now().millisecondsSinceEpoch ~/ 86400000).toString(); + var filename = time; + filename += '-'; + filename += appdata.settings['dataVersion'].toString(); + filename += '.venera'; + var files = await client.readDir('/'); + files = files.where((e) => e.name!.endsWith('.venera')).toList(); + var old = files.firstWhereOrNull( (e) => e.name!.startsWith("$time-")); + if (old != null) { + await client.remove(old.name!); + } + if (files.length >= 10) { + files.sort((a, b) => a.name!.compareTo(b.name!)); + await client.remove(files.first.name!); + } + await client.write(filename, await data.readAsBytes()); + Log.info("Upload Data", "Data uploaded successfully"); + return const Res(true); + } catch (e, s) { + Log.error("Upload Data", e, s); + return Res.error(e.toString()); + } + } finally { + isUploading = false; + notifyListeners(); + } + } + + Future> downloadData() async { + if (haveWaitingTask) return const Res(true); + while (isDownloading || isUploading) { + haveWaitingTask = true; + await Future.delayed(const Duration(milliseconds: 100)); + } + haveWaitingTask = false; + isDownloading = true; + notifyListeners(); + try { + var config = _validateConfig(); + if (config == null) { + return const Res.error('Invalid WebDAV configuration'); + } + if (config.isEmpty) { + return const Res(true); + } + String url = config[0]; + String user = config[1]; + String pass = config[2]; + + var proxy = await AppDio.getProxy(); + + var client = newClient( + url, + user: user, + password: pass, + adapter: IOHttpClientAdapter( + createHttpClient: () { + return HttpClient() + ..findProxy = (uri) => proxy == null ? "DIRECT" : "PROXY $proxy"; + }, + ), + ); + + try { + await client.ping(); + } catch (e) { + Log.error("Data Sync", 'Failed to connect to WebDAV server'); + return const Res.error('Failed to connect to WebDAV server'); + } + + try { + var files = await client.readDir('/'); + files.sort((a, b) => b.name!.compareTo(a.name!)); + var file = files.firstWhereOrNull((e) => e.name!.endsWith('.venera')); + var version = + file!.name!.split('-').elementAtOrNull(1)?.split('.').first; + if (version != null && int.tryParse(version) != null) { + var currentVersion = appdata.settings['dataVersion']; + if (currentVersion != null && int.parse(version) <= currentVersion) { + Log.info("Data Sync", 'No new data to download'); + return const Res(true); + } + } + Log.info("Data Sync", "Downloading data from WebDAV server"); + var localFile = File(FilePath.join(App.cachePath, file.name!)); + await client.read2File(file.name!, localFile.path); + await importAppData(localFile, true); + await localFile.delete(); + Log.info("Data Sync", "Data downloaded successfully"); + return const Res(true); + } catch (e, s) { + Log.error("Data Sync", e, s); + return Res.error(e.toString()); + } + } finally { + isDownloading = false; + notifyListeners(); + } + } +} diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index 37c71c0..e9281b4 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include @@ -28,9 +28,9 @@ void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) gtk_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "GtkPlugin"); gtk_plugin_register_with_registrar(gtk_registrar); - g_autoptr(FlPluginRegistrar) screen_retriever_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverPlugin"); - screen_retriever_plugin_register_with_registrar(screen_retriever_registrar); + g_autoptr(FlPluginRegistrar) screen_retriever_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverLinuxPlugin"); + screen_retriever_linux_plugin_register_with_registrar(screen_retriever_linux_registrar); g_autoptr(FlPluginRegistrar) sqlite3_flutter_libs_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "Sqlite3FlutterLibsPlugin"); sqlite3_flutter_libs_plugin_register_with_registrar(sqlite3_flutter_libs_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 819bf88..3b7ed15 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -7,7 +7,7 @@ list(APPEND FLUTTER_PLUGIN_LIST file_selector_linux flutter_qjs gtk - screen_retriever + screen_retriever_linux sqlite3_flutter_libs url_launcher_linux window_manager diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 9bf393f..4b07183 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -10,7 +10,7 @@ import desktop_webview_window import file_selector_macos import flutter_inappwebview_macos import path_provider_foundation -import screen_retriever +import screen_retriever_macos import share_plus import sqlite3_flutter_libs import url_launcher_macos @@ -22,7 +22,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) - ScreenRetrieverPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverPlugin")) + ScreenRetrieverMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverMacosPlugin")) SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin")) Sqlite3FlutterLibsPlugin.register(with: registry.registrar(forPlugin: "Sqlite3FlutterLibsPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) diff --git a/pubspec.lock b/pubspec.lock index 0c55483..c1c24c8 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -593,6 +593,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.0" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 + url: "https://pub.dev" + source: hosted + version: "6.0.2" photo_view: dependency: "direct main" description: @@ -888,6 +896,15 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" + webdav_client: + dependency: "direct main" + description: + path: "." + ref: "285f87f15bccd2d5d5ff443761348c6ee47b98d1" + resolved-ref: "285f87f15bccd2d5d5ff443761348c6ee47b98d1" + url: "https://github.com/wgh136/webdav_client" + source: git + version: "1.2.2" win32: dependency: transitive description: @@ -912,6 +929,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.4" + xml: + dependency: transitive + description: + name: xml + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 + url: "https://pub.dev" + source: hosted + version: "6.5.0" yaml: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 30c4f5e..5822a0a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -59,6 +59,10 @@ dependencies: url: https://github.com/venera-app/lodepng_flutter ref: d1c96cd6503103b3270dfe2f320d4a1c93780f53 rhttp: 0.9.1 + webdav_client: + git: + url: https://github.com/wgh136/webdav_client + ref: 285f87f15bccd2d5d5ff443761348c6ee47b98d1 dev_dependencies: flutter_test: diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index c2fe9ba..079a7f9 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include @@ -28,8 +28,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { registry->GetRegistrarForPlugin("FlutterInappwebviewWindowsPluginCApi")); FlutterQjsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("FlutterQjsPlugin")); - ScreenRetrieverPluginRegisterWithRegistrar( - registry->GetRegistrarForPlugin("ScreenRetrieverPlugin")); + ScreenRetrieverWindowsPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("ScreenRetrieverWindowsPluginCApi")); SharePlusWindowsPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi")); Sqlite3FlutterLibsPluginRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index d92ca11..1f31462 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -8,7 +8,7 @@ list(APPEND FLUTTER_PLUGIN_LIST file_selector_windows flutter_inappwebview_windows flutter_qjs - screen_retriever + screen_retriever_windows share_plus sqlite3_flutter_libs url_launcher_windows