2021-11-05 14:25:36 +03:00
import ' package:graphs/src/graph.dart ' ;
2021-11-05 00:35:51 +03:00
import ' package:graphs/curve_painter.dart ' ;
2021-11-05 14:25:36 +03:00
import ' package:file_picker/file_picker.dart ' ;
2021-11-05 00:35:51 +03:00
import ' package:flutter/material.dart ' ;
2021-11-05 02:50:05 +03:00
Graphs getGraph ( ) {
List < Dot > d = < Dot > [ ] ;
2021-11-05 20:57:12 +03:00
d . add ( Dot . fromTwoLists ( " 1 " , [ 2 , 3 ] , [ 5 , 1 ] ) ) ;
2021-11-05 02:50:05 +03:00
d . add ( Dot . fromTwoLists ( " 2 " , [ 1 , 3 ] , [ 1 , 1 ] ) ) ;
2021-11-05 20:57:12 +03:00
d . add ( Dot . fromTwoLists ( " 3 " , [ 1 , 2 ] , [ 1 , 2 ] ) ) ;
2021-11-08 18:37:13 +03:00
//d.add(Dot.fromTwoLists("Name1", [], []));
//d.add(Dot.fromTwoLists("Name2", [], []));
return Graphs . fromList ( " UMYA " , d , true , true ) ;
2021-11-05 02:50:05 +03:00
}
2021-11-05 00:35:51 +03:00
class DrawingPage extends StatefulWidget {
const DrawingPage ( { Key ? key } ) : super ( key: key ) ;
@ override
State < StatefulWidget > createState ( ) = > _DrawingPageState ( ) ;
}
class _DrawingPageState extends State < DrawingPage > {
2021-11-05 01:40:16 +03:00
double screenSize = 0 ;
2021-11-08 19:50:43 +03:00
Graphs graphData = getGraph ( ) ;
List < int > ? bfsPath ;
2021-11-08 21:37:55 +03:00
List < bool > ? dfsAccessTable ;
int ? dfsStartDot ;
2021-11-05 00:35:51 +03:00
2021-11-05 02:50:05 +03:00
final _textNameController = TextEditingController ( ) ;
2021-11-05 03:23:20 +03:00
final _textNumbController = TextEditingController ( ) ;
2021-11-05 14:25:36 +03:00
final _textDestController = TextEditingController ( ) ;
2021-11-05 02:50:05 +03:00
final _textLnthController = TextEditingController ( ) ;
2021-11-05 17:43:27 +03:00
final _textGrNmController = TextEditingController ( ) ;
2021-11-05 14:25:36 +03:00
2021-11-05 02:50:05 +03:00
void clearTextControllers ( ) {
2021-11-05 14:25:36 +03:00
_textDestController . clear ( ) ;
2021-11-05 03:23:20 +03:00
_textNumbController . clear ( ) ;
2021-11-05 02:50:05 +03:00
_textLnthController . clear ( ) ;
_textNameController . clear ( ) ;
}
2021-11-05 01:40:16 +03:00
2021-11-05 00:35:51 +03:00
@ override
Widget build ( BuildContext context ) {
2021-11-05 01:40:16 +03:00
screenSize = MediaQuery . of ( context ) . size . width ;
2021-11-08 19:50:43 +03:00
_textGrNmController . text = graphData . getName ( ) ;
2021-11-05 00:35:51 +03:00
return MaterialApp (
home: Scaffold (
appBar: AppBar (
2021-11-05 17:43:27 +03:00
title: const Align (
alignment: Alignment . topLeft ,
2021-11-08 18:37:13 +03:00
child: Text ( " Graph name: \n " ,
2021-11-05 17:43:27 +03:00
style: TextStyle (
fontSize: 18 ,
color: Colors . white ,
) ) ) ,
toolbarHeight: 110 ,
2021-11-05 00:35:51 +03:00
flexibleSpace: Container (
color: Colors . blue ,
child: Column ( children: < Widget > [
const SizedBox ( height: 5 ) ,
2021-11-05 02:50:05 +03:00
Row ( children: [
2021-11-08 19:50:43 +03:00
addSpaceW ( screenSize / 8 + 19 ) ,
2021-11-05 02:50:05 +03:00
createButton ( " \n Add dot \n " , addDotPushed ) ,
createInputBox ( " Dot name " , screenSize / 4 - 25 , Icons . label ,
_textNameController ) ,
2021-11-08 19:50:43 +03:00
addSpaceW ( 8 ) ,
createButton ( " \n Add path \n " , addPathPushed ) ,
createInputBox ( " Input length " , screenSize / 4 - 25 ,
Icons . arrow_right_alt_outlined , _textLnthController ) ,
2021-11-05 02:50:05 +03:00
] ) ,
addSpaceH ( 3 ) ,
2021-11-05 01:40:16 +03:00
Row ( children: [
2021-11-08 19:50:43 +03:00
addSpaceW ( 5 ) ,
2021-11-05 17:43:27 +03:00
createInputBox (
" Name " , screenSize / 8 - 25 , null , _textGrNmController ) ,
//addSpaceW(screenSize / 8 - 4),
2021-11-08 19:50:43 +03:00
createButton ( " \n Del dot \n " , delDotPushed ) ,
createInputBox ( " Dot number " , screenSize / 4 - 25 ,
Icons . fiber_manual_record , _textNumbController ) ,
2021-11-05 14:25:36 +03:00
addSpaceW ( 13 ) ,
createButton ( " \n Del path \n " , delPathPushed ) ,
createInputBox ( " Destination number " , screenSize / 4 - 25 ,
Icons . fiber_manual_record , _textDestController ) ,
2021-11-05 01:40:16 +03:00
] ) ,
2021-11-05 00:35:51 +03:00
] ) ,
) ,
actions: [
IconButton (
2021-11-08 21:37:55 +03:00
onPressed: ( ) = > graphData . flushData ( ) ,
2021-11-05 02:50:05 +03:00
icon: const Icon ( Icons . delete_sweep ) ,
iconSize: 60 ,
2021-11-05 00:35:51 +03:00
) ,
] ) ,
body: CustomPaint (
2021-11-08 21:37:55 +03:00
painter: CurvePainter (
graphData: graphData ,
bfsPath: bfsPath ,
dfsStart: dfsStartDot ,
dfsAccessTable: dfsAccessTable ) ,
2021-11-05 03:23:20 +03:00
child: Align (
alignment: Alignment . topRight ,
child: ButtonBar (
mainAxisSize: MainAxisSize . min ,
children: < Widget > [
2021-11-08 19:50:43 +03:00
createButton ( " Bfs " , bfsPushed ) ,
2021-11-08 21:37:55 +03:00
createButton ( " Dfs " , dfsPushed ) ,
2021-11-08 19:50:43 +03:00
createButton ( " Clear dfs or bfs " , ( ) = > bfsPath = null ) ,
createButton ( graphData . getUseLengthStr ( ) , changeLength ) ,
createButton ( graphData . getDoubleSidedStr ( ) , changeOriented ) ,
2021-11-05 17:43:27 +03:00
/ * Text ( _textGrNmController . text ,
style:
TextStyle ( fontSize: 15 , color: Colors . blueGrey . shade900 ) ) , * /
createButton ( " Save to file " , fileSaver ) ,
2021-11-05 14:25:36 +03:00
createButton ( " Load from file " , fileOpener ) ,
2021-11-08 19:50:43 +03:00
createButton ( " Help " , ( ) {
String out =
" В поле \" Graph name \" можно сменить имя графу. \n " ;
out + =
" Для добавления точки необходимо ввести имя в \" Dot name \" и нажать на \" Add dot \" . \n " ;
out + =
" Для удаления точки необходимо ввести номер в \" Dot number \" и нажать на \" Del dot \" . \n " ;
out + =
" Для добавления пути необходимо ввести: номер выходной вершины в \" Dot number \" , номер входной вершины в \" Destination number \" " ;
out + =
" и, если граф взвешенный, то ввести длину пути в \" Input length \" . Затем нажать \" Add path \" . \n " ;
out + =
" Для удаления пути необходимо ввести номер выходной вершины в \" Dot number \" и номер входной вершины в \" Destination number \" . Затем нажать \" Del path \" . \n \n " ;
out + =
" Кнопки \" Bfs \" и \" Dfs \" нумеруют точки в зависимости от послежовательности, в которой они будут пройдены. \n " ;
out + =
" Кнопки \" Взвешенный \" и \" Ориентированный \" позволяют сменить эти значения перед построением графа (т.е . для их работы граф должен быть пустым). \n " ;
out + =
" Кнопки \" Save to file \" и \" Load from file \" позволяют вывести информацию в файл и загрузить информацию из файла соответственно. \n " ;
out + =
" Кнопка \" Help \" описывает работу с интерфейсом программы. " ;
showPopUp ( " Help: " , out ) ;
} )
2021-11-05 03:23:20 +03:00
] ,
) ,
) ,
2021-11-05 00:35:51 +03:00
) ,
) ) ;
}
2021-11-05 01:40:16 +03:00
// ignore: avoid_types_as_parameter_names, non_constant_identifier_names, use_function_type_syntax_for_parameters
ElevatedButton createButton ( String txt , void onPressing ( ) ) {
2021-11-05 00:35:51 +03:00
return ElevatedButton (
2021-11-05 01:40:16 +03:00
onPressed: onPressing ,
2021-11-05 00:35:51 +03:00
child: Text ( txt ,
style: const TextStyle (
fontSize: 15 ,
color: Colors . white ,
height: 1 ,
) ) ,
) ;
}
2021-11-05 17:43:27 +03:00
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 ,
2021-11-08 19:50:43 +03:00
onChanged: ( name ) = > graphData . setName ( name ) ,
2021-11-05 17:43:27 +03:00
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 ) ,
) ) ;
}
2021-11-05 01:40:16 +03:00
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 ) {
2021-11-05 00:35:51 +03:00
return SizedBox ( height: h ) ;
}
2021-11-05 01:40:16 +03:00
SizedBox addSpaceW ( double w ) {
return SizedBox ( width: w ) ;
}
2021-11-08 19:50:43 +03:00
void showPopUp ( String alertTitle , String err ) = > showDialog < String > (
context: context ,
builder: ( BuildContext context ) = > AlertDialog (
title: Text ( alertTitle ) ,
content: Text ( err ) ,
actions: < Widget > [
TextButton (
onPressed: ( ) = > Navigator . pop ( context , ' OK ' ) ,
child: const Text ( ' OK ' ) ,
) ,
] ,
) ,
) ;
//*********ButtonsFunctions*********
2021-11-05 01:40:16 +03:00
void addDotPushed ( ) {
2021-11-05 02:50:05 +03:00
//showPopUp("Test", "Test message");
//var inp = int.tryParse(_textNameController.text);
2021-11-05 17:43:27 +03:00
setState ( ( ) {
if ( _textNameController . text = = " " ) {
showPopUp ( " Error " , " No name in \" Dot name \" box " ) ;
} else {
2021-11-08 19:50:43 +03:00
String ? res = graphData . addIsolated ( _textNameController . text ) ;
2021-11-05 17:43:27 +03:00
if ( res ! = null ) {
showPopUp ( " Error " , res ) ;
}
2021-11-05 02:50:05 +03:00
}
2021-11-05 17:43:27 +03:00
clearTextControllers ( ) ;
} ) ;
2021-11-05 14:25:36 +03:00
}
void addPathPushed ( ) {
2021-11-05 17:43:27 +03:00
setState ( ( ) {
if ( _textNumbController . text = = " " ) {
showPopUp ( " Error " , " No number in \" Dot number \" box " ) ;
} else if ( _textDestController . text = = " " ) {
2021-11-08 19:50:43 +03:00
showPopUp ( " Error " , " No name in \" Destination number \" box " ) ;
} else if ( _textLnthController . text = = " " & &
graphData . getUseLengthBool ( ) ) {
2021-11-05 17:43:27 +03:00
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 | |
2021-11-08 19:50:43 +03:00
( len = = null & & graphData . getUseLengthBool ( ) ) ) {
2021-11-05 17:43:27 +03:00
showPopUp ( " Error " ,
" Can't parse input. \n Ints only allowed in \" Dot number \" , \" Destination number \" and \" Input length \" " ) ;
} else {
2021-11-08 19:50:43 +03:00
len ? ? = 0 ;
String ? res = graphData . addPath ( from , to , len ) ;
2021-11-05 17:43:27 +03:00
if ( res ! = null ) {
showPopUp ( " Error " , res ) ;
}
}
2021-11-05 14:25:36 +03:00
}
2021-11-05 17:43:27 +03:00
clearTextControllers ( ) ;
} ) ;
}
void changeOriented ( ) {
setState ( ( ) {
2021-11-08 19:50:43 +03:00
String ? res = graphData . flipUseOrientation ( ) ;
2021-11-05 17:43:27 +03:00
if ( res ! = null ) showPopUp ( " Error " , res ) ;
} ) ;
}
void changeLength ( ) {
setState ( ( ) {
2021-11-08 19:50:43 +03:00
String ? res = graphData . flipUseLength ( ) ;
2021-11-05 17:43:27 +03:00
if ( res ! = null ) showPopUp ( " Error " , res ) ;
} ) ;
}
2021-11-05 14:25:36 +03:00
void delPathPushed ( ) {
2021-11-05 17:43:27 +03:00
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. \n Ints only allowed in \" Dot number \" and \" Destination number \" " ) ;
} else {
2021-11-08 19:50:43 +03:00
String ? res = graphData . delPath ( from , to ) ;
2021-11-05 17:43:27 +03:00
if ( res ! = null ) {
showPopUp ( " Error " , res ) ;
}
}
2021-11-05 14:25:36 +03:00
}
2021-11-05 17:43:27 +03:00
clearTextControllers ( ) ;
} ) ;
2021-11-05 02:50:05 +03:00
}
void delDotPushed ( ) {
2021-11-05 17:43:27 +03:00
setState ( ( ) {
if ( _textNumbController . text = = " " ) {
showPopUp ( " Error " , " No number in \" Dot number \" box " ) ;
2021-11-05 03:23:20 +03:00
} else {
2021-11-05 17:43:27 +03:00
int ? dot = int . tryParse ( _textNumbController . text ) ;
if ( dot = = null ) {
showPopUp ( " Error " , " Can't parse input. \n Ints only allowed " ) ;
} else {
2021-11-08 19:50:43 +03:00
String ? res = graphData . delDot ( dot ) ;
2021-11-05 17:43:27 +03:00
if ( res ! = null ) {
showPopUp ( " Error " , res ) ;
}
2021-11-05 03:23:20 +03:00
}
2021-11-05 02:50:05 +03:00
}
2021-11-05 17:43:27 +03:00
clearTextControllers ( ) ;
} ) ;
2021-11-05 01:40:16 +03:00
}
2021-11-05 14:25:36 +03:00
void fileOpener ( ) async {
2021-11-05 17:43:27 +03:00
FilePickerResult ? result =
await FilePicker . platform . pickFiles ( allowedExtensions: [ " txt " ] ) ;
setState ( ( ) {
if ( result ! = null ) {
2021-11-05 20:57:12 +03:00
if ( ! result . files . single . path ! . endsWith ( " .txt " ) ) {
showPopUp ( " Error " , " Can open only \" .txt \" files " ) ;
} else {
//print(result.files.single.path!);
2021-11-08 19:50:43 +03:00
String ? res =
graphData . replaceDataFromFile ( result . files . single . path ! ) ;
2021-11-05 20:57:12 +03:00
if ( res ! = null ) showPopUp ( " Error " , res ) ;
}
2021-11-05 17:43:27 +03:00
} else {
showPopUp ( " Error " , " No file selected " ) ;
// User canceled the picker
}
} ) ;
}
2021-11-05 14:25:36 +03:00
2021-11-05 17:43:27 +03:00
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 " ) ;
2021-11-05 14:25:36 +03:00
// User canceled the picker
2021-11-05 17:43:27 +03:00
} else {
if ( ! outputFile . endsWith ( " .txt " ) ) {
outputFile + = " .txt " ;
}
2021-11-08 19:50:43 +03:00
graphData . printToFile ( outputFile ) ;
2021-11-05 00:35:51 +03:00
}
}
2021-11-05 14:25:36 +03:00
2021-11-08 19:50:43 +03:00
void bfsPushed ( ) {
setState ( ( ) {
2021-11-08 21:37:55 +03:00
dfsAccessTable = null ;
bfsPath = null ;
2021-11-08 19:50:43 +03:00
if ( _textNumbController . text = = " " ) {
showPopUp ( " Error " , " No number in \" Dot number \" box " ) ;
} else if ( _textDestController . text = = " " ) {
showPopUp ( " Error " , " No name in \" Destination number \" 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. \n Ints only allowed in \" Dot number \" and \" Destination number \" " ) ;
} else {
bfsPath = graphData . bfsPath ( from , to ) ;
if ( bfsPath = = null ) {
showPopUp ( " Info " , " There is no path " ) ;
}
print ( bfsPath ) ;
}
}
clearTextControllers ( ) ;
} ) ;
}
2021-11-08 21:37:55 +03:00
void dfsPushed ( ) {
setState ( ( ) {
bfsPath = null ;
bfsPath = null ;
if ( _textNumbController . text = = " " ) {
showPopUp ( " Error " , " No number in \" Dot number \" box " ) ;
} else {
int ? from = int . tryParse ( _textNumbController . text ) ;
if ( from = = null ) {
showPopUp ( " Error " ,
" Can't parse input. \n Ints only allowed in \" Dot number \" . " ) ;
} else {
dfsAccessTable = graphData . dfsIterative ( from ) ;
if ( dfsAccessTable = = null ) {
showPopUp ( " Err " , " report this error. " ) ;
}
print ( dfsAccessTable ) ;
}
}
clearTextControllers ( ) ;
} ) ;
}
2021-11-08 19:50:43 +03:00
//*********ButtonsFunctions*********
2021-11-05 00:35:51 +03:00
}