Skip to content

Flutter app crashing with no error message or exceptions #119016

Closed
@CookieWookiee321

Description

@CookieWookiee321

I'm building a Flutter app primarily for use on desktop. The issue comes up when a particular method, _saveReportSync, is called when interacting with a particular textfield. The method in question takes the present text, formats it, and saves it to an Isar database. After that, it called up a message with ScaffoldMessenger.

The crash seems to happen after the method completes and when the textfield would ordinarily regain focus. The only message I get from the Debug Console is Lost connection to device. Exited (sigterm).

Steps to Reproduce

  1. Execute flutter run on the code sample (must be on desktop)
  2. Initiate the method by pressing CTRL+S with the textfield in focus

Expected results: The text should be formatted, and a message should appear saying this report has been saved to the database.

Actual results: The text is formatted and then the program crashes shortly after

Code sample
import 'dart:ui';

import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_speed_dial/flutter_speed_dial.dart';
import 'package:lesson_companion/controllers/companion_methods.dart';
import 'package:lesson_companion/controllers/text_mode_input_controller.dart';
import 'package:lesson_companion/models/database.dart';
import 'package:lesson_companion/models/dictionary/look_up.dart';
import 'package:lesson_companion/models/lesson.dart';
import 'package:lesson_companion/models/report.dart';
import 'package:lesson_companion/models/student.dart';
import 'package:lesson_companion/views/dialogs/lookups/new_language_look_up.dart';
import 'package:lesson_companion/views/main_windows/pdf_preview.dart';

import '../../controllers/styling/companion_lexer.dart';

//TODO: saving crashes the app

final _template = """=<
@ Name


@ Date
-\t${CompanionMethods.getShortDate(DateTime.now())}

@ Topic


@ New Language


@ Pronunciation


@ Corrections

>=""";

final _nonAutoRowStartKeys = [
  "Backspace",
  "Delete",
  "-",
  "@",
  "Arrow Left",
  "Arrow Right",
  "Arrow Up",
  "Arrow Down",
  "Alt Right",
  "Alt Left",
  "Shift Left",
  "Shift Right",
  "Control Left",
  "Control Right",
];

final _nonSplitterKeys = [
  "Backspace",
  "Delete",
  "Arrow Left",
  "Arrow Right",
  "Arrow Up",
  "Arrow Down",
  "Alt Right",
  "Alt Left",
  "Shift Left",
  "Shift Right",
  "Control Left",
  "Control Right",
];

const _rowStart = "-";
const _headingStart = "@";
const _commentStart = "!!";
const _start = "=<";
const _stop = ">=";

//======================================================================
//Text Input Mode View
//======================================================================
class TextInputModeView extends StatefulWidget {
  const TextInputModeView({Key? key}) : super(key: key);

  @override
  State<TextInputModeView> createState() => _TextInputModeViewState();
}

class _TextInputModeViewState extends State<TextInputModeView> {
  final _lookUps = <NewLanguageLookUp>[];
  final _lookUpCards = <NewLanguageLookUpCard>[];
  final _lookUpReturns = <LookUpReturn>[];

  int? _currentReportId;

  final _textController = TextEditingController();
  bool _inFocus = false;
  bool _loading = false;
  final _textNode = FocusNode();

  double _fontSize = 11.0;

  //FORMATTING------------------------------------------------------------------

  String _unformat() {
    String temp = _textController.text;
    temp = temp.replaceAll("\n\t\t", "");
    temp = temp.replaceAll("\n\t\t\t\t", "");
    temp = temp.replaceAll("\t", "");
    return temp;
  }

  String _format(String input) {
    final sb = StringBuffer();
    final whitespacePostSplit = "\t\t\t\t";
    final whitespacePreSplit = "\t\t";

    bool afterSplit = false;

    for (int i = 0; i < input.length; i++) {
      switch (input[i]) {
        case "@":
          sb.write("\n\n${input[i]}");
          break;
        case "|":
          if (input[i - 1] == "|") {
            if (!afterSplit) {
              sb.write("${input[i]}\n$whitespacePostSplit");
              afterSplit = true;
            } else {
              //only one splitter is allowed per row
              sb.write(input[i]);
            }
          } else {
            sb.write(input[i]);
          }
          break;
        case "/":
          if (input[i - 1] == "/") {
            if (afterSplit) {
              sb.write("${input[i]}\n$whitespacePostSplit");
            } else {
              sb.write("${input[i]}\n$whitespacePreSplit");
            }
          } else {
            sb.write(input[i]);
          }
          break;
        case "-":
          if (input[i - 1] == "\n") {
            sb.write("\n${input[i]}\t");
            afterSplit = false;
          } else {
            sb.write(input[i]);
          }
          break;
        case ">":
          if (input[i - 1] == "\n" && input[i + 1] == "=") {
            sb.write("\n\n${input[i]}");
          } else {
            sb.write(input[i]);
          }
          break;
        case "\t":
          //skip tabs
          break;
        case "\n":
          //skip line breaks
          break;
        default:
          sb.write(input[i]);
      }
    }
    return sb.toString().replaceAll("\n- ", "\n-\t");
  }

  String _autoStartRow(String keyLabel, int minOffset) {
    final sb = StringBuffer();
    sb.write(_textController.text);

    final strA = sb.toString().substring(0, minOffset);
    final strB = sb.toString().substring(minOffset, sb.toString().length);

    return "$strA-\t$strB";
  }

  String _autoCellBreak(int caretIndex) {
    final sb = StringBuffer();
    sb.write(_textController.text);

    final strA = sb.toString().substring(0, caretIndex);
    final strB = sb.toString().substring(caretIndex, sb.toString().length);

    return "$strA|\n\t\t\t\t$strB";
  }

  String _autoLineBreak(int caretIndex, bool afterSplitter) {
    final sb = StringBuffer();
    sb.write(_textController.text);

    final strA = sb.toString().substring(0, caretIndex);
    final strB = sb.toString().substring(caretIndex, sb.toString().length);

    if (afterSplitter) {
      return "$strA/\n\t\t\t\t$strB";
    } else {
      return "$strA/\n\t\t$strB";
    }
  }

  //LOOK UP---------------------------------------------------------------------

  void _switchLoading() {
    setState(() {
      _loading = (_loading) ? false : true;
    });
  }

  Future<bool> _lookUpWords() async {
    List<String> temp = [];

    final connection = await Connectivity().checkConnectivity();
    if (connection == ConnectivityResult.none) {
      ScaffoldMessenger.of(context).showSnackBar(SnackBar(
          content: const Text(
              "No Internet connection detected. Please make sure you are connected to use this feature.")));
      return false;
    }

    _textController.text = _format(_textController.text);
    final indexStart = _textController.text.indexOf("@ New Language");
    final indexEnd = (_textController.text.indexOf("@", indexStart + 1) != -1)
        ? _textController.text.indexOf("@", indexStart + 1)
        : _textController.text.indexOf(">=");
    final chunk = _textController.text.substring(indexStart, indexEnd);
    final terms = chunk.split("\n-");

    //skip the first term as it is just the heading
    for (int i = 1; i < terms.length; i++) {
      if (terms[i].trim().length == 0) continue;

      final String thisTerm;

      if (terms[i].contains("||")) {
        thisTerm = terms[i].trim().substring(0, terms[i].trim().indexOf("||"));
      } else {
        thisTerm = terms[i].trim();
      }

      if (thisTerm.isNotEmpty && thisTerm != "-") {
        temp.add(thisTerm);
      }
    }

    if (temp.isNotEmpty) {
      _lookUpReturns.addAll(await showDialog(
          context: context,
          builder: ((context) {
            return NewLanguageLookUpDialog(
                lookUpQueries: temp, controller: _textController);
          })));
      return true;
    }
    return false;
  }

  //OTHER-----------------------------------------------------------------------

  void _onPressedSubmit() async {
    //_textController.text = _autoFormat(_textController.text);
    String text = _unformat();
    if (TextModeMethods.checkNeededHeadings(text)) {
      try {
        while (text.contains("=<") && text.contains(">=")) {
          final start = text.indexOf("=<");
          final stop = text.indexOf(">=");
          final singleEntry = text.substring(start + 2, stop);
          text = text.substring(stop + 2, text.length);

          final report = Report(singleEntry);
          final mapping = report.toMap(singleEntry);

          //check if Student exists
          final student = Student();
          final studentId;
          if (!await Database.checkStudentExistsByName(
              mapping["Name"]!.first)) {
            //if not, create new Hive entry
            student.name = mapping["Name"]!.first;
            student.active = true;
            await Database.saveStudent(student);
          }
          studentId = await Database.getStudentId(mapping["Name"]!.first);

          if (student.name != null) {
            student.id = studentId!;
          } else {
            student.name = mapping["Name"]!.first;
            student.active = true;
            student.id = studentId!;
          }

          //format the Date string
          if (mapping["Date"]!.first.toString().contains('/')) {
            mapping["Date"]!.first =
                mapping["Date"]!.first.replaceAll('/', '-');
          }
          if (mapping["Date"]!.first.toString().split('-')[2].length == 1) {
            final tempList = mapping["Date"]!.first.toString().split('-');
            final tempDay = "0${tempList[2]}";
            mapping["Date"]!.first = "${tempList[0]}-${tempList[1]}-$tempDay";
          }

          final date = DateTime.parse(mapping["Date"]!.first);
          final topic = mapping["Topic"]!;
          final homework = mapping["Homework"];

          //Submit Lesson
          var less = await Database.getLesson(student.name, date);
          if (less != null) {
            less.topic = CompanionMethods.convertListToString(topic);
            less.homework = homework != null
                ? CompanionMethods.convertListToString(homework)
                : "";
          } else {
            less = Lesson(
                studentId: studentId!,
                date: date,
                topic: CompanionMethods.convertListToString(topic),
                homework: homework != null
                    ? CompanionMethods.convertListToString(homework)
                    : "");
          }

          await Database.saveLesson(less);
          print(
              "Lesson saved: ${mapping["Name"]!.first} >> ${mapping["Topic"]!.first}");
          ScaffoldMessenger.of(context).showSnackBar(SnackBar(
              content: Text(
                  "Lesson saved: ${mapping["Name"]!.first} >> ${mapping["Topic"]!.first}")));

          if (mapping.keys.length > 4 ||
              (mapping.keys.length == 4 &&
                  !mapping.keys.contains("Homework"))) {
            try {
              final pdfDoc = await report.toPdfDoc();
              Navigator.push(context, MaterialPageRoute(
                builder: (context) {
                  return PdfPreviewPage(pdfDocument: pdfDoc);
                },
              ));
            } on Exception {
              ScaffoldMessenger.of(context).showSnackBar(SnackBar(
                  content: Text(
                      "Report could not be made.\nYou may have made a mistake with you notation markers.\nPlease check them again")));
            }
          }
        }
      } on InputException {
        final we = InputException("Name, Date, and Topic are required fields");
        ScaffoldMessenger.of(context)
            .showSnackBar(SnackBar(content: Text(we.cause)));
      }
    } else {
      ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
          content: Text(
              "Failed to submit lesson.\nThere is a problem with the text format.")));
    }
  }

  KeyEventResult _handleKey(RawKeyEvent value) {
    final k = value.logicalKey;

    if (value is RawKeyDownEvent) {
      print(k.keyLabel);
      final List<int> caretIndex = [
        _textController.selection.baseOffset,
        _textController.selection.extentOffset
      ];

      if (CompanionLexer.markers.contains(k.keyLabel)) {
        final newText = CompanionMethods.autoInsertBrackets(
            k.keyLabel, _textController, caretIndex[0], caretIndex[1]);

        _textController.text = newText;
        _textController.selection = TextSelection(
            baseOffset: caretIndex[0] + 1, extentOffset: caretIndex[1] + 1);

        return KeyEventResult.handled;
      } else if (value.isControlPressed) {
        switch (k.keyLabel) {
          case "S":
            _saveReportSync();
            break;
          case "B":
            _textController.text =
                CompanionMethods.insertStyleSyntax("**", _textController);
            _textController.selection = TextSelection(
                baseOffset: caretIndex[0] + 2, extentOffset: caretIndex[1] + 2);
            break;
          case "I":
            _textController.text =
                CompanionMethods.insertStyleSyntax("*", _textController);
            _textController.selection = TextSelection(
                baseOffset: caretIndex[0] + 1, extentOffset: caretIndex[1] + 1);
            break;
          case "U":
            _textController.text =
                CompanionMethods.insertStyleSyntax("_", _textController);
            _textController.selection = TextSelection(
                baseOffset: caretIndex[0] + 1, extentOffset: caretIndex[1] + 1);
            break;
          case "Enter":
            final fullText = _textController.text;

            final before;
            final middle = "\n";
            final after;
            final newSelectionIndex;

            final indexNextLineEnd =
                fullText.indexOf("\n", _textController.selection.baseOffset);

            if (indexNextLineEnd != -1) {
              before = fullText.substring(0, indexNextLineEnd);
              after = fullText.substring(indexNextLineEnd, fullText.length);
              newSelectionIndex = indexNextLineEnd;
            } else {
              before = fullText;
              after = "";
              newSelectionIndex = fullText.length + 1;
            }

            _textController.text = "$before$middle$after";
            _textController.selection =
                TextSelection.collapsed(offset: newSelectionIndex + 1);

            return KeyEventResult.handled;
          case "Numpad Add":
            //increase font size
            setState(() {
              _fontSize++;
            });
            break;
          case "Numpad Subtract":
            //decrease font size
            setState(() {
              _fontSize--;
            });
            break;
          default:
        }
        return KeyEventResult.ignored;
      } else {
        if (!_nonAutoRowStartKeys.contains(k.keyLabel) && //auto-start row
            _textController.text[caretIndex[0] - 1] == "\n") {
          final indexMin =
              (caretIndex[0] < caretIndex[1]) ? caretIndex[0] : caretIndex[1];

          _textController.text = _autoStartRow(k.keyLabel, indexMin);
          _textController.selection = TextSelection(
              baseOffset: caretIndex[0] + 2, extentOffset: caretIndex[1] + 2);
        } else if (k.keyLabel == "|" && //auto-go to new line for RHS cell entry
            (_textController.text[caretIndex[0] - 1] == "|")) {
          _textController.text = _autoCellBreak(caretIndex[0]);
          _textController.selection = TextSelection(
              baseOffset: caretIndex[0] + 4, extentOffset: caretIndex[1] + 4);
          return KeyEventResult.handled;
        } else if (k.keyLabel == "/" && //auto-make line break in cell
            (_textController.text[caretIndex[0] - 1] == "/")) {
          int lineStartIndex = 0;
          int thisIndex;

          if (_textController.text.contains("\n-")) {
            thisIndex = _textController.text.indexOf("\n-");

            while (thisIndex < caretIndex[0]) {
              lineStartIndex = thisIndex;
              thisIndex =
                  _textController.text.indexOf("\n-", lineStartIndex + 1);

              if (thisIndex == -1) {
                lineStartIndex = _textController.text.indexOf("\n-");
                break;
              }
            }
          } else {
            thisIndex = _textController.text.indexOf("\n");
          }

          final start = lineStartIndex;
          final end = caretIndex[0];

          final line = _textController.text.substring(start, end);
          if (line.contains("||") && (line.indexOf("||") < caretIndex[0])) {
            _textController.text = _autoLineBreak(caretIndex[0], true);
            _textController.selection = TextSelection(
                baseOffset: caretIndex[0] + 6, extentOffset: caretIndex[1] + 6);
          } else {
            _textController.text = _autoLineBreak(caretIndex[0], false);
            _textController.selection = TextSelection(
                baseOffset: caretIndex[0] + 4, extentOffset: caretIndex[1] + 4);
          }
          return KeyEventResult.handled;
        }
      }
    }
    return KeyEventResult.ignored;
  }

  void _saveReportSync() {
    _textController.text = _format(_textController.text);

    final report;
    if (_currentReportId != null) {
      report = Report.getReportSync(_currentReportId!);

      if (report == null) {
        final newReport = Report(_textController.text);
        Report.saveReportSync(newReport);
        _currentReportId = newReport.id;
      } else {
        report.text = _textController.text;
        Report.saveReportSync(report);
      }
    } else {
      final newReport = Report(_textController.text);
      Report.saveReportSync(newReport);
      _currentReportId = newReport.id;
    }
    ScaffoldMessenger.of(context)
        .showSnackBar(SnackBar(content: Text("Report saved")));
  }

  void _duplicateCorrections() {
    _textController.text = _format(_textController.text);

    final fullText = _textController.text;
    final StringBuffer sb = StringBuffer();

    final indexStart = fullText.indexOf("@ Corrections") + 14;
    final indexEnd;
    if (fullText.indexOf("@", indexStart) != -1) {
      indexEnd = fullText.indexOf("@", indexStart);
    } else {
      indexEnd = fullText.indexOf(">=");
    }

    final nl = fullText.substring(indexStart, indexEnd).split("\n");

    for (final line in nl) {
      if (line.isEmpty || line.trim().length == 0) continue;

      if (!line.contains("||")) {
        sb.writeln("${line.trim()} || ${line.substring(2)}");
      } else {
        sb.writeln(line);
      }
    }

    final before = fullText.substring(0, indexStart);
    final middle = sb.toString().trim();
    final after = fullText.substring(indexEnd, fullText.length);

    _textController.text = "$before\n$middle\n\n$after";
  }

  //MAIN------------------------------------------------------------------------

  @override
  initState() {
    _textController.text = _template;
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: FocusScope(
          autofocus: true,
          canRequestFocus: true,
          onKey: (node, event) {
            return _handleKey(event);
          },
          child: Focus(
            child: Column(
              children: [
                Expanded(
                    child: Card(
                  child: Padding(
                    padding: EdgeInsets.all(0),
                    child: Row(
                      children: [
                        Expanded(
                            child: RawKeyboardListener(
                          focusNode: _textNode,
                          autofocus: true,
                          child: TextField(
                            controller: _textController,
                            onSubmitted: ((value) {
                              _textController.selection =
                                  TextSelection.collapsed(offset: 0);
                            }),
                            style: TextStyle(
                                fontSize: _fontSize, fontFamily: "Roboto"),
                            maxLines: null,
                            expands: true,
                          ),
                          onKey: null,
                        )),
                      ],
                    ),
                  ),
                )),
                Padding(
                    padding: const EdgeInsets.all(5),
                    child: ElevatedButton(
                        onPressed: _onPressedSubmit,
                        child: const Text("Submit")))
              ],
            ),
            onFocusChange: (value) {
              setState(() {
                _inFocus = value;
              });
            },
          ),
        ),
        floatingActionButton: SpeedDial(
          icon: Icons.more,
          children: [
            SpeedDialChild(
                label: "Look Up New Language",
                onTap: () async {
                  _switchLoading();
                  _lookUpWords().then((value) {
                    _switchLoading();
                  });
                }),
            SpeedDialChild(
                label: "Duplicate Corrections",
                onTap: () {
                  _duplicateCorrections();
                  _textController.text = _format(_textController.text);
                }),
            SpeedDialChild(
                label: "Reset",
                onTap: () {
                  setState(() {
                    _textController.text = _template;
                  });
                }),
            SpeedDialChild(
                label: "Unformat",
                onTap: () {
                  setState(() {
                    _textController.text = _unformat();
                  });
                }),
            SpeedDialChild(
                label: "Format",
                onTap: () {
                  setState(() {
                    _textController.text = _format(_textController.text);
                  });
                }),
          ],
        ));
  }
}

Logs I've cut out most of the log from `flutter run --verbose` due to the character limit here, but I'll post it later if need be.

Here is from where the _saveReportSync method is called.

[ +837 ms] flutter: Control Left
[ +336 ms] flutter: S
[+3256 ms] Service protocol connection closed.
[   +1 ms] Lost connection to device.
[   +6 ms] DevFS: Deleting filesystem on the device
(file:///C:/Users/micha/AppData/Local/Temp/lesson_companiond0f8b01e/lesson_companion/)
[ +254 ms] Ignored error while cleaning up DevFS: TimeoutException after 0:00:00.250000: Future not completed
[   +5 ms] "flutter run" took 34 090ms.
[ +260 ms] ensureAnalyticsSent: 250ms
[   +1 ms] Running 1 shutdown hook
[  +20 ms] Shutdown hooks complete
[   +4 ms] exiting with code 0

Here are the flutter analyze results:

warning - The include file 'package:flutter_lints/flutter.yaml' in
       'C:\Users\micha\Documents\Flutter\lesson_companion\analysis_options.yaml' can't be found when analyzing
       'C:\Users\micha\Documents\Flutter\lesson_companion' - analysis_options.yaml:10:10 - include_file_not_found
   info - Unused import: 'package:connectivity_plus/connectivity_plus.dart' -
          lib\views\dialogs\lookups\new_language_look_up.dart:1:8 - unused_import
   info - The declaration '_template' isn't referenced - lib\views\dialogs\main_menu_dialog.dart:9:7 - unused_element
   info - The declaration 'setState' isn't referenced - lib\views\dialogs\snippets\snippet_list.dart:99:21 -
          unused_element
   info - Unused import: 'package:lesson_companion/views/main_windows/report_view.dart' -
          lib\views\main_windows\base_view.dart:2:8 - unused_import
   info - The value of the field '_currentFocus' isn't used - lib\views\main_windows\home_view.dart:42:8 - unused_field
   info - The value of the local variable 'dateSplit' isn't used - lib\views\main_windows\home_view.dart:146:13 -
          unused_local_variable
   info - The value of the field '_currentRow' isn't used - lib\views\main_windows\home_view.dart:435:7 - unused_field
   info - The declaration '_updateCurrent' isn't referenced - lib\views\main_windows\home_view.dart:438:8 -
          unused_element
   info - This class (or a class that this class inherits from) is marked as '@immutable', but one or more of its
          instance fields aren't final: PdfPreviewPage._bytes - lib\views\main_windows\pdf_preview.dart:10:7 -
          must_be_immutable
   info - The value of the field '_bytes' isn't used - lib\views\main_windows\pdf_preview.dart:12:14 - unused_field
   info - The declaration '_deleteDialog' isn't referenced - lib\views\main_windows\report_view.dart:141:15 -
          unused_element
   info - Unused import: 'package:lesson_companion/models/dictionary/free_dictionary.dart' -
          lib\views\main_windows\text_input_mode_view.dart:10:8 - unused_import
   info - The declaration '_nonSplitterKeys' isn't referenced - lib\views\main_windows\text_input_mode_view.dart:59:7 -
          unused_element
   info - The declaration '_rowStart' isn't referenced - lib\views\main_windows\text_input_mode_view.dart:74:7 -
          unused_element
   info - The declaration '_headingStart' isn't referenced - lib\views\main_windows\text_input_mode_view.dart:75:7 -
          unused_element
   info - The declaration '_commentStart' isn't referenced - lib\views\main_windows\text_input_mode_view.dart:76:7 -
          unused_element
   info - The declaration '_start' isn't referenced - lib\views\main_windows\text_input_mode_view.dart:77:7 -
          unused_element
   info - The declaration '_stop' isn't referenced - lib\views\main_windows\text_input_mode_view.dart:78:7 -
          unused_element
   info - The value of the field '_lookUps' isn't used - lib\views\main_windows\text_input_mode_view.dart:91:9 -
          unused_field
   info - The value of the field '_lookUpCards' isn't used - lib\views\main_windows\text_input_mode_view.dart:92:9 -
          unused_field
   info - The value of the field '_inFocus' isn't used - lib\views\main_windows\text_input_mode_view.dart:98:8 -
          unused_field

22 issues found. (ran in 21.5s)

Logs from flutter doctor -v:

[√] Flutter (Channel master, 3.7.0-24.0.pre.52, on Microsoft Windows [Version 10.0.22621.1105], locale en-ZA)
    ΓÇó Flutter version 3.7.0-24.0.pre.52 on channel master at C:\src\flutter
    ΓÇó Upstream repository https://github.com/flutter/flutter.git
    ΓÇó Framework revision 8d60a8c0bb (2 days ago), 2023-01-21 03:44:24 -0500
    ΓÇó Engine revision 3a444b3665
    ΓÇó Dart version 3.0.0 (build 3.0.0-150.0.dev)
    ΓÇó DevTools version 2.20.1

[√] Windows Version (Installed version of Windows is version 10 or higher)

[√] Android toolchain - develop for Android devices (Android SDK version 32.1.0-rc1)
    ΓÇó Android SDK at C:\Users\micha\AppData\Local\Android\Sdk
    ΓÇó Platform android-33, build-tools 32.1.0-rc1
    ΓÇó Java binary at: C:\Program Files\Java\jdk-16.0.2\bin\java
    ΓÇó Java version Java(TM) SE Runtime Environment (build 16.0.2+7-67)
    ΓÇó All Android licenses accepted.

[X] Chrome - develop for the web (Cannot find Chrome executable at .\Google\Chrome\Application\chrome.exe)
    ! Cannot find Chrome. Try setting CHROME_EXECUTABLE to a Chrome executable.

[√] Visual Studio - develop for Windows (Visual Studio Community 2022 17.3.6)
    ΓÇó Visual Studio at C:\Program Files\Microsoft Visual Studio\2022\Community
    ΓÇó Visual Studio Community 2022 version 17.3.32929.385
    ΓÇó Windows 10 SDK version 10.0.19041.0

[!] Android Studio (not installed)
    ΓÇó Android Studio not found; download from https://developer.android.com/studio/index.html
      (or visit https://flutter.dev/docs/get-started/install/windows#android-setup for detailed instructions).

[√] Connected device (3 available)
    ΓÇó MAR LX1A (mobile) ΓÇó EUH4C20311000017 ΓÇó android-arm64  ΓÇó Android 10 (API 29)
    ΓÇó Windows (desktop) ΓÇó windows          ΓÇó windows-x64    ΓÇó Microsoft Windows [Version 10.0.22621.1105]
    ΓÇó Edge (web)        ΓÇó edge             ΓÇó web-javascript ΓÇó Microsoft Edge 109.0.1518.55

[√] HTTP Host Availability
    ΓÇó All required HTTP hosts are available

! Doctor found issues in 2 categories.

Metadata

Metadata

Assignees

No one assigned

    Labels

    in triagePresently being triaged by the triage teamwaiting for customer responseThe Flutter team cannot make further progress on this issue until the original reporter responds

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions