| 1 | // Copyright 2014 The Flutter Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | // Snapshot from http://www.nasdaq.com/screening/company-list.aspx |
| 6 | // Fetched 2/23/2014. |
| 7 | // "Symbol","Name","LastSale","MarketCap","IPOyear","Sector","industry","Summary Quote", |
| 8 | // Data in stock_data.json |
| 9 | |
| 10 | import 'dart:convert'; |
| 11 | import 'dart:math' as math; |
| 12 | |
| 13 | import 'package:flutter/foundation.dart'; |
| 14 | import 'package:http/http.dart' as http; |
| 15 | |
| 16 | final math.Random _rng = math.Random(); |
| 17 | |
| 18 | class Stock { |
| 19 | Stock(this.symbol, this.name, this.lastSale, this.marketCap, this.percentChange); |
| 20 | |
| 21 | Stock.fromFields(List<String> fields) { |
| 22 | // TODO(jackson): This class should only have static data, not lastSale, etc. |
| 23 | // "Symbol","Name","LastSale","MarketCap","IPOyear","Sector","industry","Summary Quote", |
| 24 | lastSale = 0.0; |
| 25 | try { |
| 26 | lastSale = double.parse(fields[2]); |
| 27 | } catch (_) {} |
| 28 | symbol = fields[0]; |
| 29 | name = fields[1]; |
| 30 | marketCap = fields[4]; |
| 31 | percentChange = (_rng.nextDouble() * 20) - 10; |
| 32 | } |
| 33 | |
| 34 | late String symbol; |
| 35 | late String name; |
| 36 | late double lastSale; |
| 37 | late String marketCap; |
| 38 | late double percentChange; |
| 39 | } |
| 40 | |
| 41 | class StockData extends ChangeNotifier { |
| 42 | StockData() { |
| 43 | if (actuallyFetchData) { |
| 44 | _httpClient = http.Client(); |
| 45 | _fetchNextChunk(); |
| 46 | } |
| 47 | } |
| 48 | |
| 49 | final List<String> _symbols = <String>[]; |
| 50 | final Map<String, Stock> _stocks = <String, Stock>{}; |
| 51 | |
| 52 | List<String> get allSymbols => _symbols; |
| 53 | |
| 54 | Stock? operator [](String symbol) => _stocks[symbol]; |
| 55 | |
| 56 | bool get loading => _httpClient != null; |
| 57 | |
| 58 | void add(List<dynamic> data) { |
| 59 | for (final List<dynamic> fields in data.cast<List<dynamic>>()) { |
| 60 | final Stock stock = Stock.fromFields(fields.cast<String>()); |
| 61 | _symbols.add(stock.symbol); |
| 62 | _stocks[stock.symbol] = stock; |
| 63 | } |
| 64 | _symbols.sort(); |
| 65 | notifyListeners(); |
| 66 | } |
| 67 | |
| 68 | static const int _chunkCount = 30; |
| 69 | int _nextChunk = 0; |
| 70 | |
| 71 | Uri _urlToFetch(int chunk) => |
| 72 | Uri.https('domokit.github.io' , 'examples/stocks/data/stock_data_ $chunk.json' ); |
| 73 | |
| 74 | http.Client? _httpClient; |
| 75 | |
| 76 | static bool actuallyFetchData = true; |
| 77 | |
| 78 | void _fetchNextChunk() { |
| 79 | _httpClient!.get(_urlToFetch(_nextChunk++)).then<void>((http.Response response) { |
| 80 | final String json = response.body; |
| 81 | const JsonDecoder decoder = JsonDecoder(); |
| 82 | add(decoder.convert(json) as List<dynamic>); |
| 83 | if (_nextChunk < _chunkCount) { |
| 84 | _fetchNextChunk(); |
| 85 | } else { |
| 86 | _end(); |
| 87 | } |
| 88 | }); |
| 89 | } |
| 90 | |
| 91 | void _end() { |
| 92 | _httpClient!.close(); |
| 93 | _httpClient = null; |
| 94 | } |
| 95 | } |
| 96 | |