skip to Main Content

I have to sort items of a class created with @freezed annotation. I have added Comparable interface to the signature. It is causing following compile time exception:

Error (Xcode): lib/models/app_language.freezed.dart:143:7: Error: The
non-abstract class ‘_$_AppLanguage’ is missing implementations for
these members:

Could not build the application for the simulator.

// app_language.dart

import 'package:freezed_annotation/freezed_annotation.dart';

part 'app_language.freezed.dart';
part 'app_language.g.dart';

@freezed
class AppLanguage with _$AppLanguage implements Comparable<AppLanguage> {
  const factory AppLanguage({
    @Default("en") String id,
    String? name,
    String? msg,
    @Default([0, 0, 0, 0]) List<int> color,
    @Default(false) bool rtl,
  }) = _AppLanguage;

  factory AppLanguage.fromJson(Map<String, dynamic> json) =>
      _$AppLanguageFromJson(json);

  @override
  int compareTo(AppLanguage other) {
    if (rtl == other.rtl) {
      if (name != null && other.name != null) {
        return name!.compareTo(other.name!);
      } else if (name == null && other.name == null) {
        return 0;
      } else if (name != null) {
        return 1;
      } else {
        return -1;
      }
    } else {
      return rtl ? 1 : -1;
    }
  }
}

pubspec.yaml (snippet)

dependencies:
  freezed: ^2.3.2
  freezed_annotation: ^2.2.0
dev_dependencies:
  build_runner: ^2.3.3
  json_serializable: ^6.6.0

usage

// here value is list of AppLanguages and I am returning another sorted list.
return <AppLanguage>[...value]..sort();

How do I resolve compilation error? Any help will be appreciated.

Right now,
I have added separate comparator so that it could work. But having the model class implements the Comparable is desired.

import 'package:freezed_annotation/freezed_annotation.dart';

import '../localization/localization.dart';

part 'app_language.freezed.dart';
part 'app_language.g.dart';

@freezed
class AppLanguage with _$AppLanguage {
  const factory AppLanguage({
    @Default(localeDefault) String id,
    String? name,
    String? msg,
    @Default([0, 0, 0, 0]) List<int> color,
    @Default(false) bool rtl,
  }) = _AppLanguage;

  factory AppLanguage.fromJson(Map<String, dynamic> json) =>
      _$AppLanguageFromJson(json);

  // @override
  // // ignore: library_private_types_in_public_api
  // int compareTo(_$_AppLanguage other) {
  //   if (rtl == other.rtl) {
  //     if (name != null && other.name != null) {
  //       return name!.compareTo(other.name!);
  //     } else if (name == null && other.name == null) {
  //       return 0;
  //     } else if (name != null) {
  //       return 1;
  //     } else {
  //       return -1;
  //     }
  //   } else {
  //     return rtl ? 1 : -1;
  //   }
  // }
}

int appLanguageComparator(AppLanguage a, AppLanguage b) {
  if (a.rtl == b.rtl) {
    final aName = a.name;
    final bName = b.name;
    if (aName != null && bName != null) {
      return aName.compareTo(bName);
    } else if (aName == null && bName == null) {
      return 0;
    } else if (aName != null) {
      return 1;
    } else {
      return -1;
    }
  } else {
    return a.rtl ? 1 : -1;
  }
}

Usage:

return <AppLanguage>[...value]..sort(appLanguageComparator);

2

Answers


  1. For others that will encounter the same issue in the future, in order to add custom methods/getters etc to a freezed class you need to provide a empty const constructor. For example:

    @freezed
    class Person with _$Person {
      const factory Person(String name, {int? age}) = _Person;
    
      void method() {
        print('hello world');
      }
    }
    

    This implementation will throw a compile error and in order to make it work you need to do:

    @freezed
    class Person with _$Person {
      // Added constructor. Must not have any parameter
      const Person._();
    
      const factory Person(String name, {int? age}) = _Person;
    
      void method() {
        print('hello world');
      }
    }
    

    Keep in mind, the constructor must be an empty constructor.

    Login or Signup to reply.
  2. You have to extend the class with Comparable<AppLanguage> and should override compareTo with parameter of AppLanguage as following

    import 'package:freezed_annotation/freezed_annotation.dart';
    
    import '../localization/localization.dart';
    
    part 'app_language.freezed.dart';
    part 'app_language.g.dart';
    
    @freezed
    class AppLanguage extends Comparable<AppLanguage> with _$AppLanguage {
      const factory AppLanguage({
        @Default(localeDefault) String id,
        String? name,
        String? msg,
        @Default([0, 0, 0, 0]) List<int> color,
        @Default(false) bool rtl,
      }) = _AppLanguage;
    
      factory AppLanguage.fromJson(Map<String, dynamic> json) =>
          _$AppLanguageFromJson(json);
    
      
     @override
     int compareTo(AppLanguage other) {
       if (rtl == other.rtl) {
         if (name != null && other.name != null) {
           return name!.compareTo(other.name!);
         } else if (name == null && other.name == null) {
           return 0;
         } else if (name != null) {
           return 1;
         } else {
           return -1;
         }
       } else {
         return rtl ? 1 : -1;
       }
     }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search