diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 8b89139..b30b33d 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1,9 +1,14 @@ PODS: - Flutter (1.0.0) + - flutter_secure_storage (6.0.0): + - Flutter - media_kit_video (0.0.1): - Flutter - package_info_plus (0.4.5): - Flutter + - path_provider_foundation (0.0.1): + - Flutter + - FlutterMacOS - screen_brightness_ios (0.1.0): - Flutter - url_launcher_ios (0.0.1): @@ -15,24 +20,33 @@ PODS: - Flutter - wakelock_plus (0.0.1): - Flutter + - webview_flutter_wkwebview (0.0.1): + - Flutter DEPENDENCIES: - Flutter (from `Flutter`) + - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) - media_kit_video (from `.symlinks/plugins/media_kit_video/ios`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) + - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - screen_brightness_ios (from `.symlinks/plugins/screen_brightness_ios/ios`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/darwin`) - volume_controller (from `.symlinks/plugins/volume_controller/ios`) - wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`) + - webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/ios`) EXTERNAL SOURCES: Flutter: :path: Flutter + flutter_secure_storage: + :path: ".symlinks/plugins/flutter_secure_storage/ios" media_kit_video: :path: ".symlinks/plugins/media_kit_video/ios" package_info_plus: :path: ".symlinks/plugins/package_info_plus/ios" + path_provider_foundation: + :path: ".symlinks/plugins/path_provider_foundation/darwin" screen_brightness_ios: :path: ".symlinks/plugins/screen_brightness_ios/ios" url_launcher_ios: @@ -43,16 +57,21 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/volume_controller/ios" wakelock_plus: :path: ".symlinks/plugins/wakelock_plus/ios" + webview_flutter_wkwebview: + :path: ".symlinks/plugins/webview_flutter_wkwebview/ios" SPEC CHECKSUMS: Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 + flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be media_kit_video: 26c5b265a4094a2df3e8d41e6724d9b964c13151 package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c + path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c screen_brightness_ios: 715ca807df953bf676d339f11464e438143ee625 url_launcher_ios: 6116280ddcfe98ab8820085d8d76ae7449447586 video_player_avfoundation: 2b4384f3b157206b5e150a0083cdc0c905d260d3 volume_controller: 531ddf792994285c9b17f9d8a7e4dcdd29b3eae9 wakelock_plus: 78ec7c5b202cab7761af8e2b2b3d0671be6c4ae1 + webview_flutter_wkwebview: be0f0d33777f1bfd0c9fdcb594786704dbf65f36 PODFILE CHECKSUM: 819463e6a0290f5a72f145ba7cde16e8b6ef0796 diff --git a/lib/i18n/app_en.arb b/lib/i18n/app_en.arb index 059c81f..7be074e 100644 --- a/lib/i18n/app_en.arb +++ b/lib/i18n/app_en.arb @@ -1,4 +1,9 @@ { "solian": "Solian", - "explore": "Explore" + "explore": "Explore", + "account": "Account", + "signIn": "Sign In", + "signInCaption": "Sign in to create post, start a realm, message your friend and more!", + "signUp": "Sign Up", + "signUpCaption": "Create an account on Solarpass and then get the access of entire Solar Networks!" } \ No newline at end of file diff --git a/lib/i18n/app_zh.arb b/lib/i18n/app_zh.arb index 6b84fab..3fefa95 100644 --- a/lib/i18n/app_zh.arb +++ b/lib/i18n/app_zh.arb @@ -1,4 +1,9 @@ { "solian": "索链", - "explore": "探索" + "explore": "探索", + "account": "账号", + "signIn": "登陆", + "signInCaption": "登陆以发表帖子、文章、创建领域、和你的朋友聊天,以及获取更多功能!", + "signUp": "注册", + "signUpCaption": "在 Solarpass 注册一个账号以获得整个 Solar Networks 的存取权!" } \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index ec1243e..39ec226 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,9 +1,8 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:solian/providers/layout_provider.dart'; +import 'package:solian/providers/auth.dart'; import 'package:solian/router.dart'; import 'package:solian/utils/timeago.dart'; -import 'package:solian/widgets/wrapper.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; void main() { @@ -33,11 +32,9 @@ class SolianApp extends StatelessWidget { OverlayEntry(builder: (context) { return MultiProvider( providers: [ - Provider(create: (_) => LayoutConfig(context)) + Provider(create: (_) => AuthProvider()), ], - child: LayoutWrapper( - child: child, - ), + child: child, ); }) ], diff --git a/lib/providers/auth.dart b/lib/providers/auth.dart new file mode 100755 index 0000000..753ed9a --- /dev/null +++ b/lib/providers/auth.dart @@ -0,0 +1,132 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +import 'package:solian/screens/auth.dart'; +import 'package:oauth2/oauth2.dart' as oauth2; +import 'package:solian/utils/service_url.dart'; + +final authClient = AuthProvider(); + +class AuthProvider { + AuthProvider(); + + final deviceEndpoint = + getRequestUri('passport', '/api/notifications/subscribe'); + final authorizationEndpoint = getRequestUri('passport', '/auth/o/connect'); + final tokenEndpoint = getRequestUri('passport', '/api/auth/token'); + final userinfoEndpoint = getRequestUri('passport', '/api/users/me'); + final redirectUrl = Uri.parse('solian://auth'); + + static const clientId = "solian"; + static const clientSecret = "_F4%q2Eea3"; + + static const storage = FlutterSecureStorage(); + static const storageKey = "identity"; + static const profileKey = "profiles"; + + oauth2.Client? client; + DateTime? lastRefreshedAt; + + Future pickClient() async { + if (await storage.containsKey(key: storageKey)) { + try { + var credentials = + oauth2.Credentials.fromJson((await storage.read(key: storageKey))!); + client = oauth2.Client(credentials, + identifier: clientId, secret: clientSecret); + await fetchProfiles(); + return true; + } catch (e) { + signOff(); + return false; + } + } else { + return false; + } + } + + Future createClient(BuildContext context) async { + // If logged in + if (await pickClient()) { + return client!; + } + + var grant = oauth2.AuthorizationCodeGrant( + clientId, + authorizationEndpoint, + tokenEndpoint, + secret: clientSecret, + basicAuth: false, + ); + + var authorizationUrl = grant.getAuthorizationUrl(redirectUrl, scopes: ["openid"]); + + if (Platform.isAndroid || Platform.isIOS) { + // Use WebView to get authorization url + var responseUrl = await Navigator.of(context, rootNavigator: true).push( + MaterialPageRoute( + builder: (context) => AuthorizationScreen(authorizationUrl), + ), + ); + + var responseUri = Uri.parse(responseUrl); + return await grant + .handleAuthorizationResponse(responseUri.queryParameters); + } else { + throw UnimplementedError("unsupported platform"); + } + } + + Future fetchProfiles() async { + if (client != null) { + var userinfo = await client!.get(userinfoEndpoint); + storage.write(key: profileKey, value: utf8.decode(userinfo.bodyBytes)); + } + } + + Future refreshToken() async { + if (client != null) { + var credentials = await client?.credentials.refresh( + identifier: clientId, secret: clientSecret, basicAuth: false); + + storage.write(key: storageKey, value: credentials!.toJson()); + } + } + + Future signIn(BuildContext context) async { + client = await createClient(context); + storage.write(key: storageKey, value: client!.credentials.toJson()); + + await fetchProfiles(); + } + + void signOff() { + storage.delete(key: profileKey); + storage.delete(key: storageKey); + } + + Future isAuthorized() async { + const storage = FlutterSecureStorage(); + if (await storage.containsKey(key: storageKey)) { + if (client != null) { + if (lastRefreshedAt == null || + lastRefreshedAt! + .add(const Duration(minutes: 3)) + .isAfter(DateTime.now())) { + await refreshToken(); + lastRefreshedAt = DateTime.now(); + } + } + return true; + } else { + return false; + } + } + + Future getProfiles() async { + const storage = FlutterSecureStorage(); + return jsonDecode(await storage.read(key: profileKey) ?? "{}"); + } +} diff --git a/lib/providers/layout_provider.dart b/lib/providers/layout_provider.dart deleted file mode 100644 index bcb075b..0000000 --- a/lib/providers/layout_provider.dart +++ /dev/null @@ -1,10 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_gen/gen_l10n/app_localizations.dart'; - -class LayoutConfig { - String title = "Solian"; - - LayoutConfig(BuildContext context) { - title = AppLocalizations.of(context)!.solian; - } -} \ No newline at end of file diff --git a/lib/router.dart b/lib/router.dart index 9db2aaf..f0193f1 100644 --- a/lib/router.dart +++ b/lib/router.dart @@ -1,4 +1,5 @@ import 'package:go_router/go_router.dart'; +import 'package:solian/screens/account.dart'; import 'package:solian/screens/explore.dart'; final router = GoRouter( @@ -8,5 +9,10 @@ final router = GoRouter( name: 'explore', builder: (context, state) => const ExploreScreen(), ), + GoRoute( + path: '/account', + name: 'account', + builder: (context, state) => const AccountScreen(), + ), ], ); diff --git a/lib/screens/account.dart b/lib/screens/account.dart new file mode 100644 index 0000000..fa51be5 --- /dev/null +++ b/lib/screens/account.dart @@ -0,0 +1,202 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:solian/providers/auth.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:solian/utils/service_url.dart'; +import 'package:solian/widgets/wrapper.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class AccountScreen extends StatefulWidget { + const AccountScreen({super.key}); + + @override + State createState() => _AccountScreenState(); +} + +class _AccountScreenState extends State { + bool isAuthorized = false; + + @override + void initState() { + Future.delayed(Duration.zero, () async { + var authorized = await context.read().isAuthorized(); + setState(() => isAuthorized = authorized); + }); + + super.initState(); + } + + @override + Widget build(BuildContext context) { + final auth = context.watch(); + + return LayoutWrapper( + title: AppLocalizations.of(context)!.account, + child: isAuthorized + ? Column( + children: [ + const Padding( + padding: EdgeInsets.symmetric(vertical: 8, horizontal: 24), + child: NameCard(), + ), + InkWell( + child: const Padding( + padding: EdgeInsets.symmetric(horizontal: 18), + child: ListTile( + leading: Icon(Icons.logout), + title: Text("Sign out"), + ), + ), + onTap: () { + auth.signOff(); + setState(() { + isAuthorized = false; + }); + }, + ) + ], + ) + : Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + ActionCard( + icon: const Icon(Icons.login, color: Colors.white), + title: AppLocalizations.of(context)!.signIn, + caption: AppLocalizations.of(context)!.signInCaption, + onTap: () { + auth.signIn(context).then((_) { + authClient.isAuthorized().then((val) { + setState(() => isAuthorized = val); + }); + }); + }, + ), + ActionCard( + icon: const Icon(Icons.plus_one, color: Colors.white), + title: AppLocalizations.of(context)!.signUp, + caption: AppLocalizations.of(context)!.signUpCaption, + onTap: () { + launchUrl(getRequestUri('passport', '/auth/sign-up')); + }, + ), + ], + ), + ), + ); + } +} + +class NameCard extends StatelessWidget { + const NameCard({super.key}); + + Future renderAvatar() async { + final profiles = await authClient.getProfiles(); + return CircleAvatar(backgroundImage: NetworkImage(profiles["picture"])); + } + + Future renderLabel() async { + final profiles = await authClient.getProfiles(); + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + profiles["nick"], + style: const TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + Text(profiles["email"]) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Card( + child: InkWell( + splashColor: Colors.indigo.withAlpha(30), + child: Padding( + padding: const EdgeInsets.all(20), + child: Row( + children: [ + FutureBuilder( + future: renderAvatar(), + builder: + (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.hasData) { + return snapshot.data!; + } else { + return const CircularProgressIndicator(); + } + }, + ), + const SizedBox(width: 20), + FutureBuilder( + future: renderLabel(), + builder: + (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.hasData) { + return snapshot.data!; + } else { + return const Column(); + } + }, + ) + ], + ), + ), + ), + ); + } +} + +class ActionCard extends StatelessWidget { + final Widget icon; + final String title; + final String caption; + final Function onTap; + + const ActionCard( + {super.key, + required this.onTap, + required this.title, + required this.caption, + required this.icon}); + + @override + Widget build(BuildContext context) { + return Card( + child: InkWell( + borderRadius: BorderRadius.circular(10), + onTap: () => onTap(), + child: Container( + width: 320, + padding: const EdgeInsets.all(20), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(bottom: 12), + child: CircleAvatar( + backgroundColor: Colors.indigo, + child: icon, + ), + ), + Text( + title, + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.w900, + ), + ), + Text(caption), + ], + ), + ), + ), + ); + } +} diff --git a/lib/screens/auth.dart b/lib/screens/auth.dart new file mode 100755 index 0000000..cf739e3 --- /dev/null +++ b/lib/screens/auth.dart @@ -0,0 +1,41 @@ +import 'package:flutter/material.dart'; +import 'package:url_launcher/url_launcher.dart'; +import 'package:webview_flutter/webview_flutter.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + +class AuthorizationScreen extends StatelessWidget { + final Uri authorizationUrl; + + const AuthorizationScreen(this.authorizationUrl, {super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(AppLocalizations.of(context)!.signIn), + ), + body: Stack(children: [ + WebViewWidget( + controller: WebViewController() + ..setJavaScriptMode(JavaScriptMode.unrestricted) + ..setBackgroundColor(Colors.white) + ..setNavigationDelegate(NavigationDelegate( + onNavigationRequest: (NavigationRequest request) { + if (request.url.startsWith('solian')) { + Navigator.of(context).pop(request.url); + WebViewCookieManager().clearCookies(); + return NavigationDecision.prevent; + } else if (request.url.contains("sign-up")) { + launchUrl(Uri.parse(request.url)); + return NavigationDecision.prevent; + } + return NavigationDecision.navigate; + }, + )) + ..loadRequest(authorizationUrl) + ..clearCache(), + ), + ]), + ); + } +} diff --git a/lib/screens/explore.dart b/lib/screens/explore.dart index 34fbae0..8ea46d4 100644 --- a/lib/screens/explore.dart +++ b/lib/screens/explore.dart @@ -1,15 +1,14 @@ import 'dart:convert'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; import 'package:solian/models/pagination.dart'; import 'package:solian/models/post.dart'; import 'package:solian/utils/service_url.dart'; import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart'; -import 'package:solian/providers/layout_provider.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:http/http.dart' as http; import 'package:solian/widgets/posts/item.dart'; +import 'package:solian/widgets/wrapper.dart'; class ExploreScreen extends StatefulWidget { const ExploreScreen({super.key}); @@ -51,12 +50,6 @@ class _ExploreScreenState extends State { @override void initState() { - Future.delayed(Duration.zero, () { - // Wait for the context - context.read().title = - AppLocalizations.of(context)!.explore; - }); - super.initState(); _pagingController.addPageRequestListener((pageKey) => fetchFeed(pageKey)); @@ -64,18 +57,21 @@ class _ExploreScreenState extends State { @override Widget build(BuildContext context) { - return RefreshIndicator( - onRefresh: () => Future.sync( - () => _pagingController.refresh(), - ), - child: Center( - child: Container( - constraints: const BoxConstraints(maxWidth: 720), - child: PagedListView.separated( - pagingController: _pagingController, - separatorBuilder: (context, index) => const Divider(thickness: 0.3), - builderDelegate: PagedChildBuilderDelegate( - itemBuilder: (context, item, index) => PostItem(item: item), + return LayoutWrapper( + title: AppLocalizations.of(context)!.explore, + child: RefreshIndicator( + onRefresh: () => Future.sync( + () => _pagingController.refresh(), + ), + child: Center( + child: Container( + constraints: const BoxConstraints(maxWidth: 720), + child: PagedListView.separated( + pagingController: _pagingController, + separatorBuilder: (context, index) => const Divider(thickness: 0.3), + builderDelegate: PagedChildBuilderDelegate( + itemBuilder: (context, item, index) => PostItem(item: item), + ), ), ), ), diff --git a/lib/widgets/navigation_drawer.dart b/lib/widgets/navigation_drawer.dart index 92207e6..d06dee7 100644 --- a/lib/widgets/navigation_drawer.dart +++ b/lib/widgets/navigation_drawer.dart @@ -27,6 +27,13 @@ class _SolianNavigationDrawerState extends State { ), "explore", ), + ( + NavigationDrawerDestination( + icon: const Icon(Icons.account_circle), + label: Text(AppLocalizations.of(context)!.account), + ), + "account", + ), ]; return NavigationDrawer( diff --git a/lib/widgets/posts/item.dart b/lib/widgets/posts/item.dart index 8c27ed3..2a74186 100644 --- a/lib/widgets/posts/item.dart +++ b/lib/widgets/posts/item.dart @@ -36,8 +36,6 @@ class _PostItemState extends State { @override Widget build(BuildContext context) { - const borderRadius = Radius.circular(16); - return Padding( padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16), child: Column( diff --git a/lib/widgets/wrapper.dart b/lib/widgets/wrapper.dart index 928c96c..3befc6e 100644 --- a/lib/widgets/wrapper.dart +++ b/lib/widgets/wrapper.dart @@ -1,20 +1,17 @@ import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; -import 'package:solian/providers/layout_provider.dart'; import 'package:solian/widgets/navigation_drawer.dart'; class LayoutWrapper extends StatelessWidget { final Widget? child; + final String title; - const LayoutWrapper({super.key, this.child}); + const LayoutWrapper({super.key, this.child, required this.title}); @override Widget build(BuildContext context) { - var cfg = context.watch(); - return Scaffold( drawer: const SolianNavigationDrawer(), - appBar: AppBar(title: Text(cfg.title)), + appBar: AppBar(title: Text(title)), body: child ?? Container(), ); } diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index 1488f85..71fe128 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -6,10 +6,14 @@ #include "generated_plugin_registrant.h" +#include #include #include void fl_register_plugins(FlPluginRegistry* registry) { + 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); g_autoptr(FlPluginRegistrar) media_kit_video_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "MediaKitVideoPlugin"); media_kit_video_plugin_register_with_registrar(media_kit_video_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 3439794..4ab696d 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + flutter_secure_storage_linux media_kit_video url_launcher_linux ) diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index c7b0cb8..0e54e39 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,16 +5,20 @@ import FlutterMacOS import Foundation +import flutter_secure_storage_macos import media_kit_video import package_info_plus +import path_provider_foundation import screen_brightness_macos import url_launcher_macos import video_player_avfoundation import wakelock_plus func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin")) MediaKitVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitVideoPlugin")) FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) ScreenBrightnessMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenBrightnessMacosPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) FVPVideoPlayerPlugin.register(with: registry.registrar(forPlugin: "FVPVideoPlayerPlugin")) diff --git a/pubspec.lock b/pubspec.lock index 6f1ab50..f01a978 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -163,6 +163,54 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.22+1" + flutter_secure_storage: + dependency: "direct main" + description: + name: flutter_secure_storage + sha256: ffdbb60130e4665d2af814a0267c481bcf522c41ae2e43caf69fa0146876d685 + url: "https://pub.dev" + source: hosted + version: "9.0.0" + flutter_secure_storage_linux: + dependency: transitive + description: + name: flutter_secure_storage_linux + sha256: "3d5032e314774ee0e1a7d0a9f5e2793486f0dff2dd9ef5a23f4e3fb2a0ae6a9e" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + flutter_secure_storage_macos: + dependency: transitive + description: + name: flutter_secure_storage_macos + sha256: bd33935b4b628abd0b86c8ca20655c5b36275c3a3f5194769a7b3f37c905369c + url: "https://pub.dev" + source: hosted + version: "3.0.1" + flutter_secure_storage_platform_interface: + dependency: transitive + description: + name: flutter_secure_storage_platform_interface + sha256: "0d4d3a5dd4db28c96ae414d7ba3b8422fd735a8255642774803b2532c9a61d7e" + url: "https://pub.dev" + source: hosted + version: "1.0.2" + flutter_secure_storage_web: + dependency: transitive + description: + name: flutter_secure_storage_web + sha256: "30f84f102df9dcdaa2241866a958c2ec976902ebdaa8883fbfe525f1f2f3cf20" + url: "https://pub.dev" + source: hosted + version: "1.1.2" + flutter_secure_storage_windows: + dependency: transitive + description: + name: flutter_secure_storage_windows + sha256: "5809c66f9dd3b4b93b0a6e2e8561539405322ee767ac2f64d084e2ab5429d108" + url: "https://pub.dev" + source: hosted + version: "3.0.0" flutter_staggered_grid_view: dependency: transitive description: @@ -341,6 +389,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.0" + oauth2: + dependency: "direct main" + description: + name: oauth2 + sha256: c4013ef62be37744efdc0861878fd9e9285f34db1f9e331cc34100d7674feb42 + url: "https://pub.dev" + source: hosted + version: "2.0.2" package_info_plus: dependency: transitive description: @@ -365,6 +421,54 @@ packages: url: "https://pub.dev" source: hosted version: "1.9.0" + path_provider: + dependency: transitive + description: + name: path_provider + sha256: c9e7d3a4cd1410877472158bee69963a4579f78b68c65a2b7d40d1a7a88bb161 + url: "https://pub.dev" + source: hosted + version: "2.1.3" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: a248d8146ee5983446bf03ed5ea8f6533129a12b11f12057ad1b4a67a2b3b41d + url: "https://pub.dev" + source: hosted + version: "2.2.4" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 + url: "https://pub.dev" + source: hosted + version: "2.2.1" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" + url: "https://pub.dev" + source: hosted + version: "2.2.1" petitparser: dependency: transitive description: @@ -373,6 +477,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.0.2" + platform: + dependency: transitive + description: + name: platform + sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" + url: "https://pub.dev" + source: hosted + version: "3.1.4" plugin_platform_interface: dependency: transitive description: @@ -722,6 +834,38 @@ packages: url: "https://pub.dev" source: hosted version: "0.5.1" + webview_flutter: + dependency: "direct main" + description: + name: webview_flutter + sha256: "25e1b6e839e8cbfbd708abc6f85ed09d1727e24e08e08c6b8590d7c65c9a8932" + url: "https://pub.dev" + source: hosted + version: "4.7.0" + webview_flutter_android: + dependency: transitive + description: + name: webview_flutter_android + sha256: f038ee2fae73b509dde1bc9d2c5a50ca92054282de17631a9a3d515883740934 + url: "https://pub.dev" + source: hosted + version: "3.16.0" + webview_flutter_platform_interface: + dependency: transitive + description: + name: webview_flutter_platform_interface + sha256: d937581d6e558908d7ae3dc1989c4f87b786891ab47bb9df7de548a151779d8d + url: "https://pub.dev" + source: hosted + version: "2.10.0" + webview_flutter_wkwebview: + dependency: transitive + description: + name: webview_flutter_wkwebview + sha256: f12f8d8a99784b863e8b85e4a9a5e3cf1839d6803d2c0c3e0533a8f3c5a992a7 + url: "https://pub.dev" + source: hosted + version: "3.13.0" win32: dependency: transitive description: @@ -730,6 +874,14 @@ packages: url: "https://pub.dev" source: hosted version: "5.4.0" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d + url: "https://pub.dev" + source: hosted + version: "1.0.4" xml: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 9c2a66c..9a35d62 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -50,6 +50,9 @@ dependencies: media_kit_video: ^1.2.4 chewie: ^1.8.1 video_player: ^2.8.6 + flutter_secure_storage: ^9.0.0 + oauth2: ^2.0.2 + webview_flutter: ^4.7.0 dev_dependencies: flutter_test: diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index fa1110c..c38fbf3 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -6,11 +6,14 @@ #include "generated_plugin_registrant.h" +#include #include #include #include void RegisterPlugins(flutter::PluginRegistry* registry) { + FlutterSecureStorageWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin")); MediaKitVideoPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("MediaKitVideoPluginCApi")); ScreenBrightnessWindowsPluginRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 3ded1e2..827eb9c 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + flutter_secure_storage_windows media_kit_video screen_brightness_windows url_launcher_windows