migrated Marianum Message module to the Marianum-Connect API and implemented push notification deep linking

This commit is contained in:
2026-07-11 17:37:50 +02:00
parent ff23199345
commit c444ed54a5
13 changed files with 237 additions and 78 deletions
@@ -27,8 +27,10 @@ abstract class MarianumMessageList with _$MarianumMessageList {
@freezed
abstract class MarianumMessage with _$MarianumMessage {
const factory MarianumMessage({
@Default('') String id,
required String name,
required String date,
@Default('') String description,
required String url,
}) = _MarianumMessage;
@@ -568,7 +568,7 @@ as List<MarianumMessage>,
/// @nodoc
mixin _$MarianumMessage {
String get name; String get date; String get url;
String get id; String get name; String get date; String get description; String get url;
/// Create a copy of MarianumMessage
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@@ -581,16 +581,16 @@ $MarianumMessageCopyWith<MarianumMessage> get copyWith => _$MarianumMessageCopyW
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is MarianumMessage&&(identical(other.name, name) || other.name == name)&&(identical(other.date, date) || other.date == date)&&(identical(other.url, url) || other.url == url));
return identical(this, other) || (other.runtimeType == runtimeType&&other is MarianumMessage&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.date, date) || other.date == date)&&(identical(other.description, description) || other.description == description)&&(identical(other.url, url) || other.url == url));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,name,date,url);
int get hashCode => Object.hash(runtimeType,id,name,date,description,url);
@override
String toString() {
return 'MarianumMessage(name: $name, date: $date, url: $url)';
return 'MarianumMessage(id: $id, name: $name, date: $date, description: $description, url: $url)';
}
@@ -601,7 +601,7 @@ abstract mixin class $MarianumMessageCopyWith<$Res> {
factory $MarianumMessageCopyWith(MarianumMessage value, $Res Function(MarianumMessage) _then) = _$MarianumMessageCopyWithImpl;
@useResult
$Res call({
String name, String date, String url
String id, String name, String date, String description, String url
});
@@ -618,10 +618,12 @@ class _$MarianumMessageCopyWithImpl<$Res>
/// Create a copy of MarianumMessage
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? name = null,Object? date = null,Object? url = null,}) {
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? name = null,Object? date = null,Object? description = null,Object? url = null,}) {
return _then(_self.copyWith(
name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
as String,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
as String,date: null == date ? _self.date : date // ignore: cast_nullable_to_non_nullable
as String,description: null == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
as String,url: null == url ? _self.url : url // ignore: cast_nullable_to_non_nullable
as String,
));
@@ -708,10 +710,10 @@ return $default(_that);case _:
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String name, String date, String url)? $default,{required TResult orElse(),}) {final _that = this;
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String name, String date, String description, String url)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _MarianumMessage() when $default != null:
return $default(_that.name,_that.date,_that.url);case _:
return $default(_that.id,_that.name,_that.date,_that.description,_that.url);case _:
return orElse();
}
@@ -729,10 +731,10 @@ return $default(_that.name,_that.date,_that.url);case _:
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String name, String date, String url) $default,) {final _that = this;
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String name, String date, String description, String url) $default,) {final _that = this;
switch (_that) {
case _MarianumMessage():
return $default(_that.name,_that.date,_that.url);case _:
return $default(_that.id,_that.name,_that.date,_that.description,_that.url);case _:
throw StateError('Unexpected subclass');
}
@@ -749,10 +751,10 @@ return $default(_that.name,_that.date,_that.url);case _:
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String name, String date, String url)? $default,) {final _that = this;
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String name, String date, String description, String url)? $default,) {final _that = this;
switch (_that) {
case _MarianumMessage() when $default != null:
return $default(_that.name,_that.date,_that.url);case _:
return $default(_that.id,_that.name,_that.date,_that.description,_that.url);case _:
return null;
}
@@ -764,11 +766,13 @@ return $default(_that.name,_that.date,_that.url);case _:
@JsonSerializable()
class _MarianumMessage implements MarianumMessage {
const _MarianumMessage({required this.name, required this.date, required this.url});
const _MarianumMessage({this.id = '', required this.name, required this.date, this.description = '', required this.url});
factory _MarianumMessage.fromJson(Map<String, dynamic> json) => _$MarianumMessageFromJson(json);
@override@JsonKey() final String id;
@override final String name;
@override final String date;
@override@JsonKey() final String description;
@override final String url;
/// Create a copy of MarianumMessage
@@ -784,16 +788,16 @@ Map<String, dynamic> toJson() {
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _MarianumMessage&&(identical(other.name, name) || other.name == name)&&(identical(other.date, date) || other.date == date)&&(identical(other.url, url) || other.url == url));
return identical(this, other) || (other.runtimeType == runtimeType&&other is _MarianumMessage&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.date, date) || other.date == date)&&(identical(other.description, description) || other.description == description)&&(identical(other.url, url) || other.url == url));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,name,date,url);
int get hashCode => Object.hash(runtimeType,id,name,date,description,url);
@override
String toString() {
return 'MarianumMessage(name: $name, date: $date, url: $url)';
return 'MarianumMessage(id: $id, name: $name, date: $date, description: $description, url: $url)';
}
@@ -804,7 +808,7 @@ abstract mixin class _$MarianumMessageCopyWith<$Res> implements $MarianumMessage
factory _$MarianumMessageCopyWith(_MarianumMessage value, $Res Function(_MarianumMessage) _then) = __$MarianumMessageCopyWithImpl;
@override @useResult
$Res call({
String name, String date, String url
String id, String name, String date, String description, String url
});
@@ -821,10 +825,12 @@ class __$MarianumMessageCopyWithImpl<$Res>
/// Create a copy of MarianumMessage
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? name = null,Object? date = null,Object? url = null,}) {
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? name = null,Object? date = null,Object? description = null,Object? url = null,}) {
return _then(_MarianumMessage(
name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
as String,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
as String,date: null == date ? _self.date : date // ignore: cast_nullable_to_non_nullable
as String,description: null == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
as String,url: null == url ? _self.url : url // ignore: cast_nullable_to_non_nullable
as String,
));
@@ -32,14 +32,18 @@ Map<String, dynamic> _$MarianumMessageListToJson(
_MarianumMessage _$MarianumMessageFromJson(Map<String, dynamic> json) =>
_MarianumMessage(
id: json['id'] as String? ?? '',
name: json['name'] as String,
date: json['date'] as String,
description: json['description'] as String? ?? '',
url: json['url'] as String,
);
Map<String, dynamic> _$MarianumMessageToJson(_MarianumMessage instance) =>
<String, dynamic>{
'id': instance.id,
'name': instance.name,
'date': instance.date,
'description': instance.description,
'url': instance.url,
};
@@ -1,13 +1,53 @@
import 'package:dio/dio.dart';
import 'package:intl/intl.dart';
import '../../../basis/dataloader/mhsl_data_loader.dart';
import '../../../infrastructure/data_loader/data_loader.dart';
import '../../../../../api/marianumconnect/errors/marianumconnect_error.dart';
import '../../../../../api/marianumconnect/marianumconnect_api.dart';
import '../../../../../api/marianumconnect/marianumconnect_endpoint.dart';
import '../bloc/marianum_message_state.dart';
class MarianumMessageGetMessages extends MhslDataLoader<MarianumMessageList> {
@override
Future<Response<String>> fetch() async => dio.get('/message/messages.json');
@override
MarianumMessageList assemble(DataLoaderResult data) =>
MarianumMessageList.fromJson(data.asMap());
/// Loads the "Marianum Message" list from `GET /api/mobile/v1/newsletter`
/// (formerly the mhsl.eu `message/messages.json` endpoint). Bearer token is
/// attached by the shared Marianum-Connect dio.
class MarianumMessageGetMessages {
final Dio _dio;
MarianumMessageGetMessages({Dio? dio}) : _dio = dio ?? MarianumConnectApi.dio();
Future<MarianumMessageList> run() async {
try {
final response = await _dio.get<List<dynamic>>(
MarianumConnectEndpoint.resolve('newsletter'),
);
final messages = (response.data ?? const [])
.cast<Map<String, dynamic>>()
.map(_mapItem)
.toList();
return MarianumMessageList(
base: MarianumConnectEndpoint.current(),
messages: messages,
);
} on DioException catch (e) {
throw mapMarianumConnectError(e);
}
}
MarianumMessage _mapItem(Map<String, dynamic> map) => MarianumMessage(
id: map['id'] as String,
name: map['title'] as String? ?? '',
date: _formatDate(map['date'] as String?),
description: map['description'] as String? ?? '',
url: map['fileUrl'] as String? ?? '',
);
static final DateFormat _monthYear = DateFormat.yMMMM('de');
/// Server sends ISO `yyyy-MM-dd`; the list shows only the German month + year
/// (e.g. "April 2024").
static String _formatDate(String? iso) {
if (iso == null || iso.isEmpty) return '';
final parsed = DateTime.tryParse(iso);
if (parsed == null) return iso;
return _monthYear.format(parsed);
}
}