mirror of
https://gitlab.com/mysocialportal/relatica
synced 2024-10-18 12:23:31 +00:00
Initial sign in/sign out workflow with proper state routing
This commit is contained in:
parent
5d9986121f
commit
f647b68881
16 changed files with 330 additions and 60 deletions
|
@ -1,11 +1,11 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:result_monad/result_monad.dart';
|
||||
|
||||
import 'models/credentials.dart';
|
||||
import 'models/exec_error.dart';
|
||||
import 'models/timeline_entry.dart';
|
||||
import 'package:result_monad/result_monad.dart';
|
||||
|
||||
import 'serializers/mastodon/timeline_entry_mastodon_extensions.dart';
|
||||
|
||||
class FriendicaClient {
|
||||
|
@ -14,6 +14,8 @@ class FriendicaClient {
|
|||
|
||||
String get serverName => _credentials.serverName;
|
||||
|
||||
Credentials get credentials => _credentials;
|
||||
|
||||
FriendicaClient({required Credentials credentials})
|
||||
: _credentials = credentials {
|
||||
final authenticationString =
|
||||
|
|
|
@ -1,12 +1,33 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_portal/globals.dart';
|
||||
import 'package:flutter_portal/routes.dart';
|
||||
import 'package:flutter_portal/screens/sign_in.dart';
|
||||
import 'package:flutter_portal/services/auth_service.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:result_monad/result_monad.dart';
|
||||
|
||||
void main() {
|
||||
getIt.registerLazySingleton<AuthService>(() => AuthService());
|
||||
import 'globals.dart';
|
||||
import 'routes.dart';
|
||||
import 'screens/sign_in.dart';
|
||||
import 'services/auth_service.dart';
|
||||
import 'services/secrets_service.dart';
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
final authService = AuthService();
|
||||
final secretsService = SecretsService();
|
||||
getIt.registerSingleton<SecretsService>(secretsService);
|
||||
getIt.registerSingleton<AuthService>(authService);
|
||||
|
||||
await secretsService.initialize().andThenSuccessAsync((credentials) async {
|
||||
if (credentials.isEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
final wasLoggedIn = await authService.getStoredLoginState();
|
||||
if (wasLoggedIn) {
|
||||
final result = await authService.signIn(credentials);
|
||||
print('Startup login result: $result');
|
||||
} else {
|
||||
print('Was not logged in');
|
||||
}
|
||||
});
|
||||
|
||||
runApp(const App());
|
||||
}
|
||||
|
@ -17,22 +38,6 @@ class App extends StatelessWidget {
|
|||
// This widget is the root of your application.
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// return MaterialApp(
|
||||
// title: 'Flutter Demo',
|
||||
// theme: ThemeData(
|
||||
// // This is the theme of your application.
|
||||
// //
|
||||
// // Try running your application with "flutter run". You'll see the
|
||||
// // application has a blue toolbar. Then, without quitting the app, try
|
||||
// // changing the primarySwatch below to Colors.green and then invoke
|
||||
// // "hot reload" (press "r" in the console where you ran "flutter run",
|
||||
// // or simply save your changes to "hot reload" in a Flutter IDE).
|
||||
// // Notice that the counter didn't reset back to zero; the application
|
||||
// // is not restarted.
|
||||
// primarySwatch: Colors.blue,
|
||||
// ),
|
||||
// home: const Home(),
|
||||
// );
|
||||
return MultiProvider(
|
||||
providers: [
|
||||
ChangeNotifierProvider<AuthService>(
|
||||
|
|
|
@ -11,6 +11,17 @@ class Credentials {
|
|||
required this.password,
|
||||
required this.serverName});
|
||||
|
||||
factory Credentials.empty() => Credentials(
|
||||
username: '',
|
||||
password: '',
|
||||
serverName: '',
|
||||
);
|
||||
|
||||
bool get isEmpty =>
|
||||
username.isEmpty && password.isEmpty && serverName.isEmpty;
|
||||
|
||||
String get handle => '$username@$serverName';
|
||||
|
||||
Credentials copy({String? username, String? password, String? serverName}) {
|
||||
return Credentials(
|
||||
username: username ?? this.username,
|
||||
|
@ -31,7 +42,7 @@ class Credentials {
|
|||
password: password,
|
||||
serverName: elements[1],
|
||||
);
|
||||
print(result);
|
||||
|
||||
return Result.ok(result);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import 'globals.dart';
|
||||
import 'screens/home.dart';
|
||||
import 'screens/sign_in.dart';
|
||||
import 'screens/splash.dart';
|
||||
import 'services/auth_service.dart';
|
||||
|
||||
class ScreenPaths {
|
||||
static String splash = '/splash';
|
||||
|
@ -12,9 +15,33 @@ class ScreenPaths {
|
|||
}
|
||||
|
||||
bool needAuthChangeInitialized = true;
|
||||
final _authService = getIt<AuthService>();
|
||||
final allowedLoggedOut = [
|
||||
ScreenPaths.splash,
|
||||
ScreenPaths.signin,
|
||||
ScreenPaths.signup
|
||||
];
|
||||
|
||||
final appRouter = GoRouter(
|
||||
initialLocation: ScreenPaths.signin,
|
||||
initialLocation: ScreenPaths.home,
|
||||
debugLogDiagnostics: true,
|
||||
refreshListenable: _authService,
|
||||
redirect: (context, state) async {
|
||||
print('redirect handler');
|
||||
final loggedIn = _authService.loggedIn;
|
||||
print('$loggedIn ${state.location}');
|
||||
if (!loggedIn && !allowedLoggedOut.contains(state.location)) {
|
||||
print('Redirecting to sign in');
|
||||
return ScreenPaths.signin;
|
||||
}
|
||||
|
||||
if (loggedIn && allowedLoggedOut.contains(state.location)) {
|
||||
print('Redirecting to home');
|
||||
return ScreenPaths.home;
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: ScreenPaths.signin,
|
||||
|
@ -26,4 +53,9 @@ final appRouter = GoRouter(
|
|||
name: ScreenPaths.home,
|
||||
builder: (context, state) => HomeScreen(),
|
||||
),
|
||||
GoRoute(
|
||||
path: ScreenPaths.splash,
|
||||
name: ScreenPaths.splash,
|
||||
builder: (context, state) => SplashScreen(),
|
||||
),
|
||||
]);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:result_monad/result_monad.dart';
|
||||
|
||||
import '../controls/padding.dart';
|
||||
|
@ -14,7 +15,7 @@ class HomeScreen extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final clientResult = getIt<AuthService>().currentClient;
|
||||
final clientResult = context.read<AuthService>().currentClient;
|
||||
final body = clientResult.fold(onSuccess: (client) {
|
||||
return Column(
|
||||
children: [
|
||||
|
@ -50,6 +51,14 @@ class HomeScreen extends StatelessWidget {
|
|||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('Home'),
|
||||
actions: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
getIt<AuthService>().signOut();
|
||||
},
|
||||
icon: Icon(Icons.logout),
|
||||
)
|
||||
],
|
||||
),
|
||||
body: body,
|
||||
);
|
||||
|
|
|
@ -1,21 +1,36 @@
|
|||
import 'package:email_validator/email_validator.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:result_monad/result_monad.dart';
|
||||
|
||||
import '../controls/padding.dart';
|
||||
import '../friendica_client.dart';
|
||||
import '../globals.dart';
|
||||
import '../models/credentials.dart';
|
||||
import '../routes.dart';
|
||||
import '../services/auth_service.dart';
|
||||
import '../services/secrets_service.dart';
|
||||
import '../utils/snackbar_builder.dart';
|
||||
|
||||
class SignInScreen extends StatelessWidget {
|
||||
class SignInScreen extends StatefulWidget {
|
||||
@override
|
||||
State<SignInScreen> createState() => _SignInScreenState();
|
||||
}
|
||||
|
||||
class _SignInScreenState extends State<SignInScreen> {
|
||||
final formKey = GlobalKey<FormState>();
|
||||
final usernameController = TextEditingController();
|
||||
final passwordController = TextEditingController();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
getIt<SecretsService>().credentials.andThenSuccess((credentials) {
|
||||
if (credentials.isEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
usernameController.text = credentials.handle;
|
||||
passwordController.text = credentials.password;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
|
@ -81,20 +96,16 @@ class SignInScreen extends StatelessWidget {
|
|||
void _signIn(BuildContext context) async {
|
||||
if (formKey.currentState?.validate() ?? false) {
|
||||
print('Attempting login...');
|
||||
await Credentials.buildFromHandle(
|
||||
final result = await Credentials.buildFromHandle(
|
||||
usernameController.text,
|
||||
passwordController.text,
|
||||
)
|
||||
.andThenSuccess((creds) => FriendicaClient(credentials: creds))
|
||||
.andThenAsync((client) async =>
|
||||
(await client.getMyProfile()).mapValue((_) => client))
|
||||
.match(onSuccess: (client) {
|
||||
print('Logged in');
|
||||
getIt<AuthService>().updateClient(client);
|
||||
context.pushNamed(ScreenPaths.home);
|
||||
}, onError: (error) {
|
||||
buildSnackbar(context, 'Error logging in: $error');
|
||||
).andThenSuccess((creds) async {
|
||||
return await getIt<AuthService>().signIn(creds);
|
||||
});
|
||||
|
||||
if (result.isFailure) {
|
||||
buildSnackbar(context, 'Error signing in: ${result.error}');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
17
lib/screens/splash.dart
Normal file
17
lib/screens/splash.dart
Normal file
|
@ -0,0 +1,17 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class SplashScreen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
const Text('Friendica Portal'),
|
||||
],
|
||||
)),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,11 +1,16 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:result_monad/result_monad.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import '../models/exec_error.dart';
|
||||
import '../friendica_client.dart';
|
||||
import '../globals.dart';
|
||||
import '../models/credentials.dart';
|
||||
import '../models/exec_error.dart';
|
||||
import 'secrets_service.dart';
|
||||
|
||||
class AuthService extends ChangeNotifier {
|
||||
FriendicaClient? _friendicaClient;
|
||||
bool _loggedIn = false;
|
||||
|
||||
Result<FriendicaClient, ExecError> get currentClient {
|
||||
if (_friendicaClient == null) {
|
||||
|
@ -18,14 +23,44 @@ class AuthService extends ChangeNotifier {
|
|||
return Result.ok(_friendicaClient!);
|
||||
}
|
||||
|
||||
Result<FriendicaClient, ExecError> updateClient(FriendicaClient newClient) {
|
||||
_friendicaClient = newClient;
|
||||
notifyListeners();
|
||||
return Result.ok(newClient);
|
||||
bool get loggedIn => _loggedIn && _friendicaClient != null;
|
||||
|
||||
Future<bool> getStoredLoginState() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
return prefs.getBool('logged-in') ?? false;
|
||||
}
|
||||
|
||||
void clearCredentials() {
|
||||
FutureResult<FriendicaClient, ExecError> signIn(
|
||||
Credentials credentials) async {
|
||||
final client = FriendicaClient(credentials: credentials);
|
||||
final result = await client.getMyProfile();
|
||||
if (result.isFailure) {
|
||||
return result.errorCast();
|
||||
}
|
||||
|
||||
getIt<SecretsService>().storeCredentials(client.credentials);
|
||||
await _setLoginState(true);
|
||||
_friendicaClient = client;
|
||||
notifyListeners();
|
||||
return Result.ok(client);
|
||||
}
|
||||
|
||||
Future signOut() async {
|
||||
print('Sign out');
|
||||
await _setLoginState(false);
|
||||
_friendicaClient = null;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future clearCredentials() async {
|
||||
_friendicaClient = null;
|
||||
await _setLoginState(false);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> _setLoginState(bool state) async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setBool('logged-in', state);
|
||||
_loggedIn = state;
|
||||
}
|
||||
}
|
||||
|
|
83
lib/services/secrets_service.dart
Normal file
83
lib/services/secrets_service.dart
Normal file
|
@ -0,0 +1,83 @@
|
|||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:result_monad/result_monad.dart';
|
||||
|
||||
import '../models/credentials.dart';
|
||||
import '../models/exec_error.dart';
|
||||
|
||||
class SecretsService {
|
||||
static const _usernameKey = 'username';
|
||||
static const _passwordKey = 'password';
|
||||
static const _serverNameKey = 'server-name';
|
||||
|
||||
Credentials? _cachedCredentials;
|
||||
|
||||
Result<Credentials, ExecError> get credentials => _cachedCredentials != null
|
||||
? Result.ok(_cachedCredentials!)
|
||||
: Result.error(
|
||||
ExecError(
|
||||
type: ErrorType.localError,
|
||||
message: 'Credentials not initialized',
|
||||
),
|
||||
);
|
||||
|
||||
final _secureStorage = const FlutterSecureStorage(
|
||||
iOptions: IOSOptions(
|
||||
accessibility: KeychainAccessibility.first_unlock,
|
||||
),
|
||||
);
|
||||
|
||||
FutureResult<Credentials, ExecError> initialize() async {
|
||||
return await getCredentials();
|
||||
}
|
||||
|
||||
FutureResult<Credentials, ExecError> clearCredentials() async {
|
||||
try {
|
||||
await _secureStorage.delete(key: _usernameKey);
|
||||
await _secureStorage.read(key: _passwordKey);
|
||||
await _secureStorage.read(key: _serverNameKey);
|
||||
return Result.ok(Credentials.empty());
|
||||
} on PlatformException catch (e) {
|
||||
return Result.error(ExecError(
|
||||
type: ErrorType.localError,
|
||||
message: e.message ?? '',
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Result<Credentials, ExecError> storeCredentials(Credentials credentials) {
|
||||
try {
|
||||
_secureStorage.write(key: _usernameKey, value: credentials.username);
|
||||
_secureStorage.write(key: _passwordKey, value: credentials.password);
|
||||
_secureStorage.write(key: _serverNameKey, value: credentials.serverName);
|
||||
return Result.ok(credentials);
|
||||
} on PlatformException catch (e) {
|
||||
return Result.error(ExecError(
|
||||
type: ErrorType.localError,
|
||||
message: e.message ?? '',
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
FutureResult<Credentials, ExecError> getCredentials() async {
|
||||
try {
|
||||
final username = await _secureStorage.read(key: _usernameKey);
|
||||
final password = await _secureStorage.read(key: _passwordKey);
|
||||
final serverName = await _secureStorage.read(key: _serverNameKey);
|
||||
if (username == null || password == null || serverName == null) {
|
||||
return Result.ok(Credentials.empty());
|
||||
}
|
||||
_cachedCredentials = Credentials(
|
||||
username: username,
|
||||
password: password,
|
||||
serverName: serverName,
|
||||
);
|
||||
return Result.ok(_cachedCredentials!);
|
||||
} on PlatformException catch (e) {
|
||||
return Result.error(ExecError(
|
||||
type: ErrorType.localError,
|
||||
message: e.message ?? '',
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,9 +7,13 @@
|
|||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <desktop_window/desktop_window_plugin.h>
|
||||
#include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h>
|
||||
|
||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
||||
g_autoptr(FlPluginRegistrar) desktop_window_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "DesktopWindowPlugin");
|
||||
desktop_window_plugin_register_with_registrar(desktop_window_registrar);
|
||||
g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin");
|
||||
flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
desktop_window
|
||||
flutter_secure_storage_linux
|
||||
)
|
||||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||
|
|
|
@ -6,12 +6,14 @@ import FlutterMacOS
|
|||
import Foundation
|
||||
|
||||
import desktop_window
|
||||
import flutter_secure_storage_macos
|
||||
import path_provider_macos
|
||||
import shared_preferences_macos
|
||||
import sqflite
|
||||
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
DesktopWindowPlugin.register(with: registry.registrar(forPlugin: "DesktopWindowPlugin"))
|
||||
FlutterSecureStorageMacosPlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStorageMacosPlugin"))
|
||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
|
||||
|
|
42
pubspec.lock
42
pubspec.lock
|
@ -146,6 +146,48 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
flutter_secure_storage:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_secure_storage
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "6.0.0"
|
||||
flutter_secure_storage_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_secure_storage_linux
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
flutter_secure_storage_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_secure_storage_macos
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
flutter_secure_storage_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_secure_storage_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
flutter_secure_storage_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_secure_storage_web
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
flutter_secure_storage_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_secure_storage_windows
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.2"
|
||||
flutter_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
|
|
34
pubspec.yaml
34
pubspec.yaml
|
@ -10,22 +10,23 @@ environment:
|
|||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
cupertino_icons: ^1.0.2
|
||||
provider: ^6.0.4
|
||||
email_validator: ^2.1.17
|
||||
get_it: ^7.2.0
|
||||
go_router: ^5.1.3
|
||||
uuid: ^3.0.6
|
||||
logging: ^1.1.0
|
||||
get_it_mixin: ^3.1.4
|
||||
cached_network_image: ^3.2.2
|
||||
result_monad: ^2.0.2
|
||||
cupertino_icons: ^1.0.2
|
||||
desktop_window: ^0.4.0
|
||||
email_validator: ^2.1.17
|
||||
flutter_secure_storage: ^6.0.0
|
||||
flutter_widget_from_html_core: ^0.9.0
|
||||
get_it: ^7.2.0
|
||||
get_it_mixin: ^3.1.4
|
||||
go_router: ^5.1.3
|
||||
logging: ^1.1.0
|
||||
markdown: ^6.0.1
|
||||
metadata_fetch: ^0.4.1
|
||||
shared_preferences: ^2.0.15
|
||||
network_to_file_image: ^4.0.1
|
||||
desktop_window: ^0.4.0
|
||||
provider: ^6.0.4
|
||||
result_monad: ^2.0.2
|
||||
shared_preferences: ^2.0.15
|
||||
uuid: ^3.0.6
|
||||
time_machine: ^0.9.17
|
||||
|
||||
dev_dependencies:
|
||||
|
@ -36,6 +37,17 @@ dev_dependencies:
|
|||
flutter:
|
||||
uses-material-design: true
|
||||
|
||||
parts:
|
||||
uet-lms:
|
||||
source: .
|
||||
plugin: flutter
|
||||
flutter-target: lib/main.dart
|
||||
build-packages:
|
||||
- libsecret-1-dev
|
||||
- libjsoncpp-dev
|
||||
stage-packages:
|
||||
- libsecret-1-dev
|
||||
- libjsoncpp1-dev
|
||||
# To add assets to your application, add an assets section, like this:
|
||||
# assets:
|
||||
# - images/a_dot_burr.jpeg
|
||||
|
|
|
@ -7,8 +7,11 @@
|
|||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <desktop_window/desktop_window_plugin.h>
|
||||
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
|
||||
|
||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
DesktopWindowPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("DesktopWindowPlugin"));
|
||||
FlutterSecureStorageWindowsPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin"));
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
desktop_window
|
||||
flutter_secure_storage_windows
|
||||
)
|
||||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||
|
|
Loading…
Reference in a new issue