This commit is contained in:
2026-02-13 15:53:22 +01:00
commit 25271189b5
639 changed files with 49083 additions and 0 deletions

View File

@@ -0,0 +1,49 @@
import 'package:html/parser.dart' show parse;
class WebViewHelper {
static String getHtmlContentWithoutMedia(String htmlContent) {
final doc = parse(addHead(htmlContent));
doc.getElementsByClassName('post_title').forEach((element) {
element.remove();
});
doc.getElementsByClassName('g-breadcrumbs').forEach((element) {
element.remove();
});
doc.getElementsByClassName('post_navigation').forEach((element) {
element.remove();
});
doc.getElementsByTagName('img').forEach((element) {
element.remove();
});
doc.getElementsByTagName('video').forEach((element) {
element.remove();
});
doc.getElementsByTagName('iframe').forEach((element) {
element.remove();
});
return doc.documentElement!.innerHtml;
}
static String addHead(String htmlContent) =>
'<!DOCTYPE html><html><head><meta name="viewport" content="width=device-width, initial-scale=1.0"><style> * { font-family: Segoe UI, Frutiger, Frutiger Linotype, Dejavu Sans, Helvetica Neue, Arial, sans-serif; } </style></head><body>$htmlContent</body></html>';
static List<String> getImageMedia(String htmlContent) {
final doc = parse(htmlContent);
return doc
.getElementsByClassName('w-grid-item-anchor')
.map((e) => e.attributes['href']!)
.toList();
}
static List<String> getWebVideoMedia(String htmlContent) => [];
static List<String> getVideoMedia(String htmlContent) {
final doc = parse(htmlContent);
return doc
.getElementsByTagName('source')
.map((element) => element.attributes['src']!)
.toList();
}
static getContent(String htmlContent) {}
}

182
lib/todo/calendar.dart Normal file
View File

@@ -0,0 +1,182 @@
import 'dart:core';
import 'package:flutter/material.dart';
import 'package:hiddingsel_app/constants/constant.dart';
import 'package:hiddingsel_app/packages/list_view_extension/colum_extension.dart';
import 'package:table_calendar/table_calendar.dart';
import '../constants/enums.dart';
import '../appflow/controller/events.dart';
import '../appflow/model/event.dart';
import '../appflow/view/navigation_drawer.dart';
import 'calendar_list.dart';
class CalendarListPage extends StatefulWidget with NavigationDrawerItem {
final String title = 'Termine';
@override
State<StatefulWidget> createState() => CalendarListPageState();
}
class CalendarListPageState extends State<CalendarListPage> {
List _selectedDayList = [];
Map<DateTime, List<EventModel>> _events = {};
@override
void dispose() {
super.dispose();
}
@override
void initState() {
super.initState();
init();
}
void init() async {
EventController.getEventListStream().forEach((events) {
setState(() {
_events = _mapListToCalendarEvents(events);
});
});
}
@override
Widget build(BuildContext context) => SafeArea(
bottom: false,
child: Padding(
padding: const EdgeInsets.fromLTRB(UIShapes.paddingSimple,
UIShapes.paddingSimple, UIShapes.paddingSimple, 0),
child: ListView(
primary: true,
children: <Widget>[
FormattedCalendar(_events, _onDaySelected),
ColumnExtension.builder(
itemCount: _selectedDayList.length,
itemBuilder: (context, index) =>
CalendarListTile(_selectedDayList[index]),
),
],
),
),
);
void _onDaySelected(DateTime dateTime) {
setState(() {
_selectedDayList = _events[DateTime(dateTime.year, dateTime.month, dateTime.day)] ?? [];
});
}
Map<DateTime, List<EventModel>> _mapListToCalendarEvents(List<EventModel> list) {
final map = <DateTime, List<EventModel>>{};
DateTime dateKey;
int i;
int j;
for (final e in list) {
j = 0;
dateKey = e.schedule.startTime;
do {
if (e.schedule.frequency != Frequency.once && e.schedule.interval != null) {
if (e.schedule.frequency == Frequency.days) {
dateKey = dateKey.add(Duration(days: e.schedule.interval!));
} else if (e.schedule.frequency == Frequency.weeks) {
dateKey = dateKey.add(Duration(days: 7 * e.schedule.interval!));
} else if (e.schedule.frequency == Frequency.months) {
dateKey = dateKey =
DateTime(dateKey.year, dateKey.month + e.schedule.interval!, dateKey.day);
}
if (e.schedule.until != null && e.schedule.until!.isBefore(dateKey)) {
break;
}
}
i = 0;
do {
var dateKey2 = dateKey.add(Duration(days: i));
dateKey2 = DateTime(dateKey2.year, dateKey2.month, dateKey2.day);
if (map.containsKey(dateKey2)) {
map[dateKey2]!.add(e);
} else {
map[dateKey2] = [e];
}
i++;
} while (i < e.schedule.endTime.difference(e.schedule.startTime).inDays);
j++;
} while (e.schedule.frequency != Frequency.once && e.schedule.interval != null && j < 52);
}
return map;
}
}
class FormattedCalendar extends StatefulWidget {
final Map<DateTime, List<EventModel>> _events;
final void Function(DateTime) _onDaySelected;
FormattedCalendar(this._events, this._onDaySelected);
@override
_FormattedCalendarState createState() => _FormattedCalendarState();
}
class _FormattedCalendarState extends State<FormattedCalendar> {
DateTime _focusedDay = DateTime.now();
DateTime? _selectedDay;
_FormattedCalendarState();
@override
Widget build(BuildContext context) {
var firstDay = DateTime.utc(2010, 10, 16);
var lastDay = DateTime.utc(2030, 3, 14);
final calendar = TableCalendar(
locale: 'de_DE',
availableCalendarFormats: const {
CalendarFormat.month: 'Month',
},
headerStyle: HeaderStyle(
titleCentered: true,
titleTextStyle: UITheme.theme.textTheme.headlineSmall!,
),
firstDay: firstDay,
lastDay: lastDay,
focusedDay: _focusedDay,
startingDayOfWeek: StartingDayOfWeek.monday,
calendarStyle: CalendarStyle(
weekendTextStyle: UITheme.theme.textTheme.bodyLarge!,
defaultTextStyle: UITheme.theme.textTheme.bodyLarge!,
todayTextStyle: UITheme.theme.textTheme.bodyMedium!,
selectedTextStyle: UITheme.theme.textTheme.bodyMedium!,
selectedDecoration: BoxDecoration(
color: UIColors.grey5,
shape: BoxShape.circle,
),
todayDecoration: BoxDecoration(
color: UIColors.grey4,
shape: BoxShape.circle,
),
markerDecoration: BoxDecoration(
color: UIColors.yellow,
shape: BoxShape.circle,
)
),
eventLoader: (day) {
return _getEventsForDay(day);
},
selectedDayPredicate: (day) {
return isSameDay(_selectedDay, day);
},
onDaySelected: (selectedDay, focusedDay) {
setState(() {
_selectedDay = selectedDay;
_focusedDay = focusedDay;
widget._onDaySelected(selectedDay);
});
},
);
return calendar;
}
List<EventModel> _getEventsForDay(DateTime day) {
return widget._events[DateTime(day.year, day.month, day.day)] ?? [];
}
}

View File

@@ -0,0 +1,55 @@
import 'package:flutter/material.dart';
import 'package:hiddingsel_app/constants/constant.dart';
import 'package:intl/intl.dart';
import '../appflow/model/event.dart';
class CalendarListTile extends StatelessWidget {
final EventModel _event;
const CalendarListTile(this._event);
@override
Widget build(BuildContext context) {
String time;
if (_event.schedule.isAllDay) {
time = 'Ganztägig';
} else {
time =
'${DateFormat('kk:mm').format(_event.schedule.startTime)} - ${DateFormat('kk:mm').format(_event.schedule.endTime)} Uhr';
}
return Card(child:
ExpansionTile(
leading: ShaderMask(
shaderCallback: (Rect bounds) {
return UIGradiants.yellow.createShader(bounds);
},
child: Container(
width: UIShapes.paddingSimple,
decoration: new BoxDecoration(
color: Colors.white,
shape: BoxShape.circle,
),
),
),
title: Text(_event.name, style: UITheme.theme.textTheme.displaySmall,),
childrenPadding: EdgeInsets.all(UIShapes.paddingSimple),
children: <Widget>[
Container(
width: 1000,
child:
Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Termin: $time', style: UITheme.theme.textTheme.bodyLarge,),
Divider(),
Text('Ort: ${_event.contact.location?.address ?? 'Keine Angabe'}', style: UITheme.theme.textTheme.bodyLarge,),
Divider(),
Text('Veranstalter: ${_event.eventOrganizer.map((e) => e.name).toList().join(', ')}', style: UITheme.theme.textTheme.bodyLarge,),
],
),),
],
),
);
}
}

212
lib/todo/calendar_old.dart Normal file
View File

@@ -0,0 +1,212 @@
import 'dart:core';
/*class CalendarListPage extends StatefulWidget with NavigationDrawerItem {
final String title = 'Termine';
@override
State<StatefulWidget> createState() => CalendarListPageState();
}
class CalendarListPageState extends State<CalendarListPage> {
List _selectedDayList = [];
Map<DateTime, List<EventModel>> _events = {};
CalendarController? _calendarController;
@override
void dispose() {
_calendarController!.dispose();
super.dispose();
}
@override
void initState() {
super.initState();
_calendarController = CalendarController();
init();
}
void init() async {
EventController.getEventListStream().forEach((events) {
setState(() {
_events = _mapListToCalendarEvents(events);
_selectedDayList = events
.where((e) =>
DateTime(e.schedule.startTime.year, e.schedule.startTime.month, e.schedule.startTime.day) ==
DateTime(
_calendarController!.selectedDay.year,
_calendarController!.selectedDay.month,
_calendarController!.selectedDay.day))
.toList();
});
});
}
@override
Widget build(BuildContext context) => SafeArea(
bottom: false,
child: Padding(
padding: const EdgeInsets.fromLTRB(UIShapes.paddingSimple,
UIShapes.paddingSimple, UIShapes.paddingSimple, 0),
child: ListView(
primary: true,
children: <Widget>[
FormattedCalendar(_events, _calendarController!, _onDaySelected),
ColumnExtension.builder(
itemCount: _selectedDayList.length,
itemBuilder: (context, index) =>
CalendarListTile(_selectedDayList[index]),
),
],
),
),
);
void _onDaySelected(DateTime dateTime, List list, List list2) {
setState(() {
_selectedDayList = list.isEmpty ? [] : list;
});
}
Map<DateTime, List<EventModel>> _mapListToCalendarEvents(List<EventModel> list) {
final map = <DateTime, List<EventModel>>{};
DateTime dateKey;
int i;
int j;
for (final e in list) {
j = 0;
dateKey = e.schedule.startTime;
do {
if (e.schedule.frequency != Frequency.once && e.schedule.interval != null) {
if (e.schedule.frequency == Frequency.days) {
dateKey = dateKey.add(Duration(days: e.schedule.interval!));
} else if (e.schedule.frequency == Frequency.weeks) {
dateKey = dateKey.add(Duration(days: 7 * e.schedule.interval!));
} else if (e.schedule.frequency == Frequency.months) {
dateKey = dateKey =
DateTime(dateKey.year, dateKey.month + e.schedule.interval!, dateKey.day);
}
if (e.schedule.until != null && e.schedule.until!.isBefore(dateKey)) {
break;
}
}
i = 0;
do {
var dateKey2 = dateKey.add(Duration(days: i));
dateKey2 = DateTime(dateKey2.year, dateKey2.month, dateKey2.day);
if (map.containsKey(dateKey2)) {
map[dateKey2]!.add(e);
} else {
map[dateKey2] = [e];
}
i++;
} while (i < e.schedule.endTime.difference(e.schedule.startTime).inDays);
j++;
} while (e.schedule.frequency != Frequency.once && e.schedule.interval != null && j < 52);
}
return map;
}
}
class FormattedCalendar extends StatelessWidget {
final Map<DateTime, List> _events;
final CalendarController _controller;
final void Function(DateTime, List, List) _onDaySelected;
const FormattedCalendar(this._events, this._controller, this._onDaySelected);
@override
Widget build(BuildContext context) {
final defaultCalendar = TableCalendar(
calendarController: CalendarController(),
);
final calendar = TableCalendar(
locale: 'de_DE',
availableCalendarFormats: const {
CalendarFormat.month: 'Month',
},
headerStyle: HeaderStyle(
centerHeaderTitle: true,
titleTextBuilder: (date, locale) =>
'${getMonthName(date.month)} ${date.year.toString()}'.toUpperCase(),
titleTextStyle: UITheme.theme.textTheme.headline5,
),
daysOfWeekStyle: DaysOfWeekStyle(
weekendStyle: defaultCalendar.daysOfWeekStyle.weekdayStyle,
dowTextBuilder: (date, locale) =>
getDayName(date.weekday).toUpperCase(),
),
startingDayOfWeek: StartingDayOfWeek.monday,
calendarStyle: CalendarStyle(
outsideWeekendStyle: defaultCalendar.calendarStyle.outsideStyle,
weekendStyle: defaultCalendar.calendarStyle.weekdayStyle
.apply(color: UIColors.grey5),
weekdayStyle: defaultCalendar.calendarStyle.weekdayStyle
.apply(color: UIColors.grey5),
eventDayStyle: defaultCalendar.calendarStyle.weekdayStyle
.apply(color: UIColors.grey5,),
todayColor: UIColors.grey3,
selectedColor: UIColors.grey5,
markersColor: Color(0xFFFFD445),
),
events: _events,
calendarController: _controller,
onDaySelected: _onDaySelected,
);
return calendar;
}
static String getMonthName(int month) {
switch (month) {
case 1:
return 'Januar';
case 2:
return 'Februar';
case 3:
return 'März';
case 4:
return 'April';
case 5:
return 'Mai';
case 6:
return 'Juni';
case 7:
return 'July';
case 8:
return 'August';
case 9:
return 'September';
case 10:
return 'Oktober';
case 11:
return 'November';
case 12:
return 'Dezember';
default:
return '?';
}
}
static String getDayName(int month) {
switch (month) {
case 1:
return 'Mo';
case 2:
return 'Di';
case 3:
return 'Mi';
case 4:
return 'Do';
case 5:
return 'Fr';
case 6:
return 'Sa';
case 7:
return 'So';
default:
return '?';
}
}
}
*/

143
lib/todo/parser.dart Normal file
View File

@@ -0,0 +1,143 @@
import 'package:hiddingsel_app/appflow/model/event_organisations.dart';
import 'package:hiddingsel_app/appflow/model/location.dart';
import '../constants/enums.dart';
import '../appflow/model/contacts.dart';
import '../appflow/model/event.dart';
import '../appflow/model/schedules.dart';
class IcalParser {
static List<EventModel> parse(String data) {
final regex = RegExp('BEGIN:VEVENT(.*?)END:VEVENT', dotAll: true);
return regex
.allMatches(data)
.map((e) => e.group(0))
.map((e) => _parseToEvent(e!))
.where((e) => e != null)
.cast<EventModel>()
.toList();
}
static EventModel? _parseToEvent(String data) {
try {
final cleandData = data.replaceAll('\n', '\r');
final String id = RegExp('UID:(.*?)\\r').firstMatch(cleandData)!.group(1)!;
final String summary =
RegExp('SUMMARY.*?:(.*?)\\r').firstMatch(cleandData)!.group(1)!;
final String dtStart =
RegExp('DTSTART.*:(.*?)\\r').firstMatch(cleandData)!.group(1)!;
final String dtEnd = RegExp('DTEND.*:(.*?)\\r').firstMatch(cleandData)!.group(1)!;
final description =
RegExp('DESCRIPTION:(.*?)\\r').firstMatch(cleandData)?.group(1);
var location =
RegExp('LOCATION:(.*?)\\r').firstMatch(cleandData)?.group(1)?.replaceAll('\\,', ',');
final attendees =
RegExp('ATTENDEE.*?CN=(.*?);', dotAll: true).allMatches(cleandData).map((e) => e.group(1)?.replaceAll('\r', '')
.replaceAll('\n', '')
.replaceAll(' ', '')).where((e) => e != null).cast<String>().toList();
final freq = RegExp('RRULE.*?FREQ=(.*?);', dotAll: true)
.firstMatch(cleandData)
?.group(1);
final interval = RegExp('RRULE.*?INTERVAL=(.*?);', dotAll: true)
.firstMatch(cleandData)
?.group(1);
final until = RegExp('RRULE.*?UNTIL=(.*?);', dotAll: true)
.firstMatch(cleandData)
?.group(1);
final List<EventOrganisationModel> eventOrganizer;
if(location!.contains('Brinkstraße')) {
location = 'Hiddingsel';
eventOrganizer = [EventOrganisationModel.fromId('garbage')!];
} else {
eventOrganizer = attendees.map((e) => fromAttendee(e)).where((e) => e != null).cast<EventOrganisationModel>().toList();
}
var freqKey = Frequency.once;
if (freq == 'DAILY') {
freqKey = Frequency.days;
} else if (freq == 'WEEKLY') {
freqKey = Frequency.weeks;
} else if (freq == 'MONTHLY') {
freqKey = Frequency.months;
}
return EventModel(id,
ScheduleModel(
_parse(dtStart),
_parse(dtEnd),
freqKey,
interval != null ? _parseInt(interval) : 1,
until != null ? _parse(until) : null
),
summary,
ContactModel(location: LocationModel(address: location)),
description: description,
eventOrganizer: eventOrganizer,
);
} catch (e) {
return null;
}
}
static DateTime _parse(String data) => DateTime.parse(data).toLocal();
static int _parseInt(String data) => int.parse(data);
static EventOrganisationModel? fromAttendee(String? attendee) {
if(attendee == null) return null;
switch (attendee) {
case 'sportverein@hiddingsel.de':
return EventOrganisationModel.fromId('svVorwaertsHiddingsel');
case 'dorfgemeinschaft@hiddingsel.de':
return EventOrganisationModel.fromId('dorfgemeinschaft');
case 'dorfnews@hiddingsel.de':
return EventOrganisationModel.fromId('dorfgemeinschaft');
case 'schuetzenverein-hiddingsel@hiddingsel.de':
return EventOrganisationModel.fromId('allgemeinerSchuetzenverein');
case 'kolping@hiddingsel.de':
return EventOrganisationModel.fromId('kolpingfamilieHiddingsel');
case 'landjugend@hiddingsel.de':
return EventOrganisationModel.fromId('landjugendHiddingsel');
case 'feuerwehr@hiddingsel.de':
return EventOrganisationModel.fromId('freiwilligeFeuerwehr');
case 'kirche@hiddingsel.de':
return EventOrganisationModel.fromId('stGeorgKirche');
case 'kindergarten@hiddingsel.de':
return EventOrganisationModel.fromId('kindergarten');
case 'grundschule@hiddingsel.de':
return EventOrganisationModel.fromId('grundschule');
case 'landfrauen@hiddingsel.de':
return EventOrganisationModel.fromId('landfrauen');
case 'schuetzenverein-daldrup@hiddingsel.de':
return EventOrganisationModel.fromId('daldruperSchuetzenverein');
case 'landwirtschaftlicher-ortsverein@hiddingsel.de':
return EventOrganisationModel.fromId('landwirtschaflicherOrtsverein');
case 'drk@hiddingsel.de':
return EventOrganisationModel.fromId('drk');
case 'eltern-kind-gruppe@hiddingsel.de':
return EventOrganisationModel.fromId('elternKindGruppe');
case 'kfd@hiddingsel.de':
return EventOrganisationModel.fromId('kfd');
case 'kulturforum@hiddingsel.de':
return EventOrganisationModel.fromId('kulturforum');
case 'psg@hiddingsel.de':
return EventOrganisationModel.fromId('pfadfinderinnenschaftStGeorg');
case 'seniorengemeinschaft@hiddingsel.de':
return EventOrganisationModel.fromId('seniorengemeinschaft');
case 'voices@hiddingsel.de':
return EventOrganisationModel.fromId('voices');
case 'aida@hiddingsel.de':
return EventOrganisationModel.fromId('aktivInDasAlter');
case 'foerderverein-kiga-schule@hiddingsel.de':
return EventOrganisationModel.fromId('foerdervereinKigaSchu');
case 'buecherei@hiddingsel.de':
return EventOrganisationModel.fromId('buecherei');
case 'jaegerzug@hiddingsel.de':
return EventOrganisationModel.fromId('jaegerzug');
case 'cdu@hiddingsel.de':
return EventOrganisationModel.fromId('cdu');
default:
return null;
}
}
}

View File

@@ -0,0 +1,63 @@
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:timezone/timezone.dart' as tz;
class ScheduledNotificationConnector {
static Future<bool?> initialize() async {
const initializationSettingsAndroid =
AndroidInitializationSettings('@mipmap/ic_launcher');
const initializationSettingsDarwin =
DarwinInitializationSettings(
requestAlertPermission: false,
requestBadgePermission: false,
requestSoundPermission: false,
);
const initializationSettings = InitializationSettings(
android: initializationSettingsAndroid,
iOS: initializationSettingsDarwin,
macOS: initializationSettingsDarwin);
return FlutterLocalNotificationsPlugin().initialize(initializationSettings);
}
static Future<void> displayNotification(
int id, String title, String description) async {
final platformChannelSpecifics = NotificationDetails(
android: AndroidNotificationDetails(
'1', 'Benachrichtigungen', channelDescription: 'Benachrichtigungen'));
await FlutterLocalNotificationsPlugin().show(
id,
title,
description,
platformChannelSpecifics,
);
}
static Future<void> scheduleNotification(
int id,
DateTime scheduledNotificationDateTime,
String title,
String description) async {
if (scheduledNotificationDateTime.isBefore(DateTime.now())) {
return;
}
final platformChannelSpecifics = NotificationDetails(
android: AndroidNotificationDetails(
'1', 'Benachrichtigungen', channelDescription: 'Benachrichtigungen'));
await FlutterLocalNotificationsPlugin().zonedSchedule(
id.hashCode,
title,
description,
tz.TZDateTime.from(scheduledNotificationDateTime, tz.local),
platformChannelSpecifics,
androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle,
uiLocalNotificationDateInterpretation:
UILocalNotificationDateInterpretation.absoluteTime);
}
static Future<void> cancelScheduledNotification(String id) async {
await FlutterLocalNotificationsPlugin().cancel(id.hashCode);
}
static Future<void> cancelAllScheduledNotification() async {
await FlutterLocalNotificationsPlugin().cancelAll();
}
}