migrated holidays module to MarianumConnect API, replaced local Holiday model.

This commit is contained in:
2026-05-24 17:49:25 +02:00
parent 93b9929f8f
commit 01b4b44010
15 changed files with 161 additions and 456 deletions
@@ -0,0 +1,30 @@
import 'package:json_annotation/json_annotation.dart';
part 'mc_holiday.g.dart';
@JsonSerializable(explicitToJson: true)
class McHoliday {
final String shortName;
final String longName;
@JsonKey(fromJson: _dateFromJson, toJson: _dateToJson)
final DateTime startDate;
@JsonKey(fromJson: _dateFromJson, toJson: _dateToJson)
final DateTime endDate;
McHoliday({
required this.shortName,
required this.longName,
required this.startDate,
required this.endDate,
});
factory McHoliday.fromJson(Map<String, dynamic> json) =>
_$McHolidayFromJson(json);
Map<String, dynamic> toJson() => _$McHolidayToJson(this);
static DateTime _dateFromJson(String raw) => DateTime.parse(raw);
static String _dateToJson(DateTime d) =>
'${d.year.toString().padLeft(4, '0')}-${d.month.toString().padLeft(2, '0')}-${d.day.toString().padLeft(2, '0')}';
}
@@ -0,0 +1,21 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'mc_holiday.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
McHoliday _$McHolidayFromJson(Map<String, dynamic> json) => McHoliday(
shortName: json['shortName'] as String,
longName: json['longName'] as String,
startDate: McHoliday._dateFromJson(json['startDate'] as String),
endDate: McHoliday._dateFromJson(json['endDate'] as String),
);
Map<String, dynamic> _$McHolidayToJson(McHoliday instance) => <String, dynamic>{
'shortName': instance.shortName,
'longName': instance.longName,
'startDate': McHoliday._dateToJson(instance.startDate),
'endDate': McHoliday._dateToJson(instance.endDate),
};
@@ -0,0 +1,25 @@
import 'package:dio/dio.dart';
import '../../errors/marianumconnect_error.dart';
import '../../marianumconnect_api.dart';
import '../../marianumconnect_endpoint.dart';
import '../../models/mc_holiday.dart';
class GetHolidays {
final Dio _dio;
GetHolidays({Dio? dio}) : _dio = dio ?? MarianumConnectApi.dio();
Future<List<McHoliday>> run() async {
try {
final response = await _dio.get<List<dynamic>>(
MarianumConnectEndpoint.resolve('holidays'),
);
return response.data!
.map((e) => McHoliday.fromJson(e as Map<String, dynamic>))
.toList();
} on DioException catch (e) {
throw mapMarianumConnectError(e);
}
}
}
@@ -1,36 +1,12 @@
import 'package:json_annotation/json_annotation.dart'; import 'package:json_annotation/json_annotation.dart';
import '../../../api_response.dart'; import '../../../api_response.dart';
import '../../models/mc_holiday.dart';
export '../../models/mc_holiday.dart';
part 'timetable_get_holidays_response.g.dart'; part 'timetable_get_holidays_response.g.dart';
@JsonSerializable(explicitToJson: true)
class McHoliday {
final String shortName;
final String longName;
@JsonKey(fromJson: _dateFromJson, toJson: _dateToJson)
final DateTime startDate;
@JsonKey(fromJson: _dateFromJson, toJson: _dateToJson)
final DateTime endDate;
McHoliday({
required this.shortName,
required this.longName,
required this.startDate,
required this.endDate,
});
factory McHoliday.fromJson(Map<String, dynamic> json) =>
_$McHolidayFromJson(json);
Map<String, dynamic> toJson() => _$McHolidayToJson(this);
static DateTime _dateFromJson(String raw) => DateTime.parse(raw);
static String _dateToJson(DateTime d) =>
'${d.year.toString().padLeft(4, '0')}-${d.month.toString().padLeft(2, '0')}-${d.day.toString().padLeft(2, '0')}';
}
@JsonSerializable(explicitToJson: true) @JsonSerializable(explicitToJson: true)
class TimetableGetHolidaysResponse extends ApiResponse { class TimetableGetHolidaysResponse extends ApiResponse {
final List<McHoliday> result; final List<McHoliday> result;
@@ -6,20 +6,6 @@ part of 'timetable_get_holidays_response.dart';
// JsonSerializableGenerator // JsonSerializableGenerator
// ************************************************************************** // **************************************************************************
McHoliday _$McHolidayFromJson(Map<String, dynamic> json) => McHoliday(
shortName: json['shortName'] as String,
longName: json['longName'] as String,
startDate: McHoliday._dateFromJson(json['startDate'] as String),
endDate: McHoliday._dateFromJson(json['endDate'] as String),
);
Map<String, dynamic> _$McHolidayToJson(McHoliday instance) => <String, dynamic>{
'shortName': instance.shortName,
'longName': instance.longName,
'startDate': McHoliday._dateToJson(instance.startDate),
'endDate': McHoliday._dateToJson(instance.endDate),
};
TimetableGetHolidaysResponse _$TimetableGetHolidaysResponseFromJson( TimetableGetHolidaysResponse _$TimetableGetHolidaysResponseFromJson(
Map<String, dynamic> json, Map<String, dynamic> json,
) => ) =>
@@ -1,8 +0,0 @@
import 'package:dio/dio.dart';
import '../../infrastructure/data_loader/data_loader.dart';
abstract class HolidayDataLoader<TResult> extends DataLoader<TResult> {
HolidayDataLoader()
: super(Dio(BaseOptions(baseUrl: 'https://ferien-api.de/api/v1/')));
}
+1 -1
View File
@@ -115,7 +115,7 @@ class AppModule {
Modules.holidays: AppModule( Modules.holidays: AppModule(
Modules.holidays, Modules.holidays,
name: 'Schulferien', name: 'Schulferien',
icon: () => Icon(Icons.flight), icon: () => Icon(Icons.beach_access_outlined),
breakerArea: BreakerArea.more, breakerArea: BreakerArea.more,
create: HolidaysView.new, create: HolidaysView.new,
), ),
@@ -1,3 +1,4 @@
import '../../../../../api/marianumconnect/models/mc_holiday.dart';
import '../../../infrastructure/utility_widgets/loadable_hydrated_bloc/loadable_hydrated_bloc.dart'; import '../../../infrastructure/utility_widgets/loadable_hydrated_bloc/loadable_hydrated_bloc.dart';
import '../../../infrastructure/utility_widgets/loadable_hydrated_bloc/loadable_hydrated_bloc_event.dart'; import '../../../infrastructure/utility_widgets/loadable_hydrated_bloc/loadable_hydrated_bloc_event.dart';
import '../repository/holidays_repository.dart'; import '../repository/holidays_repository.dart';
@@ -24,12 +25,12 @@ class HolidaysBloc
bool showPastHolidays() => innerState?.showPastHolidays ?? false; bool showPastHolidays() => innerState?.showPastHolidays ?? false;
bool showDisclaimerOnEntry() => innerState?.showDisclaimer ?? false; bool showDisclaimerOnEntry() => innerState?.showDisclaimer ?? false;
List<Holiday>? getHolidays() => List<McHoliday>? getHolidays() =>
innerState?.holidays innerState?.holidays
.where( .where(
(element) => (element) =>
showPastHolidays() || showPastHolidays() ||
DateTime.parse(element.end).isAfter(DateTime.now()), element.endDate.isAfter(DateTime.now()),
) )
.toList() ?? .toList() ??
[]; [];
@@ -1,6 +1,8 @@
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
import '../../../../../api/marianumconnect/models/mc_holiday.dart';
part 'holidays_state.freezed.dart'; part 'holidays_state.freezed.dart';
part 'holidays_state.g.dart'; part 'holidays_state.g.dart';
@@ -9,24 +11,9 @@ abstract class HolidaysState with _$HolidaysState {
const factory HolidaysState({ const factory HolidaysState({
required bool showPastHolidays, required bool showPastHolidays,
required bool showDisclaimer, required bool showDisclaimer,
required List<Holiday> holidays, required List<McHoliday> holidays,
}) = _HolidaysState; }) = _HolidaysState;
factory HolidaysState.fromJson(Map<String, Object?> json) => factory HolidaysState.fromJson(Map<String, Object?> json) =>
_$HolidaysStateFromJson(json); _$HolidaysStateFromJson(json);
} }
@freezed
abstract class Holiday with _$Holiday {
const factory Holiday({
required String start,
required String end,
required int year,
required String stateCode,
required String name,
required String slug,
}) = _Holiday;
factory Holiday.fromJson(Map<String, Object?> json) =>
_$HolidayFromJson(json);
}
@@ -15,7 +15,7 @@ T _$identity<T>(T value) => value;
/// @nodoc /// @nodoc
mixin _$HolidaysState implements DiagnosticableTreeMixin { mixin _$HolidaysState implements DiagnosticableTreeMixin {
bool get showPastHolidays; bool get showDisclaimer; List<Holiday> get holidays; bool get showPastHolidays; bool get showDisclaimer; List<McHoliday> get holidays;
/// Create a copy of HolidaysState /// Create a copy of HolidaysState
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false) @JsonKey(includeFromJson: false, includeToJson: false)
@@ -54,7 +54,7 @@ abstract mixin class $HolidaysStateCopyWith<$Res> {
factory $HolidaysStateCopyWith(HolidaysState value, $Res Function(HolidaysState) _then) = _$HolidaysStateCopyWithImpl; factory $HolidaysStateCopyWith(HolidaysState value, $Res Function(HolidaysState) _then) = _$HolidaysStateCopyWithImpl;
@useResult @useResult
$Res call({ $Res call({
bool showPastHolidays, bool showDisclaimer, List<Holiday> holidays bool showPastHolidays, bool showDisclaimer, List<McHoliday> holidays
}); });
@@ -76,7 +76,7 @@ class _$HolidaysStateCopyWithImpl<$Res>
showPastHolidays: null == showPastHolidays ? _self.showPastHolidays : showPastHolidays // ignore: cast_nullable_to_non_nullable showPastHolidays: null == showPastHolidays ? _self.showPastHolidays : showPastHolidays // ignore: cast_nullable_to_non_nullable
as bool,showDisclaimer: null == showDisclaimer ? _self.showDisclaimer : showDisclaimer // ignore: cast_nullable_to_non_nullable as bool,showDisclaimer: null == showDisclaimer ? _self.showDisclaimer : showDisclaimer // ignore: cast_nullable_to_non_nullable
as bool,holidays: null == holidays ? _self.holidays : holidays // ignore: cast_nullable_to_non_nullable as bool,holidays: null == holidays ? _self.holidays : holidays // ignore: cast_nullable_to_non_nullable
as List<Holiday>, as List<McHoliday>,
)); ));
} }
@@ -161,7 +161,7 @@ return $default(_that);case _:
/// } /// }
/// ``` /// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool showPastHolidays, bool showDisclaimer, List<Holiday> holidays)? $default,{required TResult orElse(),}) {final _that = this; @optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool showPastHolidays, bool showDisclaimer, List<McHoliday> holidays)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) { switch (_that) {
case _HolidaysState() when $default != null: case _HolidaysState() when $default != null:
return $default(_that.showPastHolidays,_that.showDisclaimer,_that.holidays);case _: return $default(_that.showPastHolidays,_that.showDisclaimer,_that.holidays);case _:
@@ -182,7 +182,7 @@ return $default(_that.showPastHolidays,_that.showDisclaimer,_that.holidays);case
/// } /// }
/// ``` /// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool showPastHolidays, bool showDisclaimer, List<Holiday> holidays) $default,) {final _that = this; @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool showPastHolidays, bool showDisclaimer, List<McHoliday> holidays) $default,) {final _that = this;
switch (_that) { switch (_that) {
case _HolidaysState(): case _HolidaysState():
return $default(_that.showPastHolidays,_that.showDisclaimer,_that.holidays);case _: return $default(_that.showPastHolidays,_that.showDisclaimer,_that.holidays);case _:
@@ -202,7 +202,7 @@ return $default(_that.showPastHolidays,_that.showDisclaimer,_that.holidays);case
/// } /// }
/// ``` /// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool showPastHolidays, bool showDisclaimer, List<Holiday> holidays)? $default,) {final _that = this; @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool showPastHolidays, bool showDisclaimer, List<McHoliday> holidays)? $default,) {final _that = this;
switch (_that) { switch (_that) {
case _HolidaysState() when $default != null: case _HolidaysState() when $default != null:
return $default(_that.showPastHolidays,_that.showDisclaimer,_that.holidays);case _: return $default(_that.showPastHolidays,_that.showDisclaimer,_that.holidays);case _:
@@ -217,13 +217,13 @@ return $default(_that.showPastHolidays,_that.showDisclaimer,_that.holidays);case
@JsonSerializable() @JsonSerializable()
class _HolidaysState with DiagnosticableTreeMixin implements HolidaysState { class _HolidaysState with DiagnosticableTreeMixin implements HolidaysState {
const _HolidaysState({required this.showPastHolidays, required this.showDisclaimer, required final List<Holiday> holidays}): _holidays = holidays; const _HolidaysState({required this.showPastHolidays, required this.showDisclaimer, required final List<McHoliday> holidays}): _holidays = holidays;
factory _HolidaysState.fromJson(Map<String, dynamic> json) => _$HolidaysStateFromJson(json); factory _HolidaysState.fromJson(Map<String, dynamic> json) => _$HolidaysStateFromJson(json);
@override final bool showPastHolidays; @override final bool showPastHolidays;
@override final bool showDisclaimer; @override final bool showDisclaimer;
final List<Holiday> _holidays; final List<McHoliday> _holidays;
@override List<Holiday> get holidays { @override List<McHoliday> get holidays {
if (_holidays is EqualUnmodifiableListView) return _holidays; if (_holidays is EqualUnmodifiableListView) return _holidays;
// ignore: implicit_dynamic_type // ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_holidays); return EqualUnmodifiableListView(_holidays);
@@ -269,7 +269,7 @@ abstract mixin class _$HolidaysStateCopyWith<$Res> implements $HolidaysStateCopy
factory _$HolidaysStateCopyWith(_HolidaysState value, $Res Function(_HolidaysState) _then) = __$HolidaysStateCopyWithImpl; factory _$HolidaysStateCopyWith(_HolidaysState value, $Res Function(_HolidaysState) _then) = __$HolidaysStateCopyWithImpl;
@override @useResult @override @useResult
$Res call({ $Res call({
bool showPastHolidays, bool showDisclaimer, List<Holiday> holidays bool showPastHolidays, bool showDisclaimer, List<McHoliday> holidays
}); });
@@ -291,297 +291,7 @@ class __$HolidaysStateCopyWithImpl<$Res>
showPastHolidays: null == showPastHolidays ? _self.showPastHolidays : showPastHolidays // ignore: cast_nullable_to_non_nullable showPastHolidays: null == showPastHolidays ? _self.showPastHolidays : showPastHolidays // ignore: cast_nullable_to_non_nullable
as bool,showDisclaimer: null == showDisclaimer ? _self.showDisclaimer : showDisclaimer // ignore: cast_nullable_to_non_nullable as bool,showDisclaimer: null == showDisclaimer ? _self.showDisclaimer : showDisclaimer // ignore: cast_nullable_to_non_nullable
as bool,holidays: null == holidays ? _self._holidays : holidays // ignore: cast_nullable_to_non_nullable as bool,holidays: null == holidays ? _self._holidays : holidays // ignore: cast_nullable_to_non_nullable
as List<Holiday>, as List<McHoliday>,
));
}
}
/// @nodoc
mixin _$Holiday implements DiagnosticableTreeMixin {
String get start; String get end; int get year; String get stateCode; String get name; String get slug;
/// Create a copy of Holiday
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$HolidayCopyWith<Holiday> get copyWith => _$HolidayCopyWithImpl<Holiday>(this as Holiday, _$identity);
/// Serializes this Holiday to a JSON map.
Map<String, dynamic> toJson();
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
properties
..add(DiagnosticsProperty('type', 'Holiday'))
..add(DiagnosticsProperty('start', start))..add(DiagnosticsProperty('end', end))..add(DiagnosticsProperty('year', year))..add(DiagnosticsProperty('stateCode', stateCode))..add(DiagnosticsProperty('name', name))..add(DiagnosticsProperty('slug', slug));
}
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is Holiday&&(identical(other.start, start) || other.start == start)&&(identical(other.end, end) || other.end == end)&&(identical(other.year, year) || other.year == year)&&(identical(other.stateCode, stateCode) || other.stateCode == stateCode)&&(identical(other.name, name) || other.name == name)&&(identical(other.slug, slug) || other.slug == slug));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,start,end,year,stateCode,name,slug);
@override
String toString({ DiagnosticLevel minLevel = DiagnosticLevel.info }) {
return 'Holiday(start: $start, end: $end, year: $year, stateCode: $stateCode, name: $name, slug: $slug)';
}
}
/// @nodoc
abstract mixin class $HolidayCopyWith<$Res> {
factory $HolidayCopyWith(Holiday value, $Res Function(Holiday) _then) = _$HolidayCopyWithImpl;
@useResult
$Res call({
String start, String end, int year, String stateCode, String name, String slug
});
}
/// @nodoc
class _$HolidayCopyWithImpl<$Res>
implements $HolidayCopyWith<$Res> {
_$HolidayCopyWithImpl(this._self, this._then);
final Holiday _self;
final $Res Function(Holiday) _then;
/// Create a copy of Holiday
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? start = null,Object? end = null,Object? year = null,Object? stateCode = null,Object? name = null,Object? slug = null,}) {
return _then(_self.copyWith(
start: null == start ? _self.start : start // ignore: cast_nullable_to_non_nullable
as String,end: null == end ? _self.end : end // ignore: cast_nullable_to_non_nullable
as String,year: null == year ? _self.year : year // ignore: cast_nullable_to_non_nullable
as int,stateCode: null == stateCode ? _self.stateCode : stateCode // ignore: cast_nullable_to_non_nullable
as String,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
as String,slug: null == slug ? _self.slug : slug // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
/// Adds pattern-matching-related methods to [Holiday].
extension HolidayPatterns on Holiday {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _Holiday value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _Holiday() when $default != null:
return $default(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _Holiday value) $default,){
final _that = this;
switch (_that) {
case _Holiday():
return $default(_that);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _Holiday value)? $default,){
final _that = this;
switch (_that) {
case _Holiday() when $default != null:
return $default(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String start, String end, int year, String stateCode, String name, String slug)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _Holiday() when $default != null:
return $default(_that.start,_that.end,_that.year,_that.stateCode,_that.name,_that.slug);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String start, String end, int year, String stateCode, String name, String slug) $default,) {final _that = this;
switch (_that) {
case _Holiday():
return $default(_that.start,_that.end,_that.year,_that.stateCode,_that.name,_that.slug);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String start, String end, int year, String stateCode, String name, String slug)? $default,) {final _that = this;
switch (_that) {
case _Holiday() when $default != null:
return $default(_that.start,_that.end,_that.year,_that.stateCode,_that.name,_that.slug);case _:
return null;
}
}
}
/// @nodoc
@JsonSerializable()
class _Holiday with DiagnosticableTreeMixin implements Holiday {
const _Holiday({required this.start, required this.end, required this.year, required this.stateCode, required this.name, required this.slug});
factory _Holiday.fromJson(Map<String, dynamic> json) => _$HolidayFromJson(json);
@override final String start;
@override final String end;
@override final int year;
@override final String stateCode;
@override final String name;
@override final String slug;
/// Create a copy of Holiday
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$HolidayCopyWith<_Holiday> get copyWith => __$HolidayCopyWithImpl<_Holiday>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$HolidayToJson(this, );
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
properties
..add(DiagnosticsProperty('type', 'Holiday'))
..add(DiagnosticsProperty('start', start))..add(DiagnosticsProperty('end', end))..add(DiagnosticsProperty('year', year))..add(DiagnosticsProperty('stateCode', stateCode))..add(DiagnosticsProperty('name', name))..add(DiagnosticsProperty('slug', slug));
}
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _Holiday&&(identical(other.start, start) || other.start == start)&&(identical(other.end, end) || other.end == end)&&(identical(other.year, year) || other.year == year)&&(identical(other.stateCode, stateCode) || other.stateCode == stateCode)&&(identical(other.name, name) || other.name == name)&&(identical(other.slug, slug) || other.slug == slug));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,start,end,year,stateCode,name,slug);
@override
String toString({ DiagnosticLevel minLevel = DiagnosticLevel.info }) {
return 'Holiday(start: $start, end: $end, year: $year, stateCode: $stateCode, name: $name, slug: $slug)';
}
}
/// @nodoc
abstract mixin class _$HolidayCopyWith<$Res> implements $HolidayCopyWith<$Res> {
factory _$HolidayCopyWith(_Holiday value, $Res Function(_Holiday) _then) = __$HolidayCopyWithImpl;
@override @useResult
$Res call({
String start, String end, int year, String stateCode, String name, String slug
});
}
/// @nodoc
class __$HolidayCopyWithImpl<$Res>
implements _$HolidayCopyWith<$Res> {
__$HolidayCopyWithImpl(this._self, this._then);
final _Holiday _self;
final $Res Function(_Holiday) _then;
/// Create a copy of Holiday
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? start = null,Object? end = null,Object? year = null,Object? stateCode = null,Object? name = null,Object? slug = null,}) {
return _then(_Holiday(
start: null == start ? _self.start : start // ignore: cast_nullable_to_non_nullable
as String,end: null == end ? _self.end : end // ignore: cast_nullable_to_non_nullable
as String,year: null == year ? _self.year : year // ignore: cast_nullable_to_non_nullable
as int,stateCode: null == stateCode ? _self.stateCode : stateCode // ignore: cast_nullable_to_non_nullable
as String,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
as String,slug: null == slug ? _self.slug : slug // ignore: cast_nullable_to_non_nullable
as String,
)); ));
} }
@@ -11,7 +11,7 @@ _HolidaysState _$HolidaysStateFromJson(Map<String, dynamic> json) =>
showPastHolidays: json['showPastHolidays'] as bool, showPastHolidays: json['showPastHolidays'] as bool,
showDisclaimer: json['showDisclaimer'] as bool, showDisclaimer: json['showDisclaimer'] as bool,
holidays: (json['holidays'] as List<dynamic>) holidays: (json['holidays'] as List<dynamic>)
.map((e) => Holiday.fromJson(e as Map<String, dynamic>)) .map((e) => McHoliday.fromJson(e as Map<String, dynamic>))
.toList(), .toList(),
); );
@@ -21,21 +21,3 @@ Map<String, dynamic> _$HolidaysStateToJson(_HolidaysState instance) =>
'showDisclaimer': instance.showDisclaimer, 'showDisclaimer': instance.showDisclaimer,
'holidays': instance.holidays, 'holidays': instance.holidays,
}; };
_Holiday _$HolidayFromJson(Map<String, dynamic> json) => _Holiday(
start: json['start'] as String,
end: json['end'] as String,
year: (json['year'] as num).toInt(),
stateCode: json['stateCode'] as String,
name: json['name'] as String,
slug: json['slug'] as String,
);
Map<String, dynamic> _$HolidayToJson(_Holiday instance) => <String, dynamic>{
'start': instance.start,
'end': instance.end,
'year': instance.year,
'stateCode': instance.stateCode,
'name': instance.name,
'slug': instance.slug,
};
@@ -1,14 +0,0 @@
import 'package:dio/dio.dart';
import '../../../basis/dataloader/holiday_data_loader.dart';
import '../../../infrastructure/data_loader/data_loader.dart';
import '../bloc/holidays_state.dart';
class HolidaysGetHolidays extends HolidayDataLoader<List<Holiday>> {
@override
List<Holiday> assemble(DataLoaderResult data) =>
data.asListOfMaps().map(Holiday.fromJson).toList();
@override
Future<Response<String>> fetch() => dio.get('/holidays/HE');
}
@@ -1,7 +1,8 @@
import '../../../../../api/marianumconnect/models/mc_holiday.dart';
import '../../../../../api/marianumconnect/queries/get_holidays/get_holidays.dart';
import '../../../infrastructure/repository/repository.dart'; import '../../../infrastructure/repository/repository.dart';
import '../bloc/holidays_state.dart'; import '../bloc/holidays_state.dart';
import '../data_provider/holidays_get_holidays.dart';
class HolidaysRepository extends Repository<HolidaysState> { class HolidaysRepository extends Repository<HolidaysState> {
Future<List<Holiday>> getHolidays() => HolidaysGetHolidays().run(); Future<List<McHoliday>> getHolidays() => GetHolidays().run();
} }
+36 -34
View File
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:jiffy/jiffy.dart';
import '../../../api/marianumconnect/models/mc_holiday.dart';
import '../../../extensions/date_time.dart';
import '../../../state/app/infrastructure/loadable_state/loadable_state.dart'; import '../../../state/app/infrastructure/loadable_state/loadable_state.dart';
import '../../../state/app/infrastructure/loadable_state/view/loadable_state_consumer.dart'; import '../../../state/app/infrastructure/loadable_state/view/loadable_state_consumer.dart';
import '../../../state/app/infrastructure/utility_widgets/bloc_module.dart'; import '../../../state/app/infrastructure/utility_widgets/bloc_module.dart';
@@ -13,7 +14,7 @@ import '../../../widget/debug/debug_tile.dart';
import '../../../widget/details_bottom_sheet.dart'; import '../../../widget/details_bottom_sheet.dart';
import '../../../widget/info_dialog.dart'; import '../../../widget/info_dialog.dart';
import '../../../widget/list_view_util.dart'; import '../../../widget/list_view_util.dart';
import '../../../widget/string_extensions.dart'; import '../../../widget/placeholder_view.dart';
class HolidaysView extends StatelessWidget { class HolidaysView extends StatelessWidget {
const HolidaysView({super.key}); const HolidaysView({super.key});
@@ -28,14 +29,13 @@ class HolidaysView extends StatelessWidget {
void showDisclaimer() => InfoDialog.show( void showDisclaimer() => InfoDialog.show(
context, context,
'Sämtliche Datumsangaben sind ohne Gewähr.\n' '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' '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.',
'Die Daten stammen von https://ferien-api.de/', title: 'Richtigkeit der Daten',
title: 'Richtigkeit und Bereitstellung der Daten',
); );
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: const Text('Schulferien in Hessen'), title: const Text('Schulferien'),
actions: [ actions: [
IconButton( IconButton(
icon: const Icon(Icons.info_outline), icon: const Icon(Icons.info_outline),
@@ -73,34 +73,38 @@ class HolidaysView extends StatelessWidget {
if (state.showDisclaimer) showDisclaimer(); if (state.showDisclaimer) showDisclaimer();
bloc.add(DisclaimerDismissed()); bloc.add(DisclaimerDismissed());
}, },
child: (state, loading) => ListViewUtil.fromList<Holiday>( child: (state, loading) {
bloc.getHolidays(), final holidays = bloc.getHolidays();
if (holidays == null || holidays.isEmpty) {
return const PlaceholderView(
icon: Icons.beach_access_outlined,
text: 'Keine Schulferien verfügbar',
);
}
return ListViewUtil.fromList<McHoliday>(
holidays,
(holiday) { (holiday) {
var holidayType = holiday.name.split(' ').first.capitalize(); String holidayYear() {
String formatDate(String date) => final startYear = holiday.startDate.year;
Jiffy.parse(date).format(pattern: 'dd.MM.yyyy'); final endYear = holiday.endDate.year;
String getYear(String date, {String format = 'yyyy'}) => if (startYear == endYear) return '$startYear';
Jiffy.parse(date).format(pattern: format); return '$startYear/${endYear % 100}';
}
String getHolidayYear(String startDate, String endDate) =>
getYear(startDate) == getYear(endDate)
? getYear(startDate)
: '${getYear(startDate)}/${getYear(endDate, format: 'yy')}';
return ListTile( return ListTile(
leading: const CenteredLeading(Icon(Icons.calendar_month)), leading: const CenteredLeading(Icon(Icons.calendar_month)),
title: Text( title: Text(
'$holidayType ${getHolidayYear(holiday.start, holiday.end)}', '${holiday.longName} ${holidayYear()}',
), ),
subtitle: Text( subtitle: Text(
'${formatDate(holiday.start)} - ${formatDate(holiday.end)}', '${holiday.startDate.formatDate()} - ${holiday.endDate.formatDate()}',
), ),
onTap: () => showDetailsBottomSheet( onTap: () => showDetailsBottomSheet(
context, context,
header: Padding( header: Padding(
padding: const EdgeInsets.fromLTRB(16, 4, 16, 12), padding: const EdgeInsets.fromLTRB(16, 4, 16, 12),
child: Text( child: Text(
'$holidayType ${holiday.year} in Hessen', '${holiday.longName} ${holidayYear()}',
style: Theme.of(context).textTheme.titleLarge, style: Theme.of(context).textTheme.titleLarge,
), ),
), ),
@@ -109,25 +113,23 @@ class HolidaysView extends StatelessWidget {
leading: const CenteredLeading( leading: const CenteredLeading(
Icon(Icons.signpost_outlined), Icon(Icons.signpost_outlined),
), ),
title: Text(holiday.name.capitalize()), title: Text(holiday.longName),
subtitle: Text(holiday.slug.capitalize()), subtitle: Text(holiday.shortName),
), ),
ListTile( ListTile(
leading: const Icon(Icons.date_range_outlined), leading: const Icon(Icons.date_range_outlined),
title: Text('vom ${formatDate(holiday.start)}'), title: Text('vom ${holiday.startDate.formatDate()}'),
), ),
ListTile( ListTile(
leading: const Icon(Icons.date_range_outlined), leading: const Icon(Icons.date_range_outlined),
title: Text('bis zum ${formatDate(holiday.end)}'), title: Text('bis zum ${holiday.endDate.formatDate()}'),
), ),
if (DateTime.parse( if (holiday.startDate.difference(DateTime.now()).isNegative)
holiday.start,
).difference(DateTime.now()).isNegative)
ListTile( ListTile(
leading: const CenteredLeading( leading: const CenteredLeading(
Icon(Icons.content_paste_search_outlined), Icon(Icons.content_paste_search_outlined),
), ),
title: Text(Jiffy.parse(holiday.start).fromNow()), title: Text(holiday.startDate.formatRelative()),
) )
else else
ListTile( ListTile(
@@ -135,11 +137,10 @@ class HolidaysView extends StatelessWidget {
Icon(Icons.timer_outlined), Icon(Icons.timer_outlined),
), ),
title: AnimatedTime( title: AnimatedTime(
callback: () => DateTime.parse( callback: () =>
holiday.start, holiday.startDate.difference(DateTime.now()),
).difference(DateTime.now()),
), ),
subtitle: Text(Jiffy.parse(holiday.start).fromNow()), subtitle: Text(holiday.startDate.formatRelative()),
), ),
DebugTile(sheetCtx).jsonData(holiday.toJson()), DebugTile(sheetCtx).jsonData(holiday.toJson()),
], ],
@@ -147,7 +148,8 @@ class HolidaysView extends StatelessWidget {
trailing: const Icon(Icons.arrow_right), trailing: const Icon(Icons.arrow_right),
); );
}, },
), );
},
), ),
); );
}, },
+12 -6
View File
@@ -12,14 +12,18 @@ class PlaceholderView extends StatelessWidget {
}); });
@override @override
Widget build(BuildContext context) => Scaffold( Widget build(BuildContext context) => CustomScrollView(
body: Center( physics: const AlwaysScrollableScrollPhysics(),
child: Container( slivers: [
margin: const EdgeInsets.only(top: 100, left: 20, right: 20), SliverFillRemaining(
child: Center(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min,
children: [ children: [
Container( Padding(
margin: const EdgeInsets.all(30), padding: const EdgeInsets.all(30),
child: Icon(icon, size: 60), child: Icon(icon, size: 60),
), ),
Text( Text(
@@ -33,5 +37,7 @@ class PlaceholderView extends StatelessWidget {
), ),
), ),
), ),
),
],
); );
} }