Setup: Migrate to null safety

This commit is contained in:
Vishesh Handa
2021-06-02 08:42:13 +02:00
parent a65477080e
commit a5b6940884
7 changed files with 125 additions and 124 deletions

@ -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<GitHost, UserInfo, void> onDone;
final Func2<GitHost?, UserInfo?, void> 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<GitHostSetupAutoConfigure> {
GitHost gitHost;
GitHost? gitHost;
String errorMessage = "";
bool _configuringStarted = false;
@ -46,7 +44,7 @@ class GitHostSetupAutoConfigureState extends State<GitHostSetupAutoConfigure> {
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<GitHostSetupAutoConfigure> {
}
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<Settings>(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<GitHostSetupAutoConfigure> {
});
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<GitHostSetupAutoConfigure> {
@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<GitHostSetupAutoConfigure> {
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,
),
),

@ -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<void> 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();
}

@ -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<void> 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<void> 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<void> 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<void> 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<void> cloneRemote({
await repo.checkout(".");
}
Future<String> _remoteDefaultBranch({
@required GitRepository repo,
@required git_bindings.GitRepo libGit2Repo,
@required String remoteName,
@required String sshPublicKey,
@required String sshPrivateKey,
@required String sshPassword,
Future<String?> _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<String> _remoteDefaultBranch({
if (remoteBranch == null) {
return 'master';
}
return remoteBranch.target.branchName();
return remoteBranch.target!.branchName();
}
String folderNameFromCloneUrl(String cloneUrl) {

@ -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<GitCloneUrlPage> {
@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");
}

@ -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();

@ -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<GitHostRepo, void> 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<GitHostSetupRepoSelector> {
List<GitHostRepo> 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<GitHostSetupRepoSelector> {
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<GitHostSetupRepoSelector> {
@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<GitHostSetupRepoSelector> {
text: tr('setup.next'),
onPressed: () async {
if (selectedRepo != null) {
widget.onDone(selectedRepo);
widget.onDone(selectedRepo!);
return;
}
@ -228,7 +227,7 @@ class GitHostSetupRepoSelectorState extends State<GitHostSetupRepoSelector> {
widget.onDone(repo);
return;
} catch (e, stacktrace) {
_handleGitHostException(e, stacktrace);
_handleGitHostException(e as Exception, stacktrace);
}
},
),
@ -287,14 +286,14 @@ List<GitHostRepo> filterList(List<GitHostRepo> 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);

@ -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<String, String, Future<void>> 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<GitHostSetupScreen> {
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<GitHostSetupScreen> {
} 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<GitHostSetupScreen> {
);
} 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<GitHostSetupScreen> {
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<GitHostSetupScreen> {
"-" +
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<Settings>(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<GitHostSetupScreen> {
}
void _startGitClone(BuildContext context) async {
if (gitCloneErrorMessage.isNotEmpty) {
if (gitCloneErrorMessage!.isNotEmpty) {
return;
}
@ -539,7 +543,7 @@ class GitHostSetupScreenState extends State<GitHostSetupScreen> {
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<GitHostSetupScreen> {
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<GitHostSetupScreen> {
_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<Settings>(context, listen: false);
settings.sshPublicKey = sshKey.publicKey;
settings.sshPrivateKey = sshKey.privateKey;
@ -615,7 +623,7 @@ class GitHostSetupScreenState extends State<GitHostSetupScreen> {
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<void> 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<GitHostSetupType, void> onDone;
GitHostAutoConfigureChoicePage({@required this.onDone});
GitHostAutoConfigureChoicePage({required this.onDone});
@override
Widget build(BuildContext context) {