From ec6b659f381640ac97cbd4edd5a4839a670102bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Cig=C3=A1nek?= Date: Wed, 6 Sep 2023 16:13:46 +0200 Subject: [PATCH 1/3] Enable repo mounting on linux --- lib/app/app.dart | 31 +++++++--- lib/app/cubits/cubits.dart | 20 ++++--- lib/app/cubits/mount.dart | 22 ++++--- lib/app/pages/main_page.dart | 59 ++++++++++++------ lib/app/utils/settings.dart | 40 ++++++++++--- .../modal_repository_creation_dialog.dart | 6 +- lib/app/widgets/settings/logs_section.dart | 53 ++++++++-------- lib/main.dart | 2 +- pubspec.lock | 60 +++++++++++-------- pubspec.yaml | 4 +- 10 files changed, 184 insertions(+), 113 deletions(-) diff --git a/lib/app/app.dart b/lib/app/app.dart index 499b96572..a78699d0c 100644 --- a/lib/app/app.dart +++ b/lib/app/app.dart @@ -31,6 +31,20 @@ Future initOuiSyncApp(List args, String appSuffix) async { logPath: logPath, ); + // NOTE: When the app exits, the `State.dispose()` methods are not guaranteed to be called for + // some reason. To ensure resources are properly disposed of, we need to do it via this lifecycle + // listener. + // NOTE: The lifecycle listener itself is never `dispose`d but that's OK because it's supposed to + // live as long as the app itself. + AppLifecycleListener( + onExitRequested: () async { + await session.dispose(); + windowManager.dispose(); + + return AppExitResponse.exit; + }, + ); + // Make sure to only output logs after Session is created (which sets up the log subscriber), // otherwise the logs will go nowhere. Loggy.initLoggy(logPrinter: AppLogPrinter()); @@ -153,14 +167,12 @@ class _OuiSyncAppState extends State with AppLogger { @override void dispose() { _mediaReceiver.dispose(); - - widget.windowManager.dispose(); - super.dispose(); } @override Widget build(BuildContext context) { + // TODO: We are recreating this on every rebuild. Is that what we want? final upgradeExists = UpgradeExistsCubit( widget.session.currentProtocolVersion, widget.settings); @@ -189,12 +201,13 @@ class _OuiSyncAppState extends State with AppLogger { loggy.app('Drop exited: ${detail.localPosition}'); }, child: MainPage( - session: widget.session, - upgradeExists: upgradeExists, - backgroundServiceManager: _backgroundServiceManager, - mediaReceiver: _mediaReceiver, - settings: widget.settings, - windowManager: widget.windowManager))), + session: widget.session, + upgradeExists: upgradeExists, + backgroundServiceManager: _backgroundServiceManager, + mediaReceiver: _mediaReceiver, + settings: widget.settings, + windowManager: widget.windowManager, + ))), ); } } diff --git a/lib/app/cubits/cubits.dart b/lib/app/cubits/cubits.dart index f9b349450..8d099c0d0 100644 --- a/lib/app/cubits/cubits.dart +++ b/lib/app/cubits/cubits.dart @@ -1,5 +1,3 @@ -import 'dart:io' as io; - import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -36,20 +34,24 @@ class Cubits { final UpgradeExistsCubit upgradeExists; final BackgroundServiceManager backgroundServiceManager; final PlatformWindowManager windowManager; - // Is not null only on operating system where mounting is supported. - final MountCubit? mount; + final MountCubit mount; - Cubits(this.repositories, this.powerControl, this.panicCounter, - this.upgradeExists, this.backgroundServiceManager, this.windowManager) - : mount = - (io.Platform.isWindows) ? MountCubit(repositories.session) : null; + Cubits({ + required this.repositories, + required this.powerControl, + required this.panicCounter, + required this.upgradeExists, + required this.backgroundServiceManager, + required this.windowManager, + required this.mount, + }); Color? mainNotificationBadgeColor() { final upgradeExists = this.upgradeExists.state; final panicCount = panicCounter.state ?? 0; final isNetworkEnabled = powerControl.state.isNetworkEnabled ?? true; final showWarning = backgroundServiceManager.showWarning(); - final mountState = mount?.state; + final mountState = mount.state; if (upgradeExists || panicCount > 0 || mountState is MountStateError) { return Constants.errorColor; diff --git a/lib/app/cubits/mount.dart b/lib/app/cubits/mount.dart index 0e041509c..e8d401350 100644 --- a/lib/app/cubits/mount.dart +++ b/lib/app/cubits/mount.dart @@ -6,6 +6,8 @@ import '../utils/log.dart'; class MountState {} +class MountStateDisabled extends MountState {} + class MountStateMounting extends MountState {} class MountStateSuccess extends MountState {} @@ -17,16 +19,22 @@ class MountStateError extends MountState { } class MountCubit extends Cubit with AppLogger { - MountCubit(oui.Session session) : super(MountStateMounting()) { - unawaited(_mountFileSystem(session)); - } + final oui.Session session; + + MountCubit(this.session) : super(MountStateDisabled()); + + Future mount(String mountPoint) async { + emit(MountStateMounting()); - Future _mountFileSystem(oui.Session session) async { try { - await session.mountAllRepositories("O:"); + await session.mountAllRepositories(mountPoint); emit(MountStateSuccess()); - } on oui.Error catch (error) { - loggy.app("Failed to mount repositories ${error.code}: ${error.message}"); + } on oui.Error catch (error, st) { + loggy.error( + 'Failed to mount repositories at $mountPoint:', + error.message, + st, + ); emit(MountStateError(error.code, error.message)); } } diff --git a/lib/app/pages/main_page.dart b/lib/app/pages/main_page.dart index 1958d5404..11d0d3da1 100644 --- a/lib/app/pages/main_page.dart +++ b/lib/app/pages/main_page.dart @@ -26,13 +26,14 @@ typedef MoveEntryCallback = void Function( String origin, String path, EntryType type); class MainPage extends StatefulWidget { - const MainPage( - {required this.session, - required this.upgradeExists, - required this.backgroundServiceManager, - required this.mediaReceiver, - required this.settings, - required this.windowManager}); + const MainPage({ + required this.session, + required this.upgradeExists, + required this.backgroundServiceManager, + required this.mediaReceiver, + required this.settings, + required this.windowManager, + }); final Session session; final UpgradeExistsCubit upgradeExists; @@ -42,8 +43,13 @@ class MainPage extends StatefulWidget { final PlatformWindowManager windowManager; @override - State createState() => _MainPageState(session, upgradeExists, - backgroundServiceManager, settings, windowManager); + State createState() => _MainPageState( + session, + upgradeExists, + backgroundServiceManager, + settings, + windowManager, + ); } class _MainPageState extends State @@ -63,23 +69,38 @@ class _MainPageState extends State _MainPageState._(this._cubits); factory _MainPageState( - Session session, - UpgradeExistsCubit upgradeExists, - BackgroundServiceManager backgroundServiceManager, - Settings settings, - PlatformWindowManager windowManager) { + Session session, + UpgradeExistsCubit upgradeExists, + BackgroundServiceManager backgroundServiceManager, + Settings settings, + PlatformWindowManager windowManager, + ) { final repositories = ReposCubit( session: session, settings: settings, ); final powerControl = PowerControl(session, settings); final panicCounter = StateMonitorIntCubit( - repositories.rootStateMonitor - .child(oui.MonitorId.expectUnique("Session")), - "panic_counter"); + repositories.rootStateMonitor + .child(oui.MonitorId.expectUnique("Session")), + "panic_counter", + ); + + final mount = MountCubit(session); + final mountPoint = settings.getMountPoint(); + if (mountPoint != null) { + unawaited(mount.mount(mountPoint)); + } - return _MainPageState._(Cubits(repositories, powerControl, panicCounter, - upgradeExists, backgroundServiceManager, windowManager)); + return _MainPageState._(Cubits( + repositories: repositories, + powerControl: powerControl, + panicCounter: panicCounter, + upgradeExists: upgradeExists, + backgroundServiceManager: backgroundServiceManager, + windowManager: windowManager, + mount: mount, + )); } RepoEntry? get _currentRepo => _cubits.repositories.currentRepo; diff --git a/lib/app/utils/settings.dart b/lib/app/utils/settings.dart index 4c92b550c..dc773f77c 100644 --- a/lib/app/utils/settings.dart +++ b/lib/app/utils/settings.dart @@ -1,4 +1,4 @@ -import 'dart:io' as io show Directory, Platform; +import 'dart:io' show Directory, Platform; import 'package:path/path.dart' as p; import 'package:path_provider/path_provider.dart' as path_provider; @@ -13,7 +13,7 @@ class SettingsRepoEntry { RepoMetaInfo info; String get name => info.name; - io.Directory get dir => info.dir; + Directory get dir => info.dir; SettingsRepoEntry(this.databaseId, this.info); } @@ -70,6 +70,9 @@ class Settings with AppLogger { // directory and moved everything there into this settings. static const String _legacyReposIncluded = "LEGACY_REPOS_INCLUDED"; + // Path to mount repositories at + static const String _mountPoint = "MOUNT_POINT"; + final SharedPreferences _prefs; final _CachedString _defaultRepo; @@ -140,7 +143,7 @@ class Settings with AppLogger { await _prefs.setBool(_launchAtStartup, value); } - Future defaultRepoLocation() async { + Future defaultRepoLocation() async { try { // Docs says this throws on non Android systems. // https://pub.dev/documentation/path_provider/latest/path_provider/getExternalStorageDirectory.html @@ -160,7 +163,7 @@ class Settings with AppLogger { // also gets deleted when the app is un/re-installed. final alternativeDir = await path_provider.getApplicationDocumentsDirectory(); - if (io.Platform.isAndroid) { + if (Platform.isAndroid) { return alternativeDir; } @@ -168,7 +171,7 @@ class Settings with AppLogger { final nonAndroidAlternativePath = context.join(alternativeDir.path, 'ouisync'); - final documents = await io.Directory(nonAndroidAlternativePath).create(); + final documents = await Directory(nonAndroidAlternativePath).create(); return documents; } @@ -196,7 +199,7 @@ class Settings with AppLogger { RepoMetaInfo? repoMetaInfo(String repoName) { final dir = _repos[repoName]; if (dir == null) return null; - return RepoMetaInfo.fromDirAndName(io.Directory(dir), repoName); + return RepoMetaInfo.fromDirAndName(Directory(dir), repoName); } Future setDefaultRepo(String? name) async { @@ -232,7 +235,9 @@ class Settings with AppLogger { await forgetRepository(oldName); return SettingsRepoEntry( - databaseId, RepoMetaInfo.fromDirAndName(io.Directory(path), newName)); + databaseId, + RepoMetaInfo.fromDirAndName(Directory(path), newName), + ); } Future addRepo( @@ -302,6 +307,9 @@ class Settings with AppLogger { await _setRepositoryString(repoName, _authenticationMode, str); } + String? getMountPoint() => + _prefs.getString(_mountPoint) ?? _defaultMountPoint(); + // Read and remove a bool property. This functions exists to facilitate migration to the new // repository config system where config values are stored in the repository metadata. bool? takeRepositoryBool(String repoName, String key) { @@ -349,7 +357,7 @@ class Settings with AppLogger { // We used to have all the repositories in a single place in the internal // memory. The disadvantage was that the user had no access to them and // thus couldn't back them up or put them on an SD card. - final dir = io.Directory(p.join( + final dir = Directory(p.join( (await path_provider.getApplicationSupportDirectory()).path, Constants.folderRepositoriesName)); @@ -397,3 +405,19 @@ class _CachedString { } } } + +String? _defaultMountPoint() { + if (Platform.isLinux || Platform.isMacOS) { + final home = Platform.environment['HOME']; + + if (home == null) { + return null; + } + + return '$home/Ouisync'; + } else if (Platform.isWindows) { + return 'O:'; + } else { + return null; + } +} diff --git a/lib/app/widgets/dialogs/modal_repository_creation_dialog.dart b/lib/app/widgets/dialogs/modal_repository_creation_dialog.dart index 130e7700f..707f4e2e1 100644 --- a/lib/app/widgets/dialogs/modal_repository_creation_dialog.dart +++ b/lib/app/widgets/dialogs/modal_repository_creation_dialog.dart @@ -198,12 +198,8 @@ class RepositoryCreation extends HookWidget with AppLogger { try { shareToken = await ShareToken.fromString(cubit.session, initialToken); - - if (shareToken == null) { - throw "Failed to construct the token from \"$initialToken\""; - } } catch (e, st) { - loggy.app('Extract repository token exception', e, st); + loggy.error('Extract repository token exception:', e, st); showSnackBar(context, message: S.current.messageErrorTokenInvalid); } diff --git a/lib/app/widgets/settings/logs_section.dart b/lib/app/widgets/settings/logs_section.dart index 90469bc6a..6a2b3ae89 100644 --- a/lib/app/widgets/settings/logs_section.dart +++ b/lib/app/widgets/settings/logs_section.dart @@ -71,32 +71,31 @@ class LogsSection extends SettingsSection with AppLogger { return _warningTile( context, S.current.messageMissingBackgroundServicePermission); }), - if (mountCubit != null) - BlocBuilder( - bloc: mountCubit, - builder: (context, error) { - if (error is! MountStateError) { - return SizedBox.shrink(); - } - - String reason; - Widget? trailing; - void Function()? onTap; - - if (error.code == oui.ErrorCode.vfsDriverInstall) { - reason = - S.current.messageErrorDokanNotInstalled(Constants.dokanUrl); - trailing = Icon(Icons.open_in_browser); - onTap = () { - unawaited(launchUrl(Uri.parse(Constants.dokanUrl))); - }; - } else { - reason = error.message; - } - - return _errorTile(context, S.current.messageFailedToMount(reason), - trailing: trailing, onTap: onTap); - }) + BlocBuilder( + bloc: mountCubit, + builder: (context, error) { + if (error is! MountStateError) { + return SizedBox.shrink(); + } + + String reason; + Widget? trailing; + void Function()? onTap; + + if (error.code == oui.ErrorCode.vfsDriverInstall) { + reason = + S.current.messageErrorDokanNotInstalled(Constants.dokanUrl); + trailing = Icon(Icons.open_in_browser); + onTap = () { + unawaited(launchUrl(Uri.parse(Constants.dokanUrl))); + }; + } else { + reason = error.message; + } + + return _errorTile(context, S.current.messageFailedToMount(reason), + trailing: trailing, onTap: onTap); + }) ]; } @@ -120,7 +119,7 @@ class LogsSection extends SettingsSection with AppLogger { @override bool containsErrorNotification() { return (_cubits.panicCounter.state ?? 0) > 0 || - _cubits.mount?.state is MountStateError; + _cubits.mount.state is MountStateError; } @override diff --git a/lib/main.dart b/lib/main.dart index ff76034a0..78c5a0c25 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -9,7 +9,7 @@ Future main(List args) async { const appSuffix = String.fromEnvironment('DEV_SUFFIX'); final dsn = Env.ouisyncDSN; - + await setupSentry( () async => runApp(await initOuiSyncApp(args, appSuffix)), dsn); } diff --git a/pubspec.lock b/pubspec.lock index c5a49e659..d93e4ccb5 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -109,10 +109,10 @@ packages: dependency: transitive description: name: build_daemon - sha256: "757153e5d9cd88253cb13f28c2fb55a537dc31fefd98137549895b5beb7c6169" + sha256: "5f02d73eb2ba16483e693f80bee4f088563a820e47d1027d4cdfe62b5bb43e65" url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "4.0.0" build_resolvers: dependency: transitive description: @@ -122,13 +122,13 @@ packages: source: hosted version: "2.2.0" build_runner: - dependency: "direct main" + dependency: "direct dev" description: name: build_runner - sha256: b0a8a7b8a76c493e85f1b84bffa0588859a06197863dba8c9036b15581fd9727 + sha256: "10c6bcdbf9d049a0b666702cf1cee4ddfdc38f02a19d35ae392863b47519848b" url: "https://pub.dev" source: hosted - version: "2.3.3" + version: "2.4.6" build_runner_core: dependency: transitive description: @@ -197,10 +197,10 @@ packages: dependency: "direct main" description: name: collection - sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" + sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 url: "https://pub.dev" source: hosted - version: "1.17.1" + version: "1.17.2" connectivity_plus: dependency: "direct main" description: @@ -301,10 +301,10 @@ packages: dependency: "direct main" description: name: desktop_webview_window - sha256: da2fc164b46257c7a8b88649d3f2b34b4d98e7b7c403fb9e4183ebe8ff008004 + sha256: "57cf20d81689d5cbb1adfd0017e96b669398a669d927906073b0e42fc64111c0" url: "https://pub.dev" source: hosted - version: "0.2.0" + version: "0.2.3" diff_match_patch: dependency: transitive description: @@ -642,10 +642,10 @@ packages: dependency: "direct main" description: name: intl - sha256: a3715e3bc90294e971cb7dc063fbf3cd9ee0ebf8604ffeafabd9e6f16abbdbe6 + sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" url: "https://pub.dev" source: hosted - version: "0.18.0" + version: "0.18.1" intl_utils: dependency: "direct dev" description: @@ -779,18 +779,18 @@ packages: dependency: transitive description: name: matcher - sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" url: "https://pub.dev" source: hosted - version: "0.12.15" + version: "0.12.16" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" url: "https://pub.dev" source: hosted - version: "0.2.0" + version: "0.5.0" menu_base: dependency: transitive description: @@ -827,10 +827,10 @@ packages: dependency: "direct main" description: name: mockito - sha256: dd61809f04da1838a680926de50a9e87385c1de91c6579629c3d1723946e8059 + sha256: "8b46d7eb40abdda92d62edd01546051f0c27365e65608c284de336dccfef88cc" url: "https://pub.dev" source: hosted - version: "5.4.0" + version: "5.4.1" mocktail: dependency: transitive description: @@ -1353,10 +1353,10 @@ packages: dependency: transitive description: name: source_span - sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.10.0" stack_trace: dependency: transitive description: @@ -1417,26 +1417,26 @@ packages: dependency: transitive description: name: test - sha256: "3dac9aecf2c3991d09b9cdde4f98ded7b30804a88a0d7e4e7e1678e78d6b97f4" + sha256: "13b41f318e2a5751c3169137103b60c584297353d4b1761b66029bae6411fe46" url: "https://pub.dev" source: hosted - version: "1.24.1" + version: "1.24.3" test_api: dependency: transitive description: name: test_api - sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb + sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" url: "https://pub.dev" source: hosted - version: "0.5.1" + version: "0.6.0" test_core: dependency: transitive description: name: test_core - sha256: "5138dbffb77b2289ecb12b81c11ba46036590b72a64a7a90d6ffb880f1a29e93" + sha256: "99806e9e6d95c7b059b7a0fc08f07fc53fabe54a829497f0d9676299f1e8637e" url: "https://pub.dev" source: hosted - version: "0.5.1" + version: "0.5.3" timing: dependency: transitive description: @@ -1573,6 +1573,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" + web: + dependency: transitive + description: + name: web + sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 + url: "https://pub.dev" + source: hosted + version: "0.1.4-beta" web_socket_channel: dependency: transitive description: @@ -1686,5 +1694,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.0.0 <4.0.0" + dart: ">=3.1.0-185.0.dev <4.0.0" flutter: ">=3.7.0" diff --git a/pubspec.yaml b/pubspec.yaml index 99fb0b185..ca62e9384 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -28,13 +28,12 @@ dependencies: badges: ^2.0.2 biometric_storage: ^4.1.3 bloc_test: ^9.0.3 - build_runner: ^2.1.7 collection: ^1.16.0 connectivity_plus: ^4.0.1 cross_file: ^0.3.3 cupertino_icons: ^1.0.4 desktop_drop: ^0.4.1 - desktop_webview_window: ^0.2.0 + desktop_webview_window: ^0.2.3 dns_client: ^0.2.1 envied: ^0.3.0+3 equatable: ^2.0.3 @@ -111,6 +110,7 @@ dependency_overrides: dev_dependencies: args: ^2.4.2 + build_runner: ^2.4.6 date_format: ^2.0.7 envied_generator: ^0.3.0+3 flutter_test: From 4e1263b3c2c9704d21938adbb5a21bf2de89c5b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Cig=C3=A1nek?= Date: Wed, 6 Sep 2023 17:14:04 +0200 Subject: [PATCH 2/3] Implement file preview on all desktop platforms using url_launcher --- lib/app/pages/main_page.dart | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/lib/app/pages/main_page.dart b/lib/app/pages/main_page.dart index 11d0d3da1..e890c3047 100644 --- a/lib/app/pages/main_page.dart +++ b/lib/app/pages/main_page.dart @@ -8,6 +8,7 @@ import 'package:move_to_background/move_to_background.dart'; import 'package:ouisync_plugin/ouisync_plugin.dart'; import 'package:ouisync_plugin/state_monitor.dart' as oui; import 'package:receive_sharing_intent/receive_sharing_intent.dart'; +import 'package:url_launcher/url_launcher.dart'; import '../../generated/l10n.dart'; import '../cubits/cubits.dart'; @@ -466,24 +467,27 @@ class _MainPageState extends State ); } - Future _previewFile( - RepoCubit repo, FileItem item, String authority) async { + Future _previewFile(RepoCubit repo, FileItem item) async { if (io.Platform.isAndroid) { + // TODO: Consider using `launchUrl` also here, using the 'content://' scheme. + await NativeChannels.previewOuiSyncFile( - authority, + Constants.androidAppAuthority, item.path, item.size ?? 0, useDefaultApp: true, ); - } else if (io.Platform.isWindows) { + } else if (io.Platform.isWindows || + io.Platform.isLinux || + io.Platform.isMacOS) { final mountedDirectory = repo.mountedDirectory(); if (mountedDirectory == null) { showSnackBar(context, message: S.current.messageRepositoryNotMounted); return; } - var result = await io.Process.run( - 'cmd', ['/c', 'start', '', '$mountedDirectory${item.path}']); - loggy.app(result.stdout); + + final url = Uri.parse('file:$mountedDirectory${item.path}'); + await launchUrl(url); } else { // Only the above platforms are supported right now. showSnackBar(context, message: S.current.messageFilePreviewNotAvailable); @@ -513,8 +517,7 @@ class _MainPageState extends State return; } - await _previewFile( - currentRepo, item, Constants.androidAppAuthority); + await _previewFile(currentRepo, item); }; } else if (item is FolderItem) { actionByType = () { From 771119109476bc510d0739eaa5cf2982895e57e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Cig=C3=A1nek?= Date: Thu, 7 Sep 2023 12:13:13 +0200 Subject: [PATCH 3/3] Update ouisync-plugin --- ouisync-plugin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ouisync-plugin b/ouisync-plugin index c210b88c7..661025b82 160000 --- a/ouisync-plugin +++ b/ouisync-plugin @@ -1 +1 @@ -Subproject commit c210b88c77b67790ef1c2f6fcf9c216d6eb0dcba +Subproject commit 661025b8248fc2139edf24743a39fa0b01c87913