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

73 Views Asked by At

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.

1

There are 1 best solutions below

2
Vladyslav Ulianytskyi On BEST ANSWER

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