flutterdartunhandled-exception

Flutter: Unhandled Exception: type 'Mood' is not a subtype of type 'MoodType'


I'm a beginner programmer trying to create a mental health app. In Calendar screen you can press on a date and you're forwarded to Journal Entry screen where you can select a mood in a DropdownButtonFormField and write a journal entry in a TextFormField. When I select a mood I get an error [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: type 'Mood' is not a subtype of type 'MoodType'. What is the problem and how can I resolve it?

Here's a full error log: Restarted application in 801ms. I/zygote (15437): Do partial code cache collection, code=61KB, data=53KB I/zygote (15437): After code cache collection, code=61KB, data=53KB I/zygote (15437): Increasing code cache capacity to 256KB I/flutter (15437): Selected date: 2023-05-03 00:00:00.000 E/flutter (15437): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: type 'Mood' is not a subtype of type 'MoodType' E/flutter (15437): #0 _JournalEntryScreenState.build.. (package:v1/journal_entry.dart:137:21) E/flutter (15437): #1 State.setState (package:flutter/src/widgets/framework.dart:1133:30) E/flutter (15437): #2 _JournalEntryScreenState.build. (package:v1/journal_entry.dart:136:19) E/flutter (15437): #3 _DropdownButtonFormFieldState.didChange (package:flutter/src/material/dropdown.dart:1686:39) E/flutter (15437): #4 _DropdownButtonState._handleTap. (package:flutter/src/material/dropdown.dart:1325:25) E/flutter (15437): E/flutter (15437):


**journal_entry.dart:**
import 'package:flutter/material.dart';
import 'db_helper.dart';
import 'event_interface.dart';
import 'package:intl/intl.dart';
import 'mood_type.dart';
class JournalEntry extends StatefulWidget implements EventInterface {

  final int id;
  @required final DateTime date;
  final MoodType mood;
  final String entry;

  JournalEntry({this.id, @required this.date, @required this.mood, this.entry});

  @override
  DateTime get eventDate => date;

  Map<String, dynamic> toMap() {
    return {
      'id': id,
      'date': date?.millisecondsSinceEpoch ?? 0,
      'mood': mood?.index ?? 0,
      'entry': entry,
    };
  }

  static JournalEntry fromMap(Map<String, dynamic> map) {
    return JournalEntry(
      id: map['id'],
      date: DateTime.fromMillisecondsSinceEpoch(map['date']),
      mood: MoodType.values[map['mood']],
      entry: map['entry'],
    );
  }
  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
          other is JournalEntry &&
              runtimeType == other.runtimeType &&
              id == other.id &&
              date == other.date &&
              mood == other.mood &&
              entry == other.entry;

  @override
  int get hashCode =>
      id.hashCode ^ date.hashCode ^ mood.hashCode ^ entry.hashCode;

  @override
  _JournalEntryState createState() => _JournalEntryState();
}

class _JournalEntryState extends State<JournalEntry> {

  @override
  Widget build(BuildContext context) {
    throw UnimplementedError();
  }
}

class JournalEntryScreen extends StatefulWidget {

  final DateTime selectedDate;

  JournalEntryScreen({Key key, this.selectedDate}) : super(key: key);

  @override
  _JournalEntryScreenState createState() => _JournalEntryScreenState();
}

class _JournalEntryScreenState extends State<JournalEntryScreen> {
  DateTime _selectedDate;
  final _formKey = GlobalKey<FormState>();
  TextEditingController _journalEntryController = TextEditingController();
  String _journalEntry = '';
  MoodType _selectedMood;

  @override
  void initState() {
    super.initState();
    _selectedDate = widget.selectedDate ?? DateTime.now();
    _getJournalEntry(_selectedDate);
  }

  void _getJournalEntry(DateTime date) async {
    DatabaseHelper databaseHelper = DatabaseHelper.instance;

    List<JournalEntry> entries =
    await databaseHelper.getJournalEntryByDate(date);
    if (entries != null && entries.isNotEmpty) {
      JournalEntry entry = entries.first;
      print('Retrieved journal entry for date: ${entry.date}');
      setState(() {
        _journalEntry = entry.entry;
        _selectedDate = entry.date;
        _selectedMood = entry.mood;
        print('Selected date updated to: $_selectedDate');
      });
      print('Set state for date: $_selectedDate and journal entry: $_journalEntry');
      _journalEntryController.text = _journalEntry;
    }
  }

  @override
  Widget build(BuildContext context) {

    return Scaffold(
      appBar: AppBar(
        title: Text('Journal Entry'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Form(
          key: _formKey,
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                DateFormat.yMMMMd().format(widget.selectedDate ?? DateTime.now()),
                style: TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold),
              ),
              SizedBox(height: 16.0),
              DropdownButtonFormField(
                value: _selectedMood,
                hint: Text('Select a mood'),
                items: moodMap.values
                    .map((mood) => DropdownMenuItem(
                  value: mood,
                  child: Text(mood.name),
                ))
                    .toList(),
                onChanged: (value) {
                  setState(() {
                    _selectedMood = value;
                  });
                },
                validator: (value) {
                  if (value == null) {
                    return 'Please select a mood';
                  }
                  return null;
                },
              ),
              TextFormField(
                controller: _journalEntryController,
                decoration: InputDecoration(
                  hintText: 'Write your journal entry here',
                  border: OutlineInputBorder(),
                ),
                maxLines: null,
                onChanged: (value) {
                  setState(() {
                    _journalEntry = value;
                  });
                },
                validator: (value) {
                  if (value.isEmpty) {
                    return 'Please enter some text';
                  }
                  return null;
                },
              ),
              SizedBox(height: 16.0),
              ElevatedButton(
                onPressed: () async {
                  if (_formKey.currentState.validate()) {
                    JournalEntry entry = JournalEntry(
                      date: widget.selectedDate,
                      mood: _selectedMood,
                      entry: _journalEntry,
                    );
                    DatabaseHelper databaseHelper = DatabaseHelper.instance;
                    int id = await databaseHelper.insertJournalEntry(entry);
                    Navigator.pop(context, true);
                  }
                },
                child: Text('Save'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

**mood_type.dart:**
import 'dart:ui';
import 'package:flutter/material.dart';

enum MoodType {
  veryHappy,
  happy,
  neutral,
  sad,
  verySad
}

class Mood {
  final String name;
  final Color color;
  final MoodType type;

  Mood({this.name, this.color, this.type});
}

final moodMap = {
  MoodType.veryHappy: Mood(name: 'Very Happy', color: Colors.green, type: MoodType.veryHappy),
  MoodType.happy: Mood(name: 'Happy', color: Colors.lightGreen, type: MoodType.happy),
  MoodType.neutral: Mood(name: 'Neutral', color: Colors.grey, type: MoodType.neutral),
  MoodType.sad: Mood(name: 'Sad', color: Colors.blue, type: MoodType.sad),
  MoodType.verySad: Mood(name: 'Very Sad', color: Colors.black87, type: MoodType.verySad),
};

I can also add calendar_screen.dart and db_helper.dart if it's needed for the reproduction of the error.

I've tried to refactor the code to use MoodType type instead of mood and tried implementing MoodType to the class Mood, but I feel completely stuck.


Solution

  • Your dropdown is based on Mood but your _selectedMood is a MoodType. In the onchanged you try to assign a Mood to a MoodType. Try changing

                onChanged: (value) {
                  setState(() {
                    _selectedMood = value;
                  });
                },
    

    to

                onChanged: (value) {
                  setState(() {
                    _selectedMood = value.type;
                  });
                },
    

    and I believe a similar mistake is done at the items. I think

                items: moodMap.values
                    .map((mood) => DropdownMenuItem(
                  value: mood,
                  child: Text(mood.name),
                ))
    

    needs to be

                items: moodMap.values
                    .map((mood) => DropdownMenuItem(
                  value: mood.type,
                  child: Text(mood.name),
                ))