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