Skip to content

Commit

Permalink
Null Safe!
Browse files Browse the repository at this point in the history
Changelog 1.2.0:
- Upgraded from Dart 2.11.0 to 2.12.3 for null safety
- The animated_check package is not null safe and was removed
- animated_check is now local and null safe. Will be making a PR soon on the official Github
The following files have been updated to be null safe
- DriveHelper.dart
- FileAppendDialog.dart
- HomePage.dart
- LogOutDialog.dart
  • Loading branch information
theRookieCoder committed May 8, 2021
1 parent 383bce7 commit ae95a8c
Show file tree
Hide file tree
Showing 7 changed files with 178 additions and 67 deletions.
50 changes: 26 additions & 24 deletions lib/DriveHelper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,30 +12,30 @@ import 'package:package_info_plus/package_info_plus.dart' show PackageInfo;
import 'package:url_launcher/url_launcher.dart' show launch;

class DriveHelper {
String logFileID; // FileID of log file
String appFolderID; // FileID of the folder the log file is in
DriveApi driveApi; // Google Drive API
GoogleSignInAccount account; // Google user account
String version; // Version of app for about
GoogleSignIn signInScopes; // For signing out
late String logFileID; // FileID of log file
late String appFolderID; // FileID of the folder the log file is in
late DriveApi driveApi; // Google Drive API
late GoogleSignInAccount account; // Google user account
late String version; // Version of app for about
late GoogleSignIn signInScopes; // For signing out

DriveHelper();

GoogleUserCircleAvatar getAvatar() =>
GoogleUserCircleAvatar(identity: account);

String getDisplayName() => account.displayName;
String getDisplayName() => account.displayName!;

String getEmail() => account.email;

void showLogFile() =>
launch("https://docs.google.com/spreadsheets/d/$logFileID/");

Future<GoogleSignInAccount> signInWithGoogle(
Future<GoogleSignInAccount?> signInWithGoogle(
GoogleSignIn googleDriveSignIn,
) async {
// Silent sign in doesn't require user input
GoogleSignInAccount account = await googleDriveSignIn.signInSilently();
GoogleSignInAccount? account = await googleDriveSignIn.signInSilently();
if (account == null) {
print("Silent sign in failed");
account = await googleDriveSignIn.signIn();
Expand All @@ -58,7 +58,14 @@ class DriveHelper {
signInScopes = GoogleSignIn.standard(
scopes: [DriveApi.driveFileScope],
);
account = await signInWithGoogle(signInScopes).catchError((e) => throw e);
GoogleSignInAccount? testAccount =
await signInWithGoogle(signInScopes).catchError((e) => throw e);

if (testAccount == null) {
throw "Google user account null";
} else {
account = testAccount;
}

// Then initialise all the variables

Expand Down Expand Up @@ -112,19 +119,18 @@ class DriveHelper {
spaces:
'drive'); // Use name to search and make sure it isn't in the bin

if (search.files.length == 0) {
return null;
if (search.files!.length == 0) {
throw "File not found";
}
return search.files[0].id;
return search.files![0].id!;
}

Future<String> exportFileData(String fileID) async {
Media fileMedia = await driveApi.files
Future<String?> exportFileData(String fileID) async {
Media? fileMedia = await driveApi.files
.export(fileID, "text/csv", downloadOptions: DownloadOptions.fullMedia);

String fileData;

await fileMedia.stream.listen((event) {
String? fileData;
await fileMedia!.stream.listen((event) {
fileData = String.fromCharCodes(event);
}).asFuture();
return fileData;
Expand All @@ -146,11 +152,7 @@ class DriveHelper {
);
await driveApi.files
.update(new File(), logFileID, uploadMedia: media)
.onError((error, stackTrace) {
print("Error: $error was caught by DriveHelper");
print("This was the stack trace when the exception was caught: ");
print(stackTrace);
return null;
}); // Update the existing file with the new data
.onError((error, stackTrace) =>
throw "File update failed with $error"); // Update the existing file with the new data
}
}
12 changes: 6 additions & 6 deletions lib/FileAppendDialog.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import 'package:bp_logger/DriveHelper.dart';
import 'package:flutter/material.dart';
import 'package:animated_check/animated_check.dart';
import 'animated_check.dart';

class FileAppendDialog extends StatefulWidget {
const FileAppendDialog({
Key key,
@required this.text,
@required this.driveHelper,
Key? key,
required this.text,
required this.driveHelper,
}) : super(key: key);

final String text;
Expand All @@ -18,8 +18,8 @@ class FileAppendDialog extends StatefulWidget {

class _FileAppendDialogState extends State<FileAppendDialog>
with SingleTickerProviderStateMixin {
AnimationController _animationController;
Animation<double> _animation;
late AnimationController _animationController;
late Animation<double> _animation;
String title = "";

@override
Expand Down
26 changes: 13 additions & 13 deletions lib/HomePage.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import 'LogOutDialog.dart'; // For logging out
import "DriveHelper.dart"; // Backend stuff

class HomePage extends StatefulWidget {
const HomePage({Key key, @required this.driveHelper}) : super(key: key);
const HomePage({Key? key, required this.driveHelper}) : super(key: key);
final DriveHelper driveHelper;

@override
Expand All @@ -20,7 +20,7 @@ class _HomePageState extends State<HomePage> {
static DateTime date = new DateTime.now();
var textFieldController1 = TextEditingController(); // Diastolic
var textFieldController2 = TextEditingController(); // Systolic
DriveHelper driveHelper; // "Backend" interface
DriveHelper? driveHelper; // "Backend" interface

// To get 3/4ths of the screen to display the drawer to a suitable width on all devices
double _getDrawerWidth(context) {
Expand All @@ -41,11 +41,11 @@ class _HomePageState extends State<HomePage> {

// Datepicker for selecting the date
_selectDate(BuildContext context) async {
final DateTime picked = await showDatePicker(
final DateTime? picked = await showDatePicker(
context: context,
initialDate: date,
firstDate: DateTime(2015),
lastDate: DateTime(3000),
firstDate: DateTime.now().subtract(Duration(days: 7)),
lastDate: DateTime.now(),
);
if (picked != null && picked != date) {
// Only update if user picked and isn"t the same as before
Expand Down Expand Up @@ -76,22 +76,22 @@ class _HomePageState extends State<HomePage> {
child: Container(
height: _getDrawerWidth(context) / 2.5,
width: _getDrawerWidth(context) / 2.5,
child: driveHelper.getAvatar(),
child: driveHelper!.getAvatar(),
),
),
// Name of user
FittedBox(
fit: BoxFit.scaleDown,
child: Text(
driveHelper.getDisplayName(),
driveHelper!.getDisplayName(),
style: Theme.of(context).textTheme.headline4,
),
),
// Email ID of user
FittedBox(
fit: BoxFit.scaleDown,
child: Text(
driveHelper.getEmail(),
driveHelper!.getEmail(),
style: Theme.of(context).textTheme.headline6,
),
)
Expand All @@ -107,7 +107,7 @@ class _HomePageState extends State<HomePage> {
showDialog(
context: context,
builder: (BuildContext context) {
return LogOutDialog(logOut: driveHelper.signOut);
return LogOutDialog(logOut: driveHelper!.signOut);
},
);
},
Expand All @@ -116,7 +116,7 @@ class _HomePageState extends State<HomePage> {
ListTile(
leading: Icon(Icons.insert_drive_file_outlined),
title: Text("Access file"),
onTap: driveHelper.showLogFile,
onTap: driveHelper!.showLogFile,
),
// For opening the support page
ListTile(
Expand All @@ -135,7 +135,7 @@ class _HomePageState extends State<HomePage> {
builder: (BuildContext context) {
return AboutDialog(
applicationName: "BP Logger",
applicationVersion: "Version ${driveHelper.version}",
applicationVersion: "Version ${driveHelper!.version}",
children: <Widget>[
Padding(
padding: EdgeInsets.only(left: 20),
Expand All @@ -150,7 +150,7 @@ class _HomePageState extends State<HomePage> {
text: "in Github",
style: Theme.of(context)
.textTheme
.caption
.caption!
.apply(
color: Colors.blue,
),
Expand Down Expand Up @@ -272,7 +272,7 @@ class _HomePageState extends State<HomePage> {
builder: (BuildContext context) {
return FileAppendDialog(
text: text,
driveHelper: driveHelper,
driveHelper: driveHelper!,
);
},
barrierDismissible: false,
Expand Down
8 changes: 3 additions & 5 deletions lib/LogOutDialog.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import 'package:flutter/material.dart'; // UI

class LogOutDialog extends StatefulWidget {
const LogOutDialog({
Key key,
@required this.logOut,
}) : super(key: key);
const LogOutDialog({Key? key, required this.logOut}) : super(key: key);
final Future<void> Function() logOut;

@override
Expand All @@ -18,7 +15,8 @@ class _LogOutDialogState extends State<LogOutDialog> {
title: Text(
"Logout instructions",
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.headline4.apply(fontSizeFactor: 0.9),
style:
Theme.of(context).textTheme.headline4!.apply(fontSizeFactor: 0.9),
),
content: Text(
"To logout, follow the steps below\n 1. Click the logout button below\n 2. Close the website/app in the task switcher\n 3. Open the app again and sign in",
Expand Down
119 changes: 119 additions & 0 deletions lib/animated_check.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// https://github.com/chrisedg87/flutter_animated_check
// MIT License
// By chrisedg87
// Copied for null safety purposes

import 'dart:ui';

import 'package:flutter/material.dart';

class AnimatedCheck extends StatefulWidget {
AnimatedCheck({
Key? key,
required this.progress,
required this.size,
this.color,
this.strokeWidth,
}) : super(key: key);

final Animation<double> progress;
final double size; // The size of the checkmark
final Color? color; // The primary color of the checkmark
final double? strokeWidth; // The width of the checkmark stroke

@override
State<StatefulWidget> createState() => AnimatedCheckState();
}

class AnimatedCheckState extends State<AnimatedCheck>
with SingleTickerProviderStateMixin {
@override
Widget build(BuildContext context) {
return CustomPaint(
foregroundPainter: AnimatedPathPainter(
widget.progress,
widget.color ?? Theme.of(context).primaryColor,
widget.strokeWidth,
),
child: new SizedBox(
width: widget.size,
height: widget.size,
),
);
}
}

class AnimatedPathPainter extends CustomPainter {
AnimatedPathPainter(
this._animation,
this._color,
this.strokeWidth,
) : super(repaint: _animation);

final Animation<double> _animation;
final Color _color;
final double? strokeWidth;

Path _createAnyPath(Size size) {
return Path()
..moveTo(0.27083 * size.width, 0.54167 * size.height)
..lineTo(0.41667 * size.width, 0.68750 * size.height)
..lineTo(0.75000 * size.width, 0.35417 * size.height);
}

Path createAnimatedPath(Path originalPath, double animationPercent) {
final totalLength = originalPath
.computeMetrics()
.fold(0.0, (double prev, PathMetric metric) => prev + metric.length);

final currentLength = totalLength * animationPercent;

return extractPathUntilLength(originalPath, currentLength);
}

Path extractPathUntilLength(Path originalPath, double length) {
var currentLength = 0.0;

final path = new Path();

var metricsIterator = originalPath.computeMetrics().iterator;

while (metricsIterator.moveNext()) {
var metric = metricsIterator.current;

var nextLength = currentLength + metric.length;

final isLastSegment = nextLength > length;
if (isLastSegment) {
final remainingLength = length - currentLength;
final pathSegment = metric.extractPath(0.0, remainingLength);

path.addPath(pathSegment, Offset.zero);
break;
} else {
final pathSegment = metric.extractPath(0.0, metric.length);
path.addPath(pathSegment, Offset.zero);
}

currentLength = nextLength;
}

return path;
}

@override
void paint(Canvas canvas, Size size) {
final animationPercent = this._animation.value;
final path = createAnimatedPath(_createAnyPath(size), animationPercent);
final Paint paint = Paint();

paint.color = _color;
paint.style = PaintingStyle.stroke;
paint.strokeWidth = strokeWidth ?? size.width * 0.06;

canvas.drawPath(path, paint);
}

@override
bool shouldRepaint(CustomPainter oldDelegate) => true;
}
Loading

0 comments on commit ae95a8c

Please sign in to comment.