forked from eatvio/eatvio_app
Merge remote-tracking branch 'refs/remotes/origin/feature/feed'
# Conflicts: # lib/app_router.dart # lib/locator_service.dart
This commit is contained in:
@@ -11,7 +11,6 @@ import 'package:eatvio_app/features/diary/presentation/pages/diary_screen.dart';
|
||||
import 'package:eatvio_app/features/feed/models/recipes_model.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/pages/feed_screen.dart';
|
||||
import 'package:eatvio_app/features/recipes/presentation/pages/about_recipes_screen.dart';
|
||||
import 'package:eatvio_app/features/recipes/presentation/pages/recipe_create_screen.dart';
|
||||
import 'package:eatvio_app/features/registration/presentation/pages/registration_screen.dart';
|
||||
import 'package:eatvio_app/presentation/auth/auth_screen/auth_screen.dart';
|
||||
import 'package:eatvio_app/presentation/diets/diet_create_screen/diet_create_screen.dart';
|
||||
@@ -94,9 +93,18 @@ class AppRouter {
|
||||
),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/recipe-create-screen',
|
||||
name: 'recipeCreateScreen',
|
||||
builder: (context, state) => RecipeCreateScreen(),
|
||||
path: '/profile-screen',
|
||||
name: 'profileScreen',
|
||||
builder: (context, state) => ProfileScreen(
|
||||
author: state.extra as Author,
|
||||
),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/about-diet-screen',
|
||||
name: 'aboutDietScreen',
|
||||
builder: (context, state) => AboutDietScreen(
|
||||
datum: state.extra as Datum,
|
||||
),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/blog-post-create-screen',
|
||||
|
||||
@@ -49,7 +49,7 @@ class _BlogPostCreateScreenState extends State<BlogPostCreateScreen> {
|
||||
|
||||
_buildBlogPostCreate(BuildContext context, BlogPostCreateLoadedState state) {
|
||||
return Scaffold(
|
||||
resizeToAvoidBottomInset: false,
|
||||
resizeToAvoidBottomInset: true,
|
||||
appBar: AppBar(),
|
||||
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
|
||||
floatingActionButton: SizedBox(
|
||||
@@ -62,8 +62,12 @@ class _BlogPostCreateScreenState extends State<BlogPostCreateScreen> {
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
backgroundColor: appTheme.blueA400,
|
||||
onPressed: () => _submitForm(context, state.title!.text, state.description!.text, state.youtubeURL!.text),
|
||||
backgroundColor: state.image != null || state.title!.text.isNotEmpty || state.description!.text.isNotEmpty || state.youtubeURL!.text.isNotEmpty
|
||||
? appTheme.blueA400
|
||||
: Colors.grey,
|
||||
onPressed: state.image != null || state.title!.text.isNotEmpty || state.description!.text.isNotEmpty || state.youtubeURL!.text.isNotEmpty
|
||||
? () => _submitForm(context, state.title!.text, state.description!.text, state.youtubeURL!.text)
|
||||
: null,
|
||||
label: Text(
|
||||
'Создать',
|
||||
style: theme.textTheme.titleSmall,
|
||||
@@ -75,32 +79,29 @@ class _BlogPostCreateScreenState extends State<BlogPostCreateScreen> {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (state.youtubeURL!.text.isEmpty) Text('Изображение поста'),
|
||||
if (state.youtubeURL!.text.isEmpty) SizedBox(height: 8),
|
||||
if (state.youtubeURL!.text.isEmpty) _buildAddPhoto(context, state),
|
||||
SizedBox(height: 16),
|
||||
Text('Заголовок'),
|
||||
SizedBox(height: 8),
|
||||
CustomTextFormField(
|
||||
controller: state.title,
|
||||
validator: _validateTitle,
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Text('Описание'),
|
||||
SizedBox(height: 8),
|
||||
CustomTextFormField(
|
||||
controller: state.description,
|
||||
validator: _validateDescription,
|
||||
maxLines: 6,
|
||||
minLines: 1,
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Text('Ссылка на видео'),
|
||||
SizedBox(height: 8),
|
||||
CustomTextFormField(
|
||||
if (state.image == null) Text('Ссылка на видео'),
|
||||
if (state.image == null) SizedBox(height: 8),
|
||||
if (state.image == null) CustomTextFormField(
|
||||
controller: state.youtubeURL,
|
||||
validator: _validateYouTubeLink,
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Text('Изображение поста'),
|
||||
SizedBox(height: 8),
|
||||
_buildAddPhoto(context, state),
|
||||
SizedBox(height: 80),
|
||||
],
|
||||
),
|
||||
@@ -110,20 +111,7 @@ class _BlogPostCreateScreenState extends State<BlogPostCreateScreen> {
|
||||
}
|
||||
|
||||
_submitForm(BuildContext context, String title, String description, String youtubeURL) async {
|
||||
String? titleError = _validateTitle(title);
|
||||
String? descriptionError = _validateDescription(description);
|
||||
String? youtubeURLError = _validateYouTubeLink(youtubeURL);
|
||||
|
||||
if (titleError != null || descriptionError != null || youtubeURLError != null) {
|
||||
// Display error messages or handle invalid input as needed
|
||||
// For example, show a snackbar with the error message
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(titleError ?? descriptionError ?? youtubeURLError!)),
|
||||
);
|
||||
} else {
|
||||
// Proceed with form submission
|
||||
context.read<BlogPostCreateBloc>().add(CreateBlogPost());
|
||||
}
|
||||
context.read<BlogPostCreateBloc>().add(CreateBlogPost());
|
||||
}
|
||||
|
||||
_buildAddPhoto(BuildContext context, BlogPostCreateLoadedState state) {
|
||||
@@ -179,31 +167,3 @@ addImage(BuildContext context, bool isLoading) {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
String? _validateTitle(value) {
|
||||
if (value!.isEmpty) {
|
||||
return 'Пожалуйста, введите заголовок';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
String? _validateDescription(value) {
|
||||
if (value!.isEmpty) {
|
||||
return 'Пожалуйста, введите описание';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
String? _validateYouTubeLink(value) {
|
||||
if (value!.isEmpty) {
|
||||
return 'Пожалуйста, введите ссылку';
|
||||
} else if (!_isValidUrl(value)) {
|
||||
return 'Пожалуйста, введите корректную ссылку';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
bool _isValidUrl(String url) {
|
||||
final RegExp urlRegExp = new RegExp(r"^(http|https):\/\/([\w-]+\.)+[\w-]+(\/[\w-./?%&=]*)?$");
|
||||
return urlRegExp.hasMatch(url);
|
||||
}
|
||||
|
||||
250
lib/features/diets/presentation/pages/about_diet_screen.dart
Normal file
250
lib/features/diets/presentation/pages/about_diet_screen.dart
Normal file
@@ -0,0 +1,250 @@
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:eatvio_app/core/constants/constants.dart';
|
||||
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
|
||||
import 'package:eatvio_app/theme/theme_helper.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
class AboutDietScreen extends StatefulWidget {
|
||||
final Datum datum;
|
||||
late final List<int> selectedIndexes;
|
||||
|
||||
AboutDietScreen({super.key, required this.datum}) {
|
||||
selectedIndexes = List.generate(datum.dailySchedule.length, (_) => 0);
|
||||
}
|
||||
|
||||
@override
|
||||
State<AboutDietScreen> createState() => _AboutDietScreenState();
|
||||
}
|
||||
|
||||
class _AboutDietScreenState extends State<AboutDietScreen> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
|
||||
floatingActionButton: SizedBox(
|
||||
width: MediaQuery.of(context).size.width - 32,
|
||||
child: FloatingActionButton.extended(
|
||||
heroTag: 'nextButtonRegistration',
|
||||
highlightElevation: 0,
|
||||
elevation: 0,
|
||||
focusElevation: 0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
backgroundColor: appTheme.greenA700,
|
||||
onPressed: () {},
|
||||
label: Text(
|
||||
'Начать диету',
|
||||
style: theme.textTheme.titleSmall,
|
||||
),
|
||||
),
|
||||
),
|
||||
appBar: AppBar(
|
||||
actions: [
|
||||
InkWell(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
onTap: () => GoRouter.of(context).pushNamed('profileScreen', extra: widget.datum.author),
|
||||
child: Ink(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
CircleAvatar(
|
||||
maxRadius: 16,
|
||||
minRadius: 16,
|
||||
backgroundImage: NetworkImage(widget.datum.author.authorProfileIcon),
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
Text(
|
||||
widget.datum.author.authorName,
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
padding: EdgeInsets.only(bottom: 80),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Text(
|
||||
widget.datum.name,
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.w500,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 12),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(Icons.timer_outlined),
|
||||
SizedBox(width: 4),
|
||||
Text(
|
||||
widget.datum.duration.toString() + ' дней',
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: 12),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Text(
|
||||
widget.datum.details,
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
height: 1.2,
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 12),
|
||||
CachedNetworkImage(
|
||||
imageUrl: baseUrl + '/storage/' + widget.datum.image,
|
||||
),
|
||||
SizedBox(height: 12),
|
||||
ListView.separated(
|
||||
padding: EdgeInsets.all(16),
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
shrinkWrap: true,
|
||||
itemBuilder: (context, index) {
|
||||
return _dayOfPlan(widget.datum.dailySchedule[index], index);
|
||||
},
|
||||
separatorBuilder: (context, index) => Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
child: Container(
|
||||
height: 0.4,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
),
|
||||
),
|
||||
itemCount: widget.datum.dailySchedule.length,
|
||||
),
|
||||
SizedBox(height: 32),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
_dayOfPlan(List<List<DailySchedule>> day, int dayNumber) {
|
||||
_choiceChipWidget(int index) {
|
||||
return ChoiceChip(
|
||||
selectedColor: appTheme.blueA400,
|
||||
pressElevation: 0,
|
||||
showCheckmark: false,
|
||||
side: BorderSide.none,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
label: Text((index + 1).toString()),
|
||||
labelStyle: TextStyle(
|
||||
color: index == widget.selectedIndexes[dayNumber] ? Colors.white : appTheme.gray600,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 12,
|
||||
),
|
||||
selected: widget.selectedIndexes[dayNumber] == index,
|
||||
backgroundColor: appTheme.gray100,
|
||||
onSelected: (bool selected) {
|
||||
setState(() {
|
||||
widget.selectedIndexes[dayNumber] = index;
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'День ' + (dayNumber + 1).toString(),
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
Text(
|
||||
'Приём пищи',
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
_choiceChipWidget(0),
|
||||
_choiceChipWidget(1),
|
||||
_choiceChipWidget(2),
|
||||
_choiceChipWidget(3),
|
||||
_choiceChipWidget(4),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
ListView.separated(
|
||||
shrinkWrap: true,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
itemBuilder: (context, index) => _daily(day[widget.selectedIndexes[dayNumber]][index]),
|
||||
separatorBuilder: (context, index) => SizedBox(height: 4),
|
||||
itemCount: day[widget.selectedIndexes[dayNumber]].length,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
_daily(DailySchedule daily) {
|
||||
return Row(
|
||||
children: [
|
||||
Text(
|
||||
'• ' + daily.name,
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
height: 1.2,
|
||||
),
|
||||
),
|
||||
Spacer(),
|
||||
Text(
|
||||
daily.quantity.toString() + ' ' + daily.portion.name,
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
height: 1.2,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/diets_cubit/diets_state.dart';
|
||||
import 'package:eatvio_app/features/feed/repositories/feed_repository.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class DietsCubit extends Cubit<DietsState> {
|
||||
final FeedRepository feedRepository;
|
||||
|
||||
DietsCubit({required this.feedRepository}) : super(const DietsState.loading());
|
||||
|
||||
loadDiets() async {
|
||||
try {
|
||||
final diets = await feedRepository.getDiets();
|
||||
emit(DietsState.loaded(diets: diets));
|
||||
} catch (e) {
|
||||
emit(DietsState.error(errorMessage: e.toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'diets_state.freezed.dart';
|
||||
|
||||
@freezed
|
||||
abstract class DietsState with _$DietsState {
|
||||
const factory DietsState() = _DietsState;
|
||||
|
||||
const factory DietsState.loading() = DietsStateLoading;
|
||||
|
||||
const factory DietsState.loaded({
|
||||
required DietsPagination diets,
|
||||
}) = DietsStateLoaded;
|
||||
|
||||
const factory DietsState.error({
|
||||
required String errorMessage,
|
||||
}) = DietsStateError;
|
||||
}
|
||||
@@ -0,0 +1,620 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'diets_state.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
|
||||
|
||||
/// @nodoc
|
||||
mixin _$DietsState {
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>(
|
||||
TResult Function() $default, {
|
||||
required TResult Function() loading,
|
||||
required TResult Function(DietsPagination diets) loaded,
|
||||
required TResult Function(String errorMessage) error,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>(
|
||||
TResult? Function()? $default, {
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(DietsPagination diets)? loaded,
|
||||
TResult? Function(String errorMessage)? error,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>(
|
||||
TResult Function()? $default, {
|
||||
TResult Function()? loading,
|
||||
TResult Function(DietsPagination diets)? loaded,
|
||||
TResult Function(String errorMessage)? error,
|
||||
required TResult orElse(),
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>(
|
||||
TResult Function(_DietsState value) $default, {
|
||||
required TResult Function(DietsStateLoading value) loading,
|
||||
required TResult Function(DietsStateLoaded value) loaded,
|
||||
required TResult Function(DietsStateError value) error,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>(
|
||||
TResult? Function(_DietsState value)? $default, {
|
||||
TResult? Function(DietsStateLoading value)? loading,
|
||||
TResult? Function(DietsStateLoaded value)? loaded,
|
||||
TResult? Function(DietsStateError value)? error,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>(
|
||||
TResult Function(_DietsState value)? $default, {
|
||||
TResult Function(DietsStateLoading value)? loading,
|
||||
TResult Function(DietsStateLoaded value)? loaded,
|
||||
TResult Function(DietsStateError value)? error,
|
||||
required TResult orElse(),
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $DietsStateCopyWith<$Res> {
|
||||
factory $DietsStateCopyWith(
|
||||
DietsState value, $Res Function(DietsState) then) =
|
||||
_$DietsStateCopyWithImpl<$Res, DietsState>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$DietsStateCopyWithImpl<$Res, $Val extends DietsState>
|
||||
implements $DietsStateCopyWith<$Res> {
|
||||
_$DietsStateCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$DietsStateImplCopyWith<$Res> {
|
||||
factory _$$DietsStateImplCopyWith(
|
||||
_$DietsStateImpl value, $Res Function(_$DietsStateImpl) then) =
|
||||
__$$DietsStateImplCopyWithImpl<$Res>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$DietsStateImplCopyWithImpl<$Res>
|
||||
extends _$DietsStateCopyWithImpl<$Res, _$DietsStateImpl>
|
||||
implements _$$DietsStateImplCopyWith<$Res> {
|
||||
__$$DietsStateImplCopyWithImpl(
|
||||
_$DietsStateImpl _value, $Res Function(_$DietsStateImpl) _then)
|
||||
: super(_value, _then);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$DietsStateImpl implements _DietsState {
|
||||
const _$DietsStateImpl();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'DietsState()';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is _$DietsStateImpl);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => runtimeType.hashCode;
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>(
|
||||
TResult Function() $default, {
|
||||
required TResult Function() loading,
|
||||
required TResult Function(DietsPagination diets) loaded,
|
||||
required TResult Function(String errorMessage) error,
|
||||
}) {
|
||||
return $default();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>(
|
||||
TResult? Function()? $default, {
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(DietsPagination diets)? loaded,
|
||||
TResult? Function(String errorMessage)? error,
|
||||
}) {
|
||||
return $default?.call();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>(
|
||||
TResult Function()? $default, {
|
||||
TResult Function()? loading,
|
||||
TResult Function(DietsPagination diets)? loaded,
|
||||
TResult Function(String errorMessage)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if ($default != null) {
|
||||
return $default();
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>(
|
||||
TResult Function(_DietsState value) $default, {
|
||||
required TResult Function(DietsStateLoading value) loading,
|
||||
required TResult Function(DietsStateLoaded value) loaded,
|
||||
required TResult Function(DietsStateError value) error,
|
||||
}) {
|
||||
return $default(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>(
|
||||
TResult? Function(_DietsState value)? $default, {
|
||||
TResult? Function(DietsStateLoading value)? loading,
|
||||
TResult? Function(DietsStateLoaded value)? loaded,
|
||||
TResult? Function(DietsStateError value)? error,
|
||||
}) {
|
||||
return $default?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>(
|
||||
TResult Function(_DietsState value)? $default, {
|
||||
TResult Function(DietsStateLoading value)? loading,
|
||||
TResult Function(DietsStateLoaded value)? loaded,
|
||||
TResult Function(DietsStateError value)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if ($default != null) {
|
||||
return $default(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _DietsState implements DietsState {
|
||||
const factory _DietsState() = _$DietsStateImpl;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$DietsStateLoadingImplCopyWith<$Res> {
|
||||
factory _$$DietsStateLoadingImplCopyWith(_$DietsStateLoadingImpl value,
|
||||
$Res Function(_$DietsStateLoadingImpl) then) =
|
||||
__$$DietsStateLoadingImplCopyWithImpl<$Res>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$DietsStateLoadingImplCopyWithImpl<$Res>
|
||||
extends _$DietsStateCopyWithImpl<$Res, _$DietsStateLoadingImpl>
|
||||
implements _$$DietsStateLoadingImplCopyWith<$Res> {
|
||||
__$$DietsStateLoadingImplCopyWithImpl(_$DietsStateLoadingImpl _value,
|
||||
$Res Function(_$DietsStateLoadingImpl) _then)
|
||||
: super(_value, _then);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$DietsStateLoadingImpl implements DietsStateLoading {
|
||||
const _$DietsStateLoadingImpl();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'DietsState.loading()';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is _$DietsStateLoadingImpl);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => runtimeType.hashCode;
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>(
|
||||
TResult Function() $default, {
|
||||
required TResult Function() loading,
|
||||
required TResult Function(DietsPagination diets) loaded,
|
||||
required TResult Function(String errorMessage) error,
|
||||
}) {
|
||||
return loading();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>(
|
||||
TResult? Function()? $default, {
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(DietsPagination diets)? loaded,
|
||||
TResult? Function(String errorMessage)? error,
|
||||
}) {
|
||||
return loading?.call();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>(
|
||||
TResult Function()? $default, {
|
||||
TResult Function()? loading,
|
||||
TResult Function(DietsPagination diets)? loaded,
|
||||
TResult Function(String errorMessage)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (loading != null) {
|
||||
return loading();
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>(
|
||||
TResult Function(_DietsState value) $default, {
|
||||
required TResult Function(DietsStateLoading value) loading,
|
||||
required TResult Function(DietsStateLoaded value) loaded,
|
||||
required TResult Function(DietsStateError value) error,
|
||||
}) {
|
||||
return loading(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>(
|
||||
TResult? Function(_DietsState value)? $default, {
|
||||
TResult? Function(DietsStateLoading value)? loading,
|
||||
TResult? Function(DietsStateLoaded value)? loaded,
|
||||
TResult? Function(DietsStateError value)? error,
|
||||
}) {
|
||||
return loading?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>(
|
||||
TResult Function(_DietsState value)? $default, {
|
||||
TResult Function(DietsStateLoading value)? loading,
|
||||
TResult Function(DietsStateLoaded value)? loaded,
|
||||
TResult Function(DietsStateError value)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (loading != null) {
|
||||
return loading(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class DietsStateLoading implements DietsState {
|
||||
const factory DietsStateLoading() = _$DietsStateLoadingImpl;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$DietsStateLoadedImplCopyWith<$Res> {
|
||||
factory _$$DietsStateLoadedImplCopyWith(_$DietsStateLoadedImpl value,
|
||||
$Res Function(_$DietsStateLoadedImpl) then) =
|
||||
__$$DietsStateLoadedImplCopyWithImpl<$Res>;
|
||||
@useResult
|
||||
$Res call({DietsPagination diets});
|
||||
|
||||
$DietsPaginationCopyWith<$Res> get diets;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$DietsStateLoadedImplCopyWithImpl<$Res>
|
||||
extends _$DietsStateCopyWithImpl<$Res, _$DietsStateLoadedImpl>
|
||||
implements _$$DietsStateLoadedImplCopyWith<$Res> {
|
||||
__$$DietsStateLoadedImplCopyWithImpl(_$DietsStateLoadedImpl _value,
|
||||
$Res Function(_$DietsStateLoadedImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? diets = null,
|
||||
}) {
|
||||
return _then(_$DietsStateLoadedImpl(
|
||||
diets: null == diets
|
||||
? _value.diets
|
||||
: diets // ignore: cast_nullable_to_non_nullable
|
||||
as DietsPagination,
|
||||
));
|
||||
}
|
||||
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$DietsPaginationCopyWith<$Res> get diets {
|
||||
return $DietsPaginationCopyWith<$Res>(_value.diets, (value) {
|
||||
return _then(_value.copyWith(diets: value));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$DietsStateLoadedImpl implements DietsStateLoaded {
|
||||
const _$DietsStateLoadedImpl({required this.diets});
|
||||
|
||||
@override
|
||||
final DietsPagination diets;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'DietsState.loaded(diets: $diets)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$DietsStateLoadedImpl &&
|
||||
(identical(other.diets, diets) || other.diets == diets));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, diets);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$DietsStateLoadedImplCopyWith<_$DietsStateLoadedImpl> get copyWith =>
|
||||
__$$DietsStateLoadedImplCopyWithImpl<_$DietsStateLoadedImpl>(
|
||||
this, _$identity);
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>(
|
||||
TResult Function() $default, {
|
||||
required TResult Function() loading,
|
||||
required TResult Function(DietsPagination diets) loaded,
|
||||
required TResult Function(String errorMessage) error,
|
||||
}) {
|
||||
return loaded(diets);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>(
|
||||
TResult? Function()? $default, {
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(DietsPagination diets)? loaded,
|
||||
TResult? Function(String errorMessage)? error,
|
||||
}) {
|
||||
return loaded?.call(diets);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>(
|
||||
TResult Function()? $default, {
|
||||
TResult Function()? loading,
|
||||
TResult Function(DietsPagination diets)? loaded,
|
||||
TResult Function(String errorMessage)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (loaded != null) {
|
||||
return loaded(diets);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>(
|
||||
TResult Function(_DietsState value) $default, {
|
||||
required TResult Function(DietsStateLoading value) loading,
|
||||
required TResult Function(DietsStateLoaded value) loaded,
|
||||
required TResult Function(DietsStateError value) error,
|
||||
}) {
|
||||
return loaded(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>(
|
||||
TResult? Function(_DietsState value)? $default, {
|
||||
TResult? Function(DietsStateLoading value)? loading,
|
||||
TResult? Function(DietsStateLoaded value)? loaded,
|
||||
TResult? Function(DietsStateError value)? error,
|
||||
}) {
|
||||
return loaded?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>(
|
||||
TResult Function(_DietsState value)? $default, {
|
||||
TResult Function(DietsStateLoading value)? loading,
|
||||
TResult Function(DietsStateLoaded value)? loaded,
|
||||
TResult Function(DietsStateError value)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (loaded != null) {
|
||||
return loaded(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class DietsStateLoaded implements DietsState {
|
||||
const factory DietsStateLoaded({required final DietsPagination diets}) =
|
||||
_$DietsStateLoadedImpl;
|
||||
|
||||
DietsPagination get diets;
|
||||
@JsonKey(ignore: true)
|
||||
_$$DietsStateLoadedImplCopyWith<_$DietsStateLoadedImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$DietsStateErrorImplCopyWith<$Res> {
|
||||
factory _$$DietsStateErrorImplCopyWith(_$DietsStateErrorImpl value,
|
||||
$Res Function(_$DietsStateErrorImpl) then) =
|
||||
__$$DietsStateErrorImplCopyWithImpl<$Res>;
|
||||
@useResult
|
||||
$Res call({String errorMessage});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$DietsStateErrorImplCopyWithImpl<$Res>
|
||||
extends _$DietsStateCopyWithImpl<$Res, _$DietsStateErrorImpl>
|
||||
implements _$$DietsStateErrorImplCopyWith<$Res> {
|
||||
__$$DietsStateErrorImplCopyWithImpl(
|
||||
_$DietsStateErrorImpl _value, $Res Function(_$DietsStateErrorImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? errorMessage = null,
|
||||
}) {
|
||||
return _then(_$DietsStateErrorImpl(
|
||||
errorMessage: null == errorMessage
|
||||
? _value.errorMessage
|
||||
: errorMessage // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$DietsStateErrorImpl implements DietsStateError {
|
||||
const _$DietsStateErrorImpl({required this.errorMessage});
|
||||
|
||||
@override
|
||||
final String errorMessage;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'DietsState.error(errorMessage: $errorMessage)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$DietsStateErrorImpl &&
|
||||
(identical(other.errorMessage, errorMessage) ||
|
||||
other.errorMessage == errorMessage));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, errorMessage);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$DietsStateErrorImplCopyWith<_$DietsStateErrorImpl> get copyWith =>
|
||||
__$$DietsStateErrorImplCopyWithImpl<_$DietsStateErrorImpl>(
|
||||
this, _$identity);
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>(
|
||||
TResult Function() $default, {
|
||||
required TResult Function() loading,
|
||||
required TResult Function(DietsPagination diets) loaded,
|
||||
required TResult Function(String errorMessage) error,
|
||||
}) {
|
||||
return error(errorMessage);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>(
|
||||
TResult? Function()? $default, {
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(DietsPagination diets)? loaded,
|
||||
TResult? Function(String errorMessage)? error,
|
||||
}) {
|
||||
return error?.call(errorMessage);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>(
|
||||
TResult Function()? $default, {
|
||||
TResult Function()? loading,
|
||||
TResult Function(DietsPagination diets)? loaded,
|
||||
TResult Function(String errorMessage)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (error != null) {
|
||||
return error(errorMessage);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>(
|
||||
TResult Function(_DietsState value) $default, {
|
||||
required TResult Function(DietsStateLoading value) loading,
|
||||
required TResult Function(DietsStateLoaded value) loaded,
|
||||
required TResult Function(DietsStateError value) error,
|
||||
}) {
|
||||
return error(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>(
|
||||
TResult? Function(_DietsState value)? $default, {
|
||||
TResult? Function(DietsStateLoading value)? loading,
|
||||
TResult? Function(DietsStateLoaded value)? loaded,
|
||||
TResult? Function(DietsStateError value)? error,
|
||||
}) {
|
||||
return error?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>(
|
||||
TResult Function(_DietsState value)? $default, {
|
||||
TResult Function(DietsStateLoading value)? loading,
|
||||
TResult Function(DietsStateLoaded value)? loaded,
|
||||
TResult Function(DietsStateError value)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (error != null) {
|
||||
return error(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class DietsStateError implements DietsState {
|
||||
const factory DietsStateError({required final String errorMessage}) =
|
||||
_$DietsStateErrorImpl;
|
||||
|
||||
String get errorMessage;
|
||||
@JsonKey(ignore: true)
|
||||
_$$DietsStateErrorImplCopyWith<_$DietsStateErrorImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/diets_cubit/diets_state.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/feed_cubit/feed_state.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/recipes_cubit/recipes_cubit.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/recipes_cubit/recipes_state.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/widgets/blog_post_widget.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/widgets/diets_widget.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/widgets/recipes_widget.dart';
|
||||
import 'package:eatvio_app/theme/theme_helper.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
@@ -59,14 +62,57 @@ class _FeedScreenState extends State<FeedScreen> {
|
||||
builder: (BuildContext context) {
|
||||
if (_selectedChipIndex == 0)
|
||||
return _buildAllBlogPosts();
|
||||
else
|
||||
else if (_selectedChipIndex == 1)
|
||||
return _buildAllRecipes();
|
||||
else if (_selectedChipIndex == 2)
|
||||
return _buildDiets();
|
||||
else
|
||||
return Center(child: Text(chipsLabelList[_selectedChipIndex]));
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
_buildDiets() {
|
||||
return RefreshIndicator(
|
||||
onRefresh: () => context.read<DietsCubit>().loadDiets(),
|
||||
child: BlocBuilder<DietsCubit, DietsState>(
|
||||
builder: (BuildContext context, DietsState state) {
|
||||
if (state is DietsStateLoaded) {
|
||||
return ListView.separated(
|
||||
padding: EdgeInsets.symmetric(vertical: 8),
|
||||
shrinkWrap: true,
|
||||
physics: BouncingScrollPhysics(),
|
||||
itemBuilder: (context, index) {
|
||||
return DietsWidget(datum: state.diets.data[index]);
|
||||
},
|
||||
separatorBuilder: (context, index) {
|
||||
return SizedBox(height: 8);
|
||||
},
|
||||
itemCount: state.diets.data.length,
|
||||
);
|
||||
} else if (state is DietsStateError) {
|
||||
return Scaffold(
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Center(
|
||||
child: Text(state.errorMessage),
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return Scaffold(
|
||||
body: Center(
|
||||
child: CupertinoActivityIndicator(),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
_buildAllBlogPosts() {
|
||||
return RefreshIndicator(
|
||||
onRefresh: () => context.read<FeedCubit>().loadFeedBlogPostList(),
|
||||
|
||||
187
lib/features/feed/presentation/widgets/diets_widget.dart
Normal file
187
lib/features/feed/presentation/widgets/diets_widget.dart
Normal file
@@ -0,0 +1,187 @@
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:dismissible_page/dismissible_page.dart';
|
||||
import 'package:eatvio_app/core/app_export.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/pages/photo_view_screen.dart';
|
||||
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
class DietsWidget extends StatefulWidget {
|
||||
final Datum datum;
|
||||
|
||||
const DietsWidget({super.key, required this.datum});
|
||||
|
||||
@override
|
||||
State<DietsWidget> createState() => _DietsWidgetState();
|
||||
}
|
||||
|
||||
class _DietsWidgetState extends State<DietsWidget> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
onTap: () => GoRouter.of(context).pushNamed('aboutDietScreen', extra: widget.datum),
|
||||
child: Ink(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
color: Colors.white,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Stack(
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(12)),
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
context.pushTransparentRoute(
|
||||
rootNavigator: true,
|
||||
PhotoViewScreen(
|
||||
imageUrls: [baseUrl + '/storage/' + widget.datum.image],
|
||||
index: 0,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Hero(
|
||||
tag: baseUrl + '/storage/' + widget.datum.image,
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: baseUrl + '/storage/' + widget.datum.image,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
left: 8,
|
||||
bottom: 8,
|
||||
child: Wrap(
|
||||
runSpacing: 8,
|
||||
children: [
|
||||
_iconButton(Icons.fastfood, '139.9 ккал'),
|
||||
SizedBox(width: 8),
|
||||
_iconButton(Icons.timer_rounded, widget.datum.state),
|
||||
SizedBox(width: 8),
|
||||
_iconButton(Icons.fast_forward_rounded, widget.datum.duration.toString()),
|
||||
],
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
left: 8,
|
||||
top: 8,
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withOpacity(0.8),
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.favorite_rounded,
|
||||
size: 16,
|
||||
color: Colors.black,
|
||||
),
|
||||
SizedBox(width: 4),
|
||||
Text(
|
||||
widget.datum.totalLikes.toString(),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
right: 8,
|
||||
top: 8,
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withOpacity(0.8),
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.visibility_rounded,
|
||||
size: 16,
|
||||
color: Colors.black,
|
||||
),
|
||||
SizedBox(width: 4),
|
||||
Text(
|
||||
widget.datum.totalViews.toString(),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 12),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
child: Text(
|
||||
widget.datum.name,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.black87,
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
child: Text(
|
||||
widget.datum.details,
|
||||
style: TextStyle(
|
||||
color: Colors.black87,
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 12),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
_iconButton(IconData icon, [String? text]) {
|
||||
return Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withOpacity(0.8),
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
height: 32,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
icon,
|
||||
size: 16,
|
||||
color: Colors.black,
|
||||
),
|
||||
if (text != null) SizedBox(width: 8),
|
||||
if (text != null)
|
||||
Text(
|
||||
text,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
34
lib/features/profile/presentation/pages/profile_screen.dart
Normal file
34
lib/features/profile/presentation/pages/profile_screen.dart
Normal file
@@ -0,0 +1,34 @@
|
||||
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ProfileScreen extends StatelessWidget {
|
||||
final Author author;
|
||||
|
||||
const ProfileScreen({super.key, required this.author});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(),
|
||||
body: Column(
|
||||
children: [
|
||||
CircleAvatar(
|
||||
maxRadius: 128,
|
||||
minRadius: 128,
|
||||
backgroundImage: NetworkImage(author.authorProfileIcon),
|
||||
),
|
||||
SizedBox(height: 32),
|
||||
Text(
|
||||
author.authorName,
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.w400,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -61,6 +61,19 @@ class AboutRecipesScreen extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
SizedBox(height: 12),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Text(
|
||||
recipes.description,
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
height: 1.2,
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 12),
|
||||
CachedNetworkImage(
|
||||
imageUrl: baseUrl + '/storage/' + recipes.image,
|
||||
),
|
||||
@@ -124,7 +137,7 @@ class AboutRecipesScreen extends StatelessWidget {
|
||||
|
||||
_ingredient(Ingredient ingredient) {
|
||||
return Text(
|
||||
'• '+ ingredient.name + ' ' + ingredient.portion + ' ' + (ingredient.unit ?? ''),
|
||||
'• ' + ingredient.name + ' ' + ingredient.portion + ' ' + (ingredient.unit ?? ''),
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 14,
|
||||
|
||||
@@ -15,6 +15,7 @@ import 'package:eatvio_app/features/chat/services/chat_service.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/bloc/diary_bloc.dart';
|
||||
import 'package:eatvio_app/features/diary/repositories/diary_repository.dart';
|
||||
import 'package:eatvio_app/features/diary/services/diary_service.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/recipes_cubit/recipes_cubit.dart';
|
||||
import 'package:eatvio_app/features/feed/repositories/feed_repository.dart';
|
||||
@@ -28,43 +29,32 @@ final sl = GetIt.instance;
|
||||
|
||||
Future<void> init() async {
|
||||
// BLoC / Cubit
|
||||
sl.registerLazySingleton<InitializationCubit>(
|
||||
() => InitializationCubit(chatRepository: sl()));
|
||||
sl.registerLazySingleton<InitializationCubit>(() => InitializationCubit(chatRepository: sl()));
|
||||
sl.registerLazySingleton<NewMessagesCubit>(() => NewMessagesCubit());
|
||||
sl.registerLazySingleton<NotificationsCubit>(() => NotificationsCubit());
|
||||
|
||||
sl.registerFactory<RegistrationCubit>(
|
||||
() => RegistrationCubit(registrationRepository: sl()));
|
||||
sl.registerFactory<ChatRoomCubit>(
|
||||
() => ChatRoomCubit(chatRepository: sl(), initializationCubit: sl()));
|
||||
sl.registerFactory<RegistrationCubit>(() => RegistrationCubit(registrationRepository: sl()));
|
||||
sl.registerFactory<ChatRoomCubit>(() => ChatRoomCubit(chatRepository: sl(), initializationCubit: sl()));
|
||||
sl.registerFactory<FeedCubit>(() => FeedCubit(feedRepository: sl()));
|
||||
sl.registerFactory<RecipesCubit>(() => RecipesCubit(feedRepository: sl()));
|
||||
sl.registerFactory<BlogPostCubit>(
|
||||
() => BlogPostCubit(blogPostRepository: sl()));
|
||||
sl.registerFactory<DietsCubit>(() => DietsCubit(feedRepository: sl()));
|
||||
sl.registerFactory<BlogPostCubit>(() => BlogPostCubit(blogPostRepository: sl()));
|
||||
sl.registerFactory<DiaryBloc>(() => DiaryBloc(diaryRepository: sl()));
|
||||
sl.registerFactory<CalendarCubit>(
|
||||
() => CalendarCubit(calendarRepository: sl()));
|
||||
sl.registerFactory<CalendarCubit>(() => CalendarCubit(calendarRepository: sl()));
|
||||
|
||||
// Repository
|
||||
sl.registerLazySingleton<ChatRepository>(
|
||||
() => ChatRepository(chatService: sl()));
|
||||
sl.registerLazySingleton<FeedRepository>(
|
||||
() => FeedRepository(feedService: sl()));
|
||||
sl.registerLazySingleton<BlogPostRepository>(
|
||||
() => BlogPostRepository(blogPostService: sl()));
|
||||
sl.registerLazySingleton<RegistrationRepository>(
|
||||
() => RegistrationRepository(registrationService: sl()));
|
||||
sl.registerLazySingleton<DiaryRepository>(
|
||||
() => DiaryRepository(diaryService: sl()));
|
||||
sl.registerLazySingleton<CalendarRepository>(
|
||||
() => CalendarRepository(calendarService: sl()));
|
||||
sl.registerLazySingleton<ChatRepository>(() => ChatRepository(chatService: sl()));
|
||||
sl.registerLazySingleton<FeedRepository>(() => FeedRepository(feedService: sl()));
|
||||
sl.registerLazySingleton<BlogPostRepository>(() => BlogPostRepository(blogPostService: sl()));
|
||||
sl.registerLazySingleton<RegistrationRepository>(() => RegistrationRepository(registrationService: 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<RegistrationService>(
|
||||
() => RegistrationService(sl()));
|
||||
sl.registerLazySingleton<RegistrationService>(() => RegistrationService(sl()));
|
||||
sl.registerLazySingleton<DiaryService>(() => DiaryService(sl()));
|
||||
sl.registerLazySingleton<CalendarService>(() => CalendarService(sl()));
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import 'package:eatvio_app/features/calendar/presentation/bloc/calendar_cubit.da
|
||||
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/diary/presentation/bloc/diary_bloc.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/recipes_cubit/recipes_cubit.dart';
|
||||
import 'package:eatvio_app/locator_service.dart' as di;
|
||||
@@ -51,6 +52,7 @@ class MyApp extends StatelessWidget {
|
||||
BlocProvider<ThemeBloc>(create: (context) => ThemeBloc(ThemeState(themeType: PrefUtils().getThemeData()))),
|
||||
BlocProvider<FeedCubit>(create: (context) => sl<FeedCubit>()..loadFeedBlogPostList()),
|
||||
BlocProvider<RecipesCubit>(create: (context) => sl<RecipesCubit>()..loadRecipesList()),
|
||||
BlocProvider<DietsCubit>(create: (context) => sl<DietsCubit>()..loadDiets()),
|
||||
BlocProvider<MyProfileBloc>(create: (context) => MyProfileBloc(MyProfileState(myProfileModelObj: MyProfileModel()))..add(MyProfileInitialEvent())),
|
||||
BlocProvider<DiaryBloc>(create: (context) => sl<DiaryBloc>()..add(LoadDiary())),
|
||||
BlocProvider<ChatSelectBloc>(
|
||||
|
||||
Reference in New Issue
Block a user