api and storage restructure

This commit is contained in:
2026-05-05 22:00:07 +02:00
parent 4f796dac2e
commit 9b5a70b285
53 changed files with 318 additions and 460 deletions
+11 -19
View File
@@ -1,26 +1,18 @@
import 'dart:convert';
import '../requestCache.dart'; import '../requestCache.dart';
import 'getHolidays.dart'; import 'getHolidays.dart';
import 'getHolidaysResponse.dart'; import 'getHolidaysResponse.dart';
class GetHolidaysCache extends RequestCache<GetHolidaysResponse> { class GetHolidaysCache extends SimpleCache<GetHolidaysResponse> {
GetHolidaysCache({void Function(GetHolidaysResponse)? onUpdate, bool? renew}) : super(RequestCache.cacheDay, onUpdate, renew: renew) { GetHolidaysCache({super.onUpdate, super.renew})
: super(
cacheTime: RequestCache.cacheDay,
loader: () => GetHolidays().query(),
fromJson: (json) => GetHolidaysResponse(
(json['data'] as List)
.map((i) => GetHolidaysResponseObject.fromJson(i as Map<String, dynamic>))
.toList(),
),
) {
start('state-holidays'); start('state-holidays');
} }
@override
GetHolidaysResponse onLocalData(String json) {
List<dynamic> parsedListJson = jsonDecode(json)['data'];
return GetHolidaysResponse(
List<GetHolidaysResponseObject>.from(
parsedListJson.map<GetHolidaysResponseObject>(
(i) => GetHolidaysResponseObject.fromJson(i as Map<String, dynamic>)
)
)
);
}
@override
Future<GetHolidaysResponse> onLoad() => GetHolidays().query();
} }
@@ -3,31 +3,25 @@ import 'dart:io';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import '../../../model/account_data.dart'; import '../nextcloud_ocs.dart';
import '../../../model/endpoint_data.dart';
import 'autocompleteResponse.dart'; import 'autocompleteResponse.dart';
class AutocompleteApi { class AutocompleteApi {
Future<AutocompleteResponse> find(String query) async { Future<AutocompleteResponse> find(String query) async {
var getParameters = <String, dynamic>{ final endpoint = NextcloudOcs.uri(
'search': query, 'core/autocomplete/get',
'itemType': ' ', queryParameters: {
'itemId': ' ', 'search': query,
'shareTypes[]': ['0'], 'itemType': ' ',
'limit': '10', 'itemId': ' ',
}; 'shareTypes[]': ['0'],
'limit': '10',
var headers = <String, String>{}; },
headers.putIfAbsent('Accept', () => 'application/json'); );
headers.putIfAbsent('OCS-APIRequest', () => 'true'); final response = await http.get(endpoint, headers: NextcloudOcs.headers());
headers.putIfAbsent('Authorization', AccountData().getBasicAuthHeader); if (response.statusCode != HttpStatus.ok) {
throw Exception('Api call failed with ${response.statusCode}: ${response.body}');
var endpoint = Uri.https(EndpointData().nextcloud().domain, '${EndpointData().nextcloud().path}/ocs/v2.php/core/autocomplete/get', getParameters); }
return AutocompleteResponse.fromJson(jsonDecode(response.body)['ocs']);
var response = await http.get(endpoint, headers: headers);
if(response.statusCode != HttpStatus.ok) throw Exception('Api call failed with ${response.statusCode}: ${response.body}');
var result = response.body;
return AutocompleteResponse.fromJson(jsonDecode(result)['ocs']);
} }
} }
@@ -2,21 +2,17 @@ import 'dart:io';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import '../../../model/account_data.dart'; import '../nextcloud_ocs.dart';
import '../../../model/endpoint_data.dart';
import 'fileSharingApiParams.dart'; import 'fileSharingApiParams.dart';
class FileSharingApi { class FileSharingApi {
Future<void> share(FileSharingApiParams query) async { Future<void> share(FileSharingApiParams query) async {
var headers = <String, String>{}; final endpoint = NextcloudOcs.uri(
headers.putIfAbsent('Accept', () => 'application/json'); 'apps/files_sharing/api/v1/shares',
headers.putIfAbsent('OCS-APIRequest', () => 'true'); queryParameters: query.toJson(),
headers.putIfAbsent('Authorization', AccountData().getBasicAuthHeader); );
final response = await http.post(endpoint, headers: NextcloudOcs.headers());
var endpoint = Uri.https(EndpointData().nextcloud().domain, '${EndpointData().nextcloud().path}/ocs/v2.php/apps/files_sharing/api/v1/shares', query.toJson().map((key, value) => MapEntry(key, value.toString()))); if (response.statusCode != HttpStatus.ok) {
var response = await http.post(endpoint, headers: 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}');
} }
} }
+33
View File
@@ -0,0 +1,33 @@
import '../../model/account_data.dart';
import '../../model/endpoint_data.dart';
/// Shared helpers for Nextcloud OCS v2 endpoints.
///
/// Three call sites previously duplicated the same header dictionary and the
/// same URI scaffolding (TalkApi, AutocompleteApi, FileSharingApi). Anything
/// that talks to `https://<domain>/<base>/ocs/v2.php/...` should go through
/// these two helpers so additions like a new header or a different auth
/// scheme only need to change here.
class NextcloudOcs {
NextcloudOcs._();
/// The standard OCS request header set: JSON accept, OCS API marker,
/// HTTP Basic auth from the active [AccountData].
static Map<String, String> headers() => {
'Accept': 'application/json',
'OCS-APIRequest': 'true',
'Authorization': AccountData().getBasicAuthHeader(),
};
/// Builds an OCS URI by appending [pathSuffix] under `/ocs/v2.php/` of
/// the configured Nextcloud endpoint. Query parameters are converted to
/// strings (Uri rejects non-string values).
static Uri uri(String pathSuffix, {Map<String, dynamic>? queryParameters}) {
final endpoint = EndpointData().nextcloud();
return Uri.https(
endpoint.domain,
'${endpoint.path}/ocs/v2.php/$pathSuffix',
queryParameters?.map((key, value) => MapEntry(key, value.toString())),
);
}
}
@@ -0,0 +1,50 @@
import 'package:http/http.dart' as http;
import '../../../apiParams.dart';
import '../../../apiResponse.dart';
import '../talkApi.dart';
/// Small POST/DELETE-only Talk endpoints that have no response payload.
/// Each class extends [TalkApi] with `assemble` returning `null`. They share
/// no state — they're collected here purely to avoid eight near-empty files.
class SetFavorite extends TalkApi {
final String chatToken;
final bool favoriteState;
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);
}
class LeaveRoom extends TalkApi {
final String chatToken;
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);
}
class DeleteMessage extends TalkApi {
final String chatToken;
final int messageId;
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);
}
@@ -1,36 +1,26 @@
import 'dart:convert';
import '../../../requestCache.dart'; import '../../../requestCache.dart';
import 'getChat.dart'; import 'getChat.dart';
import 'getChatParams.dart'; import 'getChatParams.dart';
import 'getChatResponse.dart'; import 'getChatResponse.dart';
class GetChatCache extends RequestCache<GetChatResponse> { class GetChatCache extends SimpleCache<GetChatResponse> {
String chatToken;
GetChatCache({ GetChatCache({
required void Function(GetChatResponse) onUpdate, required void Function(GetChatResponse) onUpdate,
void Function(Exception)? onError, super.onError,
required this.chatToken, required String chatToken,
}) : super( }) : super(
RequestCache.cacheNothing, cacheTime: RequestCache.cacheNothing,
onUpdate, loader: () => GetChat(
onError: onError ?? RequestCache.ignore, chatToken,
GetChatParams(
lookIntoFuture: GetChatParamsSwitch.off,
setReadMarker: GetChatParamsSwitch.on,
limit: 200,
),
).run(),
fromJson: GetChatResponse.fromJson,
onUpdate: onUpdate,
) { ) {
start('nc-chat-$chatToken'); start('nc-chat-$chatToken');
} }
@override
Future<GetChatResponse> onLoad() => GetChat(
chatToken,
GetChatParams(
lookIntoFuture: GetChatParamsSwitch.off,
setReadMarker: GetChatParamsSwitch.on,
limit: 200,
)
).run();
@override
GetChatResponse onLocalData(String json) => GetChatResponse.fromJson(jsonDecode(json));
} }
@@ -1,18 +0,0 @@
import 'package:http/http.dart' as http;
import 'package:http/http.dart';
import '../../../apiParams.dart';
import '../talkApi.dart';
class DeleteMessage extends TalkApi {
String chatToken;
int messageId;
DeleteMessage(this.chatToken, this.messageId) : super('v1/chat/$chatToken/$messageId', null);
@override
assemble(String raw) => null;
@override
Future<Response>? request(Uri uri, ApiParams? body, Map<String, String>? headers) => http.delete(uri, headers: headers);
}
@@ -1,22 +1,17 @@
import 'dart:convert';
import '../../../requestCache.dart'; import '../../../requestCache.dart';
import 'getParticipants.dart'; import 'getParticipants.dart';
import 'getParticipantsResponse.dart'; import 'getParticipantsResponse.dart';
class GetParticipantsCache extends RequestCache<GetParticipantsResponse> { class GetParticipantsCache extends SimpleCache<GetParticipantsResponse> {
String chatToken; GetParticipantsCache({
required void Function(GetParticipantsResponse) onUpdate,
GetParticipantsCache({required void Function(GetParticipantsResponse) onUpdate, required this.chatToken}) : super(RequestCache.cacheNothing, onUpdate) { required String chatToken,
}) : super(
cacheTime: RequestCache.cacheNothing,
loader: () => GetParticipants(chatToken).run(),
fromJson: GetParticipantsResponse.fromJson,
onUpdate: onUpdate,
) {
start('nc-chat-participants-$chatToken'); start('nc-chat-participants-$chatToken');
} }
@override
Future<GetParticipantsResponse> onLoad() => GetParticipants(
chatToken,
).run();
@override
GetParticipantsResponse onLocalData(String json) => GetParticipantsResponse.fromJson(jsonDecode(json));
} }
@@ -1,16 +0,0 @@
import 'package:http/http.dart' as http;
import 'package:http/http.dart';
import '../talkApi.dart';
class LeaveRoom extends TalkApi {
String chatToken;
LeaveRoom(this.chatToken) : super('v4/room/$chatToken/participants/self', null);
@override
assemble(String raw) => null;
@override
Future<Response> request(Uri uri, Object? body, Map<String, String>? headers) => http.delete(uri, headers: headers);
}
@@ -1,32 +1,15 @@
import 'dart:convert';
import '../../../requestCache.dart'; import '../../../requestCache.dart';
import 'getRoom.dart'; import 'getRoom.dart';
import 'getRoomParams.dart'; import 'getRoomParams.dart';
import 'getRoomResponse.dart'; import 'getRoomResponse.dart';
class GetRoomCache extends RequestCache<GetRoomResponse> { class GetRoomCache extends SimpleCache<GetRoomResponse> {
GetRoomCache({ GetRoomCache({super.onUpdate, super.onError, super.renew})
void Function(GetRoomResponse)? onUpdate, : super(
void Function(Exception)? onError, cacheTime: RequestCache.cacheMinute,
bool? renew, loader: () => GetRoom(GetRoomParams(includeStatus: true)).run(),
}) : super( fromJson: GetRoomResponse.fromJson,
RequestCache.cacheMinute,
onUpdate,
onError: onError ?? RequestCache.ignore,
renew: renew,
) { ) {
start('nc-rooms'); start('nc-rooms');
} }
@override
GetRoomResponse onLocalData(String json) => GetRoomResponse.fromJson(jsonDecode(json));
@override
Future<GetRoomResponse> onLoad() => GetRoom(
GetRoomParams(
includeStatus: true,
)
).run();
} }
@@ -1,5 +0,0 @@
import '../../../apiResponse.dart';
class SendMessageResponse extends ApiResponse {
}
@@ -1,25 +0,0 @@
import 'package:http/http.dart' as http;
import 'package:http/http.dart';
import '../talkApi.dart';
class SetFavorite extends TalkApi {
String chatToken;
bool favoriteState;
SetFavorite(this.chatToken, this.favoriteState) : super('v4/room/$chatToken/favorite', null);
@override
assemble(String raw) => null;
@override
Future<Response> request(Uri uri, Object? body, Map<String, String>? headers) {
if(favoriteState) {
return http.post(uri, headers: headers);
} else {
return http.delete(uri, headers: headers);
}
}
}
+13 -22
View File
@@ -2,12 +2,11 @@ import 'dart:developer';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import '../../../model/account_data.dart';
import '../../../model/endpoint_data.dart';
import '../../apiError.dart'; import '../../apiError.dart';
import '../../apiParams.dart'; import '../../apiParams.dart';
import '../../apiRequest.dart'; import '../../apiRequest.dart';
import '../../apiResponse.dart'; import '../../apiResponse.dart';
import '../nextcloud_ocs.dart';
enum TalkApiMethod { enum TalkApiMethod {
get, get,
@@ -19,7 +18,7 @@ enum TalkApiMethod {
abstract class TalkApi<T extends ApiResponse?> extends ApiRequest { abstract class TalkApi<T extends ApiResponse?> extends ApiRequest {
String path; String path;
ApiParams? body; ApiParams? body;
Map<String, String>? headers = {}; Map<String, String>? headers;
Map<String, dynamic>? getParameters; Map<String, dynamic>? getParameters;
http.Response? response; http.Response? response;
@@ -30,36 +29,28 @@ abstract class TalkApi<T extends ApiResponse?> extends ApiRequest {
T assemble(String raw); T assemble(String raw);
Future<T> run() async { Future<T> run() async {
getParameters?.forEach((key, value) { final endpoint = NextcloudOcs.uri('apps/spreed/api/$path', queryParameters: getParameters);
getParameters?.update(key, (value) => value.toString()); final mergedHeaders = {...NextcloudOcs.headers(), ...?headers};
});
var endpoint = Uri.https(EndpointData().nextcloud().domain, '${EndpointData().nextcloud().path}/ocs/v2.php/apps/spreed/api/$path', getParameters);
headers ??= {};
headers?.putIfAbsent('Accept', () => 'application/json');
headers?.putIfAbsent('OCS-APIRequest', () => 'true');
headers?.putIfAbsent('Authorization', AccountData().getBasicAuthHeader);
http.Response? data; http.Response? data;
try { try {
data = await request(endpoint, body, headers); data = await request(endpoint, body, mergedHeaders);
if(data == null) throw Exception('No response Data'); if (data == null) throw Exception('No response Data');
if(data.statusCode >= 400 || data.statusCode < 200) throw Exception("Response status code '${data.statusCode}' might indicate an error"); if (data.statusCode >= 400 || data.statusCode < 200) {
} catch(e) { throw Exception("Response status code '${data.statusCode}' might indicate an error");
}
} catch (e) {
log(e.toString()); log(e.toString());
throw ApiError('Request $endpoint could not be dispatched: ${e.toString()}'); throw ApiError('Request $endpoint could not be dispatched: ${e.toString()}');
} }
//dynamic jsonData = jsonDecode(data.body);
T assembled;
try { try {
assembled = assemble(data.body); final assembled = assemble(data.body);
assembled?.headers = data.headers; assembled?.headers = data.headers;
return assembled; return assembled;
} catch (e) { } catch (e) {
var message = 'Error assembling Talk API ${T.toString()} message: ${e.toString()} response with request body: $body and request headers: ${headers.toString()}'; final message = 'Error assembling Talk API ${T.toString()} message: ${e.toString()}'
' response with request body: $body and request headers: $mergedHeaders';
log(message); log(message);
throw Exception(message); throw Exception(message);
} }
@@ -1,26 +0,0 @@
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:http/http.dart';
import '../getPoll/getPollStateResponse.dart';
import '../talkApi.dart';
import 'votePollParams.dart';
@Deprecated('VotePoll is broken')
class VotePoll extends TalkApi {
String token;
int pollId;
VotePoll({required this.token, required this.pollId, required VotePollParams params}) : super('v1/poll/$token/$pollId', params);
@override
GetPollStateResponse assemble(String raw) => GetPollStateResponse.fromJson(jsonDecode(raw)['ocs']);
@override
Future<Response>? request(Uri uri, Object? body, Map<String, String>? headers) {
if(body is VotePollParams) {
return http.post(uri, headers: headers, body: body.toJson().toString());
}
return null;
}
}
@@ -1,15 +0,0 @@
import 'package:json_annotation/json_annotation.dart';
import '../../../apiParams.dart';
part 'votePollParams.g.dart';
@JsonSerializable()
@Deprecated('VotePoll is broken')
class VotePollParams extends ApiParams {
List<int> optionIds;
VotePollParams({required this.optionIds});
factory VotePollParams.fromJson(Map<String, dynamic> json) => _$VotePollParamsFromJson(json);
Map<String, dynamic> toJson() => _$VotePollParamsToJson(this);
}
@@ -1,17 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'votePollParams.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
VotePollParams _$VotePollParamsFromJson(Map<String, dynamic> json) =>
VotePollParams(
optionIds: (json['optionIds'] as List<dynamic>)
.map((e) => (e as num).toInt())
.toList(),
);
Map<String, dynamic> _$VotePollParamsToJson(VotePollParams instance) =>
<String, dynamic>{'optionIds': instance.optionIds};
@@ -6,34 +6,20 @@ import 'listFiles.dart';
import 'listFilesParams.dart'; import 'listFilesParams.dart';
import 'listFilesResponse.dart'; import 'listFilesResponse.dart';
class ListFilesCache extends RequestCache<ListFilesResponse> { class ListFilesCache extends SimpleCache<ListFilesResponse> {
String path;
ListFilesCache({ ListFilesCache({
required void Function(ListFilesResponse) onUpdate, required void Function(ListFilesResponse) onUpdate,
void Function(ListFilesResponse)? onCacheData, super.onCacheData,
void Function(ListFilesResponse)? onNetworkData, super.onNetworkData,
void Function(Exception)? onError, super.onError,
required this.path, required String path,
}) : super( }) : super(
RequestCache.cacheNothing, cacheTime: RequestCache.cacheNothing,
onUpdate, loader: () => ListFiles(ListFilesParams(path)).run(),
onError: onError ?? RequestCache.ignore, fromJson: ListFilesResponse.fromJson,
onCacheData: onCacheData, onUpdate: onUpdate,
onNetworkData: onNetworkData,
) { ) {
var bytes = utf8.encode('MarianumMobile-$path'); final cacheName = md5.convert(utf8.encode('MarianumMobile-$path')).toString();
var cacheName = md5.convert(bytes).toString();
start('wd-folder-$cacheName'); start('wd-folder-$cacheName');
} }
@override
Future<ListFilesResponse> onLoad() async {
var data = await ListFiles(ListFilesParams(path)).run();
return data;
}
@override
ListFilesResponse onLocalData(String json) => ListFilesResponse.fromJson(jsonDecode(json));
} }
@@ -1,17 +1,14 @@
import 'dart:convert';
import '../../../requestCache.dart'; import '../../../requestCache.dart';
import 'getBreakers.dart'; import 'getBreakers.dart';
import 'getBreakersResponse.dart'; import 'getBreakersResponse.dart';
class GetBreakersCache extends SimpleCache<GetBreakersResponse> {
class GetBreakersCache extends RequestCache<GetBreakersResponse> { GetBreakersCache({super.onUpdate, super.renew})
GetBreakersCache({void Function(GetBreakersResponse)? onUpdate, bool? renew}) : super(RequestCache.cacheMinute, onUpdate, renew: renew) { : super(
cacheTime: RequestCache.cacheMinute,
loader: () => GetBreakers().run(),
fromJson: GetBreakersResponse.fromJson,
) {
start('breakers'); start('breakers');
} }
@override
GetBreakersResponse onLocalData(String json) => GetBreakersResponse.fromJson(jsonDecode(json));
@override
Future<GetBreakersResponse> onLoad() => GetBreakers().run();
} }
@@ -1,30 +1,19 @@
import 'dart:convert';
import '../../../requestCache.dart'; import '../../../requestCache.dart';
import 'getCustomTimetableEvent.dart'; import 'getCustomTimetableEvent.dart';
import 'getCustomTimetableEventParams.dart'; import 'getCustomTimetableEventParams.dart';
import 'getCustomTimetableEventResponse.dart'; import 'getCustomTimetableEventResponse.dart';
class GetCustomTimetableEventCache extends RequestCache<GetCustomTimetableEventResponse> { class GetCustomTimetableEventCache extends SimpleCache<GetCustomTimetableEventResponse> {
GetCustomTimetableEventParams params;
GetCustomTimetableEventCache( GetCustomTimetableEventCache(
this.params, { GetCustomTimetableEventParams params, {
void Function(GetCustomTimetableEventResponse)? onUpdate, super.onUpdate,
void Function(Exception)? onError, super.onError,
bool? renew, super.renew,
}) : super( }) : super(
RequestCache.cacheMinute, cacheTime: RequestCache.cacheMinute,
onUpdate, loader: () => GetCustomTimetableEvent(params).run(),
onError: onError ?? RequestCache.ignore, fromJson: GetCustomTimetableEventResponse.fromJson,
renew: renew,
) { ) {
start('customTimetableEvents'); start('customTimetableEvents');
} }
@override
Future<GetCustomTimetableEventResponse> onLoad() => GetCustomTimetableEvent(params).run();
@override
GetCustomTimetableEventResponse onLocalData(String json) => GetCustomTimetableEventResponse.fromJson(jsonDecode(json));
} }
+35
View File
@@ -79,3 +79,38 @@ abstract class RequestCache<T extends ApiResponse?> {
Future<T> onLoad(); Future<T> onLoad();
} }
/// Concrete [RequestCache] that delegates the two overrides to functions
/// passed in the constructor. Used to collapse the dozens of one-class-per-
/// endpoint cache files that all just forward to `<Endpoint>().run()` and
/// `<Response>.fromJson(jsonDecode(...))`.
class SimpleCache<T extends ApiResponse?> extends RequestCache<T> {
final Future<T> Function() _loader;
final T Function(Map<String, dynamic> json) _fromJson;
SimpleCache({
required int cacheTime,
required Future<T> Function() loader,
required T Function(Map<String, dynamic> json) fromJson,
void Function(T)? onUpdate,
void Function(T)? onCacheData,
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,
);
@override
Future<T> onLoad() => _loader();
@override
T onLocalData(String json) => _fromJson(jsonDecode(json));
}
@@ -1,26 +1,14 @@
import 'dart:convert';
import '../../../requestCache.dart'; import '../../../requestCache.dart';
import 'getHolidays.dart'; import 'getHolidays.dart';
import 'getHolidaysResponse.dart'; import 'getHolidaysResponse.dart';
class GetHolidaysCache extends RequestCache<GetHolidaysResponse> { class GetHolidaysCache extends SimpleCache<GetHolidaysResponse> {
GetHolidaysCache({ GetHolidaysCache({super.onUpdate, super.onError, super.renew})
void Function(GetHolidaysResponse)? onUpdate, : super(
void Function(Exception)? onError, cacheTime: RequestCache.cacheDay,
bool? renew, loader: () => GetHolidays().run(),
}) : super( fromJson: GetHolidaysResponse.fromJson,
RequestCache.cacheDay,
onUpdate,
onError: onError ?? RequestCache.ignore,
renew: renew,
) { ) {
start('wu-holidays'); start('wu-holidays');
} }
@override
Future<GetHolidaysResponse> onLoad() => GetHolidays().run();
@override
GetHolidaysResponse onLocalData(String json) => GetHolidaysResponse.fromJson(jsonDecode(json));
} }
@@ -1,27 +1,14 @@
import 'dart:convert';
import '../../../requestCache.dart'; import '../../../requestCache.dart';
import 'getRooms.dart'; import 'getRooms.dart';
import 'getRoomsResponse.dart'; import 'getRoomsResponse.dart';
class GetRoomsCache extends RequestCache<GetRoomsResponse> { class GetRoomsCache extends SimpleCache<GetRoomsResponse> {
GetRoomsCache({ GetRoomsCache({super.onUpdate, super.onError, super.renew})
void Function(GetRoomsResponse)? onUpdate, : super(
void Function(Exception)? onError, cacheTime: RequestCache.cacheHour,
bool? renew, loader: () => GetRooms().run(),
}) : super( fromJson: GetRoomsResponse.fromJson,
RequestCache.cacheHour,
onUpdate,
onError: onError ?? RequestCache.ignore,
renew: renew,
) { ) {
start('wu-rooms'); start('wu-rooms');
} }
@override
Future<GetRoomsResponse> onLoad() => GetRooms().run();
@override
GetRoomsResponse onLocalData(String json) => GetRoomsResponse.fromJson(jsonDecode(json));
} }
@@ -1,27 +1,14 @@
import 'dart:convert';
import '../../../requestCache.dart'; import '../../../requestCache.dart';
import 'getSubjects.dart'; import 'getSubjects.dart';
import 'getSubjectsResponse.dart'; import 'getSubjectsResponse.dart';
class GetSubjectsCache extends RequestCache<GetSubjectsResponse> { class GetSubjectsCache extends SimpleCache<GetSubjectsResponse> {
GetSubjectsCache({ GetSubjectsCache({super.onUpdate, super.onError, super.renew})
void Function(GetSubjectsResponse)? onUpdate, : super(
void Function(Exception)? onError, cacheTime: RequestCache.cacheHour,
bool? renew, loader: () => GetSubjects().run(),
}) : super( fromJson: GetSubjectsResponse.fromJson,
RequestCache.cacheHour,
onUpdate,
onError: onError ?? RequestCache.ignore,
renew: renew,
) { ) {
start('wu-subjects'); start('wu-subjects');
} }
@override
Future<GetSubjectsResponse> onLoad() => GetSubjects().run();
@override
onLocalData(String json) => GetSubjectsResponse.fromJson(jsonDecode(json));
} }
@@ -1,20 +1,14 @@
import 'dart:convert';
import '../../../requestCache.dart'; import '../../../requestCache.dart';
import 'getTimegridUnits.dart'; import 'getTimegridUnits.dart';
import 'getTimegridUnitsResponse.dart'; import 'getTimegridUnitsResponse.dart';
class GetTimegridUnitsCache extends RequestCache<GetTimegridUnitsResponse> { class GetTimegridUnitsCache extends SimpleCache<GetTimegridUnitsResponse> {
GetTimegridUnitsCache({ GetTimegridUnitsCache({super.onUpdate, super.renew})
void Function(GetTimegridUnitsResponse)? onUpdate, : super(
bool? renew, cacheTime: RequestCache.cacheDay,
}) : super(RequestCache.cacheDay, onUpdate, renew: renew) { loader: () => GetTimegridUnits().run(),
fromJson: GetTimegridUnitsResponse.fromJson,
) {
start('wu-timegrid'); start('wu-timegrid');
} }
@override
Future<GetTimegridUnitsResponse> onLoad() => GetTimegridUnits().run();
@override
GetTimegridUnitsResponse onLocalData(String json) => GetTimegridUnitsResponse.fromJson(jsonDecode(json));
} }
@@ -1,49 +1,43 @@
import 'dart:convert';
import '../../../requestCache.dart'; import '../../../requestCache.dart';
import '../authenticate/authenticate.dart'; import '../authenticate/authenticate.dart';
import 'getTimetable.dart'; import 'getTimetable.dart';
import 'getTimetableParams.dart'; import 'getTimetableParams.dart';
import 'getTimetableResponse.dart'; import 'getTimetableResponse.dart';
class GetTimetableCache extends RequestCache<GetTimetableResponse> { class GetTimetableCache extends SimpleCache<GetTimetableResponse> {
int startdate;
int enddate;
GetTimetableCache({ GetTimetableCache({
required void Function(GetTimetableResponse) onUpdate, required void Function(GetTimetableResponse) onUpdate,
void Function(Exception)? onError, super.onError,
required this.startdate, required int startdate,
required this.enddate, required int enddate,
bool? renew, super.renew,
}) : super( }) : super(
RequestCache.cacheMinute, cacheTime: RequestCache.cacheMinute,
onUpdate, loader: () => _load(startdate, enddate),
onError: onError ?? RequestCache.ignore, fromJson: GetTimetableResponse.fromJson,
renew: renew, onUpdate: onUpdate,
) { ) {
start('wu-timetable-$startdate-$enddate'); start('wu-timetable-$startdate-$enddate');
} }
@override static Future<GetTimetableResponse> _load(int startdate, int enddate) async {
GetTimetableResponse onLocalData(String json) => GetTimetableResponse.fromJson(jsonDecode(json)); final session = await Authenticate.getSession();
return GetTimetable(
@override GetTimetableParams(
Future<GetTimetableResponse> onLoad() async => GetTimetable( options: GetTimetableParamsOptions(
GetTimetableParams( element: GetTimetableParamsOptionsElement(
options: GetTimetableParamsOptions( id: session.personId,
element: GetTimetableParamsOptionsElement( type: session.personType,
id: (await Authenticate.getSession()).personId, keyType: GetTimetableParamsOptionsElementKeyType.id,
type: (await Authenticate.getSession()).personType, ),
keyType: GetTimetableParamsOptionsElementKeyType.id, startDate: startdate,
), endDate: enddate,
startDate: startdate, teacherFields: GetTimetableParamsOptionsFields.all,
endDate: enddate, subjectFields: GetTimetableParamsOptionsFields.all,
teacherFields: GetTimetableParamsOptionsFields.all, roomFields: GetTimetableParamsOptionsFields.all,
subjectFields: GetTimetableParamsOptionsFields.all, klasseFields: GetTimetableParamsOptionsFields.all,
roomFields: GetTimetableParamsOptionsFields.all, ),
klasseFields: GetTimetableParamsOptionsFields.all, ),
)
)
).run(); ).run();
}
} }
+1 -1
View File
@@ -28,7 +28,7 @@ import 'state/app/modules/chat/bloc/chat_bloc.dart';
import 'state/app/modules/chatList/bloc/chat_list_bloc.dart'; import 'state/app/modules/chatList/bloc/chat_list_bloc.dart';
import 'state/app/modules/settings/bloc/settings_cubit.dart'; import 'state/app/modules/settings/bloc/settings_cubit.dart';
import 'state/app/modules/timetable/bloc/timetable_bloc.dart'; import 'state/app/modules/timetable/bloc/timetable_bloc.dart';
import 'storage/base/settings.dart'; import 'storage/settings.dart';
import 'theming/dark_app_theme.dart'; import 'theming/dark_app_theme.dart';
import 'theming/light_app_theme.dart'; import 'theming/light_app_theme.dart';
import 'view/login/login.dart'; import 'view/login/login.dart';
@@ -3,7 +3,7 @@ import 'dart:developer';
import 'package:easy_debounce/easy_debounce.dart'; import 'package:easy_debounce/easy_debounce.dart';
import 'package:hydrated_bloc/hydrated_bloc.dart'; import 'package:hydrated_bloc/hydrated_bloc.dart';
import '../../../../../storage/base/settings.dart'; import '../../../../../storage/settings.dart';
import '../../../../../view/pages/settings/data/default_settings.dart'; import '../../../../../view/pages/settings/data/default_settings.dart';
import '../../app_modules.dart'; import '../../app_modules.dart';
@@ -1,6 +1,6 @@
import 'package:json_annotation/json_annotation.dart'; import 'package:json_annotation/json_annotation.dart';
part 'devToolsSettings.g.dart'; part 'dev_tools_settings.g.dart';
@JsonSerializable() @JsonSerializable()
class DevToolsSettings { class DevToolsSettings {
@@ -1,6 +1,6 @@
// GENERATED CODE - DO NOT MODIFY BY HAND // GENERATED CODE - DO NOT MODIFY BY HAND
part of 'devToolsSettings.dart'; part of 'dev_tools_settings.dart';
// ************************************************************************** // **************************************************************************
// JsonSerializableGenerator // JsonSerializableGenerator
@@ -2,7 +2,7 @@ import 'package:json_annotation/json_annotation.dart';
import '../../view/pages/files/files.dart'; import '../../view/pages/files/files.dart';
part 'fileSettings.g.dart'; part 'file_settings.g.dart';
@JsonSerializable() @JsonSerializable()
class FileSettings { class FileSettings {
@@ -1,6 +1,6 @@
// GENERATED CODE - DO NOT MODIFY BY HAND // GENERATED CODE - DO NOT MODIFY BY HAND
part of 'fileSettings.dart'; part of 'file_settings.dart';
// ************************************************************************** // **************************************************************************
// JsonSerializableGenerator // JsonSerializableGenerator
@@ -1,6 +1,6 @@
import 'package:json_annotation/json_annotation.dart'; import 'package:json_annotation/json_annotation.dart';
part 'fileViewSettings.g.dart'; part 'file_view_settings.g.dart';
@JsonSerializable() @JsonSerializable()
class FileViewSettings { class FileViewSettings {
@@ -1,6 +1,6 @@
// GENERATED CODE - DO NOT MODIFY BY HAND // GENERATED CODE - DO NOT MODIFY BY HAND
part of 'fileViewSettings.dart'; part of 'file_view_settings.dart';
// ************************************************************************** // **************************************************************************
// JsonSerializableGenerator // JsonSerializableGenerator
@@ -1,6 +1,6 @@
import 'package:json_annotation/json_annotation.dart'; import 'package:json_annotation/json_annotation.dart';
part 'holidaysSettings.g.dart'; part 'holidays_settings.g.dart';
@JsonSerializable() @JsonSerializable()
class HolidaysSettings { class HolidaysSettings {
@@ -1,6 +1,6 @@
// GENERATED CODE - DO NOT MODIFY BY HAND // GENERATED CODE - DO NOT MODIFY BY HAND
part of 'holidaysSettings.dart'; part of 'holidays_settings.dart';
// ************************************************************************** // **************************************************************************
// JsonSerializableGenerator // JsonSerializableGenerator
@@ -2,7 +2,7 @@ import 'package:freezed_annotation/freezed_annotation.dart';
import '../../state/app/modules/app_modules.dart'; import '../../state/app/modules/app_modules.dart';
part 'modulesSettings.g.dart'; part 'modules_settings.g.dart';
@JsonSerializable() @JsonSerializable()
class ModulesSettings { class ModulesSettings {
@@ -1,6 +1,6 @@
// GENERATED CODE - DO NOT MODIFY BY HAND // GENERATED CODE - DO NOT MODIFY BY HAND
part of 'modulesSettings.dart'; part of 'modules_settings.dart';
// ************************************************************************** // **************************************************************************
// JsonSerializableGenerator // JsonSerializableGenerator
@@ -1,6 +1,6 @@
import 'package:json_annotation/json_annotation.dart'; import 'package:json_annotation/json_annotation.dart';
part 'notificationSettings.g.dart'; part 'notification_settings.g.dart';
@JsonSerializable() @JsonSerializable()
class NotificationSettings { class NotificationSettings {
@@ -1,6 +1,6 @@
// GENERATED CODE - DO NOT MODIFY BY HAND // GENERATED CODE - DO NOT MODIFY BY HAND
part of 'notificationSettings.dart'; part of 'notification_settings.dart';
// ************************************************************************** // **************************************************************************
// JsonSerializableGenerator // JsonSerializableGenerator
@@ -1,14 +1,14 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:json_annotation/json_annotation.dart'; import 'package:json_annotation/json_annotation.dart';
import '../devTools/devToolsSettings.dart'; import 'dev_tools_settings.dart';
import '../file/fileSettings.dart'; import 'file_settings.dart';
import '../fileView/fileViewSettings.dart'; import 'file_view_settings.dart';
import '../general/modulesSettings.dart'; import 'modules_settings.dart';
import '../holidays/holidaysSettings.dart'; import 'holidays_settings.dart';
import '../notification/notificationSettings.dart'; import 'notification_settings.dart';
import '../talk/talkSettings.dart'; import 'talk_settings.dart';
import '../timetable/timetableSettings.dart'; import 'timetable_settings.dart';
part 'settings.g.dart'; part 'settings.g.dart';
@@ -1,6 +1,6 @@
import 'package:json_annotation/json_annotation.dart'; import 'package:json_annotation/json_annotation.dart';
part 'talkSettings.g.dart'; part 'talk_settings.g.dart';
@JsonSerializable() @JsonSerializable()
class TalkSettings { class TalkSettings {
@@ -1,6 +1,6 @@
// GENERATED CODE - DO NOT MODIFY BY HAND // GENERATED CODE - DO NOT MODIFY BY HAND
part of 'talkSettings.dart'; part of 'talk_settings.dart';
// ************************************************************************** // **************************************************************************
// JsonSerializableGenerator // JsonSerializableGenerator
@@ -1,8 +1,8 @@
import 'package:json_annotation/json_annotation.dart'; import 'package:json_annotation/json_annotation.dart';
import 'timetable_name_mode.dart'; import '../../../view/pages/timetable/data/timetable_name_mode.dart';
part 'timetableSettings.g.dart'; part 'timetable_settings.g.dart';
@JsonSerializable() @JsonSerializable()
class TimetableSettings { class TimetableSettings {
@@ -1,6 +1,6 @@
// GENERATED CODE - DO NOT MODIFY BY HAND // GENERATED CODE - DO NOT MODIFY BY HAND
part of 'timetableSettings.dart'; part of 'timetable_settings.dart';
// ************************************************************************** // **************************************************************************
// JsonSerializableGenerator // JsonSerializableGenerator
+1 -1
View File
@@ -9,7 +9,7 @@ import '../../extensions/render_not_null.dart';
import '../../routing/app_routes.dart'; import '../../routing/app_routes.dart';
import '../../state/app/modules/app_modules.dart'; import '../../state/app/modules/app_modules.dart';
import '../../state/app/modules/settings/bloc/settings_cubit.dart'; import '../../state/app/modules/settings/bloc/settings_cubit.dart';
import '../../storage/base/settings.dart' as model; import '../../storage/settings.dart' as model;
import '../../widget/centered_leading.dart'; import '../../widget/centered_leading.dart';
import '../../widget/info_dialog.dart'; import '../../widget/info_dialog.dart';
import 'settings/data/default_settings.dart'; import 'settings/data/default_settings.dart';
@@ -3,16 +3,16 @@ import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../../../../state/app/modules/app_modules.dart'; import '../../../../state/app/modules/app_modules.dart';
import '../../../../storage/base/settings.dart'; import '../../../../storage/settings.dart';
import '../../../../storage/devTools/devToolsSettings.dart'; import '../../../../storage/dev_tools_settings.dart';
import '../../../../storage/file/fileSettings.dart'; import '../../../../storage/file_settings.dart';
import '../../../../storage/fileView/fileViewSettings.dart'; import '../../../../storage/file_view_settings.dart';
import '../../../../storage/general/modulesSettings.dart'; import '../../../../storage/modules_settings.dart';
import '../../../../storage/holidays/holidaysSettings.dart'; import '../../../../storage/holidays_settings.dart';
import '../../../../storage/notification/notificationSettings.dart'; import '../../../../storage/notification_settings.dart';
import '../../../../storage/talk/talkSettings.dart'; import '../../../../storage/talk_settings.dart';
import '../../../../storage/timetable/timetable_name_mode.dart'; import '../../../../view/pages/timetable/data/timetable_name_mode.dart';
import '../../../../storage/timetable/timetableSettings.dart'; import '../../../../storage/timetable_settings.dart';
import '../../files/files.dart'; import '../../files/files.dart';
class DefaultSettings { class DefaultSettings {
@@ -3,7 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../../state/app/modules/settings/bloc/settings_cubit.dart'; import '../../../../state/app/modules/settings/bloc/settings_cubit.dart';
import '../../../../state/app/modules/timetable/bloc/timetable_bloc.dart'; import '../../../../state/app/modules/timetable/bloc/timetable_bloc.dart';
import '../../../../storage/timetable/timetable_name_mode.dart'; import '../../../../view/pages/timetable/data/timetable_name_mode.dart';
class TimetableSection extends StatelessWidget { class TimetableSection extends StatelessWidget {
const TimetableSection({super.key}); const TimetableSection({super.key});
+1 -1
View File
@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../state/app/modules/settings/bloc/settings_cubit.dart'; import '../../../state/app/modules/settings/bloc/settings_cubit.dart';
import '../../../storage/base/settings.dart' as model; import '../../../storage/settings.dart' as model;
import 'sections/about_section.dart'; import 'sections/about_section.dart';
import 'sections/account_section.dart'; import 'sections/account_section.dart';
import 'sections/appearance_section.dart'; import 'sections/appearance_section.dart';
@@ -5,7 +5,7 @@ import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../../api/marianumcloud/talk/chat/getChatResponse.dart'; import '../../../../api/marianumcloud/talk/chat/getChatResponse.dart';
import '../../../../api/marianumcloud/talk/deleteMessage/deleteMessage.dart'; import '../../../../api/marianumcloud/talk/actions/talk_actions.dart';
import '../../../../api/marianumcloud/talk/reactMessage/reactMessage.dart'; import '../../../../api/marianumcloud/talk/reactMessage/reactMessage.dart';
import '../../../../api/marianumcloud/talk/reactMessage/reactMessageParams.dart'; import '../../../../api/marianumcloud/talk/reactMessage/reactMessageParams.dart';
import '../../../../api/marianumcloud/talk/room/getRoomResponse.dart'; import '../../../../api/marianumcloud/talk/room/getRoomResponse.dart';
+1 -2
View File
@@ -3,10 +3,9 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:jiffy/jiffy.dart'; import 'package:jiffy/jiffy.dart';
import '../../../../api/marianumcloud/talk/actions/talk_actions.dart';
import '../../../../api/marianumcloud/talk/chat/richObjectStringProcessor.dart'; import '../../../../api/marianumcloud/talk/chat/richObjectStringProcessor.dart';
import '../../../../api/marianumcloud/talk/leaveRoom/leaveRoom.dart';
import '../../../../api/marianumcloud/talk/room/getRoomResponse.dart'; import '../../../../api/marianumcloud/talk/room/getRoomResponse.dart';
import '../../../../api/marianumcloud/talk/setFavorite/setFavorite.dart';
import '../../../../api/marianumcloud/talk/setReadMarker/setReadMarker.dart'; import '../../../../api/marianumcloud/talk/setReadMarker/setReadMarker.dart';
import '../../../../api/marianumcloud/talk/setReadMarker/setReadMarkerParams.dart'; import '../../../../api/marianumcloud/talk/setReadMarker/setReadMarkerParams.dart';
import '../../../../model/account_data.dart'; import '../../../../model/account_data.dart';
@@ -5,8 +5,8 @@ import '../../../../api/mhsl/customTimetableEvent/customTimetableEvent.dart';
import '../../../../api/webuntis/queries/getRooms/getRoomsResponse.dart'; import '../../../../api/webuntis/queries/getRooms/getRoomsResponse.dart';
import '../../../../api/webuntis/queries/getSubjects/getSubjectsResponse.dart'; import '../../../../api/webuntis/queries/getSubjects/getSubjectsResponse.dart';
import '../../../../api/webuntis/queries/getTimetable/getTimetableResponse.dart'; import '../../../../api/webuntis/queries/getTimetable/getTimetableResponse.dart';
import '../../../../storage/timetable/timetableSettings.dart'; import '../../../../storage/timetable_settings.dart';
import '../../../../storage/timetable/timetable_name_mode.dart'; import 'timetable_name_mode.dart';
import '../custom_events/custom_event_colors.dart'; import '../custom_events/custom_event_colors.dart';
import 'arbitrary_appointment.dart'; import 'arbitrary_appointment.dart';
import 'lesson_color.dart'; import 'lesson_color.dart';
@@ -1,6 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../../widget/dropdown_display.dart'; import '../../../../widget/dropdown_display.dart';
enum TimetableNameMode { name, longName, alternateName } enum TimetableNameMode { name, longName, alternateName }