diameter/lib/data_export.dart

367 lines
13 KiB
Dart
Raw Permalink Normal View History

import 'dart:convert';
import 'dart:io';
import 'package:diameter/localization_keys.dart';
import 'package:diameter/models/accuracy.dart';
import 'package:diameter/models/basal.dart';
import 'package:diameter/models/basal_profile.dart';
import 'package:diameter/models/bolus.dart';
import 'package:diameter/models/bolus_profile.dart';
import 'package:diameter/models/glucose_target.dart';
import 'package:diameter/models/log_bolus.dart';
import 'package:diameter/models/log_entry.dart';
import 'package:diameter/models/log_event.dart';
import 'package:diameter/models/log_event_type.dart';
import 'package:diameter/models/log_meal.dart';
import 'package:diameter/models/meal.dart';
import 'package:diameter/models/meal_category.dart';
import 'package:diameter/models/meal_portion_type.dart';
import 'package:diameter/models/meal_source.dart';
import 'package:diameter/models/settings.dart';
import 'package:flutter_translate/flutter_translate.dart';
// import 'package:flutter/material.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:intl/intl.dart';
import 'package:path_provider/path_provider.dart';
import 'package:http/http.dart' as http;
import 'package:googleapis/drive/v3.dart' as drive;
class GoogleAuthClient extends http.BaseClient {
final Map<String, String> _headers;
final http.Client _client = http.Client();
GoogleAuthClient(this._headers);
@override
Future<http.StreamedResponse> send(http.BaseRequest request) {
return _client.send(request..headers.addAll(_headers));
}
}
class DataExport {
static Map<String, dynamic> appDataToJson(DateTime timestamp) {
final Map<String, dynamic> data = <String, dynamic>{};
data['exportDate'] = timestamp.toString();
data['accuracies'] =
Accuracy.box.getAll().map((accuracy) => accuracy.toJson()).toList();
data['basalProfiles'] = BasalProfile.box
.getAll()
.map((basalProfile) => basalProfile.toJson())
.toList();
data['basalRates'] =
Basal.box.getAll().map((basal) => basal.toJson()).toList();
data['bolusProfiles'] = BolusProfile.box
.getAll()
.map((bolusProfile) => bolusProfile.toJson())
.toList();
data['bolusRates'] =
Bolus.box.getAll().map((bolusRates) => bolusRates.toJson()).toList();
data['glucoseTargets'] = GlucoseTarget.box
.getAll()
.map((glucoseTarget) => glucoseTarget.toJson())
.toList();
data['logBoli'] =
LogBolus.box.getAll().map((logBolus) => logBolus.toJson()).toList();
data['logEntries'] =
LogEntry.box.getAll().map((logEntry) => logEntry.toJson()).toList();
data['logEventTypes'] = LogEventType.box
.getAll()
.map((logEventType) => logEventType.toJson())
.toList();
data['logEvents'] =
LogEvent.box.getAll().map((logEvent) => logEvent.toJson()).toList();
data['logMeals'] =
LogMeal.box.getAll().map((logMeal) => logMeal.toJson()).toList();
data['mealCategories'] = MealCategory.box
.getAll()
.map((mealCategory) => mealCategory.toJson())
.toList();
data['mealPortionTypes'] = MealPortionType.box
.getAll()
.map((mealPortionType) => mealPortionType.toJson())
.toList();
data['mealSources'] = MealSource.box
.getAll()
.map((mealSource) => mealSource.toJson())
.toList();
data['meals'] = Meal.box.getAll().map((meal) => meal.toJson()).toList();
data['settings'] = Settings.toJson();
return data;
}
List<String> appDataFromJson(File file,
{String source = '', bool overrideExisting = true, bool skipDeleted = false}) {
final Map<String, dynamic> data = json.decode(file.openRead().toString());
final List<String> errors = [];
final exportDate = DateTime.tryParse(data['exportDate']);
if (exportDate != null && Settings.lastExportTimeStamp != null && exportDate.isAfter(Settings.lastExportTimeStamp!)) {
if (data.keys.contains('accuracies')) {
for (var entry in data['accuracies']) {
if (!skipDeleted || entry['deleted'] == false) {
final error = Accuracy.putFromJson(entry, overrideExisting, source);
if (error != null) {
errors.add(translate(LocalizationKeys.export_error, args: {"data": entry}));
}
}
}
}
if (data.keys.contains('basalProfiles')) {
for (var entry in data['basalProfiles']) {
if (!skipDeleted || entry['deleted'] == false) {
final error = BasalProfile.putFromJson(entry, overrideExisting, source);
if (error != null) {
errors.add(translate(LocalizationKeys.export_error, args: {"data": entry}));
}
}
}
}
if (data.keys.contains('basalRates')) {
for (var entry in data['basalRates']) {
if (!skipDeleted || entry['deleted'] == false) {
final error = Basal.putFromJson(entry, overrideExisting, source);
if (error != null) {
errors.add(translate(LocalizationKeys.export_error, args: {"data": entry}));
}
}
}
}
if (data.keys.contains('bolusRates')) {
for (var entry in data['bolusRates']) {
if (!skipDeleted || entry['deleted'] == false) {
final error = Bolus.putFromJson(entry, overrideExisting, source);
if (error != null) {
errors.add(translate(LocalizationKeys.export_error, args: {"data": entry}));
}
}
}
}
if (data.keys.contains('glucoseTargets')) {
for (var entry in data['glucoseTargets']) {
if (!skipDeleted || entry['deleted'] == false) {
final error = GlucoseTarget.putFromJson(entry, overrideExisting, source);
if (error != null) {
errors.add(translate(LocalizationKeys.export_error, args: {"data": entry}));
}
}
}
}
if (data.keys.contains('logBoli')) {
for (var entry in data['logBoli']) {
if (!skipDeleted || entry['deleted'] == false) {
final error = LogBolus.putFromJson(entry, overrideExisting, source);
if (error != null) {
errors.add(translate(LocalizationKeys.export_error, args: {"data": entry}));
}
}
}
}
if (data.keys.contains('logEntries')) {
for (var entry in data['logEntries']) {
if (!skipDeleted || entry['deleted'] == false) {
final error = LogEntry.putFromJson(entry, overrideExisting, source);
if (error != null) {
errors.add(translate(LocalizationKeys.export_error, args: {"data": entry}));
}
}
}
}
if (data.keys.contains('logEvents')) {
for (var entry in data['logEvents']) {
if (!skipDeleted || entry['deleted'] == false) {
final error = LogEvent.putFromJson(entry, overrideExisting, source);
if (error != null) {
errors.add(translate(LocalizationKeys.export_error, args: {"data": entry}));
}
}
}
}
if (data.keys.contains('logMeals')) {
for (var entry in data['logMeals']) {
if (!skipDeleted || entry['deleted'] == false) {
final error = LogMeal.putFromJson(entry, overrideExisting, source);
if (error != null) {
errors.add(translate(LocalizationKeys.export_error, args: {"data": entry}));
}
}
}
}
if (data.keys.contains('mealCategories')) {
for (var entry in data['mealCategories']) {
if (!skipDeleted || entry['deleted'] == false) {
final error = MealCategory.putFromJson(entry, overrideExisting, source);
if (error != null) {
errors.add(translate(LocalizationKeys.export_error, args: {"data": entry}));
}
}
}
}
if (data.keys.contains('mealPortionTypes')) {
for (var entry in data['mealPortionTypes']) {
if (!skipDeleted || entry['deleted'] == false) {
final error = MealPortionType.putFromJson(entry, overrideExisting, source);
if (error != null) {
errors.add(translate(LocalizationKeys.export_error, args: {"data": entry}));
}
}
}
}
if (data.keys.contains('mealSources')) {
for (var entry in data['mealSources']) {
if (!skipDeleted || entry['deleted'] == false) {
final error = MealSource.putFromJson(entry, overrideExisting, source);
if (error != null) {
errors.add(translate(LocalizationKeys.export_error, args: {"data": entry}));
}
}
}
}
if (data.keys.contains('meals')) {
for (var entry in data['meals']) {
if (!skipDeleted || entry['deleted'] == false) {
final error = Meal.putFromJson(entry, overrideExisting, source);
if (error != null) {
errors.add(translate(LocalizationKeys.export_error, args: {"data": entry}));
}
}
}
}
} else {
// show confirmation dialog because export is newer than last saved timestamp
}
return errors;
}
static Future<File> exportDataToFile(DateTime timestamp) async {
final appDocDir = await getApplicationDocumentsDirectory();
final appDocPath = appDocDir.path;
final DateFormat formatter = DateFormat(DateFormat.YEAR_MONTH_DAY);
final date = DateTime.now();
final file = File('$appDocPath/diameter_${formatter.format(date)}.json');
file.writeAsStringSync(json.encode(appDataToJson(timestamp)));
return file;
}
static Future<void> exportToGoogleDrive() async {
final login = GoogleSignIn.standard(scopes: [drive.DriveApi.driveScope]);
final GoogleSignInAccount? account = await login.signIn();
if (account != null) {
final authenticateClient = GoogleAuthClient(await account.authHeaders);
final driveApi = drive.DriveApi(authenticateClient);
final timestamp = DateTime.now();
var localFile = await DataExport.exportDataToFile(timestamp);
var media = drive.Media(localFile.openRead(), localFile.lengthSync());
final settings = Settings.get();
settings.lastExportTimestamp = timestamp;
Settings.put(settings);
drive.File driveFile = drive.File()..name = 'diameter.json';
await driveApi.files.create(driveFile, uploadMedia: media);
}
}
static Future<void> importFromGoogleDrive() async {
final login = GoogleSignIn.standard(scopes: [drive.DriveApi.driveScope]);
final GoogleSignInAccount? account = await login.signIn();
if (account != null) {
final authenticateClient = GoogleAuthClient(await account.authHeaders);
final driveApi = drive.DriveApi(authenticateClient);
final timestamp = DateTime.now();
var localFile = await DataExport.exportDataToFile(timestamp);
var media = drive.Media(localFile.openRead(), localFile.lengthSync());
final settings = Settings.get();
settings.lastExportTimestamp = timestamp;
Settings.put(settings);
drive.File driveFile = drive.File()..name = 'diameter.json';
await driveApi.files.create(driveFile, uploadMedia: media);
}
}
}
// class DataExportDialog extends StatefulWidget {
// static const String routeName = '/data-export';
// const DataExportDialog({Key? key}) : super(key: key);
// @override
// _DataExportDialogState createState() => _DataExportDialogState();
// }
// class _DataExportDialogState extends State<DataExportDialog> {
// final ScrollController _scrollController = ScrollController();
// bool _isSaving = false;
// @override
// void dispose() {
// _scrollController.dispose();
// super.dispose();
// }
// @override
// void initState() {
// super.initState();
// }
// void onExport(BuildContext context) async {
// setState(() {
// _isSaving = true;
// });
// Navigator.pop(context);
// setState(() {
// _isSaving = false;
// });
// }
// @override
// Widget build(BuildContext context) {
// return AlertDialog(
// content: Column(
// mainAxisSize: MainAxisSize.min,
// crossAxisAlignment: CrossAxisAlignment.center,
// children: const [
// // CheckboxListTile(
// // value: showChart,
// // onChanged: (_) => setState(() => showChart = !showChart),
// // title: const Text('show Chart'),
// // controlAffinity: ListTileControlAffinity.leading,
// // ),
// ],
// ),
// actions: <Widget>[
// TextButton(
// onPressed: () => Navigator.pop(context),
// child: const Text('CANCEL'),
// ),
// ElevatedButton(
// onPressed: !_isSaving ? () => onExport(context) : null,
// child: const Text('EXPORT'),
// ),
// ]);
// }
// }