dart format
This commit is contained in:
@@ -1,3 +1 @@
|
||||
class ApiParams {
|
||||
|
||||
}
|
||||
class ApiParams {}
|
||||
|
||||
@@ -1,5 +1 @@
|
||||
|
||||
|
||||
class ApiRequest {
|
||||
|
||||
}
|
||||
class ApiRequest {}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
abstract class ApiResponse {
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
late http.Response rawResponse;
|
||||
|
||||
@@ -9,15 +9,16 @@ class AuthException extends AppException {
|
||||
super.technicalDetails,
|
||||
}) : super(allowRetry: false);
|
||||
|
||||
factory AuthException.unauthorized({String? technicalDetails}) => AuthException(
|
||||
factory AuthException.unauthorized({String? technicalDetails}) =>
|
||||
AuthException(
|
||||
statusCode: 401,
|
||||
userMessage: 'Bitte melde dich erneut an, um fortzufahren.',
|
||||
technicalDetails: technicalDetails,
|
||||
);
|
||||
|
||||
factory AuthException.forbidden({String? technicalDetails}) => AuthException(
|
||||
statusCode: 403,
|
||||
userMessage: 'Du hast keine Berechtigung für diese Aktion.',
|
||||
technicalDetails: technicalDetails,
|
||||
);
|
||||
statusCode: 403,
|
||||
userMessage: 'Du hast keine Berechtigung für diese Aktion.',
|
||||
technicalDetails: technicalDetails,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -14,7 +14,8 @@ import 'server_exception.dart';
|
||||
import 'talk_exception.dart';
|
||||
import 'webuntis_exception.dart';
|
||||
|
||||
const String _defaultFallback = 'Etwas ist schiefgelaufen. Bitte versuche es erneut.';
|
||||
const String _defaultFallback =
|
||||
'Etwas ist schiefgelaufen. Bitte versuche es erneut.';
|
||||
const String _tlsErrorMessage =
|
||||
'Die sichere Verbindung zum Server wurde abgelehnt (Zertifikat oder TLS-Fehler). '
|
||||
'Häufige Ursachen: falsche Geräte-Uhrzeit oder ein WLAN mit Anmeldeseite (z.B. Café/Hotel).';
|
||||
@@ -28,9 +29,7 @@ AppException? _dioToAppException(DioException error) {
|
||||
case DioExceptionType.connectionError:
|
||||
return NetworkException(technicalDetails: error.message);
|
||||
case DioExceptionType.badCertificate:
|
||||
return const NetworkException(
|
||||
userMessage: _tlsErrorMessage,
|
||||
);
|
||||
return const NetworkException(userMessage: _tlsErrorMessage);
|
||||
case DioExceptionType.badResponse:
|
||||
final status = error.response?.statusCode;
|
||||
return ServerException(
|
||||
@@ -40,13 +39,15 @@ AppException? _dioToAppException(DioException error) {
|
||||
case DioExceptionType.cancel:
|
||||
case DioExceptionType.unknown:
|
||||
final inner = error.error;
|
||||
if (inner is SocketException) return NetworkException(technicalDetails: inner.message);
|
||||
if (inner is HandshakeException) {
|
||||
return const NetworkException(
|
||||
userMessage: _tlsErrorMessage,
|
||||
);
|
||||
if (inner is SocketException) {
|
||||
return NetworkException(technicalDetails: inner.message);
|
||||
}
|
||||
if (inner is HandshakeException) {
|
||||
return const NetworkException(userMessage: _tlsErrorMessage);
|
||||
}
|
||||
if (inner is FormatException) {
|
||||
return ParseException(technicalDetails: inner.message);
|
||||
}
|
||||
if (inner is FormatException) return ParseException(technicalDetails: inner.message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,15 @@ import 'app_exception.dart';
|
||||
|
||||
class NetworkException extends AppException {
|
||||
const NetworkException({
|
||||
super.userMessage = 'Keine Internetverbindung. Bitte prüfe dein Netzwerk und versuche es erneut.',
|
||||
super.userMessage =
|
||||
'Keine Internetverbindung. Bitte prüfe dein Netzwerk und versuche es erneut.',
|
||||
super.technicalDetails,
|
||||
}) : super(allowRetry: true);
|
||||
|
||||
factory NetworkException.timeout({String? technicalDetails}) => NetworkException(
|
||||
userMessage: 'Der Server hat zu lange gebraucht. Bitte versuche es erneut.',
|
||||
factory NetworkException.timeout({String? technicalDetails}) =>
|
||||
NetworkException(
|
||||
userMessage:
|
||||
'Der Server hat zu lange gebraucht. Bitte versuche es erneut.',
|
||||
technicalDetails: technicalDetails,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,9 @@ class ServerException extends AppException {
|
||||
String? userMessage,
|
||||
super.technicalDetails,
|
||||
}) : super(
|
||||
userMessage: userMessage ?? 'Der Server hat gerade Probleme (Status $statusCode). Bitte später erneut versuchen.',
|
||||
allowRetry: true,
|
||||
);
|
||||
userMessage:
|
||||
userMessage ??
|
||||
'Der Server hat gerade Probleme (Status $statusCode). Bitte später erneut versuchen.',
|
||||
allowRetry: true,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,11 +5,12 @@ class TalkException extends AppException {
|
||||
final TalkError source;
|
||||
|
||||
TalkException(this.source)
|
||||
: super(
|
||||
userMessage: _mapMessage(source),
|
||||
technicalDetails: 'Talk ${source.status} (${source.code}): ${source.message}',
|
||||
allowRetry: source.code >= 500,
|
||||
);
|
||||
: super(
|
||||
userMessage: _mapMessage(source),
|
||||
technicalDetails:
|
||||
'Talk ${source.status} (${source.code}): ${source.message}',
|
||||
allowRetry: source.code >= 500,
|
||||
);
|
||||
|
||||
static String _mapMessage(TalkError e) {
|
||||
switch (e.code) {
|
||||
@@ -27,7 +28,9 @@ class TalkException extends AppException {
|
||||
if (e.code >= 500) {
|
||||
return 'Talk-Server hat gerade Probleme (${e.code}).';
|
||||
}
|
||||
return e.message.isNotEmpty ? e.message : 'Talk meldet einen Fehler (${e.code}).';
|
||||
return e.message.isNotEmpty
|
||||
? e.message
|
||||
: 'Talk meldet einen Fehler (${e.code}).';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,11 +5,11 @@ class WebuntisException extends AppException {
|
||||
final WebuntisError source;
|
||||
|
||||
WebuntisException(this.source)
|
||||
: super(
|
||||
userMessage: _mapMessage(source),
|
||||
technicalDetails: 'WebUntis (${source.code}): ${source.message}',
|
||||
allowRetry: true,
|
||||
);
|
||||
: super(
|
||||
userMessage: _mapMessage(source),
|
||||
technicalDetails: 'WebUntis (${source.code}): ${source.message}',
|
||||
allowRetry: true,
|
||||
);
|
||||
|
||||
static String _mapMessage(WebuntisError e) {
|
||||
switch (e.code) {
|
||||
|
||||
@@ -20,9 +20,13 @@ class AutocompleteApi {
|
||||
);
|
||||
final response = await http.get(endpoint, headers: NextcloudOcs.headers());
|
||||
if (response.statusCode != HttpStatus.ok) {
|
||||
throw Exception('Api call failed with ${response.statusCode}: ${response.body}');
|
||||
throw Exception(
|
||||
'Api call failed with ${response.statusCode}: ${response.body}',
|
||||
);
|
||||
}
|
||||
final decoded = jsonDecode(response.body) as Map<String, dynamic>;
|
||||
return AutocompleteResponse.fromJson(decoded['ocs'] as Map<String, dynamic>);
|
||||
return AutocompleteResponse.fromJson(
|
||||
decoded['ocs'] as Map<String, dynamic>,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,8 @@ class AutocompleteResponse {
|
||||
|
||||
AutocompleteResponse(this.data);
|
||||
|
||||
factory AutocompleteResponse.fromJson(Map<String, dynamic> json) => _$AutocompleteResponseFromJson(json);
|
||||
factory AutocompleteResponse.fromJson(Map<String, dynamic> json) =>
|
||||
_$AutocompleteResponseFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$AutocompleteResponseToJson(this);
|
||||
}
|
||||
|
||||
@@ -22,9 +23,17 @@ class AutocompleteResponseObject {
|
||||
String? subline;
|
||||
String? shareWithDisplayNameUniqe;
|
||||
|
||||
AutocompleteResponseObject(this.id, this.label, this.icon, this.source, this.status,
|
||||
this.subline, this.shareWithDisplayNameUniqe);
|
||||
AutocompleteResponseObject(
|
||||
this.id,
|
||||
this.label,
|
||||
this.icon,
|
||||
this.source,
|
||||
this.status,
|
||||
this.subline,
|
||||
this.shareWithDisplayNameUniqe,
|
||||
);
|
||||
|
||||
factory AutocompleteResponseObject.fromJson(Map<String, dynamic> json) => _$AutocompleteResponseObjectFromJson(json);
|
||||
factory AutocompleteResponseObject.fromJson(Map<String, dynamic> json) =>
|
||||
_$AutocompleteResponseObjectFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$AutocompleteResponseObjectToJson(this);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,9 @@ class FileSharingApi {
|
||||
);
|
||||
final response = await http.post(endpoint, headers: NextcloudOcs.headers());
|
||||
if (response.statusCode != HttpStatus.ok) {
|
||||
throw Exception('Api call failed with ${response.statusCode}: ${response.body}');
|
||||
throw Exception(
|
||||
'Api call failed with ${response.statusCode}: ${response.body}',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,9 +15,10 @@ class FileSharingApiParams {
|
||||
required this.shareWith,
|
||||
required this.path,
|
||||
this.referenceId,
|
||||
this.talkMetaData
|
||||
this.talkMetaData,
|
||||
});
|
||||
|
||||
factory FileSharingApiParams.fromJson(Map<String, dynamic> json) => _$FileSharingApiParamsFromJson(json);
|
||||
factory FileSharingApiParams.fromJson(Map<String, dynamic> json) =>
|
||||
_$FileSharingApiParamsFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$FileSharingApiParamsToJson(this);
|
||||
}
|
||||
|
||||
@@ -7,10 +7,10 @@ class NextcloudOcs {
|
||||
NextcloudOcs._();
|
||||
|
||||
static Map<String, String> headers() => {
|
||||
'Accept': 'application/json',
|
||||
'OCS-APIRequest': 'true',
|
||||
'Authorization': AccountData().getBasicAuthHeader(),
|
||||
};
|
||||
'Accept': 'application/json',
|
||||
'OCS-APIRequest': 'true',
|
||||
'Authorization': AccountData().getBasicAuthHeader(),
|
||||
};
|
||||
|
||||
static Uri uri(String pathSuffix, {Map<String, dynamic>? queryParameters}) {
|
||||
final endpoint = EndpointData().nextcloud();
|
||||
|
||||
@@ -12,39 +12,53 @@ class SetFavorite extends TalkApi {
|
||||
final String chatToken;
|
||||
final bool favoriteState;
|
||||
|
||||
SetFavorite(this.chatToken, this.favoriteState) : super('v4/room/$chatToken/favorite', null);
|
||||
SetFavorite(this.chatToken, this.favoriteState)
|
||||
: super('v4/room/$chatToken/favorite', null);
|
||||
|
||||
@override
|
||||
ApiResponse? assemble(String raw) => null;
|
||||
|
||||
@override
|
||||
Future<http.Response> request(Uri uri, ApiParams? body, Map<String, String>? headers) =>
|
||||
favoriteState ? http.post(uri, headers: headers) : http.delete(uri, headers: headers);
|
||||
Future<http.Response> request(
|
||||
Uri uri,
|
||||
ApiParams? body,
|
||||
Map<String, String>? headers,
|
||||
) => favoriteState
|
||||
? http.post(uri, headers: headers)
|
||||
: http.delete(uri, headers: headers);
|
||||
}
|
||||
|
||||
class LeaveRoom extends TalkApi {
|
||||
final String chatToken;
|
||||
|
||||
LeaveRoom(this.chatToken) : super('v4/room/$chatToken/participants/self', null);
|
||||
LeaveRoom(this.chatToken)
|
||||
: super('v4/room/$chatToken/participants/self', null);
|
||||
|
||||
@override
|
||||
ApiResponse? assemble(String raw) => null;
|
||||
|
||||
@override
|
||||
Future<http.Response> request(Uri uri, ApiParams? body, Map<String, String>? headers) =>
|
||||
http.delete(uri, headers: headers);
|
||||
Future<http.Response> request(
|
||||
Uri uri,
|
||||
ApiParams? body,
|
||||
Map<String, String>? headers,
|
||||
) => http.delete(uri, headers: headers);
|
||||
}
|
||||
|
||||
class DeleteMessage extends TalkApi {
|
||||
final String chatToken;
|
||||
final int messageId;
|
||||
|
||||
DeleteMessage(this.chatToken, this.messageId) : super('v1/chat/$chatToken/$messageId', null);
|
||||
DeleteMessage(this.chatToken, this.messageId)
|
||||
: super('v1/chat/$chatToken/$messageId', null);
|
||||
|
||||
@override
|
||||
ApiResponse? assemble(String raw) => null;
|
||||
|
||||
@override
|
||||
Future<http.Response> request(Uri uri, ApiParams? body, Map<String, String>? headers) =>
|
||||
http.delete(uri, headers: headers);
|
||||
Future<http.Response> request(
|
||||
Uri uri,
|
||||
ApiParams? body,
|
||||
Map<String, String>? headers,
|
||||
) => http.delete(uri, headers: headers);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,8 @@ class GetChat extends TalkApi<GetChatResponse> {
|
||||
String chatToken;
|
||||
|
||||
GetChatParams params;
|
||||
GetChat(this.chatToken, this.params) : super('v1/chat/$chatToken', null, getParameters: params.toJson());
|
||||
GetChat(this.chatToken, this.params)
|
||||
: super('v1/chat/$chatToken', null, getParameters: params.toJson());
|
||||
|
||||
@override
|
||||
GetChatResponse assemble(String raw) {
|
||||
@@ -20,6 +21,9 @@ class GetChat extends TalkApi<GetChatResponse> {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Response> request(Uri uri, Object? body, Map<String, String>? headers) => http.get(uri, headers: headers);
|
||||
|
||||
Future<Response> request(
|
||||
Uri uri,
|
||||
Object? body,
|
||||
Map<String, String>? headers,
|
||||
) => http.get(uri, headers: headers);
|
||||
}
|
||||
|
||||
@@ -10,17 +10,17 @@ class GetChatCache extends SimpleCache<GetChatResponse> {
|
||||
super.onError,
|
||||
required String chatToken,
|
||||
}) : super(
|
||||
cacheTime: RequestCache.cacheNothing,
|
||||
loader: () => GetChat(
|
||||
chatToken,
|
||||
GetChatParams(
|
||||
lookIntoFuture: GetChatParamsSwitch.off,
|
||||
setReadMarker: GetChatParamsSwitch.on,
|
||||
limit: 200,
|
||||
),
|
||||
).run(),
|
||||
fromJson: GetChatResponse.fromJson,
|
||||
) {
|
||||
cacheTime: RequestCache.cacheNothing,
|
||||
loader: () => GetChat(
|
||||
chatToken,
|
||||
GetChatParams(
|
||||
lookIntoFuture: GetChatParamsSwitch.off,
|
||||
setReadMarker: GetChatParamsSwitch.on,
|
||||
limit: 200,
|
||||
),
|
||||
).run(),
|
||||
fromJson: GetChatResponse.fromJson,
|
||||
) {
|
||||
start('nc-chat-$chatToken');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,20 +15,23 @@ class GetChatParams extends ApiParams {
|
||||
GetChatParamsSwitch? includeLastKnown;
|
||||
|
||||
GetChatParams({
|
||||
required this.lookIntoFuture,
|
||||
this.limit,
|
||||
this.lastKnownMessageId,
|
||||
this.lastCommonReadId,
|
||||
this.timeout,
|
||||
this.setReadMarker,
|
||||
this.includeLastKnown
|
||||
required this.lookIntoFuture,
|
||||
this.limit,
|
||||
this.lastKnownMessageId,
|
||||
this.lastCommonReadId,
|
||||
this.timeout,
|
||||
this.setReadMarker,
|
||||
this.includeLastKnown,
|
||||
});
|
||||
|
||||
factory GetChatParams.fromJson(Map<String, dynamic> json) => _$GetChatParamsFromJson(json);
|
||||
factory GetChatParams.fromJson(Map<String, dynamic> json) =>
|
||||
_$GetChatParamsFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$GetChatParamsToJson(this);
|
||||
}
|
||||
|
||||
enum GetChatParamsSwitch {
|
||||
@JsonValue(1) on,
|
||||
@JsonValue(0) off,
|
||||
@JsonValue(1)
|
||||
on,
|
||||
@JsonValue(0)
|
||||
off,
|
||||
}
|
||||
|
||||
@@ -12,7 +12,8 @@ class GetChatResponse extends ApiResponse {
|
||||
|
||||
GetChatResponse(this.data);
|
||||
|
||||
factory GetChatResponse.fromJson(Map<String, dynamic> json) => _$GetChatResponseFromJson(json);
|
||||
factory GetChatResponse.fromJson(Map<String, dynamic> json) =>
|
||||
_$GetChatResponseFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$GetChatResponseToJson(this);
|
||||
|
||||
List<GetChatResponseObject> sortByTimestamp() {
|
||||
@@ -37,28 +38,30 @@ class GetChatResponseObject {
|
||||
String message;
|
||||
Map<String, int>? reactions;
|
||||
List<String>? reactionsSelf;
|
||||
@JsonKey(fromJson: _fromJson) Map<String, RichObjectString>? messageParameters;
|
||||
@JsonKey(fromJson: _fromJson)
|
||||
Map<String, RichObjectString>? messageParameters;
|
||||
GetChatResponseObject? parent;
|
||||
|
||||
GetChatResponseObject(
|
||||
this.id,
|
||||
this.token,
|
||||
this.actorType,
|
||||
this.actorId,
|
||||
this.actorDisplayName,
|
||||
this.timestamp,
|
||||
this.systemMessage,
|
||||
this.messageType,
|
||||
this.isReplyable,
|
||||
this.referenceId,
|
||||
this.message,
|
||||
this.messageParameters,
|
||||
this.reactions,
|
||||
this.reactionsSelf,
|
||||
this.parent,
|
||||
this.id,
|
||||
this.token,
|
||||
this.actorType,
|
||||
this.actorId,
|
||||
this.actorDisplayName,
|
||||
this.timestamp,
|
||||
this.systemMessage,
|
||||
this.messageType,
|
||||
this.isReplyable,
|
||||
this.referenceId,
|
||||
this.message,
|
||||
this.messageParameters,
|
||||
this.reactions,
|
||||
this.reactionsSelf,
|
||||
this.parent,
|
||||
);
|
||||
|
||||
factory GetChatResponseObject.fromJson(Map<String, dynamic> json) => _$GetChatResponseObjectFromJson(json);
|
||||
factory GetChatResponseObject.fromJson(Map<String, dynamic> json) =>
|
||||
_$GetChatResponseObjectFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$GetChatResponseObjectToJson(this);
|
||||
|
||||
static GetChatResponseObject getDateDummy(int timestamp) {
|
||||
@@ -66,7 +69,8 @@ class GetChatResponseObject {
|
||||
return getTextDummy(elementDate.formatDate());
|
||||
}
|
||||
|
||||
static GetChatResponseObject getTextDummy(String text) => GetChatResponseObject(
|
||||
static GetChatResponseObject getTextDummy(String text) =>
|
||||
GetChatResponseObject(
|
||||
0,
|
||||
'',
|
||||
GetRoomResponseObjectMessageActorType.user,
|
||||
@@ -82,15 +86,17 @@ class GetChatResponseObject {
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
);
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, RichObjectString>? _fromJson(dynamic json) {
|
||||
if (json is Map<String, dynamic>) {
|
||||
final data = <String, RichObjectString>{};
|
||||
for (final element in json.keys) {
|
||||
data.putIfAbsent(element, () => RichObjectString.fromJson(json[element] as Map<String, dynamic>));
|
||||
data.putIfAbsent(
|
||||
element,
|
||||
() => RichObjectString.fromJson(json[element] as Map<String, dynamic>),
|
||||
);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
@@ -109,17 +115,26 @@ class RichObjectString {
|
||||
|
||||
RichObjectString(this.type, this.id, this.name, this.path, this.link);
|
||||
|
||||
factory RichObjectString.fromJson(Map<String, dynamic> json) => _$RichObjectStringFromJson(json);
|
||||
factory RichObjectString.fromJson(Map<String, dynamic> json) =>
|
||||
_$RichObjectStringFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$RichObjectStringToJson(this);
|
||||
}
|
||||
|
||||
enum RichObjectStringObjectType {
|
||||
@JsonValue('user') user,
|
||||
@JsonValue('group') group,
|
||||
@JsonValue('file') file,
|
||||
@JsonValue('guest') guest,
|
||||
@JsonValue('highlight') highlight,
|
||||
@JsonValue('talk-poll') talkPoll,
|
||||
@JsonValue('geo-location') geoLocation,
|
||||
@JsonValue('call') call,
|
||||
@JsonValue('user')
|
||||
user,
|
||||
@JsonValue('group')
|
||||
group,
|
||||
@JsonValue('file')
|
||||
file,
|
||||
@JsonValue('guest')
|
||||
guest,
|
||||
@JsonValue('highlight')
|
||||
highlight,
|
||||
@JsonValue('talk-poll')
|
||||
talkPoll,
|
||||
@JsonValue('geo-location')
|
||||
geoLocation,
|
||||
@JsonValue('call')
|
||||
call,
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
|
||||
import 'get_chat_response.dart';
|
||||
|
||||
class RichObjectStringProcessor {
|
||||
static String parseToString(String message, Map<String, RichObjectString>? data) {
|
||||
if(data == null) return message;
|
||||
static String parseToString(
|
||||
String message,
|
||||
Map<String, RichObjectString>? data,
|
||||
) {
|
||||
if (data == null) return message;
|
||||
|
||||
data.forEach((key, value) {
|
||||
message = message.replaceAll(RegExp('{$key}'), value.name);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:http/http.dart';
|
||||
|
||||
import '../talk_api.dart';
|
||||
import 'create_room_params.dart';
|
||||
|
||||
class CreateRoom extends TalkApi {
|
||||
CreateRoomParams params;
|
||||
|
||||
@@ -13,9 +13,19 @@ class CreateRoom extends TalkApi {
|
||||
Null assemble(String raw) => null;
|
||||
|
||||
@override
|
||||
Future<Response>? request(Uri uri, Object? body, Map<String, String>? headers) {
|
||||
if(body is CreateRoomParams) {
|
||||
return http.post(uri, headers: headers, body: body.toJson().map((key, value) => MapEntry(key, value.toString())));
|
||||
Future<Response>? request(
|
||||
Uri uri,
|
||||
Object? body,
|
||||
Map<String, String>? headers,
|
||||
) {
|
||||
if (body is CreateRoomParams) {
|
||||
return http.post(
|
||||
uri,
|
||||
headers: headers,
|
||||
body: body.toJson().map(
|
||||
(key, value) => MapEntry(key, value.toString()),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -19,9 +19,10 @@ class CreateRoomParams extends ApiParams {
|
||||
this.source,
|
||||
this.roomName,
|
||||
this.objectType,
|
||||
this.objectId
|
||||
this.objectId,
|
||||
});
|
||||
|
||||
factory CreateRoomParams.fromJson(Map<String, dynamic> json) => _$CreateRoomParamsFromJson(json);
|
||||
factory CreateRoomParams.fromJson(Map<String, dynamic> json) =>
|
||||
_$CreateRoomParamsFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$CreateRoomParamsToJson(this);
|
||||
}
|
||||
|
||||
@@ -8,17 +8,24 @@ import 'delete_react_message_params.dart';
|
||||
class DeleteReactMessage extends TalkApi {
|
||||
String chatToken;
|
||||
int messageId;
|
||||
DeleteReactMessage({required this.chatToken, required this.messageId, required DeleteReactMessageParams params}) : super('v1/reaction/$chatToken/$messageId', params);
|
||||
DeleteReactMessage({
|
||||
required this.chatToken,
|
||||
required this.messageId,
|
||||
required DeleteReactMessageParams params,
|
||||
}) : super('v1/reaction/$chatToken/$messageId', params);
|
||||
|
||||
@override
|
||||
Null assemble(String raw) => null;
|
||||
|
||||
@override
|
||||
Future<Response>? request(Uri uri, ApiParams? body, Map<String, String>? headers) {
|
||||
if(body is DeleteReactMessageParams) {
|
||||
Future<Response>? request(
|
||||
Uri uri,
|
||||
ApiParams? body,
|
||||
Map<String, String>? headers,
|
||||
) {
|
||||
if (body is DeleteReactMessageParams) {
|
||||
return http.delete(uri, headers: headers, body: body.toJson());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ class DeleteReactMessageParams extends ApiParams {
|
||||
|
||||
DeleteReactMessageParams(this.reaction);
|
||||
|
||||
factory DeleteReactMessageParams.fromJson(Map<String, dynamic> json) => _$DeleteReactMessageParamsFromJson(json);
|
||||
factory DeleteReactMessageParams.fromJson(Map<String, dynamic> json) =>
|
||||
_$DeleteReactMessageParamsFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$DeleteReactMessageParamsToJson(this);
|
||||
}
|
||||
|
||||
@@ -12,10 +12,15 @@ class GetParticipants extends TalkApi<GetParticipantsResponse> {
|
||||
@override
|
||||
GetParticipantsResponse assemble(String raw) {
|
||||
final decoded = jsonDecode(raw) as Map<String, dynamic>;
|
||||
return GetParticipantsResponse.fromJson(decoded['ocs'] as Map<String, dynamic>);
|
||||
return GetParticipantsResponse.fromJson(
|
||||
decoded['ocs'] as Map<String, dynamic>,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<http.Response> request(Uri uri, Object? body, Map<String, String>? headers) => http.get(uri, headers: headers);
|
||||
|
||||
Future<http.Response> request(
|
||||
Uri uri,
|
||||
Object? body,
|
||||
Map<String, String>? headers,
|
||||
) => http.get(uri, headers: headers);
|
||||
}
|
||||
|
||||
@@ -7,11 +7,11 @@ class GetParticipantsCache extends SimpleCache<GetParticipantsResponse> {
|
||||
required void Function(GetParticipantsResponse) onUpdate,
|
||||
required String chatToken,
|
||||
}) : super(
|
||||
cacheTime: RequestCache.cacheNothing,
|
||||
loader: () => GetParticipants(chatToken).run(),
|
||||
fromJson: GetParticipantsResponse.fromJson,
|
||||
onUpdate: onUpdate,
|
||||
) {
|
||||
cacheTime: RequestCache.cacheNothing,
|
||||
loader: () => GetParticipants(chatToken).run(),
|
||||
fromJson: GetParticipantsResponse.fromJson,
|
||||
onUpdate: onUpdate,
|
||||
) {
|
||||
start('nc-chat-participants-$chatToken');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
import '../../../api_response.dart';
|
||||
@@ -11,7 +10,8 @@ class GetParticipantsResponse extends ApiResponse {
|
||||
|
||||
GetParticipantsResponse(this.data);
|
||||
|
||||
factory GetParticipantsResponse.fromJson(Map<String, dynamic> json) => _$GetParticipantsResponseFromJson(json);
|
||||
factory GetParticipantsResponse.fromJson(Map<String, dynamic> json) =>
|
||||
_$GetParticipantsResponseFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$GetParticipantsResponseToJson(this);
|
||||
}
|
||||
|
||||
@@ -34,42 +34,55 @@ class GetParticipantsResponseObject {
|
||||
String? roomToken;
|
||||
|
||||
GetParticipantsResponseObject(
|
||||
this.attendeeId,
|
||||
this.actorType,
|
||||
this.actorId,
|
||||
this.displayName,
|
||||
this.participantType,
|
||||
this.lastPing,
|
||||
this.inCall,
|
||||
this.permissions,
|
||||
this.attendeePermissions,
|
||||
this.sessionId,
|
||||
this.sessionIds,
|
||||
this.status,
|
||||
this.statusIcon,
|
||||
this.statusMessage,
|
||||
this.roomToken);
|
||||
this.attendeeId,
|
||||
this.actorType,
|
||||
this.actorId,
|
||||
this.displayName,
|
||||
this.participantType,
|
||||
this.lastPing,
|
||||
this.inCall,
|
||||
this.permissions,
|
||||
this.attendeePermissions,
|
||||
this.sessionId,
|
||||
this.sessionIds,
|
||||
this.status,
|
||||
this.statusIcon,
|
||||
this.statusMessage,
|
||||
this.roomToken,
|
||||
);
|
||||
|
||||
factory GetParticipantsResponseObject.fromJson(Map<String, dynamic> json) => _$GetParticipantsResponseObjectFromJson(json);
|
||||
factory GetParticipantsResponseObject.fromJson(Map<String, dynamic> json) =>
|
||||
_$GetParticipantsResponseObjectFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$GetParticipantsResponseObjectToJson(this);
|
||||
}
|
||||
|
||||
enum GetParticipantsResponseObjectParticipantType {
|
||||
@JsonValue(1) owner('Besitzer'),
|
||||
@JsonValue(2) moderator('Moderator'),
|
||||
@JsonValue(3) user('Teilnehmer'),
|
||||
@JsonValue(4) guest('Gast'),
|
||||
@JsonValue(5) userFollowingPublicLink('Teilnehmer über Link'),
|
||||
@JsonValue(6) guestWithModeratorPermissions('Gast Moderator');
|
||||
@JsonValue(1)
|
||||
owner('Besitzer'),
|
||||
@JsonValue(2)
|
||||
moderator('Moderator'),
|
||||
@JsonValue(3)
|
||||
user('Teilnehmer'),
|
||||
@JsonValue(4)
|
||||
guest('Gast'),
|
||||
@JsonValue(5)
|
||||
userFollowingPublicLink('Teilnehmer über Link'),
|
||||
@JsonValue(6)
|
||||
guestWithModeratorPermissions('Gast Moderator');
|
||||
|
||||
const GetParticipantsResponseObjectParticipantType(this.prettyName);
|
||||
final String prettyName;
|
||||
}
|
||||
|
||||
enum GetParticipantsResponseObjectParticipantsInCallFlags {
|
||||
@JsonValue(0) disconnected,
|
||||
@JsonValue(1) inCall,
|
||||
@JsonValue(2) providesAudio,
|
||||
@JsonValue(3) providesVideo,
|
||||
@JsonValue(4) usesSipDialIn
|
||||
@JsonValue(0)
|
||||
disconnected,
|
||||
@JsonValue(1)
|
||||
inCall,
|
||||
@JsonValue(2)
|
||||
providesAudio,
|
||||
@JsonValue(3)
|
||||
providesVideo,
|
||||
@JsonValue(4)
|
||||
usesSipDialIn,
|
||||
}
|
||||
|
||||
@@ -8,14 +8,21 @@ import 'get_poll_state_response.dart';
|
||||
class GetPollState extends TalkApi<GetPollStateResponse> {
|
||||
String token;
|
||||
int pollId;
|
||||
GetPollState({required this.token, required this.pollId}) : super('v1/poll/$token/$pollId', null);
|
||||
GetPollState({required this.token, required this.pollId})
|
||||
: super('v1/poll/$token/$pollId', null);
|
||||
|
||||
@override
|
||||
GetPollStateResponse assemble(String raw) {
|
||||
final decoded = jsonDecode(raw) as Map<String, dynamic>;
|
||||
return GetPollStateResponse.fromJson(decoded['ocs'] as Map<String, dynamic>);
|
||||
return GetPollStateResponse.fromJson(
|
||||
decoded['ocs'] as Map<String, dynamic>,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<http.Response> request(Uri uri, Object? body, Map<String, String>? headers) => http.get(uri, headers: headers);
|
||||
Future<http.Response> request(
|
||||
Uri uri,
|
||||
Object? body,
|
||||
Map<String, String>? headers,
|
||||
) => http.get(uri, headers: headers);
|
||||
}
|
||||
|
||||
@@ -10,7 +10,8 @@ class GetPollStateResponse extends ApiResponse {
|
||||
|
||||
GetPollStateResponse(this.data);
|
||||
|
||||
factory GetPollStateResponse.fromJson(Map<String, dynamic> json) => _$GetPollStateResponseFromJson(json);
|
||||
factory GetPollStateResponse.fromJson(Map<String, dynamic> json) =>
|
||||
_$GetPollStateResponseFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$GetPollStateResponseToJson(this);
|
||||
}
|
||||
|
||||
@@ -31,20 +32,22 @@ class GetPollStateResponseObject {
|
||||
List<dynamic>? details;
|
||||
|
||||
GetPollStateResponseObject(
|
||||
this.id,
|
||||
this.question,
|
||||
this.options,
|
||||
this.votes,
|
||||
this.actorType,
|
||||
this.actorId,
|
||||
this.actorDisplayName,
|
||||
this.status,
|
||||
this.resultMode,
|
||||
this.maxVotes,
|
||||
this.votedSelf,
|
||||
this.numVoters,
|
||||
this.details);
|
||||
this.id,
|
||||
this.question,
|
||||
this.options,
|
||||
this.votes,
|
||||
this.actorType,
|
||||
this.actorId,
|
||||
this.actorDisplayName,
|
||||
this.status,
|
||||
this.resultMode,
|
||||
this.maxVotes,
|
||||
this.votedSelf,
|
||||
this.numVoters,
|
||||
this.details,
|
||||
);
|
||||
|
||||
factory GetPollStateResponseObject.fromJson(Map<String, dynamic> json) => _$GetPollStateResponseObjectFromJson(json);
|
||||
factory GetPollStateResponseObject.fromJson(Map<String, dynamic> json) =>
|
||||
_$GetPollStateResponseObjectFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$GetPollStateResponseObjectToJson(this);
|
||||
}
|
||||
|
||||
@@ -10,15 +10,21 @@ import 'get_reactions_response.dart';
|
||||
class GetReactions extends TalkApi<GetReactionsResponse> {
|
||||
String chatToken;
|
||||
int messageId;
|
||||
GetReactions({required this.chatToken, required this.messageId}) : super('v1/reaction/$chatToken/$messageId', null);
|
||||
GetReactions({required this.chatToken, required this.messageId})
|
||||
: super('v1/reaction/$chatToken/$messageId', null);
|
||||
|
||||
@override
|
||||
GetReactionsResponse assemble(String raw) {
|
||||
final decoded = jsonDecode(raw) as Map<String, dynamic>;
|
||||
return GetReactionsResponse.fromJson(decoded['ocs'] as Map<String, dynamic>);
|
||||
return GetReactionsResponse.fromJson(
|
||||
decoded['ocs'] as Map<String, dynamic>,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Response>? request(Uri uri, ApiParams? body, Map<String, String>? headers) => http.get(uri, headers: headers);
|
||||
|
||||
Future<Response>? request(
|
||||
Uri uri,
|
||||
ApiParams? body,
|
||||
Map<String, String>? headers,
|
||||
) => http.get(uri, headers: headers);
|
||||
}
|
||||
|
||||
@@ -10,7 +10,8 @@ class GetReactionsResponse extends ApiResponse {
|
||||
|
||||
GetReactionsResponse(this.data);
|
||||
|
||||
factory GetReactionsResponse.fromJson(Map<String, dynamic> json) => _$GetReactionsResponseFromJson(json);
|
||||
factory GetReactionsResponse.fromJson(Map<String, dynamic> json) =>
|
||||
_$GetReactionsResponseFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$GetReactionsResponseToJson(this);
|
||||
}
|
||||
|
||||
@@ -21,13 +22,21 @@ class GetReactionsResponseObject {
|
||||
String actorDisplayName;
|
||||
int timestamp;
|
||||
|
||||
GetReactionsResponseObject(this.actorType, this.actorId, this.actorDisplayName, this.timestamp);
|
||||
GetReactionsResponseObject(
|
||||
this.actorType,
|
||||
this.actorId,
|
||||
this.actorDisplayName,
|
||||
this.timestamp,
|
||||
);
|
||||
|
||||
factory GetReactionsResponseObject.fromJson(Map<String, dynamic> json) => _$GetReactionsResponseObjectFromJson(json);
|
||||
factory GetReactionsResponseObject.fromJson(Map<String, dynamic> json) =>
|
||||
_$GetReactionsResponseObjectFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$GetReactionsResponseObjectToJson(this);
|
||||
}
|
||||
|
||||
enum GetReactionsResponseObjectActorType {
|
||||
@JsonValue('guests') guests,
|
||||
@JsonValue('users') users,
|
||||
@JsonValue('guests')
|
||||
guests,
|
||||
@JsonValue('users')
|
||||
users,
|
||||
}
|
||||
|
||||
@@ -8,17 +8,24 @@ import 'react_message_params.dart';
|
||||
class ReactMessage extends TalkApi {
|
||||
String chatToken;
|
||||
int messageId;
|
||||
ReactMessage({required this.chatToken, required this.messageId, required ReactMessageParams params}) : super('v1/reaction/$chatToken/$messageId', params);
|
||||
ReactMessage({
|
||||
required this.chatToken,
|
||||
required this.messageId,
|
||||
required ReactMessageParams params,
|
||||
}) : super('v1/reaction/$chatToken/$messageId', params);
|
||||
|
||||
@override
|
||||
Null assemble(String raw) => null;
|
||||
|
||||
@override
|
||||
Future<Response>? request(Uri uri, ApiParams? body, Map<String, String>? headers) {
|
||||
if(body is ReactMessageParams) {
|
||||
Future<Response>? request(
|
||||
Uri uri,
|
||||
ApiParams? body,
|
||||
Map<String, String>? headers,
|
||||
) {
|
||||
if (body is ReactMessageParams) {
|
||||
return http.post(uri, headers: headers, body: body.toJson());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ class ReactMessageParams extends ApiParams {
|
||||
|
||||
ReactMessageParams(this.reaction);
|
||||
|
||||
factory ReactMessageParams.fromJson(Map<String, dynamic> json) => _$ReactMessageParamsFromJson(json);
|
||||
factory ReactMessageParams.fromJson(Map<String, dynamic> json) =>
|
||||
_$ReactMessageParamsFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$ReactMessageParamsToJson(this);
|
||||
}
|
||||
|
||||
@@ -6,13 +6,10 @@ import '../talk_api.dart';
|
||||
import 'get_room_params.dart';
|
||||
import 'get_room_response.dart';
|
||||
|
||||
|
||||
class GetRoom extends TalkApi<GetRoomResponse> {
|
||||
GetRoomParams params;
|
||||
GetRoom(this.params) : super('v4/room', null, getParameters: params.toJson());
|
||||
|
||||
|
||||
|
||||
@override
|
||||
GetRoomResponse assemble(String raw) {
|
||||
final decoded = jsonDecode(raw) as Map<String, dynamic>;
|
||||
@@ -20,6 +17,9 @@ class GetRoom extends TalkApi<GetRoomResponse> {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<http.Response> request(Uri uri, Object? body, Map<String, String>? headers) => http.get(uri, headers: headers);
|
||||
|
||||
Future<http.Response> request(
|
||||
Uri uri,
|
||||
Object? body,
|
||||
Map<String, String>? headers,
|
||||
) => http.get(uri, headers: headers);
|
||||
}
|
||||
|
||||
@@ -5,11 +5,11 @@ import 'get_room_response.dart';
|
||||
|
||||
class GetRoomCache extends SimpleCache<GetRoomResponse> {
|
||||
GetRoomCache({super.onUpdate, super.onError, super.renew})
|
||||
: super(
|
||||
cacheTime: RequestCache.cacheMinute,
|
||||
loader: () => GetRoom(GetRoomParams(includeStatus: true)).run(),
|
||||
fromJson: GetRoomResponse.fromJson,
|
||||
) {
|
||||
: super(
|
||||
cacheTime: RequestCache.cacheMinute,
|
||||
loader: () => GetRoom(GetRoomParams(includeStatus: true)).run(),
|
||||
fromJson: GetRoomResponse.fromJson,
|
||||
) {
|
||||
start('nc-rooms');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
import '../../../api_params.dart';
|
||||
@@ -8,18 +7,22 @@ part 'get_room_params.g.dart';
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class GetRoomParams extends ApiParams {
|
||||
GetRoomParamsStatusUpdate? noStatusUpdate;
|
||||
@JsonKey(toJson: _format) bool? includeStatus;
|
||||
@JsonKey(toJson: _format)
|
||||
bool? includeStatus;
|
||||
int? modifiedSince;
|
||||
|
||||
GetRoomParams({this.noStatusUpdate, this.includeStatus, this.modifiedSince});
|
||||
|
||||
factory GetRoomParams.fromJson(Map<String, dynamic> json) => _$GetRoomParamsFromJson(json);
|
||||
factory GetRoomParams.fromJson(Map<String, dynamic> json) =>
|
||||
_$GetRoomParamsFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$GetRoomParamsToJson(this);
|
||||
|
||||
|
||||
static String _format(bool? v) => v.toString();
|
||||
}
|
||||
|
||||
enum GetRoomParamsStatusUpdate {
|
||||
@JsonValue(0) defaults,
|
||||
@JsonValue(1) keepAlive,
|
||||
@JsonValue(0)
|
||||
defaults,
|
||||
@JsonValue(1)
|
||||
keepAlive,
|
||||
}
|
||||
|
||||
@@ -11,17 +11,22 @@ class GetRoomResponse extends ApiResponse {
|
||||
|
||||
GetRoomResponse(this.data);
|
||||
|
||||
factory GetRoomResponse.fromJson(Map<String, dynamic> json) => _$GetRoomResponseFromJson(json);
|
||||
factory GetRoomResponse.fromJson(Map<String, dynamic> json) =>
|
||||
_$GetRoomResponseFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$GetRoomResponseToJson(this);
|
||||
|
||||
List<GetRoomResponseObject> sortBy({bool lastActivity = true, required bool favoritesToTop, required bool unreadToTop}) {
|
||||
List<GetRoomResponseObject> sortBy({
|
||||
bool lastActivity = true,
|
||||
required bool favoritesToTop,
|
||||
required bool unreadToTop,
|
||||
}) {
|
||||
for (var chat in data) {
|
||||
final buffer = StringBuffer();
|
||||
|
||||
if(favoritesToTop) {
|
||||
if (favoritesToTop) {
|
||||
buffer.write(chat.isFavorite ? 'b' : 'a');
|
||||
}
|
||||
if(unreadToTop) {
|
||||
if (unreadToTop) {
|
||||
buffer.write(chat.unreadMessages > 0 ? 'b' : 'a');
|
||||
}
|
||||
|
||||
@@ -69,69 +74,91 @@ class GetRoomResponseObject {
|
||||
String? sort;
|
||||
|
||||
GetRoomResponseObject(
|
||||
this.id,
|
||||
this.token,
|
||||
this.type,
|
||||
this.name,
|
||||
this.displayName,
|
||||
this.description,
|
||||
this.participantType,
|
||||
this.participantFlags,
|
||||
this.readOnly,
|
||||
this.listable,
|
||||
this.lastPing,
|
||||
this.sessionId,
|
||||
this.hasPassword,
|
||||
this.hasCall,
|
||||
this.callFlag,
|
||||
this.canStartCall,
|
||||
this.canDeleteConversation,
|
||||
this.canLeaveConversation,
|
||||
this.lastActivity,
|
||||
this.isFavorite,
|
||||
this.notificationLevel,
|
||||
this.unreadMessages,
|
||||
this.unreadMention,
|
||||
this.unreadMentionDirect,
|
||||
this.lastReadMessage,
|
||||
this.lastCommonReadMessage,
|
||||
this.lastMessage,
|
||||
this.status,
|
||||
this.statusIcon,
|
||||
this.statusMessage);
|
||||
this.id,
|
||||
this.token,
|
||||
this.type,
|
||||
this.name,
|
||||
this.displayName,
|
||||
this.description,
|
||||
this.participantType,
|
||||
this.participantFlags,
|
||||
this.readOnly,
|
||||
this.listable,
|
||||
this.lastPing,
|
||||
this.sessionId,
|
||||
this.hasPassword,
|
||||
this.hasCall,
|
||||
this.callFlag,
|
||||
this.canStartCall,
|
||||
this.canDeleteConversation,
|
||||
this.canLeaveConversation,
|
||||
this.lastActivity,
|
||||
this.isFavorite,
|
||||
this.notificationLevel,
|
||||
this.unreadMessages,
|
||||
this.unreadMention,
|
||||
this.unreadMentionDirect,
|
||||
this.lastReadMessage,
|
||||
this.lastCommonReadMessage,
|
||||
this.lastMessage,
|
||||
this.status,
|
||||
this.statusIcon,
|
||||
this.statusMessage,
|
||||
);
|
||||
|
||||
factory GetRoomResponseObject.fromJson(Map<String, dynamic> json) => _$GetRoomResponseObjectFromJson(json);
|
||||
factory GetRoomResponseObject.fromJson(Map<String, dynamic> json) =>
|
||||
_$GetRoomResponseObjectFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$GetRoomResponseObjectToJson(this);
|
||||
}
|
||||
|
||||
enum GetRoomResponseObjectConversationType {
|
||||
@JsonValue(1) oneToOne,
|
||||
@JsonValue(2) group,
|
||||
@JsonValue(3) public,
|
||||
@JsonValue(4) changelog,
|
||||
@JsonValue(5) deleted,
|
||||
@JsonValue(6) noteToSelf,
|
||||
@JsonValue(1)
|
||||
oneToOne,
|
||||
@JsonValue(2)
|
||||
group,
|
||||
@JsonValue(3)
|
||||
public,
|
||||
@JsonValue(4)
|
||||
changelog,
|
||||
@JsonValue(5)
|
||||
deleted,
|
||||
@JsonValue(6)
|
||||
noteToSelf,
|
||||
}
|
||||
|
||||
enum GetRoomResponseObjectParticipantNotificationLevel {
|
||||
@JsonValue(0) defaultLevel,
|
||||
@JsonValue(1) alwaysNotify,
|
||||
@JsonValue(2) notifyOnMention,
|
||||
@JsonValue(3) neverNotify,
|
||||
@JsonValue(0)
|
||||
defaultLevel,
|
||||
@JsonValue(1)
|
||||
alwaysNotify,
|
||||
@JsonValue(2)
|
||||
notifyOnMention,
|
||||
@JsonValue(3)
|
||||
neverNotify,
|
||||
}
|
||||
|
||||
enum GetRoomResponseObjectMessageActorType {
|
||||
@JsonValue('deleted_users') deletedUsers,
|
||||
@JsonValue('users') user,
|
||||
@JsonValue('guests') guest,
|
||||
@JsonValue('bots') bot,
|
||||
@JsonValue('bridged') bridge,
|
||||
@JsonValue('deleted_users')
|
||||
deletedUsers,
|
||||
@JsonValue('users')
|
||||
user,
|
||||
@JsonValue('guests')
|
||||
guest,
|
||||
@JsonValue('bots')
|
||||
bot,
|
||||
@JsonValue('bridged')
|
||||
bridge,
|
||||
}
|
||||
|
||||
enum GetRoomResponseObjectMessageType {
|
||||
@JsonValue('comment') comment,
|
||||
@JsonValue('voice-message') voiceMessage,
|
||||
@JsonValue('comment_deleted') deletedComment,
|
||||
@JsonValue('system') system,
|
||||
@JsonValue('command') command,
|
||||
@JsonValue('comment')
|
||||
comment,
|
||||
@JsonValue('voice-message')
|
||||
voiceMessage,
|
||||
@JsonValue('comment_deleted')
|
||||
deletedComment,
|
||||
@JsonValue('system')
|
||||
system,
|
||||
@JsonValue('command')
|
||||
command,
|
||||
}
|
||||
|
||||
@@ -7,17 +7,21 @@ import 'send_message_params.dart';
|
||||
|
||||
class SendMessage extends TalkApi {
|
||||
String chatToken;
|
||||
SendMessage(this.chatToken, SendMessageParams params) : super('v1/chat/$chatToken', params);
|
||||
SendMessage(this.chatToken, SendMessageParams params)
|
||||
: super('v1/chat/$chatToken', params);
|
||||
|
||||
@override
|
||||
Null assemble(String raw) => null;
|
||||
|
||||
@override
|
||||
Future<Response>? request(Uri uri, ApiParams? body, Map<String, String>? headers) {
|
||||
if(body is SendMessageParams) {
|
||||
Future<Response>? request(
|
||||
Uri uri,
|
||||
ApiParams? body,
|
||||
Map<String, String>? headers,
|
||||
) {
|
||||
if (body is SendMessageParams) {
|
||||
return http.post(uri, headers: headers, body: body.toJson());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ class SendMessageParams extends ApiParams {
|
||||
|
||||
SendMessageParams(this.message, {this.replyTo});
|
||||
|
||||
factory SendMessageParams.fromJson(Map<String, dynamic> json) => _$SendMessageParamsFromJson(json);
|
||||
factory SendMessageParams.fromJson(Map<String, dynamic> json) =>
|
||||
_$SendMessageParamsFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$SendMessageParamsToJson(this);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:http/http.dart';
|
||||
|
||||
@@ -10,21 +9,28 @@ class SetReadMarker extends TalkApi {
|
||||
bool readState;
|
||||
SetReadMarkerParams? setReadMarkerParams;
|
||||
|
||||
SetReadMarker(this.chatToken, this.readState, {this.setReadMarkerParams}) : super('v1/chat/$chatToken/read', null, getParameters: setReadMarkerParams?.toJson()) {
|
||||
if(readState) assert(setReadMarkerParams?.lastReadMessage != null);
|
||||
SetReadMarker(this.chatToken, this.readState, {this.setReadMarkerParams})
|
||||
: super(
|
||||
'v1/chat/$chatToken/read',
|
||||
null,
|
||||
getParameters: setReadMarkerParams?.toJson(),
|
||||
) {
|
||||
if (readState) assert(setReadMarkerParams?.lastReadMessage != null);
|
||||
}
|
||||
|
||||
@override
|
||||
Null assemble(String raw) => null;
|
||||
|
||||
@override
|
||||
Future<Response> request(Uri uri, Object? body, Map<String, String>? headers) {
|
||||
if(readState) {
|
||||
|
||||
Future<Response> request(
|
||||
Uri uri,
|
||||
Object? body,
|
||||
Map<String, String>? headers,
|
||||
) {
|
||||
if (readState) {
|
||||
return http.post(uri, headers: headers);
|
||||
} else {
|
||||
return http.delete(uri, headers: headers);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,10 +8,9 @@ part 'set_read_marker_params.g.dart';
|
||||
class SetReadMarkerParams extends ApiParams {
|
||||
int? lastReadMessage;
|
||||
|
||||
SetReadMarkerParams({
|
||||
this.lastReadMessage
|
||||
});
|
||||
SetReadMarkerParams({this.lastReadMessage});
|
||||
|
||||
factory SetReadMarkerParams.fromJson(Map<String, dynamic> json) => _$SetReadMarkerParamsFromJson(json);
|
||||
factory SetReadMarkerParams.fromJson(Map<String, dynamic> json) =>
|
||||
_$SetReadMarkerParamsFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$SetReadMarkerParamsToJson(this);
|
||||
}
|
||||
|
||||
@@ -14,12 +14,7 @@ import '../../errors/parse_exception.dart';
|
||||
import '../../errors/server_exception.dart';
|
||||
import '../nextcloud_ocs.dart';
|
||||
|
||||
enum TalkApiMethod {
|
||||
get,
|
||||
post,
|
||||
put,
|
||||
delete,
|
||||
}
|
||||
enum TalkApiMethod { get, post, put, delete }
|
||||
|
||||
abstract class TalkApi<T extends ApiResponse?> extends ApiRequest {
|
||||
String path;
|
||||
@@ -31,11 +26,18 @@ abstract class TalkApi<T extends ApiResponse?> extends ApiRequest {
|
||||
|
||||
TalkApi(this.path, this.body, {this.headers, this.getParameters});
|
||||
|
||||
Future<http.Response>? request(Uri uri, ApiParams? body, Map<String, String>? headers);
|
||||
Future<http.Response>? request(
|
||||
Uri uri,
|
||||
ApiParams? body,
|
||||
Map<String, String>? headers,
|
||||
);
|
||||
T assemble(String raw);
|
||||
|
||||
Future<T> run() async {
|
||||
final endpoint = NextcloudOcs.uri('apps/spreed/api/$path', queryParameters: getParameters);
|
||||
final endpoint = NextcloudOcs.uri(
|
||||
'apps/spreed/api/$path',
|
||||
queryParameters: getParameters,
|
||||
);
|
||||
final mergedHeaders = {...NextcloudOcs.headers(), ...?headers};
|
||||
|
||||
final http.Response data;
|
||||
@@ -60,8 +62,12 @@ abstract class TalkApi<T extends ApiResponse?> extends ApiRequest {
|
||||
if (status < 200 || status >= 300) {
|
||||
final detail = 'Talk $endpoint -> HTTP $status';
|
||||
log(detail);
|
||||
if (status == 401) throw AuthException.unauthorized(technicalDetails: detail);
|
||||
if (status == 403) throw AuthException.forbidden(technicalDetails: detail);
|
||||
if (status == 401) {
|
||||
throw AuthException.unauthorized(technicalDetails: detail);
|
||||
}
|
||||
if (status == 403) {
|
||||
throw AuthException.forbidden(technicalDetails: detail);
|
||||
}
|
||||
if (status == 404) throw NotFoundException(technicalDetails: detail);
|
||||
throw ServerException(statusCode: status, technicalDetails: detail);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
import '../../../../api_response.dart';
|
||||
import '../../webdav_api.dart';
|
||||
import 'download_file_params.dart';
|
||||
|
||||
@@ -10,8 +10,13 @@ class DownloadFileParams extends ApiParams {
|
||||
String localTargetPath;
|
||||
String filename;
|
||||
|
||||
DownloadFileParams(this.webdavSourcePath, this.localTargetPath, this.filename);
|
||||
DownloadFileParams(
|
||||
this.webdavSourcePath,
|
||||
this.localTargetPath,
|
||||
this.filename,
|
||||
);
|
||||
|
||||
factory DownloadFileParams.fromJson(Map<String, dynamic> json) => _$DownloadFileParamsFromJson(json);
|
||||
factory DownloadFileParams.fromJson(Map<String, dynamic> json) =>
|
||||
_$DownloadFileParamsFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$DownloadFileParamsToJson(this);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'download_file_response.g.dart';
|
||||
@@ -9,6 +8,7 @@ class DownloadFileResponse {
|
||||
|
||||
DownloadFileResponse(this.path);
|
||||
|
||||
factory DownloadFileResponse.fromJson(Map<String, dynamic> json) => _$DownloadFileResponseFromJson(json);
|
||||
factory DownloadFileResponse.fromJson(Map<String, dynamic> json) =>
|
||||
_$DownloadFileResponseFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$DownloadFileResponseToJson(this);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,16 @@ class CacheableFile {
|
||||
DateTime? modifiedAt;
|
||||
String? sort;
|
||||
|
||||
CacheableFile({required this.path, required this.isDirectory, required this.name, this.mimeType, this.size, this.eTag, this.createdAt, this.modifiedAt});
|
||||
CacheableFile({
|
||||
required this.path,
|
||||
required this.isDirectory,
|
||||
required this.name,
|
||||
this.mimeType,
|
||||
this.size,
|
||||
this.eTag,
|
||||
this.createdAt,
|
||||
this.modifiedAt,
|
||||
});
|
||||
|
||||
CacheableFile.fromDavFile(WebDavFile file) {
|
||||
path = file.path.path;
|
||||
@@ -28,6 +37,7 @@ class CacheableFile {
|
||||
modifiedAt = file.lastModified;
|
||||
}
|
||||
|
||||
factory CacheableFile.fromJson(Map<String, dynamic> json) => _$CacheableFileFromJson(json);
|
||||
factory CacheableFile.fromJson(Map<String, dynamic> json) =>
|
||||
_$CacheableFileFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$CacheableFileToJson(this);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
import 'package:nextcloud/nextcloud.dart';
|
||||
|
||||
import '../../webdav_api.dart';
|
||||
@@ -26,12 +25,15 @@ class ListFiles extends WebdavApi<ListFilesParams> {
|
||||
Future<ListFilesResponse> run() async {
|
||||
final webdav = await WebdavApi.webdav;
|
||||
final timeout = _isRoot ? _rootTimeout : _subfolderTimeout;
|
||||
final davFiles = (await webdav.propfind(PathUri.parse(params.path)).timeout(timeout)).toWebDavFiles();
|
||||
final davFiles =
|
||||
(await webdav.propfind(PathUri.parse(params.path)).timeout(timeout))
|
||||
.toWebDavFiles();
|
||||
final files = davFiles.map(CacheableFile.fromDavFile).toSet();
|
||||
|
||||
|
||||
// somehow the current working folder is also listed, it is filtered here.
|
||||
files.removeWhere((element) => element.path == '/${params.path}/' || element.path == '/');
|
||||
files.removeWhere(
|
||||
(element) => element.path == '/${params.path}/' || element.path == '/',
|
||||
);
|
||||
|
||||
return ListFilesResponse(files);
|
||||
}
|
||||
|
||||
@@ -17,16 +17,18 @@ class ListFilesCache extends SimpleCache<ListFilesResponse> {
|
||||
super.onError,
|
||||
required String path,
|
||||
}) : super(
|
||||
cacheTime: RequestCache.cacheNothing,
|
||||
loader: () => ListFiles(ListFilesParams(path)).run(),
|
||||
fromJson: ListFilesResponse.fromJson,
|
||||
onUpdate: onUpdate,
|
||||
) {
|
||||
cacheTime: RequestCache.cacheNothing,
|
||||
loader: () => ListFiles(ListFilesParams(path)).run(),
|
||||
fromJson: ListFilesResponse.fromJson,
|
||||
onUpdate: onUpdate,
|
||||
) {
|
||||
start(_documentId(path));
|
||||
}
|
||||
|
||||
static String _documentId(String path) {
|
||||
final cacheName = md5.convert(utf8.encode('MarianumMobile-$path')).toString();
|
||||
final cacheName = md5
|
||||
.convert(utf8.encode('MarianumMobile-$path'))
|
||||
.toString();
|
||||
return 'wd-folder-$cacheName';
|
||||
}
|
||||
|
||||
@@ -35,7 +37,10 @@ class ListFilesCache extends SimpleCache<ListFilesResponse> {
|
||||
/// `_FilesView` for that path via [CacheInvalidationBus] so it refetches
|
||||
/// even while it is sitting in the background of the navigation stack.
|
||||
static Future<void> invalidate(String path) async {
|
||||
await Localstore.instance.collection(RequestCache.collection).doc(_documentId(path)).delete();
|
||||
await Localstore.instance
|
||||
.collection(RequestCache.collection)
|
||||
.doc(_documentId(path))
|
||||
.delete();
|
||||
CacheInvalidationBus.notifyListFiles(path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ class ListFilesParams extends ApiParams {
|
||||
|
||||
ListFilesParams(this.path);
|
||||
|
||||
factory ListFilesParams.fromJson(Map<String, dynamic> json) => _$ListFilesParamsFromJson(json);
|
||||
factory ListFilesParams.fromJson(Map<String, dynamic> json) =>
|
||||
_$ListFilesParamsFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$ListFilesParamsToJson(this);
|
||||
}
|
||||
|
||||
@@ -9,49 +9,73 @@ part 'list_files_response.g.dart';
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class ListFilesResponse extends ApiResponse {
|
||||
Set<CacheableFile> files;
|
||||
Set<CacheableFile> files;
|
||||
|
||||
ListFilesResponse(this.files);
|
||||
ListFilesResponse(this.files);
|
||||
|
||||
factory ListFilesResponse.fromJson(Map<String, dynamic> json) => _$ListFilesResponseFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$ListFilesResponseToJson(this);
|
||||
factory ListFilesResponse.fromJson(Map<String, dynamic> json) =>
|
||||
_$ListFilesResponseFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$ListFilesResponseToJson(this);
|
||||
|
||||
List<CacheableFile> sortBy({bool foldersToTop = true, SortOption sortOption = SortOption.name, bool reversed = false}) {
|
||||
var list = List<CacheableFile>.empty(growable: true);
|
||||
List<CacheableFile> sortBy({
|
||||
bool foldersToTop = true,
|
||||
SortOption sortOption = SortOption.name,
|
||||
bool reversed = false,
|
||||
}) {
|
||||
var list = List<CacheableFile>.empty(growable: true);
|
||||
|
||||
if(foldersToTop) {
|
||||
list.addAll(_sort(files.where((element) => element.isDirectory).toSet(), reversed: reversed, sortOption: sortOption));
|
||||
list.addAll(_sort(files.where((element) => !element.isDirectory).toSet(), reversed: reversed, sortOption: sortOption));
|
||||
} else {
|
||||
list.addAll(_sort(files, reversed: reversed, sortOption: sortOption));
|
||||
}
|
||||
|
||||
return list;
|
||||
if (foldersToTop) {
|
||||
list.addAll(
|
||||
_sort(
|
||||
files.where((element) => element.isDirectory).toSet(),
|
||||
reversed: reversed,
|
||||
sortOption: sortOption,
|
||||
),
|
||||
);
|
||||
list.addAll(
|
||||
_sort(
|
||||
files.where((element) => !element.isDirectory).toSet(),
|
||||
reversed: reversed,
|
||||
sortOption: sortOption,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
list.addAll(_sort(files, reversed: reversed, sortOption: sortOption));
|
||||
}
|
||||
|
||||
List<CacheableFile> _sort(Set<CacheableFile> files, {SortOption sortOption = SortOption.name, bool reversed = false}) {
|
||||
for (var file in files) {
|
||||
final buffer = StringBuffer();
|
||||
return list;
|
||||
}
|
||||
|
||||
switch(sortOption) {
|
||||
case SortOption.date:
|
||||
buffer.write(Jiffy.parseFromMillisecondsSinceEpoch(file.modifiedAt?.millisecondsSinceEpoch ?? 0).format(pattern: 'yyyyMMddhhmmss'));
|
||||
break;
|
||||
List<CacheableFile> _sort(
|
||||
Set<CacheableFile> files, {
|
||||
SortOption sortOption = SortOption.name,
|
||||
bool reversed = false,
|
||||
}) {
|
||||
for (var file in files) {
|
||||
final buffer = StringBuffer();
|
||||
|
||||
case SortOption.name:
|
||||
buffer.write(file.name.toLowerCase());
|
||||
break;
|
||||
switch (sortOption) {
|
||||
case SortOption.date:
|
||||
buffer.write(
|
||||
Jiffy.parseFromMillisecondsSinceEpoch(
|
||||
file.modifiedAt?.millisecondsSinceEpoch ?? 0,
|
||||
).format(pattern: 'yyyyMMddhhmmss'),
|
||||
);
|
||||
break;
|
||||
|
||||
case SortOption.size:
|
||||
buffer.write(file.size);
|
||||
break;
|
||||
}
|
||||
case SortOption.name:
|
||||
buffer.write(file.name.toLowerCase());
|
||||
break;
|
||||
|
||||
file.sort = buffer.toString();
|
||||
}
|
||||
case SortOption.size:
|
||||
buffer.write(file.size);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
var list = files.toList()..sort((a, b) => b.sort!.compareTo(a.sort!));
|
||||
return reversed ? list.reversed.toList() : list;
|
||||
file.sort = buffer.toString();
|
||||
}
|
||||
|
||||
var list = files.toList()..sort((a, b) => b.sort!.compareTo(a.sort!));
|
||||
return reversed ? list.reversed.toList() : list;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,12 @@ abstract class WebdavApi<T> extends ApiRequest {
|
||||
|
||||
static Future<WebDavClient> webdav = establishWebdavConnection();
|
||||
|
||||
static Future<WebDavClient> establishWebdavConnection() async => NextcloudClient(Uri.parse('https://${EndpointData().nextcloud().full()}'), password: AccountData().getPassword(), loginName: AccountData().getUsername()).webdav;
|
||||
static Future<WebDavClient> establishWebdavConnection() async =>
|
||||
NextcloudClient(
|
||||
Uri.parse('https://${EndpointData().nextcloud().full()}'),
|
||||
password: AccountData().getPassword(),
|
||||
loginName: AccountData().getUsername(),
|
||||
).webdav;
|
||||
|
||||
/// Builds the WebDAV download URL without embedded credentials. Callers must
|
||||
/// authenticate via the [AccountData.authHeaders] header instead.
|
||||
|
||||
@@ -9,9 +9,9 @@ class GetBreakers extends MhslApi<GetBreakersResponse> {
|
||||
GetBreakers() : super('breaker/');
|
||||
|
||||
@override
|
||||
GetBreakersResponse assemble(String raw) => GetBreakersResponse.fromJson(jsonDecode(raw) as Map<String, dynamic>);
|
||||
GetBreakersResponse assemble(String raw) =>
|
||||
GetBreakersResponse.fromJson(jsonDecode(raw) as Map<String, dynamic>);
|
||||
|
||||
@override
|
||||
Future<Response>? request(Uri uri) => http.get(uri);
|
||||
|
||||
}
|
||||
|
||||
@@ -4,11 +4,11 @@ import 'get_breakers_response.dart';
|
||||
|
||||
class GetBreakersCache extends SimpleCache<GetBreakersResponse> {
|
||||
GetBreakersCache({super.onUpdate, super.renew})
|
||||
: super(
|
||||
cacheTime: RequestCache.cacheMinute,
|
||||
loader: () => GetBreakers().run(),
|
||||
fromJson: GetBreakersResponse.fromJson,
|
||||
) {
|
||||
: super(
|
||||
cacheTime: RequestCache.cacheMinute,
|
||||
loader: () => GetBreakers().run(),
|
||||
fromJson: GetBreakersResponse.fromJson,
|
||||
) {
|
||||
start('breakers');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
import '../../../api_response.dart';
|
||||
@@ -12,7 +11,8 @@ class GetBreakersResponse extends ApiResponse {
|
||||
|
||||
GetBreakersResponse(this.global, this.regional);
|
||||
|
||||
factory GetBreakersResponse.fromJson(Map<String, dynamic> json) => _$GetBreakersResponseFromJson(json);
|
||||
factory GetBreakersResponse.fromJson(Map<String, dynamic> json) =>
|
||||
_$GetBreakersResponseFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$GetBreakersResponseToJson(this);
|
||||
}
|
||||
|
||||
@@ -23,14 +23,20 @@ class GetBreakersReponseObject {
|
||||
|
||||
GetBreakersReponseObject(this.areas, this.message);
|
||||
|
||||
factory GetBreakersReponseObject.fromJson(Map<String, dynamic> json) => _$GetBreakersReponseObjectFromJson(json);
|
||||
factory GetBreakersReponseObject.fromJson(Map<String, dynamic> json) =>
|
||||
_$GetBreakersReponseObjectFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$GetBreakersReponseObjectToJson(this);
|
||||
}
|
||||
|
||||
enum BreakerArea {
|
||||
@JsonValue('GLOBAL') global,
|
||||
@JsonValue('TIMETABLE') timetable,
|
||||
@JsonValue('TALK') talk,
|
||||
@JsonValue('FILES') files,
|
||||
@JsonValue('MORE') more,
|
||||
@JsonValue('GLOBAL')
|
||||
global,
|
||||
@JsonValue('TIMETABLE')
|
||||
timetable,
|
||||
@JsonValue('TALK')
|
||||
talk,
|
||||
@JsonValue('FILES')
|
||||
files,
|
||||
@JsonValue('MORE')
|
||||
more,
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import 'add_custom_timetable_event_params.dart';
|
||||
|
||||
class AddCustomTimetableEvent extends MhslApi<void> {
|
||||
AddCustomTimetableEventParams params;
|
||||
|
||||
|
||||
AddCustomTimetableEvent(this.params) : super('server/timetable/customEvents');
|
||||
|
||||
@override
|
||||
|
||||
@@ -11,6 +11,7 @@ class AddCustomTimetableEventParams {
|
||||
|
||||
AddCustomTimetableEventParams(this.user, this.event);
|
||||
|
||||
factory AddCustomTimetableEventParams.fromJson(Map<String, dynamic> json) => _$AddCustomTimetableEventParamsFromJson(json);
|
||||
factory AddCustomTimetableEventParams.fromJson(Map<String, dynamic> json) =>
|
||||
_$AddCustomTimetableEventParamsFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$AddCustomTimetableEventParamsToJson(this);
|
||||
}
|
||||
|
||||
@@ -20,9 +20,19 @@ class CustomTimetableEvent {
|
||||
@JsonKey(toJson: MhslApi.dateTimeToJson, fromJson: MhslApi.dateTimeFromJson)
|
||||
DateTime updatedAt;
|
||||
|
||||
CustomTimetableEvent({required this.id, required this.title, required this.description, required this.startDate,
|
||||
required this.endDate, required this.color, required this.rrule, required this.createdAt, required this.updatedAt});
|
||||
CustomTimetableEvent({
|
||||
required this.id,
|
||||
required this.title,
|
||||
required this.description,
|
||||
required this.startDate,
|
||||
required this.endDate,
|
||||
required this.color,
|
||||
required this.rrule,
|
||||
required this.createdAt,
|
||||
required this.updatedAt,
|
||||
});
|
||||
|
||||
factory CustomTimetableEvent.fromJson(Map<String, dynamic> json) => _$CustomTimetableEventFromJson(json);
|
||||
factory CustomTimetableEvent.fromJson(Map<String, dynamic> json) =>
|
||||
_$CustomTimetableEventFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$CustomTimetableEventToJson(this);
|
||||
}
|
||||
|
||||
@@ -9,10 +9,12 @@ import 'get_custom_timetable_event_response.dart';
|
||||
|
||||
class GetCustomTimetableEvent extends MhslApi<GetCustomTimetableEventResponse> {
|
||||
GetCustomTimetableEventParams params;
|
||||
GetCustomTimetableEvent(this.params) : super('server/timetable/customEvents?user=${params.user}');
|
||||
GetCustomTimetableEvent(this.params)
|
||||
: super('server/timetable/customEvents?user=${params.user}');
|
||||
|
||||
@override
|
||||
GetCustomTimetableEventResponse assemble(String raw) => GetCustomTimetableEventResponse.fromJson({'events': jsonDecode(raw)});
|
||||
GetCustomTimetableEventResponse assemble(String raw) =>
|
||||
GetCustomTimetableEventResponse.fromJson({'events': jsonDecode(raw)});
|
||||
|
||||
@override
|
||||
Future<Response>? request(Uri uri) => http.get(uri);
|
||||
|
||||
@@ -3,17 +3,18 @@ import 'get_custom_timetable_event.dart';
|
||||
import 'get_custom_timetable_event_params.dart';
|
||||
import 'get_custom_timetable_event_response.dart';
|
||||
|
||||
class GetCustomTimetableEventCache extends SimpleCache<GetCustomTimetableEventResponse> {
|
||||
class GetCustomTimetableEventCache
|
||||
extends SimpleCache<GetCustomTimetableEventResponse> {
|
||||
GetCustomTimetableEventCache(
|
||||
GetCustomTimetableEventParams params, {
|
||||
super.onUpdate,
|
||||
super.onError,
|
||||
super.renew,
|
||||
}) : super(
|
||||
cacheTime: RequestCache.cacheMinute,
|
||||
loader: () => GetCustomTimetableEvent(params).run(),
|
||||
fromJson: GetCustomTimetableEventResponse.fromJson,
|
||||
) {
|
||||
cacheTime: RequestCache.cacheMinute,
|
||||
loader: () => GetCustomTimetableEvent(params).run(),
|
||||
fromJson: GetCustomTimetableEventResponse.fromJson,
|
||||
) {
|
||||
start('customTimetableEvents');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ class GetCustomTimetableEventParams {
|
||||
|
||||
GetCustomTimetableEventParams(this.user);
|
||||
|
||||
factory GetCustomTimetableEventParams.fromJson(Map<String, dynamic> json) => _$GetCustomTimetableEventParamsFromJson(json);
|
||||
factory GetCustomTimetableEventParams.fromJson(Map<String, dynamic> json) =>
|
||||
_$GetCustomTimetableEventParamsFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$GetCustomTimetableEventParamsToJson(this);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@ class GetCustomTimetableEventResponse extends ApiResponse {
|
||||
|
||||
GetCustomTimetableEventResponse(this.events);
|
||||
|
||||
factory GetCustomTimetableEventResponse.fromJson(Map<String, dynamic> json) => _$GetCustomTimetableEventResponseFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$GetCustomTimetableEventResponseToJson(this);
|
||||
factory GetCustomTimetableEventResponse.fromJson(Map<String, dynamic> json) =>
|
||||
_$GetCustomTimetableEventResponseFromJson(json);
|
||||
Map<String, dynamic> toJson() =>
|
||||
_$GetCustomTimetableEventResponseToJson(this);
|
||||
}
|
||||
|
||||
@@ -9,11 +9,13 @@ import 'remove_custom_timetable_event_params.dart';
|
||||
class RemoveCustomTimetableEvent extends MhslApi<void> {
|
||||
RemoveCustomTimetableEventParams params;
|
||||
|
||||
RemoveCustomTimetableEvent(this.params) : super('server/timetable/customEvents');
|
||||
RemoveCustomTimetableEvent(this.params)
|
||||
: super('server/timetable/customEvents');
|
||||
|
||||
@override
|
||||
void assemble(String raw) {}
|
||||
|
||||
@override
|
||||
Future<Response>? request(Uri uri) => http.delete(uri, body: jsonEncode(params.toJson()));
|
||||
Future<Response>? request(Uri uri) =>
|
||||
http.delete(uri, body: jsonEncode(params.toJson()));
|
||||
}
|
||||
|
||||
+5
-2
@@ -8,6 +8,9 @@ class RemoveCustomTimetableEventParams {
|
||||
|
||||
RemoveCustomTimetableEventParams(this.id);
|
||||
|
||||
factory RemoveCustomTimetableEventParams.fromJson(Map<String, dynamic> json) => _$RemoveCustomTimetableEventParamsFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$RemoveCustomTimetableEventParamsToJson(this);
|
||||
factory RemoveCustomTimetableEventParams.fromJson(
|
||||
Map<String, dynamic> json,
|
||||
) => _$RemoveCustomTimetableEventParamsFromJson(json);
|
||||
Map<String, dynamic> toJson() =>
|
||||
_$RemoveCustomTimetableEventParamsToJson(this);
|
||||
}
|
||||
|
||||
@@ -9,11 +9,13 @@ import 'update_custom_timetable_event_params.dart';
|
||||
class UpdateCustomTimetableEvent extends MhslApi<void> {
|
||||
UpdateCustomTimetableEventParams params;
|
||||
|
||||
UpdateCustomTimetableEvent(this.params) : super('server/timetable/customEvents');
|
||||
UpdateCustomTimetableEvent(this.params)
|
||||
: super('server/timetable/customEvents');
|
||||
|
||||
@override
|
||||
void assemble(String raw) {}
|
||||
|
||||
@override
|
||||
Future<Response>? request(Uri uri) => http.patch(uri, body: jsonEncode(params.toJson()));
|
||||
Future<Response>? request(Uri uri) =>
|
||||
http.patch(uri, body: jsonEncode(params.toJson()));
|
||||
}
|
||||
|
||||
+5
-3
@@ -1,4 +1,3 @@
|
||||
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
import '../custom_timetable_event.dart';
|
||||
@@ -12,6 +11,9 @@ class UpdateCustomTimetableEventParams {
|
||||
|
||||
UpdateCustomTimetableEventParams(this.id, this.event);
|
||||
|
||||
factory UpdateCustomTimetableEventParams.fromJson(Map<String, dynamic> json) => _$UpdateCustomTimetableEventParamsFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$UpdateCustomTimetableEventParamsToJson(this);
|
||||
factory UpdateCustomTimetableEventParams.fromJson(
|
||||
Map<String, dynamic> json,
|
||||
) => _$UpdateCustomTimetableEventParamsFromJson(json);
|
||||
Map<String, dynamic> toJson() =>
|
||||
_$UpdateCustomTimetableEventParamsToJson(this);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,9 @@ abstract class MhslApi<T> extends ApiRequest {
|
||||
T assemble(String raw);
|
||||
|
||||
Future<T> run() async {
|
||||
final endpoint = Uri.parse('https://mhsl.eu/marianum/marianummobile/$subpath');
|
||||
final endpoint = Uri.parse(
|
||||
'https://mhsl.eu/marianum/marianummobile/$subpath',
|
||||
);
|
||||
|
||||
final http.Response data;
|
||||
try {
|
||||
@@ -54,6 +56,7 @@ abstract class MhslApi<T> extends ApiRequest {
|
||||
}
|
||||
}
|
||||
|
||||
static String dateTimeToJson(DateTime time) => Jiffy.parseFromDateTime(time).format(pattern: 'yyyy-MM-dd HH:mm:ss');
|
||||
static String dateTimeToJson(DateTime time) =>
|
||||
Jiffy.parseFromDateTime(time).format(pattern: 'yyyy-MM-dd HH:mm:ss');
|
||||
static DateTime dateTimeFromJson(String time) => DateTime.parse(time);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
import 'dart:convert';
|
||||
import 'dart:developer';
|
||||
|
||||
@@ -11,11 +10,8 @@ class NotifyRegister extends MhslApi<void> {
|
||||
NotifyRegisterParams params;
|
||||
NotifyRegister(this.params) : super('notify/register/');
|
||||
|
||||
|
||||
@override
|
||||
void assemble(String raw) {
|
||||
|
||||
}
|
||||
void assemble(String raw) {}
|
||||
|
||||
@override
|
||||
Future<http.Response> request(Uri uri) {
|
||||
|
||||
@@ -11,9 +11,10 @@ class NotifyRegisterParams {
|
||||
NotifyRegisterParams({
|
||||
required this.username,
|
||||
required this.password,
|
||||
required this.fcmToken
|
||||
required this.fcmToken,
|
||||
});
|
||||
|
||||
factory NotifyRegisterParams.fromJson(Map<String, dynamic> json) => _$NotifyRegisterParamsFromJson(json);
|
||||
factory NotifyRegisterParams.fromJson(Map<String, dynamic> json) =>
|
||||
_$NotifyRegisterParamsFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$NotifyRegisterParamsToJson(this);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import 'package:http/http.dart' as http;
|
||||
import '../../mhsl_api.dart';
|
||||
import 'add_feedback_params.dart';
|
||||
|
||||
|
||||
class AddFeedback extends MhslApi<void> {
|
||||
AddFeedbackParams params;
|
||||
AddFeedback(this.params) : super('server/feedback');
|
||||
@@ -15,5 +14,6 @@ class AddFeedback extends MhslApi<void> {
|
||||
void assemble(String raw) {}
|
||||
|
||||
@override
|
||||
Future<Response>? request(Uri uri) => http.post(uri, body: jsonEncode(params.toJson()));
|
||||
Future<Response>? request(Uri uri) =>
|
||||
http.post(uri, body: jsonEncode(params.toJson()));
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ class AddFeedbackParams {
|
||||
String? screenshot;
|
||||
int appVersion;
|
||||
|
||||
|
||||
AddFeedbackParams({
|
||||
required this.user,
|
||||
required this.feedback,
|
||||
@@ -17,6 +16,7 @@ class AddFeedbackParams {
|
||||
required this.appVersion,
|
||||
});
|
||||
|
||||
factory AddFeedbackParams.fromJson(Map<String, dynamic> json) => _$AddFeedbackParamsFromJson(json);
|
||||
factory AddFeedbackParams.fromJson(Map<String, dynamic> json) =>
|
||||
_$AddFeedbackParamsFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$AddFeedbackParamsToJson(this);
|
||||
}
|
||||
|
||||
@@ -10,15 +10,15 @@ class UpdateUserIndexParams {
|
||||
int appVersion;
|
||||
String deviceInfo;
|
||||
|
||||
|
||||
UpdateUserIndexParams({
|
||||
required this.user,
|
||||
required this.username,
|
||||
required this.device,
|
||||
required this.appVersion,
|
||||
required this.deviceInfo
|
||||
required this.deviceInfo,
|
||||
});
|
||||
|
||||
factory UpdateUserIndexParams.fromJson(Map<String, dynamic> json) => _$UpdateUserIndexParamsFromJson(json);
|
||||
factory UpdateUserIndexParams.fromJson(Map<String, dynamic> json) =>
|
||||
_$UpdateUserIndexParamsFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$UpdateUserIndexParamsToJson(this);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:developer';
|
||||
@@ -26,14 +25,18 @@ class UpdateUserIndex extends MhslApi<void> {
|
||||
}
|
||||
|
||||
static Future<void> index() async {
|
||||
unawaited(UpdateUserIndex(
|
||||
UpdateUserIndexParams(
|
||||
username: AccountData().getUsername(),
|
||||
user: AccountData().getUserSecret(),
|
||||
device: await AccountData().getDeviceId(),
|
||||
appVersion: int.parse((await PackageInfo.fromPlatform()).buildNumber),
|
||||
deviceInfo: jsonEncode((await DeviceInfoPlugin().deviceInfo).data).toString(),
|
||||
),
|
||||
).run());
|
||||
unawaited(
|
||||
UpdateUserIndex(
|
||||
UpdateUserIndexParams(
|
||||
username: AccountData().getUsername(),
|
||||
user: AccountData().getUserSecret(),
|
||||
device: await AccountData().getDeviceId(),
|
||||
appVersion: int.parse((await PackageInfo.fromPlatform()).buildNumber),
|
||||
deviceInfo: jsonEncode(
|
||||
(await DeviceInfoPlugin().deviceInfo).data,
|
||||
).toString(),
|
||||
),
|
||||
).run(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+36
-27
@@ -49,7 +49,10 @@ abstract class RequestCache<T extends ApiResponse?> {
|
||||
|
||||
Future<void> start(String document) async {
|
||||
try {
|
||||
final tableData = await Localstore.instance.collection(collection).doc(document).get();
|
||||
final tableData = await Localstore.instance
|
||||
.collection(collection)
|
||||
.doc(document)
|
||||
.get();
|
||||
if (tableData != null) {
|
||||
final cached = onLocalData(tableData['json'] as String);
|
||||
onUpdate?.call(cached);
|
||||
@@ -57,7 +60,8 @@ abstract class RequestCache<T extends ApiResponse?> {
|
||||
}
|
||||
|
||||
final lastUpdate = (tableData?['lastupdate'] as num?) ?? 0;
|
||||
if (DateTime.now().millisecondsSinceEpoch - (maxCacheTime * 1000) < lastUpdate) {
|
||||
if (DateTime.now().millisecondsSinceEpoch - (maxCacheTime * 1000) <
|
||||
lastUpdate) {
|
||||
if (renew == null || !renew!) return;
|
||||
}
|
||||
|
||||
@@ -65,10 +69,12 @@ abstract class RequestCache<T extends ApiResponse?> {
|
||||
final newValue = await onLoad();
|
||||
onUpdate?.call(newValue);
|
||||
onNetworkData?.call(newValue);
|
||||
unawaited(Localstore.instance.collection(collection).doc(document).set({
|
||||
'json': jsonEncode(newValue),
|
||||
'lastupdate': DateTime.now().millisecondsSinceEpoch,
|
||||
}));
|
||||
unawaited(
|
||||
Localstore.instance.collection(collection).doc(document).set({
|
||||
'json': jsonEncode(newValue),
|
||||
'lastupdate': DateTime.now().millisecondsSinceEpoch,
|
||||
}),
|
||||
);
|
||||
} on Exception catch (e) {
|
||||
onError(e);
|
||||
}
|
||||
@@ -79,7 +85,6 @@ abstract class RequestCache<T extends ApiResponse?> {
|
||||
|
||||
T onLocalData(String json);
|
||||
Future<T> onLoad();
|
||||
|
||||
}
|
||||
|
||||
/// Concrete [RequestCache] that takes the two overrides as constructor
|
||||
@@ -97,22 +102,23 @@ class SimpleCache<T extends ApiResponse?> extends RequestCache<T> {
|
||||
void Function(T)? onNetworkData,
|
||||
void Function(Exception)? onError,
|
||||
bool? renew,
|
||||
}) : _loader = loader,
|
||||
_fromJson = fromJson,
|
||||
super(
|
||||
cacheTime,
|
||||
onUpdate,
|
||||
onError: onError ?? RequestCache.ignore,
|
||||
renew: renew,
|
||||
onCacheData: onCacheData,
|
||||
onNetworkData: onNetworkData,
|
||||
);
|
||||
}) : _loader = loader,
|
||||
_fromJson = fromJson,
|
||||
super(
|
||||
cacheTime,
|
||||
onUpdate,
|
||||
onError: onError ?? RequestCache.ignore,
|
||||
renew: renew,
|
||||
onCacheData: onCacheData,
|
||||
onNetworkData: onNetworkData,
|
||||
);
|
||||
|
||||
@override
|
||||
Future<T> onLoad() => _loader();
|
||||
|
||||
@override
|
||||
T onLocalData(String json) => _fromJson(jsonDecode(json) as Map<String, dynamic>);
|
||||
T onLocalData(String json) =>
|
||||
_fromJson(jsonDecode(json) as Map<String, dynamic>);
|
||||
}
|
||||
|
||||
/// Captures the latest cache payload (cached or network) and rethrows the
|
||||
@@ -120,24 +126,27 @@ class SimpleCache<T extends ApiResponse?> extends RequestCache<T> {
|
||||
/// `latest`/`capturedError`/`await ready` boilerplate that DataProviders
|
||||
/// otherwise repeat per endpoint.
|
||||
Future<T> resolveFromCache<T extends ApiResponse?>(
|
||||
RequestCache<T> Function(void Function(T) onUpdate, void Function(Exception) onError) build, {
|
||||
RequestCache<T> Function(
|
||||
void Function(T) onUpdate,
|
||||
void Function(Exception) onError,
|
||||
)
|
||||
build, {
|
||||
void Function(Object)? onError,
|
||||
String? operationName,
|
||||
}) async {
|
||||
T? latest;
|
||||
Object? capturedError;
|
||||
final cache = build(
|
||||
(data) => latest = data,
|
||||
(e) {
|
||||
capturedError = e;
|
||||
onError?.call(e);
|
||||
},
|
||||
);
|
||||
final cache = build((data) => latest = data, (e) {
|
||||
capturedError = e;
|
||||
onError?.call(e);
|
||||
});
|
||||
await cache.ready;
|
||||
if (latest != null) return latest as T;
|
||||
final err = capturedError;
|
||||
if (err != null) throw err;
|
||||
throw ParseException(
|
||||
technicalDetails: operationName != null ? 'No data and no error from $operationName' : null,
|
||||
technicalDetails: operationName != null
|
||||
? 'No data and no error from $operationName'
|
||||
: null,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,8 @@ import 'authenticate_response.dart';
|
||||
class Authenticate extends WebuntisApi {
|
||||
AuthenticateParams param;
|
||||
|
||||
Authenticate(this.param) : super('authenticate', param, authenticatedResponse: false);
|
||||
Authenticate(this.param)
|
||||
: super('authenticate', param, authenticatedResponse: false);
|
||||
|
||||
@override
|
||||
Future<AuthenticateResponse> run() async {
|
||||
@@ -17,7 +18,11 @@ class Authenticate extends WebuntisApi {
|
||||
try {
|
||||
final rawAnswer = await query(this);
|
||||
final decoded = jsonDecode(rawAnswer) as Map<String, dynamic>;
|
||||
final response = finalize(AuthenticateResponse.fromJson(decoded['result'] as Map<String, dynamic>));
|
||||
final response = finalize(
|
||||
AuthenticateResponse.fromJson(
|
||||
decoded['result'] as Map<String, dynamic>,
|
||||
),
|
||||
);
|
||||
_lastResponse = response;
|
||||
if (!awaitedResponse.isCompleted) awaitedResponse.complete();
|
||||
return response;
|
||||
@@ -40,23 +45,22 @@ class Authenticate extends WebuntisApi {
|
||||
|
||||
static Future<void> createSession() async {
|
||||
_lastResponse = await Authenticate(
|
||||
AuthenticateParams(
|
||||
user: AccountData().getUsername(),
|
||||
password: AccountData().getPassword(),
|
||||
)
|
||||
AuthenticateParams(
|
||||
user: AccountData().getUsername(),
|
||||
password: AccountData().getPassword(),
|
||||
),
|
||||
).run();
|
||||
}
|
||||
|
||||
static Future<AuthenticateResponse> getSession() async {
|
||||
if(awaitingResponse) {
|
||||
if (awaitingResponse) {
|
||||
await awaitedResponse.future;
|
||||
}
|
||||
|
||||
if(_lastResponse == null) {
|
||||
if (_lastResponse == null) {
|
||||
awaitingResponse = true;
|
||||
await createSession();
|
||||
}
|
||||
return _lastResponse!;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,12 +6,12 @@ part 'authenticate_params.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class AuthenticateParams extends ApiParams {
|
||||
|
||||
String user;
|
||||
String password;
|
||||
|
||||
AuthenticateParams({required this.user, required this.password});
|
||||
factory AuthenticateParams.fromJson(Map<String, dynamic> json) => _$AuthenticateParamsFromJson(json);
|
||||
factory AuthenticateParams.fromJson(Map<String, dynamic> json) =>
|
||||
_$AuthenticateParamsFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => _$AuthenticateParamsToJson(this);
|
||||
}
|
||||
|
||||
@@ -6,14 +6,19 @@ part 'authenticate_response.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class AuthenticateResponse extends ApiResponse {
|
||||
|
||||
String sessionId;
|
||||
int personType;
|
||||
int personId;
|
||||
int klasseId;
|
||||
|
||||
AuthenticateResponse(this.sessionId, this.personType, this.personId, this.klasseId);
|
||||
AuthenticateResponse(
|
||||
this.sessionId,
|
||||
this.personType,
|
||||
this.personId,
|
||||
this.klasseId,
|
||||
);
|
||||
|
||||
factory AuthenticateResponse.fromJson(Map<String, dynamic> json) => _$AuthenticateResponseFromJson(json);
|
||||
factory AuthenticateResponse.fromJson(Map<String, dynamic> json) =>
|
||||
_$AuthenticateResponseFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$AuthenticateResponseToJson(this);
|
||||
}
|
||||
|
||||
@@ -9,10 +9,17 @@ class GetHolidays extends WebuntisApi {
|
||||
@override
|
||||
Future<GetHolidaysResponse> run() async {
|
||||
final rawAnswer = await query(this);
|
||||
return finalize(GetHolidaysResponse.fromJson(jsonDecode(rawAnswer) as Map<String, dynamic>));
|
||||
return finalize(
|
||||
GetHolidaysResponse.fromJson(
|
||||
jsonDecode(rawAnswer) as Map<String, dynamic>,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
static GetHolidaysResponseObject? find(GetHolidaysResponse holidaysResponse, {DateTime? time}) {
|
||||
static GetHolidaysResponseObject? find(
|
||||
GetHolidaysResponse holidaysResponse, {
|
||||
DateTime? time,
|
||||
}) {
|
||||
time ??= DateTime.now();
|
||||
time = DateTime(time.year, time.month, time.day, 0, 0, 0, 0, 0);
|
||||
|
||||
@@ -20,9 +27,8 @@ class GetHolidays extends WebuntisApi {
|
||||
var start = DateTime.parse(element.startDate.toString());
|
||||
var end = DateTime.parse(element.endDate.toString());
|
||||
|
||||
if(!start.isAfter(time) && !end.isBefore(time)) return element;
|
||||
if (!start.isAfter(time) && !end.isBefore(time)) return element;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,11 +4,11 @@ import 'get_holidays_response.dart';
|
||||
|
||||
class GetHolidaysCache extends SimpleCache<GetHolidaysResponse> {
|
||||
GetHolidaysCache({super.onUpdate, super.onError, super.renew})
|
||||
: super(
|
||||
cacheTime: RequestCache.cacheDay,
|
||||
loader: () => GetHolidays().run(),
|
||||
fromJson: GetHolidaysResponse.fromJson,
|
||||
) {
|
||||
: super(
|
||||
cacheTime: RequestCache.cacheDay,
|
||||
loader: () => GetHolidays().run(),
|
||||
fromJson: GetHolidaysResponse.fromJson,
|
||||
) {
|
||||
start('wu-holidays');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,8 @@ class GetHolidaysResponse extends ApiResponse {
|
||||
|
||||
GetHolidaysResponse(this.result);
|
||||
|
||||
factory GetHolidaysResponse.fromJson(Map<String, dynamic> json) => _$GetHolidaysResponseFromJson(json);
|
||||
factory GetHolidaysResponse.fromJson(Map<String, dynamic> json) =>
|
||||
_$GetHolidaysResponseFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$GetHolidaysResponseToJson(this);
|
||||
}
|
||||
|
||||
@@ -22,8 +23,15 @@ class GetHolidaysResponseObject {
|
||||
int startDate;
|
||||
int endDate;
|
||||
|
||||
GetHolidaysResponseObject(this.id, this.name, this.longName, this.startDate, this.endDate);
|
||||
GetHolidaysResponseObject(
|
||||
this.id,
|
||||
this.name,
|
||||
this.longName,
|
||||
this.startDate,
|
||||
this.endDate,
|
||||
);
|
||||
|
||||
factory GetHolidaysResponseObject.fromJson(Map<String, dynamic> json) => _$GetHolidaysResponseObjectFromJson(json);
|
||||
factory GetHolidaysResponseObject.fromJson(Map<String, dynamic> json) =>
|
||||
_$GetHolidaysResponseObjectFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$GetHolidaysResponseObjectToJson(this);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,11 @@ class GetRooms extends WebuntisApi {
|
||||
Future<GetRoomsResponse> run() async {
|
||||
final rawAnswer = await query(this);
|
||||
try {
|
||||
return finalize(GetRoomsResponse.fromJson(jsonDecode(rawAnswer) as Map<String, dynamic>));
|
||||
return finalize(
|
||||
GetRoomsResponse.fromJson(
|
||||
jsonDecode(rawAnswer) as Map<String, dynamic>,
|
||||
),
|
||||
);
|
||||
} catch (e, trace) {
|
||||
log(trace.toString());
|
||||
log('Failed to parse getRoom data with server response: $rawAnswer');
|
||||
@@ -19,5 +23,4 @@ class GetRooms extends WebuntisApi {
|
||||
|
||||
throw Exception('Failed to parse getRoom server response: $rawAnswer');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,11 +4,11 @@ import 'get_rooms_response.dart';
|
||||
|
||||
class GetRoomsCache extends SimpleCache<GetRoomsResponse> {
|
||||
GetRoomsCache({super.onUpdate, super.onError, super.renew})
|
||||
: super(
|
||||
cacheTime: RequestCache.cacheHour,
|
||||
loader: () => GetRooms().run(),
|
||||
fromJson: GetRoomsResponse.fromJson,
|
||||
) {
|
||||
: super(
|
||||
cacheTime: RequestCache.cacheHour,
|
||||
loader: () => GetRooms().run(),
|
||||
fromJson: GetRoomsResponse.fromJson,
|
||||
) {
|
||||
start('wu-rooms');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,8 @@ class GetRoomsResponse extends ApiResponse {
|
||||
|
||||
GetRoomsResponse(this.result);
|
||||
|
||||
factory GetRoomsResponse.fromJson(Map<String, dynamic> json) => _$GetRoomsResponseFromJson(json);
|
||||
factory GetRoomsResponse.fromJson(Map<String, dynamic> json) =>
|
||||
_$GetRoomsResponseFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$GetRoomsResponseToJson(this);
|
||||
}
|
||||
|
||||
@@ -22,8 +23,15 @@ class GetRoomsResponseObject {
|
||||
bool active;
|
||||
String building;
|
||||
|
||||
GetRoomsResponseObject(this.id, this.name, this.longName, this.active, this.building);
|
||||
GetRoomsResponseObject(
|
||||
this.id,
|
||||
this.name,
|
||||
this.longName,
|
||||
this.active,
|
||||
this.building,
|
||||
);
|
||||
|
||||
factory GetRoomsResponseObject.fromJson(Map<String, dynamic> json) => _$GetRoomsResponseObjectFromJson(json);
|
||||
factory GetRoomsResponseObject.fromJson(Map<String, dynamic> json) =>
|
||||
_$GetRoomsResponseObjectFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$GetRoomsResponseObjectToJson(this);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,10 @@ class GetSubjects extends WebuntisApi {
|
||||
@override
|
||||
Future<GetSubjectsResponse> run() async {
|
||||
final rawAnswer = await query(this);
|
||||
return finalize(GetSubjectsResponse.fromJson(jsonDecode(rawAnswer) as Map<String, dynamic>));
|
||||
return finalize(
|
||||
GetSubjectsResponse.fromJson(
|
||||
jsonDecode(rawAnswer) as Map<String, dynamic>,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,11 +4,11 @@ import 'get_subjects_response.dart';
|
||||
|
||||
class GetSubjectsCache extends SimpleCache<GetSubjectsResponse> {
|
||||
GetSubjectsCache({super.onUpdate, super.onError, super.renew})
|
||||
: super(
|
||||
cacheTime: RequestCache.cacheHour,
|
||||
loader: () => GetSubjects().run(),
|
||||
fromJson: GetSubjectsResponse.fromJson,
|
||||
) {
|
||||
: super(
|
||||
cacheTime: RequestCache.cacheHour,
|
||||
loader: () => GetSubjects().run(),
|
||||
fromJson: GetSubjectsResponse.fromJson,
|
||||
) {
|
||||
start('wu-subjects');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,8 @@ class GetSubjectsResponse extends ApiResponse {
|
||||
|
||||
GetSubjectsResponse(this.result);
|
||||
|
||||
factory GetSubjectsResponse.fromJson(Map<String, dynamic> json) => _$GetSubjectsResponseFromJson(json);
|
||||
factory GetSubjectsResponse.fromJson(Map<String, dynamic> json) =>
|
||||
_$GetSubjectsResponseFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$GetSubjectsResponseToJson(this);
|
||||
}
|
||||
|
||||
@@ -22,8 +23,15 @@ class GetSubjectsResponseObject {
|
||||
String alternateName;
|
||||
bool active;
|
||||
|
||||
GetSubjectsResponseObject(this.id, this.name, this.longName, this.alternateName, this.active);
|
||||
GetSubjectsResponseObject(
|
||||
this.id,
|
||||
this.name,
|
||||
this.longName,
|
||||
this.alternateName,
|
||||
this.active,
|
||||
);
|
||||
|
||||
factory GetSubjectsResponseObject.fromJson(Map<String, dynamic> json) => _$GetSubjectsResponseObjectFromJson(json);
|
||||
factory GetSubjectsResponseObject.fromJson(Map<String, dynamic> json) =>
|
||||
_$GetSubjectsResponseObjectFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$GetSubjectsResponseObjectToJson(this);
|
||||
}
|
||||
|
||||
@@ -11,12 +11,20 @@ class GetTimegridUnits extends WebuntisApi {
|
||||
Future<GetTimegridUnitsResponse> run() async {
|
||||
final rawAnswer = await query(this);
|
||||
try {
|
||||
return finalize(GetTimegridUnitsResponse.fromJson(jsonDecode(rawAnswer) as Map<String, dynamic>));
|
||||
return finalize(
|
||||
GetTimegridUnitsResponse.fromJson(
|
||||
jsonDecode(rawAnswer) as Map<String, dynamic>,
|
||||
),
|
||||
);
|
||||
} catch (e, trace) {
|
||||
log(trace.toString());
|
||||
log('Failed to parse getTimegridUnits data with server response: $rawAnswer');
|
||||
log(
|
||||
'Failed to parse getTimegridUnits data with server response: $rawAnswer',
|
||||
);
|
||||
}
|
||||
|
||||
throw Exception('Failed to parse getTimegridUnits server response: $rawAnswer');
|
||||
throw Exception(
|
||||
'Failed to parse getTimegridUnits server response: $rawAnswer',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,11 +4,11 @@ import 'get_timegrid_units_response.dart';
|
||||
|
||||
class GetTimegridUnitsCache extends SimpleCache<GetTimegridUnitsResponse> {
|
||||
GetTimegridUnitsCache({super.onUpdate, super.renew})
|
||||
: super(
|
||||
cacheTime: RequestCache.cacheDay,
|
||||
loader: () => GetTimegridUnits().run(),
|
||||
fromJson: GetTimegridUnitsResponse.fromJson,
|
||||
) {
|
||||
: super(
|
||||
cacheTime: RequestCache.cacheDay,
|
||||
loader: () => GetTimegridUnits().run(),
|
||||
fromJson: GetTimegridUnitsResponse.fromJson,
|
||||
) {
|
||||
start('wu-timegrid');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,8 @@ class GetTimegridUnitsResponse extends ApiResponse {
|
||||
|
||||
GetTimegridUnitsResponse(this.result);
|
||||
|
||||
factory GetTimegridUnitsResponse.fromJson(Map<String, dynamic> json) => _$GetTimegridUnitsResponseFromJson(json);
|
||||
factory GetTimegridUnitsResponse.fromJson(Map<String, dynamic> json) =>
|
||||
_$GetTimegridUnitsResponseFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$GetTimegridUnitsResponseToJson(this);
|
||||
}
|
||||
|
||||
@@ -21,7 +22,8 @@ class GetTimegridUnitsResponseDay {
|
||||
|
||||
GetTimegridUnitsResponseDay(this.day, this.timeUnits);
|
||||
|
||||
factory GetTimegridUnitsResponseDay.fromJson(Map<String, dynamic> json) => _$GetTimegridUnitsResponseDayFromJson(json);
|
||||
factory GetTimegridUnitsResponseDay.fromJson(Map<String, dynamic> json) =>
|
||||
_$GetTimegridUnitsResponseDayFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$GetTimegridUnitsResponseDayToJson(this);
|
||||
}
|
||||
|
||||
@@ -33,6 +35,7 @@ class GetTimegridUnitsResponseUnit {
|
||||
|
||||
GetTimegridUnitsResponseUnit(this.name, this.startTime, this.endTime);
|
||||
|
||||
factory GetTimegridUnitsResponseUnit.fromJson(Map<String, dynamic> json) => _$GetTimegridUnitsResponseUnitFromJson(json);
|
||||
factory GetTimegridUnitsResponseUnit.fromJson(Map<String, dynamic> json) =>
|
||||
_$GetTimegridUnitsResponseUnitFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$GetTimegridUnitsResponseUnitToJson(this);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,10 @@ class GetTimetable extends WebuntisApi {
|
||||
@override
|
||||
Future<GetTimetableResponse> run() async {
|
||||
final rawAnswer = await query(this);
|
||||
return finalize(GetTimetableResponse.fromJson(jsonDecode(rawAnswer) as Map<String, dynamic>));
|
||||
return finalize(
|
||||
GetTimetableResponse.fromJson(
|
||||
jsonDecode(rawAnswer) as Map<String, dynamic>,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,11 +12,11 @@ class GetTimetableCache extends SimpleCache<GetTimetableResponse> {
|
||||
required int enddate,
|
||||
super.renew,
|
||||
}) : super(
|
||||
cacheTime: RequestCache.cacheMinute,
|
||||
loader: () => _load(startdate, enddate),
|
||||
fromJson: GetTimetableResponse.fromJson,
|
||||
onUpdate: onUpdate,
|
||||
) {
|
||||
cacheTime: RequestCache.cacheMinute,
|
||||
loader: () => _load(startdate, enddate),
|
||||
fromJson: GetTimetableResponse.fromJson,
|
||||
onUpdate: onUpdate,
|
||||
) {
|
||||
start('wu-timetable-$startdate-$enddate');
|
||||
}
|
||||
|
||||
|
||||
@@ -10,11 +10,11 @@ class GetTimetableParams extends ApiParams {
|
||||
|
||||
GetTimetableParams({required this.options});
|
||||
|
||||
factory GetTimetableParams.fromJson(Map<String, dynamic> json) => _$GetTimetableParamsFromJson(json);
|
||||
factory GetTimetableParams.fromJson(Map<String, dynamic> json) =>
|
||||
_$GetTimetableParamsFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$GetTimetableParamsToJson(this);
|
||||
}
|
||||
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class GetTimetableParamsOptions {
|
||||
GetTimetableParamsOptionsElement element;
|
||||
@@ -59,20 +59,30 @@ class GetTimetableParamsOptions {
|
||||
this.klasseFields,
|
||||
this.roomFields,
|
||||
this.subjectFields,
|
||||
this.teacherFields
|
||||
this.teacherFields,
|
||||
});
|
||||
|
||||
factory GetTimetableParamsOptions.fromJson(Map<String, dynamic> json) => _$GetTimetableParamsOptionsFromJson(json);
|
||||
factory GetTimetableParamsOptions.fromJson(Map<String, dynamic> json) =>
|
||||
_$GetTimetableParamsOptionsFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$GetTimetableParamsOptionsToJson(this);
|
||||
}
|
||||
|
||||
enum GetTimetableParamsOptionsFields {
|
||||
@JsonValue('id') id,
|
||||
@JsonValue('name') name,
|
||||
@JsonValue('longname') longname,
|
||||
@JsonValue('externalkey') externalkey;
|
||||
@JsonValue('id')
|
||||
id,
|
||||
@JsonValue('name')
|
||||
name,
|
||||
@JsonValue('longname')
|
||||
longname,
|
||||
@JsonValue('externalkey')
|
||||
externalkey;
|
||||
|
||||
static List<GetTimetableParamsOptionsFields> all = [id, name, longname, externalkey];
|
||||
static List<GetTimetableParamsOptionsFields> all = [
|
||||
id,
|
||||
name,
|
||||
longname,
|
||||
externalkey,
|
||||
];
|
||||
}
|
||||
|
||||
@JsonSerializable()
|
||||
@@ -82,13 +92,23 @@ class GetTimetableParamsOptionsElement {
|
||||
@JsonKey(includeIfNull: false)
|
||||
GetTimetableParamsOptionsElementKeyType? keyType;
|
||||
|
||||
GetTimetableParamsOptionsElement({required this.id, required this.type, this.keyType});
|
||||
factory GetTimetableParamsOptionsElement.fromJson(Map<String, dynamic> json) => _$GetTimetableParamsOptionsElementFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$GetTimetableParamsOptionsElementToJson(this);
|
||||
GetTimetableParamsOptionsElement({
|
||||
required this.id,
|
||||
required this.type,
|
||||
this.keyType,
|
||||
});
|
||||
factory GetTimetableParamsOptionsElement.fromJson(
|
||||
Map<String, dynamic> json,
|
||||
) => _$GetTimetableParamsOptionsElementFromJson(json);
|
||||
Map<String, dynamic> toJson() =>
|
||||
_$GetTimetableParamsOptionsElementToJson(this);
|
||||
}
|
||||
|
||||
enum GetTimetableParamsOptionsElementKeyType {
|
||||
@JsonValue('id') id,
|
||||
@JsonValue('name') name,
|
||||
@JsonValue('externalkey') externalkey
|
||||
@JsonValue('id')
|
||||
id,
|
||||
@JsonValue('name')
|
||||
name,
|
||||
@JsonValue('externalkey')
|
||||
externalkey,
|
||||
}
|
||||
|
||||
@@ -10,9 +10,9 @@ class GetTimetableResponse extends ApiResponse {
|
||||
|
||||
GetTimetableResponse(this.result);
|
||||
|
||||
factory GetTimetableResponse.fromJson(Map<String, dynamic> json) => _$GetTimetableResponseFromJson(json);
|
||||
factory GetTimetableResponse.fromJson(Map<String, dynamic> json) =>
|
||||
_$GetTimetableResponseFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$GetTimetableResponseToJson(this);
|
||||
|
||||
}
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
@@ -55,10 +55,11 @@ class GetTimetableResponseObject {
|
||||
required this.kl,
|
||||
required this.te,
|
||||
required this.su,
|
||||
required this.ro
|
||||
required this.ro,
|
||||
});
|
||||
|
||||
factory GetTimetableResponseObject.fromJson(Map<String, dynamic> json) => _$GetTimetableResponseObjectFromJson(json);
|
||||
factory GetTimetableResponseObject.fromJson(Map<String, dynamic> json) =>
|
||||
_$GetTimetableResponseObjectFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$GetTimetableResponseObjectToJson(this);
|
||||
}
|
||||
|
||||
@@ -68,8 +69,11 @@ class GetTimetableResponseObjectFields {
|
||||
|
||||
GetTimetableResponseObjectFields(this.te);
|
||||
|
||||
factory GetTimetableResponseObjectFields.fromJson(Map<String, dynamic> json) => _$GetTimetableResponseObjectFieldsFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$GetTimetableResponseObjectFieldsToJson(this);
|
||||
factory GetTimetableResponseObjectFields.fromJson(
|
||||
Map<String, dynamic> json,
|
||||
) => _$GetTimetableResponseObjectFieldsFromJson(json);
|
||||
Map<String, dynamic> toJson() =>
|
||||
_$GetTimetableResponseObjectFieldsToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable()
|
||||
@@ -79,10 +83,18 @@ class GetTimetableResponseObjectFieldsObject {
|
||||
String? longname;
|
||||
String? externalkey;
|
||||
|
||||
GetTimetableResponseObjectFieldsObject({this.id, this.name, this.longname, this.externalkey});
|
||||
GetTimetableResponseObjectFieldsObject({
|
||||
this.id,
|
||||
this.name,
|
||||
this.longname,
|
||||
this.externalkey,
|
||||
});
|
||||
|
||||
factory GetTimetableResponseObjectFieldsObject.fromJson(Map<String, dynamic> json) => _$GetTimetableResponseObjectFieldsObjectFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$GetTimetableResponseObjectFieldsObjectToJson(this);
|
||||
factory GetTimetableResponseObjectFieldsObject.fromJson(
|
||||
Map<String, dynamic> json,
|
||||
) => _$GetTimetableResponseObjectFieldsObjectFromJson(json);
|
||||
Map<String, dynamic> toJson() =>
|
||||
_$GetTimetableResponseObjectFieldsObjectToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable()
|
||||
@@ -92,10 +104,17 @@ class GetTimetableResponseObjectClass {
|
||||
String longname;
|
||||
String? externalkey;
|
||||
|
||||
GetTimetableResponseObjectClass(this.id, this.name, this.longname, this.externalkey);
|
||||
GetTimetableResponseObjectClass(
|
||||
this.id,
|
||||
this.name,
|
||||
this.longname,
|
||||
this.externalkey,
|
||||
);
|
||||
|
||||
factory GetTimetableResponseObjectClass.fromJson(Map<String, dynamic> json) => _$GetTimetableResponseObjectClassFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$GetTimetableResponseObjectClassToJson(this);
|
||||
factory GetTimetableResponseObjectClass.fromJson(Map<String, dynamic> json) =>
|
||||
_$GetTimetableResponseObjectClassFromJson(json);
|
||||
Map<String, dynamic> toJson() =>
|
||||
_$GetTimetableResponseObjectClassToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable()
|
||||
@@ -107,11 +126,20 @@ class GetTimetableResponseObjectTeacher {
|
||||
String? orgname;
|
||||
String? externalkey;
|
||||
|
||||
GetTimetableResponseObjectTeacher(
|
||||
this.id,
|
||||
this.name,
|
||||
this.longname,
|
||||
this.orgid,
|
||||
this.orgname,
|
||||
this.externalkey,
|
||||
);
|
||||
|
||||
GetTimetableResponseObjectTeacher(this.id, this.name, this.longname, this.orgid, this.orgname, this.externalkey);
|
||||
|
||||
factory GetTimetableResponseObjectTeacher.fromJson(Map<String, dynamic> json) => _$GetTimetableResponseObjectTeacherFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$GetTimetableResponseObjectTeacherToJson(this);
|
||||
factory GetTimetableResponseObjectTeacher.fromJson(
|
||||
Map<String, dynamic> json,
|
||||
) => _$GetTimetableResponseObjectTeacherFromJson(json);
|
||||
Map<String, dynamic> toJson() =>
|
||||
_$GetTimetableResponseObjectTeacherToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable()
|
||||
@@ -122,8 +150,11 @@ class GetTimetableResponseObjectSubject {
|
||||
|
||||
GetTimetableResponseObjectSubject(this.id, this.name, this.longname);
|
||||
|
||||
factory GetTimetableResponseObjectSubject.fromJson(Map<String, dynamic> json) => _$GetTimetableResponseObjectSubjectFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$GetTimetableResponseObjectSubjectToJson(this);
|
||||
factory GetTimetableResponseObjectSubject.fromJson(
|
||||
Map<String, dynamic> json,
|
||||
) => _$GetTimetableResponseObjectSubjectFromJson(json);
|
||||
Map<String, dynamic> toJson() =>
|
||||
_$GetTimetableResponseObjectSubjectToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable()
|
||||
@@ -134,6 +165,7 @@ class GetTimetableResponseObjectRoom {
|
||||
|
||||
GetTimetableResponseObjectRoom(this.id, this.name, this.longname);
|
||||
|
||||
factory GetTimetableResponseObjectRoom.fromJson(Map<String, dynamic> json) => _$GetTimetableResponseObjectRoomFromJson(json);
|
||||
factory GetTimetableResponseObjectRoom.fromJson(Map<String, dynamic> json) =>
|
||||
_$GetTimetableResponseObjectRoomFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$GetTimetableResponseObjectRoomToJson(this);
|
||||
}
|
||||
|
||||
@@ -9,10 +9,14 @@ import '../queries/get_subjects/get_subjects_response.dart';
|
||||
/// When a record is missing the resolver returns a placeholder fallback
|
||||
/// instead of `null` so call sites stay branch-free.
|
||||
class LessonResolver {
|
||||
static GetSubjectsResponseObject resolveSubject(TimetableState state, int? id) {
|
||||
static GetSubjectsResponseObject resolveSubject(
|
||||
TimetableState state,
|
||||
int? id,
|
||||
) {
|
||||
final fallback = GetSubjectsResponseObject(0, '?', 'Unbekannt', '?', true);
|
||||
if (id == null) return fallback;
|
||||
return state.subjects?.result.firstWhereOrNull((s) => s.id == id) ?? fallback;
|
||||
return state.subjects?.result.firstWhereOrNull((s) => s.id == id) ??
|
||||
fallback;
|
||||
}
|
||||
|
||||
static GetRoomsResponseObject resolveRoom(TimetableState state, int? id) {
|
||||
@@ -61,9 +65,7 @@ class LessonFormatter {
|
||||
/// optional longname (rendered in parentheses if it differs from `name`),
|
||||
/// and optional extra info (joined with `·`).
|
||||
static String formatLine(String name, {String? longname, String? extra}) {
|
||||
final parts = <String>[
|
||||
if (name.isNotEmpty) name else '?',
|
||||
];
|
||||
final parts = <String>[if (name.isNotEmpty) name else '?'];
|
||||
final ln = (longname ?? '').trim();
|
||||
if (ln.isNotEmpty && ln != name) parts.add('($ln)');
|
||||
final ex = (extra ?? '').trim();
|
||||
|
||||
@@ -14,18 +14,24 @@ import 'queries/authenticate/authenticate.dart';
|
||||
import 'webuntis_error.dart';
|
||||
|
||||
abstract class WebuntisApi extends ApiRequest {
|
||||
Uri endpoint = Uri.parse('https://${EndpointData().webuntis().full()}/WebUntis/jsonrpc.do?school=marianum-fulda');
|
||||
Uri endpoint = Uri.parse(
|
||||
'https://${EndpointData().webuntis().full()}/WebUntis/jsonrpc.do?school=marianum-fulda',
|
||||
);
|
||||
String method;
|
||||
ApiParams? genericParam;
|
||||
http.Response? response;
|
||||
|
||||
bool authenticatedResponse;
|
||||
|
||||
WebuntisApi(this.method, this.genericParam, {this.authenticatedResponse = true});
|
||||
|
||||
WebuntisApi(
|
||||
this.method,
|
||||
this.genericParam, {
|
||||
this.authenticatedResponse = true,
|
||||
});
|
||||
|
||||
Future<String> query(WebuntisApi untis, {bool retry = false}) async {
|
||||
final body = '{"id":"ID","method":"$method","params":${untis._body()},"jsonrpc":"2.0"}';
|
||||
final body =
|
||||
'{"id":"ID","method":"$method","params":${untis._body()},"jsonrpc":"2.0"}';
|
||||
|
||||
var sessionId = '0';
|
||||
if (authenticatedResponse) {
|
||||
@@ -38,13 +44,20 @@ abstract class WebuntisApi extends ApiRequest {
|
||||
try {
|
||||
jsonData = jsonDecode(data.body) as Map<String, dynamic>;
|
||||
} on FormatException catch (e) {
|
||||
throw ParseException(technicalDetails: 'WebUntis JSON decode: ${e.message}');
|
||||
throw ParseException(
|
||||
technicalDetails: 'WebUntis JSON decode: ${e.message}',
|
||||
);
|
||||
}
|
||||
final error = jsonData['error'] as Map<String, dynamic>?;
|
||||
if (error != null) {
|
||||
final code = error['code'] as int;
|
||||
if (code == -8520) {
|
||||
if (retry) throw WebuntisError('Authentication was tried (probably session timeout), but was not successful!', -8520);
|
||||
if (retry) {
|
||||
throw WebuntisError(
|
||||
'Authentication was tried (probably session timeout), but was not successful!',
|
||||
-8520,
|
||||
);
|
||||
}
|
||||
await Authenticate.createSession();
|
||||
return query(untis, retry: true);
|
||||
} else {
|
||||
@@ -65,14 +78,22 @@ abstract class WebuntisApi extends ApiRequest {
|
||||
|
||||
Future<http.Response> post(String data, Map<String, String>? headers) async {
|
||||
try {
|
||||
return await http.post(endpoint, body: data, headers: headers).timeout(
|
||||
return await http
|
||||
.post(endpoint, body: data, headers: headers)
|
||||
.timeout(
|
||||
const Duration(seconds: 10),
|
||||
onTimeout: () => throw NetworkException.timeout(technicalDetails: 'WebUntis $method timed out after 10s'),
|
||||
onTimeout: () => throw NetworkException.timeout(
|
||||
technicalDetails: 'WebUntis $method timed out after 10s',
|
||||
),
|
||||
);
|
||||
} on SocketException catch (e) {
|
||||
throw NetworkException(technicalDetails: 'WebUntis $method: ${e.message}');
|
||||
throw NetworkException(
|
||||
technicalDetails: 'WebUntis $method: ${e.message}',
|
||||
);
|
||||
} on http.ClientException catch (e) {
|
||||
throw NetworkException(technicalDetails: 'WebUntis $method: ${e.message}');
|
||||
throw NetworkException(
|
||||
technicalDetails: 'WebUntis $method: ${e.message}',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+86
-78
@@ -95,7 +95,9 @@ class _AppState extends State<App> with WidgetsBindingObserver {
|
||||
if (!mounted) return;
|
||||
NotificationController.onForegroundMessageHandler(message, context);
|
||||
});
|
||||
FirebaseMessaging.onBackgroundMessage(NotificationController.onBackgroundMessageHandler);
|
||||
FirebaseMessaging.onBackgroundMessage(
|
||||
NotificationController.onBackgroundMessageHandler,
|
||||
);
|
||||
|
||||
FirebaseMessaging.onMessageOpenedApp.listen((message) {
|
||||
if (!mounted) return;
|
||||
@@ -119,83 +121,89 @@ class _AppState extends State<App> with WidgetsBindingObserver {
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => BlocBuilder<SettingsCubit, model.Settings>(
|
||||
builder: (context, _) {
|
||||
final bottomBarModules = AppModule.getBottomBarModules(context);
|
||||
final totalTabs = bottomBarModules.length + 1;
|
||||
final currentIndex = Main.bottomNavigator.index;
|
||||
Widget build(
|
||||
BuildContext context,
|
||||
) => BlocBuilder<SettingsCubit, model.Settings>(
|
||||
builder: (context, _) {
|
||||
final bottomBarModules = AppModule.getBottomBarModules(context);
|
||||
final totalTabs = bottomBarModules.length + 1;
|
||||
final currentIndex = Main.bottomNavigator.index;
|
||||
|
||||
// The bottom-bar layout is identified by the ordered list of module
|
||||
// names plus the trailing 'more' slot. Whenever this layout changes
|
||||
// — slot count, reordering, or hiding a module — we recreate the
|
||||
// entire PersistentTabView via the [layoutKey] below. The package
|
||||
// caches per-tab navigator state by index in `_navigatorKeys`, and
|
||||
// its internal `alignLength` only ever appends or trims at the end.
|
||||
// So when the module sitting at e.g. index 3 changes, the navigator
|
||||
// at that index still serves the old screen's route stack and the
|
||||
// user sees stale content. Re-mounting clears those stacks; the
|
||||
// trade-off (losing in-tab pushed routes on a settings change) is
|
||||
// acceptable since the user explicitly re-shaped the bar.
|
||||
final layoutKey = ValueKey('${bottomBarModules.map((m) => m.module.name).join('|')}|more');
|
||||
|
||||
if (totalTabs != _knownTotalTabs) {
|
||||
var targetIndex = currentIndex;
|
||||
if (_userOnLastTab) {
|
||||
targetIndex = totalTabs - 1;
|
||||
} else if (currentIndex >= totalTabs) {
|
||||
targetIndex = totalTabs - 1;
|
||||
}
|
||||
// Re-mounting PTV with a new key constructs fresh internals from
|
||||
// its controller's current index. If the controller still points
|
||||
// past the new tab list, Style6BottomNavBar (and others) crash on
|
||||
// out-of-range access during initState. Replace the controller
|
||||
// atomically with one initialised at the safe target index so the
|
||||
// new PTV mounts cleanly.
|
||||
if (targetIndex != currentIndex) {
|
||||
Main.bottomNavigator.removeListener(_onTabControllerChanged);
|
||||
Main.bottomNavigator = PersistentTabController(initialIndex: targetIndex);
|
||||
Main.bottomNavigator.addListener(_onTabControllerChanged);
|
||||
_userOnLastTab = targetIndex == totalTabs - 1;
|
||||
}
|
||||
}
|
||||
|
||||
_knownTotalTabs = totalTabs;
|
||||
|
||||
return PersistentTabView(
|
||||
key: layoutKey,
|
||||
controller: Main.bottomNavigator,
|
||||
navBarOverlap: const NavBarOverlap.none(),
|
||||
backgroundColor: Theme.of(context).colorScheme.primary,
|
||||
handleAndroidBackButtonPress: true,
|
||||
screenTransitionAnimation: const ScreenTransitionAnimation(
|
||||
curve: Curves.easeOutQuad,
|
||||
duration: Duration(milliseconds: 200),
|
||||
),
|
||||
tabs: [
|
||||
...bottomBarModules.map((e) => e.toBottomTab(context)),
|
||||
PersistentTabConfig(
|
||||
screen: const Breaker(breaker: BreakerArea.more, child: Overhang()),
|
||||
item: ItemConfig(
|
||||
activeForegroundColor: Theme.of(context).primaryColor,
|
||||
inactiveForegroundColor: Theme.of(context).colorScheme.secondary,
|
||||
icon: const Icon(Icons.apps),
|
||||
title: 'Mehr',
|
||||
),
|
||||
),
|
||||
],
|
||||
navBarBuilder: (config) => Style6BottomNavBar(
|
||||
// Style6BottomNavBar builds its internal animation controller list
|
||||
// in initState and never grows it on didUpdateWidget. Keying by the
|
||||
// item count forces a fresh State whenever the slot count changes,
|
||||
// which avoids a RangeError when more tabs slide in.
|
||||
key: ValueKey(config.items.length),
|
||||
navBarConfig: config,
|
||||
navBarDecoration: NavBarDecoration(
|
||||
border: const Border(top: BorderSide(width: 1, color: Colors.grey)),
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
// The bottom-bar layout is identified by the ordered list of module
|
||||
// names plus the trailing 'more' slot. Whenever this layout changes
|
||||
// — slot count, reordering, or hiding a module — we recreate the
|
||||
// entire PersistentTabView via the [layoutKey] below. The package
|
||||
// caches per-tab navigator state by index in `_navigatorKeys`, and
|
||||
// its internal `alignLength` only ever appends or trims at the end.
|
||||
// So when the module sitting at e.g. index 3 changes, the navigator
|
||||
// at that index still serves the old screen's route stack and the
|
||||
// user sees stale content. Re-mounting clears those stacks; the
|
||||
// trade-off (losing in-tab pushed routes on a settings change) is
|
||||
// acceptable since the user explicitly re-shaped the bar.
|
||||
final layoutKey = ValueKey(
|
||||
'${bottomBarModules.map((m) => m.module.name).join('|')}|more',
|
||||
);
|
||||
|
||||
if (totalTabs != _knownTotalTabs) {
|
||||
var targetIndex = currentIndex;
|
||||
if (_userOnLastTab) {
|
||||
targetIndex = totalTabs - 1;
|
||||
} else if (currentIndex >= totalTabs) {
|
||||
targetIndex = totalTabs - 1;
|
||||
}
|
||||
// Re-mounting PTV with a new key constructs fresh internals from
|
||||
// its controller's current index. If the controller still points
|
||||
// past the new tab list, Style6BottomNavBar (and others) crash on
|
||||
// out-of-range access during initState. Replace the controller
|
||||
// atomically with one initialised at the safe target index so the
|
||||
// new PTV mounts cleanly.
|
||||
if (targetIndex != currentIndex) {
|
||||
Main.bottomNavigator.removeListener(_onTabControllerChanged);
|
||||
Main.bottomNavigator = PersistentTabController(
|
||||
initialIndex: targetIndex,
|
||||
);
|
||||
Main.bottomNavigator.addListener(_onTabControllerChanged);
|
||||
_userOnLastTab = targetIndex == totalTabs - 1;
|
||||
}
|
||||
}
|
||||
|
||||
_knownTotalTabs = totalTabs;
|
||||
|
||||
return PersistentTabView(
|
||||
key: layoutKey,
|
||||
controller: Main.bottomNavigator,
|
||||
navBarOverlap: const NavBarOverlap.none(),
|
||||
backgroundColor: Theme.of(context).colorScheme.primary,
|
||||
handleAndroidBackButtonPress: true,
|
||||
screenTransitionAnimation: const ScreenTransitionAnimation(
|
||||
curve: Curves.easeOutQuad,
|
||||
duration: Duration(milliseconds: 200),
|
||||
),
|
||||
tabs: [
|
||||
...bottomBarModules.map((e) => e.toBottomTab(context)),
|
||||
PersistentTabConfig(
|
||||
screen: const Breaker(breaker: BreakerArea.more, child: Overhang()),
|
||||
item: ItemConfig(
|
||||
activeForegroundColor: Theme.of(context).primaryColor,
|
||||
inactiveForegroundColor: Theme.of(context).colorScheme.secondary,
|
||||
icon: const Icon(Icons.apps),
|
||||
title: 'Mehr',
|
||||
),
|
||||
),
|
||||
],
|
||||
navBarBuilder: (config) => Style6BottomNavBar(
|
||||
// Style6BottomNavBar builds its internal animation controller list
|
||||
// in initState and never grows it on didUpdateWidget. Keying by the
|
||||
// item count forces a fresh State whenever the slot count changes,
|
||||
// which avoids a RangeError when more tabs slide in.
|
||||
key: ValueKey(config.items.length),
|
||||
navBarConfig: config,
|
||||
navBarDecoration: NavBarDecoration(
|
||||
border: const Border(top: BorderSide(width: 1, color: Colors.grey)),
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,11 +2,14 @@ import 'package:flutter/material.dart';
|
||||
import 'package:jiffy/jiffy.dart';
|
||||
|
||||
extension IsSameDay on DateTime {
|
||||
bool isSameDay(DateTime other) => year == other.year && month == other.month && day == other.day;
|
||||
bool isSameDay(DateTime other) =>
|
||||
year == other.year && month == other.month && day == other.day;
|
||||
|
||||
DateTime nextWeekday(int day) => add(Duration(days: (day - weekday) % DateTime.daysPerWeek));
|
||||
DateTime nextWeekday(int day) =>
|
||||
add(Duration(days: (day - weekday) % DateTime.daysPerWeek));
|
||||
|
||||
DateTime withTime(TimeOfDay time) => copyWith(hour: time.hour, minute: time.minute);
|
||||
DateTime withTime(TimeOfDay time) =>
|
||||
copyWith(hour: time.hour, minute: time.minute);
|
||||
|
||||
TimeOfDay toTimeOfDay() => TimeOfDay(hour: hour, minute: minute);
|
||||
|
||||
@@ -25,15 +28,20 @@ extension IsSameDay on DateTime {
|
||||
extension DateTimeFormatting on DateTime {
|
||||
String formatHm() => Jiffy.parseFromDateTime(this).format(pattern: 'HH:mm');
|
||||
|
||||
String formatDate() => Jiffy.parseFromDateTime(this).format(pattern: 'dd.MM.yyyy');
|
||||
String formatDate() =>
|
||||
Jiffy.parseFromDateTime(this).format(pattern: 'dd.MM.yyyy');
|
||||
|
||||
String formatDateTime() => Jiffy.parseFromDateTime(this).format(pattern: 'dd.MM.yyyy HH:mm');
|
||||
String formatDateTime() =>
|
||||
Jiffy.parseFromDateTime(this).format(pattern: 'dd.MM.yyyy HH:mm');
|
||||
|
||||
String formatDateShort() => Jiffy.parseFromDateTime(this).format(pattern: 'dd.MM.');
|
||||
String formatDateShort() =>
|
||||
Jiffy.parseFromDateTime(this).format(pattern: 'dd.MM.');
|
||||
|
||||
String formatDateShortHm() => Jiffy.parseFromDateTime(this).format(pattern: 'dd.MM. HH:mm');
|
||||
String formatDateShortHm() =>
|
||||
Jiffy.parseFromDateTime(this).format(pattern: 'dd.MM. HH:mm');
|
||||
|
||||
String formatMonthYear() => Jiffy.parseFromDateTime(this).format(pattern: 'MMMM yyyy');
|
||||
String formatMonthYear() =>
|
||||
Jiffy.parseFromDateTime(this).format(pattern: 'MMMM yyyy');
|
||||
|
||||
String formatRelative() => Jiffy.parseFromDateTime(this).fromNow();
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
extension RenderNotNullExt<T> on T? {
|
||||
R? wrapNullable<R>(R Function(T data) defaultValueCallback) => this != null ? defaultValueCallback(this as T) : null;
|
||||
R? wrapNullable<R>(R Function(T data) defaultValueCallback) =>
|
||||
this != null ? defaultValueCallback(this as T) : null;
|
||||
}
|
||||
|
||||
@@ -3,9 +3,9 @@ import 'package:flutter/material.dart';
|
||||
extension TextExt on Text {
|
||||
Size get size {
|
||||
final textPainter = TextPainter(
|
||||
text: TextSpan(text: data, style: style),
|
||||
maxLines: 1,
|
||||
textDirection: TextDirection.ltr
|
||||
text: TextSpan(text: data, style: style),
|
||||
maxLines: 1,
|
||||
textDirection: TextDirection.ltr,
|
||||
)..layout(minWidth: 0, maxWidth: double.infinity);
|
||||
return textPainter.size;
|
||||
}
|
||||
|
||||
@@ -5,5 +5,6 @@ extension TimeOfDayExt on TimeOfDay {
|
||||
|
||||
bool isAfter(TimeOfDay other) => hour > other.hour && minute > other.minute;
|
||||
|
||||
TimeOfDay add({int hours = 0, int minutes = 0}) => replacing(hour: hour + hours, minute: minute + minutes);
|
||||
TimeOfDay add({int hours = 0, int minutes = 0}) =>
|
||||
replacing(hour: hour + hours, minute: minute + minutes);
|
||||
}
|
||||
|
||||
@@ -63,7 +63,8 @@ class DefaultFirebaseOptions {
|
||||
messagingSenderId: '522850592536',
|
||||
projectId: 'marmobile-33b10',
|
||||
storageBucket: 'marmobile-33b10.appspot.com',
|
||||
iosClientId: '522850592536-edj90sbbnkjqe3aqui37j8enu93v4fk8.apps.googleusercontent.com',
|
||||
iosClientId:
|
||||
'522850592536-edj90sbbnkjqe3aqui37j8enu93v4fk8.apps.googleusercontent.com',
|
||||
iosBundleId: 'eu.mhsl.marianum.mobile.client',
|
||||
);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user