diff --git a/lib/features/blog_post_create/bloc/blog_post_create_cubit/blog_post_create_cubit.dart b/lib/features/blog_post_create/bloc/blog_post_create_cubit/blog_post_create_cubit.dart new file mode 100644 index 00000000..e66401f2 --- /dev/null +++ b/lib/features/blog_post_create/bloc/blog_post_create_cubit/blog_post_create_cubit.dart @@ -0,0 +1,28 @@ +import 'package:eatvio_app/features/blog_post_create/bloc/blog_post_create_cubit/blog_post_create_state.dart'; +import 'package:eatvio_app/features/blog_post_create/repositories/blog_post_repository.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_image_compress/flutter_image_compress.dart'; + +class BlogPostCreateCubit extends Cubit { + final BlogPostRepository blogPostRepository; + + BlogPostCreateCubit({ + required this.blogPostRepository, + }) : super(BlogPostCreateState()); + + createBlogPost({ + String? title, + String? youtubeURL, + String? description, + XFile? image, + }) async { + emit(BlogPostCreateState.loading()); + await blogPostRepository.createBlogPost( + title, + youtubeURL, + description, + image, + ); + emit(BlogPostCreateState.loaded()); + } +} diff --git a/lib/features/blog_post_create/bloc/blog_post_create_cubit/blog_post_create_state.dart b/lib/features/blog_post_create/bloc/blog_post_create_cubit/blog_post_create_state.dart new file mode 100644 index 00000000..05919499 --- /dev/null +++ b/lib/features/blog_post_create/bloc/blog_post_create_cubit/blog_post_create_state.dart @@ -0,0 +1,16 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'blog_post_create_state.freezed.dart'; + +@freezed +abstract class BlogPostCreateState with _$BlogPostCreateState { + const factory BlogPostCreateState() = _BlogPostCreateState; + + const factory BlogPostCreateState.loading() = BlogPostCreateStateLoading; + + const factory BlogPostCreateState.loaded() = BlogPostCreateStateLoaded; + + const factory BlogPostCreateState.error({ + required String errorMessage, + }) = BlogPostCreateStateError; +} diff --git a/lib/features/blog_post_create/bloc/blog_post_create_cubit/blog_post_create_state.freezed.dart b/lib/features/blog_post_create/bloc/blog_post_create_cubit/blog_post_create_state.freezed.dart new file mode 100644 index 00000000..d9a702c6 --- /dev/null +++ b/lib/features/blog_post_create/bloc/blog_post_create_cubit/blog_post_create_state.freezed.dart @@ -0,0 +1,608 @@ +// 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 'blog_post_create_state.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(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 _$BlogPostCreateState { + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function() loaded, + required TResult Function(String errorMessage) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function()? loaded, + TResult? Function(String errorMessage)? error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function()? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map( + TResult Function(_BlogPostCreateState value) $default, { + required TResult Function(BlogPostCreateStateLoading value) loading, + required TResult Function(BlogPostCreateStateLoaded value) loaded, + required TResult Function(BlogPostCreateStateError value) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_BlogPostCreateState value)? $default, { + TResult? Function(BlogPostCreateStateLoading value)? loading, + TResult? Function(BlogPostCreateStateLoaded value)? loaded, + TResult? Function(BlogPostCreateStateError value)? error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap( + TResult Function(_BlogPostCreateState value)? $default, { + TResult Function(BlogPostCreateStateLoading value)? loading, + TResult Function(BlogPostCreateStateLoaded value)? loaded, + TResult Function(BlogPostCreateStateError value)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $BlogPostCreateStateCopyWith<$Res> { + factory $BlogPostCreateStateCopyWith( + BlogPostCreateState value, $Res Function(BlogPostCreateState) then) = + _$BlogPostCreateStateCopyWithImpl<$Res, BlogPostCreateState>; +} + +/// @nodoc +class _$BlogPostCreateStateCopyWithImpl<$Res, $Val extends BlogPostCreateState> + implements $BlogPostCreateStateCopyWith<$Res> { + _$BlogPostCreateStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of BlogPostCreateState + /// with the given fields replaced by the non-null parameter values. +} + +/// @nodoc +abstract class _$$BlogPostCreateStateImplCopyWith<$Res> { + factory _$$BlogPostCreateStateImplCopyWith(_$BlogPostCreateStateImpl value, + $Res Function(_$BlogPostCreateStateImpl) then) = + __$$BlogPostCreateStateImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$BlogPostCreateStateImplCopyWithImpl<$Res> + extends _$BlogPostCreateStateCopyWithImpl<$Res, _$BlogPostCreateStateImpl> + implements _$$BlogPostCreateStateImplCopyWith<$Res> { + __$$BlogPostCreateStateImplCopyWithImpl(_$BlogPostCreateStateImpl _value, + $Res Function(_$BlogPostCreateStateImpl) _then) + : super(_value, _then); + + /// Create a copy of BlogPostCreateState + /// with the given fields replaced by the non-null parameter values. +} + +/// @nodoc + +class _$BlogPostCreateStateImpl implements _BlogPostCreateState { + const _$BlogPostCreateStateImpl(); + + @override + String toString() { + return 'BlogPostCreateState()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$BlogPostCreateStateImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function() loaded, + required TResult Function(String errorMessage) error, + }) { + return $default(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function()? loaded, + TResult? Function(String errorMessage)? error, + }) { + return $default?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function()? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if ($default != null) { + return $default(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_BlogPostCreateState value) $default, { + required TResult Function(BlogPostCreateStateLoading value) loading, + required TResult Function(BlogPostCreateStateLoaded value) loaded, + required TResult Function(BlogPostCreateStateError value) error, + }) { + return $default(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_BlogPostCreateState value)? $default, { + TResult? Function(BlogPostCreateStateLoading value)? loading, + TResult? Function(BlogPostCreateStateLoaded value)? loaded, + TResult? Function(BlogPostCreateStateError value)? error, + }) { + return $default?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_BlogPostCreateState value)? $default, { + TResult Function(BlogPostCreateStateLoading value)? loading, + TResult Function(BlogPostCreateStateLoaded value)? loaded, + TResult Function(BlogPostCreateStateError value)? error, + required TResult orElse(), + }) { + if ($default != null) { + return $default(this); + } + return orElse(); + } +} + +abstract class _BlogPostCreateState implements BlogPostCreateState { + const factory _BlogPostCreateState() = _$BlogPostCreateStateImpl; +} + +/// @nodoc +abstract class _$$BlogPostCreateStateLoadingImplCopyWith<$Res> { + factory _$$BlogPostCreateStateLoadingImplCopyWith( + _$BlogPostCreateStateLoadingImpl value, + $Res Function(_$BlogPostCreateStateLoadingImpl) then) = + __$$BlogPostCreateStateLoadingImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$BlogPostCreateStateLoadingImplCopyWithImpl<$Res> + extends _$BlogPostCreateStateCopyWithImpl<$Res, + _$BlogPostCreateStateLoadingImpl> + implements _$$BlogPostCreateStateLoadingImplCopyWith<$Res> { + __$$BlogPostCreateStateLoadingImplCopyWithImpl( + _$BlogPostCreateStateLoadingImpl _value, + $Res Function(_$BlogPostCreateStateLoadingImpl) _then) + : super(_value, _then); + + /// Create a copy of BlogPostCreateState + /// with the given fields replaced by the non-null parameter values. +} + +/// @nodoc + +class _$BlogPostCreateStateLoadingImpl implements BlogPostCreateStateLoading { + const _$BlogPostCreateStateLoadingImpl(); + + @override + String toString() { + return 'BlogPostCreateState.loading()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$BlogPostCreateStateLoadingImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function() loaded, + required TResult Function(String errorMessage) error, + }) { + return loading(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function()? loaded, + TResult? Function(String errorMessage)? error, + }) { + return loading?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function()? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if (loading != null) { + return loading(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_BlogPostCreateState value) $default, { + required TResult Function(BlogPostCreateStateLoading value) loading, + required TResult Function(BlogPostCreateStateLoaded value) loaded, + required TResult Function(BlogPostCreateStateError value) error, + }) { + return loading(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_BlogPostCreateState value)? $default, { + TResult? Function(BlogPostCreateStateLoading value)? loading, + TResult? Function(BlogPostCreateStateLoaded value)? loaded, + TResult? Function(BlogPostCreateStateError value)? error, + }) { + return loading?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_BlogPostCreateState value)? $default, { + TResult Function(BlogPostCreateStateLoading value)? loading, + TResult Function(BlogPostCreateStateLoaded value)? loaded, + TResult Function(BlogPostCreateStateError value)? error, + required TResult orElse(), + }) { + if (loading != null) { + return loading(this); + } + return orElse(); + } +} + +abstract class BlogPostCreateStateLoading implements BlogPostCreateState { + const factory BlogPostCreateStateLoading() = _$BlogPostCreateStateLoadingImpl; +} + +/// @nodoc +abstract class _$$BlogPostCreateStateLoadedImplCopyWith<$Res> { + factory _$$BlogPostCreateStateLoadedImplCopyWith( + _$BlogPostCreateStateLoadedImpl value, + $Res Function(_$BlogPostCreateStateLoadedImpl) then) = + __$$BlogPostCreateStateLoadedImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$BlogPostCreateStateLoadedImplCopyWithImpl<$Res> + extends _$BlogPostCreateStateCopyWithImpl<$Res, + _$BlogPostCreateStateLoadedImpl> + implements _$$BlogPostCreateStateLoadedImplCopyWith<$Res> { + __$$BlogPostCreateStateLoadedImplCopyWithImpl( + _$BlogPostCreateStateLoadedImpl _value, + $Res Function(_$BlogPostCreateStateLoadedImpl) _then) + : super(_value, _then); + + /// Create a copy of BlogPostCreateState + /// with the given fields replaced by the non-null parameter values. +} + +/// @nodoc + +class _$BlogPostCreateStateLoadedImpl implements BlogPostCreateStateLoaded { + const _$BlogPostCreateStateLoadedImpl(); + + @override + String toString() { + return 'BlogPostCreateState.loaded()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$BlogPostCreateStateLoadedImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function() loaded, + required TResult Function(String errorMessage) error, + }) { + return loaded(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function()? loaded, + TResult? Function(String errorMessage)? error, + }) { + return loaded?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function()? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if (loaded != null) { + return loaded(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_BlogPostCreateState value) $default, { + required TResult Function(BlogPostCreateStateLoading value) loading, + required TResult Function(BlogPostCreateStateLoaded value) loaded, + required TResult Function(BlogPostCreateStateError value) error, + }) { + return loaded(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_BlogPostCreateState value)? $default, { + TResult? Function(BlogPostCreateStateLoading value)? loading, + TResult? Function(BlogPostCreateStateLoaded value)? loaded, + TResult? Function(BlogPostCreateStateError value)? error, + }) { + return loaded?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_BlogPostCreateState value)? $default, { + TResult Function(BlogPostCreateStateLoading value)? loading, + TResult Function(BlogPostCreateStateLoaded value)? loaded, + TResult Function(BlogPostCreateStateError value)? error, + required TResult orElse(), + }) { + if (loaded != null) { + return loaded(this); + } + return orElse(); + } +} + +abstract class BlogPostCreateStateLoaded implements BlogPostCreateState { + const factory BlogPostCreateStateLoaded() = _$BlogPostCreateStateLoadedImpl; +} + +/// @nodoc +abstract class _$$BlogPostCreateStateErrorImplCopyWith<$Res> { + factory _$$BlogPostCreateStateErrorImplCopyWith( + _$BlogPostCreateStateErrorImpl value, + $Res Function(_$BlogPostCreateStateErrorImpl) then) = + __$$BlogPostCreateStateErrorImplCopyWithImpl<$Res>; + @useResult + $Res call({String errorMessage}); +} + +/// @nodoc +class __$$BlogPostCreateStateErrorImplCopyWithImpl<$Res> + extends _$BlogPostCreateStateCopyWithImpl<$Res, + _$BlogPostCreateStateErrorImpl> + implements _$$BlogPostCreateStateErrorImplCopyWith<$Res> { + __$$BlogPostCreateStateErrorImplCopyWithImpl( + _$BlogPostCreateStateErrorImpl _value, + $Res Function(_$BlogPostCreateStateErrorImpl) _then) + : super(_value, _then); + + /// Create a copy of BlogPostCreateState + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? errorMessage = null, + }) { + return _then(_$BlogPostCreateStateErrorImpl( + errorMessage: null == errorMessage + ? _value.errorMessage + : errorMessage // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc + +class _$BlogPostCreateStateErrorImpl implements BlogPostCreateStateError { + const _$BlogPostCreateStateErrorImpl({required this.errorMessage}); + + @override + final String errorMessage; + + @override + String toString() { + return 'BlogPostCreateState.error(errorMessage: $errorMessage)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$BlogPostCreateStateErrorImpl && + (identical(other.errorMessage, errorMessage) || + other.errorMessage == errorMessage)); + } + + @override + int get hashCode => Object.hash(runtimeType, errorMessage); + + /// Create a copy of BlogPostCreateState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$BlogPostCreateStateErrorImplCopyWith<_$BlogPostCreateStateErrorImpl> + get copyWith => __$$BlogPostCreateStateErrorImplCopyWithImpl< + _$BlogPostCreateStateErrorImpl>(this, _$identity); + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function() loaded, + required TResult Function(String errorMessage) error, + }) { + return error(errorMessage); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function()? loaded, + TResult? Function(String errorMessage)? error, + }) { + return error?.call(errorMessage); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function()? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(errorMessage); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_BlogPostCreateState value) $default, { + required TResult Function(BlogPostCreateStateLoading value) loading, + required TResult Function(BlogPostCreateStateLoaded value) loaded, + required TResult Function(BlogPostCreateStateError value) error, + }) { + return error(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_BlogPostCreateState value)? $default, { + TResult? Function(BlogPostCreateStateLoading value)? loading, + TResult? Function(BlogPostCreateStateLoaded value)? loaded, + TResult? Function(BlogPostCreateStateError value)? error, + }) { + return error?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_BlogPostCreateState value)? $default, { + TResult Function(BlogPostCreateStateLoading value)? loading, + TResult Function(BlogPostCreateStateLoaded value)? loaded, + TResult Function(BlogPostCreateStateError value)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(this); + } + return orElse(); + } +} + +abstract class BlogPostCreateStateError implements BlogPostCreateState { + const factory BlogPostCreateStateError({required final String errorMessage}) = + _$BlogPostCreateStateErrorImpl; + + String get errorMessage; + + /// Create a copy of BlogPostCreateState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + _$$BlogPostCreateStateErrorImplCopyWith<_$BlogPostCreateStateErrorImpl> + get copyWith => throw _privateConstructorUsedError; +} diff --git a/lib/features/blog_post_create/presentation/pages/blog_post_create_screen.dart b/lib/features/blog_post_create/presentation/pages/blog_post_create_screen.dart index d41a1967..c09cbf94 100644 --- a/lib/features/blog_post_create/presentation/pages/blog_post_create_screen.dart +++ b/lib/features/blog_post_create/presentation/pages/blog_post_create_screen.dart @@ -1,6 +1,8 @@ import 'dart:async'; import 'dart:io'; -import 'package:eatvio_app/old/feed/blog_post_create_screen/bloc/blog_post_create_bloc.dart'; +import 'package:eatvio_app/features/blog_post_create/bloc/blog_post_create_cubit/blog_post_create_cubit.dart'; +import 'package:eatvio_app/features/blog_post_create/bloc/blog_post_create_cubit/blog_post_create_state.dart'; +import 'package:eatvio_app/locator_service.dart'; import 'package:eatvio_app/theme/app_decoration.dart'; import 'package:eatvio_app/theme/theme_helper.dart'; import 'package:eatvio_app/widgets/custom_text_form_field.dart'; @@ -8,19 +10,27 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart'; +import 'package:go_router/go_router.dart'; import 'package:image_picker/image_picker.dart'; class BlogPostCreateScreen extends StatefulWidget { - const BlogPostCreateScreen({Key? key}) : super(key: key); + const BlogPostCreateScreen({ + Key? key, + }) : super(key: key); @override State createState() => _BlogPostCreateScreenState(); } class _BlogPostCreateScreenState extends State { - final blogPostCreateBloc = BlogPostCreateBloc(BlogPostCreateState())..add(BlogPostCreateInitialEvent()); + final blogPostCubit = sl(); bool shrinkImage = false; late StreamSubscription keyboardSubscription; + XFile? image; + final titleController = TextEditingController(); + final descriptionController = TextEditingController(); + final youtubeUrlController = TextEditingController(); + bool isLoading = false; @override void initState() { @@ -40,26 +50,15 @@ class _BlogPostCreateScreenState extends State { } Widget build(BuildContext context) { - return BlocProvider( - create: (BuildContext context) => blogPostCreateBloc, - child: BlocBuilder( - builder: (context, state) { - if (state is BlogPostCreateInitialState) { - // Это начальное состояние, данные ещё не загружены. - return Container( - color: Colors.white, - ); - } else if (state is BlogPostCreateLoadedState) { - // Данные загружены, можно строить экран. - return _buildBlogPostCreate(context, state); - } else if (state is BlogPostCreateErrorState) { - // Произошла ошибка при загрузке данных. - return Center(child: Text(state.errorMessage)); - } else { - // Другие состояния, если они есть. - return Container(); // Пустой контейнер для необработанных состояний. + return BlocProvider( + create: (BuildContext context) => blogPostCubit, + child: BlocListener( + listener: (BuildContext context, BlogPostCreateState state) { + if (state is BlogPostCreateStateLoaded) { + GoRouter.of(context).pop(); } }, + child: _buildBlogPostCreate(), ), ); } @@ -72,8 +71,8 @@ class _BlogPostCreateScreenState extends State { CupertinoActionSheetAction( onPressed: () async { final picker = ImagePicker(); - XFile? image = await picker.pickImage(source: ImageSource.camera); - if (image != null) blogPostCreateBloc.add(UploadImages(image)); + image = await picker.pickImage(source: ImageSource.camera); + setState(() {}); Navigator.of(context).pop(); }, child: const Row( @@ -87,8 +86,8 @@ class _BlogPostCreateScreenState extends State { CupertinoActionSheetAction( onPressed: () async { final picker = ImagePicker(); - XFile? image = await picker.pickImage(source: ImageSource.gallery); - if (image != null) blogPostCreateBloc.add(UploadImages(image)); + image = await picker.pickImage(source: ImageSource.gallery); + setState(() {}); Navigator.of(context).pop(); }, child: const Row( @@ -109,7 +108,7 @@ class _BlogPostCreateScreenState extends State { ); } - _buildBlogPostCreate(BuildContext context, BlogPostCreateLoadedState state) { + _buildBlogPostCreate() { return Scaffold( resizeToAvoidBottomInset: true, appBar: AppBar(), @@ -125,13 +124,27 @@ class _BlogPostCreateScreenState extends State { borderRadius: BorderRadius.circular(16), ), backgroundColor: appTheme.blueA400, - onPressed: () => _submitForm(context, state.title!.text, state.description!.text, state.youtubeURL!.text), - label: Text( - 'Создать', - style: TextStyle( - color: Colors.white, - ), - ), + label: isLoading + ? CircularProgressIndicator() + : Text( + 'Создать', + style: TextStyle( + color: Colors.white, + ), + ), + onPressed: isLoading + ? null + : () { + setState(() { + isLoading = true; + }); + blogPostCubit.createBlogPost( + title: titleController.text, + description: descriptionController.text, + youtubeURL: youtubeUrlController.text, + image: image, + ); + }, ), ), body: SingleChildScrollView( @@ -143,26 +156,26 @@ class _BlogPostCreateScreenState extends State { Text('Заголовок'), SizedBox(height: 8), CustomTextFormField( - controller: state.title, + controller: titleController, ), SizedBox(height: 16), Text('Описание'), SizedBox(height: 8), CustomTextFormField( - controller: state.description, + controller: descriptionController, maxLines: 6, minLines: 4, ), SizedBox(height: 16), - if (state.youtubeURL!.text.isEmpty) Text('Изображение поста'), - if (state.youtubeURL!.text.isEmpty) SizedBox(height: 8), - if (state.youtubeURL!.text.isEmpty) _buildAddPhoto(state), + if (youtubeUrlController.text.isEmpty) Text('Изображение поста'), + if (youtubeUrlController.text.isEmpty) SizedBox(height: 8), + if (youtubeUrlController.text.isEmpty) _buildAddPhoto(), SizedBox(height: 16), - if (state.image == null) Text('Ссылка на видео'), - if (state.image == null) SizedBox(height: 8), - if (state.image == null) + if (image == null) Text('Ссылка на видео'), + if (image == null) SizedBox(height: 8), + if (image == null) CustomTextFormField( - controller: state.youtubeURL, + controller: youtubeUrlController, ), SizedBox(height: 80), ], @@ -171,14 +184,14 @@ class _BlogPostCreateScreenState extends State { ); } - _buildAddPhoto(BlogPostCreateLoadedState state) { - bool isLoading = state.isLoading; - + _buildAddPhoto() { return GestureDetector( - onTap: addImage(context, isLoading), + onTap: () { + _showImagePicker(); + }, child: Stack( children: [ - if (state.image == null) + if (image == null) AnimatedContainer( height: shrinkImage ? 52 : 128, curve: Curves.easeIn, @@ -202,7 +215,7 @@ class _BlogPostCreateScreenState extends State { ], ), ), - if (state.image != null) + if (image != null) Container( width: shrinkImage ? 52 : MediaQuery.of(context).size.width - 32, child: ClipRRect( @@ -210,7 +223,7 @@ class _BlogPostCreateScreenState extends State { child: Image( image: FileImage( File( - state.image!.path, + image!.path, ), ), ), @@ -220,21 +233,4 @@ class _BlogPostCreateScreenState extends State { ), ); } - - addImage(BuildContext context, bool isLoading) { - if (!isLoading) { - return () { - _showImagePicker(); - }; - } - } -} - -_submitForm( - BuildContext context, - String title, - String description, - String youtubeURL, -) async { - context.read().add(CreateBlogPost()); } diff --git a/lib/features/blog_post_create/repositories/blog_post_repository.dart b/lib/features/blog_post_create/repositories/blog_post_repository.dart new file mode 100644 index 00000000..3c0e9c37 --- /dev/null +++ b/lib/features/blog_post_create/repositories/blog_post_repository.dart @@ -0,0 +1,32 @@ +import 'dart:io'; +import 'package:dio/dio.dart'; +import 'package:eatvio_app/core/image_compressing/image_compress_utility.dart'; +import 'package:eatvio_app/features/blog_post_create/services/blog_post_service.dart'; +import 'package:flutter_image_compress/flutter_image_compress.dart'; + +class BlogPostRepository { + final BlogPostService blogPostService; + + BlogPostRepository({ + required this.blogPostService, + }); + + Future createBlogPost( + String? title, + String? youtubeURL, + String? description, + XFile? image, + ) async { + FormData formData = FormData.fromMap({ + 'title': title, + 'description': description, + 'state': 'active', + 'youtube_url': youtubeURL, + 'image': image != null ? await MultipartFile.fromFile((await ImageCompressUtility.compressFile(File(image.path))).path, filename: image.name) : null, + }); + + return await blogPostService.createBlogPost( + formData: formData, + ); + } +} diff --git a/lib/features/blog_post_create/repositories/blog_repository.dart b/lib/features/blog_post_create/repositories/blog_repository.dart deleted file mode 100644 index e69de29b..00000000 diff --git a/lib/features/blog_post_create/services/blog_post_service.dart b/lib/features/blog_post_create/services/blog_post_service.dart index 33524124..8d09a84e 100644 --- a/lib/features/blog_post_create/services/blog_post_service.dart +++ b/lib/features/blog_post_create/services/blog_post_service.dart @@ -9,11 +9,7 @@ abstract class BlogPostService { @POST('/api/blogPosts/create') @MultiPart() - Future sendMessage({ - @Path() String? title, - @Path() required String state, - @Path() String? description, - @Part() String? youtube_url, - @Part(name: 'image', contentType: 'multipart/form-data') List? media_data, + Future createBlogPost({ + @Body() required FormData formData, }); } diff --git a/lib/features/blog_post_create/services/blog_post_service.g.dart b/lib/features/blog_post_create/services/blog_post_service.g.dart index b104b16e..de8f722f 100644 --- a/lib/features/blog_post_create/services/blog_post_service.g.dart +++ b/lib/features/blog_post_create/services/blog_post_service.g.dart @@ -22,27 +22,11 @@ class _BlogPostService implements BlogPostService { final ParseErrorLogger? errorLogger; @override - Future sendMessage({ - String? title, - required String state, - String? description, - String? youtube_url, - List? media_data, - }) async { + Future createBlogPost({required FormData formData}) async { final _extra = {}; final queryParameters = {}; - queryParameters.removeWhere((k, v) => v == null); final _headers = {}; - final _data = FormData(); - if (youtube_url != null) { - _data.fields.add(MapEntry( - 'youtube_url', - youtube_url, - )); - } - if (media_data != null) { - _data.files.addAll(media_data.map((i) => MapEntry('image', i))); - } + final _data = formData; final _options = _setStreamType(Options( method: 'POST', headers: _headers, diff --git a/lib/locator_service.dart b/lib/locator_service.dart index 8afebb45..cd75ebcc 100644 --- a/lib/locator_service.dart +++ b/lib/locator_service.dart @@ -3,6 +3,9 @@ import 'package:eatvio_app/core/const.dart'; import 'package:eatvio_app/core/data/diet/repositories/diet_repository.dart'; import 'package:eatvio_app/core/data/diet/services/diet_service.dart'; import 'package:eatvio_app/core/initialization_cubit/initialization_cubit.dart'; +import 'package:eatvio_app/features/blog_post_create/bloc/blog_post_create_cubit/blog_post_create_cubit.dart'; +import 'package:eatvio_app/features/blog_post_create/repositories/blog_post_repository.dart'; +import 'package:eatvio_app/features/blog_post_create/services/blog_post_service.dart'; import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/new_messages_cubit/new_messages_cubit.dart'; import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_cubit.dart'; import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/profile_avatar_cubit/profile_avatar_cubit.dart'; @@ -70,6 +73,7 @@ Future init() async { sl.registerFactory(() => RegisterConsultantCubit(consultantRepository: sl())); sl.registerFactory(() => DiaryCubit(diaryRepository: sl(), glossaryRepository: sl())); sl.registerFactory(() => AboutDietCubit(dietsRepository: sl())); + sl.registerFactory(() => BlogPostCreateCubit(blogPostRepository: sl())); // Repository sl.registerLazySingleton(() => ChatRepository(chatService: sl())); @@ -84,6 +88,7 @@ Future init() async { sl.registerLazySingleton(() => DiaryRepository(diaryService: sl())); sl.registerLazySingleton(() => GlossaryRepository(glossaryService: sl())); sl.registerLazySingleton(() => DietRepository(dietsService: sl())); + sl.registerLazySingleton(() => BlogPostRepository(blogPostService: sl())); // Services sl.registerLazySingleton(() => ChatService(sl())); @@ -98,6 +103,7 @@ Future init() async { sl.registerLazySingleton(() => DiaryService(sl())); sl.registerLazySingleton(() => GlossaryService(sl())); sl.registerLazySingleton(() => DietService(sl())); + sl.registerLazySingleton(() => BlogPostService(sl())); // External sl.registerLazySingleton(