diff --git a/lib/main.dart b/lib/main.dart index 2efb0a70..5b7a9966 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -13,6 +13,7 @@ import 'package:logging/logging.dart'; import 'package:overlay_support/overlay_support.dart'; import 'package:provider/provider.dart'; import 'package:tray_manager/tray_manager.dart'; +import 'package:uni_links_desktop/uni_links_desktop.dart'; import 'package:window_manager/window_manager.dart'; import 'package:zenon_syrius_wallet_flutter/blocs/blocs.dart'; import 'package:zenon_syrius_wallet_flutter/model/model.dart'; @@ -105,15 +106,16 @@ main() async { } }); + if (Platform.isWindows) { + registerProtocol('syrius'); + } + runApp( const MyApp(), ); } Future _setupTrayManager() async { - if (!Platform.isWindows) { - await trayManager.setTitle('s y r i u s'); - } await trayManager.setIcon( Platform.isWindows ? 'assets/images/tray_app_icon.ico' diff --git a/lib/widgets/main_app_container.dart b/lib/widgets/main_app_container.dart index ce179578..c368b0ba 100644 --- a/lib/widgets/main_app_container.dart +++ b/lib/widgets/main_app_container.dart @@ -1,9 +1,12 @@ import 'dart:async'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_vector_icons/flutter_vector_icons.dart'; +import 'package:logging/logging.dart'; import 'package:provider/provider.dart'; +import 'package:uni_links/uni_links.dart'; import 'package:zenon_syrius_wallet_flutter/blocs/blocs.dart'; import 'package:zenon_syrius_wallet_flutter/main.dart'; import 'package:zenon_syrius_wallet_flutter/model/model.dart'; @@ -56,6 +59,7 @@ class _MainAppContainerState extends State final NodeSyncStatusBloc _netSyncStatusBloc = NodeSyncStatusBloc(); late StreamSubscription _lockBlockStreamSubscription; + late StreamSubscription _incomingLinkSubscription; Timer? _navigateToLockTimer; @@ -70,6 +74,8 @@ class _MainAppContainerState extends State canRequestFocus: false, ); + bool _initialUriIsHandled = false; + @override void initState() { _netSyncStatusBloc.getDataPeriodically(); @@ -87,6 +93,8 @@ class _MainAppContainerState extends State _animation = Tween(begin: 1.0, end: 3.0).animate(_animationController); kCurrentPage = kWalletInitCompleted ? Tabs.dashboard : Tabs.lock; _initLockBlock(); + _handleIncomingLinks(); + _handleInitialUri(); super.initState(); } @@ -467,6 +475,7 @@ class _MainAppContainerState extends State _netSyncStatusBloc.dispose(); _navigateToLockTimer?.cancel(); _lockBlockStreamSubscription.cancel(); + _incomingLinkSubscription.cancel(); _tabController?.dispose(); super.dispose(); } @@ -630,4 +639,38 @@ class _MainAppContainerState extends State _lockBloc.addEvent(LockEvent.countDown); } } + + void _handleIncomingLinks() { + if (!kIsWeb) { + _incomingLinkSubscription = uriLinkStream.listen((Uri? uri) { + Logger('MainAppContainer') + .log(Level.INFO, '_handleIncomingLinks ${uri!.toString()}'); + if (!mounted) return; + }, onError: (Object err) { + Logger('MainAppContainer') + .log(Level.WARNING, '_handleIncomingLinks', err); + if (!mounted) return; + }); + } + } + + Future _handleInitialUri() async { + if (!_initialUriIsHandled) { + _initialUriIsHandled = true; + try { + final uri = await getInitialUri(); + if (uri != null) { + Logger('MainAppContainer').log(Level.INFO, '_handleInitialUri $uri'); + } + if (!mounted) return; + } on PlatformException catch (e, stackTrace) { + Logger('MainAppContainer').log(Level.WARNING, + '_handleInitialUri PlatformException', e, stackTrace); + } on FormatException catch (e, stackTrace) { + Logger('MainAppContainer').log( + Level.WARNING, '_handleInitialUri FormatException', e, stackTrace); + if (!mounted) return; + } + } + } } diff --git a/lib/widgets/reusable_widgets/layout_scaffold/card_scaffold.dart b/lib/widgets/reusable_widgets/layout_scaffold/card_scaffold.dart index fa900c2c..18850757 100644 --- a/lib/widgets/reusable_widgets/layout_scaffold/card_scaffold.dart +++ b/lib/widgets/reusable_widgets/layout_scaffold/card_scaffold.dart @@ -229,7 +229,7 @@ class _CardScaffoldState extends State> { Expanded( child: Text( title, - style: Theme.of(context).textTheme.bodyText1!.copyWith( + style: Theme.of(context).textTheme.bodyLarge!.copyWith( fontSize: widget.titleFontSize, height: 1.0, ), diff --git a/macos/Runner/Info.plist b/macos/Runner/Info.plist index cd4cdf19..73e2a575 100644 --- a/macos/Runner/Info.plist +++ b/macos/Runner/Info.plist @@ -26,6 +26,19 @@ $(PRODUCT_COPYRIGHT) NSMainNibFile MainMenu + CFBundleURLTypes + + + CFBundleTypeRole + Editor + CFBundleURLName + + CFBundleURLSchemes + + syrius + + + NSPrincipalClass NSApplication diff --git a/pubspec.lock b/pubspec.lock index 471bf370..389581f2 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1101,6 +1101,38 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.1" + uni_links: + dependency: "direct main" + description: + name: uni_links + sha256: "051098acfc9e26a9fde03b487bef5d3d228ca8f67693480c6f33fd4fbb8e2b6e" + url: "https://pub.dev" + source: hosted + version: "0.5.1" + uni_links_desktop: + dependency: "direct main" + description: + name: uni_links_desktop + sha256: "205484c01890259b56d9271bcf299adf9889e881616c976f13061e29e94bb9f0" + url: "https://pub.dev" + source: hosted + version: "0.1.4" + uni_links_platform_interface: + dependency: transitive + description: + name: uni_links_platform_interface + sha256: "929cf1a71b59e3b7c2d8a2605a9cf7e0b125b13bc858e55083d88c62722d4507" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + uni_links_web: + dependency: transitive + description: + name: uni_links_web + sha256: "7539db908e25f67de2438e33cc1020b30ab94e66720b5677ba6763b25f6394df" + url: "https://pub.dev" + source: hosted + version: "0.1.0" universal_io: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index e05590c9..d5a928fc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -55,6 +55,8 @@ dependencies: tray_manager: ^0.2.0 open_filex: ^4.3.2 launch_at_startup: ^0.2.1 + uni_links_desktop: ^0.1.4 + uni_links: ^0.5.1 logging: ^1.1.1 dev_dependencies: diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index bf871b3a..3e759a9d 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -28,6 +29,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi")); TrayManagerPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("TrayManagerPlugin")); + UniLinksDesktopPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("UniLinksDesktopPlugin")); UrlLauncherWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("UrlLauncherWindows")); WindowManagerPluginRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index ed4b229a..ccc2a4d4 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -9,6 +9,7 @@ list(APPEND FLUTTER_PLUGIN_LIST screen_retriever share_plus tray_manager + uni_links_desktop url_launcher_windows window_manager ) diff --git a/windows/runner/main.cpp b/windows/runner/main.cpp index 25f090a9..afc0de84 100644 --- a/windows/runner/main.cpp +++ b/windows/runner/main.cpp @@ -5,8 +5,18 @@ #include "flutter_window.h" #include "utils.h" +#include + int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, _In_ wchar_t *command_line, _In_ int show_command) { + HWND hwnd = ::FindWindow(L"FLUTTER_RUNNER_WIN32_WINDOW", L"s y r i u s"); + if (hwnd != NULL) { + DispatchToUniLinksDesktop(hwnd); + + ::ShowWindow(hwnd, SW_NORMAL); + ::SetForegroundWindow(hwnd); + return EXIT_FAILURE; + } // Attach to console when present (e.g., 'flutter run') or create a // new console when running with a debugger. if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) {