I build the app that should return the tree of blocks connected to each other. I would like to have the possibility to save the info after user made the changes on the phone. I use for this getApplicationDocumentsDirectory() to get the path. After the user made changes and closes the app, he or she can open it and see all his or her progress. So I try to read the file asynchronously in initState()
I tried everything: FutureBuilder; anonymous async functions in initState; then; whenComplete. All the time I have the same result: the information is read after the tree is built.
Could you help me with that? (My code is below; Now it returns type error, but I don't know how to solve it)
main.dart
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:graphview/GraphView.dart';
import 'dart:math';
import 'MyNode.dart';
void main() {
print("main");
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) => MaterialApp(
home: TreeViewPage(),
);
}
class TreeViewPage extends StatefulWidget {
@override
_TreeViewPageState createState() => _TreeViewPageState();
}
var parsedJson;
final Graph graph = Graph()..isTree = true;
SugiyamaConfiguration builder = SugiyamaConfiguration();
// builder
// ..levelSeparation = (150)
// ..nodeSeparation = (100)
// ..orientation = (SugiyamaConfiguration.ORIENTATION_TOP_BOTTOM);
List<MyNode> ListMyNode = [];
int nodesCount = 0;
String text_from_init_state = "no_data";
class _TreeViewPageState extends State {
@override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder(
future: parsedJson,
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (parsedJson == null) {
return Center(
child: CircularProgressIndicator(
backgroundColor: Colors.red,
valueColor: AlwaysStoppedAnimation<Color>(Colors.blue)),
);
}
return Column(
mainAxisSize: MainAxisSize.max,
children: [
Text(text_from_init_state),
Expanded(
child: InteractiveViewer(
constrained: false,
boundaryMargin: EdgeInsets.all(300),
minScale: 0.01,
maxScale: 5.6,
child: GraphView(
graph: graph,
algorithm: SugiyamaAlgorithm(builder),
paint: Paint()
..color = Colors.green
..strokeWidth = 1
..style = PaintingStyle.stroke,
builder: (Node node) {
// I can decide what widget should be shown here based on the id
var a = node.key!.value as int;
return rectangleWidget(a);
},
),
),
),
],
);
},
),
);
}
Widget rectangleWidget(int a) {
TextEditingController textController = TextEditingController();
if (ListMyNode[a - 1].text != "") {
textController.text = ListMyNode[a - 1].text;
}
return InkWell(
onTap: () {
print("a" a.toString());
},
child: Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4),
boxShadow: [
BoxShadow(color: Colors.blue, spreadRadius: 1),
],
),
child: Column(
children: [
Container(
// height: 80,
width: 80,
child: TextField(
keyboardType: TextInputType.multiline,
maxLines: null,
controller: textController,
decoration: const InputDecoration(),
onChanged: (v) async {
await ListMyNode[a - 1].UpdateText(v, ListMyNode);
},
),
),
Container(
alignment: Alignment.bottomRight,
child: IconButton(
icon: Icon(Icons.add_box_rounded),
iconSize: 24,
onPressed: () async {
nodesCount ;
final newNode = Node.Id(nodesCount);
var edge = graph.getNodeAtPosition(a - 1);
graph.addEdge(edge, newNode);
text_from_init_state = await readJson();
setState(() {
MyNode b = MyNode(nodesCount, "");
ListMyNode.add(b);
});
},
),
),
],
),
),
);
}
@override
void initState() {
readJson2().whenComplete(() {
print("PArsed Json: " parsedJson.toString());
if (parsedJson == "{}") {
final node1 = Node.Id(1);
final node2 = Node.Id(2);
MyNode block0 = MyNode(nodesCount, "empty1");
nodesCount ;
MyNode block1 = MyNode(nodesCount, "empty2");
nodesCount ;
ListMyNode.add(block0);
ListMyNode.add(block1);
graph.addEdge(node1, node2);
} else {
final node1 = Node.Id(1);
final node2 = Node.Id(2);
MyNode block0 = MyNode(nodesCount, parsedJson.toString());
nodesCount ;
MyNode block1 = MyNode(nodesCount, "not_empty2");
nodesCount ;
ListMyNode.add(block0);
ListMyNode.add(block1);
graph.addEdge(node1, node2);
}
print("before setState: " parsedJson);
setState(() {});
print("after setState: " parsedJson);
});
super.initState();
builder
..levelSeparation = (150)
..nodeSeparation = (100)
..orientation = (SugiyamaConfiguration.ORIENTATION_TOP_BOTTOM);
}
Future<void> readJson2() async {
try {
final file = await localFile();
// Read the file
final contents = await file.readAsString();
parsedJson = contents;
} catch (e) {
// If encountering an error, return 0
parsedJson = "{}";
}
}
}
MyNode.dart
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
String ListMyNodeJSON(List<MyNode> lst) {
Map<int, String> mapMyNodeJSON = {};
for (int i = 0; i < lst.length; i ) {
mapMyNodeJSON[lst[i].id] = lst[i].text;
}
return mapMyNodeJSON.toString();
}
Future<String> localPath() async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
Future<File> localFile() async {
final path = await localPath();
return File('$path/tree.json');
}
Future<File> writeJson(text) async {
final file = await localFile();
return file.writeAsString("$text");
}
Future<String> readJson() async {
try {
final file = await localFile();
// Read the file
final contents = await file.readAsString();
return contents;
} catch (e) {
// If encountering an error, return 0
return "{}";
}
}
class MyNode {
int id = 0;
String text = "";
MyNode(int id, String text) {
this.id = id;
this.text = text;
}
Future<void> UpdateText(String text, List<MyNode> lst) async {
this.text = text;
await writeJson(ListMyNodeJSON(lst));
}
String toString() {
return this.id.toString() "---" this.text;
}
}
CodePudding user response:
I updated your code to show loading bar while fetching data and show blocks when completed. Now it gets the progress from file but it seems that you haven't implemented game logic for resuming the progress yet. I find this an interesting project. Hope this code solves your problem and continue developing progress logic section.
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:graphview/GraphView.dart';
import 'dart:math';
import 'MyNode.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) => MaterialApp(
home: TreeViewPage(),
);
}
class TreeViewPage extends StatefulWidget {
@override
_TreeViewPageState createState() => _TreeViewPageState();
}
final Graph graph = Graph()..isTree = true;
SugiyamaConfiguration builder = SugiyamaConfiguration();
// builder
// ..levelSeparation = (150)
// ..nodeSeparation = (100)
// ..orientation = (SugiyamaConfiguration.ORIENTATION_TOP_BOTTOM);
List<MyNode> ListMyNode = [];
int nodesCount = 0;
String text_from_init_state = "no_data";
class _TreeViewPageState extends State {
late String parsedJson;
@override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder(
future: readJson2(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: CircularProgressIndicator(
backgroundColor: Colors.red,
valueColor: AlwaysStoppedAnimation<Color>(Colors.blue)),
);
} else if (snapshot.connectionState == ConnectionState.done) {
parsedJson = snapshot.data as String;
updateNode(parsedJson);
return Column(
mainAxisSize: MainAxisSize.max,
children: [
Text(text_from_init_state),
Expanded(
child: InteractiveViewer(
constrained: false,
boundaryMargin: EdgeInsets.all(300),
minScale: 0.01,
maxScale: 5.6,
child: GraphView(
graph: graph,
algorithm: SugiyamaAlgorithm(builder),
paint: Paint()
..color = Colors.green
..strokeWidth = 1
..style = PaintingStyle.stroke,
builder: (Node node) {
// I can decide what widget should be shown here
//based on the id
var a = node.key!.value as int;
return rectangleWidget(a);
},
),
),
),
],
);
}
return Center(
child: Text(
'Something went wrong!',
style: TextStyle(
color: Colors.red,
),
),
);
},
),
);
}
void updateNode(String parsedReadJson2) {
if (parsedReadJson2.isEmpty) {
final node1 = Node.Id(1);
final node2 = Node.Id(2);
MyNode block0 = MyNode(nodesCount, "empty1");
nodesCount ;
MyNode block1 = MyNode(nodesCount, "empty2");
nodesCount ;
ListMyNode.add(block0);
ListMyNode.add(block1);
graph.addEdge(node1, node2);
} else {
final node1 = Node.Id(1);
final node2 = Node.Id(2);
MyNode block0 = MyNode(nodesCount, parsedReadJson2.toString());
nodesCount ;
MyNode block1 = MyNode(nodesCount, "not_empty2");
nodesCount ;
ListMyNode.add(block0);
ListMyNode.add(block1);
graph.addEdge(node1, node2);
}
}
Widget rectangleWidget(int a) {
TextEditingController textController = TextEditingController();
if (ListMyNode[a - 1].text != "") {
textController.text = ListMyNode[a - 1].text;
}
return InkWell(
onTap: () {
print("a$a");
},
child: Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4),
boxShadow: [
BoxShadow(color: Colors.blue, spreadRadius: 1),
],
),
child: Column(
children: [
Container(
// height: 80,
width: 80,
child: TextField(
keyboardType: TextInputType.multiline,
maxLines: null,
controller: textController,
decoration: const InputDecoration(),
onChanged: (v) async {
await ListMyNode[a - 1].UpdateText(v, ListMyNode);
},
),
),
Container(
alignment: Alignment.bottomRight,
child: IconButton(
icon: Icon(Icons.add_box_rounded),
iconSize: 24,
onPressed: () async {
nodesCount ;
final newNode = Node.Id(nodesCount);
var edge = graph.getNodeAtPosition(a - 1);
graph.addEdge(edge, newNode);
text_from_init_state = await readJson();
setState(() {
MyNode b = MyNode(nodesCount, "");
ListMyNode.add(b);
});
},
),
),
],
),
),
);
}
@override
void initState() {
super.initState();
builder
..levelSeparation = (150)
..nodeSeparation = (100)
..orientation = (SugiyamaConfiguration.ORIENTATION_TOP_BOTTOM);
}
Future<String> readJson2() async {
try {
final file = await localFile();
// Read the file
final contents = await file.readAsString();
return contents;
} catch (e) {
// If encountering an error, return empty string
return '';
}
}
}