diff --git a/lib/setup/autoconfigure.dart b/lib/setup/autoconfigure.dart index 0cbc1cba..c2e2c787 100644 --- a/lib/setup/autoconfigure.dart +++ b/lib/setup/autoconfigure.dart @@ -1,5 +1,3 @@ -// @dart=2.9 - import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -18,11 +16,11 @@ import 'loading.dart'; class GitHostSetupAutoConfigure extends StatefulWidget { final GitHostType gitHostType; - final Func2 onDone; + final Func2 onDone; GitHostSetupAutoConfigure({ - @required this.gitHostType, - @required this.onDone, + required this.gitHostType, + required this.onDone, }); @override @@ -32,7 +30,7 @@ class GitHostSetupAutoConfigure extends StatefulWidget { } class GitHostSetupAutoConfigureState extends State { - GitHost gitHost; + GitHost? gitHost; String errorMessage = ""; bool _configuringStarted = false; @@ -46,7 +44,7 @@ class GitHostSetupAutoConfigureState extends State { gitHost = createGitHost(widget.gitHostType); try { - gitHost.init((Exception error) async { + gitHost!.init((Exception? error) async { if (error != null) { if (mounted) { setState(() { @@ -59,18 +57,18 @@ class GitHostSetupAutoConfigureState extends State { } Log.d("GitHost Initalized: " + widget.gitHostType.toString()); - UserInfo userInfo; + UserInfo? userInfo; try { setState(() { _message = tr('setup.autoconfigure.readUser'); }); - userInfo = await gitHost.getUserInfo(); + userInfo = await gitHost!.getUserInfo(); var settings = Provider.of(context, listen: false); - if (userInfo.name != null && userInfo.name.isNotEmpty) { + if (userInfo != null && userInfo.name.isNotEmpty) { settings.gitAuthor = userInfo.name; } - if (userInfo.email != null && userInfo.email.isNotEmpty) { + if (userInfo != null && userInfo.email.isNotEmpty) { settings.gitAuthorEmail = userInfo.email; } settings.save(); @@ -82,7 +80,7 @@ class GitHostSetupAutoConfigureState extends State { }); try { - await gitHost.launchOAuthScreen(); + await gitHost!.launchOAuthScreen(); } on PlatformException catch (e, stack) { Log.d("LaunchOAuthScreen: Caught platform exception:", ex: e, stacktrace: stack); @@ -111,11 +109,11 @@ class GitHostSetupAutoConfigureState extends State { @override Widget build(BuildContext context) { if (_configuringStarted) { - if (errorMessage == null || errorMessage.isEmpty) { - return GitHostSetupLoadingPage(_message); + if (errorMessage.isNotEmpty) { + return GitHostSetupErrorPage(errorMessage); } - return GitHostSetupErrorPage(errorMessage); + return GitHostSetupLoadingPage(_message); } var columns = Column( @@ -146,7 +144,7 @@ class GitHostSetupAutoConfigureState extends State { const SizedBox(height: 32.0), Text( tr('setup.autoconfigure.warning'), - style: Theme.of(context).textTheme.bodyText1.copyWith( + style: Theme.of(context).textTheme.bodyText1!.copyWith( fontStyle: FontStyle.italic, ), ), diff --git a/lib/setup/button.dart b/lib/setup/button.dart index 1c088fa1..85db612b 100644 --- a/lib/setup/button.dart +++ b/lib/setup/button.dart @@ -1,5 +1,3 @@ -// @dart=2.9 - import 'package:flutter/material.dart'; import 'package:function_types/function_types.dart'; @@ -10,11 +8,11 @@ import 'package:gitjournal/utils/logger.dart'; class GitHostSetupButton extends StatelessWidget { final Func0 onPressed; final String text; - final String iconUrl; + final String? iconUrl; GitHostSetupButton({ - @required this.text, - @required this.onPressed, + required this.text, + required this.onPressed, this.iconUrl, }); @@ -42,7 +40,7 @@ class GitHostSetupButton extends StatelessWidget { textAlign: TextAlign.center, style: Theme.of(context).textTheme.button, ), - icon: Image.asset(iconUrl, width: 32, height: 32), + icon: Image.asset(iconUrl!, width: 32, height: 32), color: Theme.of(context).primaryColor, onPressed: _onPressedWithAnalytics, ), @@ -54,7 +52,7 @@ class GitHostSetupButton extends StatelessWidget { Log.d("githostsetup_button_click " + text); logEvent(Event.GitHostSetupButtonClick, parameters: { 'text': text, - 'icon_url': iconUrl == null ? "" : iconUrl, + 'icon_url': iconUrl == null ? "" : iconUrl!, }); onPressed(); } diff --git a/lib/setup/clone.dart b/lib/setup/clone.dart index f12cc8b4..584c5ec6 100644 --- a/lib/setup/clone.dart +++ b/lib/setup/clone.dart @@ -1,21 +1,18 @@ -// @dart=2.9 - import 'package:dart_git/dart_git.dart'; import 'package:git_bindings/git_bindings.dart' as git_bindings; -import 'package:meta/meta.dart'; import 'package:path/path.dart' as p; import 'package:gitjournal/utils/logger.dart'; Future cloneRemote({ - @required String repoPath, - @required String cloneUrl, - @required String remoteName, - @required String sshPublicKey, - @required String sshPrivateKey, - @required String sshPassword, - @required String authorName, - @required String authorEmail, + required String repoPath, + required String cloneUrl, + required String remoteName, + required String sshPublicKey, + required String sshPrivateKey, + required String sshPassword, + required String authorName, + required String authorEmail, }) async { var repo = await GitRepository.load(repoPath); @@ -42,11 +39,11 @@ Future cloneRemote({ var branches = await repo.branches(); if (branches.isEmpty) { Log.i("Completing - no local branch"); - var remoteBranch = await repo.remoteBranch(remoteName, remoteBranchName); + var remoteBranch = await repo.remoteBranch(remoteName, remoteBranchName!); - if (remoteBranchName != null && - remoteBranchName.isNotEmpty && - remoteBranch != null) { + // FIXME: This logic doesn't seem right. What if the remoteBranchName is empty + if (/*remoteBranchName != null &&*/ + remoteBranchName.isNotEmpty && remoteBranch != null) { await repo.createBranch(remoteBranchName, hash: remoteBranch.hash); await repo.checkoutBranch(remoteBranchName); } @@ -66,7 +63,7 @@ Future cloneRemote({ await repo.checkoutBranch(branch); } - await repo.setUpstreamTo(remote, remoteBranchName); + await repo.setUpstreamTo(remote, remoteBranchName!); var remoteBranch = await repo.remoteBranch(remoteName, remoteBranchName); if (remoteBranch != null) { Log.i("Merging '$remoteName/$remoteBranchName'"); @@ -78,7 +75,7 @@ Future cloneRemote({ } } else { Log.i("Completing - localBranch diff remote: $branch $remoteBranchName"); - await repo.createBranch(remoteBranchName); + await repo.createBranch(remoteBranchName!); await repo.checkoutBranch(remoteBranchName); await repo.deleteBranch(branch); @@ -102,13 +99,13 @@ Future cloneRemote({ await repo.checkout("."); } -Future _remoteDefaultBranch({ - @required GitRepository repo, - @required git_bindings.GitRepo libGit2Repo, - @required String remoteName, - @required String sshPublicKey, - @required String sshPrivateKey, - @required String sshPassword, +Future _remoteDefaultBranch({ + required GitRepository repo, + required git_bindings.GitRepo libGit2Repo, + required String remoteName, + required String sshPublicKey, + required String sshPrivateKey, + required String sshPassword, }) async { try { var branch = await libGit2Repo.defaultBranch( @@ -129,7 +126,7 @@ Future _remoteDefaultBranch({ if (remoteBranch == null) { return 'master'; } - return remoteBranch.target.branchName(); + return remoteBranch.target!.branchName(); } String folderNameFromCloneUrl(String cloneUrl) { diff --git a/lib/setup/clone_url.dart b/lib/setup/clone_url.dart index 00ba4004..72c97e75 100644 --- a/lib/setup/clone_url.dart +++ b/lib/setup/clone_url.dart @@ -1,5 +1,3 @@ -// @dart=2.9 - import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -15,8 +13,8 @@ class GitCloneUrlPage extends StatefulWidget { final String initialValue; GitCloneUrlPage({ - @required this.doneFunction, - @required this.initialValue, + required this.doneFunction, + required this.initialValue, }); @override @@ -35,10 +33,10 @@ class GitCloneUrlPageState extends State { @override Widget build(BuildContext context) { final formSubmitted = () { - if (_formKey.currentState.validate()) { - _formKey.currentState.save(); + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); - var url = sshUrlKey.currentState.value; + var url = sshUrlKey.currentState!.value!; widget.doneFunction(url.trim()); inputFormFocus.unfocus(); } @@ -95,10 +93,10 @@ class GitCloneUrlKnownProviderPage extends StatefulWidget { final String initialValue; GitCloneUrlKnownProviderPage({ - @required this.doneFunction, - @required this.launchCreateUrlPage, - @required this.gitHostType, - @required this.initialValue, + required this.doneFunction, + required this.launchCreateUrlPage, + required this.gitHostType, + required this.initialValue, }); @override @@ -118,10 +116,10 @@ class GitCloneUrlKnownProviderPageState @override Widget build(BuildContext context) { final formSubmitted = () { - if (_formKey.currentState.validate()) { - _formKey.currentState.save(); + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); - var url = sshUrlKey.currentState.value; + var url = sshUrlKey.currentState!.value!; widget.doneFunction(url.trim()); inputFormFocus.unfocus(); } @@ -185,8 +183,8 @@ class GitCloneUrlKnownProviderPageState } // Returns null when valid -String _isCloneUrlValid(String url) { - url = url.trim(); +String? _isCloneUrlValid(String? url) { + url = url!.trim(); if (url.isEmpty) { return tr("setup.cloneUrl.validator.empty"); } diff --git a/lib/setup/key_editors.dart b/lib/setup/key_editors.dart index 0ec609c4..cfdb91b3 100644 --- a/lib/setup/key_editors.dart +++ b/lib/setup/key_editors.dart @@ -1,5 +1,3 @@ -// @dart=2.9 - import 'dart:io'; import 'package:flutter/material.dart'; @@ -20,7 +18,11 @@ class PublicKeyEditor extends StatelessWidget { return KeyEditor(formKey, _controller, _validator); } - String _validator(String val) { + String? _validator(String? val) { + if (val == null) { + return null; + } + val = val.trim(); if (!val.startsWith("ssh-rsa ")) { return tr("setup.keyEditors.public"); @@ -40,7 +42,11 @@ class PrivateKeyEditor extends StatelessWidget { return KeyEditor(formKey, _controller, _validator); } - String _validator(String val) { + String? _validator(String? val) { + if (val == null) { + return null; + } + val = val.trim(); if (!val.startsWith("-----BEGIN ")) { return tr("setup.keyEditors.private"); @@ -56,13 +62,9 @@ class PrivateKeyEditor extends StatelessWidget { class KeyEditor extends StatelessWidget { final Key formKey; final TextEditingController textEditingController; - final Function validator; + final String? Function(String?) validator; - KeyEditor(this.formKey, this.textEditingController, this.validator) { - assert(formKey != null); - assert(textEditingController != null); - assert(validator != null); - } + KeyEditor(this.formKey, this.textEditingController, this.validator); @override Widget build(BuildContext context) { @@ -109,7 +111,7 @@ class KeyEditor extends StatelessWidget { var result = await FilePicker.platform.pickFiles(); if (result != null) { - var file = File(result.files.single.path); + var file = File(result.files.single.path!); try { var data = await file.readAsString(); textEditingController.text = data.trim(); diff --git a/lib/setup/repo_selector.dart b/lib/setup/repo_selector.dart index 22c9bd2c..61f366ec 100644 --- a/lib/setup/repo_selector.dart +++ b/lib/setup/repo_selector.dart @@ -1,5 +1,3 @@ -// @dart=2.9 - import 'package:flutter/material.dart'; import 'package:collection/collection.dart'; @@ -27,9 +25,9 @@ class GitHostSetupRepoSelector extends StatefulWidget { final Func1 onDone; GitHostSetupRepoSelector({ - @required this.gitHost, - @required this.userInfo, - @required this.onDone, + required this.gitHost, + required this.userInfo, + required this.onDone, }); @override @@ -44,14 +42,15 @@ class GitHostSetupRepoSelectorState extends State { List repos = []; var fetchedRepos = false; - GitHostRepo selectedRepo; - var _textController = TextEditingController(); + GitHostRepo? selectedRepo; + late TextEditingController _textController; bool createRepo = false; @override void initState() { super.initState(); + _textController = TextEditingController(); _textController.addListener(() { var q = _textController.text.toLowerCase(); if (q.isEmpty) { @@ -85,7 +84,7 @@ class GitHostSetupRepoSelectorState extends State { var allRepos = await widget.gitHost.listRepos(); allRepos.sort((GitHostRepo a, GitHostRepo b) { if (a.updatedAt != null && b.updatedAt != null) { - return a.updatedAt.compareTo(b.updatedAt); + return a.updatedAt!.compareTo(b.updatedAt!); } if (a.updatedAt == null && b.updatedAt == null) { return a.fullName.compareTo(b.fullName); @@ -138,7 +137,7 @@ class GitHostSetupRepoSelectorState extends State { @override Widget build(BuildContext context) { - if (errorMessage != null && errorMessage.isNotEmpty) { + if (errorMessage.isNotEmpty) { return GitHostSetupErrorPage(errorMessage); } if (!fetchedRepos) { @@ -218,7 +217,7 @@ class GitHostSetupRepoSelectorState extends State { text: tr('setup.next'), onPressed: () async { if (selectedRepo != null) { - widget.onDone(selectedRepo); + widget.onDone(selectedRepo!); return; } @@ -228,7 +227,7 @@ class GitHostSetupRepoSelectorState extends State { widget.onDone(repo); return; } catch (e, stacktrace) { - _handleGitHostException(e, stacktrace); + _handleGitHostException(e as Exception, stacktrace); } }, ), @@ -287,14 +286,14 @@ List filterList(List repos, String q) { class _RepoTile extends StatelessWidget { final GitHostRepo repo; final String searchText; - final Function onTap; + final void Function() onTap; final bool selected; _RepoTile({ - @required this.repo, - @required this.searchText, - @required this.onTap, - @required this.selected, + required this.repo, + required this.searchText, + required this.onTap, + required this.selected, }); @override @@ -350,7 +349,7 @@ class _RepoTile extends StatelessWidget { text: repo.name, highlightText: searchText, highlightTextLowerCase: searchText, - style: style, + style: style!, highlightStyle: style.copyWith(fontWeight: FontWeight.bold), ).build(context), ], @@ -401,8 +400,8 @@ class _IconText extends StatelessWidget { */ class _SmartDateTime extends StatelessWidget { - final DateTime dt; - final TextStyle style; + final DateTime? dt; + final TextStyle? style; _SmartDateTime(this.dt, this.style); @@ -412,12 +411,13 @@ class _SmartDateTime extends StatelessWidget { @override Widget build(BuildContext context) { - if (dt == null) { + if (this.dt == null) { return Container(); } String text; + var dt = this.dt!; if (dt.isAfter(thirtyDaysAgo)) { Locale locale = Localizations.localeOf(context); text = timeago.format(dt, locale: locale.languageCode); diff --git a/lib/setup/screens.dart b/lib/setup/screens.dart index 2c49f8cd..74c93d11 100644 --- a/lib/setup/screens.dart +++ b/lib/setup/screens.dart @@ -1,5 +1,3 @@ -// @dart=2.9 - import 'dart:io'; import 'package:flutter/material.dart'; @@ -36,9 +34,9 @@ class GitHostSetupScreen extends StatefulWidget { final Func2> onCompletedFunction; GitHostSetupScreen({ - @required this.repoFolderName, - @required this.remoteName, - @required this.onCompletedFunction, + required this.repoFolderName, + required this.remoteName, + required this.onCompletedFunction, }); @override @@ -61,21 +59,21 @@ class GitHostSetupScreenState extends State { var _keyGenerationChoice = KeyGenerationChoice.Unknown; var _gitHostType = GitHostType.Unknown; - GitHost _gitHost; - GitHostRepo _gitHostRepo; + GitHost? _gitHost; + late GitHostRepo _gitHostRepo; String _autoConfigureMessage = ""; String _autoConfigureErrorMessage = ""; var _gitCloneUrl = ""; - var gitCloneErrorMessage = ""; + String? gitCloneErrorMessage = ""; var publicKey = ""; var pageController = PageController(); int _currentPageIndex = 0; - UserInfo _userInfo; + UserInfo? _userInfo; - Widget _buildPage(BuildContext context, int pos) { + Widget? _buildPage(BuildContext context, int pos) { assert(_pageCount >= 1); if (pos == 0) { @@ -179,14 +177,20 @@ class GitHostSetupScreenState extends State { } else if (_pageChoice[1] == PageChoice1.Auto) { return GitHostSetupAutoConfigure( gitHostType: _gitHostType, - onDone: (GitHost gitHost, UserInfo userInfo) { - setState(() { - _gitHost = gitHost; - _userInfo = userInfo; - _pageCount = pos + 2; + onDone: (GitHost? gitHost, UserInfo? userInfo) { + if (gitHost == null) { + setState(() { + // FIXME: Set an error when it failed to get the gitHost + }); + } else { + setState(() { + _gitHost = gitHost; + _userInfo = userInfo; + _pageCount = pos + 2; - _nextPage(); - }); + _nextPage(); + }); + } }, ); } @@ -259,8 +263,8 @@ class GitHostSetupScreenState extends State { ); } else if (_pageChoice[1] == PageChoice1.Auto) { return GitHostSetupRepoSelector( - gitHost: _gitHost, - userInfo: _userInfo, + gitHost: _gitHost!, + userInfo: _userInfo!, onDone: (GitHostRepo repo) { // close keyboard FocusManager.instance.primaryFocus?.unfocus(); @@ -355,7 +359,7 @@ class GitHostSetupScreenState extends State { Widget build(BuildContext context) { var pageView = PageView.builder( controller: pageController, - itemBuilder: _buildPage, + itemBuilder: _buildPage as Widget Function(BuildContext, int), itemCount: _pageCount, onPageChanged: (int pageNum) { setState(() { @@ -457,9 +461,9 @@ class GitHostSetupScreenState extends State { "-" + DateTime.now().toIso8601String().substring(0, 10); // only the date - generateSSHKeys(comment: comment).then((SshKey sshKey) { + generateSSHKeys(comment: comment).then((SshKey? sshKey) { var settings = Provider.of(context, listen: false); - settings.sshPublicKey = sshKey.publicKey; + settings.sshPublicKey = sshKey!.publicKey; settings.sshPrivateKey = sshKey.privateKey; settings.sshPassword = sshKey.password; settings.save(); @@ -528,7 +532,7 @@ class GitHostSetupScreenState extends State { } void _startGitClone(BuildContext context) async { - if (gitCloneErrorMessage.isNotEmpty) { + if (gitCloneErrorMessage!.isNotEmpty) { return; } @@ -539,7 +543,7 @@ class GitHostSetupScreenState extends State { var repoPath = p.join(basePath, widget.repoFolderName); Log.i("RepoPath: $repoPath"); - String error; + String? error; try { await cloneRemote( cloneUrl: _gitCloneUrl, @@ -560,7 +564,7 @@ class GitHostSetupScreenState extends State { Log.i("Not completing gitClone because of error"); setState(() { logEvent(Event.GitHostSetupGitCloneError, parameters: { - 'error': error, + 'error': error!, }); gitCloneErrorMessage = error; }); @@ -602,6 +606,10 @@ class GitHostSetupScreenState extends State { _autoConfigureMessage = tr('setup.sshKey.generate'); }); var sshKey = await generateSSHKeys(comment: "GitJournal"); + if (sshKey == null) { + // FIXME: Handle case when sshKey generation failed + return; + } var settings = Provider.of(context, listen: false); settings.sshPublicKey = sshKey.publicKey; settings.sshPrivateKey = sshKey.privateKey; @@ -615,7 +623,7 @@ class GitHostSetupScreenState extends State { Log.i("Adding as a deploy key"); _autoConfigureMessage = tr('setup.sshKey.addDeploy'); - await _gitHost.addDeployKey(publicKey, _gitHostRepo.fullName); + await _gitHost!.addDeployKey(publicKey, _gitHostRepo.fullName); } on Exception catch (e, stacktrace) { _handleGitHostException(e, stacktrace); return; @@ -677,8 +685,8 @@ class GitHostChoicePage extends StatelessWidget { final Func0 onCustomGitHost; GitHostChoicePage({ - @required this.onKnownGitHost, - @required this.onCustomGitHost, + required this.onKnownGitHost, + required this.onCustomGitHost, }); @override @@ -729,7 +737,7 @@ enum GitHostSetupType { class GitHostAutoConfigureChoicePage extends StatelessWidget { final Func1 onDone; - GitHostAutoConfigureChoicePage({@required this.onDone}); + GitHostAutoConfigureChoicePage({required this.onDone}); @override Widget build(BuildContext context) {