Refactor: Implement multi-item inventory for Pad Tracker and dynamic navigation
This commit is contained in:
@@ -1,69 +1,57 @@
|
||||
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 'package:path_provider/path_provider.dart';
|
||||
import 'package:share_plus/share_plus.dart'; // Ensure share_plus is in dependencies or use printing/share mechanism
|
||||
import '../models/cycle_entry.dart';
|
||||
|
||||
// Since we might not have share_plus in the pubspec explicitly seen earlier (user plan said adding dependencies),
|
||||
// keeping it safe. The pubspec had 'pdf', 'printing', 'path_provider', 'universal_html'.
|
||||
// 'share_plus' was not explicitly in the list I viewed in Step 258, but 'printing' can share PDF.
|
||||
// For ICS, we need a way to share the file. 'printing' relies on pdf.
|
||||
// Wait, Step 258 pubspec content lines 9-48...
|
||||
// I don't see `share_plus`.
|
||||
// I'll check `pubspec.yaml` again to be absolutely sure or add it via `flutter pub add`.
|
||||
// Actually, `printing` has a share method but it's specific to PDF bytes usually? No, `Printing.sharePdf`.
|
||||
// I should use `share_plus` if I want to share a text/ics file.
|
||||
// Or I can just write to file and open it with `open_filex`.
|
||||
|
||||
import 'package:open_filex/open_filex.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
|
||||
final buffer = StringBuffer();
|
||||
buffer.writeln('BEGIN:VCALENDAR');
|
||||
buffer.writeln('VERSION:2.0');
|
||||
buffer.writeln('PRODID:-//Christian Period Tracker//Cycle Calendar//EN');
|
||||
|
||||
// Sort entries
|
||||
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 dateStr = DateFormat('yyyyMMdd').format(entry.date);
|
||||
buffer.writeln('BEGIN:VEVENT');
|
||||
buffer.writeln('UID:${entry.id}');
|
||||
buffer.writeln('DTSTAMP:${DateFormat('yyyyMMddTHHmmss').format(DateTime.now())}Z');
|
||||
buffer.writeln('DTSTART;VALUE=DATE:$dateStr'); // All day event
|
||||
buffer.writeln('DTEND;VALUE=DATE:${DateFormat('yyyyMMdd').format(entry.date.add(const Duration(days: 1)))}');
|
||||
buffer.writeln('SUMMARY:Period');
|
||||
buffer.writeln('DESCRIPTION:Logged period day.');
|
||||
buffer.writeln('END:VEVENT');
|
||||
}
|
||||
}
|
||||
|
||||
final String icsContent = iCalendar.serialize();
|
||||
final String fileName = 'cycle_calendar_${DateFormat('yyyyMMdd').format(DateTime.now())}.ics';
|
||||
buffer.writeln('END:VCALENDAR');
|
||||
|
||||
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);
|
||||
// Save to file
|
||||
final directory = await getApplicationDocumentsDirectory();
|
||||
final file = File('${directory.path}/cycle_calendar.ics');
|
||||
await file.writeAsString(buffer.toString());
|
||||
|
||||
// Open/Share file
|
||||
final result = await OpenFilex.open(file.path);
|
||||
if (result.type != ResultType.done) {
|
||||
throw 'Could not open file: ${result.message}';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user