Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions assets/translations/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -170,12 +170,42 @@
"licenses": "Lizenzen",
"privacyPolicy": "Datenschutzrichtlinie",
"createCalendarEvent": "Kalenderereignis erstellen",
"createCalendarSeries": "Kalenderserie erstellen",
"editCalendarEvent": "Kalenderereignis bearbeiten",
"editCalendarSeries": "Kalenderserie bearbeiten",
"title": "Titel",
"annotation": "Bemerkung",
"from": "Von",
"to": "Bis",
"start": "Beginn",
"end": "Ende",
"recurrence": "Wiederholen",
"recurrenceDaily": "Tag",
"recurrenceWeekly": "Woche",
"recurrenceBiweekly": "2 Wochen",
"recurrenceMonthly": "Monat",
"repeatEvery": "Wiederholen alle",
"for": "für",
"until": "bis",
"endsOn": "Ende am",
"times": "Mal",
"timeFrame": "Zeitrahmen",
"delete": "Löschen",
"series": "Terminserie",
"editingSeriesBanner": "Alle Wiederholungen dieser Terminserie werden aktualisiert",
"creatingSeriesBanner": "Dieser Termin wird in eine Terminserie umgewandelt",
"editEvent": "Termin bearbeiten",
"editSeries": "Terminserie bearbeiten",
"confirmDeleteEventTitle": "Termin löschen?",
"confirmDeleteEventMessage": "Dieser Termin wird dauerhaft gelöscht.",
"confirmDeleteSeriesTitle": "Terminserie löschen?",
"confirmDeleteSeriesMessage": "Dadurch werden dauerhaft alle {} Termine dieser Serie gelöscht.",
"customEvent": "Eigener Termin",
"details": "Details",
"actions": "Aktionen",
"deleteThisEvent": "Dieses Ereignis löschen",
"deleteSeries": "Terminserie löschen",
"deleteThisAndFollowing": "Dieses und folgende löschen",
"deviceSettings": "Geräte-Einstellungen",
"edit": "Editieren",
"digitalStudentCard": "StudentCard",
Expand Down
30 changes: 30 additions & 0 deletions assets/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -170,12 +170,42 @@
"licenses": "Licenses",
"privacyPolicy": "Privacy Policy",
"createCalendarEvent": "Create Calendar Event",
"createCalendarSeries": "Create Calendar Series",
"editCalendarEvent": "Edit Calendar Event",
"editCalendarSeries": "Edit Calendar Series",
"title": "Title",
"annotation": "Annotation",
"from": "From",
"to": "To",
"start": "Start",
"end": "End",
"recurrence": "Repeat",
"recurrenceDaily": "day",
"recurrenceWeekly": "week",
"recurrenceBiweekly": "2 weeks",
"recurrenceMonthly": "month",
"repeatEvery": "Repeat every",
"for": "for",
"until": "until",
"endsOn": "ends on",
"times": "times",
"timeFrame": "Time Frame",
"delete": "Delete",
"series": "Series",
"editingSeriesBanner": "All occurrences in this series will be updated",
"creatingSeriesBanner": "This event will be converted into a series",
"editEvent": "Edit Event",
"editSeries": "Edit Series",
"confirmDeleteEventTitle": "Delete event?",
"confirmDeleteEventMessage": "This event will be permanently deleted.",
"confirmDeleteSeriesTitle": "Delete series?",
"confirmDeleteSeriesMessage": "This will permanently delete all {} events in this series.",
"customEvent": "Custom Event",
"details": "Details",
"actions": "Actions",
"deleteThisEvent": "Delete this event",
"deleteSeries": "Delete series",
"deleteThisAndFollowing": "Delete this and following",
"deviceSettings": "Device Settings",
"edit": "Edit",
"digitalStudentCard": "StudentCard",
Expand Down
11 changes: 7 additions & 4 deletions lib/base/routing/router.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'package:campus_flutter/base/routing/router_service.dart';
import 'package:campus_flutter/base/routing/routes.dart';
import 'package:campus_flutter/calendarComponent/model/calendar_event.dart';
import 'package:campus_flutter/calendarComponent/views/calendars_view.dart';
import 'package:campus_flutter/calendarComponent/views/custom_event_view.dart';
import 'package:campus_flutter/calendarComponent/views/event_creation_view.dart';
import 'package:campus_flutter/campusComponent/screen/campus_screen.dart';
import 'package:campus_flutter/campusComponent/screen/movie_screen.dart';
Expand Down Expand Up @@ -145,10 +146,12 @@ final _router = GoRouter(
),
GoRoute(
path: calendarDetails,
builder: (context, state) => LectureDetailsScaffold(
event: state.extra as CalendarEvent,
scrollController: null,
),
builder: (context, state) {
final event = state.extra as CalendarEvent;
return event.hasLectureDetailsLink
? LectureDetailsScaffold(event: event, scrollController: null)
: CustomEventScaffold(calendarEvent: event);
},
),
GoRoute(
path: studentClubs,
Expand Down
11 changes: 11 additions & 0 deletions lib/base/util/color_picker_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,17 @@ class _ColorPickerViewState extends State<ColorPickerView> {
super.didChangeDependencies();
}

@override
void didUpdateWidget(covariant ColorPickerView oldWidget) {
super.didUpdateWidget(oldWidget);

final nextColor = widget.color ?? context.primaryColor;
final previousColor = oldWidget.color ?? context.primaryColor;
if (nextColor != previousColor) {
selectedColor = nextColor;
}
}

@override
Widget build(BuildContext context) {
return InkWell(
Expand Down
4 changes: 4 additions & 0 deletions lib/calendarComponent/model/calendar_editing.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ import 'package:json_annotation/json_annotation.dart';

part 'calendar_editing.g.dart';

enum RecurrenceType { none, daily, weekly, biweekly, monthly }

enum RecurrenceEndType { count, untilDate }

class AddedCalendarEvent {
final String title;
final String? annotation;
Expand Down
58 changes: 51 additions & 7 deletions lib/calendarComponent/model/calendar_event.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,28 +32,66 @@ class CalendarEvent extends Searchable {
}

String? get lvNr {
return url?.split("LvNr=").last;
final value = url;
if (value == null || value.isEmpty) {
return null;
}

final uri = Uri.tryParse(value);
if (uri != null) {
return uri.queryParameters['cLvNr'] ??
uri.queryParameters['pLvNr'] ??
uri.queryParameters['pLVNr'] ??
uri.queryParameters['LvNr'] ??
value;
}

final match = RegExp(
r'(?:^|[?&])(?:cLvNr|pLvNr|pLVNr|LvNr)=([^&]+)',
).firstMatch(value);
return match?.group(1) ?? value;
}

bool get hasLectureDetailsLink {
final value = url;
if (value == null || value.isEmpty) {
return false;
}

final uri = Uri.tryParse(value);
if (uri == null || !uri.path.contains('lv.detail')) {
return false;
}

return uri.queryParameters['cLvNr']?.isNotEmpty == true ||
uri.queryParameters['pLvNr']?.isNotEmpty == true ||
uri.queryParameters['pLVNr']?.isNotEmpty == true ||
uri.queryParameters['LvNr']?.isNotEmpty == true;
}

String get timePeriod {
return "${DateFormat.Hm().format(startDate)} - ${DateFormat.Hm().format(endDate)}";
}

String _dateTimePeriod(BuildContext context) {
final start = DateFormat(
String _localizedDateTime(BuildContext context, DateTime value) {
return DateFormat(
"EE, dd.MM.yyyy, HH:mm",
context.locale.languageCode,
).format(startDate);
).format(value);
}

String _dateTimePeriod(BuildContext context) {
final start = _localizedDateTime(context, startDate);
final end = DateFormat("HH:mm").format(endDate);
return "$start - $end";
}

String timePeriodText(BuildContext context) {
if (startDate.day == endDate.day) {
if (_isSameCalendarDay(startDate, endDate)) {
return _dateTimePeriod(context);
} else {
final start = DateFormat(null, "de").format(startDate);
final end = DateFormat(null, "de").format(endDate);
final start = _localizedDateTime(context, startDate);
final end = _localizedDateTime(context, endDate);
return "$start ${context.tr("to").toLowerCase()}\n$end";
}
}
Expand All @@ -62,6 +100,12 @@ class CalendarEvent extends Searchable {
return status == "CANCEL";
}

bool _isSameCalendarDay(DateTime left, DateTime right) {
return left.year == right.year &&
left.month == right.month &&
left.day == right.day;
}

String get subject {
final location = locations.firstOrNull ?? "";
return "$title\n$location";
Expand Down
8 changes: 7 additions & 1 deletion lib/calendarComponent/model/calendar_preferences.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,14 @@ part 'calendar_preferences.g.dart';
class CalendarPreferences {
final Map<String, int> colorPreferences;
final Map<String, bool> visibilityPreferences;
@JsonKey(defaultValue: {})
final Map<String, String> seriesPreferences;

CalendarPreferences(this.colorPreferences, this.visibilityPreferences);
CalendarPreferences(
this.colorPreferences,
this.visibilityPreferences, [
this.seriesPreferences = const {},
]);

factory CalendarPreferences.fromJson(Map<String, dynamic> json) =>
_$CalendarPreferencesFromJson(json);
Expand Down
5 changes: 5 additions & 0 deletions lib/calendarComponent/model/calendar_preferences.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

83 changes: 64 additions & 19 deletions lib/calendarComponent/services/calendar_preference_service.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'dart:convert';
import 'dart:developer';

import 'package:campus_flutter/base/extensions/color.dart';
import 'package:campus_flutter/calendarComponent/model/calendar_preferences.dart';
Expand All @@ -13,23 +14,18 @@ class CalendarPreferenceService {

Map<String, int> colorPreferences = {};
Map<String, bool> visibilityPreferences = {};
Map<String, String> seriesPreferences = {};
bool _loaded = false;

CalendarPreferenceService(this.sharedPreferences);

void saveColorPreference(String id, Color color) {
colorPreferences[id] = color.intValue;
try {
sharedPreferences.setString(
key,
jsonEncode(
CalendarPreferences(colorPreferences, visibilityPreferences).toJson(),
),
);
} catch (_) {}
_persist();
}

Color? getColorPreference(String key) {
if (colorPreferences.isEmpty) {
if (!_loaded) {
loadPreferences();
}

Expand All @@ -39,24 +35,65 @@ class CalendarPreferenceService {

void saveVisibilityPreference(String id, bool isVisible) {
visibilityPreferences[id] = isVisible;
try {
sharedPreferences.setString(
key,
jsonEncode(
CalendarPreferences(colorPreferences, visibilityPreferences).toJson(),
),
);
} catch (_) {}
_persist();
}

bool? getVisibilityPreference(String key) {
if (visibilityPreferences.isEmpty) {
if (!_loaded) {
loadPreferences();
}

return visibilityPreferences[key];
}

void saveSeriesId(String eventId, String seriesId) {
seriesPreferences[eventId] = seriesId;
_persist();
}

String? getSeriesId(String eventId) {
if (!_loaded) {
loadPreferences();
}
return seriesPreferences[eventId];
}

List<String> getSeriesEventIds(String seriesId) {
if (!_loaded) {
loadPreferences();
}
return seriesPreferences.entries
.where((e) => e.value == seriesId)
.map((e) => e.key)
.toList();
}

void removeEventPreferences(Iterable<String> eventIds) {
for (final eventId in eventIds) {
colorPreferences.remove(eventId);
visibilityPreferences.remove(eventId);
seriesPreferences.remove(eventId);
}
_persist();
}

void _persist() {
try {
sharedPreferences.setString(
key,
jsonEncode(
CalendarPreferences(
colorPreferences,
visibilityPreferences,
seriesPreferences,
).toJson(),
),
);
} catch (e) {
log('Failed to persist calendar preferences: $e');
}
}

void loadPreferences() {
try {
final data = sharedPreferences.getString(key);
Expand All @@ -67,11 +104,19 @@ class CalendarPreferenceService {
);
colorPreferences = calendarPreferences.colorPreferences;
visibilityPreferences = calendarPreferences.visibilityPreferences;
seriesPreferences = Map.from(calendarPreferences.seriesPreferences);
}
} catch (_) {}
_loaded = true;
} catch (e) {
log('Failed to load calendar preferences: $e');
}
}

void resetPreferences() {
sharedPreferences.remove(key);
colorPreferences = {};
visibilityPreferences = {};
seriesPreferences = {};
_loaded = true;
}
}
2 changes: 1 addition & 1 deletion lib/calendarComponent/services/calendar_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class CalendarService {

static Future<void> deleteCalendarEvent(String id) async {
RestClient restClient = getIt<RestClient>();
restClient.getWithException(
await restClient.getWithException(
TumOnlineApi(TumOnlineEndpointEventDelete(eventId: id)),
CalendarDeletionConfirmationData.fromJson,
TumOnlineApiException.fromJson,
Expand Down
Loading
Loading