main.dart 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. import 'dart:convert';
  2. import 'package:flutter/material.dart';
  3. import 'package:flutter/services.dart';
  4. import 'package:http/http.dart' as http;
  5. import 'package:k_chart_plus/k_chart_plus.dart';
  6. void main() => runApp(const MyApp());
  7. class MyApp extends StatelessWidget {
  8. const MyApp({super.key});
  9. @override
  10. Widget build(BuildContext context) {
  11. return MaterialApp(
  12. title: 'Flutter Demo',
  13. theme: ThemeData(
  14. primarySwatch: Colors.deepPurple,
  15. ),
  16. home: const MyHomePage(title: 'Flutter Demo Home Page'),
  17. );
  18. }
  19. }
  20. class MyHomePage extends StatefulWidget {
  21. const MyHomePage({Key? key, this.title}) : super(key: key);
  22. final String? title;
  23. @override
  24. State<MyHomePage> createState() => _MyHomePageState();
  25. }
  26. class _MyHomePageState extends State<MyHomePage> {
  27. List<KLineEntity>? datas;
  28. bool showLoading = true;
  29. bool _volHidden = false;
  30. // final Set<SecondaryState> _secondaryStateLi = <SecondaryState>{};
  31. final List<MainState> _mainStateLi = [];
  32. final List<SecondaryState> _secondaryStateLi = [];
  33. List<DepthEntity>? _bids, _asks;
  34. ChartStyle chartStyle = ChartStyle();
  35. ChartColors chartColors = ChartColors();
  36. @override
  37. void initState() {
  38. super.initState();
  39. getData('1day');
  40. rootBundle.loadString('assets/depth.json').then((result) {
  41. final parseJson = json.decode(result);
  42. final tick = parseJson['tick'] as Map<String, dynamic>;
  43. final List<DepthEntity> bids = (tick['bids'] as List<dynamic>)
  44. .map<DepthEntity>(
  45. (item) => DepthEntity(item[0] as double, item[1] as double))
  46. .toList();
  47. final List<DepthEntity> asks = (tick['asks'] as List<dynamic>)
  48. .map<DepthEntity>(
  49. (item) => DepthEntity(item[0] as double, item[1] as double))
  50. .toList();
  51. initDepth(bids, asks);
  52. });
  53. }
  54. void initDepth(List<DepthEntity>? bids, List<DepthEntity>? asks) {
  55. if (bids == null || asks == null || bids.isEmpty || asks.isEmpty) return;
  56. _bids = [];
  57. _asks = [];
  58. double amount = 0.0;
  59. bids.sort((left, right) => left.price.compareTo(right.price));
  60. for (var item in bids.reversed) {
  61. amount += item.vol;
  62. item.vol = amount;
  63. _bids!.insert(0, item);
  64. }
  65. amount = 0.0;
  66. asks.sort((left, right) => left.price.compareTo(right.price));
  67. for (var item in asks) {
  68. amount += item.vol;
  69. item.vol = amount;
  70. _asks!.add(item);
  71. }
  72. setState(() {});
  73. }
  74. @override
  75. Widget build(BuildContext context) {
  76. return Scaffold(
  77. body: ListView(
  78. shrinkWrap: true,
  79. children: <Widget>[
  80. const SafeArea(bottom: false, child: SizedBox(height: 10)),
  81. Stack(children: <Widget>[
  82. KChartWidget(
  83. datas,
  84. chartStyle,
  85. chartColors,
  86. mBaseHeight: 360,
  87. isTrendLine: false,
  88. mainStateLi: _mainStateLi.toSet(),
  89. volHidden: _volHidden,
  90. secondaryStateLi: _secondaryStateLi.toSet(),
  91. fixedLength: 2,
  92. timeFormat: TimeFormat.YEAR_MONTH_DAY,
  93. ),
  94. if (showLoading)
  95. Container(
  96. width: double.infinity,
  97. height: 450,
  98. alignment: Alignment.center,
  99. child: const CircularProgressIndicator(),
  100. ),
  101. ]),
  102. _buildTitle(context, 'VOL'),
  103. buildVolButton(),
  104. _buildTitle(context, 'Main State'),
  105. buildMainButtons(),
  106. _buildTitle(context, 'Secondary State'),
  107. buildSecondButtons(),
  108. const SizedBox(height: 30),
  109. if (_bids != null && _asks != null)
  110. Container(
  111. color: Colors.white,
  112. height: 320,
  113. width: double.infinity,
  114. child: DepthChart(
  115. _bids!,
  116. _asks!,
  117. chartColors,
  118. ),
  119. )
  120. ],
  121. ),
  122. );
  123. }
  124. Widget _buildTitle(BuildContext context, String title) {
  125. return Padding(
  126. padding: const EdgeInsets.fromLTRB(16, 20, 12, 15),
  127. child: Text(
  128. title,
  129. style: Theme.of(context).textTheme.bodyMedium?.copyWith(
  130. // color: Colors.white,
  131. fontWeight: FontWeight.w600,
  132. ),
  133. ),
  134. );
  135. }
  136. Widget buildVolButton() {
  137. return Padding(
  138. padding: const EdgeInsets.symmetric(horizontal: 16),
  139. child: Align(
  140. alignment: Alignment.centerLeft,
  141. child: _buildButton(
  142. context: context,
  143. title: 'VOL',
  144. isActive: !_volHidden,
  145. onPress: () {
  146. _volHidden = !_volHidden;
  147. setState(() {});
  148. }),
  149. ),
  150. );
  151. }
  152. Widget buildMainButtons() {
  153. return Padding(
  154. padding: const EdgeInsets.symmetric(horizontal: 16),
  155. child: Wrap(
  156. alignment: WrapAlignment.start,
  157. spacing: 10,
  158. runSpacing: 10,
  159. children: MainState.values.map((e) {
  160. bool isActive = _mainStateLi.contains(e);
  161. return _buildButton(
  162. context: context,
  163. title: e.name,
  164. isActive: isActive,
  165. onPress: () {
  166. if (isActive) {
  167. _mainStateLi.remove(e);
  168. } else {
  169. _mainStateLi.add(e);
  170. }
  171. },
  172. );
  173. }).toList(),
  174. ),
  175. );
  176. }
  177. Widget buildSecondButtons() {
  178. return Padding(
  179. padding: const EdgeInsets.symmetric(horizontal: 16),
  180. child: Wrap(
  181. alignment: WrapAlignment.start,
  182. spacing: 10,
  183. runSpacing: 5,
  184. children: SecondaryState.values.map((e) {
  185. bool isActive = _secondaryStateLi.contains(e);
  186. return _buildButton(
  187. context: context,
  188. title: e.name,
  189. isActive: _secondaryStateLi.contains(e),
  190. onPress: () {
  191. if (isActive) {
  192. _secondaryStateLi.remove(e);
  193. } else {
  194. _secondaryStateLi.add(e);
  195. }
  196. },
  197. );
  198. }).toList(),
  199. ),
  200. );
  201. }
  202. Widget _buildButton({
  203. required BuildContext context,
  204. required String title,
  205. required isActive,
  206. required Function onPress,
  207. }) {
  208. late Color? bgColor, txtColor;
  209. if (isActive) {
  210. bgColor = Theme.of(context).primaryColor.withAlpha(30);
  211. txtColor = Theme.of(context).primaryColor;
  212. } else {
  213. bgColor = Colors.transparent;
  214. txtColor = Theme.of(context).textTheme.bodyMedium?.color;
  215. }
  216. return InkWell(
  217. onTap: () {
  218. onPress();
  219. setState(() {});
  220. },
  221. child: Container(
  222. decoration: BoxDecoration(
  223. color: bgColor,
  224. borderRadius: BorderRadius.circular(6),
  225. ),
  226. constraints: const BoxConstraints(minWidth: 60),
  227. padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10),
  228. child: Text(
  229. title,
  230. style: Theme.of(context).textTheme.bodyMedium?.copyWith(
  231. color: txtColor,
  232. ),
  233. textAlign: TextAlign.center,
  234. ),
  235. ),
  236. );
  237. }
  238. void getData(String period) {
  239. final Future<String> future = getChatDataFromInternet(period);
  240. //final Future<String> future = getChatDataFromJson();
  241. future.then((String result) {
  242. solveChatData(result);
  243. }).catchError((_) {
  244. showLoading = false;
  245. setState(() {});
  246. debugPrint('### datas error $_');
  247. });
  248. }
  249. Future<String> getChatDataFromInternet(String? period) async {
  250. var url =
  251. 'https://api.huobi.br.com/market/history/kline?period=${period ?? '1day'}&size=300&symbol=btcusdt';
  252. late String result;
  253. final response = await http.get(Uri.parse(url));
  254. if (response.statusCode == 200) {
  255. result = response.body;
  256. } else {
  257. debugPrint('Failed getting IP address');
  258. }
  259. return result;
  260. }
  261. Future<String> getChatDataFromJson() async {
  262. return rootBundle.loadString('assets/chatData.json');
  263. }
  264. void solveChatData(String result) {
  265. final Map parseJson = json.decode(result) as Map<dynamic, dynamic>;
  266. final list = parseJson['data'] as List<dynamic>;
  267. datas = list
  268. .map((item) => KLineEntity.fromJson(item as Map<String, dynamic>))
  269. .toList()
  270. .reversed
  271. .toList()
  272. .cast<KLineEntity>();
  273. DataUtil.calculate(datas!);
  274. showLoading = false;
  275. setState(() {});
  276. }
  277. }