-
Notifications
You must be signed in to change notification settings - Fork 247
[102] Complete #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[102] Complete #3
Conversation
MDC-102/complete/lib/home.dart
Outdated
Expanded( | ||
child: Padding( | ||
padding: EdgeInsets.fromLTRB( | ||
16.0, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did the flutter formatter put all these numbers on their own lines? Because that's the first time I've seen positional parameters split out like that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It did.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it does that only if the last one ends in a comma.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mind blown.
MDC-102/complete/lib/home.dart
Outdated
), | ||
SizedBox(height: 8.0), | ||
// TODO(larche): Make subtitle2 when available | ||
Text('${products[index].priceString}', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
products[index].priceString
is already a string, unless I'm mistaken. The string interpolation should be unnecessary here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, duh. Yeah :)
|
||
final String priceString; | ||
|
||
const Product(category, id, isFeatured, name, price, priceString) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider named parameters here with @required from dart/meta. Six positional parameters is a lot to remember/get right each time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having this constructor isn't actually necessary anymore. It was when I was trying to have the formatter live in the class and format on creation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But did the @required
on the next one.
MDC-102/complete/lib/model/data.dart
Outdated
|
||
import 'product.dart'; | ||
|
||
List<Product> allProducts = generateProducts(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure how much kibitzing you're looking for here, but I would recommend refactoring this code a bit
- Get rid of
allProducts
, which I don't think is being used. - Change
formatter
to be a parameter in the call togenerateProducts()
. - Change
getData
to return Future<List<Product>> rather than Future<Null> - Change
_HomePageState
to have a member variable calledallProducts
of typeList<Product>
- In the initState method for
HomePage
(line 61) of previous file, do this:
getData().then((list)` =>
setState(() {
allProducts = list;
});
);
That puts a copy of the products to be displayed into the State
object, and avoids having an empty setState
call, which I've heard is a code smell for Flutter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, I couldn't do exactly that because I needed to have a default value for the formatter incase the async method took too long (which I've seen.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PTAL
MDC-102/complete/lib/home.dart
Outdated
icon: Icon(Icons.menu), | ||
onPressed: () { | ||
print('Menu button'); | ||
}), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
General comment, I think it might be a style guidance to put a comma after each parameter, so the end ) of IconButton matches the indent of leading
. Same for below, where there'd be a comma after childAspectRatio: 8.0 / 9.0,
so that the last ),
matches the child
indent. Might want to verify w Flutter team
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes you are correct! I had that wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I went thru and added them anywhere I could catch. It really improved the formatting!
MDC-102/complete/lib/main.dart
Outdated
|
||
import 'package:flutter/material.dart'; | ||
|
||
void main() => runApp(new ShrineApp()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this can just be ShrineApp()
, no need new
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
MDC-102/complete/lib/home.dart
Outdated
} | ||
|
||
class _HomePageState extends State<HomePage> { | ||
List<Product> allProducts = generateProducts(null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than catching and replacing this null at line 15 of data.dart, I'd recommend just passing NumberFormat.simpleCurrency()
here. If the home page is responsible for getting the locale and providing the formatter in initState
, it seems reasonable to me that it would also be responsible for choosing the fallback formatter and providing that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two mostly opinionated comments.
MDC-102/complete/lib/home.dart
Outdated
16.0, | ||
12.0, | ||
16.0, | ||
8.0, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: if the trailing comma after "8.0" is what's making these appear on their own lines (and unless you have other guidance from Hans or whomever), I'd remove it. It's just bonkers to me to have these spread out so much.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, I had it taken out and then I asked around the office and people said yes to trailing commas. They didn't see this case tho. Maybe this is an exception. @HansMuller , what do you prefer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, just one line is much easier to read. In cases like this we usually take a break from the trailing comma dogma.
EdgeInsets.fromLTRB(16.0, 12.0, 16.0, 8.0),
MDC-102/complete/lib/home.dart
Outdated
super.initState(); | ||
|
||
getLocale().then((locale) => setState(() { | ||
formatter = NumberFormat.simpleCurrency( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have anything real to back this up, but for some reason I feel like the function passed to setState
should be as small as possible, and just do assignments to the state object. I'm not sure if that's an official style point or just something I've picked up from various examples, but to me this code:
getLocale().then((locale) {
formatter = NumberFormat.simpleCurrency(
locale: locale,
decimalDigits: 0,
);
setState(() {
allProducts = generateProducts(formatter);
});
});
Seems cleaner, since all it's doing in setState
is setting things on the State
object. Hans or Filip can correct me if I'm being weird or the closures don't work this way, of course. 😃
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check out the changes Hans asked for. This is actually out. He knew a better way to get the locale.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The gist of much of the feedback is: do the localization late, when the UI is built (not in initState() or class vars).
MDC-102/complete/lib/home.dart
Outdated
// TODO(larche): Make headline6 when available | ||
Text( | ||
products[index].name, | ||
style: Theme.of(context).textTheme.title, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Theme.of() is somewhat expensive, so best to cache a ThemeData value at the top of the build function. This is really common, conventionally the variable is called theme:
final ThemeData theme = Theme.of(context);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
MDC-102/complete/lib/home.dart
Outdated
return []; | ||
} | ||
|
||
List<Card> cards = List.generate( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There doesn't seem to be any need to create this variable. Note also: you could make the formatting a little more conventional like this:
return List.generate(products.length, (int index) {
return Card(
child: ...
);
}).toList();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done! But why do I need the toList()
? Doesn't List.generate
return a List?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, you are correct, the toList()
isn't needed.
MDC-102/complete/lib/home.dart
Outdated
|
||
List<Card> cards = List.generate( | ||
products.length, | ||
(int index) => Card( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We only use =>
for one-liners that return a value
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done!
MDC-102/complete/lib/home.dart
Outdated
void initState() { | ||
super.initState(); | ||
|
||
getLocale().then((locale) => setState(() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You shouldn't call setState() from initState(). I don't think you want to do this here at all. You don't want to call getLocale() either, since Flutter's idea of Locale depends on where a widget is in its tree.
Use Localizations.localeOf(context)
to look up the locale when you need it (you'll have to convert it to a String to use it with dart:intl, like locale.toString())
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
MDC-102/complete/lib/home.dart
Outdated
|
||
List<Card> _buildGridCards(BuildContext context, List<Product> products) { | ||
if (products == null || products.isEmpty) { | ||
return []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return const <Card>[]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done!
MDC-102/complete/lib/model/data.dart
Outdated
return localeString; | ||
} | ||
|
||
List<Product> generateProducts(NumberFormat formatter) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could just export a constant list here, like kAllProducts
. If you're really trying to model an implicit lookup, then getAllProducts()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. I went with getAllProducts()
since that will set us up for category filtering later.
MDC-102/complete/lib/model/data.dart
Outdated
|
||
List<Product> generateProducts(NumberFormat formatter) { | ||
return <Product>[ | ||
Product( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be consistent: 2 space indents.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is 2 space indents. But the kerning is weird and you can't easily tell.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check the whole file...
@required this.isFeatured, | ||
@required this.name, | ||
@required this.price, | ||
@required this.priceString, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The localized price string should be computed by the widget that displays Product
, not here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
/// Formatted currency representation of price. Localized if possible. | ||
final String priceString; | ||
|
||
const Product({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Put the constructor first; assert that the parameters aren't null
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Like this:
class Product {
const Product({
@required this.category,
@required this.id,
@required this.isFeatured,
@required this.name,
@required this.price,
}) : assert(category != null),
assert(id != null),
assert(isFeatured != null),
assert(name != null),
assert(price != null);
final Category category;
final int id;
final bool isFeatured;
final String name;
final int price;
@override
String toString() => "$name (id=$id)";
}
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes
MDC-102/complete/lib/home.dart
Outdated
} | ||
|
||
class _HomePageState extends State<HomePage> { | ||
List<Product> allProducts = generateProducts(NumberFormat.simpleCurrency( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This value should be computed when it's needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I put it inside _buildGridCards
as a local variable. Lemme know if that makes sense.
MDC-102/complete/lib/home.dart
Outdated
final ThemeData theme = Theme.of(context); | ||
final NumberFormat formatter = NumberFormat.simpleCurrency( | ||
locale: Localizations.localeOf(context).toString()); | ||
return List.generate(products.length, (int index) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you're just looking up the products by index, then using map would be simpler:
return getAllProducts().map((Product product) {
return Card( ... product.name ... product.id ... etc )
}).toList();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done!
LGTM |
Dependent on #2
Ignore anything in a directory with 101. It's awaiting the earlier pull request to set those files straight.
Also, all the data an images is temporary. New images coming next week.