added back button to full-screen timetable

This commit is contained in:
Kima 2023-06-06 20:27:37 +02:00
parent db5a9fb197
commit 9883d081ff
4 changed files with 145 additions and 44 deletions

View File

@ -3,6 +3,8 @@
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>com.apple.security.application-groups</key> <key>com.apple.security.application-groups</key>
<array/> <array>
<string>group.refilcnaplo.livecard</string>
</array>
</dict> </dict>
</plist> </plist>

View File

@ -3,6 +3,8 @@
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>com.apple.security.application-groups</key> <key>com.apple.security.application-groups</key>
<array/> <array>
<string>group.refilcnaplo.livecard</string>
</array>
</dict> </dict>
</plist> </plist>

View File

@ -13,7 +13,14 @@ import 'package:flutter/foundation.dart';
import 'package:live_activities/live_activities.dart'; import 'package:live_activities/live_activities.dart';
import 'package:filcnaplo_mobile_ui/pages/home/live_card/live_card.i18n.dart'; import 'package:filcnaplo_mobile_ui/pages/home/live_card/live_card.i18n.dart';
enum LiveCardState { empty, duringLesson, duringBreak, morning, afternoon, night } enum LiveCardState {
empty,
duringLesson,
duringBreak,
morning,
afternoon,
night
}
class LiveCardProvider extends ChangeNotifier { class LiveCardProvider extends ChangeNotifier {
Lesson? currentLesson; Lesson? currentLesson;
@ -42,14 +49,17 @@ class LiveCardProvider extends ChangeNotifier {
_latestActivityId = value.isNotEmpty ? value.first : null; _latestActivityId = value.isNotEmpty ? value.first : null;
}); });
_timer = Timer.periodic(const Duration(seconds: 1), (timer) => update()); _timer = Timer.periodic(const Duration(seconds: 1), (timer) => update());
_delay = settings.bellDelayEnabled ? Duration(seconds: settings.bellDelay) : Duration.zero; _delay = settings.bellDelayEnabled
? Duration(seconds: settings.bellDelay)
: Duration.zero;
update(); update();
} }
@override @override
void dispose() { void dispose() {
_timer.cancel(); _timer.cancel();
if (_latestActivityId != null && Platform.isIOS) _liveActivitiesPlugin.endActivity(_latestActivityId!); if (_latestActivityId != null && Platform.isIOS)
_liveActivitiesPlugin.endActivity(_latestActivityId!);
super.dispose(); super.dispose();
} }
@ -78,14 +88,25 @@ class LiveCardProvider extends ChangeNotifier {
switch (currentState) { switch (currentState) {
case LiveCardState.duringLesson: case LiveCardState.duringLesson:
return { return {
"icon": currentLesson != null ? SubjectIcon.resolveName(subject: currentLesson?.subject) : "book", "icon": currentLesson != null
"index": currentLesson != null ? '${currentLesson!.lessonIndex}. ' : "", ? SubjectIcon.resolveName(subject: currentLesson?.subject)
"title": currentLesson != null ? ShortSubject.resolve(subject: currentLesson?.subject).capital() : "", : "book",
"index":
currentLesson != null ? '${currentLesson!.lessonIndex}. ' : "",
"title": currentLesson != null
? ShortSubject.resolve(subject: currentLesson?.subject).capital()
: "",
"subtitle": currentLesson?.room.replaceAll("_", " ") ?? "", "subtitle": currentLesson?.room.replaceAll("_", " ") ?? "",
"description": currentLesson?.description ?? "", "description": currentLesson?.description ?? "",
"startDate": ((currentLesson?.start.millisecondsSinceEpoch ?? 0) - _delay.inMilliseconds).toString(), "startDate": ((currentLesson?.start.millisecondsSinceEpoch ?? 0) -
"endDate": ((currentLesson?.end.millisecondsSinceEpoch ?? 0) - _delay.inMilliseconds).toString(), _delay.inMilliseconds)
"nextSubject": nextLesson != null ? ShortSubject.resolve(subject: nextLesson?.subject).capital() : "", .toString(),
"endDate": ((currentLesson?.end.millisecondsSinceEpoch ?? 0) -
_delay.inMilliseconds)
.toString(),
"nextSubject": nextLesson != null
? ShortSubject.resolve(subject: nextLesson?.subject).capital()
: "",
"nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "", "nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "",
}; };
case LiveCardState.duringBreak: case LiveCardState.duringBreak:
@ -101,10 +122,19 @@ class LiveCardProvider extends ChangeNotifier {
return { return {
"icon": iconFloorMap[diff] ?? "cup.and.saucer", "icon": iconFloorMap[diff] ?? "cup.and.saucer",
"title": "Szünet", "title": "Szünet",
"description": "go $diff".i18n.fill([diff != "to room" ? (nextLesson!.getFloor() ?? 0) : nextLesson!.room]), "description": "go $diff".i18n.fill([
"startDate": ((prevLesson?.end.millisecondsSinceEpoch ?? 0) - _delay.inMilliseconds).toString(), diff != "to room" ? (nextLesson!.getFloor() ?? 0) : nextLesson!.room
"endDate": ((nextLesson?.start.millisecondsSinceEpoch ?? 0) - _delay.inMilliseconds).toString(), ]),
"nextSubject": (nextLesson != null ? ShortSubject.resolve(subject: nextLesson?.subject) : "").capital(), "startDate": ((prevLesson?.end.millisecondsSinceEpoch ?? 0) -
_delay.inMilliseconds)
.toString(),
"endDate": ((nextLesson?.start.millisecondsSinceEpoch ?? 0) -
_delay.inMilliseconds)
.toString(),
"nextSubject": (nextLesson != null
? ShortSubject.resolve(subject: nextLesson?.subject)
: "")
.capital(),
"nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "", "nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "",
"index": "", "index": "",
"subtitle": "", "subtitle": "",
@ -119,15 +149,25 @@ class LiveCardProvider extends ChangeNotifier {
final cmap = toMap(); final cmap = toMap();
if (!mapEquals(cmap, _lastActivity)) { if (!mapEquals(cmap, _lastActivity)) {
_lastActivity = cmap; _lastActivity = cmap;
try {
if (_lastActivity.isNotEmpty) { if (_lastActivity.isNotEmpty) {
if (_latestActivityId == null) { if (_latestActivityId == null) {
_liveActivitiesPlugin.createActivity(_lastActivity).then((value) => _latestActivityId = value); _liveActivitiesPlugin
.createActivity(_lastActivity)
.then((value) => _latestActivityId = value);
} else {
_liveActivitiesPlugin.updateActivity(
_latestActivityId!, _lastActivity);
}
} else { } else {
_liveActivitiesPlugin.updateActivity(_latestActivityId!, _lastActivity); if (_latestActivityId != null) {
_liveActivitiesPlugin.endActivity(_latestActivityId!);
}
}
} catch (e) {
if (kDebugMode) {
print('ERROR: Unable to create or update iOS LiveCard!');
} }
} else {
if (_latestActivityId != null) _liveActivitiesPlugin.endActivity(_latestActivityId!);
} }
} }
} }
@ -139,19 +179,28 @@ class LiveCardProvider extends ChangeNotifier {
today = _today(_timetable); today = _today(_timetable);
} }
_delay = _settings.bellDelayEnabled ? Duration(seconds: _settings.bellDelay) : Duration.zero; _delay = _settings.bellDelayEnabled
? Duration(seconds: _settings.bellDelay)
: Duration.zero;
final now = _now().add(_delay); final now = _now().add(_delay);
// Filter cancelled lessons #20 // Filter cancelled lessons #20
// Filter label lessons #128 // Filter label lessons #128
today = today.where((lesson) => lesson.status?.name != "Elmaradt" && lesson.subject.id != '' && !lesson.isEmpty).toList(); today = today
.where((lesson) =>
lesson.status?.name != "Elmaradt" &&
lesson.subject.id != '' &&
!lesson.isEmpty)
.toList();
if (today.isNotEmpty) { if (today.isNotEmpty) {
// sort // sort
today.sort((a, b) => a.start.compareTo(b.start)); today.sort((a, b) => a.start.compareTo(b.start));
final _lesson = today.firstWhere((l) => l.start.isBefore(now) && l.end.isAfter(now), orElse: () => Lesson.fromJson({})); final _lesson = today.firstWhere(
(l) => l.start.isBefore(now) && l.end.isAfter(now),
orElse: () => Lesson.fromJson({}));
if (_lesson.start.year != 0) { if (_lesson.start.year != 0) {
currentLesson = _lesson; currentLesson = _lesson;
@ -159,7 +208,8 @@ class LiveCardProvider extends ChangeNotifier {
currentLesson = null; currentLesson = null;
} }
final _next = today.firstWhere((l) => l.start.isAfter(now), orElse: () => Lesson.fromJson({})); final _next = today.firstWhere((l) => l.start.isAfter(now),
orElse: () => Lesson.fromJson({}));
nextLessons = today.where((l) => l.start.isAfter(now)).toList(); nextLessons = today.where((l) => l.start.isAfter(now)).toList();
if (_next.start.year != 0) { if (_next.start.year != 0) {
@ -168,7 +218,8 @@ class LiveCardProvider extends ChangeNotifier {
nextLesson = null; nextLesson = null;
} }
final _prev = today.lastWhere((l) => l.end.isBefore(now), orElse: () => Lesson.fromJson({})); final _prev = today.lastWhere((l) => l.end.isBefore(now),
orElse: () => Lesson.fromJson({}));
if (_prev.start.year != 0) { if (_prev.start.year != 0) {
prevLesson = _prev; prevLesson = _prev;
@ -198,7 +249,10 @@ class LiveCardProvider extends ChangeNotifier {
Duration get delay => _delay; Duration get delay => _delay;
bool _sameDate(DateTime a, DateTime b) => (a.year == b.year && a.month == b.month && a.day == b.day); bool _sameDate(DateTime a, DateTime b) =>
(a.year == b.year && a.month == b.month && a.day == b.day);
List<Lesson> _today(TimetableProvider p) => (p.getWeek(Week.current()) ?? []).where((l) => _sameDate(l.date, _now())).toList(); List<Lesson> _today(TimetableProvider p) => (p.getWeek(Week.current()) ?? [])
.where((l) => _sameDate(l.date, _now()))
.toList();
} }

View File

@ -11,7 +11,8 @@ import 'package:intl/intl.dart';
import 'package:i18n_extension/i18n_widget.dart'; import 'package:i18n_extension/i18n_widget.dart';
class PremiumFSTimetable extends StatefulWidget { class PremiumFSTimetable extends StatefulWidget {
const PremiumFSTimetable({Key? key, required this.controller}) : super(key: key); const PremiumFSTimetable({Key? key, required this.controller})
: super(key: key);
final TimetableController controller; final TimetableController controller;
@ -45,16 +46,21 @@ class _PremiumFSTimetableState extends State<PremiumFSTimetable> {
final everyLesson = days.expand((x) => x).toList(); final everyLesson = days.expand((x) => x).toList();
everyLesson.sort((a, b) => a.start.compareTo(b.start)); everyLesson.sort((a, b) => a.start.compareTo(b.start));
final int maxLessonCount = days.fold(0, (a, b) => math.max(a, b.where((l) => l.subject.id != "" || l.isEmpty).length)); final int maxLessonCount = days.fold(
0,
(a, b) => math.max(
a, b.where((l) => l.subject.id != "" || l.isEmpty).length));
final int minIndex = int.tryParse(everyLesson.first.lessonIndex) ?? 0; final int minIndex = int.tryParse(everyLesson.first.lessonIndex) ?? 0;
final int maxIndex = int.tryParse(everyLesson.last.lessonIndex) ?? maxLessonCount; final int maxIndex =
int.tryParse(everyLesson.last.lessonIndex) ?? maxLessonCount;
const prefixw = 40; const prefixw = 40;
const padding = prefixw + 6 * 2; const padding = prefixw + 6 * 2;
final colw = (MediaQuery.of(context).size.width - padding) / days.length; final colw = (MediaQuery.of(context).size.width - padding) / days.length;
return Scaffold( return Scaffold(
appBar: buildAppBar(),
body: ListView.builder( body: ListView.builder(
physics: const BouncingScrollPhysics(), physics: const BouncingScrollPhysics(),
padding: const EdgeInsets.symmetric(horizontal: 6.0, vertical: 24.0), padding: const EdgeInsets.symmetric(horizontal: 6.0, vertical: 24.0),
@ -63,7 +69,10 @@ class _PremiumFSTimetableState extends State<PremiumFSTimetable> {
List<Widget> columns = []; List<Widget> columns = [];
for (int dayIndex = -1; dayIndex < days.length; dayIndex++) { for (int dayIndex = -1; dayIndex < days.length; dayIndex++) {
final dayOffset = dayIndex == -1 ? 0 : (int.tryParse(days[dayIndex].first.lessonIndex) ?? 0) - minIndex; final dayOffset = dayIndex == -1
? 0
: (int.tryParse(days[dayIndex].first.lessonIndex) ?? 0) -
minIndex;
final lessonIndex = index - 1; final lessonIndex = index - 1;
if (dayIndex == -1) { if (dayIndex == -1) {
@ -75,7 +84,9 @@ class _PremiumFSTimetableState extends State<PremiumFSTimetable> {
padding: const EdgeInsets.symmetric(horizontal: 8.0), padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Text( child: Text(
"${minIndex + lessonIndex}.", "${minIndex + lessonIndex}.",
style: TextStyle(fontWeight: FontWeight.bold, color: Theme.of(context).colorScheme.secondary), style: TextStyle(
fontWeight: FontWeight.bold,
color: Theme.of(context).colorScheme.secondary),
), ),
), ),
)); ));
@ -85,12 +96,15 @@ class _PremiumFSTimetableState extends State<PremiumFSTimetable> {
continue; continue;
} }
final lessons = days[dayIndex].where((l) => l.subject.id != "" || l.isEmpty).toList(); final lessons = days[dayIndex]
.where((l) => l.subject.id != "" || l.isEmpty)
.toList();
if (lessons.isEmpty) continue; if (lessons.isEmpty) continue;
if (lessonIndex >= lessons.length) continue; if (lessonIndex >= lessons.length) continue;
if (dayIndex >= days.length || (lessonIndex + dayOffset) >= lessons.length) { if (dayIndex >= days.length ||
(lessonIndex + dayOffset) >= lessons.length) {
columns.add(SizedBox(width: colw)); columns.add(SizedBox(width: colw));
continue; continue;
} }
@ -100,8 +114,11 @@ class _PremiumFSTimetableState extends State<PremiumFSTimetable> {
width: colw, width: colw,
height: 40.0, height: 40.0,
child: Text( child: Text(
DateFormat("EEEE", I18n.of(context).locale.languageCode).format(lessons.first.date).capital(), DateFormat("EEEE", I18n.of(context).locale.languageCode)
style: const TextStyle(fontSize: 24.0, fontWeight: FontWeight.bold), .format(lessons.first.date)
.capital(),
style: const TextStyle(
fontSize: 24.0, fontWeight: FontWeight.bold),
), ),
)); ));
continue; continue;
@ -113,11 +130,14 @@ class _PremiumFSTimetableState extends State<PremiumFSTimetable> {
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Icon(FeatherIcons.slash, size: 18.0, color: AppColors.of(context).text.withOpacity(.3)), Icon(FeatherIcons.slash,
size: 18.0,
color: AppColors.of(context).text.withOpacity(.3)),
const SizedBox(width: 8.0), const SizedBox(width: 8.0),
Text( Text(
"Lyukas óra", "Lyukas óra",
style: TextStyle(color: AppColors.of(context).text.withOpacity(.3)), style: TextStyle(
color: AppColors.of(context).text.withOpacity(.3)),
), ),
], ],
), ),
@ -139,16 +159,27 @@ class _PremiumFSTimetableState extends State<PremiumFSTimetable> {
Row( Row(
children: [ children: [
Icon( Icon(
SubjectIcon.resolveVariant(context: context, subject: lessons[lessonIndex - dayOffset].subject), SubjectIcon.resolveVariant(
context: context,
subject: lessons[lessonIndex - dayOffset].subject),
size: 18.0, size: 18.0,
color: AppColors.of(context).text.withOpacity(.7), color: AppColors.of(context).text.withOpacity(.7),
), ),
const SizedBox(width: 8.0), const SizedBox(width: 8.0),
Expanded( Expanded(
child: Text( child: Text(
lessons[lessonIndex - dayOffset].subject.renamedTo ?? lessons[lessonIndex - dayOffset].subject.name.capital(), lessons[lessonIndex - dayOffset].subject.renamedTo ??
lessons[lessonIndex - dayOffset]
.subject
.name
.capital(),
maxLines: 1, maxLines: 1,
style: TextStyle(fontStyle: lessons[lessonIndex - dayOffset].subject.isRenamed ? FontStyle.italic : null), style: TextStyle(
fontStyle: lessons[lessonIndex - dayOffset]
.subject
.isRenamed
? FontStyle.italic
: null),
overflow: TextOverflow.clip, overflow: TextOverflow.clip,
softWrap: false, softWrap: false,
), ),
@ -160,7 +191,9 @@ class _PremiumFSTimetableState extends State<PremiumFSTimetable> {
padding: const EdgeInsets.only(left: 26.0), padding: const EdgeInsets.only(left: 26.0),
child: Text( child: Text(
lessons[lessonIndex - dayOffset].room, lessons[lessonIndex - dayOffset].room,
style: TextStyle(color: AppColors.of(context).text.withOpacity(.5), overflow: TextOverflow.ellipsis), style: TextStyle(
color: AppColors.of(context).text.withOpacity(.5),
overflow: TextOverflow.ellipsis),
), ),
), ),
], ],
@ -176,4 +209,14 @@ class _PremiumFSTimetableState extends State<PremiumFSTimetable> {
), ),
); );
} }
AppBar buildAppBar() {
return AppBar(
backgroundColor: Colors.transparent,
automaticallyImplyLeading: false,
actions: const [
BackButton(),
],
);
}
} }