diff --git a/lib/app_router.dart b/lib/app_router.dart index 50f7968f..9d51f9c9 100644 --- a/lib/app_router.dart +++ b/lib/app_router.dart @@ -1,4 +1,5 @@ import 'package:eatvio_app/core/token_storage.dart'; +import 'package:eatvio_app/features/calendar/presentation/pages/calendar_screen.dart'; import 'package:eatvio_app/features/chat/presentation/pages/chat_screen.dart'; import 'package:eatvio_app/features/chat/presentation/pages/chat_select_screen/chat_select_screen.dart'; import 'package:eatvio_app/features/diary/presentation/pages/diary_screen.dart'; @@ -245,6 +246,11 @@ class AppRouter { name: 'diaryScreen', builder: (context, state) => DiaryScreen(), ), + GoRoute( + path: '/calendar-screen', + name: 'calendarScreen', + builder: (context, state) => CalendarScreen(), + ), GoRoute( path: '/chat-select-screen', name: 'chatSelectScreen', diff --git a/lib/features/calendar/models/calendar_model.dart b/lib/features/calendar/models/calendar_model.dart index c206175b..c13d5c5d 100644 --- a/lib/features/calendar/models/calendar_model.dart +++ b/lib/features/calendar/models/calendar_model.dart @@ -6,14 +6,8 @@ part 'calendar_model.g.dart'; @freezed class CalendarModel with _$CalendarModel { const factory CalendarModel({ - required int id, - required String state, - required String image, - required String description, - @JsonKey(name: "youtube_url") required String youtubeUrl, - @JsonKey(name: "created_at") required DateTime createdAt, - @JsonKey(name: "updated_at") required DateTime updatedAt, - required String title, + required String date, + Object? diary, }) = _CalendarModel; factory CalendarModel.fromJson(Map json) => diff --git a/lib/features/calendar/models/calendar_model.freezed.dart b/lib/features/calendar/models/calendar_model.freezed.dart index 7f0d3209..fd8f7ea6 100644 --- a/lib/features/calendar/models/calendar_model.freezed.dart +++ b/lib/features/calendar/models/calendar_model.freezed.dart @@ -20,17 +20,8 @@ CalendarModel _$CalendarModelFromJson(Map json) { /// @nodoc mixin _$CalendarModel { - int get id => throw _privateConstructorUsedError; - String get state => throw _privateConstructorUsedError; - String get image => throw _privateConstructorUsedError; - String get description => throw _privateConstructorUsedError; - @JsonKey(name: "youtube_url") - String get youtubeUrl => throw _privateConstructorUsedError; - @JsonKey(name: "created_at") - DateTime get createdAt => throw _privateConstructorUsedError; - @JsonKey(name: "updated_at") - DateTime get updatedAt => throw _privateConstructorUsedError; - String get title => throw _privateConstructorUsedError; + String get date => throw _privateConstructorUsedError; + Object? get diary => throw _privateConstructorUsedError; Map toJson() => throw _privateConstructorUsedError; @JsonKey(ignore: true) @@ -44,15 +35,7 @@ abstract class $CalendarModelCopyWith<$Res> { CalendarModel value, $Res Function(CalendarModel) then) = _$CalendarModelCopyWithImpl<$Res, CalendarModel>; @useResult - $Res call( - {int id, - String state, - String image, - String description, - @JsonKey(name: "youtube_url") String youtubeUrl, - @JsonKey(name: "created_at") DateTime createdAt, - @JsonKey(name: "updated_at") DateTime updatedAt, - String title}); + $Res call({String date, Object? diary}); } /// @nodoc @@ -68,48 +51,15 @@ class _$CalendarModelCopyWithImpl<$Res, $Val extends CalendarModel> @pragma('vm:prefer-inline') @override $Res call({ - Object? id = null, - Object? state = null, - Object? image = null, - Object? description = null, - Object? youtubeUrl = null, - Object? createdAt = null, - Object? updatedAt = null, - Object? title = null, + Object? date = null, + Object? diary = freezed, }) { return _then(_value.copyWith( - id: null == id - ? _value.id - : id // ignore: cast_nullable_to_non_nullable - as int, - state: null == state - ? _value.state - : state // ignore: cast_nullable_to_non_nullable - as String, - image: null == image - ? _value.image - : image // ignore: cast_nullable_to_non_nullable - as String, - description: null == description - ? _value.description - : description // ignore: cast_nullable_to_non_nullable - as String, - youtubeUrl: null == youtubeUrl - ? _value.youtubeUrl - : youtubeUrl // ignore: cast_nullable_to_non_nullable - as String, - createdAt: null == createdAt - ? _value.createdAt - : createdAt // ignore: cast_nullable_to_non_nullable - as DateTime, - updatedAt: null == updatedAt - ? _value.updatedAt - : updatedAt // ignore: cast_nullable_to_non_nullable - as DateTime, - title: null == title - ? _value.title - : title // ignore: cast_nullable_to_non_nullable + date: null == date + ? _value.date + : date // ignore: cast_nullable_to_non_nullable as String, + diary: freezed == diary ? _value.diary : diary, ) as $Val); } } @@ -122,15 +72,7 @@ abstract class _$$CalendarModelImplCopyWith<$Res> __$$CalendarModelImplCopyWithImpl<$Res>; @override @useResult - $Res call( - {int id, - String state, - String image, - String description, - @JsonKey(name: "youtube_url") String youtubeUrl, - @JsonKey(name: "created_at") DateTime createdAt, - @JsonKey(name: "updated_at") DateTime updatedAt, - String title}); + $Res call({String date, Object? diary}); } /// @nodoc @@ -144,48 +86,15 @@ class __$$CalendarModelImplCopyWithImpl<$Res> @pragma('vm:prefer-inline') @override $Res call({ - Object? id = null, - Object? state = null, - Object? image = null, - Object? description = null, - Object? youtubeUrl = null, - Object? createdAt = null, - Object? updatedAt = null, - Object? title = null, + Object? date = null, + Object? diary = freezed, }) { return _then(_$CalendarModelImpl( - id: null == id - ? _value.id - : id // ignore: cast_nullable_to_non_nullable - as int, - state: null == state - ? _value.state - : state // ignore: cast_nullable_to_non_nullable - as String, - image: null == image - ? _value.image - : image // ignore: cast_nullable_to_non_nullable - as String, - description: null == description - ? _value.description - : description // ignore: cast_nullable_to_non_nullable - as String, - youtubeUrl: null == youtubeUrl - ? _value.youtubeUrl - : youtubeUrl // ignore: cast_nullable_to_non_nullable - as String, - createdAt: null == createdAt - ? _value.createdAt - : createdAt // ignore: cast_nullable_to_non_nullable - as DateTime, - updatedAt: null == updatedAt - ? _value.updatedAt - : updatedAt // ignore: cast_nullable_to_non_nullable - as DateTime, - title: null == title - ? _value.title - : title // ignore: cast_nullable_to_non_nullable + date: null == date + ? _value.date + : date // ignore: cast_nullable_to_non_nullable as String, + diary: freezed == diary ? _value.diary : diary, )); } } @@ -193,42 +102,19 @@ class __$$CalendarModelImplCopyWithImpl<$Res> /// @nodoc @JsonSerializable() class _$CalendarModelImpl implements _CalendarModel { - const _$CalendarModelImpl( - {required this.id, - required this.state, - required this.image, - required this.description, - @JsonKey(name: "youtube_url") required this.youtubeUrl, - @JsonKey(name: "created_at") required this.createdAt, - @JsonKey(name: "updated_at") required this.updatedAt, - required this.title}); + const _$CalendarModelImpl({required this.date, this.diary}); factory _$CalendarModelImpl.fromJson(Map json) => _$$CalendarModelImplFromJson(json); @override - final int id; + final String date; @override - final String state; - @override - final String image; - @override - final String description; - @override - @JsonKey(name: "youtube_url") - final String youtubeUrl; - @override - @JsonKey(name: "created_at") - final DateTime createdAt; - @override - @JsonKey(name: "updated_at") - final DateTime updatedAt; - @override - final String title; + final Object? diary; @override String toString() { - return 'CalendarModel(id: $id, state: $state, image: $image, description: $description, youtubeUrl: $youtubeUrl, createdAt: $createdAt, updatedAt: $updatedAt, title: $title)'; + return 'CalendarModel(date: $date, diary: $diary)'; } @override @@ -236,24 +122,14 @@ class _$CalendarModelImpl implements _CalendarModel { return identical(this, other) || (other.runtimeType == runtimeType && other is _$CalendarModelImpl && - (identical(other.id, id) || other.id == id) && - (identical(other.state, state) || other.state == state) && - (identical(other.image, image) || other.image == image) && - (identical(other.description, description) || - other.description == description) && - (identical(other.youtubeUrl, youtubeUrl) || - other.youtubeUrl == youtubeUrl) && - (identical(other.createdAt, createdAt) || - other.createdAt == createdAt) && - (identical(other.updatedAt, updatedAt) || - other.updatedAt == updatedAt) && - (identical(other.title, title) || other.title == title)); + (identical(other.date, date) || other.date == date) && + const DeepCollectionEquality().equals(other.diary, diary)); } @JsonKey(ignore: true) @override - int get hashCode => Object.hash(runtimeType, id, state, image, description, - youtubeUrl, createdAt, updatedAt, title); + int get hashCode => Object.hash( + runtimeType, date, const DeepCollectionEquality().hash(diary)); @JsonKey(ignore: true) @override @@ -271,37 +147,15 @@ class _$CalendarModelImpl implements _CalendarModel { abstract class _CalendarModel implements CalendarModel { const factory _CalendarModel( - {required final int id, - required final String state, - required final String image, - required final String description, - @JsonKey(name: "youtube_url") required final String youtubeUrl, - @JsonKey(name: "created_at") required final DateTime createdAt, - @JsonKey(name: "updated_at") required final DateTime updatedAt, - required final String title}) = _$CalendarModelImpl; + {required final String date, final Object? diary}) = _$CalendarModelImpl; factory _CalendarModel.fromJson(Map json) = _$CalendarModelImpl.fromJson; @override - int get id; + String get date; @override - String get state; - @override - String get image; - @override - String get description; - @override - @JsonKey(name: "youtube_url") - String get youtubeUrl; - @override - @JsonKey(name: "created_at") - DateTime get createdAt; - @override - @JsonKey(name: "updated_at") - DateTime get updatedAt; - @override - String get title; + Object? get diary; @override @JsonKey(ignore: true) _$$CalendarModelImplCopyWith<_$CalendarModelImpl> get copyWith => diff --git a/lib/features/calendar/models/calendar_model.g.dart b/lib/features/calendar/models/calendar_model.g.dart index d675f9b1..c12dd961 100644 --- a/lib/features/calendar/models/calendar_model.g.dart +++ b/lib/features/calendar/models/calendar_model.g.dart @@ -8,24 +8,12 @@ part of 'calendar_model.dart'; _$CalendarModelImpl _$$CalendarModelImplFromJson(Map json) => _$CalendarModelImpl( - id: (json['id'] as num).toInt(), - state: json['state'] as String, - image: json['image'] as String, - description: json['description'] as String, - youtubeUrl: json['youtube_url'] as String, - createdAt: DateTime.parse(json['created_at'] as String), - updatedAt: DateTime.parse(json['updated_at'] as String), - title: json['title'] as String, + date: json['date'] as String, + diary: json['diary'], ); Map _$$CalendarModelImplToJson(_$CalendarModelImpl instance) => { - 'id': instance.id, - 'state': instance.state, - 'image': instance.image, - 'description': instance.description, - 'youtube_url': instance.youtubeUrl, - 'created_at': instance.createdAt.toIso8601String(), - 'updated_at': instance.updatedAt.toIso8601String(), - 'title': instance.title, + 'date': instance.date, + 'diary': instance.diary, }; diff --git a/lib/features/calendar/presentation/pages/calendar_screen.dart b/lib/features/calendar/presentation/pages/calendar_screen.dart new file mode 100644 index 00000000..7ef68dd8 --- /dev/null +++ b/lib/features/calendar/presentation/pages/calendar_screen.dart @@ -0,0 +1,109 @@ +// ignore_for_file: unused_local_variable + +import 'package:eatvio_app/features/calendar/presentation/bloc/calendar_cubit.dart'; +import 'package:eatvio_app/features/calendar/presentation/bloc/calendar_state.dart'; +import 'package:eatvio_app/core/app_export.dart'; +import 'package:table_calendar/table_calendar.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter_form_builder/flutter_form_builder.dart'; + +// ignore: must_be_immutable +class CalendarScreen extends StatelessWidget { + CalendarScreen({Key? key}) : super(key: key); + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + if (state is CalendarStateLoaded) { + return _buildCalendar(context, state); + } else if (state is CalendarStateLoading) { + return Scaffold( + body: Center( + child: CupertinoActivityIndicator(), + ), + ); + } else if (state is CalendarStateError) { + return Scaffold( + body: Padding( + padding: const EdgeInsets.all(16), + child: Center( + child: Text(state.errorMessage), + ), + ), + ); + } else + return Scaffold( + body: Padding( + padding: const EdgeInsets.all(16), + child: Center( + child: Text("Неопределенная ошибка"), + ), + ), + ); + }, + ); + } + + Widget _buildCalendar(BuildContext context, CalendarStateLoaded state) { + return Stack(alignment: Alignment.bottomCenter, children: [ + FormBuilder( + child: Scaffold( + appBar: AppBar( + toolbarHeight: 0, + automaticallyImplyLeading: false, + ), + backgroundColor: Color.fromARGB(255, 240, 242, 245), + resizeToAvoidBottomInset: true, + body: SizedBox( + width: double.maxFinite, + child: Column( + children: [ + Expanded( + child: SingleChildScrollView( + child: Padding( + padding: EdgeInsets.only(bottom: 5.v), + child: Column( + children: [ + SizedBox(height: 20.v), + _buildCalendarBody(context, state), + SizedBox(height: 20.v), + ], + ), + ), + ), + ), + ], + ), + ), + ), + ), + ]); + } + + _buildCalendarBody(BuildContext context, CalendarStateLoaded state) { + return Container( + margin: EdgeInsets.symmetric(horizontal: 16.h, vertical: 16.h), + padding: EdgeInsets.symmetric( + horizontal: 24.h, + vertical: 12.v, + ), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: const BorderRadius.all(Radius.circular(12)), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.5), + spreadRadius: 2, + blurRadius: 5, + offset: Offset(0, 3), + ), + ], + ), + child: TableCalendar( + firstDay: DateTime.utc(2010, 10, 16), + lastDay: DateTime.utc(2030, 3, 14), + focusedDay: DateTime.now(), + ), + ); + } +} diff --git a/lib/features/calendar/repositories/calendar_repository.dart b/lib/features/calendar/repositories/calendar_repository.dart index 97a23dca..fd9f734c 100644 --- a/lib/features/calendar/repositories/calendar_repository.dart +++ b/lib/features/calendar/repositories/calendar_repository.dart @@ -8,10 +8,7 @@ class CalendarRepository { Future> getCalendar() async { try { - return (await calendarService.getCalendar()) - .entries - .map((entry) => entry.value) - .toList(); + return await calendarService.getCalendar(); } catch (e) { rethrow; } diff --git a/lib/features/calendar/services/calendar_service.dart b/lib/features/calendar/services/calendar_service.dart index 80b98e6d..d3e3c973 100644 --- a/lib/features/calendar/services/calendar_service.dart +++ b/lib/features/calendar/services/calendar_service.dart @@ -9,5 +9,5 @@ abstract class CalendarService { factory CalendarService(Dio dio, {String baseUrl}) = _CalendarService; @GET('/calendar/index') - Future> getCalendar(); + Future> getCalendar(); } diff --git a/lib/features/calendar/services/calendar_service.g.dart b/lib/features/calendar/services/calendar_service.g.dart index 57033789..f89b79e8 100644 --- a/lib/features/calendar/services/calendar_service.g.dart +++ b/lib/features/calendar/services/calendar_service.g.dart @@ -19,13 +19,13 @@ class _CalendarService implements CalendarService { String? baseUrl; @override - Future> getCalendar() async { + Future> getCalendar() async { final _extra = {}; final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _result = await _dio.fetch>( - _setStreamType>(Options( + final _result = await _dio + .fetch>(_setStreamType>(Options( method: 'GET', headers: _headers, extra: _extra, @@ -41,8 +41,9 @@ class _CalendarService implements CalendarService { _dio.options.baseUrl, baseUrl, )))); - var _value = _result.data!.map((k, dynamic v) => - MapEntry(k, CalendarModel.fromJson(v as Map))); + var _value = _result.data! + .map((dynamic i) => CalendarModel.fromJson(i as Map)) + .toList(); return _value; } diff --git a/lib/locator_service.dart b/lib/locator_service.dart index 7f2caf5d..fa54c505 100644 --- a/lib/locator_service.dart +++ b/lib/locator_service.dart @@ -3,6 +3,9 @@ import 'package:eatvio_app/core/initialization_cubit/initialization_cubit.dart'; import 'package:eatvio_app/features/blog_post/presentation/bloc/blog_post_cubit.dart'; import 'package:eatvio_app/features/blog_post/repositories/blog_post_repository.dart'; import 'package:eatvio_app/features/blog_post/services/blog_post_service.dart'; +import 'package:eatvio_app/features/calendar/presentation/bloc/calendar_cubit.dart'; +import 'package:eatvio_app/features/calendar/repositories/calendar_repository.dart'; +import 'package:eatvio_app/features/calendar/services/calendar_service.dart'; import 'package:eatvio_app/features/chat/presentation/bloc/chat_room_cubit/chat_room_cubit.dart'; import 'package:eatvio_app/features/chat/repositories/chat_repository.dart'; import 'package:eatvio_app/features/chat/services/chat_service.dart'; @@ -27,6 +30,8 @@ Future init() async { sl.registerFactory( () => BlogPostCubit(blogPostRepository: sl())); sl.registerFactory(() => DiaryBloc(diaryRepository: sl())); + sl.registerFactory( + () => CalendarCubit(calendarRepository: sl())); // Repository sl.registerLazySingleton( @@ -37,12 +42,15 @@ Future init() async { () => BlogPostRepository(blogPostService: sl())); sl.registerLazySingleton( () => DiaryRepository(diaryService: sl())); + sl.registerLazySingleton( + () => CalendarRepository(calendarService: sl())); // Services sl.registerLazySingleton(() => ChatService(sl())); sl.registerLazySingleton(() => FeedService(sl())); sl.registerLazySingleton(() => BlogPostService(sl())); sl.registerLazySingleton(() => DiaryService(sl())); + sl.registerLazySingleton(() => CalendarService(sl())); // External sl.registerLazySingleton( diff --git a/lib/main.dart b/lib/main.dart index f71b4a54..9ce1b92e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,7 @@ import 'package:eatvio_app/app_router.dart'; import 'package:eatvio_app/core/initialization_cubit/initialization_cubit.dart'; import 'package:eatvio_app/core/initialization_cubit/initialization_state.dart'; +import 'package:eatvio_app/features/calendar/presentation/bloc/calendar_cubit.dart'; import 'package:eatvio_app/features/chat/presentation/pages/chat_select_screen/bloc/chat_select_bloc.dart'; import 'package:eatvio_app/features/chat/presentation/pages/chat_select_screen/models/chat_select_model.dart'; import 'package:eatvio_app/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart'; @@ -41,13 +42,25 @@ class MyApp extends StatelessWidget { Widget build(BuildContext context) { return MultiBlocProvider( providers: [ - BlocProvider(create: (context) => InitializationCubit(chatRepository: sl())), - BlocProvider(create: (context) => ThemeBloc(ThemeState(themeType: PrefUtils().getThemeData()))), - BlocProvider(create: (context) => sl()..loadFeedBlogPostList()), - BlocProvider(create: (context) => MyProfileBloc(MyProfileState(myProfileModelObj: MyProfileModel()))..add(MyProfileInitialEvent())), - BlocProvider(create: (context) => sl()..add(LoadDiary())), + BlocProvider( + create: (context) => InitializationCubit(chatRepository: sl())), + BlocProvider( + create: (context) => + ThemeBloc(ThemeState(themeType: PrefUtils().getThemeData()))), + BlocProvider( + create: (context) => sl()..loadFeedBlogPostList()), + BlocProvider( + create: (context) => sl()..loadCalendarList()), + BlocProvider( + create: (context) => MyProfileBloc( + MyProfileState(myProfileModelObj: MyProfileModel())) + ..add(MyProfileInitialEvent())), + BlocProvider( + create: (context) => sl()..add(LoadDiary())), BlocProvider( - create: (context) => ChatSelectBloc(ChatSelectState(chatSelectModelObj: ChatSelectModel()))..add(ChatSelectInitialEvent()), + create: (context) => ChatSelectBloc( + ChatSelectState(chatSelectModelObj: ChatSelectModel())) + ..add(ChatSelectInitialEvent()), ), ], child: BlocListener( diff --git a/lib/widgets/custom_navigation_menu.dart b/lib/widgets/custom_navigation_menu.dart index 03d11a98..0a5d354d 100644 --- a/lib/widgets/custom_navigation_menu.dart +++ b/lib/widgets/custom_navigation_menu.dart @@ -23,19 +23,21 @@ class CustomNavigationMenu extends StatelessWidget { icon: ImageConstant.imgRecipes, text: 'Мои рецепты', onTap: () => GoRouter.of(context).push('/recipe-select-screen'), - // Действие при нажатии на "Мои рецепты" ), MenuItem( icon: ImageConstant.imgDiets, text: 'Мои диеты', onTap: () => GoRouter.of(context).push('/diet-select-screen'), - // Действие при нажатии на "Мои рецепты" ), MenuItem( icon: ImageConstant.imgPlans, text: 'Мои планы', onTap: () => GoRouter.of(context).push('/plan-select-screen'), - // Действие при нажатии на "Мои рецепты" + ), + MenuItem( + icon: ImageConstant.imgRecipes, + text: 'Календарь', + onTap: () => GoRouter.of(context).push('/calendar-screen'), ), MenuItem( icon: ImageConstant.imgFinance, @@ -45,15 +47,12 @@ class CustomNavigationMenu extends StatelessWidget { MenuItem( icon: ImageConstant.imgSupport, text: 'Поддержка', - onTap: () { - // Действие при нажатии на "Поддержка" - }, + onTap: () {}, ), MenuItem( icon: ImageConstant.imgExit, text: 'Выход', onTap: _onTapLogout(context), - // Действие при нажатии на "Выход" ), ], ), diff --git a/pubspec.yaml b/pubspec.yaml index 8a60729f..a7974983 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -69,6 +69,7 @@ dependencies: # debounce easy_debounce: ^2.0.3 syncfusion_flutter_charts: ^26.1.42 + table_calendar: ^3.1.2 dev_dependencies: build_runner: ^2.4.11