Enums don't work - Unknown type
Honestly can't figure this out and your docs really aren't clear. Dart mappable is continuously saying it doesn't know what my enum is when I try to run UserSettings.toMap
User settings immediately before map
I've tried BOTH ValuesMode.indexed and ValuesMode.named, no difference
It's as if by using @MappableField on my enum field it's not making the link between the declared MappableEnum in the Enum file and it's trying to use a different map but can't find anything
If I don't include @MappableField above UserSettings.currentFocusFilter then the code generation adds FieldMode.member and ignores it entirely and doesn't serialise it
DEFINITIONS
I have a class defined as below with an enum field FocusFilter
@MappableClass()
class UserSettings with UserSettingsMappable {
@MappableField(hook: UserSettingsStateDateChoiceHook())
UserSettingsStateDateChoice currentFocusDate = UserSettingsStateDateChoice(DateTime.now(), false);
@MappableField()
FocusFilter currentFocusFilter = FocusFilter.all;
@MappableField()
bool hideStreaks = false;
@MappableField()
bool hideFocusRings = false;
@MappableField()
bool focusWallShowDates = false;
@MappableField()
FocusWallStyleTypeEnum focusWallStyleType = FocusWallStyleTypeEnum.bulletJournal;
@MappableField()
PlanType? planType = PlanType.free;
List<OnboardingQuestionnaireAreas> onboardingQuestionnaireAnswers = [];
@MappableField()
bool thankYouSheetDisplayed = false;
@MappableField()
int maxFocusCount = 3;
}
My enum is defined as
part 'focus_filter_enum.mapper.dart';
@MappableEnum()
enum FocusFilter { all, monthly, weekly, daily, uncompleted }
I've ran build_runner, which has produced the following for UserSettings and FocusFilter, there's extra code below because I've removed the excess fields in UserSettings
USER SETTINGS GENERATED CODE
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, unnecessary_cast, override_on_non_overriding_member
// ignore_for_file: strict_raw_type, inference_failure_on_untyped_parameter
part of 'user_settings.dart';
class UserSettingsMapper extends ClassMapperBase<UserSettings> {
UserSettingsMapper._();
static UserSettingsMapper? _instance;
static UserSettingsMapper ensureInitialized() {
if (_instance == null) {
MapperContainer.globals.use(_instance = UserSettingsMapper._());
}
return _instance!;
}
@override
final String id = 'UserSettings';
static UserSettingsStateDateChoice _$currentFocusDate(UserSettings v) =>
v.currentFocusDate;
static const Field<UserSettings, UserSettingsStateDateChoice>
_f$currentFocusDate = Field('currentFocusDate', _$currentFocusDate,
hook: UserSettingsStateDateChoiceHook());
static FocusFilter _$currentFocusFilter(UserSettings v) =>
v.currentFocusFilter;
static const Field<UserSettings, FocusFilter> _f$currentFocusFilter =
Field('currentFocusFilter', _$currentFocusFilter);
static bool _$hideStreaks(UserSettings v) => v.hideStreaks;
static const Field<UserSettings, bool> _f$hideStreaks =
Field('hideStreaks', _$hideStreaks);
static bool _$hideFocusRings(UserSettings v) => v.hideFocusRings;
static const Field<UserSettings, bool> _f$hideFocusRings =
Field('hideFocusRings', _$hideFocusRings);
static bool _$focusWallShowDates(UserSettings v) => v.focusWallShowDates;
static const Field<UserSettings, bool> _f$focusWallShowDates =
Field('focusWallShowDates', _$focusWallShowDates);
static FocusWallStyleTypeEnum _$focusWallStyleType(UserSettings v) =>
v.focusWallStyleType;
static const Field<UserSettings, FocusWallStyleTypeEnum>
_f$focusWallStyleType = Field('focusWallStyleType', _$focusWallStyleType);
static PlanType? _$planType(UserSettings v) => v.planType;
static const Field<UserSettings, PlanType> _f$planType =
Field('planType', _$planType);
static List<OnboardingQuestionnaireAreas> _$onboardingQuestionnaireAnswers(
UserSettings v) =>
v.onboardingQuestionnaireAnswers;
static const Field<UserSettings, List<OnboardingQuestionnaireAreas>>
_f$onboardingQuestionnaireAnswers = Field(
'onboardingQuestionnaireAnswers', _$onboardingQuestionnaireAnswers,
mode: FieldMode.member);
static bool _$thankYouSheetDisplayed(UserSettings v) =>
v.thankYouSheetDisplayed;
static const Field<UserSettings, bool> _f$thankYouSheetDisplayed =
Field('thankYouSheetDisplayed', _$thankYouSheetDisplayed);
static int _$maxFocusCount(UserSettings v) => v.maxFocusCount;
static const Field<UserSettings, int> _f$maxFocusCount =
Field('maxFocusCount', _$maxFocusCount);
@override
final MappableFields<UserSettings> fields = const {
#currentFocusDate: _f$currentFocusDate,
#currentFocusFilter: _f$currentFocusFilter,
#hideStreaks: _f$hideStreaks,
#hideFocusRings: _f$hideFocusRings,
#focusWallShowDates: _f$focusWallShowDates,
#focusWallStyleType: _f$focusWallStyleType,
#planType: _f$planType,
#onboardingQuestionnaireAnswers: _f$onboardingQuestionnaireAnswers,
#thankYouSheetDisplayed: _f$thankYouSheetDisplayed,
#maxFocusCount: _f$maxFocusCount,
};
static UserSettings _instantiate(DecodingData data) {
return UserSettings();
}
@override
final Function instantiate = _instantiate;
static UserSettings fromMap(Map<String, dynamic> map) {
return ensureInitialized().decodeMap<UserSettings>(map);
}
static UserSettings fromJson(String json) {
return ensureInitialized().decodeJson<UserSettings>(json);
}
}
mixin UserSettingsMappable {
String toJson() {
return UserSettingsMapper.ensureInitialized()
.encodeJson<UserSettings>(this as UserSettings);
}
Map<String, dynamic> toMap() {
return UserSettingsMapper.ensureInitialized()
.encodeMap<UserSettings>(this as UserSettings);
}
UserSettingsCopyWith<UserSettings, UserSettings, UserSettings> get copyWith =>
_UserSettingsCopyWithImpl(this as UserSettings, $identity, $identity);
@override
String toString() {
return UserSettingsMapper.ensureInitialized()
.stringifyValue(this as UserSettings);
}
@override
bool operator ==(Object other) {
return UserSettingsMapper.ensureInitialized()
.equalsValue(this as UserSettings, other);
}
@override
int get hashCode {
return UserSettingsMapper.ensureInitialized()
.hashValue(this as UserSettings);
}
}
extension UserSettingsValueCopy<$R, $Out>
on ObjectCopyWith<$R, UserSettings, $Out> {
UserSettingsCopyWith<$R, UserSettings, $Out> get $asUserSettings =>
$base.as((v, t, t2) => _UserSettingsCopyWithImpl(v, t, t2));
}
abstract class UserSettingsCopyWith<$R, $In extends UserSettings, $Out>
implements ClassCopyWith<$R, $In, $Out> {
$R call();
UserSettingsCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t);
}
class _UserSettingsCopyWithImpl<$R, $Out>
extends ClassCopyWithBase<$R, UserSettings, $Out>
implements UserSettingsCopyWith<$R, UserSettings, $Out> {
_UserSettingsCopyWithImpl(super.value, super.then, super.then2);
@override
late final ClassMapperBase<UserSettings> $mapper =
UserSettingsMapper.ensureInitialized();
@override
$R call() => $apply(FieldCopyWithData({}));
@override
UserSettings $make(CopyWithData data) => UserSettings();
@override
UserSettingsCopyWith<$R2, UserSettings, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t) =>
_UserSettingsCopyWithImpl($value, $cast, t);
}
FOCUS FILTER GENERATED CODE
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, unnecessary_cast, override_on_non_overriding_member
// ignore_for_file: strict_raw_type, inference_failure_on_untyped_parameter
part of 'focus_filter_enum.dart';
class FocusFilterMapper extends EnumMapper<FocusFilter> {
FocusFilterMapper._();
static FocusFilterMapper? _instance;
static FocusFilterMapper ensureInitialized() {
if (_instance == null) {
MapperContainer.globals.use(_instance = FocusFilterMapper._());
}
return _instance!;
}
static FocusFilter fromValue(dynamic value) {
ensureInitialized();
return MapperContainer.globals.fromValue(value);
}
@override
FocusFilter decode(dynamic value) {
switch (value) {
case 'all':
return FocusFilter.all;
case 'monthly':
return FocusFilter.monthly;
case 'weekly':
return FocusFilter.weekly;
case 'daily':
return FocusFilter.daily;
case 'uncompleted':
return FocusFilter.uncompleted;
default:
throw MapperException.unknownEnumValue(value);
}
}
@override
dynamic encode(FocusFilter self) {
switch (self) {
case FocusFilter.all:
return 'all';
case FocusFilter.monthly:
return 'monthly';
case FocusFilter.weekly:
return 'weekly';
case FocusFilter.daily:
return 'daily';
case FocusFilter.uncompleted:
return 'uncompleted';
}
}
}
extension FocusFilterMapperExtension on FocusFilter {
String toValue() {
FocusFilterMapper.ensureInitialized();
return MapperContainer.globals.toValue<FocusFilter>(this) as String;
}
}
Seriously why is this a thing and a requirement when I've stated that the indexed version of the enum should be used
And if it's an absolute hard requirement why on earth isn't it mentioned in the docs?
Makes no difference actually, still fails regardless
You need to add a constructor to UserSettings
Though this still might be a bug that the builder doesn't pick up the enum mapper.
Same here, but perhaps for another reason:
I have this mapper to map enums that I don't own:
final class CustomEnumMapper<T extends Enum> extends EnumMapper<T> {
const CustomEnumMapper({required this.enumValues});
final List<T> enumValues;
@override
T decode(Object value) {
if (value is! String) {
throw MapperException.unexpectedType(
value.runtimeType,
(String).runtimeType.toString(),
);
}
return enumValues.firstWhere((v) => v.name == value);
}
@override
Object? encode(T self) {
return self.name;
}
}
Then, I use this on main:
MapperContainer.globals.useAll([
const BoolMapper(), // 0 or 1
const ColorMapper(), // Color to #Hex
const DateMapper(), // A const Date class
CustomEnumMapper(enumValues: ThemeMode.values),
CustomEnumMapper(enumValues: DynamicSchemeVariant.values),
]);
When I try to serialize/deserialize something with ThemeMode, I get the same exception.
Debugging the code where the mapper is taken from _mappers (mapper_container.dart, line 300), I see only one CustomEnumMapper:
So, I guess it is overriding the CustomEnumMapper and only the last one added remains.
EDIT:
After making the CustomEnumMapper abstract and adding those:
final class ThemeModeEnumMapper extends CustomEnumMapper<ThemeMode> {
const ThemeModeEnumMapper() : super(enumValues: ThemeMode.values);
}
final class DynamicSchemeVariantEnumMapper
extends CustomEnumMapper<DynamicSchemeVariant> {
const DynamicSchemeVariantEnumMapper()
: super(enumValues: DynamicSchemeVariant.values);
}
Now, the correct mappers are added: