stock_symbol_viewer.dart 4.14 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

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

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

78 79
  final String symbol;
  final StockData stocks;
80

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

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

  final Stock stock;
Hixie's avatar
Hixie committed
130

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