import 'package:graphs/src/graph.dart'; import 'package:graphs/curve_painter.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; Graphs getGraph() { List d = []; d.add(Dot.fromTwoLists("1", [2, 3], [5, 1])); d.add(Dot.fromTwoLists("2", [1, 3], [1, 1])); d.add(Dot.fromTwoLists("3", [1, 2], [1, 2])); d.add(Dot.fromTwoLists("Name1", [], [])); d.add(Dot.fromTwoLists("Name2", [], [])); return Graphs.fromList("1", d, true, true); } class DrawingPage extends StatefulWidget { const DrawingPage({Key? key}) : super(key: key); @override State createState() => _DrawingPageState(); } class _DrawingPageState extends State { double screenSize = 0; Graphs data = getGraph(); final _textNameController = TextEditingController(); final _textNumbController = TextEditingController(); final _textDestController = TextEditingController(); final _textLnthController = TextEditingController(); final _textGrNmController = TextEditingController(); void clearTextControllers() { _textDestController.clear(); _textNumbController.clear(); _textLnthController.clear(); _textNameController.clear(); } @override Widget build(BuildContext context) { screenSize = MediaQuery.of(context).size.width; _textGrNmController.text = data.getName(); return MaterialApp( home: Scaffold( appBar: AppBar( title: const Align( alignment: Alignment.topLeft, child: Text("Graph\n\n", style: TextStyle( fontSize: 18, color: Colors.white, ))), toolbarHeight: 110, flexibleSpace: Container( color: Colors.blue, child: Column(children: [ const SizedBox(height: 5), Row(children: [ addSpaceW(screenSize / 8 + 21), createButton("\nAdd dot\n", addDotPushed), createInputBox("Dot name", screenSize / 4 - 25, Icons.label, _textNameController), addSpaceW(18), createButton("\nDel dot \n", delDotPushed), createInputBox("Dot number", screenSize / 4 - 25, Icons.fiber_manual_record, _textNumbController), ]), addSpaceH(3), Row(children: [ createInputBox( "Name", screenSize / 8 - 25, null, _textGrNmController), //addSpaceW(screenSize / 8 - 4), createButton("\nAdd path\n", addPathPushed), createInputBox("Input length", screenSize / 4 - 25, Icons.arrow_right_alt_outlined, _textLnthController), addSpaceW(13), createButton("\nDel path\n", delPathPushed), createInputBox("Destination number", screenSize / 4 - 25, Icons.fiber_manual_record, _textDestController), ]), ]), ), actions: [ IconButton( onPressed: clearScreen, icon: const Icon(Icons.delete_sweep), iconSize: 60, ), ]), body: CustomPaint( painter: CurvePainter(gr: data), child: Align( alignment: Alignment.topRight, child: ButtonBar( mainAxisSize: MainAxisSize.min, children: [ createButton(data.getUseLengthStr(), changeLength), createButton(data.getDoubleSidedStr(), changeOriented), /*Text(_textGrNmController.text, style: TextStyle(fontSize: 15, color: Colors.blueGrey.shade900)),*/ createButton("Save to file", fileSaver), createButton("Load from file", fileOpener), ], ), ), ), )); } // ignore: avoid_types_as_parameter_names, non_constant_identifier_names, use_function_type_syntax_for_parameters ElevatedButton createButton(String txt, void onPressing()) { return ElevatedButton( onPressed: onPressing, child: Text(txt, style: const TextStyle( fontSize: 15, color: Colors.white, height: 1, )), ); } Container createInputBox(String text, double wid, IconData? icon, TextEditingController? controller) { if (icon == null) { return Container( width: wid, height: 40, margin: const EdgeInsets.symmetric(horizontal: 20, vertical: 5), child: TextField( controller: controller, textAlign: TextAlign.center, onChanged: (name) => data.setName(name), decoration: InputDecoration( contentPadding: const EdgeInsets.symmetric(vertical: 10, horizontal: 10), filled: true, fillColor: Colors.white, //prefixIcon: Icon(icon, color: Colors.black), border: const OutlineInputBorder( borderRadius: BorderRadius.all(Radius.circular(40))), hintStyle: const TextStyle(color: Colors.black38), hintText: text), )); } return Container( width: wid, height: 40, margin: const EdgeInsets.symmetric(horizontal: 20, vertical: 5), child: TextField( controller: controller, textAlign: TextAlign.center, decoration: InputDecoration( contentPadding: const EdgeInsets.symmetric(vertical: 10, horizontal: 10), filled: true, fillColor: Colors.white, prefixIcon: Icon(icon, color: Colors.black), border: const OutlineInputBorder( borderRadius: BorderRadius.all(Radius.circular(40))), hintStyle: const TextStyle(color: Colors.black38), hintText: text), )); } SizedBox addSpaceH(double h) { return SizedBox(height: h); } SizedBox addSpaceW(double w) { return SizedBox(width: w); } void addDotPushed() { //showPopUp("Test", "Test message"); //var inp = int.tryParse(_textNameController.text); setState(() { if (_textNameController.text == "") { showPopUp("Error", "No name in \"Dot name\" box"); } else { String? res = data.addIsolated(_textNameController.text); if (res != null) { showPopUp("Error", res); } } clearTextControllers(); }); } void addPathPushed() { setState(() { if (_textNumbController.text == "") { showPopUp("Error", "No number in \"Dot number\" box"); } else if (_textDestController.text == "") { showPopUp("Error", "No name in \"Dot name\" box"); } else if (_textLnthController.text == "" && data.getUseLengthBool()) { showPopUp("Error", "No length in \"Input length\" box"); } else { int? from = int.tryParse(_textNumbController.text); int? to = int.tryParse(_textDestController.text); int? len = int.tryParse(_textLnthController.text); if (from == null || to == null || (len == null && data.getUseLengthBool())) { showPopUp("Error", "Can't parse input.\nInts only allowed in \"Dot number\", \"Destination number\" and \"Input length\""); } else { if (data.getUseLengthBool() && len == null) len = 0; String? res = data.addPath(from, to, len!); if (res != null) { showPopUp("Error", res); } } } clearTextControllers(); }); } void addLenPushed() { //data.delDot() print( "${_textNumbController.text} -> ${_textDestController.text} = ${_textLnthController.text}"); clearTextControllers(); } void changeOriented() { setState(() { String? res = data.flipUseOrientation(); if (res != null) showPopUp("Error", res); }); } void changeLength() { setState(() { String? res = data.flipUseLength(); if (res != null) showPopUp("Error", res); }); } void delPathPushed() { setState(() { if (_textNumbController.text == "") { showPopUp("Error", "No number in \"Dot number\" box"); } else if (_textDestController.text == "") { showPopUp("Error", "No name in \"Dot name\" box"); } else { int? from = int.tryParse(_textNumbController.text); int? to = int.tryParse(_textDestController.text); if (from == null || to == null) { showPopUp("Error", "Can't parse input.\nInts only allowed in \"Dot number\" and \"Destination number\""); } else { String? res = data.delPath(from, to); if (res != null) { showPopUp("Error", res); } } } clearTextControllers(); }); } void delDotPushed() { setState(() { if (_textNumbController.text == "") { showPopUp("Error", "No number in \"Dot number\" box"); } else { int? dot = int.tryParse(_textNumbController.text); if (dot == null) { showPopUp("Error", "Can't parse input.\nInts only allowed"); } else { String? res = data.delDot(dot); if (res != null) { showPopUp("Error", res); } } } clearTextControllers(); }); } void showPopUp(String alertTitle, String err) => showDialog( context: context, builder: (BuildContext context) => AlertDialog( title: Text(alertTitle), content: Text(err), actions: [ TextButton( onPressed: () => Navigator.pop(context, 'OK'), child: const Text('OK'), ), ], ), ); void fileOpener() async { FilePickerResult? result = await FilePicker.platform.pickFiles(allowedExtensions: ["txt"]); setState(() { if (result != null) { if (!result.files.single.path!.endsWith(".txt")) { showPopUp("Error", "Can open only \".txt\" files"); } else { //print(result.files.single.path!); String? res = data.replaceDataFromFile(result.files.single.path!); if (res != null) showPopUp("Error", res); } } else { showPopUp("Error", "No file selected"); // User canceled the picker } }); } void fileSaver() async { String? outputFile = await FilePicker.platform.saveFile( dialogTitle: 'Please select an output file:', fileName: 'output-file.txt', allowedExtensions: ["txt"]); if (outputFile == null) { showPopUp("Error", "Save cancelled"); // User canceled the picker } else { if (!outputFile.endsWith(".txt")) { outputFile += ".txt"; } data.printToFile(outputFile); } } void clearScreen() => data.flushData(); }