Commit 7fa7c10
Changed files (9)
lib/model/blood_pressure.dart
@@ -123,7 +123,7 @@ class BloodPressureModel extends ChangeNotifier {
if (Platform.isLinux || Platform.isWindows || Platform.isMacOS) {
callback(true, 'Exported to: $path');
} else if (Platform.isAndroid || Platform.isIOS) {
- // TODO: compatability option
+ // TODO: compatability option (MIME Types)
Share.shareXFiles([XFile(path, mimeType: MimeType.csv.type,)]);
callback(true, null);
} else {
lib/model/settings.dart
@@ -1,4 +1,6 @@
+import 'dart:io';
+
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:path/path.dart';
@@ -35,6 +37,13 @@ class Settings extends ChangeNotifier {
}
// factory method, to allow for async contructor
static Future<Settings> create() async {
+ if (Platform.isWindows || Platform.isLinux) {
+ // Initialize FFI
+ sqfliteFfiInit();
+ // Change the default factory
+ databaseFactory = databaseFactoryFfi;
+ }
+
final component = Settings._create();
await component._asyncInit();
return component;
@@ -72,7 +81,7 @@ class Settings extends ChangeNotifier {
_graphStepSize = (await pGraphStepSize as int?) ?? TimeStep.day;
_graphStart = DateTime.fromMillisecondsSinceEpoch((await pGraphStart as int?) ?? -1);
_graphEnd = DateTime.fromMillisecondsSinceEpoch((await pGraphEnd as int?) ?? -1);
- _followSystemDarkMode = ((await pFollowSystemDarkMode as int?) ?? "1") == "1" ? true : false;
+ _followSystemDarkMode = ((await pFollowSystemDarkMode as int?) ?? 1) == 1 ? true : false;
_darkMode = ((await pDarkMode as int?) ?? 1) == 1 ? true : false;
_accentColor = createMaterialColor(await pAccentColor as int? ?? 0xFF009688);
_sysColor = createMaterialColor(await pSysColor as int? ?? 0xFF009688);
@@ -206,6 +215,8 @@ class TimeStep {
static const year = 2;
static const lifetime = 3;
+ TimeStep._create();
+
static String getName(int opt) {
switch (opt) {
case day:
lib/main.dart
@@ -9,14 +9,6 @@ import 'package:sqflite/sqflite.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
-
- if (Platform.isWindows || Platform.isLinux) {
- // Initialize FFI
- sqfliteFfiInit();
- // Change the default factory
- databaseFactory = databaseFactoryFfi;
- }
-
// 2 different db files
final dataModel = await BloodPressureModel.create();
final settingsModel = await Settings.create();
test/model/bood_pressure_test.dart
@@ -0,0 +1,128 @@
+import 'package:blood_pressure_app/model/blood_pressure.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:sqflite_common_ffi/sqflite_ffi.dart';
+import 'dart:io';
+
+void main() {
+ group('BloodPressureRecord', () {
+ test('should initialize with all values supported by dart', () {
+ BloodPressureRecord record = BloodPressureRecord(
+ DateTime.fromMicrosecondsSinceEpoch(0),
+ 0,
+ -50,
+ 1000,
+ "((V⍳V)=⍳⍴V)/V←,V ⌷←⍳→⍴∆∇⊃‾⍎⍕⌈๏ แผ่นดินฮั่นเABCDEFGHIJKLMNOPQRSTUVWXYZ /0123456789abcdefghijklmnopqrstuvwxyz £©µÀÆÖÞßéöÿ–—‘“”„†•…‰™œŠŸž€ ΑΒΓΔΩαβγδω АБВГДабвг, \n \t д∀∂∈ℝ∧∪≡∞ ↑↗↨↻⇣ ┐┼╔╘░►☺♀ fi�⑀₂ἠḂӥẄɐː⍎אԱა");
+
+ expect(record.creationTime, DateTime.fromMicrosecondsSinceEpoch(0));
+ expect(record.systolic, 0);
+ expect(record.diastolic, -50);
+ expect(record.pulse, 1000);
+ expect(record.notes, "((V⍳V)=⍳⍴V)/V←,V ⌷←⍳→⍴∆∇⊃‾⍎⍕⌈๏ แผ่นดินฮั่นเABCDEFGHIJKLMNOPQRSTUVWXYZ /0123456789abcdefghijklmnopqrstuvwxyz £©µÀÆÖÞßéöÿ–—‘“”„†•…‰™œŠŸž€ ΑΒΓΔΩαβγδω АБВГДабвг, \n \t д∀∂∈ℝ∧∪≡∞ ↑↗↨↻⇣ ┐┼╔╘░►☺♀ fi�⑀₂ἠḂӥẄɐː⍎אԱა");
+ });
+ test('should compare depending on creation time', () {
+ var first = BloodPressureRecord(DateTime.fromMicrosecondsSinceEpoch(0), 0, 0, 0, '');
+ var middle = BloodPressureRecord(DateTime.fromMicrosecondsSinceEpoch(10000), 0, 0, 0, '');
+ var last = BloodPressureRecord(DateTime.now(), 0, 0, 0, '');
+
+ expect(first.compareTo(middle), -1);
+ expect(middle.compareTo(first), 1);
+ expect(last.compareTo(first), 1);
+ expect(last.compareTo(last), 0);
+ });
+ });
+
+ group('BloodPressureModel',() {
+ // setup db path
+ databaseFactory = databaseFactoryFfi;
+
+ test('should initialize', () async {
+ await clearDbDir();
+ expect(() async { await BloodPressureModel.create(); }, returnsNormally);
+ });
+ test('should start empty', () async {
+ await clearDbDir();
+ var m = await BloodPressureModel.create();
+
+ expect((await m.getLastX(100)).length, 0);
+ expect((await m.getInTimeRange(DateTime.fromMillisecondsSinceEpoch(0), DateTime.now())).length, 0);
+
+ });
+
+ test('should notify when adding entries', () async {
+ await clearDbDir();
+ var m = await BloodPressureModel.create();
+
+ int listenerCalls = 0;
+ int added = 0;
+ m.addListener(() {
+ listenerCalls++;
+ expect(listenerCalls, added);
+ });
+
+ m.add(BloodPressureRecord(DateTime.fromMillisecondsSinceEpoch(0), 0, 0, 0, ''));
+ added++;
+ m.add(BloodPressureRecord(DateTime.fromMillisecondsSinceEpoch(1), 0, 0, 0, ''));
+ added++;
+ m.add(BloodPressureRecord(DateTime.fromMillisecondsSinceEpoch(2), 0, 0, 0, ''));
+ added++;
+
+ });
+
+ test('should return entries as added', () async {
+ await clearDbDir();
+ var m = await BloodPressureModel.create();
+
+ var r = BloodPressureRecord(DateTime.now(), -172, 10000, 0, "((V⍳V)=⍳⍴V)/V←,V ⌷←⍳→⍴∆∇⊃‾⍎⍕⌈๏ แผ่นดินฮั่นเABCDEFGHIJKLMNOPQRSTUVWXYZ /0123456789abcdefghijklmnopqrstuvwxyz £©µÀÆÖÞßéöÿ–—‘“”„†•…‰™œŠŸž€ ΑΒΓΔΩαβγδω АБВГДабвг, \n \t д∀∂∈ℝ∧∪≡∞ ↑↗↨↻⇣ ┐┼╔╘░►☺♀ fi�⑀₂ἠḂӥẄɐː⍎אԱა");
+ m.addListener(() async {
+ var res = (await m.getLastX(1)).first;
+ expect(res, isNotNull);
+ expect(res.creationTime, r.creationTime);
+ expect(res.systolic, r.systolic);
+ expect(res.diastolic, r.diastolic);
+ expect(res.pulse, r.pulse);
+ expect(res.notes, r.notes);
+ });
+
+ m.add(r);
+ });
+
+ test('should save and load between objects/sessions', () async {
+ await clearDbDir();
+
+ var m = await BloodPressureModel.create();
+ var r = BloodPressureRecord(DateTime.fromMillisecondsSinceEpoch(31415926), -172, 10000, 0, "((V⍳V)=⍳⍴V)/V←,V ⌷←⍳→⍴∆∇⊃‾⍎⍕⌈๏ แผ่นดินฮั่นเABCDEFGHIJKLMNOPQRSTUVWXYZ /0123456789abcdefghijklmnopqrstuvwxyz £©µÀÆÖÞßéöÿ–—‘“”„†•…‰™œŠŸž€ ΑΒΓΔΩαβγδω АБВГДабвг, \n \t д∀∂∈ℝ∧∪≡∞ ↑↗↨↻⇣ ┐┼╔╘░►☺♀ fi�⑀₂ἠḂӥẄɐː⍎אԱა");
+ await m.add(r);
+
+ var m2 = await BloodPressureModel.create();
+ var res = (await m2.getLastX(1)).first;
+
+ expect(res.creationTime, r.creationTime);
+ expect(res.systolic, r.systolic);
+ expect(res.diastolic, r.diastolic);
+ expect(res.pulse, r.pulse);
+ expect(res.notes, r.notes);
+ });
+
+ test('should import exported values', () async {
+ await clearDbDir();
+ var m = await BloodPressureModel.create();
+ var r = BloodPressureRecord(DateTime.fromMillisecondsSinceEpoch(31415926), -172, 10000, 0, "((V⍳V)=⍳⍴V)/V←,V ⌷←⍳→⍴∆∇⊃‾⍎⍕⌈๏ แผ่นดินฮั่นเABCDEFGHIJKLMNOPQRSTUVWXYZ /0123456789abcdefghijklmnopqrstuvwxyz £©µÀÆÖÞßéöÿ–—‘“”„†•…‰™œŠŸž€ ΑΒΓΔΩαβγδω АБВГДабвг, \n \t д∀∂∈ℝ∧∪≡∞ ↑↗↨↻⇣ ┐┼╔╘░►☺♀ fi�⑀₂ἠḂӥẄɐː⍎אԱა");
+ await m.add(r);
+
+ m.save((success, msg) {
+ expect(success, true);
+ // TODO: rewrite blood_pressure to remove UI code entirely
+ });
+ });
+ });
+}
+
+Future<void> clearDbDir() async {
+ databaseFactory.setDatabasesPath((await getDatabasesPath()).replaceAll('databases', 'test_databases'));
+ try {
+ Directory(await getDatabasesPath()).deleteSync(recursive: true);
+ } catch (e) {
+ print('no directory to delete!');
+ }
+ Directory(await getDatabasesPath()).create(recursive: true);
+}
\ No newline at end of file
test/model/settings_test.dart
@@ -0,0 +1,117 @@
+import 'dart:io';
+
+import 'package:blood_pressure_app/model/settings.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:sqflite_common_ffi/sqflite_ffi.dart';
+
+void main() {
+ group('TimeStep', () {
+ test('names should match to fields', () {
+ expect(TimeStep.getName(TimeStep.day), 'day');
+ expect(TimeStep.getName(TimeStep.month), 'month');
+ expect(TimeStep.getName(TimeStep.year), 'year');
+ expect(TimeStep.getName(TimeStep.lifetime), 'lifetime');
+ });
+ });
+
+ group('Settings model',() {
+ // setup db path
+ databaseFactory = databaseFactoryFfi;
+
+ test('should initialize', () async {
+ await clearDbDir();
+ expect(() async { await Settings.create(); }, returnsNormally);
+ });
+ test('fields defaults should be set after initialization', () async {
+ await clearDbDir();
+
+ var s = await Settings.create();
+ expect(s.graphStepSize, TimeStep.day);
+ expect(s.graphStart, DateTime.fromMillisecondsSinceEpoch(-1));
+ expect(s.graphEnd, DateTime.fromMillisecondsSinceEpoch(-1));
+ expect(s.followSystemDarkMode, true);
+ expect(s.darkMode, true);
+ expect(s.accentColor.value, 0xFF009688);
+ expect(s.sysColor.value, 0xFF009688);
+ expect(s.diaColor.value, 0xFF4CAF50);
+ expect(s.pulColor.value, 0xFFF44336);
+ expect(s.allowManualTimeInput, true);
+ expect(s.dateFormatString, 'yy-MM-dd H:mm');
+ });
+
+ test('setting fields should notify listeners and change values', () async {
+ await clearDbDir();
+ var s = await Settings.create();
+
+ int i = 0;
+ s.addListener(() {
+ i++;
+ if (i >= 1) {
+ expect(s.graphStepSize, TimeStep.lifetime);
+ }
+ if (i >= 11) {
+ expect(s.dateFormatString, 'yy:dd @ H:mm.ss');
+ }
+ });
+
+ s.graphStepSize = TimeStep.lifetime;
+ s.graphStart = DateTime.fromMillisecondsSinceEpoch(10000);
+ s.graphEnd = DateTime.fromMillisecondsSinceEpoch(200000);
+ s.followSystemDarkMode = false;
+ s.darkMode = false;
+ s.accentColor = s.createMaterialColor(0xFF942DA4);
+ s.sysColor = s.createMaterialColor(0xFF942DA5);
+ s.diaColor = s.createMaterialColor(0xFF942DA6);
+ s.pulColor = s.createMaterialColor(0xFF942DA7);
+ s.allowManualTimeInput = false;
+ s.dateFormatString = 'yy:dd @ H:mm.ss';
+
+
+ expect(s.graphStart, DateTime.fromMillisecondsSinceEpoch(10000));
+ expect(s.graphEnd, DateTime.fromMillisecondsSinceEpoch(200000));
+ expect(s.followSystemDarkMode, false);
+ expect(s.darkMode, false);
+ expect(s.accentColor.value, 0xFF942DA4);
+ expect(s.sysColor.value, 0xFF942DA5);
+ expect(s.diaColor.value, 0xFF942DA6);
+ expect(s.pulColor.value, 0xFF942DA7);
+ expect(s.allowManualTimeInput, false);
+
+ });
+ test('setting fields should notify listeners and change values', () async {
+ await clearDbDir();
+ var s = await Settings.create();
+
+ int i = 0;
+ s.addListener(() {
+ i++;
+ });
+
+ s.graphStepSize = TimeStep.lifetime;
+ s.graphStart = DateTime.fromMillisecondsSinceEpoch(10000);
+ s.graphEnd = DateTime.fromMillisecondsSinceEpoch(200000);
+ s.followSystemDarkMode = false;
+ s.darkMode = false;
+ s.accentColor = s.createMaterialColor(0xFF942DA4);
+ s.sysColor = s.createMaterialColor(0xFF942DA5);
+ s.diaColor = s.createMaterialColor(0xFF942DA6);
+ s.pulColor = s.createMaterialColor(0xFF942DA7);
+ s.allowManualTimeInput = false;
+ s.dateFormatString = 'yy:dd @ H:mm.ss';
+
+
+ expect(i, 11);
+ });
+
+ });
+}
+
+Future<void> clearDbDir() async {
+ databaseFactory.setDatabasesPath((await getDatabasesPath()).replaceAll('databases', 'test_databases'));
+ try {
+ Directory(await getDatabasesPath()).deleteSync(recursive: true);
+ } catch (e) {
+ print('no directory to delete!');
+ }
+ Directory(await getDatabasesPath()).create(recursive: true);
+}
\ No newline at end of file
test/model_test.dart
@@ -1,5 +0,0 @@
-import 'package:flutter_test/flutter_test.dart';
-import 'package:blood_pressure_app/model/blood_pressure.dart';
-
-void main() {
-}
\ No newline at end of file
test/widget_test.dart
@@ -1,16 +0,0 @@
-// This is a basic Flutter widget test.
-//
-// To perform an interaction with a widget in your test, use the WidgetTester
-// utility in the flutter_test package. For example, you can send tap and scroll
-// gestures. You can also use WidgetTester to find child widgets in the widget
-// tree, read text, and verify that the values of widget properties are correct.
-
-import 'package:flutter/material.dart';
-import 'package:flutter_test/flutter_test.dart';
-
-import 'package:blood_pressure_app/main.dart';
-
-void main() {
- testWidgets('TODO', (WidgetTester tester) async {
- });
-}
pubspec.lock
@@ -90,7 +90,7 @@ packages:
source: hosted
version: "2.0.1"
file:
- dependency: transitive
+ dependency: "direct dev"
description:
name: file
sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d"
pubspec.yaml
@@ -48,6 +48,7 @@ dev_dependencies:
flutter_test:
sdk: flutter
sqflite_common_ffi:
+ file:
# The "flutter_lints" package below contains a set of recommended lints to
# encourage good coding practices. The lint set provided by the package is