локаль дописать осталось :)

This commit is contained in:
Алексей Тихоненков 2024-12-19 02:16:35 +04:00
parent f492991a36
commit 2d49ce9f8c
17 changed files with 363 additions and 149 deletions

View File

@ -1,9 +1,13 @@
{ {
"@@locale": "en", "@@locale": "en",
"search": "Search", "title": "Quotes"
"search_word": "Search by word",
"search_author": "Search by author",
"liked": "Like :)", "liked": "Like :)",
"disliked": "Dislike :(", "disliked": "Dislike :(",
"error": "Error :C"
"details": "Details of quote"
"arbEnding": "" "arbEnding": ""
} }

View File

@ -7,7 +7,7 @@ class AppLocaleEn extends AppLocale {
AppLocaleEn([String locale = 'en']) : super(locale); AppLocaleEn([String locale = 'en']) : super(locale);
@override @override
String get search => 'Search'; String get search => 'Поиск';
@override @override
String get liked => 'Like :)'; String get liked => 'Like :)';

View File

@ -16,9 +16,10 @@ class QuoteDataDto {
final String? body; final String? body;
final String? author; final String? author;
final String? imageUrl; final String? imageUrl;
final String? id; final dynamic id;
final bool? isLiked;
const QuoteDataDto({this.body, this.author, this.imageUrl, this.id}); const QuoteDataDto({this.body, this.author, this.imageUrl, this.id, this.isLiked});
factory QuoteDataDto.fromJson(Map<String, dynamic> json) => _$QuoteDataDtoFromJson(json); factory QuoteDataDto.fromJson(Map<String, dynamic> json) => _$QuoteDataDtoFromJson(json);
} }

View File

@ -16,4 +16,6 @@ QuoteDataDto _$QuoteDataDtoFromJson(Map<String, dynamic> json) => QuoteDataDto(
body: json['body'] as String?, body: json['body'] as String?,
author: json['author'] as String?, author: json['author'] as String?,
imageUrl: json['imageUrl'] as String?, imageUrl: json['imageUrl'] as String?,
id: json['id'],
isLiked: json['isLiked'] as bool?,
); );

View File

@ -9,6 +9,7 @@ extension QuoteDtoToModel on QuoteDataDto {
body ?? 'Без текста', body ?? 'Без текста',
author ?? 'Неизвестный автор', author ?? 'Неизвестный автор',
imageUrl ?? _imagePlaceholder, imageUrl ?? _imagePlaceholder,
id ?? "", id?.toString() ?? "",
isLiked ?? false,
); );
} }

View File

@ -3,12 +3,6 @@ class Quote {
final String author; final String author;
final String imagePath; final String imagePath;
final String id; final String id;
bool isFavorite; final bool isLiked;
Quote(this.text, this.author, this.imagePath, this.id, this.isLiked);
Quote(this.text, this.author, this.imagePath, this.id,[this.isFavorite = false]);
bool toggleFavorite() {
isFavorite = !isFavorite;
return isFavorite;
}
} }

View File

@ -1,7 +1,11 @@
import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:pmu_flutter_labs/presentation/home_page/bloc/events.dart'; import 'package:pmu_flutter_labs/presentation/home_page/bloc/events.dart';
import 'package:pmu_flutter_labs/presentation/like_bloc/like_bloc.dart'; import 'package:pmu_flutter_labs/presentation/like_bloc/like_bloc.dart';
import 'package:pmu_flutter_labs/presentation/locale_bloc/locale_bloc.dart';
import 'package:pmu_flutter_labs/presentation/locale_bloc/locale_state.dart';
import 'components/locale/l10n/app_locale.dart'; import 'components/locale/l10n/app_locale.dart';
import 'data/repositories/quotes_repository.dart'; import 'data/repositories/quotes_repository.dart';
import '/presentation/home_page/bloc/bloc.dart'; import '/presentation/home_page/bloc/bloc.dart';
@ -15,26 +19,36 @@ class MyApp extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MaterialApp( return BlocProvider<LocaleBloc>(
title: 'Цитаты', lazy: false,
localizationsDelegates: AppLocale.localizationsDelegates, create:(context) => LocaleBloc(Locale(Platform.localeName)),
supportedLocales: AppLocale.supportedLocales, child: BlocBuilder<LocaleBloc, LocaleState>(
theme: ThemeData( builder: (context, state) {
colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigo), return MaterialApp(
useMaterial3: true, title: 'Цитаты',
), locale: state.currentLocale,
home: RepositoryProvider<QuotesRepository>( localizationsDelegates: AppLocale.localizationsDelegates,
lazy: true, supportedLocales: AppLocale.supportedLocales,
create: (_) => QuotesRepository(), theme: ThemeData(
child: BlocProvider( colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigo),
create: (context) => LikeBloc(), // Add LikeBloc here useMaterial3: true,
child: BlocProvider( ),
create: (context) => HomeBloc(context.read<QuotesRepository>()) home: RepositoryProvider<QuotesRepository>(
..add(const HomeLoadDataEvent()), // Ensure initial load lazy: true,
child: const MyHomePage(title: "Цитаты"), create: (_) => QuotesRepository(),
), child: BlocProvider<LikeBloc>(
), lazy: false,
), create: (context) => LikeBloc(), // Add LikeBloc here
child: BlocProvider<HomeBloc>(
lazy: false,
create: (context) => HomeBloc(context.read<QuotesRepository>()),
child: const MyHomePage(title: "Цитаты"),
),
),
),
);
}
),
); );
} }
} }

View File

@ -3,7 +3,7 @@ import '../../../domain/quote.dart';
import '../home_page.dart'; import '../home_page.dart';
class HomeState extends Equatable { class HomeState extends Equatable {
final Future<List<Quote>>? data; // Изменено final Future<List<Quote>>? data;
const HomeState({this.data}); const HomeState({this.data});

View File

@ -1,65 +1,63 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../domain/quote.dart'; import '../../domain/quote.dart';
import '../like_bloc/like_bloc.dart';
import '../like_bloc/like_state.dart';
import 'home_page.dart'; import 'home_page.dart';
class QuoteCard extends StatelessWidget { class QuoteCard extends StatelessWidget {
final Quote quote; final Quote quote;
final VoidCallback onFavoriteToggle; final VoidCallback onFavoriteToggle;
final bool isLiked;
const QuoteCard({Key? key, required this.quote, required this.onFavoriteToggle}) : super(key: key); const QuoteCard({
super.key,
required this.quote,
required this.onFavoriteToggle,
required this.isLiked,
});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Card( return Card(
margin: const EdgeInsets.all(8.0), margin: const EdgeInsets.symmetric(
child: Padding( vertical: 8.0,
padding: const EdgeInsets.all(16.0), horizontal: 10.0,
child: Column( ),
crossAxisAlignment: CrossAxisAlignment.start, child: ListTile(
children: [ contentPadding: const EdgeInsets.all(8.0),
Text( leading: SizedBox(
quote.text, width: 50.0,
style: const TextStyle(fontSize: 18.0), child: Image.network(
), quote.imagePath,
const SizedBox(height: 8.0), fit: BoxFit.cover,
Text( errorBuilder: (_, __, ___) =>
'- ${quote.author}', const Icon(Icons.error, color: Colors.red),
style: const TextStyle(fontStyle: FontStyle.italic, fontSize: 16.0), ),
),
const SizedBox(height: 8.0),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ElevatedButton.icon(
onPressed: onFavoriteToggle,
icon: BlocBuilder<LikeBloc, LikeState>(
builder: (context, state) {
final isLiked = state.likedIds?.contains(quote.id) ?? false;
return Icon(
isLiked ? Icons.favorite : Icons.favorite_border,
color: isLiked ? Colors.red : Colors.grey,
);
},
),
label: BlocBuilder<LikeBloc, LikeState>(
builder: (context, state) {
final isLiked = state.likedIds?.contains(quote.id) ?? false;
return Text(isLiked ? 'Убрать из избранного' : 'Добавить в избранное');
},
),
),
],
),
],
), ),
title: Text(
quote.text,
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w500),
),
subtitle: Text('- ${quote.author}'),
trailing: IconButton(
icon: Icon(
isLiked ? Icons.favorite : Icons.favorite_border,
color: isLiked ? Colors.red : null,
),
onPressed: onFavoriteToggle,
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => QuoteDetailScreen(quote: quote),
),
);
},
), ),
); );
} }
} }
class QuoteDetailScreen extends StatelessWidget { class QuoteDetailScreen extends StatelessWidget {
final Quote quote; final Quote quote;
@ -80,7 +78,8 @@ class QuoteDetailScreen extends StatelessWidget {
Image.network( Image.network(
quote.imagePath, quote.imagePath,
height: 150, height: 150,
errorBuilder: (_, __, ___) => const Icon(Icons.error, color: Colors.red), errorBuilder: (_, __, ___) =>
const Icon(Icons.error, color: Colors.red),
), ),
const SizedBox(height: 20), const SizedBox(height: 20),
Text( Text(

View File

@ -1,11 +1,16 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:pmu_flutter_labs/components/extensions/context_x.dart'; import 'package:pmu_flutter_labs/components/extensions/context_x.dart';
import 'package:pmu_flutter_labs/presentation/like_bloc/like_state.dart';
import '../../components/utils/debounce.dart'; import '../../components/utils/debounce.dart';
import '../../domain/quote.dart'; import '../../domain/quote.dart';
import '../common/svg_objects.dart'; import '../common/svg_objects.dart';
import '../like_bloc/like_bloc.dart'; import '../like_bloc/like_bloc.dart';
import '../like_bloc/like_event.dart'; import '../like_bloc/like_event.dart';
import '../locale_bloc/locale_bloc.dart';
import '../locale_bloc/locale_events.dart';
import '../locale_bloc/locale_state.dart';
import '/data/repositories/quotes_repository.dart'; import '/data/repositories/quotes_repository.dart';
import '/presentation/home_page/bloc/bloc.dart'; import '/presentation/home_page/bloc/bloc.dart';
import '/presentation/home_page/bloc/events.dart'; import '/presentation/home_page/bloc/events.dart';
@ -17,15 +22,46 @@ class MyHomePage extends StatelessWidget {
final String title; final String title;
get searchController => null;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return BlocProvider(
create: (context) => HomeBloc(QuotesRepository())..add(const HomeLoadDataEvent()), create: (context) =>
HomeBloc(QuotesRepository())..add(const HomeLoadDataEvent()),
child: Scaffold( child: Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text(title), title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(title),
GestureDetector(
onTap: () =>
context.read<LocaleBloc>().add(const ChangeLocaleEvent()),
child: SizedBox.square(
dimension: 50,
child: Padding(
padding: const EdgeInsets.only(right: 12),
child: BlocBuilder<LocaleBloc, LocaleState>(
builder: (context, state) {
return state.currentLocale.languageCode == 'ru'
? const SvgRu()
: const SvgUk();
},
),
),
),
),
],
),
),
body: Column(
children: [
const Expanded(
child: _HomePageBody(),
),
],
), ),
body: const _HomePageBody(),
), ),
); );
} }
@ -50,22 +86,22 @@ class _HomePageBodyState extends State<_HomePageBody> {
searchController.addListener(() { searchController.addListener(() {
Debounce.run(() { Debounce.run(() {
context.read<HomeBloc>().add(HomeLoadDataEvent( context.read<HomeBloc>().add(HomeLoadDataEvent(
search: searchController.text, search: searchController.text,
author: authorController.text, author: authorController.text,
)); ));
}); });
}); });
authorController.addListener(() { authorController.addListener(() {
Debounce.run(() { Debounce.run(() {
context.read<HomeBloc>().add(HomeLoadDataEvent( context.read<HomeBloc>().add(HomeLoadDataEvent(
search: searchController.text, search: searchController.text,
author: authorController.text, author: authorController.text,
)); ));
}); });
}); });
context.read<HomeBloc>().add(const HomeLoadDataEvent());
context.read<LikeBloc>().add(const LoadLikesEvent()); context.read<LikeBloc>().add(const LoadLikesEvent());
} }
void _showSnackbar(BuildContext context, bool isLiked) { void _showSnackbar(BuildContext context, bool isLiked) {
@ -88,9 +124,9 @@ class _HomePageBodyState extends State<_HomePageBody> {
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: TextField( child: TextField(
controller: searchController, controller: searchController,
decoration: const InputDecoration( decoration: InputDecoration(
labelText: 'Поиск по цитате', labelText: context.locale.search,
prefixIcon: Icon(Icons.search), prefixIcon: const Icon(Icons.search),
), ),
), ),
), ),
@ -98,60 +134,76 @@ class _HomePageBodyState extends State<_HomePageBody> {
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: TextField( child: TextField(
controller: authorController, controller: authorController,
decoration: const InputDecoration( decoration: InputDecoration(
labelText: 'Поиск по автору', labelText: context.locale.search,
prefixIcon: Icon(Icons.person), prefixIcon: const Icon(Icons.person),
), ),
), ),
), ),
Expanded( BlocBuilder<LikeBloc, LikeState>(
child: state.data == null builder: (context, likeState) {
? const Center(child: CircularProgressIndicator()) return Expanded(
: FutureBuilder<List<Quote>?>( child: state.data == null
future: state.data, ? const Center(child: CircularProgressIndicator())
builder: (context, snapshot) { : FutureBuilder<List<Quote>?>(
if (snapshot.connectionState == ConnectionState.waiting) { future: state.data,
return const Center(child: CircularProgressIndicator()); builder: (context, snapshot) {
} if (snapshot.connectionState ==
if (snapshot.hasError) { ConnectionState.waiting) {
return Center(child: Text('Ошибка: ${snapshot.error}')); return const Center(
} child: CircularProgressIndicator());
if (snapshot.data == null || snapshot.data!.isEmpty) { }
return const Center( if (snapshot.hasError) {
child: Text( return Center(
'Нет цитат для отображения.', child: Text('Ошибка: ${snapshot.error}'));
style: TextStyle(fontSize: 18, color: Colors.grey), }
), if (snapshot.data == null ||
); snapshot.data!.isEmpty) {
} return const Center(
final quotes = snapshot.data!; child: Text(
return RefreshIndicator( 'Нет цитат для отображения.',
onRefresh: () async { style: TextStyle(
context.read<HomeBloc>().add(HomeRefreshEvent( fontSize: 18, color: Colors.grey),
search: searchController.text, ),
author: authorController.text, );
)); }
},
child: ListView.builder( final quotes = snapshot.data!;
itemCount: quotes.length, final likedIds = likeState.likedIds ?? [];
itemBuilder: (context, index) {
final quote = quotes[index]; return RefreshIndicator(
return QuoteCard( onRefresh: () async {
quote: quote, context.read<HomeBloc>().add(HomeRefreshEvent(
onFavoriteToggle: () { search: searchController.text,
context.read<LikeBloc>().add(ChangeLikeEvent(quote.id)); author: authorController.text,
));
},
child: ListView.builder(
itemCount: quotes.length,
itemBuilder: (context, index) {
final quote = quotes[index];
final isLiked = likedIds.contains(quote.id);
return QuoteCard(
quote: quote,
isLiked: isLiked,
onFavoriteToggle: () {
context
.read<LikeBloc>()
.add(ChangeLikeEvent(quote.id));
},
);
},
),
);
}, },
); ),
}, );
), },
); )
},
),
),
], ],
); );
}, },
); );
} }
} }

View File

@ -1,5 +1,5 @@
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
//import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'like_event.dart'; import 'like_event.dart';
import 'like_state.dart'; import 'like_state.dart';
@ -13,10 +13,10 @@ class LikeBloc extends Bloc<LikeEvent, LikeState> {
} }
Future<void> _onLoadLikes(LoadLikesEvent event, Emitter<LikeState> emit) async { Future<void> _onLoadLikes(LoadLikesEvent event, Emitter<LikeState> emit) async {
//final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
//final data = prefs.getStringList(_likedPrefsKey); final data = prefs.getStringList(_likedPrefsKey);
//emit(state.copyWith(likedIds: data)); emit(state.copyWith(likedIds: data));
} }
Future<void> _onChangeLike(ChangeLikeEvent event, Emitter<LikeState> emit) async { Future<void> _onChangeLike(ChangeLikeEvent event, Emitter<LikeState> emit) async {
@ -28,8 +28,8 @@ class LikeBloc extends Bloc<LikeEvent, LikeState> {
updatedList.add(event.id); updatedList.add(event.id);
} }
//final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
//prefs.setStringList(_likedPrefsKey, updatedList); prefs.setStringList(_likedPrefsKey, updatedList);
emit(state.copyWith(likedIds: updatedList)); emit(state.copyWith(likedIds: updatedList));
} }

View File

@ -8,6 +8,5 @@ class LoadLikesEvent extends LikeEvent {
class ChangeLikeEvent extends LikeEvent { class ChangeLikeEvent extends LikeEvent {
final String id; final String id;
const ChangeLikeEvent(this.id); const ChangeLikeEvent(this.id);
} }

View File

@ -0,0 +1,17 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../components/locale/l10n/app_locale.dart';
import 'locale_events.dart';
import 'locale_state.dart';
class LocaleBloc extends Bloc<LocaleEvent, LocaleState> {
LocaleBloc(Locale defaultLocale) : super(LocaleState(currentLocale: defaultLocale)) {
on<ChangeLocaleEvent>(_onChangeLocale);
}
Future<void> _onChangeLocale(ChangeLocaleEvent event, Emitter<LocaleState> emit) async {
final toChange = AppLocale.supportedLocales
.firstWhere((e) => e.languageCode != state.currentLocale.languageCode);
emit(state.copyWith(currentLocale: toChange));
}
}

View File

@ -0,0 +1,7 @@
abstract class LocaleEvent {
const LocaleEvent();
}
class ChangeLocaleEvent extends LocaleEvent {
const ChangeLocaleEvent();
}

View File

@ -0,0 +1,15 @@
import 'package:copy_with_extension/copy_with_extension.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
part 'locale_state.g.dart';
@CopyWith()
class LocaleState extends Equatable {
final Locale currentLocale;
const LocaleState({required this.currentLocale});
@override
List<Object?> get props => [currentLocale];
}

View File

@ -325,6 +325,11 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
flutter_web_plugins:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
frontend_server_client: frontend_server_client:
dependency: transitive dependency: transitive
description: description:
@ -533,6 +538,30 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.0" version: "1.1.0"
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: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
url: "https://pub.dev"
source: hosted
version: "2.3.0"
petitparser: petitparser:
dependency: transitive dependency: transitive
description: description:
@ -541,6 +570,22 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.0.2" version: "6.0.2"
platform:
dependency: transitive
description:
name: platform
sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984"
url: "https://pub.dev"
source: hosted
version: "3.1.6"
plugin_platform_interface:
dependency: transitive
description:
name: plugin_platform_interface
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
url: "https://pub.dev"
source: hosted
version: "2.1.8"
pool: pool:
dependency: transitive dependency: transitive
description: description:
@ -589,6 +634,62 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.0" version: "1.3.0"
shared_preferences:
dependency: "direct main"
description:
name: shared_preferences
sha256: "3c7e73920c694a436afaf65ab60ce3453d91f84208d761fbd83fc21182134d93"
url: "https://pub.dev"
source: hosted
version: "2.3.4"
shared_preferences_android:
dependency: transitive
description:
name: shared_preferences_android
sha256: "02a7d8a9ef346c9af715811b01fbd8e27845ad2c41148eefd31321471b41863d"
url: "https://pub.dev"
source: hosted
version: "2.4.0"
shared_preferences_foundation:
dependency: transitive
description:
name: shared_preferences_foundation
sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03"
url: "https://pub.dev"
source: hosted
version: "2.5.4"
shared_preferences_linux:
dependency: transitive
description:
name: shared_preferences_linux
sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
shared_preferences_platform_interface:
dependency: transitive
description:
name: shared_preferences_platform_interface
sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
shared_preferences_web:
dependency: transitive
description:
name: shared_preferences_web
sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e
url: "https://pub.dev"
source: hosted
version: "2.4.2"
shared_preferences_windows:
dependency: transitive
description:
name: shared_preferences_windows
sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
shelf: shelf:
dependency: transitive dependency: transitive
description: description:
@ -770,6 +871,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.1" version: "3.0.1"
xdg_directories:
dependency: transitive
description:
name: xdg_directories
sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
xml: xml:
dependency: transitive dependency: transitive
description: description:
@ -788,4 +897,4 @@ packages:
version: "3.1.2" version: "3.1.2"
sdks: sdks:
dart: ">=3.5.4 <4.0.0" dart: ">=3.5.4 <4.0.0"
flutter: ">=3.22.0" flutter: ">=3.24.0"

View File

@ -7,7 +7,7 @@ environment:
sdk: ^3.5.4 sdk: ^3.5.4
dependencies: dependencies:
# shared_preferences: ^2.3.3 shared_preferences: ^2.3.3
flutter: flutter:
sdk: flutter sdk: flutter