Unverified Commit 1ab20d6f authored by Shi-Hao Hong's avatar Shi-Hao Hong Committed by GitHub

[Stocks App] NNBD migration, refresh gen-l10n (#79460)

parent 9077a5c6
......@@ -16,3 +16,7 @@ output-localization-file: stock_strings.dart
## generating Flutter's localization files.
synthetic-package: false
template-arb-file: stocks_en.arb
## setting `nullable-getter` to false generates a non-nullable
## StockStrings getter. This removes the need for adding null checks
## in the Flutter application itself.
nullable-getter: false
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// THE FOLLLOWING FILES WERE GENERATED BY `flutter gen-l10n`.
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// THE FOLLLOWING FILES WERE GENERATED BY `flutter gen-l10n`.
import 'dart:async';
import 'package:flutter/foundation.dart';
......@@ -39,7 +41,7 @@ import 'stock_strings_es.dart';
/// # Internationalization support.
/// flutter_localizations:
/// sdk: flutter
/// intl: 0.16.1
/// intl: any # Use the pinned version from flutter_localizations
///
/// # rest of dependencies
/// ```
......@@ -64,12 +66,12 @@ import 'stock_strings_es.dart';
/// be consistent with the languages listed in the StockStrings.supportedLocales
/// property.
abstract class StockStrings {
StockStrings(String locale) : assert(locale != null), localeName = intl.Intl.canonicalizedLocale(locale.toString());
StockStrings(String locale) : localeName = intl.Intl.canonicalizedLocale(locale.toString());
final String localeName;
static StockStrings of(BuildContext context) {
return Localizations.of<StockStrings>(context, StockStrings);
return Localizations.of<StockStrings>(context, StockStrings)!;
}
static const LocalizationsDelegate<StockStrings> delegate = _StockStringsDelegate();
......@@ -98,13 +100,22 @@ abstract class StockStrings {
Locale('es')
];
// Title for the Stocks application
/// Title for the Stocks application
///
/// In en, this message translates to:
/// **'Stocks'**
String get title;
// Label for the Market tab
/// Label for the Market tab
///
/// In en, this message translates to:
/// **'MARKET'**
String get market;
// Label for the Portfolio tab
/// Label for the Portfolio tab
///
/// In en, this message translates to:
/// **'PORTFOLIO'**
String get portfolio;
}
......@@ -126,22 +137,27 @@ class _StockStringsDelegate extends LocalizationsDelegate<StockStrings> {
StockStrings _lookupStockStrings(Locale locale) {
// Lookup logic when language+country codes are specified.
switch (locale.languageCode) {
case 'en': {
switch (locale.countryCode) {
case 'US': return StockStringsEnUs();
}
break;
}
// Lookup logic when language+country codes are specified.
switch (locale.languageCode) {
case 'en': {
switch (locale.countryCode) {
case 'US': return StockStringsEnUs();
}
break;
}
}
// Lookup logic when only language code is specified.
switch (locale.languageCode) {
case 'en': return StockStringsEn();
// Lookup logic when only language code is specified.
switch (locale.languageCode) {
case 'en': return StockStringsEn();
case 'es': return StockStringsEs();
}
}
assert(false, 'StockStrings.delegate failed to load unsupported locale "$locale"');
return null;
throw FlutterError(
'StockStrings.delegate failed to load unsupported locale "$locale". This is likely '
'an issue with the localizations generation tool. Please file an issue '
'on GitHub with a reproducible sample app and the gen-l10n configuration '
'that was used.'
);
}
......@@ -2,6 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// THE FOLLLOWING FILES WERE GENERATED BY `flutter gen-l10n`.
import 'stock_strings.dart';
/// The translations for English (`en`).
......
......@@ -2,6 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// THE FOLLLOWING FILES WERE GENERATED BY `flutter gen-l10n`.
import 'stock_strings.dart';
/// The translations for Spanish Castilian (`es`).
......
......@@ -20,14 +20,14 @@ import 'stock_symbol_viewer.dart';
import 'stock_types.dart';
class StocksApp extends StatefulWidget {
const StocksApp({Key key}) : super(key: key);
const StocksApp({Key? key}) : super(key: key);
@override
StocksAppState createState() => StocksAppState();
}
class StocksAppState extends State<StocksApp> {
StockData stocks;
late StockData stocks = StockData();
StockConfiguration _configuration = StockConfiguration(
stockMode: StockMode.optimistic,
......@@ -42,12 +42,6 @@ class StocksAppState extends State<StocksApp> {
showSemanticsDebugger: false,
);
@override
void initState() {
super.initState();
stocks = StockData();
}
void configurationUpdater(StockConfiguration value) {
setState(() {
_configuration = value;
......@@ -67,16 +61,14 @@ class StocksAppState extends State<StocksApp> {
primarySwatch: Colors.purple,
);
}
assert(_configuration.stockMode != null);
return null;
}
Route<dynamic> _getRoute(RouteSettings settings) {
Route<dynamic>? _getRoute(RouteSettings settings) {
if (settings.name == '/stock') {
final String symbol = settings.arguments as String;
final String? symbol = settings.arguments as String?;
return MaterialPageRoute<void>(
settings: settings,
builder: (BuildContext context) => StockSymbolPage(symbol: symbol, stocks: stocks),
builder: (BuildContext context) => StockSymbolPage(symbol: symbol!, stocks: stocks),
);
}
// The other paths we support are in the routes table.
......
......@@ -7,7 +7,10 @@ import 'dart:math' as math;
import 'package:flutter/material.dart';
class StockArrowPainter extends CustomPainter {
StockArrowPainter({ this.color, this.percentChange });
StockArrowPainter({
required this.color,
required this.percentChange,
});
final Color color;
final double percentChange;
......@@ -53,7 +56,7 @@ class StockArrowPainter extends CustomPainter {
}
class StockArrow extends StatelessWidget {
const StockArrow({ Key key, this.percentChange }) : super(key: key);
const StockArrow({ Key? key, required this.percentChange }) : super(key: key);
final double percentChange;
......@@ -65,8 +68,8 @@ class StockArrow extends StatelessWidget {
Color _colorForPercentChange(double percentChange) {
if (percentChange > 0)
return Colors.green[_colorIndexForPercentChange(percentChange)];
return Colors.red[_colorIndexForPercentChange(percentChange)];
return Colors.green[_colorIndexForPercentChange(percentChange)]!;
return Colors.red[_colorIndexForPercentChange(percentChange)]!;
}
@override
......
......@@ -31,11 +31,11 @@ class Stock {
percentChange = (_rng.nextDouble() * 20) - 10;
}
String symbol;
String name;
double lastSale;
String marketCap;
double percentChange;
late String symbol;
late String name;
late double lastSale;
late String marketCap;
late double percentChange;
}
class StockData extends ChangeNotifier {
......@@ -51,7 +51,7 @@ class StockData extends ChangeNotifier {
List<String> get allSymbols => _symbols;
Stock operator [](String symbol) => _stocks[symbol];
Stock? operator [](String symbol) => _stocks[symbol];
bool get loading => _httpClient != null;
......@@ -71,12 +71,12 @@ class StockData extends ChangeNotifier {
Uri _urlToFetch(int chunk) => Uri.https(
'domokit.github.io', 'examples/stocks/data/stock_data_$chunk.json');
http.Client _httpClient;
http.Client? _httpClient;
static bool actuallyFetchData = true;
void _fetchNextChunk() {
_httpClient.get(_urlToFetch(_nextChunk++)).then<void>((http.Response response) {
_httpClient!.get(_urlToFetch(_nextChunk++)).then<void>((http.Response response) {
final String json = response.body;
if (json == null) {
debugPrint('Failed to load stock data chunk ${_nextChunk - 1}');
......@@ -94,7 +94,7 @@ class StockData extends ChangeNotifier {
}
void _end() {
_httpClient?.close();
_httpClient!.close();
_httpClient = null;
}
}
......@@ -52,7 +52,7 @@ class _NotImplementedDialog extends StatelessWidget {
}
class StockHome extends StatefulWidget {
const StockHome(this.stocks, this.configuration, this.updater, {Key key}) : super(key: key);
const StockHome(this.stocks, this.configuration, this.updater, {Key? key}) : super(key: key);
final StockData stocks;
final StockConfiguration configuration;
......@@ -69,7 +69,7 @@ class StockHomeState extends State<StockHome> {
bool _autorefresh = false;
void _handleSearchBegin() {
ModalRoute.of(context).addLocalHistoryEntry(LocalHistoryEntry(
ModalRoute.of(context)!.addLocalHistoryEntry(LocalHistoryEntry(
onRemove: () {
setState(() {
_isSearching = false;
......@@ -82,7 +82,7 @@ class StockHomeState extends State<StockHome> {
});
}
void _handleStockModeChange(StockMode value) {
void _handleStockModeChange(StockMode? value) {
if (widget.updater != null)
widget.updater(widget.configuration.copyWith(stockMode: value));
}
......@@ -231,8 +231,9 @@ class StockHomeState extends State<StockHome> {
}
static Iterable<Stock> _getStockList(StockData stocks, Iterable<String> symbols) {
return symbols.map<Stock>((String symbol) => stocks[symbol])
.where((Stock stock) => stock != null);
return symbols.map<Stock?>((String symbol) => stocks[symbol])
.where((Stock? stock) => stock != null)
.cast<Stock>();
}
Iterable<Stock> _filterBySearchQuery(Iterable<Stock> stocks) {
......@@ -266,7 +267,7 @@ class StockHomeState extends State<StockHome> {
Navigator.pushNamed(context, '/stock', arguments: stock.symbol);
},
onShow: (Stock stock) {
_scaffoldKey.currentState.showBottomSheet<void>((BuildContext context) => StockSymbolBottomSheet(stock: stock));
_scaffoldKey.currentState!.showBottomSheet<void>((BuildContext context) => StockSymbolBottomSheet(stock: stock));
},
);
}
......@@ -275,7 +276,7 @@ class StockHomeState extends State<StockHome> {
return AnimatedBuilder(
key: ValueKey<StockHomeTab>(tab),
animation: Listenable.merge(<Listenable>[_searchQuery, widget.stocks]),
builder: (BuildContext context, Widget child) {
builder: (BuildContext context, Widget? child) {
return _buildStockList(context, _filterBySearchQuery(_getStockList(widget.stocks, stockSymbols)).toList(), tab);
},
);
......
......@@ -8,7 +8,13 @@ import 'stock_data.dart';
import 'stock_row.dart';
class StockList extends StatelessWidget {
const StockList({ Key key, this.stocks, this.onOpen, this.onShow, this.onAction }) : super(key: key);
const StockList({
Key? key,
required this.stocks,
required this.onOpen,
required this.onShow,
required this.onAction,
}) : super(key: key);
final List<Stock> stocks;
final StockRowActionCallback onOpen;
......
......@@ -11,20 +11,20 @@ typedef StockRowActionCallback = void Function(Stock stock);
class StockRow extends StatelessWidget {
StockRow({
this.stock,
required this.stock,
this.onPressed,
this.onDoubleTap,
this.onLongPressed,
}) : super(key: ObjectKey(stock));
final Stock stock;
final StockRowActionCallback onPressed;
final StockRowActionCallback onDoubleTap;
final StockRowActionCallback onLongPressed;
final StockRowActionCallback? onPressed;
final StockRowActionCallback? onDoubleTap;
final StockRowActionCallback? onLongPressed;
static const double kHeight = 79.0;
GestureTapCallback _getHandler(StockRowActionCallback callback) {
GestureTapCallback? _getHandler(StockRowActionCallback? callback) {
return callback == null ? null : () => callback(stock);
}
......
......@@ -7,7 +7,7 @@ import 'package:flutter/material.dart';
import 'stock_types.dart';
class StockSettings extends StatefulWidget {
const StockSettings(this.configuration, this.updater, {Key key}) : super(key: key);
const StockSettings(this.configuration, this.updater, {Key? key}) : super(key: key);
final StockConfiguration configuration;
final ValueChanged<StockConfiguration> updater;
......@@ -17,7 +17,7 @@ class StockSettings extends StatefulWidget {
}
class StockSettingsState extends State<StockSettings> {
void _handleOptimismChanged(bool value) {
void _handleOptimismChanged(bool? value) {
value ??= false;
sendUpdates(widget.configuration.copyWith(stockMode: value ? StockMode.optimistic : StockMode.pessimistic));
}
......@@ -111,7 +111,7 @@ class StockSettingsState extends State<StockSettings> {
onTap: _confirmOptimismChange,
trailing: Checkbox(
value: widget.configuration.stockMode == StockMode.optimistic,
onChanged: (bool value) => _confirmOptimismChange(),
onChanged: (bool? value) => _confirmOptimismChange(),
),
),
ListTile(
......
......@@ -8,7 +8,10 @@ import 'stock_arrow.dart';
import 'stock_data.dart';
class _StockSymbolView extends StatelessWidget {
const _StockSymbolView({ this.stock, this.arrow });
const _StockSymbolView({
required this.stock,
required this.arrow,
});
final Stock stock;
final Widget arrow;
......@@ -21,7 +24,7 @@ class _StockSymbolView extends StatelessWidget {
if (stock.percentChange > 0)
changeInPrice = '+' + changeInPrice;
final TextStyle headings = Theme.of(context).textTheme.bodyText1;
final TextStyle headings = Theme.of(context).textTheme.bodyText1!;
return Container(
padding: const EdgeInsets.all(20.0),
child: Column(
......@@ -65,7 +68,11 @@ class _StockSymbolView extends StatelessWidget {
}
class StockSymbolPage extends StatelessWidget {
const StockSymbolPage({ Key key, this.symbol, this.stocks }) : super(key: key);
const StockSymbolPage({
Key? key,
required this.symbol,
required this.stocks,
}) : super(key: key);
final String symbol;
final StockData stocks;
......@@ -74,8 +81,8 @@ class StockSymbolPage extends StatelessWidget {
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: stocks,
builder: (BuildContext context, Widget child) {
final Stock stock = stocks[symbol];
builder: (BuildContext context, Widget? child) {
final Stock? stock = stocks[symbol];
return Scaffold(
appBar: AppBar(
title: Text(stock?.name ?? symbol),
......@@ -113,7 +120,10 @@ class StockSymbolPage extends StatelessWidget {
}
class StockSymbolBottomSheet extends StatelessWidget {
const StockSymbolBottomSheet({ Key key, this.stock }) : super(key: key);
const StockSymbolBottomSheet({
Key? key,
required this.stock,
}) : super(key: key);
final Stock stock;
......
......@@ -2,23 +2,21 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/foundation.dart';
enum StockMode { optimistic, pessimistic }
enum BackupMode { enabled, disabled }
class StockConfiguration {
StockConfiguration({
@required this.stockMode,
@required this.backupMode,
@required this.debugShowGrid,
@required this.debugShowSizes,
@required this.debugShowBaselines,
@required this.debugShowLayers,
@required this.debugShowPointers,
@required this.debugShowRainbow,
@required this.showPerformanceOverlay,
@required this.showSemanticsDebugger,
required this.stockMode,
required this.backupMode,
required this.debugShowGrid,
required this.debugShowSizes,
required this.debugShowBaselines,
required this.debugShowLayers,
required this.debugShowPointers,
required this.debugShowRainbow,
required this.showPerformanceOverlay,
required this.showSemanticsDebugger,
}) : assert(stockMode != null),
assert(backupMode != null),
assert(debugShowGrid != null),
......@@ -42,16 +40,16 @@ class StockConfiguration {
final bool showSemanticsDebugger;
StockConfiguration copyWith({
StockMode stockMode,
BackupMode backupMode,
bool debugShowGrid,
bool debugShowSizes,
bool debugShowBaselines,
bool debugShowLayers,
bool debugShowPointers,
bool debugShowRainbow,
bool showPerformanceOverlay,
bool showSemanticsDebugger,
StockMode? stockMode,
BackupMode? backupMode,
bool? debugShowGrid,
bool? debugShowSizes,
bool? debugShowBaselines,
bool? debugShowLayers,
bool? debugShowPointers,
bool? debugShowRainbow,
bool? showPerformanceOverlay,
bool? showSemanticsDebugger,
}) {
return StockConfiguration(
stockMode: stockMode ?? this.stockMode,
......
name: stocks
environment:
sdk: ">=2.0.0-dev.68.0 <3.0.0"
sdk: ">=2.12.0 <3.0.0"
dependencies:
flutter:
......
......@@ -9,7 +9,7 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:stocks/main.dart' as stocks;
import 'package:stocks/stock_data.dart' as stock_data;
Element findElementOfExactWidgetTypeGoingDown(Element node, Type targetType) {
Element? findElementOfExactWidgetTypeGoingDown(Element node, Type targetType) {
void walker(Element child) {
if (child.widget.runtimeType == targetType)
throw child;
......@@ -23,12 +23,14 @@ Element findElementOfExactWidgetTypeGoingDown(Element node, Type targetType) {
return null;
}
Element findElementOfExactWidgetTypeGoingUp(Element node, Type targetType) {
Element result;
Element? findElementOfExactWidgetTypeGoingUp(Element node, Type targetType) {
Element? result;
bool walker(Element ancestor) {
if (ancestor.widget.runtimeType == targetType)
if (ancestor.widget.runtimeType == targetType) {
result = ancestor;
return result == null;
return false;
}
return true;
}
node.visitAncestorElements(walker);
return result;
......@@ -37,11 +39,10 @@ Element findElementOfExactWidgetTypeGoingUp(Element node, Type targetType) {
final RegExp materialIconAssetNameColorExtractor = RegExp(r'[^/]+/ic_.+_(white|black)_[0-9]+dp\.png');
void checkIconColor(WidgetTester tester, String label, Color color) {
final Element listTile = findElementOfExactWidgetTypeGoingUp(tester.element(find.text(label)), ListTile);
expect(listTile, isNotNull);
final Element asset = findElementOfExactWidgetTypeGoingDown(listTile, RichText);
final Element listTile = findElementOfExactWidgetTypeGoingUp(tester.element(find.text(label)), ListTile)!;
final Element asset = findElementOfExactWidgetTypeGoingDown(listTile, RichText)!;
final RichText richText = asset.widget as RichText;
expect(richText.text.style.color, equals(color));
expect(richText.text.style!.color, equals(color));
}
void main() {
......
......@@ -9,15 +9,14 @@ import 'package:test/test.dart' hide TypeMatcher, isInstanceOf;
void main() {
group('scrolling performance test', () {
FlutterDriver driver;
late FlutterDriver driver;
setUpAll(() async {
driver = await FlutterDriver.connect();
});
tearDownAll(() async {
if (driver != null)
driver.close();
driver.close();
});
test('measure', () async {
......
......@@ -9,16 +9,14 @@ import 'package:test/test.dart' hide TypeMatcher, isInstanceOf;
void main() {
group('basic stock view test', () {
FlutterDriver driver;
late FlutterDriver driver;
setUpAll(() async {
driver = await FlutterDriver.connect();
});
tearDownAll(() async {
if (driver != null) {
driver.close();
}
driver.close();
});
test('Stock list is shown', () async {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment