Added holidays viewer
This commit is contained in:
parent
38c0cfba9c
commit
7a791ef21f
lib
13
lib/api/holidays/getHolidays.dart
Normal file
13
lib/api/holidays/getHolidays.dart
Normal file
@ -0,0 +1,13 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
import 'getHolidaysResponse.dart';
|
||||
|
||||
class GetHolidays {
|
||||
Future<GetHolidaysResponse> query() async {
|
||||
String response = (await http.get(Uri.parse("https://ferien-api.de/api/v1/holidays/HE"))).body;
|
||||
List<dynamic> parsedListJson = jsonDecode(response);
|
||||
return GetHolidaysResponse(List<GetHolidaysResponseObject>.from(parsedListJson.map<GetHolidaysResponseObject>((dynamic i) => GetHolidaysResponseObject.fromJson(i))));
|
||||
}
|
||||
}
|
22
lib/api/holidays/getHolidaysCache.dart
Normal file
22
lib/api/holidays/getHolidaysCache.dart
Normal file
@ -0,0 +1,22 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import '../requestCache.dart';
|
||||
import 'getHolidays.dart';
|
||||
import 'getHolidaysResponse.dart';
|
||||
|
||||
class GetHolidaysCache extends RequestCache<GetHolidaysResponse> {
|
||||
GetHolidaysCache({onUpdate, renew}) : super(RequestCache.cacheDay, onUpdate, renew: renew) {
|
||||
start("MarianumMobile", "state-holidays");
|
||||
}
|
||||
|
||||
@override
|
||||
GetHolidaysResponse onLocalData(String json) {
|
||||
List<dynamic> parsedListJson = jsonDecode(json)['data'];
|
||||
return GetHolidaysResponse(List<GetHolidaysResponseObject>.from(parsedListJson.map<GetHolidaysResponseObject>((dynamic i) => GetHolidaysResponseObject.fromJson(i))));
|
||||
}
|
||||
|
||||
@override
|
||||
Future<GetHolidaysResponse> onLoad() {
|
||||
return GetHolidays().query();
|
||||
}
|
||||
}
|
38
lib/api/holidays/getHolidaysResponse.dart
Normal file
38
lib/api/holidays/getHolidaysResponse.dart
Normal file
@ -0,0 +1,38 @@
|
||||
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
import '../apiResponse.dart';
|
||||
|
||||
part 'getHolidaysResponse.g.dart';
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class GetHolidaysResponse extends ApiResponse {
|
||||
List<GetHolidaysResponseObject> data;
|
||||
|
||||
GetHolidaysResponse(this.data);
|
||||
|
||||
factory GetHolidaysResponse.fromJson(Map<String, dynamic> json) => _$GetHolidaysResponseFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$GetHolidaysResponseToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable()
|
||||
class GetHolidaysResponseObject {
|
||||
String start;
|
||||
String end;
|
||||
int year;
|
||||
String stateCode;
|
||||
String name;
|
||||
String slug;
|
||||
|
||||
GetHolidaysResponseObject({
|
||||
required this.start,
|
||||
required this.end,
|
||||
required this.year,
|
||||
required this.stateCode,
|
||||
required this.name,
|
||||
required this.slug
|
||||
});
|
||||
|
||||
factory GetHolidaysResponseObject.fromJson(Map<String, dynamic> json) => _$GetHolidaysResponseObjectFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$GetHolidaysResponseObjectToJson(this);
|
||||
}
|
43
lib/api/holidays/getHolidaysResponse.g.dart
Normal file
43
lib/api/holidays/getHolidaysResponse.g.dart
Normal file
@ -0,0 +1,43 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'getHolidaysResponse.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
GetHolidaysResponse _$GetHolidaysResponseFromJson(Map<String, dynamic> json) =>
|
||||
GetHolidaysResponse(
|
||||
(json['data'] as List<dynamic>)
|
||||
.map((e) =>
|
||||
GetHolidaysResponseObject.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$GetHolidaysResponseToJson(
|
||||
GetHolidaysResponse instance) =>
|
||||
<String, dynamic>{
|
||||
'data': instance.data.map((e) => e.toJson()).toList(),
|
||||
};
|
||||
|
||||
GetHolidaysResponseObject _$GetHolidaysResponseObjectFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
GetHolidaysResponseObject(
|
||||
start: json['start'] as String,
|
||||
end: json['end'] as String,
|
||||
year: json['year'] as int,
|
||||
stateCode: json['stateCode'] as String,
|
||||
name: json['name'] as String,
|
||||
slug: json['slug'] as String,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$GetHolidaysResponseObjectToJson(
|
||||
GetHolidaysResponseObject instance) =>
|
||||
<String, dynamic>{
|
||||
'start': instance.start,
|
||||
'end': instance.end,
|
||||
'year': instance.year,
|
||||
'stateCode': instance.stateCode,
|
||||
'name': instance.name,
|
||||
'slug': instance.slug,
|
||||
};
|
@ -1,4 +1,5 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:developer';
|
||||
|
||||
import '../../webuntisApi.dart';
|
||||
import 'getRoomsResponse.dart';
|
||||
@ -9,7 +10,14 @@ class GetRooms extends WebuntisApi {
|
||||
@override
|
||||
Future<GetRoomsResponse> run() async {
|
||||
String rawAnswer = await query(this);
|
||||
return finalize(GetRoomsResponse.fromJson(jsonDecode(rawAnswer)));
|
||||
try {
|
||||
return finalize(GetRoomsResponse.fromJson(jsonDecode(rawAnswer)));
|
||||
} catch(e, trace) {
|
||||
log(trace.toString());
|
||||
log("Failed to parse getRoom data with server response: $rawAnswer");
|
||||
}
|
||||
|
||||
throw Exception("Failed to parse getRoom server response");
|
||||
}
|
||||
|
||||
}
|
@ -12,6 +12,7 @@ import 'model/accountModel.dart';
|
||||
import 'model/chatList/chatListProps.dart';
|
||||
import 'model/chatList/chatProps.dart';
|
||||
import 'model/files/filesProps.dart';
|
||||
import 'model/holidays/holidaysProps.dart';
|
||||
import 'model/message/messageProps.dart';
|
||||
import 'model/timetable/timetableProps.dart';
|
||||
import 'storage/base/settingsProvider.dart';
|
||||
@ -42,6 +43,7 @@ Future<void> main() async {
|
||||
ChangeNotifierProvider(create: (context) => FilesProps()),
|
||||
|
||||
ChangeNotifierProvider(create: (context) => MessageProps()),
|
||||
ChangeNotifierProvider(create: (context) => HolidaysProps()),
|
||||
],
|
||||
child: const Main(),
|
||||
)
|
||||
|
26
lib/model/holidays/holidaysProps.dart
Normal file
26
lib/model/holidays/holidaysProps.dart
Normal file
@ -0,0 +1,26 @@
|
||||
|
||||
import '../../api/apiResponse.dart';
|
||||
import '../../api/holidays/getHolidaysCache.dart';
|
||||
import '../../api/holidays/getHolidaysResponse.dart';
|
||||
import '../dataHolder.dart';
|
||||
|
||||
|
||||
class HolidaysProps extends DataHolder {
|
||||
GetHolidaysResponse? _getHolidaysResponse;
|
||||
GetHolidaysResponse get getHolidaysResponse => _getHolidaysResponse!;
|
||||
|
||||
@override
|
||||
List<ApiResponse?> properties() {
|
||||
return [_getHolidaysResponse];
|
||||
}
|
||||
|
||||
@override
|
||||
void run() {
|
||||
GetHolidaysCache(
|
||||
onUpdate: (GetHolidaysResponse data) => {
|
||||
_getHolidaysResponse = data,
|
||||
notifyListeners(),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@ import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
import '../file/fileSettings.dart';
|
||||
import '../gradeAverages/gradeAveragesSettings.dart';
|
||||
import '../holidays/holidaysSettings.dart';
|
||||
import '../talk/talkSettings.dart';
|
||||
import '../timetable/timetableSettings.dart';
|
||||
|
||||
@ -21,6 +22,7 @@ class Settings {
|
||||
TimetableSettings timetableSettings;
|
||||
TalkSettings talkSettings;
|
||||
FileSettings fileSettings;
|
||||
HolidaysSettings holidaysSettings;
|
||||
|
||||
Settings({
|
||||
required this.appTheme,
|
||||
@ -29,6 +31,7 @@ class Settings {
|
||||
required this.timetableSettings,
|
||||
required this.talkSettings,
|
||||
required this.fileSettings,
|
||||
required this.holidaysSettings,
|
||||
});
|
||||
|
||||
static String _themeToJson(ThemeMode m) => m.name;
|
||||
|
@ -17,6 +17,8 @@ Settings _$SettingsFromJson(Map<String, dynamic> json) => Settings(
|
||||
TalkSettings.fromJson(json['talkSettings'] as Map<String, dynamic>),
|
||||
fileSettings:
|
||||
FileSettings.fromJson(json['fileSettings'] as Map<String, dynamic>),
|
||||
holidaysSettings: HolidaysSettings.fromJson(
|
||||
json['holidaysSettings'] as Map<String, dynamic>),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$SettingsToJson(Settings instance) => <String, dynamic>{
|
||||
@ -26,4 +28,5 @@ Map<String, dynamic> _$SettingsToJson(Settings instance) => <String, dynamic>{
|
||||
'timetableSettings': instance.timetableSettings.toJson(),
|
||||
'talkSettings': instance.talkSettings.toJson(),
|
||||
'fileSettings': instance.fileSettings.toJson(),
|
||||
'holidaysSettings': instance.holidaysSettings.toJson(),
|
||||
};
|
||||
|
@ -5,6 +5,7 @@ import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import '../file/fileSettings.dart';
|
||||
import '../gradeAverages/gradeAveragesSettings.dart';
|
||||
import '../holidays/holidaysSettings.dart';
|
||||
import '../talk/talkSettings.dart';
|
||||
import '../timetable/timetableSettings.dart';
|
||||
import 'settings.dart';
|
||||
@ -64,6 +65,10 @@ class SettingsProvider extends ChangeNotifier {
|
||||
fileSettings: FileSettings(
|
||||
sortFoldersToTop: true,
|
||||
),
|
||||
holidaysSettings: HolidaysSettings(
|
||||
dismissedDisclaimer: false,
|
||||
showPastEvents: false,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
14
lib/storage/holidays/holidaysSettings.dart
Normal file
14
lib/storage/holidays/holidaysSettings.dart
Normal file
@ -0,0 +1,14 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'holidaysSettings.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class HolidaysSettings {
|
||||
bool dismissedDisclaimer;
|
||||
bool showPastEvents;
|
||||
|
||||
HolidaysSettings({required this.dismissedDisclaimer, required this.showPastEvents});
|
||||
|
||||
factory HolidaysSettings.fromJson(Map<String, dynamic> json) => _$HolidaysSettingsFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$HolidaysSettingsToJson(this);
|
||||
}
|
19
lib/storage/holidays/holidaysSettings.g.dart
Normal file
19
lib/storage/holidays/holidaysSettings.g.dart
Normal file
@ -0,0 +1,19 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'holidaysSettings.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
HolidaysSettings _$HolidaysSettingsFromJson(Map<String, dynamic> json) =>
|
||||
HolidaysSettings(
|
||||
dismissedDisclaimer: json['dismissedDisclaimer'] as bool,
|
||||
showPastEvents: json['showPastEvents'] as bool,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$HolidaysSettingsToJson(HolidaysSettings instance) =>
|
||||
<String, dynamic>{
|
||||
'dismissedDisclaimer': instance.dismissedDisclaimer,
|
||||
'showPastEvents': instance.showPastEvents,
|
||||
};
|
140
lib/view/pages/holidays/holidays.dart
Normal file
140
lib/view/pages/holidays/holidays.dart
Normal file
@ -0,0 +1,140 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:jiffy/jiffy.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../../../api/holidays/getHolidaysResponse.dart';
|
||||
import '../../../model/holidays/holidaysProps.dart';
|
||||
import '../../../storage/base/settingsProvider.dart';
|
||||
import '../../../widget/confirmDialog.dart';
|
||||
import '../../../widget/loadingSpinner.dart';
|
||||
|
||||
class Holidays extends StatefulWidget {
|
||||
const Holidays({super.key});
|
||||
|
||||
@override
|
||||
State<Holidays> createState() => _HolidaysState();
|
||||
}
|
||||
|
||||
class _HolidaysState extends State<Holidays> {
|
||||
late SettingsProvider settings = Provider.of<SettingsProvider>(context, listen: false);
|
||||
late bool showPastEvents = settings.val().holidaysSettings.showPastEvents;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
||||
Provider.of<HolidaysProps>(context, listen: false).run();
|
||||
if(!settings.val().holidaysSettings.dismissedDisclaimer) showDisclaimer();
|
||||
});
|
||||
|
||||
super.initState();
|
||||
}
|
||||
|
||||
String parseString(String enDate) {
|
||||
return Jiffy.parse(enDate).format(pattern: "dd.MM.yyyy");
|
||||
}
|
||||
|
||||
void showDisclaimer() {
|
||||
showDialog(context: context, builder: (context) {
|
||||
return AlertDialog(
|
||||
title: const Text("Richtigkeit und Bereitstellung der Daten"),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Text(""
|
||||
"Sämtliche Datumsangaben sind ohne Gewähr.\n"
|
||||
"Ich übernehme weder Verantwortung für die Richtigkeit der Daten noch hafte ich für wirtschaftliche Schäden die aus der Verwendung dieser Daten entstehen können.\n\n"
|
||||
"Die Daten stammen von https://ferien-api.de/"),
|
||||
const SizedBox(height: 30),
|
||||
ListTile(
|
||||
title: const Text("Diese Meldung nicht mehr anzeigen"),
|
||||
trailing: Checkbox(
|
||||
value: settings.val().holidaysSettings.dismissedDisclaimer,
|
||||
onChanged: (value) => settings.val(write: true).holidaysSettings.dismissedDisclaimer = value!,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
TextButton(child: const Text("ferien-api.de öffnen"), onPressed: () => ConfirmDialog.openBrowser(context, "https://ferien-api.de/")),
|
||||
TextButton(child: const Text("Schlißen"), onPressed: () => Navigator.of(context).pop()),
|
||||
],
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text("Schulferien in Hessen"),
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.warning_amber_outlined),
|
||||
onPressed: () => showDisclaimer(),
|
||||
),
|
||||
PopupMenuButton<bool>(
|
||||
initialValue: settings.val().holidaysSettings.showPastEvents,
|
||||
icon: const Icon(Icons.manage_history_outlined),
|
||||
itemBuilder: (context) {
|
||||
return [true, false].map((e) => PopupMenuItem<bool>(
|
||||
value: e,
|
||||
enabled: e != showPastEvents,
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(e ? Icons.history_outlined : Icons.history_toggle_off_outlined, color: Theme.of(context).colorScheme.onSurface),
|
||||
const SizedBox(width: 15),
|
||||
Text(e ? "Alle anzeigen" : "Nur zukünftige anzeigen")
|
||||
],
|
||||
)
|
||||
)).toList();
|
||||
},
|
||||
onSelected: (e) {
|
||||
setState(() {
|
||||
showPastEvents = e;
|
||||
settings.val(write: true).holidaysSettings.showPastEvents = e;
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
body: Consumer<HolidaysProps>(builder: (context, value, child) {
|
||||
if(value.primaryLoading()) return const LoadingSpinner();
|
||||
|
||||
List<GetHolidaysResponseObject> holidays = value.getHolidaysResponse.data;
|
||||
if(!showPastEvents) holidays = holidays.where((element) => DateTime.parse(element.end).isAfter(DateTime.now())).toList();
|
||||
|
||||
return ListView.builder(
|
||||
itemCount: holidays.length,
|
||||
itemBuilder: (context, index) {
|
||||
GetHolidaysResponseObject holiday = holidays[index];
|
||||
return ListTile(
|
||||
leading: const Icon(Icons.calendar_month),
|
||||
title: Text("${parseString(holiday.start)} bis ${parseString(holiday.end)}"),
|
||||
subtitle: Text("${holiday.name} - (${Jiffy.parse(holiday.start).fromNow()})"),
|
||||
onTap: () => showDialog(context: context, builder: (context) => SimpleDialog(
|
||||
title: Text("Ferien in Hessen | ${holiday.year}"),
|
||||
children: [
|
||||
ListTile(
|
||||
leading: const Icon(Icons.signpost_outlined),
|
||||
title: Text(holiday.name),
|
||||
subtitle: Text(holiday.slug),
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.event),
|
||||
title: Text("beginnend ${parseString(holiday.start)}"),
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.event_busy_outlined),
|
||||
title: Text("endend ${parseString(holiday.end)}"),
|
||||
),
|
||||
],
|
||||
)),
|
||||
trailing: const Icon(Icons.arrow_right),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ import 'package:persistent_bottom_nav_bar/persistent_tab_view.dart';
|
||||
|
||||
import '../../../widget/ListItem.dart';
|
||||
import '../../settings/settings.dart';
|
||||
import '../holidays/holidays.dart';
|
||||
import 'countdown/countdown.dart';
|
||||
import 'gradeAverages/gradeAverage.dart';
|
||||
import 'message/message.dart';
|
||||
@ -27,7 +28,7 @@ class Overhang extends StatelessWidget {
|
||||
ListItemNavigator(icon: Icons.newspaper, text: "Marianum Message", target: Message()),
|
||||
ListItemNavigator(icon: Icons.room, text: "Raumplan", target: Roomplan()),
|
||||
ListItemNavigator(icon: Icons.calculate, text: "Notendurschnitts rechner", target: GradeAverage()),
|
||||
if(!kReleaseMode) ListItemNavigator(icon: Icons.calendar_month, text: "Schulferien", target: Roomplan()),
|
||||
ListItemNavigator(icon: Icons.calendar_month, text: "Schulferien", target: Holidays()),
|
||||
if(!kReleaseMode) ListItemNavigator(icon: Icons.timer, text: "Countdown", target: Countdown()),
|
||||
],
|
||||
),
|
||||
|
Loading…
x
Reference in New Issue
Block a user