diff --git a/build.yaml b/build.yaml new file mode 100644 index 0000000..d439bdd --- /dev/null +++ b/build.yaml @@ -0,0 +1,7 @@ +targets: + $default: + builders: + json_serializable: + options: + explicit_to_json: true + field_rename: snake \ No newline at end of file diff --git a/lib/controllers/post_list_controller.dart b/lib/controllers/post_list_controller.dart index 2a952e6..421ff31 100644 --- a/lib/controllers/post_list_controller.dart +++ b/lib/controllers/post_list_controller.dart @@ -1,10 +1,15 @@ +import 'dart:math'; + import 'package:get/get.dart'; import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart'; +import 'package:shared_preferences/shared_preferences.dart'; import 'package:solian/models/pagination.dart'; import 'package:solian/models/post.dart'; import 'package:solian/providers/content/posts.dart'; class PostListController extends GetxController { + late final SharedPreferences _prefs; + String? author; /// The polling source modifier. @@ -19,9 +24,16 @@ class PostListController extends GetxController { PagingController(firstPageKey: 0); PostListController({this.author}) { + _initPreferences(); _initPagingController(); } + void _initPreferences() { + SharedPreferences.getInstance().then((prefs) { + _prefs = prefs; + }); + } + /// Initialize a compatibility layer to paging controller void _initPagingController() { pagingController.addPageRequestListener(_onPagingControllerRequest); @@ -96,6 +108,13 @@ class PostListController extends GetxController { final idx = {}; postList.retainWhere((x) => idx.add(x.id)); + var lastId = postList.map((x) => x.id).reduce(max); + if (_prefs.containsKey('feed_last_read_at')) { + final storedId = _prefs.getInt('feed_last_read_at') ?? 0; + lastId = max(storedId, lastId); + } + _prefs.setInt('feed_last_read_at', lastId); + return result; } diff --git a/lib/main.dart b/lib/main.dart index 81c5c98..214b8b4 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -13,6 +13,7 @@ import 'package:solian/bootstrapper.dart'; import 'package:solian/firebase_options.dart'; import 'package:solian/platform.dart'; import 'package:solian/providers/attachment_uploader.dart'; +import 'package:solian/providers/daily_sign.dart'; import 'package:solian/providers/link_expander.dart'; import 'package:solian/providers/stickers.dart'; import 'package:solian/providers/theme_switcher.dart'; @@ -129,6 +130,7 @@ class SolianApp extends StatelessWidget { Get.lazyPut(() => RealmProvider()); Get.lazyPut(() => ChatCallProvider()); Get.lazyPut(() => AttachmentUploaderController()); - Get.lazyPut(() => LinkExpandController()); + Get.lazyPut(() => LinkExpandProvider()); + Get.lazyPut(() => DailySignProvider()); } } diff --git a/lib/models/daily_sign.dart b/lib/models/daily_sign.dart new file mode 100644 index 0000000..4b55a79 --- /dev/null +++ b/lib/models/daily_sign.dart @@ -0,0 +1,48 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:solian/models/account.dart'; + +part 'daily_sign.g.dart'; + +@JsonSerializable() +class DailySignRecord { + int id; + DateTime createdAt; + DateTime updatedAt; + DateTime? deletedAt; + Account account; + int resultTier; + int resultExperience; + int accountId; + + DailySignRecord({ + required this.id, + required this.createdAt, + required this.updatedAt, + required this.deletedAt, + required this.resultTier, + required this.resultExperience, + required this.account, + required this.accountId, + }); + + factory DailySignRecord.fromJson(Map json) => + _$DailySignRecordFromJson(json); + + Map toJson() => _$DailySignRecordToJson(this); + + String get symbol => switch (resultTier) { + 0 => '大\n凶', + 1 => '凶', + 2 => '中\n平', + 3 => '吉', + _ => '大\n吉', + }; + + String get overviewSuggestion => switch (resultTier) { + 0 => '诸事不宜', + 1 => '有些不宜', + 2 => '平平淡淡', + 3 => '有些事宜', + _ => '诸事皆宜', + }; +} diff --git a/lib/models/daily_sign.g.dart b/lib/models/daily_sign.g.dart new file mode 100644 index 0000000..02a37b5 --- /dev/null +++ b/lib/models/daily_sign.g.dart @@ -0,0 +1,33 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'daily_sign.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +DailySignRecord _$DailySignRecordFromJson(Map json) => + DailySignRecord( + id: (json['id'] as num).toInt(), + createdAt: DateTime.parse(json['created_at'] as String), + updatedAt: DateTime.parse(json['updated_at'] as String), + deletedAt: json['deleted_at'] == null + ? null + : DateTime.parse(json['deleted_at'] as String), + resultTier: (json['result_tier'] as num).toInt(), + resultExperience: (json['result_experience'] as num).toInt(), + account: Account.fromJson(json['account'] as Map), + accountId: (json['account_id'] as num).toInt(), + ); + +Map _$DailySignRecordToJson(DailySignRecord instance) => + { + 'id': instance.id, + 'created_at': instance.createdAt.toIso8601String(), + 'updated_at': instance.updatedAt.toIso8601String(), + 'deleted_at': instance.deletedAt?.toIso8601String(), + 'account': instance.account.toJson(), + 'result_tier': instance.resultTier, + 'result_experience': instance.resultExperience, + 'account_id': instance.accountId, + }; diff --git a/lib/providers/daily_sign.dart b/lib/providers/daily_sign.dart new file mode 100644 index 0000000..915f5e5 --- /dev/null +++ b/lib/providers/daily_sign.dart @@ -0,0 +1,37 @@ +import 'package:get/get.dart'; +import 'package:solian/exceptions/request.dart'; +import 'package:solian/exceptions/unauthorized.dart'; +import 'package:solian/models/daily_sign.dart'; +import 'package:solian/providers/auth.dart'; + +class DailySignProvider extends GetxController { + Future getToday() async { + final AuthProvider auth = Get.find(); + if (auth.isAuthorized.isFalse) throw const UnauthorizedException(); + + final client = auth.configureClient('id'); + + final resp = await client.get('/daily/today'); + if (resp.statusCode != 200 && resp.statusCode != 404) { + throw RequestException(resp); + } else if (resp.statusCode == 404) { + return null; + } + + return DailySignRecord.fromJson(resp.body); + } + + Future signToday() async { + final AuthProvider auth = Get.find(); + if (auth.isAuthorized.isFalse) throw const UnauthorizedException(); + + final client = auth.configureClient('id'); + + final resp = await client.post('/daily', {}); + if (resp.statusCode != 200) { + throw RequestException(resp); + } + + return DailySignRecord.fromJson(resp.body); + } +} diff --git a/lib/providers/link_expander.dart b/lib/providers/link_expander.dart index 76b2682..281d65e 100644 --- a/lib/providers/link_expander.dart +++ b/lib/providers/link_expander.dart @@ -5,7 +5,7 @@ import 'package:get/get.dart'; import 'package:solian/models/link.dart'; import 'package:solian/services.dart'; -class LinkExpandController extends GetxController { +class LinkExpandProvider extends GetxController { final Map _cachedResponse = {}; Future expandLink(String url) async { diff --git a/lib/screens/dashboard.dart b/lib/screens/dashboard.dart index c950bf6..3acc360 100644 --- a/lib/screens/dashboard.dart +++ b/lib/screens/dashboard.dart @@ -2,9 +2,19 @@ import 'dart:math'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:google_fonts/google_fonts.dart'; import 'package:intl/intl.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:solian/exts.dart'; +import 'package:solian/models/daily_sign.dart'; +import 'package:solian/models/pagination.dart'; +import 'package:solian/models/post.dart'; +import 'package:solian/providers/content/posts.dart'; +import 'package:solian/providers/daily_sign.dart'; import 'package:solian/providers/websocket.dart'; +import 'package:solian/router.dart'; import 'package:solian/screens/account/notification.dart'; +import 'package:solian/widgets/posts/post_list.dart'; class DashboardScreen extends StatefulWidget { const DashboardScreen({super.key}); @@ -15,6 +25,57 @@ class DashboardScreen extends StatefulWidget { class _DashboardScreenState extends State { late final WebSocketProvider _ws = Get.find(); + late final PostProvider _posts = Get.find(); + late final DailySignProvider _dailySign = Get.find(); + + List? _currentPosts; + + Future _pullPosts() async { + final prefs = await SharedPreferences.getInstance(); + final resp = await _posts.listRecommendations(0); + final result = PaginationResult.fromJson(resp.body); + if (prefs.containsKey('feed_last_read_at')) { + final id = prefs.getInt('feed_last_read_at')!; + setState(() { + _currentPosts = result.data + ?.map((e) => Post.fromJson(e)) + .where((x) => x.id > id) + .toList(); + }); + } + } + + bool _signingDaily = true; + DailySignRecord? _signRecord; + + Future _pullDaily() async { + try { + _signRecord = await _dailySign.getToday(); + } catch (e) { + context.showErrorDialog(e); + } + + setState(() => _signingDaily = false); + } + + Future _signDaily() async { + setState(() => _signingDaily = true); + + try { + _signRecord = await _dailySign.signToday(); + } catch (e) { + context.showErrorDialog(e); + } + + setState(() => _signingDaily = false); + } + + @override + void initState() { + super.initState(); + _pullPosts(); + _pullDaily(); + } @override Widget build(BuildContext context) { @@ -28,7 +89,65 @@ class _DashboardScreenState extends State { Text('today'.tr, style: Theme.of(context).textTheme.headlineSmall), Text(DateFormat('yyyy/MM/dd').format(DateTime.now())), ], - ).paddingOnly(top: 8, left: 18, right: 18), + ).paddingOnly(top: 8, left: 18, right: 18, bottom: 12), + Card( + child: ListTile( + leading: AnimatedSwitcher( + switchInCurve: Curves.fastOutSlowIn, + switchOutCurve: Curves.fastOutSlowIn, + duration: const Duration(milliseconds: 300), + transitionBuilder: (child, animation) { + return ScaleTransition( + scale: animation, + child: child, + ); + }, + child: _signRecord == null + ? Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + DateFormat('dd').format(DateTime.now()), + style: + GoogleFonts.robotoMono(fontSize: 22, height: 1.2), + ), + Text( + DateFormat('yy/MM').format(DateTime.now()), + style: GoogleFonts.robotoMono(fontSize: 12), + ), + ], + ) + : Text( + _signRecord!.symbol, + style: GoogleFonts.notoSerifHk(fontSize: 20, height: 1), + ).paddingSymmetric(horizontal: 9), + ).paddingOnly(left: 4), + title: _signRecord == null + ? const Text('诸事不宜') + : Text(_signRecord!.overviewSuggestion), + subtitle: _signRecord == null + ? const Text('今日未拜访佛祖') + : Text('+${_signRecord!.resultExperience} EXP'), + trailing: AnimatedSwitcher( + switchInCurve: Curves.fastOutSlowIn, + switchOutCurve: Curves.fastOutSlowIn, + duration: const Duration(milliseconds: 300), + transitionBuilder: (child, animation) { + return ScaleTransition( + scale: animation, + child: child, + ); + }, + child: _signRecord == null + ? IconButton( + tooltip: '上香求签', + icon: const Icon(Icons.local_fire_department), + onPressed: _signingDaily ? null : _signDaily, + ) + : const SizedBox(), + ), + ), + ).paddingSymmetric(horizontal: 8), const Divider(thickness: 0.3).paddingSymmetric(vertical: 8), Obx( () => Column( @@ -108,8 +227,72 @@ class _DashboardScreenState extends State { ), ).paddingSymmetric(horizontal: 8), ], - ), + ).paddingOnly(bottom: 12), ), + if (_currentPosts?.isNotEmpty ?? false) + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'feed'.tr, + style: Theme.of(context) + .textTheme + .titleMedium! + .copyWith(fontSize: 18), + ), + Text( + 'notificationUnreadCount'.trParams({ + 'count': (_currentPosts?.length ?? 0).toString(), + }), + ), + ], + ), + IconButton( + icon: const Icon(Icons.arrow_forward), + onPressed: () { + AppRouter.instance.goNamed('feed'); + }, + ), + ], + ).paddingOnly(left: 18, right: 18, bottom: 8), + SizedBox( + height: 360, + width: width, + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: _currentPosts!.length, + itemBuilder: (context, idx) { + final item = _currentPosts![idx]; + return SizedBox( + width: width, + child: Card( + child: Card( + child: PostListEntryWidget( + item: item, + isClickable: true, + isShowEmbed: true, + isNestedClickable: true, + onUpdate: (_) { + _pullPosts(); + }, + backgroundColor: Theme.of(context) + .colorScheme + .surfaceContainerLow, + ), + ), + ).paddingSymmetric(horizontal: 8), + ); + }, + ), + ) + ], + ), ], ); } diff --git a/lib/screens/feed.dart b/lib/screens/feed.dart index 7c7c0ed..8c4ebf9 100644 --- a/lib/screens/feed.dart +++ b/lib/screens/feed.dart @@ -65,7 +65,7 @@ class _FeedScreenState extends State headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { return [ SliverAppBar( - title: AppBarTitle('home'.tr), + title: AppBarTitle('feed'.tr), centerTitle: false, floating: true, toolbarHeight: SolianTheme.toolbarHeight(context), diff --git a/lib/widgets/link_expansion.dart b/lib/widgets/link_expansion.dart index da5f6c4..aeddb40 100644 --- a/lib/widgets/link_expansion.dart +++ b/lib/widgets/link_expansion.dart @@ -60,7 +60,7 @@ class LinkExpansion extends StatelessWidget { return const SizedBox(); } - final LinkExpandController expandController = Get.find(); + final LinkExpandProvider expandController = Get.find(); return Wrap( children: matches.map((x) { diff --git a/lib/widgets/navigation/app_navigation.dart b/lib/widgets/navigation/app_navigation.dart index 9e792c4..cc1cff9 100644 --- a/lib/widgets/navigation/app_navigation.dart +++ b/lib/widgets/navigation/app_navigation.dart @@ -4,9 +4,14 @@ import 'package:get/utils.dart'; abstract class AppNavigation { static List destinations = [ AppNavigationDestination( - icon: Icons.home, - label: 'home'.tr, - page: 'home', + icon: Icons.dashboard, + label: 'dashboard'.tr, + page: 'dashboard', + ), + AppNavigationDestination( + icon: Icons.newspaper, + label: 'feed'.tr, + page: 'feed', ), AppNavigationDestination( icon: Icons.workspaces, diff --git a/pubspec.lock b/pubspec.lock index 69f766c..7dd208a 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -13,10 +13,10 @@ packages: dependency: transitive description: name: _flutterfire_internals - sha256: b1595874fbc8f7a50da90f5d8f327bb0bfd6a95dc906c390efe991540c3b54aa + sha256: "9371d13b8ee442e3bfc08a24e3a1b3742c839abbfaf5eef11b79c4b862c89bf7" url: "https://pub.dev" source: hosted - version: "1.3.40" + version: "1.3.41" _macros: dependency: transitive description: dart @@ -466,114 +466,114 @@ packages: dependency: "direct main" description: name: firebase_analytics - sha256: "064e5b57b0693305946b7caa6a80ed80a918f46804c247b6cd7ed9cd327df48f" + sha256: "7e032ade38dec2a92f543ba02c5f72f54ffaa095c60d2132b867eab56de3bc73" url: "https://pub.dev" source: hosted - version: "11.2.1" + version: "11.3.0" firebase_analytics_platform_interface: dependency: transitive description: name: firebase_analytics_platform_interface - sha256: d094547c9022c404b5ca39b7209607fc80e75e39d38875f050508fa4346b3e74 + sha256: b62a2444767d95067a7e36b1d6e335e0b877968574bbbfb656168c46f2e95a13 url: "https://pub.dev" source: hosted - version: "4.2.1" + version: "4.2.2" firebase_analytics_web: dependency: transitive description: name: firebase_analytics_web - sha256: "06dc023b0144c0df630a56b6262cc9e7d6069fe78148853d97614dbefb6ea923" + sha256: bad44f71f96cfca6c16c9dd4f70b85f123ddca7d5dd698977449fadf298b1782 url: "https://pub.dev" source: hosted - version: "0.5.9+1" + version: "0.5.9+2" firebase_core: dependency: "direct main" description: name: firebase_core - sha256: "3187f4f8e49968573fd7403011dca67ba95aae419bc0d8131500fae160d94f92" + sha256: "06537da27db981947fa535bb91ca120b4e9cb59cb87278dbdde718558cafc9ff" url: "https://pub.dev" source: hosted - version: "3.3.0" + version: "3.4.0" firebase_core_platform_interface: dependency: transitive description: name: firebase_core_platform_interface - sha256: "3c3a1e92d6f4916c32deea79c4a7587aa0e9dbbe5889c7a16afcf005a485ee02" + sha256: f7d7180c7f99babd4b4c517754d41a09a4943a0f7a69b65c894ca5c68ba66315 url: "https://pub.dev" source: hosted - version: "5.2.0" + version: "5.2.1" firebase_core_web: dependency: transitive description: name: firebase_core_web - sha256: e8d1e22de72cb21cdcfc5eed7acddab3e99cd83f3b317f54f7a96c32f25fd11e + sha256: "362e52457ed2b7b180964769c1e04d1e0ea0259fdf7025fdfedd019d4ae2bd88" url: "https://pub.dev" source: hosted - version: "2.17.4" + version: "2.17.5" firebase_crashlytics: dependency: "direct main" description: name: firebase_crashlytics - sha256: "30260e1b8ad1464b41ca4531b44ce63d752daaf2f12c92ca6cdcd82b270abecc" + sha256: "4c9872020c0d97a161362ee6af7000cfdb8666234ddc290a15252ad379bb235a" url: "https://pub.dev" source: hosted - version: "4.0.4" + version: "4.1.0" firebase_crashlytics_platform_interface: dependency: transitive description: name: firebase_crashlytics_platform_interface - sha256: a75e1826d92ea4e86e4a753c7b5d64b844a362676fa653185f1581c859186d18 + sha256: ede8a199ff03378857d3c8cbb7fa58d37c27bb5a6b75faf8415ff6925dcaae2a url: "https://pub.dev" source: hosted - version: "3.6.40" + version: "3.6.41" firebase_messaging: dependency: "direct main" description: name: firebase_messaging - sha256: "1b0a4f9ecbaf9007771bac152afad738ddfacc4b8431a7591c00829480d99553" + sha256: "29941ba5a3204d80656c0e52103369aa9a53edfd9ceae05a2bb3376f24fda453" url: "https://pub.dev" source: hosted - version: "15.0.4" + version: "15.1.0" firebase_messaging_platform_interface: dependency: transitive description: name: firebase_messaging_platform_interface - sha256: c5a6443e66ae064fe186901d740ee7ce648ca2a6fd0484b8c5e963849ac0fc28 + sha256: "26c5370d3a79b15c8032724a68a4741e28f63e1f1a45699c4f0a8ae740aadd72" url: "https://pub.dev" source: hosted - version: "4.5.42" + version: "4.5.43" firebase_messaging_web: dependency: transitive description: name: firebase_messaging_web - sha256: "232ef63b986467ae5b5577a09c2502b26e2e2aebab5b85e6c966a5ca9b038b89" + sha256: "58276cd5d9e22a9320ef9e5bc358628920f770f93c91221f8b638e8346ed5df4" url: "https://pub.dev" source: hosted - version: "3.8.12" + version: "3.8.13" firebase_performance: dependency: "direct main" description: name: firebase_performance - sha256: "6d17133458b9627f15f278d6f71bebbbce885d393f3462b690e55deeb5c36b90" + sha256: "66666f697ecdcca2616af99f8ccfa74d795e5819c598227f2784fc00b1c6e421" url: "https://pub.dev" source: hosted - version: "0.10.0+4" + version: "0.10.0+5" firebase_performance_platform_interface: dependency: transitive description: name: firebase_performance_platform_interface - sha256: "28dc0a70a3459fe51d1c1be5754803a9a0db0e210322ec7526f6ce42bf6ad83e" + sha256: ceaa026d067347cc6ea11113ba926ae450f56e305c186d1edce78f05983b481a url: "https://pub.dev" source: hosted - version: "0.1.4+40" + version: "0.1.4+41" firebase_performance_web: dependency: transitive description: name: firebase_performance_web - sha256: db91d86b34280f5253d2913945fdd51d7114486584a298a7bedf1c4b2ab08f79 + sha256: "6d121cd7e27b63995998dc4039caf0cbf304c2eee6fc6ed9ac7f80860cc0e51c" url: "https://pub.dev" source: hosted - version: "0.1.6+12" + version: "0.1.6+13" fixnum: dependency: transitive description: @@ -853,6 +853,22 @@ packages: url: "https://pub.dev" source: hosted version: "10.7.0" + freezed: + dependency: "direct dev" + description: + name: freezed + sha256: "44c19278dd9d89292cf46e97dc0c1e52ce03275f40a97c5a348e802a924bf40e" + url: "https://pub.dev" + source: hosted + version: "2.5.7" + freezed_annotation: + dependency: "direct main" + description: + name: freezed_annotation + sha256: c2e2d632dd9b8a2b7751117abcfc2b4888ecfe181bd9fca7170d9ef02e595fe2 + url: "https://pub.dev" + source: hosted + version: "2.4.4" frontend_server_client: dependency: transitive description: @@ -893,6 +909,14 @@ packages: url: "https://pub.dev" source: hosted version: "14.2.7" + google_fonts: + dependency: "direct main" + description: + name: google_fonts + sha256: b1ac0fe2832c9cc95e5e88b57d627c5e68c223b9657f4b96e1487aa9098c7b82 + url: "https://pub.dev" + source: hosted + version: "6.2.1" graphs: dependency: transitive description: @@ -1070,13 +1094,21 @@ packages: source: hosted version: "0.6.7" json_annotation: - dependency: transitive + dependency: "direct main" description: name: json_annotation sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" url: "https://pub.dev" source: hosted version: "4.9.0" + json_serializable: + dependency: "direct dev" + description: + name: json_serializable + sha256: ea1432d167339ea9b5bb153f0571d0039607a873d6e04e0117af043f14a1fd4b + url: "https://pub.dev" + source: hosted + version: "6.8.0" leak_tracker: dependency: transitive description: @@ -1265,10 +1297,10 @@ packages: dependency: transitive description: name: mime - sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2" + sha256: "801fd0b26f14a4a58ccb09d5892c3fbdeff209594300a542492cf13fba9d247a" url: "https://pub.dev" source: hosted - version: "1.0.5" + version: "1.0.6" nested: dependency: transitive description: @@ -1778,6 +1810,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.0" + source_helper: + dependency: transitive + description: + name: source_helper + sha256: "6adebc0006c37dd63fe05bca0a929b99f06402fc95aa35bf36d67f5c06de01fd" + url: "https://pub.dev" + source: hosted + version: "1.3.4" source_span: dependency: transitive description: @@ -2030,10 +2070,10 @@ packages: dependency: "direct main" description: name: uuid - sha256: "83d37c7ad7aaf9aa8e275490669535c8080377cfa7a7004c24dfac53afffaa90" + sha256: f33d6bb662f0e4f79dcd7ada2e6170f3b3a2530c28fc41f49a411ddedd576a77 url: "https://pub.dev" source: hosted - version: "4.4.2" + version: "4.5.0" vector_graphics: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index a4a827b..d1791b7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -73,6 +73,9 @@ dependencies: media_kit_libs_video: ^1.0.4 flutter_svg: ^2.0.10+1 cross_file: ^0.3.4+2 + google_fonts: ^6.2.1 + freezed_annotation: ^2.4.4 + json_annotation: ^4.9.0 dev_dependencies: flutter_test: @@ -82,10 +85,12 @@ dev_dependencies: flutter_launcher_icons: ^0.13.1 floor_generator: ^1.4.0 - build_runner: ^2.1.2 + build_runner: ^2.4.12 sqflite_common_ffi: ^2.3.3 sqflite_common_ffi_web: ^0.4.3+1 flutter_native_splash: ^2.4.1 + freezed: ^2.5.7 + json_serializable: ^6.8.0 flutter: uses-material-design: true