diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 8be03dcb..ab776f4a 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -29,6 +29,12 @@ + + + + + + + diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index 0b252ec9..a91210cc 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -1,6 +1,7 @@ import UIKit import Flutter import Libmtorrentserver +import app_links @main @objc class AppDelegate: FlutterAppDelegate { @@ -29,6 +30,12 @@ import Libmtorrentserver }) GeneratedPluginRegistrant.register(with: self) + + if let url = AppLinks.shared.getLink(launchOptions: launchOptions) { + AppLinks.shared.handleLink(url: url) + return true + } + return super.application(application, didFinishLaunchingWithOptions: launchOptions) } } diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 8ff0c8a6..fccc5fe8 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -62,5 +62,7 @@ UISupportsDocumentBrowser + FlutterDeepLinkingEnabled + diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 9e0033af..010fb536 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -416,5 +416,6 @@ "remove_extensions_repo": "Repository-Link entfernen", "manage_manga_repo_url": "Verwalte Repository-Links für Manga", "manage_anime_repo_url": "Verwalte Repository-Links für Anime", - "manage_novel_repo_url": "Verwalte Repository-Links für Novellen" + "manage_novel_repo_url": "Verwalte Repository-Links für Novellen", + "repo_added": "Erweiterungs-Repository hinzugefügt!" } \ No newline at end of file diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index bc700159..8204e7a0 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -428,5 +428,6 @@ "invalid_url_format": "Invalid URL format", "clear_all_sources": "Clear all sources", "clear_all_sources_msg": "This will completely erase all sources of the application. Are you sure you want to continue?", - "sources_cleared": "Sources cleared!!!" + "sources_cleared": "Sources cleared!!!", + "repo_added": "Source repository added!" } \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 4a068d83..65e7e54c 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,6 @@ +import 'dart:async'; import 'dart:io'; +import 'package:app_links/app_links.dart'; import 'package:bot_toast/bot_toast.dart'; import 'package:desktop_webview_window/desktop_webview_window.dart'; import 'package:flex_color_scheme/flex_color_scheme.dart'; @@ -10,8 +12,12 @@ import 'package:google_fonts/google_fonts.dart'; import 'package:intl/date_symbol_data_local.dart'; import 'package:intl/intl.dart'; import 'package:isar/isar.dart'; +import 'package:mangayomi/eval/model/m_bridge.dart'; +import 'package:mangayomi/models/manga.dart'; +import 'package:mangayomi/models/settings.dart'; import 'package:mangayomi/modules/more/data_and_storage/providers/storage_usage.dart'; import 'package:mangayomi/modules/more/settings/appearance/providers/app_font_family.dart'; +import 'package:mangayomi/modules/more/settings/browse/providers/browse_state_provider.dart'; import 'package:mangayomi/providers/l10n_providers.dart'; import 'package:mangayomi/providers/storage_provider.dart'; import 'package:mangayomi/router/router.dart'; @@ -21,6 +27,7 @@ import 'package:mangayomi/modules/more/settings/appearance/providers/pure_black_ import 'package:mangayomi/modules/more/settings/appearance/providers/theme_mode_state_provider.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:mangayomi/src/rust/frb_generated.dart'; +import 'package:mangayomi/utils/url_protocol/api.dart'; import 'package:media_kit/media_kit.dart'; import 'package:path_provider/path_provider.dart'; import 'package:window_manager/window_manager.dart'; @@ -40,6 +47,9 @@ void main(List args) async { if (!(Platform.isAndroid || Platform.isIOS)) { await windowManager.ensureInitialized(); } + if (Platform.isWindows) { + registerProtocolHandler("mangayomi"); + } if (!kIsWeb && defaultTargetPlatform == TargetPlatform.windows) { final availableVersion = await WebViewEnvironment.getAvailableVersion(); if (availableVersion != null) { @@ -73,9 +83,13 @@ class MyApp extends ConsumerStatefulWidget { } class _MyAppState extends ConsumerState { + late AppLinks _appLinks; + StreamSubscription? _linkSubscription; + @override void initState() { iniDateFormatting(); + initDeepLinks(); WidgetsBinding.instance.addPostFrameCallback((_) { if (ref.read(clearChapterCacheOnAppLaunchStateProvider)) { ref @@ -145,4 +159,55 @@ class _MyAppState extends ConsumerState { title: 'MangaYomi', ); } + + @override + void dispose() { + _linkSubscription?.cancel(); + super.dispose(); + } + + Future initDeepLinks() async { + final l10n = l10nLocalizations(context); + _appLinks = AppLinks(); + _linkSubscription = _appLinks.uriLinkStream.listen((uri) { + switch (uri.host) { + case "add-repo": + final repoName = uri.queryParameters["repo_name"]; + final repoUrl = uri.queryParameters["repo_url"]; + final mangaRepoUrls = uri.queryParametersAll["manga_url"]; + final animeRepoUrls = uri.queryParametersAll["anime_url"]; + final novelRepoUrls = uri.queryParametersAll["novel_url"]; + if (mangaRepoUrls != null) { + final mangaRepos = + ref.read(extensionsRepoStateProvider(ItemType.manga)).toList(); + mangaRepos.addAll(mangaRepoUrls.map( + (e) => Repo(name: repoName, jsonUrl: e, website: repoUrl))); + ref + .read(extensionsRepoStateProvider(ItemType.manga).notifier) + .set(mangaRepos); + } + if (animeRepoUrls != null) { + final animeRepos = + ref.read(extensionsRepoStateProvider(ItemType.anime)).toList(); + animeRepos.addAll(animeRepoUrls.map( + (e) => Repo(name: repoName, jsonUrl: e, website: repoUrl))); + ref + .read(extensionsRepoStateProvider(ItemType.anime).notifier) + .set(animeRepos); + } + if (novelRepoUrls != null) { + final novelRepos = + ref.read(extensionsRepoStateProvider(ItemType.novel)).toList(); + novelRepos.addAll(novelRepoUrls.map( + (e) => Repo(name: repoName, jsonUrl: e, website: repoUrl))); + ref + .read(extensionsRepoStateProvider(ItemType.novel).notifier) + .set(novelRepos); + } + botToast(l10n?.repo_added ?? "Source repository added!"); + break; + default: + } + }); + } } diff --git a/lib/modules/main_view/providers/migration.dart b/lib/modules/main_view/providers/migration.dart index d1cf5042..05ec080a 100644 --- a/lib/modules/main_view/providers/migration.dart +++ b/lib/modules/main_view/providers/migration.dart @@ -1,5 +1,6 @@ import 'package:isar/isar.dart'; import 'package:mangayomi/main.dart'; +import 'package:mangayomi/models/category.dart'; import 'package:mangayomi/models/history.dart'; import 'package:mangayomi/models/manga.dart'; import 'package:mangayomi/models/source.dart'; @@ -12,6 +13,8 @@ part 'migration.g.dart'; Future migration(Ref ref) async { final mangas = isar.mangas.filter().idIsNotNull().isMangaIsNotNull().findAllSync(); + final categories = + isar.categorys.filter().idIsNotNull().forMangaIsNotNull().findAllSync(); final histories = isar.historys .filter() @@ -43,6 +46,9 @@ Future migration(Ref ref) async { for (var manga in mangas) { isar.mangas.putSync(manga..itemType = _convertToItemType(manga.isManga!)); } + for (var category in categories) { + isar.categorys.putSync(category..forItemType = _convertToItemType(category.forManga!)); + } }); } diff --git a/lib/modules/more/data_and_storage/providers/restore.dart b/lib/modules/more/data_and_storage/providers/restore.dart index 87e30139..b3626d4e 100644 --- a/lib/modules/more/data_and_storage/providers/restore.dart +++ b/lib/modules/more/data_and_storage/providers/restore.dart @@ -203,7 +203,7 @@ ItemType _convertToItemType(Map backup) { ItemType _convertToItemTypeCategory(Map backup) { final forManga = backup['forManga']; return forManga == null - ? ItemType.values[backup['itemType'] ?? 0] + ? ItemType.values[backup['forItemType'] ?? 0] : forManga ? ItemType.manga : ItemType.anime; diff --git a/lib/utils/url_protocol/api.dart b/lib/utils/url_protocol/api.dart new file mode 100644 index 00000000..2813ae61 --- /dev/null +++ b/lib/utils/url_protocol/api.dart @@ -0,0 +1,42 @@ +import 'windows_protocol.dart' + if (dart.library.js_interop) 'web_url_protocol.dart'; + +/// Registers a protocol by [scheme] to allow for links in the form `://...` +/// to be processed by this application. By default, opening a link will open +/// the executable that was used to register the scheme with the URL as the first +/// argument passed to the executable. +/// +/// If a protocol is already registered for the given scheme, this function will +/// attempt to overwrite the previous handler with the current executable information. +/// However, note that depending on process permissions, this operation may be +/// disallowed by the underlying platform. +/// +/// You may pass an [executable] to override the path to the executable to run +/// when accessing the URL. +/// +/// [arguments] is a list of arguments to be used when running the executable. +/// If passed, the list must contain at least one element, and at least one of +/// those elements must contain the literal value `%s` to denote the URL to open. +/// Quoting arguments is not necessary, as this will be handled for you. +/// Escaping the `%s` as an unprocessed literal is currently unsupported. +void registerProtocolHandler( + String scheme, { + String? executable, + List? arguments, +}) { + WindowsProtocolHandler().register( + scheme, + executable: executable, + arguments: arguments, + ); +} + +/// Unregisters the protocol handler with the underlying platform. The provided +/// [scheme] will no longer be used in links. +/// +/// Note that this will unregister a protocol by scheme regardless of which process +/// had registered it. Unregistering a scheme that was not registered by this +/// application is undefined and depends on platform-specific restrictions. +void unregisterProtocolHandler(String scheme) { + WindowsProtocolHandler().unregister(scheme); +} \ No newline at end of file diff --git a/lib/utils/url_protocol/protocol.dart b/lib/utils/url_protocol/protocol.dart new file mode 100644 index 00000000..42368ca9 --- /dev/null +++ b/lib/utils/url_protocol/protocol.dart @@ -0,0 +1,15 @@ +abstract class ProtocolHandler { + void register(String scheme, {String? executable, List? arguments}); + + void unregister(String scheme); + + List getArguments(List? arguments) { + if (arguments == null) return ['%s']; + + if (arguments.isEmpty && !arguments.any((e) => e.contains('%s'))) { + throw ArgumentError('arguments must contain at least 1 instance of "%s"'); + } + + return arguments; + } +} \ No newline at end of file diff --git a/lib/utils/url_protocol/web_url_protocol.dart b/lib/utils/url_protocol/web_url_protocol.dart new file mode 100644 index 00000000..1f2bdee0 --- /dev/null +++ b/lib/utils/url_protocol/web_url_protocol.dart @@ -0,0 +1,9 @@ +import './protocol.dart'; + +class WindowsProtocolHandler extends ProtocolHandler { + @override + void register(String scheme, {String? executable, List? arguments}) {} + + @override + void unregister(String scheme) {} +} \ No newline at end of file diff --git a/lib/utils/url_protocol/windows_protocol.dart b/lib/utils/url_protocol/windows_protocol.dart new file mode 100644 index 00000000..647389c8 --- /dev/null +++ b/lib/utils/url_protocol/windows_protocol.dart @@ -0,0 +1,65 @@ +import 'dart:io'; + +import 'package:ffi/ffi.dart'; +import 'package:flutter/foundation.dart'; +import 'package:win32/win32.dart'; + +import './protocol.dart'; + +const _hive = HKEY_CURRENT_USER; + +class WindowsProtocolHandler extends ProtocolHandler { + @override + void register(String scheme, {String? executable, List? arguments}) { + if (defaultTargetPlatform != TargetPlatform.windows) return; + + final prefix = _regPrefix(scheme); + final capitalized = scheme[0].toUpperCase() + scheme.substring(1); + final args = getArguments(arguments).map((a) => _sanitize(a)); + final cmd = + '${executable ?? Platform.resolvedExecutable} ${args.join(' ')}'; + + _regCreateStringKey(_hive, prefix, '', 'URL:$capitalized'); + _regCreateStringKey(_hive, prefix, 'URL Protocol', ''); + _regCreateStringKey(_hive, '$prefix\\shell\\open\\command', '', cmd); + } + + @override + void unregister(String scheme) { + if (defaultTargetPlatform != TargetPlatform.windows) return; + + final txtKey = TEXT(_regPrefix(scheme)); + try { + RegDeleteTree(HKEY_CURRENT_USER, txtKey); + } finally { + free(txtKey); + } + } + + String _regPrefix(String scheme) => 'SOFTWARE\\Classes\\$scheme'; + + int _regCreateStringKey(int hKey, String key, String valueName, String data) { + final txtKey = TEXT(key); + final txtValue = TEXT(valueName); + final txtData = TEXT(data); + try { + return RegSetKeyValue( + hKey, + txtKey, + txtValue, + REG_VALUE_TYPE.REG_SZ, + txtData, + txtData.length * 2 + 2, + ); + } finally { + free(txtKey); + free(txtValue); + free(txtData); + } + } + + String _sanitize(String value) { + value = value.replaceAll(r'%s', '%1').replaceAll(r'"', '\\"'); + return '"$value"'; + } +} \ No newline at end of file diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index 67266b0e..3ebc68a6 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -23,6 +24,9 @@ void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) flutter_qjs_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterQjsPlugin"); flutter_qjs_plugin_register_with_registrar(flutter_qjs_registrar); + g_autoptr(FlPluginRegistrar) gtk_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "GtkPlugin"); + gtk_plugin_register_with_registrar(gtk_registrar); g_autoptr(FlPluginRegistrar) isar_flutter_libs_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "IsarFlutterLibsPlugin"); isar_flutter_libs_plugin_register_with_registrar(isar_flutter_libs_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index b3ff0c98..42ba288c 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -5,6 +5,7 @@ list(APPEND FLUTTER_PLUGIN_LIST desktop_webview_window flutter_qjs + gtk isar_flutter_libs media_kit_libs_linux media_kit_video diff --git a/linux/my_application.cc b/linux/my_application.cc index 1ae9414d..181a34de 100644 --- a/linux/my_application.cc +++ b/linux/my_application.cc @@ -17,6 +17,13 @@ G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) // Implements GApplication::activate. static void my_application_activate(GApplication* application) { MyApplication* self = MY_APPLICATION(application); + + GList* windows = gtk_application_get_windows(GTK_APPLICATION(application)); + if (windows) { + gtk_window_present(GTK_WINDOW(windows->data)); + return; + } + GtkWindow* window = GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); @@ -78,7 +85,7 @@ static gboolean my_application_local_command_line(GApplication* application, gch g_application_activate(application); *exit_status = 0; - return TRUE; + return FALSE; } // Implements GObject::dispose. @@ -99,6 +106,6 @@ static void my_application_init(MyApplication* self) {} MyApplication* my_application_new() { return MY_APPLICATION(g_object_new(my_application_get_type(), "application-id", APPLICATION_ID, - "flags", G_APPLICATION_NON_UNIQUE, + "flags", G_APPLICATION_HANDLES_COMMAND_LINE | G_APPLICATION_HANDLES_OPEN, nullptr)); } diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 6a58ed3c..9e84a9f3 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,6 +5,7 @@ import FlutterMacOS import Foundation +import app_links import audio_session import connectivity_plus import flutter_inappwebview_macos @@ -28,6 +29,7 @@ import window_manager import window_to_front func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + AppLinksMacosPlugin.register(with: registry.registrar(forPlugin: "AppLinksMacosPlugin")) AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin")) ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin")) InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin")) diff --git a/macos/Runner/AppDelegate.swift b/macos/Runner/AppDelegate.swift index b3c17614..897f9812 100644 --- a/macos/Runner/AppDelegate.swift +++ b/macos/Runner/AppDelegate.swift @@ -1,8 +1,19 @@ import Cocoa import FlutterMacOS +import app_links @main class AppDelegate: FlutterAppDelegate { + public override func application(_ application: NSApplication, + continue userActivity: NSUserActivity, + restorationHandler: @escaping ([any NSUserActivityRestoring]) -> Void) -> Bool { + guard let url = AppLinks.shared.getUniversalLink(userActivity) else { + return false + } + AppLinks.shared.handleLink(link: url.absoluteString) + return false + } + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { return true } diff --git a/macos/Runner/Info.plist b/macos/Runner/Info.plist index c527d81c..49b742eb 100644 --- a/macos/Runner/Info.plist +++ b/macos/Runner/Info.plist @@ -33,5 +33,16 @@ MainMenu NSPrincipalClass NSApplication + CFBundleURLTypes + + + CFBundleURLName + mangayomi + CFBundleURLSchemes + + mangayomi + + + diff --git a/pubspec.lock b/pubspec.lock index 502522e1..680e3baa 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -38,6 +38,38 @@ packages: url: "https://pub.dev" source: hosted version: "4.13.2" + app_links: + dependency: "direct main" + description: + name: app_links + sha256: "433df2e61b10519407475d7f69e470789d23d593f28224c38ba1068597be7950" + url: "https://pub.dev" + source: hosted + version: "6.3.3" + app_links_linux: + dependency: transitive + description: + name: app_links_linux + sha256: f5f7173a78609f3dfd4c2ff2c95bd559ab43c80a87dc6a095921d96c05688c81 + url: "https://pub.dev" + source: hosted + version: "1.0.3" + app_links_platform_interface: + dependency: transitive + description: + name: app_links_platform_interface + sha256: "05f5379577c513b534a29ddea68176a4d4802c46180ee8e2e966257158772a3f" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + app_links_web: + dependency: transitive + description: + name: app_links_web + sha256: af060ed76183f9e2b87510a9480e56a5352b6c249778d07bd2c95fc35632a555 + url: "https://pub.dev" + source: hosted + version: "1.0.4" archive: dependency: "direct main" description: @@ -796,6 +828,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.0.0" + gtk: + dependency: transitive + description: + name: gtk + sha256: e8ce9ca4b1df106e4d72dad201d345ea1a036cc12c360f1a7d5a758f78ffa42c + url: "https://pub.dev" + source: hosted + version: "2.1.0" html: dependency: "direct main" description: @@ -2060,13 +2100,13 @@ packages: source: hosted version: "3.16.3" win32: - dependency: transitive + dependency: "direct main" description: name: win32 - sha256: "154360849a56b7b67331c21f09a386562d88903f90a1099c5987afc1912e1f29" + sha256: daf97c9d80197ed7b619040e86c8ab9a9dad285e7671ee7390f9180cc828a51e url: "https://pub.dev" source: hosted - version: "5.10.0" + version: "5.10.1" window_manager: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 2878c7fd..5b213aa3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -80,6 +80,8 @@ dependencies: flutter_widget_from_html: ^0.15.3 convert: ^3.1.2 connectivity_plus: ^6.1.2 + app_links: ^6.3.3 + win32: ^5.10.1 dependency_overrides: http: ^1.2.2 diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 27f33e76..27d08b0a 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -6,6 +6,7 @@ #include "generated_plugin_registrant.h" +#include #include #include #include @@ -21,6 +22,8 @@ #include void RegisterPlugins(flutter::PluginRegistry* registry) { + AppLinksPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("AppLinksPluginCApi")); ConnectivityPlusWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin")); FlutterInappwebviewWindowsPluginCApiRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index cc3e8835..9b242a93 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + app_links connectivity_plus flutter_inappwebview_windows flutter_qjs diff --git a/windows/runner/main.cpp b/windows/runner/main.cpp index bc3da642..b7f3a03e 100644 --- a/windows/runner/main.cpp +++ b/windows/runner/main.cpp @@ -4,9 +4,51 @@ #include "flutter_window.h" #include "utils.h" +#include "app_links/app_links_plugin_c_api.h" + +bool SendAppLinkToInstance(const std::wstring& title) { + // Find our exact window + HWND hwnd = ::FindWindow(L"FLUTTER_RUNNER_WIN32_WINDOW", title.c_str()); + + if (hwnd) { + // Dispatch new link to current window + SendAppLink(hwnd); + + // (Optional) Restore our window to front in same state + WINDOWPLACEMENT place = { sizeof(WINDOWPLACEMENT) }; + GetWindowPlacement(hwnd, &place); + + switch(place.showCmd) { + case SW_SHOWMAXIMIZED: + ShowWindow(hwnd, SW_SHOWMAXIMIZED); + break; + case SW_SHOWMINIMIZED: + ShowWindow(hwnd, SW_RESTORE); + break; + default: + ShowWindow(hwnd, SW_NORMAL); + break; + } + + SetWindowPos(0, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE); + SetForegroundWindow(hwnd); + // END (Optional) Restore + + // Window has been found, don't create another one. + return true; + } + + return false; +} int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, _In_ wchar_t *command_line, _In_ int show_command) { + // Replace "example" with the generated title found as parameter of `window.Create` in this file. + // You may ignore the result if you need to create another window. + if (SendAppLinkToInstance(L"Mangayomi")) { + return EXIT_SUCCESS; + } + // 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()) { @@ -40,4 +82,4 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, ::CoUninitialize(); return EXIT_SUCCESS; -} +} \ No newline at end of file