feat(calendar): Initial layouts models and API for calendar

This commit is contained in:
2024-07-25 14:16:13 +03:00
parent 6886997fde
commit 6312de5aa8
12 changed files with 190 additions and 220 deletions

View File

@@ -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',

View File

@@ -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<String, Object?> json) =>

View File

@@ -20,17 +20,8 @@ CalendarModel _$CalendarModelFromJson(Map<String, dynamic> 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<String, dynamic> 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<String, dynamic> 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<String, dynamic> 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 =>

View File

@@ -8,24 +8,12 @@ part of 'calendar_model.dart';
_$CalendarModelImpl _$$CalendarModelImplFromJson(Map<String, dynamic> 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<String, dynamic> _$$CalendarModelImplToJson(_$CalendarModelImpl instance) =>
<String, dynamic>{
'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,
};

View File

@@ -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<CalendarCubit, CalendarState>(
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(),
),
);
}
}

View File

@@ -8,10 +8,7 @@ class CalendarRepository {
Future<List<CalendarModel>> getCalendar() async {
try {
return (await calendarService.getCalendar())
.entries
.map((entry) => entry.value)
.toList();
return await calendarService.getCalendar();
} catch (e) {
rethrow;
}

View File

@@ -9,5 +9,5 @@ abstract class CalendarService {
factory CalendarService(Dio dio, {String baseUrl}) = _CalendarService;
@GET('/calendar/index')
Future<Map<String, CalendarModel>> getCalendar();
Future<List<CalendarModel>> getCalendar();
}

View File

@@ -19,13 +19,13 @@ class _CalendarService implements CalendarService {
String? baseUrl;
@override
Future<Map<String, CalendarModel>> getCalendar() async {
Future<List<CalendarModel>> getCalendar() async {
final _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _result = await _dio.fetch<Map<String, dynamic>>(
_setStreamType<Map<String, CalendarModel>>(Options(
final _result = await _dio
.fetch<List<dynamic>>(_setStreamType<List<CalendarModel>>(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<String, dynamic>)));
var _value = _result.data!
.map((dynamic i) => CalendarModel.fromJson(i as Map<String, dynamic>))
.toList();
return _value;
}

View File

@@ -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<void> init() async {
sl.registerFactory<BlogPostCubit>(
() => BlogPostCubit(blogPostRepository: sl()));
sl.registerFactory<DiaryBloc>(() => DiaryBloc(diaryRepository: sl()));
sl.registerFactory<CalendarCubit>(
() => CalendarCubit(calendarRepository: sl()));
// Repository
sl.registerLazySingleton<ChatRepository>(
@@ -37,12 +42,15 @@ Future<void> init() async {
() => BlogPostRepository(blogPostService: sl()));
sl.registerLazySingleton<DiaryRepository>(
() => DiaryRepository(diaryService: sl()));
sl.registerLazySingleton<CalendarRepository>(
() => CalendarRepository(calendarService: sl()));
// Services
sl.registerLazySingleton<ChatService>(() => ChatService(sl()));
sl.registerLazySingleton<FeedService>(() => FeedService(sl()));
sl.registerLazySingleton<BlogPostService>(() => BlogPostService(sl()));
sl.registerLazySingleton<DiaryService>(() => DiaryService(sl()));
sl.registerLazySingleton<CalendarService>(() => CalendarService(sl()));
// External
sl.registerLazySingleton(

View File

@@ -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<InitializationCubit>(create: (context) => InitializationCubit(chatRepository: sl())),
BlocProvider<ThemeBloc>(create: (context) => ThemeBloc(ThemeState(themeType: PrefUtils().getThemeData()))),
BlocProvider<FeedCubit>(create: (context) => sl<FeedCubit>()..loadFeedBlogPostList()),
BlocProvider<MyProfileBloc>(create: (context) => MyProfileBloc(MyProfileState(myProfileModelObj: MyProfileModel()))..add(MyProfileInitialEvent())),
BlocProvider<DiaryBloc>(create: (context) => sl<DiaryBloc>()..add(LoadDiary())),
BlocProvider<InitializationCubit>(
create: (context) => InitializationCubit(chatRepository: sl())),
BlocProvider<ThemeBloc>(
create: (context) =>
ThemeBloc(ThemeState(themeType: PrefUtils().getThemeData()))),
BlocProvider<FeedCubit>(
create: (context) => sl<FeedCubit>()..loadFeedBlogPostList()),
BlocProvider<CalendarCubit>(
create: (context) => sl<CalendarCubit>()..loadCalendarList()),
BlocProvider<MyProfileBloc>(
create: (context) => MyProfileBloc(
MyProfileState(myProfileModelObj: MyProfileModel()))
..add(MyProfileInitialEvent())),
BlocProvider<DiaryBloc>(
create: (context) => sl<DiaryBloc>()..add(LoadDiary())),
BlocProvider<ChatSelectBloc>(
create: (context) => ChatSelectBloc(ChatSelectState(chatSelectModelObj: ChatSelectModel()))..add(ChatSelectInitialEvent()),
create: (context) => ChatSelectBloc(
ChatSelectState(chatSelectModelObj: ChatSelectModel()))
..add(ChatSelectInitialEvent()),
),
],
child: BlocListener<InitializationCubit, InitializationState>(

View File

@@ -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),
// Действие при нажатии на "Выход"
),
],
),

View File

@@ -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