70 lines
2.4 KiB
Dart
70 lines
2.4 KiB
Dart
import 'dart:io';
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:icalendar_parser/icalendar_parser.dart';
|
|
import 'package:path_provider/path_provider.dart';
|
|
import 'package:open_filex/open_filex.dart';
|
|
import 'package:universal_html/html.dart' as html;
|
|
import 'package:intl/intl.dart';
|
|
|
|
import '../models/cycle_entry.dart';
|
|
|
|
class IcsService {
|
|
static Future<void> generateCycleCalendar(List<CycleEntry> entries) async {
|
|
final iCalendar = ICalendar(
|
|
properties: {
|
|
'prodid': '-//Christian Period Tracker//NONSGML v1.0//EN',
|
|
'version': '2.0',
|
|
'calscale': 'GREGORIAN',
|
|
'x-wr-calname': 'Cycle Tracking',
|
|
'x-wr-timezone': DateTime.now().timeZoneName,
|
|
},
|
|
components: [],
|
|
);
|
|
|
|
// Sort entries by date to ensure proper calendar order
|
|
entries.sort((a, b) => a.date.compareTo(b.date));
|
|
|
|
for (var entry in entries) {
|
|
if (entry.isPeriodDay) {
|
|
final date = entry.date;
|
|
final formattedDate = DateFormat('yyyyMMdd').format(date);
|
|
final uid = '${date.year}${date.month}${date.day}-${entry.id}@christianperiodtracker.app';
|
|
|
|
iCalendar.components.add(
|
|
CalendarEvent(
|
|
properties: {
|
|
'uid': uid,
|
|
'dtstamp': IcsDateTime(dt: DateTime.now()),
|
|
'dtstart': IcsDateTime(dt: date, isUtc: false, date: true), // All-day event
|
|
'dtend': IcsDateTime(dt: date.add(const Duration(days: 1)), isUtc: false, date: true), // End on next day for all-day
|
|
'summary': 'Period Day',
|
|
'description': 'Period tracking for ${DateFormat.yMMMd().format(date)}',
|
|
},
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
final String icsContent = iCalendar.serialize();
|
|
final String fileName = 'cycle_calendar_${DateFormat('yyyyMMdd').format(DateTime.now())}.ics';
|
|
|
|
if (kIsWeb) {
|
|
// Web platform
|
|
final bytes = icsContent.codeUnits;
|
|
final blob = html.Blob([bytes], 'text/calendar');
|
|
final url = html.Url.createObjectUrlFromBlob(blob);
|
|
html.AnchorElement(href: url)
|
|
..setAttribute('download', fileName)
|
|
..click();
|
|
html.Url.revokeObjectUrl(url);
|
|
} else {
|
|
// Mobile platform
|
|
final directory = await getApplicationDocumentsDirectory();
|
|
final filePath = '${directory.path}/$fileName';
|
|
final file = File(filePath);
|
|
await file.writeAsString(icsContent);
|
|
await OpenFilex.open(filePath);
|
|
}
|
|
}
|
|
}
|