Browse Source

Implemented proper graph

main
root 4 months ago
parent
commit
9c1d127455
  1. 2
      .flutter-plugins-dependencies
  2. 2
      .packages
  3. 28
      lib/data/db.dart
  4. 10
      lib/data/db.g.dart
  5. 2
      lib/data/mood.dart
  6. 4
      lib/data/mood_dao.dart
  7. 60
      lib/fragments/MoodGraph.dart
  8. 10
      lib/helpers/color.dart
  9. 6
      lib/helpers/date.dart
  10. 10
      lib/helpers/human-readable.dart
  11. 6
      lib/main.dart
  12. 72
      lib/pages/MoodDashboard.dart
  13. 72
      lib/pages/MoodDump.dart
  14. 2
      lib/pages/MoodForm.dart
  15. 8
      lib/providers/db.dart

2
.flutter-plugins-dependencies

@ -1 +1 @@
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"sqflite","path":"/home/diane/dev/softwares/flutter/.pub-cache/hosted/pub.dartlang.org/sqflite-2.0.0+3/","dependencies":[]}],"android":[{"name":"sqflite","path":"/home/diane/dev/softwares/flutter/.pub-cache/hosted/pub.dartlang.org/sqflite-2.0.0+3/","dependencies":[]}],"macos":[{"name":"sqflite","path":"/home/diane/dev/softwares/flutter/.pub-cache/hosted/pub.dartlang.org/sqflite-2.0.0+3/","dependencies":[]}],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"sqflite","dependencies":[]}],"date_created":"2021-08-13 14:48:49.474530","version":"2.2.3"}
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"sqflite","path":"/home/diane/dev/softwares/flutter/.pub-cache/hosted/pub.dartlang.org/sqflite-2.0.0+3/","dependencies":[]}],"android":[{"name":"sqflite","path":"/home/diane/dev/softwares/flutter/.pub-cache/hosted/pub.dartlang.org/sqflite-2.0.0+3/","dependencies":[]}],"macos":[{"name":"sqflite","path":"/home/diane/dev/softwares/flutter/.pub-cache/hosted/pub.dartlang.org/sqflite-2.0.0+3/","dependencies":[]}],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"sqflite","dependencies":[]}],"date_created":"2021-08-13 19:21:06.692848","version":"2.2.3"}

2
.packages

@ -3,7 +3,7 @@
#
# For more info see: https://dart.dev/go/dot-packages-deprecation
#
# Generated by pub on 2021-08-13 14:48:48.621057.
# Generated by pub on 2021-08-13 15:51:03.420929.
_fe_analyzer_shared:file:///home/diane/dev/softwares/flutter/.pub-cache/hosted/pub.dartlang.org/_fe_analyzer_shared-22.0.0/lib/
analyzer:file:///home/diane/dev/softwares/flutter/.pub-cache/hosted/pub.dartlang.org/analyzer-1.7.1/lib/
args:file:///home/diane/dev/softwares/flutter/.pub-cache/hosted/pub.dartlang.org/args-2.2.0/lib/

28
lib/data/db.dart

@ -22,6 +22,34 @@ class DateTimeConverter extends TypeConverter<DateTime, int> {
@TypeConverters([DateTimeConverter, MoodLevelConverter])
@Database(version: 1, entities: [Mood])
abstract class AppDatabase extends FloorDatabase {
static const path = 'app_database.db';
MoodDao get moodDao;
static Future<void> deleteDatabase() async {
await sqflite.deleteDatabase(path);
}
Future<void> setupTestData() async {
Future.wait(
[
Mood(DateTime.now(), MoodLevel.neutral, ''),
Mood(DateTime.now(), MoodLevel.high, ''),
Mood(DateTime.now().subtract(Duration(days: 1)), MoodLevel.high, ''),
Mood(DateTime.now().subtract(Duration(days: 2)), MoodLevel.high, ''),
Mood(DateTime.now().subtract(Duration(days: 2)), MoodLevel.manic, ''),
Mood(DateTime.now().subtract(Duration(days: 3)), MoodLevel.manic, ''),
Mood(DateTime.now().subtract(Duration(days: 4)), MoodLevel.manic, ''),
Mood(DateTime.now().subtract(Duration(days: 4)), MoodLevel.low, ''),
Mood(DateTime.now().subtract(Duration(days: 5)), MoodLevel.neutral, ''),
Mood(DateTime.now().subtract(Duration(days: 5)), MoodLevel.low, ''),
Mood(DateTime.now().subtract(Duration(days: 6)), MoodLevel.low, ''),
Mood(DateTime.now().subtract(Duration(days: 6)), MoodLevel.depressive, ''),
Mood(DateTime.now().subtract(Duration(days: 7)), MoodLevel.depressive, ''),
Mood(DateTime.now().subtract(Duration(days: 8)), MoodLevel.depressive, ''),
Mood(DateTime.now().subtract(Duration(days: 8)), MoodLevel.manic, ''),
].map(moodDao.insertMood),
);
}
}

10
lib/data/db.g.dart

@ -117,13 +117,11 @@ class _$MoodDao extends MoodDao {
final InsertionAdapter<Mood> _moodInsertionAdapter;
@override
Future<List<Mood>> findAllRecentMoods() async {
Future<List<Mood>> findRecentMoods(DateTime since) async {
return _queryAdapter.queryList(
'SELECT * FROM Mood ORDER BY snapshotDate DESC LIMIT 50',
mapper: (Map<String, Object?> row) => Mood(
_dateTimeConverter.decode(row['snapshotDate'] as int),
_moodLevelConverter.decode(row['mood'] as int),
row['notes'] as String));
'SELECT * FROM Mood WHERE snapshotDate >= ?1 ORDER BY snapshotDate DESC LIMIT 50',
mapper: (Map<String, Object?> row) => Mood(_dateTimeConverter.decode(row['snapshotDate'] as int), _moodLevelConverter.decode(row['mood'] as int), row['notes'] as String),
arguments: [_dateTimeConverter.encode(since)]);
}
@override

2
lib/data/mood.dart

@ -1,6 +1,6 @@
import 'package:floor/floor.dart';
enum MoodLevel { manic, high, neutral, low, depressive }
enum MoodLevel { depressive, low, neutral, high, manic }
class MoodLevelConverter extends TypeConverter<MoodLevel, int> {
@override

4
lib/data/mood_dao.dart

@ -4,8 +4,8 @@ import 'mood.dart';
@dao
abstract class MoodDao {
@Query('SELECT * FROM Mood ORDER BY snapshotDate DESC LIMIT 50')
Future<List<Mood>> findAllRecentMoods();
@Query('SELECT * FROM Mood WHERE snapshotDate >= :since ORDER BY snapshotDate DESC')
Future<List<Mood>> findRecentMoods(DateTime since);
@insert
Future<void> insertMood(Mood mood);

60
lib/fragments/MoodGraph.dart

@ -0,0 +1,60 @@
import 'package:flutter/material.dart';
import 'package:mood_droid/data/mood.dart';
import 'package:mood_droid/helpers/color.dart';
import 'package:mood_droid/helpers/human-readable.dart';
import 'package:syncfusion_flutter_charts/charts.dart';
class MoodsPerDay {
DateTime day;
late MoodLevel lower, higher;
MoodsPerDay(this.day, MoodLevel mood) {
this.lower = mood;
this.higher = mood;
}
Color get color => colorForMood(higher);
}
class MoodGraph extends StatelessWidget {
late List<MoodsPerDay> moods;
final DateTime since, now;
MoodGraph(List<MoodsPerDay> moods, this.since, this.now) {
moods.sort((a, b) => a.day.compareTo(b.day));
this.moods = moods;
}
@override
Widget build(BuildContext context) => SfCartesianChart(
plotAreaBorderWidth: 0,
axisLabelFormatter: (args) => ChartAxisLabel(
args.axisName == 'primaryYAxis'
? shortReadableMood(MoodLevel.values[args.value.toInt()])
: args.text,
args.textStyle,
),
primaryXAxis: DateTimeAxis(
minimum: since.add(Duration(hours: 12)),
maximum: now.add(Duration(hours: 12)),
),
primaryYAxis: CategoryAxis(
edgeLabelPlacement: EdgeLabelPlacement.hide,
minimum: MoodLevel.depressive.index.toDouble(),
maximum: MoodLevel.manic.index.toDouble(),
),
title: ChartTitle(text: 'These past two weeks'),
series: [
RangeColumnSeries<MoodsPerDay, DateTime>(
animationDuration: 0,
width: 0.3,
dataSource: moods,
xValueMapper: (d, _) => d.day,
highValueMapper: (d, _) => d.higher.index + 0.5,
lowValueMapper: (d, _) => d.lower.index - 0.5,
borderRadius: BorderRadius.all(Radius.circular(5)),
pointColorMapper: (d, _) => d.color,
)
],
);
}

10
lib/helpers/color.dart

@ -0,0 +1,10 @@
import 'package:flutter/material.dart';
import 'package:mood_droid/data/mood.dart';
Color colorForMood(MoodLevel m) => [
Colors.blueGrey,
Colors.green,
Colors.lime,
Colors.orange,
Colors.red,
][m.index];

6
lib/helpers/date.dart

@ -0,0 +1,6 @@
int daysBetween(DateTime from, DateTime to) =>
(DateTime(to.year, to.month, to.day)
.difference(DateTime(from.year, from.month, from.day))
.inHours /
24)
.round();

10
lib/helpers/human-readable.dart

@ -3,11 +3,19 @@ import 'package:mood_droid/data/mood.dart';
String readableMood(MoodLevel l) => {
MoodLevel.manic: "High spirits",
MoodLevel.high: "Having a nice day",
MoodLevel.neutral: "Not bad I guess",
MoodLevel.neutral: "Feeling eh",
MoodLevel.low: "Feeling down",
MoodLevel.depressive: "Bad.",
}[l]!;
String shortReadableMood(MoodLevel l) => {
MoodLevel.manic: "Hyper",
MoodLevel.high: "Good",
MoodLevel.neutral: "Eh",
MoodLevel.low: "Meh",
MoodLevel.depressive: "Bad",
}[l]!;
String tellMoreLabel(MoodLevel l) => {
MoodLevel.manic: "That's cool!",
MoodLevel.high: "Good :3",

6
lib/main.dart

@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mood_droid/constants.dart';
import 'package:mood_droid/pages/MoodDump.dart';
import 'package:mood_droid/pages/MoodDashboard.dart';
import 'package:mood_droid/pages/MoodForm.dart';
Future<void> main() async {
@ -14,9 +14,9 @@ class MoodDroid extends StatelessWidget {
return MaterialApp(
title: AppTitle,
theme: AppTheme,
initialRoute: 'mood-picker',
initialRoute: 'dashboard',
routes: {
'dashboard': (context) => MoodDump(),
'dashboard': (context) => MoodDashboard(),
'mood-picker': (context) => MoodPicker(),
'mood-writer': (context) => MoodWriter(),
},

72
lib/pages/MoodDashboard.dart

@ -0,0 +1,72 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mood_droid/constants.dart';
import 'package:mood_droid/data/db.dart';
import 'package:mood_droid/data/mood.dart';
import 'package:mood_droid/fragments/LoadingPage.dart';
import 'package:mood_droid/fragments/MoodGraph.dart';
import 'package:mood_droid/helpers/date.dart';
import 'package:mood_droid/providers/db.dart';
class MoodDashboard extends ConsumerWidget {
@override
Widget build(BuildContext context, ScopedReader watch) {
final $db = watch(DbProvider);
final now = DateTime.now();
final since = now.subtract(Duration(days: 15));
return Scaffold(
appBar: AppBar(
title: Text(AppTitle),
),
body: loading<AppDatabase>(
$db,
(db) => FutureBuilder<List<Mood>>(
future: db.moodDao.findRecentMoods(since),
initialData: [],
builder: (ctx, snap) {
final data = (snap.data ?? []);
return Padding(
padding: EdgeInsets.only(left: 8, right: 16),
child: SizedBox(
height: 200,
child: MoodGraph(
data.fold<List<MoodsPerDay>>(
[],
(acc, e) {
final day = acc.firstWhere(
(v) => daysBetween(v.day, e.snapshotDate) == 0,
orElse: () => MoodsPerDay(e.snapshotDate, e.mood),
);
if (day.lower.index > e.mood.index) {
day.lower = e.mood;
}
if (day.higher.index < e.mood.index) {
day.higher = e.mood;
}
if (!acc.contains(day)) {
acc.add(day);
}
return acc;
},
),
since,
now,
),
),
);
},
),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
Navigator.popAndPushNamed(context, 'mood-picker');
},
),
);
}
}

72
lib/pages/MoodDump.dart

@ -1,72 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mood_droid/constants.dart';
import 'package:mood_droid/data/db.dart';
import 'package:mood_droid/data/mood.dart';
import 'package:mood_droid/fragments/LoadingPage.dart';
import 'package:mood_droid/providers/db.dart';
import 'package:syncfusion_flutter_charts/charts.dart';
class MoodDump extends ConsumerWidget {
@override
Widget build(BuildContext context, ScopedReader watch) {
final $db = watch(DbProvider);
return Scaffold(
appBar: AppBar(
title: Text(AppTitle),
),
body: loading<AppDatabase>(
$db,
(db) => FutureBuilder<List<Mood>>(
future: db.moodDao.findAllRecentMoods(),
initialData: [],
builder: (ctx, snap) {
final data = snap.data ?? [];
final now = DateTime.now();
return SingleChildScrollView(
child: Column(
children: [
SizedBox(
height: 16,
child: SfCartesianChart(
primaryXAxis: DateTimeAxis(
minimum: now.subtract(Duration(days: 7)),
maximum: now,
),
primaryYAxis: CategoryAxis(
minimum: MoodLevel.depressive.index.toDouble(),
maximum: MoodLevel.manic.index.toDouble(),
),
title: ChartTitle(text: 'This past week'),
series: [
LineSeries<Mood, DateTime>(
dataSource: data,
xValueMapper: (d, _) => d.snapshotDate,
yValueMapper: (d, _) => d.mood.index,
name: 'Mood',
)
],
)
)
],
),
);
// return ListView.builder(
// itemCount: data.length,
// itemBuilder: (ctx, i) => ListTile(
// title: Text(readableMood(data[i].mood)),
// ),
// );
},
),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.refresh),
onPressed: () {
Navigator.popAndPushNamed(context, 'mood-picker');
},
),
);
}
}

2
lib/pages/MoodForm.dart

@ -28,7 +28,7 @@ class MoodPickerState extends State<MoodPicker> {
style: Theme.of(context).textTheme.headline5,
),
),
...MoodLevel.values.map(
...MoodLevel.values.reversed.map(
(e) => RadioListTile<MoodLevel>(
title: Text(readableMood(e)),
value: e,

8
lib/providers/db.dart

@ -1,5 +1,9 @@
import 'package:mood_droid/data/db.dart';
import 'package:riverpod/riverpod.dart';
final DbProvider = FutureProvider<AppDatabase>(
(ref) => $FloorAppDatabase.databaseBuilder('app_database.db').build());
final DbProvider = FutureProvider<AppDatabase>((ref) async {
await AppDatabase.deleteDatabase();
final db = await $FloorAppDatabase.databaseBuilder('app_database.db').build();
db.setupTestData();
return db;
});