icalendar_parser .Package to parse iCalendar (.ics) files written in pure Dart.

Implementation of AnyFetch's ics-parser in JavaScript.

Getting Started

Add icalendar_parser to your pubspec.yaml:

icalendar_parser: any

How to use

You can refer to the example/ folder for a complete example implemented in Flutter.

Constructor

ICalendar.fromString

Warning: For unknown reason the command dart test on GitHub Actions will generate errors so try to prefer using ICalendar.fromLines in your unit tests.

import 'package:flutter/services.dart' show rootBundle;
import 'package:icalendar_parser/icalendar_parser.dart';

final icsString = await rootBundle.loadString('assets/your_file.ics');
final iCalendar = ICalendar.fromString(icsString);

ICalendar.fromLines

final icsLines = await File('your_file.ics').readAsLines();
final iCalendar = ICalendar.fromLines(lines);

Other methods

ICalendar.registerField

With this method you can add fields that are not already supported (check Supported Properties) to the parsing and you can specify a custom function to parse its content :

ICalendar.registerField(field: 'TEST');

ICalendar.registerField(
    field: 'TEST2',
    function: (value, params, event, lastEvent) {
        lastEvent['test2'] = 'test';
        return lastEvent;
    },
);

ICalendar.unregisterField

With this method you can remove parsed fields to ignore them in your file :

ICalendar.unregisterField('TEST');

ICalendar.toJson

Convert [ICalendar] object to a Map<String, dynamic> containing all its data, formatted into a valid JSON Map<String, dynamic>.

final icsObj = ICalendar.fromLines(File('assets/my_file.ics').readAsLinesSync());
print(jsonEncode(icsObj.toJson()));

Input

BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//hacksw/handcal//NONSGML v1.0//EN
CALSCALE:GREGORIAN
METHOD:PUBLISH
BEGIN:VEVENT
UID:uid1@example.com
DTSTAMP:19970714T170000Z
ORGANIZER;CN=John Doe:MAILTO:john.doe@example.com
DTSTART:19970714T170000Z
DTEND:19970715T035959Z
SUMMARY:Bastille Day Party
GEO:48.85299;2.36885
END:VEVENT
END:VCALENDAR

Output

{
   "version":"2.0",
   "prodid":"-//hacksw/handcal//NONSGML v1.0//EN",
   "calscale":"GREGORIAN",
   "method":"PUBLISH",
   "data":[
      {
         "type":"VEVENT",
         "uid":"uid1@example.com",
         "dtstamp":"1997-07-14T17:00:00.000Z",
         "organizer":{
            "name":"John Doe",
            "mail":"john.doe@example.com"
         },
         "dtstart":"1997-07-14T17:00:00.000Z",
         "dtend":"1997-07-15T03:59:59.000Z",
         "summary":"Bastille Day Party",
         "geo":{
            "latitude":48.85299,
            "longitude":2.36885
         }
      }
   ]
}

Supported Properties

  • VERSION
  • PRODID
  • CALSCALE
  • METHOD
  • COMPONENT:BEGIN
  • COMPONENT:END
  • DTSTART
  • DTEND
  • DTSTAMP
  • TRIGGER
  • LAST-MODIFIED
  • COMPLETED
  • DUE
  • UID
  • SUMMARY
  • DESCRIPTION
  • LOCATION
  • URL
  • ORGANIZER
  • GEO
  • CATEGORIES
  • ATTENDEE
  • ACTION
  • STATUS
  • SEQUENCE
  • REPEAT
  • RRULE

Use this package as a library

Depend on it

Run this command:

With Dart:

 $ dart pub add icalendar_parser

With Flutter:

 $ flutter pub add icalendar_parser

This will add a line like this to your package's pubspec.yaml (and run an implicit dart pub get):


dependencies:
  icalendar_parser: ^0.8.1

Alternatively, your editor might support dart pub get or flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:icalendar_parser/icalendar_parser.dart';

example/lib/main.dart

import 'dart:core';
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart' show rootBundle;
import 'package:icalendar_parser/icalendar_parser.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as p;

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  ICalendar _iCalendar;
  bool _isLoading = false;

  Future<void> _getAssetsFile(String assetName) async {
    setState(() => _isLoading = true);
    try {
      final directory = await getTemporaryDirectory();
      final path = p.join(directory.path, assetName);
      final data = await rootBundle.load('assets/$assetName');
      final bytes =
          data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
      final file = await File(path).writeAsBytes(bytes);
      final lines = await file.readAsLines();
      setState(() {
        _iCalendar = ICalendar.fromLines(lines);
        _isLoading = false;
      });
    } catch (e) {
      setState(() => _isLoading = false);
      throw 'Error: $e';
    }
  }

  Widget _generateTextContent() {
    const style = TextStyle(color: Colors.black);
    return RichText(
      text: TextSpan(
        children: [
          TextSpan(
              text: 'VERSION: ${_iCalendar.version}\n',
              style: style.copyWith(fontWeight: FontWeight.bold)),
          TextSpan(
              text: 'PRODID: ${_iCalendar.prodid}\n',
              style: style.copyWith(fontWeight: FontWeight.bold)),
          TextSpan(
              text: 'CALSCALE: ${_iCalendar.calscale}\n',
              style: style.copyWith(fontWeight: FontWeight.bold)),
          TextSpan(
              text: 'METHOD: ${_iCalendar.method}\n',
              style: style.copyWith(fontWeight: FontWeight.bold)),
          TextSpan(
              children: _iCalendar.data
                  .map((e) => TextSpan(
                        children: e.keys
                            .map((f) => TextSpan(children: [
                                  TextSpan(
                                      text: '${f.toUpperCase()}: ',
                                      style: style.copyWith(
                                          fontWeight: FontWeight.bold)),
                                  TextSpan(text: '${e[f]}\n')
                                ]))
                            .toList(),
                      ))
                  .toList()),
        ],
        style: style,
      ),
    );
  }

  Future<void> _getAssets(String assetName) async {
    setState(() => _isLoading = true);
    try {
      final icsString = await rootBundle.loadString('assets/$assetName');
      final iCalendar = ICalendar.fromString(icsString);
      setState(() {
        _iCalendar = iCalendar;
        _isLoading = false;
      });
    } catch (e) {
      setState(() => _isLoading = false);
      throw 'Error: $e';
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(16),
        child: Column(
          children: [
            if (_isLoading || _iCalendar == null)
              const Center(child: CircularProgressIndicator())
            else
              _generateTextContent(),
            ElevatedButton(
              onPressed: () => _getAssetsFile('calendar.ics'),
              child: const Text('Load File 1'),
            ),
            ElevatedButton(
              onPressed: () => _getAssetsFile('calendar2.ics'),
              child: const Text('Load File 2'),
            ),
            ElevatedButton(
              onPressed: () => _getAssets('calendar.ics'),
              child: const Text('Load String 1'),
            ),
            ElevatedButton(
              onPressed: () => _getAssetsFile('calendar3.ics'),
              child: const Text('Load File 3'),
            ),
          ],
        ),
      ),
    );
  }
}

#fluter  #dart #mobile-apps

Flutter Package to Parse ICalendar (.ics) Files
3.45 GEEK