mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-13 07:55:18 +00:00
feat: Deep link support (#950)
* feat: add deep link support * feat(android): add intent share support * chore: untranslated msg for it locale
This commit is contained in:
parent
05f9ae6a89
commit
4050f55640
@ -27,7 +27,7 @@
|
|||||||
<activity
|
<activity
|
||||||
android:name="com.ryanheise.audioservice.AudioServiceActivity"
|
android:name="com.ryanheise.audioservice.AudioServiceActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleInstance"
|
||||||
android:theme="@style/LaunchTheme"
|
android:theme="@style/LaunchTheme"
|
||||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||||
android:hardwareAccelerated="true"
|
android:hardwareAccelerated="true"
|
||||||
@ -48,6 +48,30 @@
|
|||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
<data
|
||||||
|
android:scheme="https"
|
||||||
|
android:host="open.spotify.com"
|
||||||
|
/>
|
||||||
|
</intent-filter>
|
||||||
|
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.SEND" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<data android:mimeType="text/*" />
|
||||||
|
</intent-filter>
|
||||||
|
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
<!-- Accepts URIs that begin with "spotify:// -->
|
||||||
|
<data android:scheme="spotify" />
|
||||||
|
</intent-filter>
|
||||||
|
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<!-- AudioService Config -->
|
<!-- AudioService Config -->
|
||||||
|
25
lib/collections/initializers.dart
Normal file
25
lib/collections/initializers.dart
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
import 'package:flutter_desktop_tools/flutter_desktop_tools.dart';
|
||||||
|
import 'package:win32_registry/win32_registry.dart';
|
||||||
|
|
||||||
|
Future<void> registerWindowsScheme(String scheme) async {
|
||||||
|
if (!DesktopTools.platform.isWindows) return;
|
||||||
|
String appPath = Platform.resolvedExecutable;
|
||||||
|
|
||||||
|
String protocolRegKey = 'Software\\Classes\\$scheme';
|
||||||
|
RegistryValue protocolRegValue = const RegistryValue(
|
||||||
|
'URL Protocol',
|
||||||
|
RegistryValueType.string,
|
||||||
|
'',
|
||||||
|
);
|
||||||
|
String protocolCmdRegKey = 'shell\\open\\command';
|
||||||
|
RegistryValue protocolCmdRegValue = RegistryValue(
|
||||||
|
'',
|
||||||
|
RegistryValueType.string,
|
||||||
|
'"$appPath" "%1"',
|
||||||
|
);
|
||||||
|
|
||||||
|
final regKey = Registry.currentUser.createKey(protocolRegKey);
|
||||||
|
regKey.createValue(protocolRegValue);
|
||||||
|
regKey.createKey(protocolCmdRegKey).createValue(protocolCmdRegValue);
|
||||||
|
}
|
93
lib/hooks/configurators/use_deep_linking.dart
Normal file
93
lib/hooks/configurators/use_deep_linking.dart
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
import 'package:app_links/app_links.dart';
|
||||||
|
import 'package:fl_query_hooks/fl_query_hooks.dart';
|
||||||
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:spotify/spotify.dart';
|
||||||
|
import 'package:spotube/collections/routes.dart';
|
||||||
|
import 'package:spotube/provider/spotify_provider.dart';
|
||||||
|
import 'package:flutter_sharing_intent/flutter_sharing_intent.dart';
|
||||||
|
import 'package:flutter_sharing_intent/model/sharing_file.dart';
|
||||||
|
|
||||||
|
void useDeepLinking(WidgetRef ref) {
|
||||||
|
// single instance no worries
|
||||||
|
final appLinks = AppLinks();
|
||||||
|
final spotify = ref.watch(spotifyProvider);
|
||||||
|
final queryClient = useQueryClient();
|
||||||
|
|
||||||
|
useEffect(() {
|
||||||
|
void uriListener(List<SharedFile> files) async {
|
||||||
|
for (final file in files) {
|
||||||
|
if (file.type != SharedMediaType.URL) continue;
|
||||||
|
final url = Uri.parse(file.value!);
|
||||||
|
if (url.pathSegments.length != 2) continue;
|
||||||
|
|
||||||
|
switch (url.pathSegments.first) {
|
||||||
|
case "album":
|
||||||
|
router.push(
|
||||||
|
"/album/${url.pathSegments.last}",
|
||||||
|
extra: await queryClient.fetchQuery<Album, dynamic>(
|
||||||
|
"album/${url.pathSegments.last}",
|
||||||
|
() => spotify.albums.get(url.pathSegments.last),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case "artist":
|
||||||
|
router.push("/artist/${url.pathSegments.last}");
|
||||||
|
break;
|
||||||
|
case "playlist":
|
||||||
|
router.push(
|
||||||
|
"/playlist/${url.pathSegments.last}",
|
||||||
|
extra: await queryClient.fetchQuery<Playlist, dynamic>(
|
||||||
|
"playlist/${url.pathSegments.last}",
|
||||||
|
() => spotify.playlists.get(url.pathSegments.last),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FlutterSharingIntent.instance.getInitialSharing().then(uriListener);
|
||||||
|
|
||||||
|
final mediaStream =
|
||||||
|
FlutterSharingIntent.instance.getMediaStream().listen(uriListener);
|
||||||
|
|
||||||
|
final subscription = appLinks.allStringLinkStream.listen((uri) async {
|
||||||
|
final startSegment = uri.split(":").take(2).join(":");
|
||||||
|
final endSegment = uri.split(":").last;
|
||||||
|
|
||||||
|
switch (startSegment) {
|
||||||
|
case "spotify:album":
|
||||||
|
await router.push(
|
||||||
|
"/album/$endSegment",
|
||||||
|
extra: await queryClient.fetchQuery<Album, dynamic>(
|
||||||
|
"album/$endSegment",
|
||||||
|
() => spotify.albums.get(endSegment),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case "spotify:artist":
|
||||||
|
await router.push("/artist/$endSegment");
|
||||||
|
break;
|
||||||
|
case "spotify:playlist":
|
||||||
|
await router.push(
|
||||||
|
"/playlist/$endSegment",
|
||||||
|
extra: await queryClient.fetchQuery<Playlist, dynamic>(
|
||||||
|
"playlist/$endSegment",
|
||||||
|
() => spotify.playlists.get(endSegment),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return () {
|
||||||
|
mediaStream.cancel();
|
||||||
|
subscription.cancel();
|
||||||
|
};
|
||||||
|
}, [spotify, queryClient]);
|
||||||
|
}
|
@ -13,9 +13,11 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|||||||
import 'package:media_kit/media_kit.dart';
|
import 'package:media_kit/media_kit.dart';
|
||||||
import 'package:metadata_god/metadata_god.dart';
|
import 'package:metadata_god/metadata_god.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
import 'package:spotube/collections/initializers.dart';
|
||||||
import 'package:spotube/collections/routes.dart';
|
import 'package:spotube/collections/routes.dart';
|
||||||
import 'package:spotube/collections/intents.dart';
|
import 'package:spotube/collections/intents.dart';
|
||||||
import 'package:spotube/hooks/configurators/use_close_behavior.dart';
|
import 'package:spotube/hooks/configurators/use_close_behavior.dart';
|
||||||
|
import 'package:spotube/hooks/configurators/use_deep_linking.dart';
|
||||||
import 'package:spotube/hooks/configurators/use_disable_battery_optimizations.dart';
|
import 'package:spotube/hooks/configurators/use_disable_battery_optimizations.dart';
|
||||||
import 'package:spotube/hooks/configurators/use_get_storage_perms.dart';
|
import 'package:spotube/hooks/configurators/use_get_storage_perms.dart';
|
||||||
import 'package:spotube/l10n/l10n.dart';
|
import 'package:spotube/l10n/l10n.dart';
|
||||||
@ -41,6 +43,8 @@ Future<void> main(List<String> rawArgs) async {
|
|||||||
|
|
||||||
final widgetsBinding = WidgetsFlutterBinding.ensureInitialized();
|
final widgetsBinding = WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
|
await registerWindowsScheme("spotify");
|
||||||
|
|
||||||
FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding);
|
FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding);
|
||||||
|
|
||||||
MediaKit.ensureInitialized();
|
MediaKit.ensureInitialized();
|
||||||
@ -181,8 +185,11 @@ class SpotubeState extends ConsumerState<Spotube> {
|
|||||||
final paletteColor =
|
final paletteColor =
|
||||||
ref.watch(paletteProvider.select((s) => s?.dominantColor?.color));
|
ref.watch(paletteProvider.select((s) => s?.dominantColor?.color));
|
||||||
|
|
||||||
|
useDisableBatteryOptimizations();
|
||||||
useInitSysTray(ref);
|
useInitSysTray(ref);
|
||||||
|
useDeepLinking(ref);
|
||||||
useCloseBehavior(ref);
|
useCloseBehavior(ref);
|
||||||
|
useGetStoragePermissions(ref);
|
||||||
|
|
||||||
useEffect(() {
|
useEffect(() {
|
||||||
FlutterNativeSplash.remove();
|
FlutterNativeSplash.remove();
|
||||||
@ -193,9 +200,6 @@ class SpotubeState extends ConsumerState<Spotube> {
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useDisableBatteryOptimizations();
|
|
||||||
useGetStoragePermissions(ref);
|
|
||||||
|
|
||||||
final lightTheme = useMemoized(
|
final lightTheme = useMemoized(
|
||||||
() => theme(paletteColor ?? accentMaterialColor, Brightness.light, false),
|
() => theme(paletteColor ?? accentMaterialColor, Brightness.light, false),
|
||||||
[paletteColor, accentMaterialColor],
|
[paletteColor, accentMaterialColor],
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include <dart_discord_rpc/dart_discord_rpc_plugin.h>
|
#include <dart_discord_rpc/dart_discord_rpc_plugin.h>
|
||||||
#include <file_selector_linux/file_selector_plugin.h>
|
#include <file_selector_linux/file_selector_plugin.h>
|
||||||
#include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h>
|
#include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h>
|
||||||
|
#include <gtk/gtk_plugin.h>
|
||||||
#include <local_notifier/local_notifier_plugin.h>
|
#include <local_notifier/local_notifier_plugin.h>
|
||||||
#include <media_kit_libs_linux/media_kit_libs_linux_plugin.h>
|
#include <media_kit_libs_linux/media_kit_libs_linux_plugin.h>
|
||||||
#include <screen_retriever/screen_retriever_plugin.h>
|
#include <screen_retriever/screen_retriever_plugin.h>
|
||||||
@ -28,6 +29,9 @@ void fl_register_plugins(FlPluginRegistry* registry) {
|
|||||||
g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar =
|
g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar =
|
||||||
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin");
|
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin");
|
||||||
flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar);
|
flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_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) local_notifier_registrar =
|
g_autoptr(FlPluginRegistrar) local_notifier_registrar =
|
||||||
fl_plugin_registry_get_registrar_for_plugin(registry, "LocalNotifierPlugin");
|
fl_plugin_registry_get_registrar_for_plugin(registry, "LocalNotifierPlugin");
|
||||||
local_notifier_plugin_register_with_registrar(local_notifier_registrar);
|
local_notifier_plugin_register_with_registrar(local_notifier_registrar);
|
||||||
|
@ -6,6 +6,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
|
|||||||
dart_discord_rpc
|
dart_discord_rpc
|
||||||
file_selector_linux
|
file_selector_linux
|
||||||
flutter_secure_storage_linux
|
flutter_secure_storage_linux
|
||||||
|
gtk
|
||||||
local_notifier
|
local_notifier
|
||||||
media_kit_libs_linux
|
media_kit_libs_linux
|
||||||
screen_retriever
|
screen_retriever
|
||||||
|
@ -17,6 +17,13 @@ G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION)
|
|||||||
// Implements GApplication::activate.
|
// Implements GApplication::activate.
|
||||||
static void my_application_activate(GApplication* application) {
|
static void my_application_activate(GApplication* application) {
|
||||||
MyApplication* self = MY_APPLICATION(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 =
|
GtkWindow* window =
|
||||||
GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));
|
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);
|
g_application_activate(application);
|
||||||
*exit_status = 0;
|
*exit_status = 0;
|
||||||
|
|
||||||
return TRUE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements GObject::dispose.
|
// Implements GObject::dispose.
|
||||||
@ -98,7 +105,7 @@ static void my_application_init(MyApplication* self) {}
|
|||||||
|
|
||||||
MyApplication* my_application_new() {
|
MyApplication* my_application_new() {
|
||||||
return MY_APPLICATION(g_object_new(my_application_get_type(),
|
return MY_APPLICATION(g_object_new(my_application_get_type(),
|
||||||
"application-id", APPLICATION_ID,
|
"com.github.KRTirtho.Spotube", APPLICATION_ID,
|
||||||
"flags", G_APPLICATION_NON_UNIQUE,
|
"flags", G_APPLICATION_HANDLES_COMMAND_LINE | G_APPLICATION_HANDLES_OPEN,
|
||||||
nullptr));
|
nullptr));
|
||||||
}
|
}
|
||||||
|
@ -11,3 +11,6 @@ keywords:
|
|||||||
generic_name: Music Streaming Application
|
generic_name: Music Streaming Application
|
||||||
categories:
|
categories:
|
||||||
- Music
|
- Music
|
||||||
|
|
||||||
|
supported_mime_type:
|
||||||
|
- x-scheme-handler/spotify
|
||||||
|
@ -32,3 +32,6 @@ keywords:
|
|||||||
generic_name: Music Streaming Application
|
generic_name: Music Streaming Application
|
||||||
categories:
|
categories:
|
||||||
- Music
|
- Music
|
||||||
|
|
||||||
|
supported_mime_type:
|
||||||
|
- x-scheme-handler/spotify
|
||||||
|
@ -28,3 +28,6 @@ categories:
|
|||||||
- Music
|
- Music
|
||||||
|
|
||||||
startup_notify: true
|
startup_notify: true
|
||||||
|
|
||||||
|
supported_mime_type:
|
||||||
|
- x-scheme-handler/spotify
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
import FlutterMacOS
|
import FlutterMacOS
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
import app_links
|
||||||
import audio_service
|
import audio_service
|
||||||
import audio_session
|
import audio_session
|
||||||
import device_info_plus
|
import device_info_plus
|
||||||
@ -24,6 +25,7 @@ import window_manager
|
|||||||
import window_size
|
import window_size
|
||||||
|
|
||||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
|
AppLinksMacosPlugin.register(with: registry.registrar(forPlugin: "AppLinksMacosPlugin"))
|
||||||
AudioServicePlugin.register(with: registry.registrar(forPlugin: "AudioServicePlugin"))
|
AudioServicePlugin.register(with: registry.registrar(forPlugin: "AudioServicePlugin"))
|
||||||
AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin"))
|
AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin"))
|
||||||
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
||||||
|
@ -2,6 +2,19 @@
|
|||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
|
<key>CFBundleURLTypes</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleURLName</key>
|
||||||
|
<!-- abstract name for this URL type (you can leave it blank) -->
|
||||||
|
<string>Spotify</string>
|
||||||
|
<key>CFBundleURLSchemes</key>
|
||||||
|
<array>
|
||||||
|
<!-- your schemes -->
|
||||||
|
<string>spotify</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
|
30
pubspec.lock
30
pubspec.lock
@ -17,6 +17,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.13.0"
|
version: "5.13.0"
|
||||||
|
app_links:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: app_links
|
||||||
|
sha256: "4e392b5eba997df356ca6021f28431ce1cfeb16758699553a94b13add874a3bb"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.5.0"
|
||||||
app_package_maker:
|
app_package_maker:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -907,6 +915,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.0"
|
version: "3.0.0"
|
||||||
|
flutter_sharing_intent:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_sharing_intent
|
||||||
|
sha256: "6eb896e6523b735e8230eeb206fd3b9f220f11ce879c2400a90b443147036ff9"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.0"
|
||||||
flutter_svg:
|
flutter_svg:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -1018,6 +1034,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.8"
|
version: "0.2.8"
|
||||||
|
gtk:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: gtk
|
||||||
|
sha256: e8ce9ca4b1df106e4d72dad201d345ea1a036cc12c360f1a7d5a758f78ffa42c
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.0"
|
||||||
hive:
|
hive:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -2246,13 +2270,13 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "5.0.7"
|
version: "5.0.7"
|
||||||
win32_registry:
|
win32_registry:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: win32_registry
|
name: win32_registry
|
||||||
sha256: e4506d60b7244251bc59df15656a3093501c37fb5af02105a944d73eb95be4c9
|
sha256: "41fd8a189940d8696b1b810efb9abcf60827b6cbfab90b0c43e8439e3a39d85a"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.1"
|
version: "1.1.2"
|
||||||
window_manager:
|
window_manager:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -119,6 +119,9 @@ dependencies:
|
|||||||
html_unescape: ^2.0.0
|
html_unescape: ^2.0.0
|
||||||
wikipedia_api: ^0.1.0
|
wikipedia_api: ^0.1.0
|
||||||
skeletonizer: ^0.8.0
|
skeletonizer: ^0.8.0
|
||||||
|
app_links: ^3.5.0
|
||||||
|
win32_registry: ^1.1.2
|
||||||
|
flutter_sharing_intent: ^1.1.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
build_runner: ^2.3.2
|
build_runner: ^2.3.2
|
||||||
|
@ -39,6 +39,12 @@
|
|||||||
"discord_rich_presence"
|
"discord_rich_presence"
|
||||||
],
|
],
|
||||||
|
|
||||||
|
"it": [
|
||||||
|
"audio_source",
|
||||||
|
"go_to_album",
|
||||||
|
"discord_rich_presence"
|
||||||
|
],
|
||||||
|
|
||||||
"ja": [
|
"ja": [
|
||||||
"go_to_album",
|
"go_to_album",
|
||||||
"discord_rich_presence"
|
"discord_rich_presence"
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
|
#include <app_links/app_links_plugin_c_api.h>
|
||||||
#include <dart_discord_rpc/dart_discord_rpc_plugin.h>
|
#include <dart_discord_rpc/dart_discord_rpc_plugin.h>
|
||||||
#include <file_selector_windows/file_selector_windows.h>
|
#include <file_selector_windows/file_selector_windows.h>
|
||||||
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
|
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
|
||||||
@ -20,6 +21,8 @@
|
|||||||
#include <window_size/window_size_plugin.h>
|
#include <window_size/window_size_plugin.h>
|
||||||
|
|
||||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||||
|
AppLinksPluginCApiRegisterWithRegistrar(
|
||||||
|
registry->GetRegistrarForPlugin("AppLinksPluginCApi"));
|
||||||
DartDiscordRpcPluginRegisterWithRegistrar(
|
DartDiscordRpcPluginRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("DartDiscordRpcPlugin"));
|
registry->GetRegistrarForPlugin("DartDiscordRpcPlugin"));
|
||||||
FileSelectorWindowsRegisterWithRegistrar(
|
FileSelectorWindowsRegisterWithRegistrar(
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
|
app_links
|
||||||
dart_discord_rpc
|
dart_discord_rpc
|
||||||
file_selector_windows
|
file_selector_windows
|
||||||
flutter_secure_storage_windows
|
flutter_secure_storage_windows
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <flutter_windows.h>
|
#include <flutter_windows.h>
|
||||||
|
|
||||||
#include "resource.h"
|
#include "resource.h"
|
||||||
|
#include "app_links/app_links_plugin_c_api.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
@ -105,6 +106,9 @@ Win32Window::~Win32Window() {
|
|||||||
bool Win32Window::CreateAndShow(const std::wstring& title,
|
bool Win32Window::CreateAndShow(const std::wstring& title,
|
||||||
const Point& origin,
|
const Point& origin,
|
||||||
const Size& size) {
|
const Size& size) {
|
||||||
|
if (SendAppLinkToInstance(title)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
Destroy();
|
Destroy();
|
||||||
|
|
||||||
const wchar_t* window_class =
|
const wchar_t* window_class =
|
||||||
@ -244,3 +248,39 @@ bool Win32Window::OnCreate() {
|
|||||||
void Win32Window::OnDestroy() {
|
void Win32Window::OnDestroy() {
|
||||||
// No-op; provided for subclasses.
|
// No-op; provided for subclasses.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// app_links
|
||||||
|
bool Win32Window::SendAppLinkToInstance(const std::wstring& title) {
|
||||||
|
// Find our exact window
|
||||||
|
HWND hwnd = ::FindWindow(kWindowClassName, 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 Restore
|
||||||
|
|
||||||
|
// Window has been found, don't create another one.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
@ -93,6 +93,10 @@ class Win32Window {
|
|||||||
|
|
||||||
// window handle for hosted content.
|
// window handle for hosted content.
|
||||||
HWND child_content_ = nullptr;
|
HWND child_content_ = nullptr;
|
||||||
|
// Dispatches link if any.
|
||||||
|
// This method enables our app to be with a single instance too.
|
||||||
|
// This is mandatory if you want to catch further links in same app.
|
||||||
|
bool SendAppLinkToInstance(const std::wstring& title);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // RUNNER_WIN32_WINDOW_H_
|
#endif // RUNNER_WIN32_WINDOW_H_
|
||||||
|
Loading…
Reference in New Issue
Block a user