forked from eatvio/eatvio_app
feat(feed): refactor creating post
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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,55 @@ class _FeedScreenState extends State<FeedScreen> {
|
||||
builder: (BuildContext context) {
|
||||
if (_selectedChipIndex == 0)
|
||||
return _buildAllBlogPosts();
|
||||
else
|
||||
else if (_selectedChipIndex == 1)
|
||||
return _buildAllRecipes();
|
||||
else
|
||||
return _buildDiets();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
_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(
|
||||
'0',
|
||||
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(
|
||||
'0',
|
||||
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,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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';
|
||||
@@ -36,6 +37,7 @@ Future<void> init() async {
|
||||
sl.registerFactory<ChatRoomCubit>(() => ChatRoomCubit(chatRepository: sl(), initializationCubit: sl()));
|
||||
sl.registerFactory<FeedCubit>(() => FeedCubit(feedRepository: sl()));
|
||||
sl.registerFactory<RecipesCubit>(() => RecipesCubit(feedRepository: 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()));
|
||||
|
||||
@@ -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