diff --git a/lib/generated/intl/messages_en.dart b/lib/generated/intl/messages_en.dart index bd16f177b..47af11daa 100644 --- a/lib/generated/intl/messages_en.dart +++ b/lib/generated/intl/messages_en.dart @@ -122,6 +122,7 @@ class MessageLookup extends MessageLookupByLibrary { "labelEvaluation" : MessageLookupByLibrary.simpleMessage("Evaluation"), "labelFirstName" : MessageLookupByLibrary.simpleMessage("First name"), "labelLastName" : MessageLookupByLibrary.simpleMessage("Last name"), + "labelLastUpdated" : MessageLookupByLibrary.simpleMessage("Last updated"), "labelLink" : MessageLookupByLibrary.simpleMessage("Link"), "labelLocation" : MessageLookupByLibrary.simpleMessage("Location"), "labelName" : MessageLookupByLibrary.simpleMessage("Name"), diff --git a/lib/generated/intl/messages_ro.dart b/lib/generated/intl/messages_ro.dart index 4069c0fd0..5f91e84f3 100644 --- a/lib/generated/intl/messages_ro.dart +++ b/lib/generated/intl/messages_ro.dart @@ -122,6 +122,7 @@ class MessageLookup extends MessageLookupByLibrary { "labelEvaluation" : MessageLookupByLibrary.simpleMessage("Evaluare"), "labelFirstName" : MessageLookupByLibrary.simpleMessage("Prenume"), "labelLastName" : MessageLookupByLibrary.simpleMessage("Nume"), + "labelLastUpdated" : MessageLookupByLibrary.simpleMessage("Ultima modificare"), "labelLink" : MessageLookupByLibrary.simpleMessage("Link"), "labelLocation" : MessageLookupByLibrary.simpleMessage("Locație"), "labelName" : MessageLookupByLibrary.simpleMessage("Nume"), diff --git a/lib/generated/l10n.dart b/lib/generated/l10n.dart index e9c05bf45..4d64a9d39 100644 --- a/lib/generated/l10n.dart +++ b/lib/generated/l10n.dart @@ -404,6 +404,16 @@ class S { ); } + /// `Last updated` + String get labelLastUpdated { + return Intl.message( + 'Last updated', + name: 'labelLastUpdated', + desc: '', + args: [], + ); + } + /// `Shortcuts` String get sectionShortcuts { return Intl.message( diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index e205611d8..b11b04828 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -37,6 +37,7 @@ "labelPrivacyPolicy": "Privacy Policy", "labelPersonalInformation": "Personal information", "labelPermissionsConsent": "consent for editing rights", + "labelLastUpdated": "Last updated", "sectionShortcuts": "Shortcuts", "sectionEvents": "Events", diff --git a/lib/l10n/intl_ro.arb b/lib/l10n/intl_ro.arb index 337941b33..ef2488d00 100644 --- a/lib/l10n/intl_ro.arb +++ b/lib/l10n/intl_ro.arb @@ -37,6 +37,7 @@ "labelPrivacyPolicy": "Privacy Policy", "labelPersonalInformation": "Informații personale", "labelPermissionsConsent": "consimțământul pentru drepturi de editare", + "labelLastUpdated": "Ultima modificare", "sectionShortcuts": "Scurtături", "sectionEvents": "Evenimente", diff --git a/lib/pages/classes/model/class.dart b/lib/pages/classes/model/class.dart index d426cb8e4..f711431af 100644 --- a/lib/pages/classes/model/class.dart +++ b/lib/pages/classes/model/class.dart @@ -1,6 +1,7 @@ import 'package:acs_upb_mobile/generated/l10n.dart'; import 'package:flutter/cupertino.dart'; import 'package:meta/meta.dart'; +import 'package:time_machine/time_machine.dart'; enum ShortcutType { main, classbook, resource, other } @@ -38,10 +39,15 @@ class ClassHeader { } class Class { - Class({@required this.header, List shortcuts, this.grading}) + Class( + {@required this.header, + List shortcuts, + this.grading, + this.gradingLastUpdated}) : shortcuts = shortcuts ?? []; ClassHeader header; final List shortcuts; final Map grading; + final LocalDateTime gradingLastUpdated; } diff --git a/lib/pages/classes/service/class_provider.dart b/lib/pages/classes/service/class_provider.dart index 7d6767576..cd24bbe9c 100644 --- a/lib/pages/classes/service/class_provider.dart +++ b/lib/pages/classes/service/class_provider.dart @@ -5,6 +5,7 @@ import 'package:acs_upb_mobile/pages/filter/model/filter.dart'; import 'package:acs_upb_mobile/widgets/toast.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:flutter/material.dart'; +import 'package:time_machine/time_machine.dart'; extension UserExtension on User { bool get canEditClassInfo => permissionLevel >= 3; @@ -52,6 +53,13 @@ extension ClassHeaderExtension on ClassHeader { } } +extension TimestampExtension on Timestamp { + LocalDateTime toLocalDateTime() => LocalDateTime.dateTime(toDate()) + .inZoneStrictly(DateTimeZone.utc) + .withZone(DateTimeZone.local) + .localDateTime; +} + extension ClassExtension on Class { static Class fromSnap({ClassHeader header, DocumentSnapshot snap}) { if (snap.data == null) { @@ -75,10 +83,15 @@ extension ClassExtension on Class { (String name, dynamic value) => MapEntry(name, value.toDouble()))); } + final gradingLastUpdated = snap.data['gradingLastUpdated'] == null + ? null + : (snap.data['gradingLastUpdated'] as Timestamp).toLocalDateTime(); + return Class( header: header, shortcuts: shortcuts, grading: grading, + gradingLastUpdated: gradingLastUpdated, ); } } @@ -259,13 +272,14 @@ class ClassProvider with ChangeNotifier { try { final DocumentReference doc = _db.collection('classes').document(classId); final DocumentSnapshot snap = await doc.get(); + final Timestamp now = Timestamp.now(); if (snap.data == null) { // Document does not exist - await doc.setData({'grading': grading}); + await doc.setData({'grading': grading, 'gradingLastUpdated': now}); } else { // Document exists - await doc.updateData({'grading': grading}); + await doc.updateData({'grading': grading, 'gradingLastUpdated': now}); } notifyListeners(); diff --git a/lib/pages/classes/view/class_view.dart b/lib/pages/classes/view/class_view.dart index 606df6033..8896f8fde 100644 --- a/lib/pages/classes/view/class_view.dart +++ b/lib/pages/classes/view/class_view.dart @@ -68,6 +68,7 @@ class _ClassViewState extends State { const SizedBox(height: 8), GradingChart( grading: classInfo.grading, + lastUpdated: classInfo.gradingLastUpdated, onSave: (grading) => classProvider.setGrading( classId: widget.classHeader.id, grading: grading), ), diff --git a/lib/pages/classes/view/grading_view.dart b/lib/pages/classes/view/grading_view.dart index e6245cedb..bc7c32534 100644 --- a/lib/pages/classes/view/grading_view.dart +++ b/lib/pages/classes/view/grading_view.dart @@ -8,15 +8,21 @@ import 'package:flutter/material.dart'; import 'package:pie_chart/pie_chart.dart'; import 'package:provider/provider.dart'; import 'package:quiver/iterables.dart'; +import 'package:time_machine/time_machine.dart'; class GradingChart extends StatefulWidget { const GradingChart( - {Key key, this.grading, this.withHeader = true, this.onSave}) + {Key key, + this.grading, + this.withHeader = true, + this.onSave, + this.lastUpdated}) : super(key: key); final Map grading; final bool withHeader; final void Function(Map) onSave; + final LocalDateTime lastUpdated; @override _GradingChartState createState() => _GradingChartState(); @@ -40,9 +46,19 @@ class _GradingChartState extends State { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text( - S.of(context).sectionGrading, - style: Theme.of(context).textTheme.headline6, + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + S.of(context).sectionGrading, + style: Theme.of(context).textTheme.headline6, + ), + if (widget.grading != null) + Text( + '${S.of(context).labelLastUpdated}: ${widget.lastUpdated?.toString('dd/MM/yyyy') ?? '?'}', + textAlign: TextAlign.left, + ), + ], ), GestureDetector( onTap: authProvider.currentUserFromCache.canEditClassInfo diff --git a/pubspec.lock b/pubspec.lock index 490123341..6ccf80efe 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -846,7 +846,7 @@ packages: source: hosted version: "1.3.0" time_machine: - dependency: transitive + dependency: "direct main" description: name: time_machine url: "https://pub.dartlang.org" diff --git a/pubspec.yaml b/pubspec.yaml index 443c4b30c..bea945764 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -13,7 +13,7 @@ description: A mobile application for students at ACS UPB. # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # # ACS UPB Mobile uses semantic versioning. You can read more in the CONTRIBUTING.md file. -version: 0.10.1+1 +version: 0.10.2+1 environment: sdk: ">=2.6.0 <3.0.0" @@ -77,6 +77,9 @@ dependencies: # Timetable widget timetable: ^0.2.0 + # DateTime utilities + time_machine: + # Color picker widget flutter_colorpicker: ^0.3.4