From bdfbb9804fb4fee5c148e4ce606a20a7b55a4dae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20B=C3=B6cker?= Date: Sun, 26 Jul 2020 12:44:52 +0200 Subject: [PATCH] Bunch of fixes - Added a expandAll constructor argument for expanding - Add Pedantic, fix Pedantic warnings - Run Dartfmt - Refactoring - Removed empty tests --- analysis_options.yaml | 14 + example/lib/main.dart | 4 +- lib/flutter_json_widget.dart | 394 ++++++++++++++--------------- pubspec.yaml | 3 +- test/flutter_json_widget_test.dart | 13 - 5 files changed, 211 insertions(+), 217 deletions(-) create mode 100644 analysis_options.yaml delete mode 100644 test/flutter_json_widget_test.dart diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000..2e344c3 --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,14 @@ +# Defines a default set of lint rules enforced for +# projects at Google. For details and rationale, +# see https://github.com/dart-lang/pedantic#enabled-lints. +include: package:pedantic/analysis_options.yaml + +# For lint rules and documentation, see http://dart-lang.github.io/linter/lints. +# Uncomment to specify additional rules. +# linter: +# rules: +# - camel_case_types + +analyzer: + strong-mode: + implicit-casts: false diff --git a/example/lib/main.dart b/example/lib/main.dart index 8889133..d804aba 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -143,7 +143,7 @@ class _MyHomePageState extends State { true ] }'''; - jsonObj = jsonDecode(testString); + jsonObj = jsonDecode(testString) as Map; } @override @@ -167,7 +167,7 @@ class _MyHomePageState extends State { child: SingleChildScrollView( // Center is a layout widget. It takes a single child and positions it // in the middle of the parent. - child: JsonViewerWidget(jsonObj) + child: JsonViewerWidget(jsonObj, false) ), ); } diff --git a/lib/flutter_json_widget.dart b/lib/flutter_json_widget.dart index 74b9859..1cbaa29 100644 --- a/lib/flutter_json_widget.dart +++ b/lib/flutter_json_widget.dart @@ -3,266 +3,258 @@ library flutter_json_widget; import 'package:flutter/material.dart'; class JsonViewerWidget extends StatefulWidget { - final Map jsonObj; final bool notRoot; + final bool expandAll; - JsonViewerWidget (this.jsonObj, {this.notRoot}); + JsonViewerWidget(this.jsonObj, this.expandAll, {this.notRoot}); @override - JsonViewerWidgetState createState() => new JsonViewerWidgetState(); + JsonViewerWidgetState createState() => JsonViewerWidgetState(); } class JsonViewerWidgetState extends State { + final openFlag = {}; + bool expandAll; - Map openFlag = Map(); + @override + void didUpdateWidget(JsonViewerWidget oldWidget) { + if (oldWidget.expandAll != widget.expandAll) { + setState(() { + openFlag.clear(); + expandAll = widget.expandAll; + }); + } + super.didUpdateWidget(oldWidget); + } @override Widget build(BuildContext context) { - if(widget.notRoot??false){ - return - Container( - padding: EdgeInsets.only(left: 14.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: _getList()) - ); + expandAll ??= widget.expandAll; + if (widget.notRoot ?? false) { + return Container( + padding: EdgeInsets.only(left: 14.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: _getList(), + ), + ); } return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: _getList()); + crossAxisAlignment: CrossAxisAlignment.start, children: _getList()); } - _getList(){ - List list = List(); - for(MapEntry entry in widget.jsonObj.entries){ - bool ex = isExtensible(entry.value); - bool ink = isInkWell(entry.value); + List _getList() { + final list = []; + for (var entry in widget.jsonObj.entries) { + final ink = isInkWell(entry.value); list.add( - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ex?((openFlag[entry.key]??false)?Icon(Icons.arrow_drop_down, size: 14, color: Colors.grey[700]):Icon(Icons.arrow_right, size: 14, color: Colors.grey[700])):const Icon(Icons.arrow_right, color: Color.fromARGB(0, 0, 0, 0),size: 14,), - (ex&&ink)?InkWell( - child: Text(entry.key, style:TextStyle(color: Colors.purple[900])), - onTap: (){ - setState(() { - openFlag[entry.key] = !(openFlag[entry.key]??false); - }); - } - ):Text(entry.key, style:TextStyle(color: entry.value==null?Colors.grey:Colors.purple[900])), - Text(':', style: TextStyle(color: Colors.grey),), - const SizedBox(width: 3), - getValueWidget(entry) - ],) + InkWell( + onTap: ink + ? () { + setState(() { + openFlag[entry.key] = !(openFlag[entry.key] ?? expandAll); + expandAll = false; + }); + } + : null, + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + if (ink) + InkWell( + onTap: () { + setState(() { + openFlag[entry.key] = !(openFlag[entry.key] ?? expandAll); + expandAll = false; + }); + }, + child: Icon( + (openFlag[entry.key] ?? expandAll) + ? Icons.arrow_drop_down + : Icons.arrow_right, + size: 14, + color: Colors.grey[700]), + ) + else + Icon( + Icons.arrow_right, + color: Color.fromARGB(0, 0, 0, 0), + size: 14, + ), + Text( + entry.key, + style: TextStyle(color: Colors.purple[900]), + ), + Text( + ':', + style: TextStyle(color: Colors.grey), + ), + SizedBox(width: 3), + Flexible( + child: getValueWidget(entry.value), + ) + ], + ), + ), ); - list.add(const SizedBox(height: 4)); - if(openFlag[entry.key]??false){ - list.add(getContentWidget(entry.value)); + list.add(SizedBox(height: 4)); + if (ink && (openFlag[entry.key] ?? expandAll)) { + list.add(getContentWidget(entry.value, expandAll)); } } return list; } - - static getContentWidget(dynamic content){ - if(content is List){ - return JsonArrayViewerWidget(content, notRoot: true); - }else{ - return JsonViewerWidget(content, notRoot: true); - } - } - - static isInkWell(dynamic content){ - if(content == null){ - return false; - }else if (content is int){ - return false; - }else if (content is String) { - return false; - } else if (content is bool) { - return false; - } else if (content is double) { - return false; - } else if(content is List){ - if(content.isEmpty){ - return false; - }else { - return true; - } - } - return true; - } - - getValueWidget(MapEntry entry){ - if(entry.value == null){ - return Expanded(child: Text('undefined', style: TextStyle(color: Colors.grey),)); - }else if (entry.value is int){ - return Expanded(child: Text(entry.value.toString(), style: TextStyle(color: Colors.teal),)); - }else if (entry.value is String) { - return Expanded(child: Text('\"'+entry.value+'\"', style: TextStyle(color: Colors.redAccent),)); - } else if (entry.value is bool) { - return Expanded(child: Text(entry.value.toString(), style: TextStyle(color: Colors.purple),)); - } else if (entry.value is double) { - return Expanded(child: Text(entry.value.toString(), style: TextStyle(color: Colors.teal),)); - } else if(entry.value is List){ - if(entry.value.isEmpty){ - return Text('Array[0]', style: TextStyle(color: Colors.grey),); - }else { - return InkWell( - child: Text('Array<${getTypeName(entry.value[0])}>[${entry.value.length}]', style: TextStyle(color: Colors.grey),), - onTap: (){ - setState(() { - openFlag[entry.key] = !(openFlag[entry.key]??false); - }); - }); - } - } - return InkWell( - child: Text('Object', style: TextStyle(color: Colors.grey),), - onTap: (){ - setState(() { - openFlag[entry.key] = !(openFlag[entry.key]??false); - }); - }); - } - - static isExtensible(dynamic content){ - if(content == null){ - return false; - }else if(content is int){ - return false; - }else if (content is String) { - return false; - } else if (content is bool) { - return false; - } else if (content is double) { - return false; - } - return true; - } - - static getTypeName(dynamic content){ - if (content is int){ - return 'int'; - }else if (content is String) { - return 'String'; - } else if (content is bool) { - return 'bool'; - } else if (content is double) { - return 'double'; - } else if(content is List){ - return 'List'; - } - return 'Object'; - } - } class JsonArrayViewerWidget extends StatefulWidget { - final List jsonArray; final bool notRoot; - JsonArrayViewerWidget (this.jsonArray, {this.notRoot}); + final bool expandAll; + + JsonArrayViewerWidget(this.jsonArray, this.expandAll, {this.notRoot}); @override - _JsonArrayViewerWidgetState createState() => new _JsonArrayViewerWidgetState(); + _JsonArrayViewerWidgetState createState() => _JsonArrayViewerWidgetState(); } class _JsonArrayViewerWidgetState extends State { - List openFlag; + bool expandAll; + + @override + void didUpdateWidget(JsonArrayViewerWidget oldWidget) { + if (oldWidget.expandAll != widget.expandAll) { + setState(() { + openFlag = List(widget.jsonArray.length); + expandAll = widget.expandAll; + }); + } + super.didUpdateWidget(oldWidget); + } @override Widget build(BuildContext context) { - if(widget.notRoot??false){ + expandAll ??= widget.expandAll; + if (widget.notRoot ?? false) { return Container( padding: EdgeInsets.only(left: 14.0), child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: _getList()) - ); + crossAxisAlignment: CrossAxisAlignment.start, + children: _getList())); } return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: _getList()); + crossAxisAlignment: CrossAxisAlignment.start, children: _getList()); } @override - void initState(){ + void initState() { super.initState(); openFlag = List(widget.jsonArray.length); } - _getList(){ - List list = List(); - int i = 0; - for(dynamic content in widget.jsonArray){ - bool ex = JsonViewerWidgetState.isExtensible(content); - bool ink = JsonViewerWidgetState.isInkWell(content); + void Function() onTap(int index) => () => setState(() { + openFlag[index] = !(openFlag[index] ?? expandAll); + expandAll = false; + }); + + List _getList() { + final list = []; + var i = 0; + for (dynamic content in widget.jsonArray) { + final ink = isInkWell(content); list.add( - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ex?((openFlag[i]??false)?Icon(Icons.arrow_drop_down, size: 14, color: Colors.grey[700]):Icon(Icons.arrow_right, size: 14, color: Colors.grey[700])):const Icon(Icons.arrow_right, color: Color.fromARGB(0, 0, 0, 0),size: 14,), - (ex&&ink)?getInkWell(i):Text('[$i]', style:TextStyle(color: content==null?Colors.grey:Colors.purple[900])), - Text(':', style: TextStyle(color: Colors.grey),), - const SizedBox(width: 3), - getValueWidget(content, i) - ], - ) + InkWell( + onTap: ink ? onTap(i) : null, + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + if (ink) + Icon( + (openFlag[i] ?? expandAll) + ? Icons.arrow_drop_down + : Icons.arrow_right, + size: 14, + color: Colors.grey[700]), + Text( + '$i', + style: TextStyle(color: ink ? Colors.purple[900] : Colors.grey), + ), + Text( + ':', + style: TextStyle(color: Colors.grey), + ), + SizedBox(width: 3), + Flexible( + child: getValueWidget(content), + ) + ], + ), + ), ); - list.add(const SizedBox(height: 4)); - if(openFlag[i]??false){ - list.add(JsonViewerWidgetState.getContentWidget(content)); + list.add(SizedBox(height: 4)); + if (ink && (openFlag[i] ?? expandAll)) { + list.add(getContentWidget(content, expandAll)); } i++; } return list; } +} - getInkWell(int index){ - return InkWell( - child: Text('[$index]', style:TextStyle(color: Colors.purple[900])), - onTap: (){ - setState(() { - openFlag[index] = !(openFlag[index]??false); - }); - } +Widget getValueWidget(dynamic content) { + if (content == null) { + return Text( + 'null', + style: TextStyle(color: Colors.grey), + ); + } else if (content is int) { + return Text( + content.toString(), + style: TextStyle(color: Colors.teal), + ); + } else if (content is String) { + return Text( + '\"' + content + '\"', + style: TextStyle(color: Colors.redAccent), + ); + } else if (content is bool) { + return Text( + content.toString(), + style: TextStyle(color: Colors.purple), + ); + } else if (content is double) { + return Text( + content.toString(), + style: TextStyle(color: Colors.teal), + ); + } else if (content is List) { + return Text( + '[${content.length}]', + style: TextStyle(color: Colors.grey), ); } - getValueWidget(dynamic content, int index){ - if(content == null){ - return Expanded(child: Text('undefined', style: TextStyle(color: Colors.grey),)); - }else if (content is int){ - return Expanded(child: Text(content.toString(), style: TextStyle(color: Colors.teal),)); - }else if (content is String) { - return Expanded(child: Text('\"'+content+'\"', style: TextStyle(color: Colors.redAccent),)); - } else if (content is bool) { - return Expanded(child: Text(content.toString(), style: TextStyle(color: Colors.purple),)); - } else if (content is double) { - return Expanded(child: Text(content.toString(), style: TextStyle(color: Colors.teal),)); - } else if(content is List){ - if(content.isEmpty){ - return Text('Array[0]', style: TextStyle(color: Colors.grey),); - }else { - return InkWell( - child: Text('Array<${JsonViewerWidgetState.getTypeName(content)}>[${content.length}]', style: TextStyle(color: Colors.grey),), - onTap: (){ - setState(() { - openFlag[index] = !(openFlag[index]??false); - }); - }); - } - } - return InkWell( - child: Text('Object', style: TextStyle(color: Colors.grey),), - onTap: (){ - setState(() { - openFlag[index] = !(openFlag[index]??false); - }); - }); + return Text( + '{...}', + style: TextStyle(color: Colors.grey), + ); +} + +bool isInkWell(dynamic content) => + content != null && + (content is List || content is Map) && + content.isNotEmpty as bool; + +StatefulWidget getContentWidget(dynamic content, bool expandAll) { + if (content is List) { + return JsonArrayViewerWidget(content, expandAll, notRoot: true); + } else if (content is Map) { + return JsonViewerWidget(content, expandAll, notRoot: true); } -} \ No newline at end of file + throw Exception('${content.runtimeType} is not valid'); +} diff --git a/pubspec.yaml b/pubspec.yaml index d2d446c..3e1625a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -5,7 +5,7 @@ author: Apigj homepage: https://github.com/demdog/flutter_json_widget environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.3.0 <3.0.0" dependencies: flutter: @@ -14,6 +14,7 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter + pedantic: ^1.9.0 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/test/flutter_json_widget_test.dart b/test/flutter_json_widget_test.dart deleted file mode 100644 index c76e7b8..0000000 --- a/test/flutter_json_widget_test.dart +++ /dev/null @@ -1,13 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; - -import 'package:flutter_json_widget/flutter_json_widget.dart'; - -void main() { -// test('adds one to input values', () { -// final calculator = Calculator(); -// expect(calculator.addOne(2), 3); -// expect(calculator.addOne(-7), -6); -// expect(calculator.addOne(0), 1); -// expect(() => calculator.addOne(null), throwsNoSuchMethodError); -// }); -}