flutterdartflutter-stateflutter-freezed

not able to use copyWith method in when creating a cubit and using freezed


I am creating a cubit. However, after running the build_runner command, the copyWith() method is not being generated. My search_cubit.dart file:

import 'package:book_ai/domain/book/book.dart';
import 'package:book_ai/domain/book/i_book_repository.dart';
import 'package:book_ai/domain/search/search_failure.dart';
import 'package:book_ai/domain/search/value_objects.dart';
import 'package:dartz/dartz.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:injectable/injectable.dart';

part 'search_cubit.freezed.dart';
part 'search_state.dart';

@injectable
class SearchCubit extends Cubit<SearchState> {
  final IBookRepository _bookRepository;

  SearchCubit(this._bookRepository) : super(SearchState.initial());

  void updateSearchQuery(String typedQuery) {
    emit(state.copyWith(
      searchQuery: SearchQuery(typedQuery),
      searchFailureOrSuccessOption: none(),
    ));
  }

  Future<void> search() async {
    emit(state.copyWith(isSubmitting: true));

    final possibleFailure =
        await _bookRepository.get(state.searchQuery.getOrCrash());

    emit(possibleFailure.fold(
      (failure) {
        failure.maybeWhen(
            unexpected: () => emit(
                  state.copyWith(
                    isSubmitting: false,
                    searchFailureOrSuccessOption: some(
                      left(
                        const SearchFailure.otherFailure('unknown'),
                      ),
                    ),
                  ),
                ),
            orElse: () => const SearchFailure.serverError());
      },
      (books) => SearchState.searchSuccess(books),
    ));

    // emit(state.copyWith(
    //   isSubmitting: false,
    //   searchFailureOrSuccessOption: optionOf(result),
    // ));
  }
}

My search_state.dart file:

part of 'search_cubit.dart';

@freezed
class SearchState with _$SearchState {
  const factory SearchState({
    required SearchQuery searchQuery,
    required bool isSubmitting,
    required Option<Either<SearchFailure, Unit>> searchFailureOrSuccessOption,
  }) = _SearchState;

  const SearchState._();

  const factory SearchState.initial() = _Initial;
  const factory SearchState.loading() = _Loading;
  const factory SearchState.searchFailure(SearchFailure failure) =
      _SearchFailure;
  const factory SearchState.searchSuccess(List<Book> books) = _SearchSuccess;
}

I tried modifying the search_state.dart file to explicitly define the SearchState.initial() like this:

factory SearchState.initial() => SearchState(
      searchQuery: SearchQuery(''),
      isSubmitting: false,
      searchFailureOrSuccessOption: none());

while removing the other states. In this case, the copyWith method works. However, I want to be able to use the other states too.


Solution

  • If you want have multiple states and then to be able use copyWith() you should explicitly cast to state that has params in the constructor.

    @freezed
    class SearchState with _$SearchState {
      const SearchState._();
    
      const factory SearchState.initial() = _Initial;
    
      const factory SearchState.loading() = _Loading;
    
      const factory SearchState.searching({
        required SearchQuery searchQuery,
        required Option<Either<SearchFailure, Unit>> searchFailureOrSuccessOption,
        @Default(false) bool isSubmitting,
      }) = Searching;
    
      const factory SearchState.searchFailure(SearchFailure failure) = SearchFailure;
    
      const factory SearchState.searchSuccess(List<Book> books) = SearchSuccess;
    }
    

    and then

      void updateSearchQuery(String typedQuery) {
        if (state is Searching) {
          emit(
            (state as Searching).copyWith(
              searchQuery: SearchQuery(typedQuery),
              searchFailureOrSuccessOption: none(),
            ),
          );
      }
    

    then in screen:

    @override
      Widget build(BuildContext context) => BlocBuilder<SearchCubit, SearchState>(
            builder: (context, state) => state.when(
              initial: () => const SizedBox(),
              loading: () => ProgressLoader()
              searching: (ages, searchFailureOrSuccessOption, isSubmitting) => Container(..)
        ...
    

    more info freezed