mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-12 23:45:18 +00:00
feat(desktop): implement webview based login
This commit is contained in:
parent
3bdc46da4d
commit
15bd58a955
@ -34,12 +34,9 @@ import 'package:spotube/pages/stats/streams/streams.dart';
|
||||
import 'package:spotube/pages/track/track.dart';
|
||||
import 'package:spotube/provider/authentication/authentication.dart';
|
||||
import 'package:spotube/services/kv_store/kv_store.dart';
|
||||
import 'package:spotube/utils/platform.dart';
|
||||
import 'package:spotube/components/spotube_page_route.dart';
|
||||
import 'package:spotube/pages/artist/artist.dart';
|
||||
import 'package:spotube/pages/library/library.dart';
|
||||
import 'package:spotube/pages/desktop_login/login_tutorial.dart';
|
||||
import 'package:spotube/pages/desktop_login/desktop_login.dart';
|
||||
import 'package:spotube/pages/lyrics/lyrics.dart';
|
||||
import 'package:spotube/pages/root/root_app.dart';
|
||||
import 'package:spotube/pages/settings/settings.dart';
|
||||
@ -313,16 +310,8 @@ final routerProvider = Provider((ref) {
|
||||
path: "/login",
|
||||
name: WebViewLogin.name,
|
||||
parentNavigatorKey: rootNavigatorKey,
|
||||
pageBuilder: (context, state) => SpotubePage(
|
||||
child: kIsMobile ? const WebViewLogin() : const DesktopLoginPage(),
|
||||
),
|
||||
),
|
||||
GoRoute(
|
||||
path: "/login-tutorial",
|
||||
name: LoginTutorial.name,
|
||||
parentNavigatorKey: rootNavigatorKey,
|
||||
pageBuilder: (context, state) => const SpotubePage(
|
||||
child: LoginTutorial(),
|
||||
child: WebViewLogin(),
|
||||
),
|
||||
),
|
||||
GoRoute(
|
||||
|
@ -65,7 +65,7 @@ Future<void> main(List<String> rawArgs) async {
|
||||
await FlutterDisplayMode.setHighRefreshRate();
|
||||
}
|
||||
|
||||
if (kIsDesktop) {
|
||||
if (kIsDesktop && !kIsMacOS) {
|
||||
await windowManager.setPreventClose(true);
|
||||
}
|
||||
|
||||
|
@ -1,69 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:spotube/extensions/context.dart';
|
||||
|
||||
import 'package:spotube/provider/authentication/authentication.dart';
|
||||
|
||||
class TokenLoginForm extends HookConsumerWidget {
|
||||
final void Function()? onDone;
|
||||
const TokenLoginForm({
|
||||
super.key,
|
||||
this.onDone,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, ref) {
|
||||
final authenticationNotifier = ref.watch(authenticationProvider.notifier);
|
||||
final directCodeController = useTextEditingController();
|
||||
|
||||
final isLoading = useState(false);
|
||||
|
||||
return ConstrainedBox(
|
||||
constraints: const BoxConstraints(
|
||||
maxWidth: 400,
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
TextField(
|
||||
controller: directCodeController,
|
||||
decoration: InputDecoration(
|
||||
hintText: context.l10n.spotify_cookie("\"sp_dc\""),
|
||||
labelText: context.l10n.cookie_name_cookie("sp_dc"),
|
||||
),
|
||||
keyboardType: TextInputType.visiblePassword,
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
FilledButton(
|
||||
onPressed: isLoading.value
|
||||
? null
|
||||
: () async {
|
||||
try {
|
||||
isLoading.value = true;
|
||||
if (directCodeController.text.isEmpty) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(context.l10n.fill_in_all_fields),
|
||||
behavior: SnackBarBehavior.floating,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
final cookieHeader =
|
||||
"sp_dc=${directCodeController.text.trim()}";
|
||||
|
||||
await authenticationNotifier.login(cookieHeader);
|
||||
if (context.mounted) {
|
||||
onDone?.call();
|
||||
}
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
},
|
||||
child: Text(context.l10n.submit),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,78 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
|
||||
import 'package:spotube/collections/assets.gen.dart';
|
||||
import 'package:spotube/modules/desktop_login/login_form.dart';
|
||||
import 'package:spotube/components/titlebar/titlebar.dart';
|
||||
import 'package:spotube/extensions/constrains.dart';
|
||||
import 'package:spotube/extensions/context.dart';
|
||||
import 'package:spotube/pages/mobile_login/mobile_login.dart';
|
||||
|
||||
class DesktopLoginPage extends HookConsumerWidget {
|
||||
static const name = WebViewLogin.name;
|
||||
const DesktopLoginPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, ref) {
|
||||
final mediaQuery = MediaQuery.of(context);
|
||||
final theme = Theme.of(context);
|
||||
final color = theme.colorScheme.surfaceVariant.withOpacity(.3);
|
||||
|
||||
return SafeArea(
|
||||
child: Scaffold(
|
||||
appBar: const PageWindowTitleBar(
|
||||
leading: BackButton(),
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
child: Center(
|
||||
child: Container(
|
||||
margin: const EdgeInsets.all(10),
|
||||
padding: const EdgeInsets.all(10),
|
||||
decoration: BoxDecoration(
|
||||
color: color,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Assets.spotubeLogoPng.image(
|
||||
width: MediaQuery.of(context).size.width *
|
||||
(mediaQuery.mdAndDown ? .5 : .3),
|
||||
),
|
||||
Text(
|
||||
context.l10n.add_spotify_credentials,
|
||||
style: theme.textTheme.titleMedium,
|
||||
),
|
||||
Text(
|
||||
context.l10n.credentials_will_not_be_shared_disclaimer,
|
||||
style: theme.textTheme.labelMedium,
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
TokenLoginForm(
|
||||
onDone: () => GoRouter.of(context).go("/"),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Wrap(
|
||||
alignment: WrapAlignment.center,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
Text(context.l10n.know_how_to_login),
|
||||
TextButton(
|
||||
child: Text(
|
||||
context.l10n.follow_step_by_step_guide,
|
||||
),
|
||||
onPressed: () => GoRouter.of(context).push(
|
||||
"/login-tutorial",
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,125 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:introduction_screen/introduction_screen.dart';
|
||||
|
||||
import 'package:spotube/collections/assets.gen.dart';
|
||||
import 'package:spotube/modules/desktop_login/login_form.dart';
|
||||
import 'package:spotube/components/links/hyper_link.dart';
|
||||
import 'package:spotube/components/titlebar/titlebar.dart';
|
||||
import 'package:spotube/extensions/context.dart';
|
||||
import 'package:spotube/pages/home/home.dart';
|
||||
import 'package:spotube/provider/authentication/authentication.dart';
|
||||
import 'package:spotube/utils/service_utils.dart';
|
||||
|
||||
class LoginTutorial extends ConsumerWidget {
|
||||
static const name = "login_tutorial";
|
||||
const LoginTutorial({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, ref) {
|
||||
final auth = ref.watch(authenticationProvider);
|
||||
final key = GlobalKey<State<IntroductionScreen>>();
|
||||
final theme = Theme.of(context);
|
||||
|
||||
final pageDecoration = PageDecoration(
|
||||
bodyTextStyle: theme.textTheme.bodyMedium!,
|
||||
titleTextStyle: theme.textTheme.headlineMedium!,
|
||||
);
|
||||
return Scaffold(
|
||||
appBar: PageWindowTitleBar(
|
||||
leading: TextButton(
|
||||
child: Text(context.l10n.exit),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
),
|
||||
body: IntroductionScreen(
|
||||
key: key,
|
||||
globalBackgroundColor: theme.scaffoldBackgroundColor,
|
||||
overrideBack: OutlinedButton(
|
||||
child: Center(child: Text(context.l10n.previous)),
|
||||
onPressed: () {
|
||||
(key.currentState as IntroductionScreenState).previous();
|
||||
},
|
||||
),
|
||||
overrideNext: FilledButton(
|
||||
child: Center(child: Text(context.l10n.next)),
|
||||
onPressed: () {
|
||||
(key.currentState as IntroductionScreenState).next();
|
||||
},
|
||||
),
|
||||
showBackButton: true,
|
||||
overrideDone: FilledButton(
|
||||
onPressed: auth.asData?.value != null
|
||||
? () {
|
||||
ServiceUtils.pushNamed(context, HomePage.name);
|
||||
}
|
||||
: null,
|
||||
child: Center(child: Text(context.l10n.done)),
|
||||
),
|
||||
pages: [
|
||||
PageViewModel(
|
||||
decoration: pageDecoration,
|
||||
title: context.l10n.step_1,
|
||||
image: Assets.tutorial.step1.image(),
|
||||
bodyWidget: Wrap(
|
||||
children: [
|
||||
Text(context.l10n.first_go_to),
|
||||
const SizedBox(width: 5),
|
||||
const Hyperlink(
|
||||
"accounts.spotify.com ",
|
||||
"https://accounts.spotify.com",
|
||||
),
|
||||
Text(context.l10n.login_if_not_logged_in),
|
||||
],
|
||||
),
|
||||
),
|
||||
PageViewModel(
|
||||
decoration: pageDecoration,
|
||||
title: context.l10n.step_2,
|
||||
image: Assets.tutorial.step2.image(),
|
||||
bodyWidget:
|
||||
Text(context.l10n.step_2_steps, textAlign: TextAlign.left),
|
||||
),
|
||||
PageViewModel(
|
||||
decoration: pageDecoration,
|
||||
title: context.l10n.step_3,
|
||||
image: Assets.tutorial.step3.image(),
|
||||
bodyWidget:
|
||||
Text(context.l10n.step_3_steps, textAlign: TextAlign.left),
|
||||
),
|
||||
if (auth.asData?.value != null)
|
||||
PageViewModel(
|
||||
decoration: pageDecoration.copyWith(
|
||||
bodyAlignment: Alignment.center,
|
||||
),
|
||||
title: context.l10n.success_emoji,
|
||||
image: Assets.success.image(),
|
||||
body: context.l10n.success_message,
|
||||
)
|
||||
else
|
||||
PageViewModel(
|
||||
decoration: pageDecoration,
|
||||
title: context.l10n.step_4,
|
||||
bodyWidget: Column(
|
||||
children: [
|
||||
Text(
|
||||
context.l10n.step_4_steps,
|
||||
style: theme.textTheme.labelMedium,
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
TokenLoginForm(
|
||||
onDone: () {
|
||||
GoRouter.of(context).go("/");
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
import 'package:auto_size_text/auto_size_text.dart';
|
||||
import 'package:desktop_webview_window/desktop_webview_window.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
@ -8,10 +9,12 @@ import 'package:spotube/components/image/universal_image.dart';
|
||||
import 'package:spotube/extensions/constrains.dart';
|
||||
import 'package:spotube/extensions/context.dart';
|
||||
import 'package:spotube/extensions/image.dart';
|
||||
import 'package:spotube/pages/mobile_login/mobile_login.dart';
|
||||
import 'package:spotube/pages/profile/profile.dart';
|
||||
import 'package:spotube/provider/authentication/authentication.dart';
|
||||
import 'package:spotube/provider/scrobbler/scrobbler.dart';
|
||||
import 'package:spotube/provider/spotify/spotify.dart';
|
||||
import 'package:spotube/utils/platform.dart';
|
||||
import 'package:spotube/utils/service_utils.dart';
|
||||
|
||||
class SettingsAccountSection extends HookConsumerWidget {
|
||||
@ -23,6 +26,7 @@ class SettingsAccountSection extends HookConsumerWidget {
|
||||
final router = GoRouter.of(context);
|
||||
|
||||
final auth = ref.watch(authenticationProvider);
|
||||
final authNotifier = ref.watch(authenticationProvider.notifier);
|
||||
final scrobbler = ref.watch(scrobblerProvider);
|
||||
final me = ref.watch(meProvider);
|
||||
final meData = me.asData?.value;
|
||||
@ -32,6 +36,36 @@ class SettingsAccountSection extends HookConsumerWidget {
|
||||
foregroundColor: Colors.white,
|
||||
);
|
||||
|
||||
void onLogin() async {
|
||||
if (kIsMobile) {
|
||||
router.pushNamed(WebViewLogin.name);
|
||||
return;
|
||||
}
|
||||
|
||||
final webview = await WebviewWindow.create();
|
||||
|
||||
webview.setOnUrlRequestCallback((url) {
|
||||
final exp = RegExp(r"https:\/\/accounts.spotify.com\/.+\/status");
|
||||
|
||||
if (exp.hasMatch(url)) {
|
||||
webview.getAllCookies().then((cookies) async {
|
||||
final cookieHeader =
|
||||
"sp_dc=${cookies.firstWhere((element) => element.name == "sp_dc").value}";
|
||||
|
||||
await authNotifier.login(cookieHeader);
|
||||
webview.close();
|
||||
if (context.mounted) {
|
||||
context.go("/");
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
webview.launch("https://accounts.spotify.com/");
|
||||
}
|
||||
|
||||
return SectionCardWithHeading(
|
||||
heading: context.l10n.account,
|
||||
children: [
|
||||
@ -70,17 +104,11 @@ class SettingsAccountSection extends HookConsumerWidget {
|
||||
),
|
||||
),
|
||||
),
|
||||
onTap: constrains.mdAndUp
|
||||
? null
|
||||
: () {
|
||||
router.push("/login");
|
||||
},
|
||||
onTap: constrains.mdAndUp ? null : onLogin,
|
||||
trailing: constrains.smAndDown
|
||||
? null
|
||||
: FilledButton(
|
||||
onPressed: () {
|
||||
router.push("/login");
|
||||
},
|
||||
onPressed: onLogin,
|
||||
style: ButtonStyle(
|
||||
shape: MaterialStateProperty.all(
|
||||
RoundedRectangleBorder(
|
||||
|
@ -2,6 +2,7 @@ import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:desktop_webview_window/desktop_webview_window.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:dio/io.dart';
|
||||
import 'package:drift/drift.dart';
|
||||
@ -160,6 +161,9 @@ class AuthenticationNotifier extends AsyncNotifier<AuthenticationTableData?> {
|
||||
WebStorageManager.instance().deleteAllData();
|
||||
CookieManager.instance().deleteAllCookies();
|
||||
}
|
||||
if (kIsDesktop) {
|
||||
await WebviewWindow.clearAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <dart_discord_rpc/dart_discord_rpc_plugin.h>
|
||||
#include <desktop_webview_window/desktop_webview_window_plugin.h>
|
||||
#include <file_selector_linux/file_selector_plugin.h>
|
||||
#include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h>
|
||||
#include <gtk/gtk_plugin.h>
|
||||
@ -24,6 +25,9 @@ void fl_register_plugins(FlPluginRegistry* registry) {
|
||||
g_autoptr(FlPluginRegistrar) dart_discord_rpc_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "DartDiscordRpcPlugin");
|
||||
dart_discord_rpc_plugin_register_with_registrar(dart_discord_rpc_registrar);
|
||||
g_autoptr(FlPluginRegistrar) desktop_webview_window_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "DesktopWebviewWindowPlugin");
|
||||
desktop_webview_window_plugin_register_with_registrar(desktop_webview_window_registrar);
|
||||
g_autoptr(FlPluginRegistrar) file_selector_linux_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin");
|
||||
file_selector_plugin_register_with_registrar(file_selector_linux_registrar);
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
dart_discord_rpc
|
||||
desktop_webview_window
|
||||
file_selector_linux
|
||||
flutter_secure_storage_linux
|
||||
gtk
|
||||
|
@ -9,6 +9,7 @@ import app_links
|
||||
import audio_service
|
||||
import audio_session
|
||||
import bonsoir_darwin
|
||||
import desktop_webview_window
|
||||
import device_info_plus
|
||||
import file_selector_macos
|
||||
import flutter_inappwebview_macos
|
||||
@ -32,6 +33,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
AudioServicePlugin.register(with: registry.registrar(forPlugin: "AudioServicePlugin"))
|
||||
AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin"))
|
||||
SwiftBonsoirPlugin.register(with: registry.registrar(forPlugin: "SwiftBonsoirPlugin"))
|
||||
DesktopWebviewWindowPlugin.register(with: registry.registrar(forPlugin: "DesktopWebviewWindowPlugin"))
|
||||
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
||||
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
||||
InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin"))
|
||||
|
@ -8,6 +8,8 @@ PODS:
|
||||
- bonsoir_darwin (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- desktop_webview_window (0.0.1):
|
||||
- FlutterMacOS
|
||||
- device_info_plus (0.0.1):
|
||||
- FlutterMacOS
|
||||
- file_selector_macos (0.0.1):
|
||||
@ -70,6 +72,7 @@ DEPENDENCIES:
|
||||
- audio_service (from `Flutter/ephemeral/.symlinks/plugins/audio_service/macos`)
|
||||
- audio_session (from `Flutter/ephemeral/.symlinks/plugins/audio_session/macos`)
|
||||
- bonsoir_darwin (from `Flutter/ephemeral/.symlinks/plugins/bonsoir_darwin/darwin`)
|
||||
- desktop_webview_window (from `Flutter/ephemeral/.symlinks/plugins/desktop_webview_window/macos`)
|
||||
- device_info_plus (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos`)
|
||||
- file_selector_macos (from `Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos`)
|
||||
- flutter_inappwebview_macos (from `Flutter/ephemeral/.symlinks/plugins/flutter_inappwebview_macos/macos`)
|
||||
@ -105,6 +108,8 @@ EXTERNAL SOURCES:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/audio_session/macos
|
||||
bonsoir_darwin:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/bonsoir_darwin/darwin
|
||||
desktop_webview_window:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/desktop_webview_window/macos
|
||||
device_info_plus:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos
|
||||
file_selector_macos:
|
||||
@ -151,6 +156,7 @@ SPEC CHECKSUMS:
|
||||
audio_service: b88ff778e0e3915efd4cd1a5ad6f0beef0c950a9
|
||||
audio_session: dea1f41890dbf1718f04a56f1d6150fd50039b72
|
||||
bonsoir_darwin: e3b8526c42ca46a885142df84229131dfabea842
|
||||
desktop_webview_window: 89bb3d691f4c80314a10be312f4cd35db93a9d5a
|
||||
device_info_plus: ce1b7762849d3ec103d0e0517299f2db7ad60720
|
||||
file_selector_macos: 468fb6b81fac7c0e88d71317f3eec34c3b008ff9
|
||||
flutter_inappwebview_macos: 9600c9df9fdb346aaa8933812009f8d94304203d
|
||||
|
@ -474,6 +474,15 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.10"
|
||||
desktop_webview_window:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "packages/desktop_webview_window"
|
||||
ref: "feat/cookies"
|
||||
resolved-ref: f20e433d4a948515b35089d40069f7dd9bced9e4
|
||||
url: "https://github.com/KRTirtho/flutter-plugins.git"
|
||||
source: git
|
||||
version: "0.2.4"
|
||||
device_info_plus:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -24,6 +24,11 @@ dependencies:
|
||||
collection: ^1.15.0
|
||||
curved_navigation_bar: ^1.0.3
|
||||
dbus: ^0.7.8
|
||||
desktop_webview_window:
|
||||
git:
|
||||
url: https://github.com/KRTirtho/flutter-plugins.git
|
||||
ref: feat/cookies
|
||||
path: packages/desktop_webview_window
|
||||
device_info_plus: ^10.1.0
|
||||
dio: ^5.4.3+1
|
||||
disable_battery_optimization: ^1.1.1
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <app_links/app_links_plugin_c_api.h>
|
||||
#include <bonsoir_windows/bonsoir_windows_plugin_c_api.h>
|
||||
#include <dart_discord_rpc/dart_discord_rpc_plugin.h>
|
||||
#include <desktop_webview_window/desktop_webview_window_plugin.h>
|
||||
#include <file_selector_windows/file_selector_windows.h>
|
||||
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
|
||||
#include <local_notifier/local_notifier_plugin.h>
|
||||
@ -29,6 +30,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
registry->GetRegistrarForPlugin("BonsoirWindowsPluginCApi"));
|
||||
DartDiscordRpcPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("DartDiscordRpcPlugin"));
|
||||
DesktopWebviewWindowPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("DesktopWebviewWindowPlugin"));
|
||||
FileSelectorWindowsRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FileSelectorWindows"));
|
||||
FlutterSecureStorageWindowsPluginRegisterWithRegistrar(
|
||||
|
@ -6,6 +6,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
|
||||
app_links
|
||||
bonsoir_windows
|
||||
dart_discord_rpc
|
||||
desktop_webview_window
|
||||
file_selector_windows
|
||||
flutter_secure_storage_windows
|
||||
local_notifier
|
||||
|
Loading…
Reference in New Issue
Block a user