diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..c935ab69 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,3 @@ +##1.0.0 + +- **BREAKING** feat!: migrated from date based versioning to semantic versioning. \ No newline at end of file diff --git a/lib/app_configuration/view/tabs/feed_configuration_tab.dart b/lib/app_configuration/view/tabs/feed_configuration_tab.dart index 83099120..cbff2078 100644 --- a/lib/app_configuration/view/tabs/feed_configuration_tab.dart +++ b/lib/app_configuration/view/tabs/feed_configuration_tab.dart @@ -1,6 +1,7 @@ import 'package:core/core.dart'; import 'package:flutter/material.dart'; import 'package:flutter_news_app_web_dashboard_full_source_code/app_configuration/widgets/feed_decorator_form.dart'; +import 'package:flutter_news_app_web_dashboard_full_source_code/app_configuration/widgets/saved_headlines_filters_limit_form.dart'; import 'package:flutter_news_app_web_dashboard_full_source_code/app_configuration/widgets/user_preference_limits_form.dart'; import 'package:flutter_news_app_web_dashboard_full_source_code/l10n/l10n.dart'; import 'package:flutter_news_app_web_dashboard_full_source_code/shared/extensions/feed_decorator_type_l10n.dart'; @@ -67,6 +68,15 @@ class _FeedConfigurationTabState extends State { }, initiallyExpanded: expandedIndex == tileIndex, children: [ + Text( + l10n.userContentLimitsDescription, + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: Theme.of( + context, + ).colorScheme.onSurface.withOpacity(0.7), + ), + ), + const SizedBox(height: AppSpacing.lg), UserPreferenceLimitsForm( remoteConfig: widget.remoteConfig, onConfigChanged: widget.onConfigChanged, @@ -76,11 +86,48 @@ class _FeedConfigurationTabState extends State { }, ), const SizedBox(height: AppSpacing.lg), - // New Top-level ExpansionTile for Feed Decorators + // New Top-level ExpansionTile for User Preset Limits ValueListenableBuilder( valueListenable: _expandedTileIndex, builder: (context, expandedIndex, child) { const tileIndex = 1; + return ExpansionTile( + key: ValueKey('savedHeadlinesFilterLimitsTile_$expandedIndex'), + title: Text(l10n.savedHeadlinesFilterLimitsTitle), + childrenPadding: const EdgeInsetsDirectional.only( + start: AppSpacing.lg, + top: AppSpacing.md, + bottom: AppSpacing.md, + ), + expandedCrossAxisAlignment: CrossAxisAlignment.start, + onExpansionChanged: (isExpanded) { + _expandedTileIndex.value = isExpanded ? tileIndex : null; + }, + initiallyExpanded: expandedIndex == tileIndex, + children: [ + Text( + l10n.savedHeadlinesFilterLimitsDescription, + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: Theme.of( + context, + ).colorScheme.onSurface.withOpacity(0.7), + ), + ), + const SizedBox(height: AppSpacing.lg), + SavedHeadlinesFiltersLimitForm( + remoteConfig: widget.remoteConfig, + onConfigChanged: widget.onConfigChanged, + ), + ], + ); + }, + ), + const SizedBox(height: AppSpacing.lg), + // New Top-level ExpansionTile for Feed Decorators + ValueListenableBuilder( + valueListenable: _expandedTileIndex, + builder: (context, expandedIndex, child) { + const tileIndex = 2; return ExpansionTile( key: ValueKey('feedDecoratorsTile_$expandedIndex'), title: Text(l10n.feedDecoratorsTitle), diff --git a/lib/app_configuration/widgets/saved_headlines_filters_limit_form.dart b/lib/app_configuration/widgets/saved_headlines_filters_limit_form.dart new file mode 100644 index 00000000..cbdd24ae --- /dev/null +++ b/lib/app_configuration/widgets/saved_headlines_filters_limit_form.dart @@ -0,0 +1,182 @@ +import 'package:core/core.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_news_app_web_dashboard_full_source_code/app_configuration/widgets/app_config_form_fields.dart'; +import 'package:flutter_news_app_web_dashboard_full_source_code/l10n/l10n.dart'; +import 'package:flutter_news_app_web_dashboard_full_source_code/shared/extensions/app_user_role_l10n.dart'; +import 'package:ui_kit/ui_kit.dart'; + +/// {@template saved_headlines_filters_limit_form} +/// A form for configuring saved headlines filter limits within the +/// [RemoteConfig]. +/// +/// This form provides fields to set the maximum number of saved filters +/// for guest, authenticated, and premium users. +/// {@endtemplate} +class SavedHeadlinesFiltersLimitForm extends StatefulWidget { + /// {@macro saved_headlines_filters_limit_form} + const SavedHeadlinesFiltersLimitForm({ + required this.remoteConfig, + required this.onConfigChanged, + super.key, + }); + + /// The current [RemoteConfig] object. + final RemoteConfig remoteConfig; + + /// Callback to notify parent of changes to the [RemoteConfig]. + final ValueChanged onConfigChanged; + + @override + State createState() => + _SavedHeadlinesFiltersLimitFormState(); +} + +class _SavedHeadlinesFiltersLimitFormState + extends State + with SingleTickerProviderStateMixin { + late TabController _tabController; + late final Map _controllers; + + @override + void initState() { + super.initState(); + _tabController = TabController( + length: AppUserRole.values.length, + vsync: this, + ); + _initializeControllers(); + } + + @override + void didUpdateWidget(covariant SavedHeadlinesFiltersLimitForm oldWidget) { + super.didUpdateWidget(oldWidget); + if (widget.remoteConfig.userPreferenceConfig != + oldWidget.remoteConfig.userPreferenceConfig) { + _updateControllerValues(); + } + } + + void _initializeControllers() { + _controllers = { + for (final role in AppUserRole.values) + role: TextEditingController( + text: _getSavedFiltersLimit( + widget.remoteConfig.userPreferenceConfig, + role, + ).toString(), + )..selection = TextSelection.collapsed( + offset: _getSavedFiltersLimit( + widget.remoteConfig.userPreferenceConfig, + role, + ).toString().length, + ), + }; + } + + void _updateControllerValues() { + for (final role in AppUserRole.values) { + final newLimit = _getSavedFiltersLimit( + widget.remoteConfig.userPreferenceConfig, + role, + ).toString(); + if (_controllers[role]?.text != newLimit) { + _controllers[role]?.text = newLimit; + _controllers[role]?.selection = TextSelection.collapsed( + offset: newLimit.length, + ); + } + } + } + + @override + void dispose() { + _tabController.dispose(); + for (final controller in _controllers.values) { + controller.dispose(); + } + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final l10n = AppLocalizationsX(context).l10n; + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Align( + alignment: AlignmentDirectional.centerStart, + child: SizedBox( + height: kTextTabBarHeight, + child: TabBar( + controller: _tabController, + tabAlignment: TabAlignment.start, + isScrollable: true, + tabs: AppUserRole.values + .map((role) => Tab(text: role.l10n(context))) + .toList(), + ), + ), + ), + const SizedBox(height: AppSpacing.lg), + SizedBox( + height: 120, + child: TabBarView( + controller: _tabController, + children: AppUserRole.values.map((role) { + final config = widget.remoteConfig.userPreferenceConfig; + return AppConfigIntField( + label: l10n.savedHeadlinesLimitLabel, + description: l10n.savedHeadlinesLimitDescription, + value: _getSavedFiltersLimit(config, role), + onChanged: (value) { + widget.onConfigChanged( + widget.remoteConfig.copyWith( + userPreferenceConfig: + _updateSavedFiltersLimit(config, value, role), + ), + ); + }, + controller: _controllers[role], + ); + }).toList(), + ), + ), + ], + ); + } + + /// Retrieves the saved filters limit for a given [AppUserRole]. + /// + /// This helper method abstracts the logic for accessing the correct limit + /// from the [UserPreferenceConfig] based on the provided [role]. + int _getSavedFiltersLimit(UserPreferenceConfig config, AppUserRole role) { + switch (role) { + case AppUserRole.guestUser: + return config.guestSavedFiltersLimit; + case AppUserRole.standardUser: + return config.authenticatedSavedFiltersLimit; + case AppUserRole.premiumUser: + return config.premiumSavedFiltersLimit; + } + } + + /// Updates the saved filters limit for a given [AppUserRole]. + /// + /// This helper method abstracts the logic for updating the correct limit + /// within the [UserPreferenceConfig] based on the provided [role] and [value]. + UserPreferenceConfig _updateSavedFiltersLimit( + UserPreferenceConfig config, + int value, + AppUserRole role, + ) { + switch (role) { + case AppUserRole.guestUser: + return config.copyWith(guestSavedFiltersLimit: value); + case AppUserRole.standardUser: + return config.copyWith(authenticatedSavedFiltersLimit: value); + case AppUserRole.premiumUser: + return config.copyWith(premiumSavedFiltersLimit: value); + } + } +} diff --git a/lib/app_configuration/widgets/user_preference_limits_form.dart b/lib/app_configuration/widgets/user_preference_limits_form.dart index 873ec8e7..6bfca60d 100644 --- a/lib/app_configuration/widgets/user_preference_limits_form.dart +++ b/lib/app_configuration/widgets/user_preference_limits_form.dart @@ -142,13 +142,6 @@ class _UserPreferenceLimitsFormState extends State return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - l10n.userContentLimitsDescription, - style: Theme.of(context).textTheme.bodySmall?.copyWith( - color: Theme.of(context).colorScheme.onSurface.withOpacity(0.7), - ), - ), - const SizedBox(height: AppSpacing.lg), Align( alignment: AlignmentDirectional.centerStart, child: SizedBox( diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index 61fadf6c..48b37d6a 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -1592,6 +1592,18 @@ abstract class AppLocalizations { /// **'How often an ad can appear for this user role (e.g., a value of 5 means an ad could be placed after every 5 news items).'** String get adFrequencyDescription; + /// Description for the Saved Headlines Filter Limits section + /// + /// In en, this message translates to: + /// **'Set limits on the number of saved headlines filters for each user tier.'** + String get savedHeadlinesFilterLimitsDescription; + + /// Title for the Saved Headlines Filter Limits section + /// + /// In en, this message translates to: + /// **'Saved Headlines Filter Limits'** + String get savedHeadlinesFilterLimitsTitle; + /// Label for Ad Placement Interval /// /// In en, this message translates to: diff --git a/lib/l10n/app_localizations_ar.dart b/lib/l10n/app_localizations_ar.dart index 369d3342..1e778cbe 100644 --- a/lib/l10n/app_localizations_ar.dart +++ b/lib/l10n/app_localizations_ar.dart @@ -839,6 +839,13 @@ class AppLocalizationsAr extends AppLocalizations { String get adFrequencyDescription => 'عدد مرات ظهور الإعلان لهذا الدور المستخدم (على سبيل المثال، قيمة 5 تعني أنه يمكن وضع إعلان بعد كل 5 عناصر إخبارية).'; + @override + String get savedHeadlinesFilterLimitsDescription => + 'الحد الأقصى لعدد مرشحات العناوين المحفوظة التي يمكن لهذا الدور إنشاؤها.'; + + @override + String get savedHeadlinesFilterLimitsTitle => 'حدود مرشحات العناوين المحفوظة'; + @override String get adPlacementIntervalLabel => 'فترة وضع الإعلان'; diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index 18ee64ec..8523c0ff 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -837,6 +837,13 @@ class AppLocalizationsEn extends AppLocalizations { String get adFrequencyDescription => 'How often an ad can appear for this user role (e.g., a value of 5 means an ad could be placed after every 5 news items).'; + @override + String get savedHeadlinesFilterLimitsDescription => + 'Set limits on the number of saved headlines filters for each user tier.'; + + @override + String get savedHeadlinesFilterLimitsTitle => 'Saved Headlines Filter Limits'; + @override String get adPlacementIntervalLabel => 'Ad Placement Interval'; diff --git a/lib/l10n/arb/app_ar.arb b/lib/l10n/arb/app_ar.arb index 3db46135..b3e75a9b 100644 --- a/lib/l10n/arb/app_ar.arb +++ b/lib/l10n/arb/app_ar.arb @@ -1038,6 +1038,14 @@ "@adFrequencyDescription": { "description": "وصف تكرار الإعلان" }, + "savedHeadlinesFilterLimitsTitle": "حدود مرشحات العناوين المحفوظة", + "@savedHeadlinesFilterLimitsTitle": { + "description": "وصف لحد المرشحات المحفوظة" + }, + "savedHeadlinesFilterLimitsDescription": "الحد الأقصى لعدد مرشحات العناوين المحفوظة التي يمكن لهذا الدور إنشاؤها.", + "@savedHeadlinesFilterLimitsDescription": { + "description": "وصف لحد المرشحات المحفوظة" + }, "adPlacementIntervalLabel": "فترة وضع الإعلان", "@adPlacementIntervalLabel": { "description": "تسمية فترة وضع الإعلان" diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 8b7d9ff8..560b5542 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -1038,6 +1038,14 @@ "@adFrequencyDescription": { "description": "Description for Ad Frequency" }, + "savedHeadlinesFilterLimitsDescription": "Set limits on the number of saved headlines filters for each user tier.", + "@savedHeadlinesFilterLimitsDescription": { + "description": "Description for the Saved Headlines Filter Limits section" + }, + "savedHeadlinesFilterLimitsTitle": "Saved Headlines Filter Limits", + "@savedHeadlinesFilterLimitsTitle": { + "description": "Title for the Saved Headlines Filter Limits section" + }, "adPlacementIntervalLabel": "Ad Placement Interval", "@adPlacementIntervalLabel": { "description": "Label for Ad Placement Interval" diff --git a/lib/local_ads_management/view/local_ads_management_page.dart b/lib/local_ads_management/view/local_ads_management_page.dart index 7bf8761c..334a9e9a 100644 --- a/lib/local_ads_management/view/local_ads_management_page.dart +++ b/lib/local_ads_management/view/local_ads_management_page.dart @@ -8,7 +8,6 @@ import 'package:flutter_news_app_web_dashboard_full_source_code/local_ads_manage import 'package:flutter_news_app_web_dashboard_full_source_code/local_ads_management/view/native_ads_page.dart'; import 'package:flutter_news_app_web_dashboard_full_source_code/local_ads_management/view/video_ads_page.dart'; import 'package:flutter_news_app_web_dashboard_full_source_code/router/routes.dart'; -import 'package:flutter_news_app_web_dashboard_full_source_code/shared/extensions/extensions.dart'; import 'package:flutter_news_app_web_dashboard_full_source_code/shared/shared.dart'; import 'package:go_router/go_router.dart'; import 'package:ui_kit/ui_kit.dart'; diff --git a/lib/local_ads_management/widgets/local_ad_action_buttons.dart b/lib/local_ads_management/widgets/local_ad_action_buttons.dart index 83425b60..a9a721ab 100644 --- a/lib/local_ads_management/widgets/local_ad_action_buttons.dart +++ b/lib/local_ads_management/widgets/local_ad_action_buttons.dart @@ -180,6 +180,7 @@ class LocalAdActionButtons extends StatelessWidget { case 'copyId': // Copy the ad ID to the clipboard Clipboard.setData(ClipboardData(text: itemId)).then((_) { + // ignore: use_build_context_synchronously ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(l10n.idCopied), diff --git a/pubspec.lock b/pubspec.lock index ab302b18..878a02f7 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -13,8 +13,8 @@ packages: dependency: "direct main" description: path: "." - ref: "41a7ea2bea938e422acdac0ecfbf3a614b3fb855" - resolved-ref: "41a7ea2bea938e422acdac0ecfbf3a614b3fb855" + ref: "v1.0.0" + resolved-ref: "7360a5a1af202bdc291138c81ddc817979454b78" url: "https://github.com/flutter-news-app-full-source-code/auth-api.git" source: git version: "0.0.0" @@ -22,8 +22,8 @@ packages: dependency: "direct main" description: path: "." - ref: fec23f405d58d4915638783d972b542d3faf96b2 - resolved-ref: fec23f405d58d4915638783d972b542d3faf96b2 + ref: "v1.0.0" + resolved-ref: a90e24285874e4c39cb331bbbeae2423901f3289 url: "https://github.com/flutter-news-app-full-source-code/auth-client.git" source: git version: "0.0.0" @@ -31,8 +31,8 @@ packages: dependency: "direct main" description: path: "." - ref: "7f1a582419ae37cb43efe705e3299f2092c54a8b" - resolved-ref: "7f1a582419ae37cb43efe705e3299f2092c54a8b" + ref: "v1.0.0" + resolved-ref: "5316331378ee90e13dbbb0966a964a4b02e4dfcf" url: "https://github.com/flutter-news-app-full-source-code/auth-inmemory" source: git version: "0.0.0" @@ -40,8 +40,8 @@ packages: dependency: "direct main" description: path: "." - ref: "1f1272b586b045903c164be5a39d95383809ba09" - resolved-ref: "1f1272b586b045903c164be5a39d95383809ba09" + ref: "v1.0.0" + resolved-ref: "0d751f835d563c970945a7dab828e1bcb4181049" url: "https://github.com/flutter-news-app-full-source-code/auth-repository.git" source: git version: "0.0.0" @@ -89,11 +89,11 @@ packages: dependency: "direct main" description: path: "." - ref: "828b984517edec069266579c624c7af9fbe0e2ac" - resolved-ref: "828b984517edec069266579c624c7af9fbe0e2ac" + ref: "v1.2.0" + resolved-ref: d052799c1ebb7bcdd1a725a2a7919948c14fa001 url: "https://github.com/flutter-news-app-full-source-code/core.git" source: git - version: "0.0.0" + version: "1.2.0" crypto: dependency: transitive description: @@ -106,8 +106,8 @@ packages: dependency: "direct main" description: path: "." - ref: f90ab664c6333995757026a2c96e96d304da6246 - resolved-ref: f90ab664c6333995757026a2c96e96d304da6246 + ref: "v1.0.0" + resolved-ref: b838da6b8c29ba3a54a68fe11402e7fe3886d135 url: "https://github.com/flutter-news-app-full-source-code/data-api.git" source: git version: "0.0.0" @@ -115,8 +115,8 @@ packages: dependency: "direct main" description: path: "." - ref: "960a00882045ee252274d9d57bfca606c1fe5d64" - resolved-ref: "960a00882045ee252274d9d57bfca606c1fe5d64" + ref: "v1.0.0" + resolved-ref: b9a8a8c2c660928c22f2d38d657000bcae4c74d6 url: "https://github.com/flutter-news-app-full-source-code/data-client.git" source: git version: "0.0.0" @@ -124,8 +124,8 @@ packages: dependency: "direct main" description: path: "." - ref: aaf4e18b759ca8b33d060fd4aa8509238d5d3eaa - resolved-ref: aaf4e18b759ca8b33d060fd4aa8509238d5d3eaa + ref: "v1.0.0" + resolved-ref: cd7a39e12f321c4c0c6bb5041c5d91cb32bc1586 url: "https://github.com/flutter-news-app-full-source-code/data-inmemory.git" source: git version: "0.0.0" @@ -133,8 +133,8 @@ packages: dependency: "direct main" description: path: "." - ref: f8f01f1191286efbba41fa2bb369fb16eb652ccf - resolved-ref: f8f01f1191286efbba41fa2bb369fb16eb652ccf + ref: "v1.0.0" + resolved-ref: "7f9242d810d60fefd2f883b19e1650e8e4eb41a3" url: "https://github.com/flutter-news-app-full-source-code/data-repository.git" source: git version: "0.0.0" @@ -293,8 +293,8 @@ packages: dependency: "direct main" description: path: "." - ref: "57f6bcfc0f209ecc135fdcb688194045ec87e6e8" - resolved-ref: "57f6bcfc0f209ecc135fdcb688194045ec87e6e8" + ref: "v1.0.1" + resolved-ref: ce550196f78ee2e95aa9e985759179265983689d url: "https://github.com/flutter-news-app-full-source-code/http-client.git" source: git version: "0.0.0" @@ -326,7 +326,7 @@ packages: dependency: "direct main" description: path: "." - ref: "3bcba6b11fe0480e06e1bedf6eab4159a7c59c53" + ref: "v1.0.0" resolved-ref: "3bcba6b11fe0480e06e1bedf6eab4159a7c59c53" url: "https://github.com/flutter-news-app-full-source-code/kv-storage-service.git" source: git @@ -335,8 +335,8 @@ packages: dependency: "direct main" description: path: "." - ref: "4cefd202c5fc0c53856782fea7760baa1d0733f7" - resolved-ref: "4cefd202c5fc0c53856782fea7760baa1d0733f7" + ref: "v1.0.0" + resolved-ref: ed94c16ae5ced56216f1adcc14b995e418d5c464 url: "https://github.com/flutter-news-app-full-source-code/kv-storage-shared-preferences.git" source: git version: "0.0.0" @@ -597,8 +597,8 @@ packages: dependency: "direct main" description: path: "." - ref: d9c66362ec87fd7b5e3d3dee35828da6cbc1f66a - resolved-ref: d9c66362ec87fd7b5e3d3dee35828da6cbc1f66a + ref: "v1.0.0" + resolved-ref: "5e84f206a0e047f6afd608d510aec998c6a37dd3" url: "https://github.com/flutter-news-app-full-source-code/ui-kit.git" source: git version: "0.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 47536a06..85729a8a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,8 @@ name: flutter_news_app_web_dashboard_full_source_code description: "A Flutter web application for comprehensive content management and administration within the Flutter News App Full Source Code Toolkit." -publish_to: none repository: https://github.com/flutter-news-app-full-source-code/flutter-news-app-web-dashboard-full-source-code +publish_to: none +version: 1.0.0 environment: sdk: ^3.9.0 @@ -10,42 +11,42 @@ dependencies: auth_api: git: url: https://github.com/flutter-news-app-full-source-code/auth-api.git - ref: 41a7ea2bea938e422acdac0ecfbf3a614b3fb855 + ref: v1.0.0 auth_client: git: url: https://github.com/flutter-news-app-full-source-code/auth-client.git - ref: fec23f405d58d4915638783d972b542d3faf96b2 + ref: v1.0.0 auth_inmemory: git: url: https://github.com/flutter-news-app-full-source-code/auth-inmemory - ref: 7f1a582419ae37cb43efe705e3299f2092c54a8b + ref: v1.0.0 auth_repository: git: url: https://github.com/flutter-news-app-full-source-code/auth-repository.git - ref: 1f1272b586b045903c164be5a39d95383809ba09 + ref: v1.0.0 bloc: ^9.0.0 bloc_concurrency: ^0.3.0 collection: ^1.19.1 core: git: url: https://github.com/flutter-news-app-full-source-code/core.git - ref: 828b984517edec069266579c624c7af9fbe0e2ac + ref: v1.2.0 data_api: git: url: https://github.com/flutter-news-app-full-source-code/data-api.git - ref: f90ab664c6333995757026a2c96e96d304da6246 + ref: v1.0.0 data_client: git: url: https://github.com/flutter-news-app-full-source-code/data-client.git - ref: 960a00882045ee252274d9d57bfca606c1fe5d64 + ref: v1.0.0 data_inmemory: git: url: https://github.com/flutter-news-app-full-source-code/data-inmemory.git - ref: aaf4e18b759ca8b33d060fd4aa8509238d5d3eaa + ref: v1.0.0 data_repository: git: url: https://github.com/flutter-news-app-full-source-code/data-repository.git - ref: f8f01f1191286efbba41fa2bb369fb16eb652ccf + ref: v1.0.0 data_table_2: ^2.6.0 device_preview: ^1.2.0 equatable: ^2.0.7 @@ -61,16 +62,16 @@ dependencies: http_client: git: url: https://github.com/flutter-news-app-full-source-code/http-client.git - ref: 57f6bcfc0f209ecc135fdcb688194045ec87e6e8 + ref: v1.0.1 intl: ^0.20.2 kv_storage_service: git: url: https://github.com/flutter-news-app-full-source-code/kv-storage-service.git - ref: 3bcba6b11fe0480e06e1bedf6eab4159a7c59c53 + ref: v1.0.0 kv_storage_shared_preferences: git: url: https://github.com/flutter-news-app-full-source-code/kv-storage-shared-preferences.git - ref: 4cefd202c5fc0c53856782fea7760baa1d0733f7 + ref: v1.0.0 logging: ^1.3.0 pinput: ^5.0.1 rxdart: ^0.28.0 @@ -79,10 +80,9 @@ dependencies: ui_kit: git: url: https://github.com/flutter-news-app-full-source-code/ui-kit.git - ref: d9c66362ec87fd7b5e3d3dee35828da6cbc1f66a + ref: v1.0.0 uuid: ^4.5.1 - dev_dependencies: very_good_analysis: ^9.0.0

AltStyle によって変換されたページ (->オリジナル) /