Dart: Add analysis_options

For now I've mostly tried to follow the same style guide as the flutter
repository, with many options disabled. Eventually, maybe it would make
sense to be far stricter.
This commit is contained in:
Vishesh Handa
2019-02-13 13:08:15 +01:00
parent ee34b60e53
commit acede95536
28 changed files with 295 additions and 176 deletions

124
analysis_options.yaml Normal file
View File

@ -0,0 +1,124 @@
# Specify analysis options.
#
# Until there are meta linter rules, each desired lint must be explicitly enabled.
# See: https://github.com/dart-lang/linter/issues/288
#
# For a list of lints, see: http://dart-lang.github.io/linter/lints/
#
analyzer:
strong-mode:
implicit-dynamic: true
errors:
missing_required_param: error
missing_return: error
todo: ignore
exclude:
- "bin/cache/**"
linter:
rules:
# these rules are documented on and in the same order as
# the Dart Lint rules page to make maintenance easier
# http://dart-lang.github.io/linter/lints/
# === error rules ===
- avoid_empty_else
- avoid_slow_async_io
- cancel_subscriptions
# - close_sinks # https://github.com/flutter/flutter/issues/5789
# - comment_references # blocked on https://github.com/dart-lang/dartdoc/issues/1153
- control_flow_in_finally
- empty_statements
- hash_and_equals
# - invariant_booleans # https://github.com/flutter/flutter/issues/5790
- iterable_contains_unrelated_type
- list_remove_unrelated_type
# - literal_only_boolean_expressions # https://github.com/flutter/flutter/issues/5791
- no_adjacent_strings_in_list
- no_duplicate_case_values
- test_types_in_equals
- throw_in_finally
- unrelated_type_equality_checks
- valid_regexps
# === style rules ===
- always_declare_return_types
# - always_put_control_body_on_new_line
- always_require_non_null_named_parameters
# - always_specify_types
- annotate_overrides
# - avoid_annotating_with_dynamic # not yet tested
# - avoid_as
# - avoid_catches_without_on_clauses # not yet tested
# - avoid_catching_errors # not yet tested
# - avoid_classes_with_only_static_members # not yet tested
# - avoid_function_literals_in_foreach_calls # not yet tested
- avoid_init_to_null
- avoid_null_checks_in_equality_operators
# - avoid_positional_boolean_parameters # not yet tested
- avoid_return_types_on_setters
# - avoid_returning_null # not yet tested
# - avoid_returning_this # not yet tested
# - avoid_setters_without_getters # not yet tested
# - avoid_types_on_closure_parameters # not yet tested
- await_only_futures
- camel_case_types
# - cascade_invocations # not yet tested
# - constant_identifier_names # https://github.com/dart-lang/linter/issues/204
- directives_ordering
- empty_catches
- empty_constructor_bodies
- implementation_imports
# - join_return_with_assignment # not yet tested
- library_names
- library_prefixes
- non_constant_identifier_names
# - omit_local_variable_types # opposite of always_specify_types
# - one_member_abstracts # too many false positives
# - only_throw_errors # https://github.com/flutter/flutter/issues/5792
- overridden_fields
- package_api_docs
- package_prefixed_library_names
# - parameter_assignments # we do this commonly
- prefer_adjacent_string_concatenation
# - prefer_collection_literals
# - prefer_conditional_assignment # not yet tested
# - prefer_const_constructors
# - prefer_constructors_over_static_methods # not yet tested
- prefer_contains
- prefer_equal_for_default_values
# - prefer_expression_function_bodies # conflicts with https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#consider-using--for-short-functions-and-methods
# - prefer_final_fields # https://github.com/dart-lang/linter/issues/506
# - prefer_final_locals
# - prefer_foreach # not yet tested
# - prefer_function_declarations_over_variables # not yet tested
- prefer_initializing_formals
# - prefer_interpolation_to_compose_strings # not yet tested
- prefer_is_empty
- prefer_is_not_empty
- prefer_void_to_null
# - recursive_getters # https://github.com/dart-lang/linter/issues/452
- slash_for_doc_comments
# - sort_constructors_first
# - sort_unnamed_constructors_first
- super_goes_last
# - type_annotate_public_apis # subset of always_specify_types
- type_init_formals
# - unawaited_futures # https://github.com/flutter/flutter/issues/5793
- unnecessary_brace_in_string_interps
# - unnecessary_const
- unnecessary_getters_setters
# - unnecessary_lambdas # https://github.com/dart-lang/linter/issues/498
- unnecessary_new
- unnecessary_null_aware_assignments
- unnecessary_null_in_if_null_operators
# - unnecessary_overrides # https://github.com/dart-lang/linter/issues/626 and https://github.com/dart-lang/linter/issues/627
- unnecessary_statements
# - unnecessary_this
- use_rethrow_when_possible
# - use_setters_to_change_properties # not yet tested
# - use_string_buffers # https://github.com/dart-lang/linter/pull/664
# - use_to_and_as_if_applicable # has false positives, so we prefer to catch this by code-review
# === pub rules ===
- package_names

View File

@ -11,7 +11,7 @@ Future<Directory> getGitBaseDirectory() async {
if (path == null) {
return null;
}
return new Directory(path);
return Directory(path);
}
Future<void> gitClone(String cloneUrl, String folderName) async {
@ -43,7 +43,7 @@ Future<String> generateSSHKeys({@required String comment}) async {
}
try {
String publicKey = await _platform.invokeMethod('getSSHPublicKey', {});
String publicKey = await _platform.invokeMethod('getSSHPublicKey');
print("Public Key " + publicKey);
return publicKey;
} on PlatformException catch (e) {
@ -65,7 +65,7 @@ Future<void> setSshKeys({
});
} on PlatformException catch (e) {
print("Failed to generateSSHKeys: '${e.message}'.");
throw e;
rethrow;
}
}

View File

@ -18,13 +18,13 @@ Future migrateGitRepo({
var fromBasePath = p.join(gitBasePath, fromGitBasePath);
var toBasePath = p.join(gitBasePath, toGitBasePath);
final dir = new Directory(fromBasePath);
final dir = Directory(fromBasePath);
var lister = dir.list(recursive: false);
await for (var fileEntity in lister) {
if (fileEntity is! File) {
continue;
}
var file = fileEntity as File;
File file = fileEntity;
var fileName = p.basename(file.path);
var toPath = p.join(toBasePath, fileName);

View File

@ -13,10 +13,10 @@ enum GitHostType {
GitHost createGitHost(GitHostType type) {
switch (type) {
case GitHostType.GitHub:
return new GitHub();
return GitHub();
case GitHostType.GitLab:
return new GitLab();
return GitLab();
default:
return null;

View File

@ -25,7 +25,7 @@ class GitHub implements GitHost {
print("GitHub: Called onUrl with " + call.arguments.toString());
var url = call.arguments["URL"];
String url = call.arguments["URL"];
var uri = Uri.parse(url);
var authCode = uri.queryParameters['code'];
if (authCode == null) {
@ -88,7 +88,7 @@ class GitHub implements GitHost {
}
List<dynamic> list = jsonDecode(response.body);
var repos = new List<GitRepo>();
var repos = List<GitRepo>();
list.forEach((dynamic d) {
var map = Map<String, dynamic>.from(d);
var repo = _repoFromJson(map);
@ -107,7 +107,7 @@ class GitHub implements GitHost {
}
var url = "https://api.github.com/user/repos?access_token=$_accessCode";
Map<String, dynamic> data = {
var data = <String, dynamic>{
'name': name,
'private': true,
};
@ -134,11 +134,12 @@ class GitHub implements GitHost {
}
print("GitHub createRepo: " + response.body);
var map = json.decode(response.body);
Map<String, dynamic> map = json.decode(response.body);
return _repoFromJson(map);
}
// FIXME: Proper error when the repo exists!
@override
Future addDeployKey(String sshPublicKey, String repo) async {
if (_accessCode.isEmpty) {
throw GitHostException.MissingAccessCode;
@ -147,7 +148,7 @@ class GitHub implements GitHost {
var url =
"https://api.github.com/repos/$repo/keys?access_token=$_accessCode";
Map<String, dynamic> data = {
var data = <String, dynamic>{
'title': "GitJournal",
'key': sshPublicKey,
'read_only': false,
@ -172,7 +173,7 @@ class GitHub implements GitHost {
}
GitRepo _repoFromJson(Map<String, dynamic> parsedJson) {
return new GitRepo(
return GitRepo(
fullName: parsedJson['full_name'],
cloneUrl: parsedJson['ssh_url'],
);

View File

@ -80,7 +80,7 @@ class GitLab implements GitHost {
}
List<dynamic> list = jsonDecode(response.body);
var repos = new List<GitRepo>();
var repos = List<GitRepo>();
list.forEach((dynamic d) {
var map = Map<String, dynamic>.from(d);
var repo = _repoFromJson(map);
@ -99,7 +99,7 @@ class GitLab implements GitHost {
}
var url = "https://gitlab.com/api/v4/projects?access_token=$_accessCode";
Map<String, dynamic> data = {
var data = <String, dynamic>{
'name': name,
'visibility': 'private',
};
@ -126,7 +126,7 @@ class GitLab implements GitHost {
}
print("GitLab createRepo: " + response.body);
var map = json.decode(response.body);
Map<String, dynamic> map = json.decode(response.body);
return _repoFromJson(map);
}
@ -140,7 +140,7 @@ class GitLab implements GitHost {
var url =
"https://gitlab.com/api/v4/projects/$repo/deploy_keys?access_token=$_accessCode";
Map<String, dynamic> data = {
var data = {
'title': "GitJournal",
'key': sshPublicKey,
'can_push': true,
@ -165,7 +165,7 @@ class GitLab implements GitHost {
}
GitRepo _repoFromJson(Map<String, dynamic> parsedJson) {
return new GitRepo(
return GitRepo(
fullName: parsedJson['path_with_namespace'],
cloneUrl: parsedJson['ssh_url_to_repo'],
);
@ -202,10 +202,10 @@ class GitLab implements GitHost {
}
String _randomString(int length) {
var rand = new Random();
var codeUnits = new List.generate(length, (index) {
var rand = Random();
var codeUnits = List.generate(length, (index) {
return rand.nextInt(33) + 89;
});
return new String.fromCharCodes(codeUnits);
return String.fromCharCodes(codeUnits);
}

View File

@ -28,9 +28,9 @@ class JournalApp extends StatelessWidget {
stateContainer.completeGitHostSetup();
};
return new MaterialApp(
return MaterialApp(
title: 'GitJournal',
theme: new ThemeData(
theme: ThemeData(
brightness: Brightness.light,
primaryColor: Color(0xFF66bb6a),
primaryColorLight: Color(0xFF98ee99),

View File

@ -6,11 +6,11 @@ const basePath = "journal";
String cloneUrl = "git@github.com:GitJournal/journal_test.git";
class GitApp extends StatelessWidget {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
@override
Widget build(BuildContext context) {
return new MaterialApp(
return MaterialApp(
title: 'Git App',
home: Scaffold(
key: _scaffoldKey,
@ -30,16 +30,16 @@ class GitApp extends StatelessWidget {
var text = "Success";
this._scaffoldKey.currentState
..removeCurrentSnackBar()
..showSnackBar(new SnackBar(content: new Text(text)));
..showSnackBar(SnackBar(content: Text(text)));
}
void _sendError(String text) {
this._scaffoldKey.currentState
..removeCurrentSnackBar()
..showSnackBar(new SnackBar(content: new Text("ERROR: " + text)));
..showSnackBar(SnackBar(content: Text("ERROR: " + text)));
}
_buildGitButtons() {
List<Widget> _buildGitButtons() {
return <Widget>[
RaisedButton(
child: Text("Generate Keys"),

View File

@ -21,9 +21,9 @@ void main() async {
await FlutterCrashlytics().initialize();
runZoned<Future<Null>>(() async {
runZoned<Future<void>>(() async {
await runJournalApp();
}, onError: (error, stackTrace) async {
}, onError: (Error error, StackTrace stackTrace) async {
await FlutterCrashlytics()
.reportCrash(error, stackTrace, forceCrash: false);
});
@ -60,7 +60,7 @@ Future runJournalApp() async {
await Settings.instance.load();
runApp(new StateContainer(
runApp(StateContainer(
localGitRepoConfigured: localGitRepoConfigured,
remoteGitRepoConfigured: remoteGitRepoConfigured,
localGitRepoPath: localGitRepoPath,

View File

@ -1,22 +1,18 @@
import 'package:journal/datetime_utils.dart';
typedef NoteAdder(Note note);
typedef NoteRemover(Note note);
typedef NoteUpdator(Note note);
class Note implements Comparable {
class Note implements Comparable<Note> {
String fileName;
DateTime created;
String body;
Map<String, dynamic> extraProperties = new Map<String, dynamic>();
Map<String, dynamic> extraProperties = Map<String, dynamic>();
Note({this.created, this.body, this.fileName, this.extraProperties}) {
if (created == null) {
created = DateTime(0, 0, 0, 0, 0, 0, 0, 0);
}
if (extraProperties == null) {
extraProperties = new Map<String, dynamic>();
extraProperties = Map<String, dynamic>();
}
}
@ -32,10 +28,12 @@ class Note implements Comparable {
var createdStr = json['created'].toString();
try {
created = DateTime.parse(json['created']).toLocal();
} catch (ex) {}
} catch (ex) {
// Ignore it
}
if (created == null) {
var regex = new RegExp(
var regex = RegExp(
r"(\d{4})-(\d{2})-(\d{2})T(\d{2})\:(\d{2})\:(\d{2})\+(\d{2})\:(\d{2})");
if (regex.hasMatch(createdStr)) {
// FIXME: Handle the timezone!
@ -57,7 +55,7 @@ class Note implements Comparable {
json.remove("body");
}
return new Note(
return Note(
fileName: fileName,
created: created,
body: body,
@ -96,7 +94,8 @@ class Note implements Comparable {
static bool _equalMaps(Map a, Map b) {
if (a.length != b.length) return false;
return a.keys.every((key) => b.containsKey(key) && a[key] == b[key]);
return a.keys
.every((dynamic key) => b.containsKey(key) && a[key] == b[key]);
}
@override
@ -105,7 +104,7 @@ class Note implements Comparable {
}
@override
int compareTo(other) {
int compareTo(Note other) {
if (other == null) {
return -1;
}

View File

@ -1,7 +1,6 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:journal/note.dart';
import 'package:journal/state_container.dart';
import 'package:journal/widgets/note_header.dart';
@ -15,25 +14,24 @@ class NoteEditor extends StatefulWidget {
@override
NoteEditorState createState() {
if (note == null) {
return new NoteEditorState();
return NoteEditorState();
} else {
return new NoteEditorState.fromNote(note);
return NoteEditorState.fromNote(note);
}
}
}
class NoteEditorState extends State<NoteEditor> {
Note note = new Note();
Note note = Note();
final bool newNote;
TextEditingController _textController = new TextEditingController();
TextEditingController _textController = TextEditingController();
NoteEditorState() : newNote = true {
note.created = new DateTime.now();
note.created = DateTime.now();
}
NoteEditorState.fromNote(Note n) : newNote = false {
note = n;
_textController = new TextEditingController(text: note.body);
NoteEditorState.fromNote(this.note) : newNote = false {
_textController = TextEditingController(text: note.body);
}
@override
@ -62,7 +60,7 @@ class NoteEditorState extends State<NoteEditor> {
autofocus: true,
keyboardType: TextInputType.multiline,
maxLines: null,
decoration: new InputDecoration(
decoration: InputDecoration(
hintText: 'Write here',
border: InputBorder.none,
),
@ -71,10 +69,10 @@ class NoteEditorState extends State<NoteEditor> {
),
);
var title = newNote ? "New Journal Entry" : "Edit Journal Entry";
var newJournalScreen = new Scaffold(
appBar: new AppBar(
title: new Text(title),
var title = newNote ? "Journal Entry" : "Edit Journal Entry";
var newJournalScreen = Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
@ -108,18 +106,18 @@ class NoteEditorState extends State<NoteEditor> {
? "Do you want to discard the entry"
: "Do you want to discard the changes?";
return new AlertDialog(
return AlertDialog(
// FIXME: Change this to 'Save' vs 'Discard'
title: new Text('Are you sure?'),
content: new Text(title),
title: Text('Are you sure?'),
content: Text(title),
actions: <Widget>[
new FlatButton(
FlatButton(
onPressed: () => Navigator.of(context).pop(false),
child: new Text('No'),
child: Text('No'),
),
new FlatButton(
FlatButton(
onPressed: () => Navigator.of(context).pop(true),
child: new Text('Yes'),
child: Text('Yes'),
),
],
);

View File

@ -16,7 +16,7 @@ class NoteBrowsingScreen extends StatefulWidget {
@override
NoteBrowsingScreenState createState() {
return new NoteBrowsingScreenState(noteIndex: noteIndex);
return NoteBrowsingScreenState(noteIndex: noteIndex);
}
}
@ -24,28 +24,28 @@ class NoteBrowsingScreenState extends State<NoteBrowsingScreen> {
PageController pageController;
NoteBrowsingScreenState({@required int noteIndex}) {
pageController = new PageController(initialPage: noteIndex);
pageController = PageController(initialPage: noteIndex);
}
@override
Widget build(BuildContext context) {
var pageView = new PageView.builder(
var pageView = PageView.builder(
controller: pageController,
itemCount: widget.notes.length,
itemBuilder: (BuildContext context, int pos) {
return new NoteViewer(note: widget.notes[pos]);
return NoteViewer(note: widget.notes[pos]);
},
);
return new Scaffold(
appBar: new AppBar(
title: new Text('TIMELINE'),
return Scaffold(
appBar: AppBar(
title: Text('TIMELINE'),
),
body: pageView,
floatingActionButton: FloatingActionButton(
child: Icon(Icons.edit),
onPressed: () {
var route = new MaterialPageRoute(builder: (context) {
var route = MaterialPageRoute<Widget>(builder: (context) {
int currentIndex = pageController.page.toInt();
assert(currentIndex >= 0);
assert(currentIndex < widget.notes.length);
@ -68,8 +68,8 @@ class NoteViewer extends StatelessWidget {
@override
Widget build(BuildContext context) {
var view = new SingleChildScrollView(
child: new Column(
var view = SingleChildScrollView(
child: Column(
children: <Widget>[
NoteHeader(note),
Text(note.body, style: _biggerFont),
@ -85,21 +85,21 @@ class NoteViewer extends StatelessWidget {
/*
Widget _buildFooter(BuildContext context) {
return new Padding(
return Padding(
padding: const EdgeInsets.only(top: 8.0, bottom: 8.0),
child: new Row(
child: Row(
children: <Widget>[
new IconButton(
icon: new Icon(Icons.arrow_left),
IconButton(
icon: Icon(Icons.arrow_left),
tooltip: 'Previous Entry',
onPressed: showPrevNoteFunc,
),
new Expanded(
Expanded(
flex: 10,
child: new Text(''),
child: Text(''),
),
new IconButton(
icon: new Icon(Icons.arrow_right),
IconButton(
icon: Icon(Icons.arrow_right),
tooltip: 'Next Entry',
onPressed: showNextNoteFunc,
),

View File

@ -5,7 +5,7 @@ import 'apis/githost_factory.dart';
class OAuthApp extends StatefulWidget {
@override
OAuthAppState createState() {
return new OAuthAppState();
return OAuthAppState();
}
}
@ -15,6 +15,7 @@ var key =
class OAuthAppState extends State<OAuthApp> {
GitHost githost;
@override
void initState() {
super.initState();
@ -26,7 +27,7 @@ class OAuthAppState extends State<OAuthApp> {
@override
Widget build(BuildContext context) {
return new MaterialApp(
return MaterialApp(
title: 'OAuth App',
home: Scaffold(
appBar: AppBar(

View File

@ -14,7 +14,7 @@ class GitHostSetupAutoConfigure extends StatefulWidget {
@override
GitHostSetupAutoConfigureState createState() {
return new GitHostSetupAutoConfigureState();
return GitHostSetupAutoConfigureState();
}
}

View File

@ -21,7 +21,7 @@ class GitHostSetupScreen extends StatefulWidget {
@override
GitHostSetupScreenState createState() {
return new GitHostSetupScreenState();
return GitHostSetupScreenState();
}
}
@ -42,7 +42,7 @@ class GitHostSetupScreenState extends State<GitHostSetupScreen> {
var pageController = PageController();
int _currentPageIndex = 0;
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
String publicKey = "";
bool _canLaunchDeployKeyPage = false;
@ -283,16 +283,16 @@ class GitHostSetupScreenState extends State<GitHostSetupScreen> {
},
);
var scaffold = new Scaffold(
var scaffold = Scaffold(
key: _scaffoldKey,
body: new Container(
body: Container(
width: double.infinity,
height: double.infinity,
child: Stack(
alignment: FractionalOffset.bottomCenter,
children: <Widget>[
pageView,
new DotsIndicator(
DotsIndicator(
numberOfDot: pageCount,
position: _currentPageIndex,
dotActiveColor: Theme.of(context).primaryColorDark,
@ -303,7 +303,7 @@ class GitHostSetupScreenState extends State<GitHostSetupScreen> {
),
);
return new WillPopScope(
return WillPopScope(
onWillPop: () {
if (_currentPageIndex != 0) {
pageController.previousPage(
@ -348,7 +348,7 @@ class GitHostSetupScreenState extends State<GitHostSetupScreen> {
var text = "Public Key copied to Clipboard";
this._scaffoldKey.currentState
..removeCurrentSnackBar()
..showSnackBar(new SnackBar(content: new Text(text)));
..showSnackBar(SnackBar(content: Text(text)));
}
void _launchDeployKeyPage() async {
@ -423,8 +423,8 @@ class GitHostSetupScreenState extends State<GitHostSetupScreen> {
}
Future _removeExistingClone(String baseDirPath) async {
var baseDir = new Directory(p.join(baseDirPath, "journal"));
var dotGitDir = new Directory(p.join(baseDir.path, ".git"));
var baseDir = Directory(p.join(baseDirPath, "journal"));
var dotGitDir = Directory(p.join(baseDir.path, ".git"));
bool exists = await dotGitDir.exists();
if (exists) {
print("Removing " + baseDir.path);
@ -498,7 +498,7 @@ class GitHostSetupCreateRepo extends StatefulWidget {
@override
GitHostSetupCreateRepoState createState() {
return new GitHostSetupCreateRepoState();
return GitHostSetupCreateRepoState();
}
}

View File

@ -9,7 +9,7 @@ class GitHostSetupUrl extends StatefulWidget {
@override
GitHostSetupUrlState createState() {
return new GitHostSetupUrlState();
return GitHostSetupUrlState();
}
}
@ -51,7 +51,7 @@ class GitHostSetupUrlState extends State<GitHostSetupUrl> {
return 'Only SSH urls are currently accepted';
}
RegExp regExp = new RegExp(r"[a-zA-Z0-9.]+@[a-zA-Z0-9.]+:.+");
RegExp regExp = RegExp(r"[a-zA-Z0-9.]+@[a-zA-Z0-9.]+:.+");
if (!regExp.hasMatch(value)) {
return "Invalid Input";
}

View File

@ -8,23 +8,23 @@ import 'package:journal/widgets/app_drawer.dart';
import 'package:journal/widgets/journal_list.dart';
class HomeScreen extends StatelessWidget {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
@override
Widget build(BuildContext context) {
final container = StateContainer.of(context);
final appState = container.appState;
var createButton = new FloatingActionButton(
var createButton = FloatingActionButton(
onPressed: () => _newPost(context),
child: new Icon(Icons.add),
child: Icon(Icons.add),
);
var journalList = JournalList(
notes: appState.notes,
noteSelectedFunction: (noteIndex) {
var route = new MaterialPageRoute(
builder: (context) => new NoteBrowsingScreen(
var route = MaterialPageRoute(
builder: (context) => NoteBrowsingScreen(
notes: appState.notes,
noteIndex: noteIndex,
),
@ -41,10 +41,10 @@ class HomeScreen extends StatelessWidget {
},
);
return new Scaffold(
return Scaffold(
key: _scaffoldKey,
appBar: new AppBar(
title: new Text('GitJournal'),
appBar: AppBar(
title: Text('GitJournal'),
leading: appBarMenuButton,
),
floatingActionButton: createButton,
@ -57,16 +57,16 @@ class HomeScreen extends StatelessWidget {
} on GitException catch (exp) {
_scaffoldKey.currentState
..removeCurrentSnackBar()
..showSnackBar(new SnackBar(content: new Text(exp.cause)));
..showSnackBar(SnackBar(content: Text(exp.cause)));
}
}),
),
drawer: new AppDrawer(),
drawer: AppDrawer(),
);
}
void _newPost(BuildContext context) {
var route = new MaterialPageRoute(builder: (context) => new NoteEditor());
var route = MaterialPageRoute(builder: (context) => NoteEditor());
Navigator.of(context).push(route);
}
}

View File

@ -6,7 +6,7 @@ import 'package:package_info/package_info.dart';
class SettingsScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
return Scaffold(
appBar: AppBar(
title: Text('Settings'),
leading: IconButton(
@ -24,7 +24,7 @@ class SettingsScreen extends StatelessWidget {
class SettingsList extends StatefulWidget {
@override
SettingsListState createState() {
return new SettingsListState();
return SettingsListState();
}
}
@ -142,7 +142,7 @@ class SettingsHeader extends StatelessWidget {
class VersionNumberTile extends StatefulWidget {
@override
VersionNumberTileState createState() {
return new VersionNumberTileState();
return VersionNumberTileState();
}
}

View File

@ -59,12 +59,12 @@ class StateContainerState extends State<StateContainer> {
assert(appState.localGitRepoConfigured);
if (appState.remoteGitRepoConfigured) {
noteRepo = new GitNoteRepository(
noteRepo = GitNoteRepository(
baseDirectory: appState.gitBaseDirectory,
dirName: appState.remoteGitRepoPath,
);
} else if (appState.localGitRepoConfigured) {
noteRepo = new GitNoteRepository(
noteRepo = GitNoteRepository(
baseDirectory: appState.gitBaseDirectory,
dirName: appState.localGitRepoPath,
);
@ -80,9 +80,9 @@ class StateContainerState extends State<StateContainer> {
}
void removeExistingRemoteClone() async {
var remoteGitDir = new Directory(
var remoteGitDir = Directory(
p.join(appState.gitBaseDirectory, appState.remoteGitRepoPath));
var dotGitDir = new Directory(p.join(remoteGitDir.path, ".git"));
var dotGitDir = Directory(p.join(remoteGitDir.path, ".git"));
bool exists = await dotGitDir.exists();
if (exists) {
@ -194,7 +194,7 @@ class StateContainerState extends State<StateContainer> {
gitBasePath: appState.gitBaseDirectory,
);
noteRepo = new GitNoteRepository(
noteRepo = GitNoteRepository(
baseDirectory: appState.gitBaseDirectory,
dirName: appState.remoteGitRepoPath,
);

View File

@ -26,9 +26,9 @@ class FileStorage implements NoteRepository {
@override
Future<List<Note>> listNotes() async {
final dir = new Directory(baseDirectory);
final dir = Directory(baseDirectory);
var notes = new List<Note>();
var notes = List<Note>();
var lister = dir.list(recursive: false);
await for (var fileEntity in lister) {
Note note = await _loadNote(fileEntity);
@ -63,7 +63,7 @@ class FileStorage implements NoteRepository {
var filePath = p.join(baseDirectory, note.fileName);
print("FileStorage: Adding note in " + filePath);
var file = new File(filePath);
var file = File(filePath);
if (file == null) {
return NoteRepoResult(error: true);
}
@ -77,7 +77,7 @@ class FileStorage implements NoteRepository {
Future<NoteRepoResult> removeNote(Note note) async {
var filePath = p.join(baseDirectory, note.fileName);
var file = new File(filePath);
var file = File(filePath);
await file.delete();
return NoteRepoResult(noteFilePath: filePath, error: false);
@ -94,12 +94,12 @@ class FileStorage implements NoteRepository {
}
Future<Directory> saveNotes(List<Note> notes) async {
final dir = new Directory(baseDirectory);
final dir = Directory(baseDirectory);
for (var note in notes) {
var filePath = p.join(dir.path, note.fileName);
var file = new File(filePath);
var file = File(filePath);
var contents = noteSerializer.encode(note);
await file.writeAsString(contents);
}

View File

@ -20,7 +20,7 @@ class GitNoteRepository implements NoteRepository {
@required this.dirName,
@required String baseDirectory,
}) : _fileStorage = FileStorage(
noteSerializer: new MarkdownYAMLSerializer(),
noteSerializer: MarkdownYAMLSerializer(),
baseDirectory: p.join(baseDirectory, dirName),
);
@ -92,8 +92,8 @@ class GitNoteRepository implements NoteRepository {
}
if (!checkForCloned) {
var baseDir = new Directory(_fileStorage.baseDirectory);
var dotGitDir = new Directory(p.join(baseDir.path, ".git"));
var baseDir = Directory(_fileStorage.baseDirectory);
var dotGitDir = Directory(p.join(baseDir.path, ".git"));
cloned = await dotGitDir.exists();
checkForCloned = true;
}
@ -116,7 +116,7 @@ class GitNoteRepository implements NoteRepository {
await gitPush(this.dirName);
} on GitException catch (ex) {
print(ex);
throw ex;
rethrow;
}
return true;

View File

@ -1,7 +1,7 @@
import 'dart:convert';
import 'package:yaml/yaml.dart';
import 'package:journal/note.dart';
import 'package:yaml/yaml.dart';
abstract class NoteSerializer {
String encode(Note note);
@ -12,7 +12,7 @@ class JsonNoteSerializer implements NoteSerializer {
@override
Note decode(String str) {
final json = JsonDecoder().convert(str);
return new Note.fromJson(json);
return Note.fromJson(json);
}
@override
@ -28,18 +28,18 @@ class MarkdownYAMLSerializer implements NoteSerializer {
var parts = str.split("---\n");
var yamlMap = loadYaml(parts[1]);
var map = new Map<String, dynamic>();
var map = Map<String, dynamic>();
yamlMap.forEach((key, value) {
map[key] = value;
});
map['body'] = parts[2].trimLeft();
return new Note.fromJson(map);
return Note.fromJson(map);
}
var map = new Map<String, dynamic>();
var map = Map<String, dynamic>();
map['body'] = str;
return new Note.fromJson(map);
return Note.fromJson(map);
}
@override

View File

@ -4,13 +4,13 @@ import 'package:journal/state_container.dart';
class AppDrawer extends StatelessWidget {
@override
Widget build(BuildContext context) {
Widget setupGitButton = new Container();
Widget setupGitButton = Container();
var appState = StateContainer.of(context).appState;
if (!appState.remoteGitRepoConfigured) {
setupGitButton = ListTile(
title: new Text('Setup Git Host'),
trailing: new Icon(
title: Text('Setup Git Host'),
trailing: Icon(
Icons.priority_high,
color: Colors.red,
),
@ -21,13 +21,13 @@ class AppDrawer extends StatelessWidget {
);
}
return new Drawer(
child: new ListView(
return Drawer(
child: ListView(
// Important: Remove any padding from the ListView.
padding: EdgeInsets.zero,
children: <Widget>[
new DrawerHeader(
decoration: new BoxDecoration(
DrawerHeader(
decoration: BoxDecoration(
color: Theme.of(context).buttonColor,
),
child: Padding(
@ -42,16 +42,16 @@ class AppDrawer extends StatelessWidget {
),
),
setupGitButton,
new ListTile(
title: new Text('Share App'),
ListTile(
title: Text('Share App'),
onTap: () {
Navigator.pop(context);
// Update the state of the app
// ...
},
),
new ListTile(
title: new Text('Settings'),
ListTile(
title: Text('Settings'),
onTap: () {
Navigator.pop(context);
Navigator.pushNamed(context, "/settings");

View File

@ -1,7 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:journal/note.dart';
import 'package:journal/state_container.dart';
@ -20,24 +19,24 @@ class JournalList extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new ListView.builder(
return ListView.builder(
itemBuilder: (context, i) {
if (i >= notes.length) {
return null;
}
var note = notes[i];
return new Dismissible(
key: new Key(note.fileName),
return Dismissible(
key: Key(note.fileName),
child: _buildRow(context, note, i),
background: new Container(color: Theme.of(context).accentColor),
background: Container(color: Theme.of(context).accentColor),
onDismissed: (direction) {
final stateContainer = StateContainer.of(context);
stateContainer.removeNote(note);
Scaffold.of(context).showSnackBar(new SnackBar(
content: new Text("Note deleted"),
action: new SnackBarAction(
Scaffold.of(context).showSnackBar(SnackBar(
content: Text("Note deleted"),
action: SnackBarAction(
label: 'Undo',
onPressed: () => stateContainer.insertNote(i, note),
),
@ -49,22 +48,22 @@ class JournalList extends StatelessWidget {
}
Widget _buildRow(BuildContext context, Note journal, int noteIndex) {
var formatter = new DateFormat('dd MMM, yyyy');
var formatter = DateFormat('dd MMM, yyyy');
var title = formatter.format(journal.created);
var timeFormatter = new DateFormat('Hm');
var timeFormatter = DateFormat('Hm');
var time = timeFormatter.format(journal.created);
var body = journal.body;
body = body.replaceAll("\n", " ");
return new ListTile(
return ListTile(
isThreeLine: true,
title: new Text(
title: Text(
title,
style: _biggerFont,
),
subtitle: new Text(
subtitle: Text(
time + "\n" + body,
maxLines: 3,
overflow: TextOverflow.ellipsis,

View File

@ -1,6 +1,5 @@
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:journal/note.dart';
class NoteHeader extends StatelessWidget {
@ -13,22 +12,22 @@ class NoteHeader extends StatelessWidget {
var dateStr = DateFormat('MMMM, yyyy').format(note.created);
var timeStr = DateFormat('EEEE HH:mm').format(note.created);
var bigNum = new Text(
var bigNum = Text(
note.created.day.toString(),
style: TextStyle(fontSize: 40.0),
);
var dateText = new Text(
var dateText = Text(
dateStr,
style: TextStyle(fontSize: 18.0),
);
var timeText = new Text(
var timeText = Text(
timeStr,
style: TextStyle(fontSize: 18.0),
);
var w = new Row(
var w = Row(
children: <Widget>[
bigNum,
SizedBox(width: 8.0),
@ -43,8 +42,8 @@ class NoteHeader extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
);
return new Padding(
padding: new EdgeInsets.only(top: 8.0, bottom: 18.0),
return Padding(
padding: EdgeInsets.only(top: 8.0, bottom: 18.0),
child: w,
);
}

View File

@ -1,7 +1,7 @@
import 'package:test/test.dart';
import 'package:journal/datetime_utils.dart';
import 'package:test/test.dart';
main() {
void main() {
group('DateTime Utils', () {
test('Test random date', () {
var dateTime = DateTime.utc(2011, 12, 23, 10, 15, 30);

View File

@ -1,18 +1,17 @@
import 'dart:io';
import 'package:test/test.dart';
import 'package:path/path.dart' as p;
import 'package:journal/note.dart';
import 'package:journal/storage/file_storage.dart';
import 'package:journal/storage/serializers.dart';
import 'package:path/path.dart' as p;
import 'package:test/test.dart';
DateTime nowWithoutMicro() {
var dt = DateTime.now();
return DateTime(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second);
}
main() {
void main() {
group('FileStorage', () {
var notes = [
Note(fileName: "1.md", body: "test", created: nowWithoutMicro()),
@ -26,7 +25,7 @@ main() {
tempDir = await Directory.systemTemp.createTemp('__storage_test__');
storage = FileStorage(
baseDirectory: tempDir.path,
noteSerializer: new JsonNoteSerializer(),
noteSerializer: JsonNoteSerializer(),
);
});

View File

@ -1,6 +1,5 @@
import 'package:journal/note.dart';
import 'package:journal/storage/serializers.dart';
import 'package:test/test.dart';
DateTime nowWithoutMicro() {
@ -8,13 +7,13 @@ DateTime nowWithoutMicro() {
return DateTime(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second);
}
main() {
void main() {
group('Serializers', () {
var note = Note(
fileName: "2", body: "This is the body", created: nowWithoutMicro());
test('JSON Serializer', () {
var serializer = new JsonNoteSerializer();
var serializer = JsonNoteSerializer();
var str = serializer.encode(note);
var note2 = serializer.decode(str);
@ -22,7 +21,7 @@ main() {
});
test('Markdown Serializer', () {
var serializer = new MarkdownYAMLSerializer();
var serializer = MarkdownYAMLSerializer();
var str = serializer.encode(note);
var note2 = serializer.decode(str);
@ -42,7 +41,7 @@ foo: bar
Alright.""";
var serializer = new MarkdownYAMLSerializer();
var serializer = MarkdownYAMLSerializer();
var note = serializer.decode(str);
var actualStr = serializer.encode(note);