stock_symbol_viewer.dart 4.16 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
Hixie's avatar
Hixie committed
2 3 4
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6 7
import 'package:flutter/material.dart';

import 'stock_arrow.dart';
8
import 'stock_data.dart';
Hixie's avatar
Hixie committed
9

10
class _StockSymbolView extends StatelessWidget {
11 12 13 14
  const _StockSymbolView({
    required this.stock,
    required this.arrow,
  });
Hixie's avatar
Hixie committed
15 16

  final Stock stock;
17
  final Widget arrow;
Hixie's avatar
Hixie committed
18

19
  @override
Hixie's avatar
Hixie committed
20
  Widget build(BuildContext context) {
21
    assert(stock != null);
22 23
    final String lastSale = '\$${stock.lastSale.toStringAsFixed(2)}';
    String changeInPrice = '${stock.percentChange.toStringAsFixed(2)}%';
24
    if (stock.percentChange > 0)
25
      changeInPrice = '+$changeInPrice';
26

27
    final TextStyle headings = Theme.of(context).textTheme.bodyText1!;
28
    return Container(
29
      padding: const EdgeInsets.all(20.0),
30
      child: Column(
31
        mainAxisSize: MainAxisSize.min,
32
        children: <Widget>[
33
          Row(
34
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
35
            children: <Widget>[
36
              Text(
37
                stock.symbol,
38
                key: ValueKey<String>('${stock.symbol}_symbol_name'),
39
                style: Theme.of(context).textTheme.headline3,
40
              ),
41
              arrow,
42 43
            ],
          ),
44 45 46
          Text('Last Sale', style: headings),
          Text('$lastSale ($changeInPrice)'),
          Container(
47 48
            height: 8.0
          ),
49
          Text('Market Cap', style: headings),
50
          Text(stock.marketCap),
51
          Container(
52 53
            height: 8.0
          ),
54 55
          RichText(
            text: TextSpan(
56
              style: DefaultTextStyle.of(context).style.merge(const TextStyle(fontSize: 8.0)),
57
              text: 'Prices may be delayed by ',
58
              children: const <TextSpan>[
59 60
                TextSpan(text: 'several', style: TextStyle(fontStyle: FontStyle.italic)),
                TextSpan(text: ' years.'),
61 62
              ],
            ),
63
          ),
64
        ],
65
      ),
66 67 68 69
    );
  }
}

70
class StockSymbolPage extends StatelessWidget {
71 72 73 74 75
  const StockSymbolPage({
    Key? key,
    required this.symbol,
    required this.stocks,
  }) : super(key: key);
76

77 78
  final String symbol;
  final StockData stocks;
79

80
  @override
81
  Widget build(BuildContext context) {
82
    return AnimatedBuilder(
83
      animation: stocks,
84 85
      builder: (BuildContext context, Widget? child) {
        final Stock? stock = stocks[symbol];
86 87
        return Scaffold(
          appBar: AppBar(
88
            title: Text(stock?.name ?? symbol),
89
          ),
90 91
          body: SingleChildScrollView(
            child: Container(
92
              margin: const EdgeInsets.all(20.0),
93 94
              child: Card(
                child: AnimatedCrossFade(
95 96
                  duration: const Duration(milliseconds: 300),
                  firstChild: const Padding(
97 98
                    padding: EdgeInsets.all(20.0),
                    child: Center(child: CircularProgressIndicator()),
99 100
                  ),
                  secondChild: stock != null
101
                    ? _StockSymbolView(
102
                      stock: stock,
103
                      arrow: Hero(
104
                        tag: stock,
105
                        child: StockArrow(percentChange: stock.percentChange),
106
                      ),
107
                    ) : Padding(
108
                        padding: const EdgeInsets.all(20.0),
109
                        child: Center(child: Text('$symbol not found')),
110 111 112
                    ),
                  crossFadeState: stock == null && stocks.loading ? CrossFadeState.showFirst : CrossFadeState.showSecond,
                ),
113 114 115
              ),
            ),
          ),
116 117
        );
      },
Hixie's avatar
Hixie committed
118 119
    );
  }
120 121
}

122
class StockSymbolBottomSheet extends StatelessWidget {
123 124 125 126
  const StockSymbolBottomSheet({
    Key? key,
    required this.stock,
  }) : super(key: key);
127 128

  final Stock stock;
Hixie's avatar
Hixie committed
129

130
  @override
131
  Widget build(BuildContext context) {
132
    return Container(
133
      padding: const EdgeInsets.all(10.0),
134
      decoration: const BoxDecoration(
135
        border: Border(top: BorderSide(color: Colors.black26))
136
      ),
137
      child: _StockSymbolView(
138
        stock: stock,
139 140
        arrow: StockArrow(percentChange: stock.percentChange),
      ),
141 142
   );
  }
Hixie's avatar
Hixie committed
143
}