Added Marianum Message pdf reader and backend

This commit is contained in:
Elias Müller 2023-05-30 21:08:11 +02:00
parent ba90556e69
commit d71f0d3339
16 changed files with 343 additions and 12 deletions

@ -275,6 +275,20 @@
</list>
</value>
</entry>
<entry key="device_info_plus">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dev/device_info_plus-8.2.2/lib" />
</list>
</value>
</entry>
<entry key="device_info_plus_platform_interface">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dev/device_info_plus_platform_interface-7.0.0/lib" />
</list>
</value>
</entry>
<entry key="dio">
<value>
<list>
@ -957,7 +971,7 @@
<entry key="syncfusion_flutter_core">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-21.2.5/lib" />
<option value="$USER_HOME$/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-21.2.8/lib" />
</list>
</value>
</entry>
@ -968,6 +982,48 @@
</list>
</value>
</entry>
<entry key="syncfusion_flutter_pdf">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dev/syncfusion_flutter_pdf-21.2.8/lib" />
</list>
</value>
</entry>
<entry key="syncfusion_flutter_pdfviewer">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dev/syncfusion_flutter_pdfviewer-21.2.8/lib" />
</list>
</value>
</entry>
<entry key="syncfusion_pdfviewer_macos">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dev/syncfusion_pdfviewer_macos-21.2.8/lib" />
</list>
</value>
</entry>
<entry key="syncfusion_pdfviewer_platform_interface">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dev/syncfusion_pdfviewer_platform_interface-21.2.8/lib" />
</list>
</value>
</entry>
<entry key="syncfusion_pdfviewer_web">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dev/syncfusion_pdfviewer_web-21.2.8/lib" />
</list>
</value>
</entry>
<entry key="syncfusion_pdfviewer_windows">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dev/syncfusion_pdfviewer_windows-21.2.8/lib" />
</list>
</value>
</entry>
<entry key="synchronized">
<value>
<list>
@ -1195,6 +1251,8 @@
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/csslib-0.17.2/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/cupertino_icons-1.0.5/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/dart_style-2.3.1/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/device_info_plus-8.2.2/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/device_info_plus_platform_interface-7.0.0/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/dio-4.0.6/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/fake_async-1.3.1/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/ffi-2.0.2/lib" />
@ -1284,8 +1342,14 @@
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/stream_transform-2.1.0/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/string_scanner-1.2.0/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/syncfusion_flutter_calendar-21.2.5/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-21.2.5/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-21.2.8/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/syncfusion_flutter_datepicker-21.2.5/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/syncfusion_flutter_pdf-21.2.8/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/syncfusion_flutter_pdfviewer-21.2.8/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/syncfusion_pdfviewer_macos-21.2.8/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/syncfusion_pdfviewer_platform_interface-21.2.8/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/syncfusion_pdfviewer_web-21.2.8/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/syncfusion_pdfviewer_windows-21.2.8/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/synchronized-3.1.0/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/term_glyph-1.2.1/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/test_api-0.5.1/lib" />

@ -28,6 +28,9 @@
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.7+4" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/file_picker-5.3.0" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.6" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/device_info_plus-8.2.2" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/syncfusion_pdfviewer_web-21.2.8" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/syncfusion_flutter_pdfviewer-21.2.8" />
</CLASSES>
<JAVADOC />
<SOURCES />

@ -0,0 +1,18 @@
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:marianum_mobile/api/mhsl/message/getMessages/getMessagesResponse.dart';
import 'package:marianum_mobile/api/mhsl/message/messageApi.dart';
class GetMessages extends MessageApi<GetMessagesResponse> {
@override
GetMessagesResponse assemble(String raw) {
return GetMessagesResponse.fromJson(jsonDecode(raw));
}
@override
Future<http.Response> request(Uri uri) {
return http.get(uri);
}
}

@ -0,0 +1,22 @@
import 'dart:convert';
import 'package:marianum_mobile/api/mhsl/message/getMessages/getMessagesResponse.dart';
import 'package:marianum_mobile/api/requestCache.dart';
import 'getMessages.dart';
class GetMessagesCache extends RequestCache<GetMessagesResponse> {
GetMessagesCache({onUpdate, renew}) : super(RequestCache.cacheMinute, onUpdate, renew: renew) {
start("MarianumMobile", "message");
}
@override
GetMessagesResponse onLocalData(String json) {
return GetMessagesResponse.fromJson(jsonDecode(json));
}
@override
Future<GetMessagesResponse> onLoad() {
return GetMessages().run();
}
}

@ -0,0 +1,27 @@
import 'package:json_annotation/json_annotation.dart';
import 'package:marianum_mobile/api/apiResponse.dart';
part 'getMessagesResponse.g.dart';
@JsonSerializable(explicitToJson: true)
class GetMessagesResponse extends ApiResponse {
String base;
Set<GetMessagesResponseObject> messages;
GetMessagesResponse(this.base, this.messages);
factory GetMessagesResponse.fromJson(Map<String, dynamic> json) => _$GetMessagesResponseFromJson(json);
Map<String, dynamic> toJson() => _$GetMessagesResponseToJson(this);
}
@JsonSerializable(explicitToJson: true)
class GetMessagesResponseObject {
String name;
String date;
String url;
GetMessagesResponseObject(this.name, this.date, this.url);
factory GetMessagesResponseObject.fromJson(Map<String, dynamic> json) => _$GetMessagesResponseObjectFromJson(json);
Map<String, dynamic> toJson() => _$GetMessagesResponseObjectToJson(this);
}

@ -0,0 +1,39 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'getMessagesResponse.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
GetMessagesResponse _$GetMessagesResponseFromJson(Map<String, dynamic> json) =>
GetMessagesResponse(
json['base'] as String,
(json['messages'] as List<dynamic>)
.map((e) =>
GetMessagesResponseObject.fromJson(e as Map<String, dynamic>))
.toSet(),
);
Map<String, dynamic> _$GetMessagesResponseToJson(
GetMessagesResponse instance) =>
<String, dynamic>{
'base': instance.base,
'messages': instance.messages.map((e) => e.toJson()).toList(),
};
GetMessagesResponseObject _$GetMessagesResponseObjectFromJson(
Map<String, dynamic> json) =>
GetMessagesResponseObject(
json['name'] as String,
json['date'] as String,
json['url'] as String,
);
Map<String, dynamic> _$GetMessagesResponseObjectToJson(
GetMessagesResponseObject instance) =>
<String, dynamic>{
'name': instance.name,
'date': instance.date,
'url': instance.url,
};

@ -0,0 +1,22 @@
import 'package:http/http.dart' as http;
import '../../apiError.dart';
import '../../apiRequest.dart';
abstract class MessageApi<T> extends ApiRequest {
String path = "https://mhsl.eu/marianum/marianummobile/message/messages.json";
http.Response? response;
Future<http.Response>? request(Uri uri);
T assemble(String raw);
Future<T> run() async {
Uri endpoint = Uri.parse(path);
http.Response? data = await request(endpoint);
if(data == null) {
throw ApiError("Request could not be dispatched!");
}
return assemble(data.body);
}
}

@ -49,11 +49,11 @@ class _AppState extends State<App> {
border: Border.symmetric(vertical: BorderSide.none, horizontal: BorderSide(color: Colors.grey, width: 1))
),
screenTransitionAnimation: const ScreenTransitionAnimation(animateTabTransition: true, curve: Curves.ease, duration: Duration(milliseconds: 200)),
screens: [
const Timetable(),
const ChatList(),
Files(const []),
const Overhang(),
screens: const [
Timetable(),
ChatList(),
Files([]),
Overhang(),
],
items: [
PersistentBottomNavBarItem(

@ -0,0 +1,28 @@
import 'package:marianum_mobile/api/mhsl/message/getMessages/getMessagesCache.dart';
import 'package:marianum_mobile/api/mhsl/message/getMessages/getMessagesResponse.dart';
import 'package:marianum_mobile/data/dataHolder.dart';
import '../../api/apiResponse.dart';
class MessageProps extends DataHolder {
GetMessagesResponse? _getMessagesResponse;
GetMessagesResponse get getMessagesResponse => _getMessagesResponse!;
@override
List<ApiResponse?> properties() {
return [_getMessagesResponse];
}
@override
void run({renew}) {
GetMessagesCache(
renew: renew,
onUpdate: (GetMessagesResponse data) => {
_getMessagesResponse = data,
notifyListeners(),
}
);
}
}

@ -18,6 +18,7 @@ import 'data/chatList/chatListProps.dart';
import 'data/chatList/chatProps.dart';
import 'data/accountModel.dart';
import 'data/files/filesProps.dart';
import 'data/message/messageProps.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
@ -38,6 +39,8 @@ Future<void> main() async {
ChangeNotifierProvider(create: (context) => ChatListProps()),
ChangeNotifierProvider(create: (context) => ChatProps()),
ChangeNotifierProvider(create: (context) => FilesProps()),
ChangeNotifierProvider(create: (context) => MessageProps()),
],
child: const Main(),
)

@ -1,5 +1,10 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:marianum_mobile/api/mhsl/message/getMessages/getMessagesResponse.dart';
import 'package:marianum_mobile/screen/pages/more/message/messageView.dart';
import 'package:provider/provider.dart';
import '../../../../data/message/messageProps.dart';
class Message extends StatefulWidget {
const Message({Key? key}) : super(key: key);
@ -9,17 +14,46 @@ class Message extends StatefulWidget {
}
class _MessageState extends State<Message> {
@override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
Provider.of<MessageProps>(context, listen: false).run();
});
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Marianum Message"),
),
body: ListView.builder(itemBuilder: (context, index) {
return ListTile(
leading: const Icon(Icons.newspaper),
title: Text(index.toString()),
trailing: const Icon(Icons.arrow_right),
body: Consumer<MessageProps>(builder: (context, value, child) {
if(value.primaryLoading()) return const Center(child: CircularProgressIndicator());
return RefreshIndicator(
child: ListView.builder(
itemCount: value.getMessagesResponse.messages.length,
itemBuilder: (context, index) {
GetMessagesResponseObject message = value.getMessagesResponse.messages.toList()[index];
return ListTile(
leading: const Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [Icon(Icons.newspaper)],
),
title: Text(message.name, overflow: TextOverflow.ellipsis),
subtitle: Text("vom ${message.date}"),
trailing: const Icon(Icons.arrow_right),
onTap: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => MessageView(basePath: value.getMessagesResponse.base, message: message)));
},
);
}
),
onRefresh: () {
Provider.of<MessageProps>(context, listen: false).run(renew: true);
return Future.delayed(const Duration(seconds: 3));
},
);
}),
);

@ -0,0 +1,62 @@
import 'package:flutter/material.dart';
import 'package:marianum_mobile/api/mhsl/message/getMessages/getMessagesResponse.dart';
import 'package:syncfusion_flutter_pdfviewer/pdfviewer.dart';
import 'package:url_launcher/url_launcher.dart';
class MessageView extends StatefulWidget {
final String basePath;
final GetMessagesResponseObject message;
const MessageView({Key? key, required this.basePath, required this.message}) : super(key: key);
@override
State<MessageView> createState() => _MessageViewState();
}
class _MessageViewState extends State<MessageView> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.message.name),
),
body: SfPdfViewer.network(
widget.basePath + widget.message.url,
enableHyperlinkNavigation: true,
onDocumentLoadFailed: (PdfDocumentLoadFailedDetails e) {
Navigator.of(context).pop();
showDialog(context: context, builder: (context) {
return AlertDialog(
title: const Text("Fehler beim öffnen"),
content: Text("Dokument '${widget.message.name}' konnte nicht geladen werden:\n${e.description}"),
actions: [
TextButton(onPressed: () {
Navigator.of(context).pop();
}, child: const Text("Ok"))
],
);
});
},
onHyperlinkClicked: (PdfHyperlinkClickedDetails e) {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: const Text("Link öffnen"),
content: Text("Möchtest du den folgenden Link öffnen?\n${e.uri}"),
actions: [
TextButton(onPressed: () {
Navigator.of(context).pop();
}, child: const Text("Abbrechen")),
TextButton(onPressed: () {
launchUrl(Uri.parse(e.uri), mode: LaunchMode.externalApplication);
}, child: const Text("Öffnen")),
],
);
},
);
},
),
);
}
}

@ -5,16 +5,20 @@
import FlutterMacOS
import Foundation
import device_info_plus
import package_info
import path_provider_foundation
import shared_preferences_foundation
import sqflite
import syncfusion_pdfviewer_macos
import url_launcher_macos
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
FLTPackageInfoPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
SyncfusionFlutterPdfViewerPlugin.register(with: registry.registrar(forPlugin: "SyncfusionFlutterPdfViewerPlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
}

@ -79,6 +79,7 @@ dependencies:
syncfusion_flutter_calendar: ^21.2.4
async: ^2.11.0
animated_digit: ^3.2.1
syncfusion_flutter_pdfviewer: ^21.2.8
dev_dependencies:
flutter_test:

@ -6,9 +6,12 @@
#include "generated_plugin_registrant.h"
#include <syncfusion_pdfviewer_windows/syncfusion_pdfviewer_windows_plugin.h>
#include <url_launcher_windows/url_launcher_windows.h>
void RegisterPlugins(flutter::PluginRegistry* registry) {
SyncfusionPdfviewerWindowsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("SyncfusionPdfviewerWindowsPlugin"));
UrlLauncherWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
}

@ -3,6 +3,7 @@
#
list(APPEND FLUTTER_PLUGIN_LIST
syncfusion_pdfviewer_windows
url_launcher_windows
)