-
Notifications
You must be signed in to change notification settings - Fork 3
Code style
Basically, code as described in the Effective Dart Style guide.
Note: We have pretty strict linter rules that are also shown in VS Code and validated when opening a PR. They help you write readable and uniform code :)
Here are some amendments specific to this project:
There are basically 3 types of imports that should be organized into four distinct groups, separated by a newline:
- Dart-Imports like
import 'dart:ui';
. - Package imports like
import 'package:flutter/flutter.dart';
or imports of other modules likeimport 'package:schulcloud/app/app.dart';
. - Imports of files in the same module. To make the code more succinct, these should be relative imports like
import '../bloc.dart';
Example
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:schulcloud/app/app.dart';
import '../model.dart';
import 'article_image.dart';
import 'article_screen.dart';
import 'section.dart';
import 'theme.dart';
Only make stuff non-private if it's accessed outside of the file.
Example
class _SampleWidgetState extends State<SampleWidget> {
void _counter = 0;
Widget build(BuildContext context) {...}
void _countUp() => setState(() => _counter++);
}
If arguments to a function are not used by that function, they can be named _
(an underscore), __
(two underscores) etc., to indicate to the reader that their value is not relevant.
Example
StreamBuilder<Update>(
stream: /* ... */,
builder: (_, snapshot) => MyWidget(snapshot),
)
The widget tree in the build
function should not contain any closures that are longer than one line (or are similarly simple). Rather, move these functions out into a new method that has a descriptive name. That helps readers of the build
method to quickly understanding the action without interrupting their flow (they're probably trying to figure out how the widget tree is built, not what happens if an action is taken).
If the widget tree gets very deep, consider two options:
- If there are parts of the widget tree that don't need to rebuild if the whole widget rebuilds, consider refactoring them to standalone widgets.
- Otherwise, consider defining helper methods (descriptively named
_buildButton
) for parts of the tree.
This should be the order of functions in a widget (note some of them are optional):
initState
didChangeDependencies
dispose
build
- helper functions used in
build
- helper
build
-functions (_build...
)
Example
// (inside a [StatelessWidget] or the [State] of a [StatefulWidget])
Widget build(BuildContext context) {...}
void startSleeping() { /* ... */ }
void eat(Banana banana) { /* ... */ }
Widget _buildHeader(BuildContext context, int someData) { /* ... */ }
void _onHeaderClicked() { /* ... */ }
Need help? Feel free to contact Jonas Wanke, a former member of the Flutter team at the HPI Schul-Cloud :)