Fliin
On this page

Blocks / lists

Event card

Shows an agenda event in its own card: the times it starts and ends in a column, its title, the word now while it is happening, and its place, description and attendees, read as one node.

16 of 16 variants pass
Event card, upcoming state
Platform
Brightness
Text scale
Direction

Import

Event card is part of Fliin Pro. With a license key, sign in once with fliin login, then add it in a Flutter app where fliin init has run:

fliin login
fliin add event-card

Also installs: core, avatar, avatar-group, badge, icons, surface, text

Examples

Upcoming

An event as a card: hours in a column, title, place, description and attendees, counted in attendeesLabel for the screen reader.

Event card, upcoming state
import 'package:your_app/ui/fliin/components/avatar/fl_avatar.dart';
import 'package:your_app/ui/fliin/components/event_card/fl_event_card.dart';
import 'package:flutter/widgets.dart';

class EventCardUpcomingExample extends StatelessWidget {
  const EventCardUpcomingExample({super.key});

  @override
  Widget build(BuildContext context) {
    return FlEventCard(
      title: 'Team check-in',
      start: '9:30\u202fAM',
      end: '10:00\u202fAM',
      timeLabel: 'from 9:30 AM to 10:00 AM',
      location: 'Rivoli room',
      description: 'Sprint progress and blockers.',
      attendees: [
        for (final initials in ['CM', 'LB', 'ND', 'TR']) FlAvatar(initials: initials, variant: FlAvatarVariant.soft),
      ],
      attendeesLabel: '4 attendees',
      onPressed: () {},
    );
  }
}

Current

An event under way: currentLabel adds the "Now" tag.

Event card, current state
import 'package:your_app/ui/fliin/components/event_card/fl_event_card.dart';
import 'package:flutter/widgets.dart';

class EventCardCurrentExample extends StatelessWidget {
  const EventCardCurrentExample({super.key});

  @override
  Widget build(BuildContext context) {
    return FlEventCard(
      title: 'Lunch with Camille',
      start: '12:30\u202fPM',
      end: '2:00\u202fPM',
      timeLabel: 'from 12:30 PM to 2:00 PM',
      location: 'The Corner Bistro',
      currentLabel: 'Now',
      onPressed: () {},
    );
  }
}

All day

An all-day event: start alone, in words, without an end.

Event card, all-day state
import 'package:your_app/ui/fliin/components/event_card/fl_event_card.dart';
import 'package:flutter/widgets.dart';

class EventCardAllDayExample extends StatelessWidget {
  const EventCardAllDayExample({super.key});

  @override
  Widget build(BuildContext context) {
    return FlEventCard(
      title: 'Day off',
      start: 'All day',
      timeLabel: 'all day',
      onPressed: () {},
    );
  }
}

Overnight

An event that ends the next day: end carries its day.

Event card, overnight state
import 'package:your_app/ui/fliin/components/event_card/fl_event_card.dart';
import 'package:flutter/widgets.dart';

class EventCardOvernightExample extends StatelessWidget {
  const EventCardOvernightExample({super.key});

  @override
  Widget build(BuildContext context) {
    return FlEventCard(
      title: 'Night shift',
      start: '10:00\u202fPM',
      end: 'Thu 6:00\u202fAM',
      timeLabel: 'from 10:00 PM to 6:00 AM on Thursday, October 29',
      location: 'Saint-Louis hospital',
      onPressed: () {},
    );
  }
}

Calendars

Events from several calendars: color draws each calendar's stripe along the card's start edge, on the row card as on the small tiles of a week.

Event card, calendars state
import 'package:your_app/ui/fliin/components/event_card/fl_event_card.dart';
import 'package:your_app/ui/fliin/core/fliin.dart';
import 'package:flutter/widgets.dart';

class EventCardCalendarsExample extends StatelessWidget {
  const EventCardCalendarsExample({super.key});

  @override
  Widget build(BuildContext context) {
    final theme = FlScope.of(context);
    final colors = theme.colors;
    return Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      spacing: theme.space.sm,
      children: [
        FlEventCard(
          title: 'Design review',
          start: '14:00',
          end: '15:00',
          timeLabel: 'from 14:00 to 15:00',
          location: 'Studio 2',
          color: colors.accent,
          onPressed: () {},
        ),
        Row(
          crossAxisAlignment: CrossAxisAlignment.start,
          spacing: theme.space.sm,
          children: [
            Expanded(
              child: FlEventCard(
                variant: FlEventCardVariant.tile,
                title: 'Yoga',
                start: '18:30',
                end: '19:30',
                timeLabel: 'from 18:30 to 19:30',
                location: 'Parc Monceau',
                color: colors.success,
                onPressed: () {},
              ),
            ),
            Expanded(
              child: FlEventCard(
                variant: FlEventCardVariant.tile,
                title: 'Dinner with Camille',
                start: '20:30',
                timeLabel: 'at 20:30',
                location: 'The Corner Bistro',
                color: colors.warning,
                onPressed: () {},
              ),
            ),
          ],
        ),
      ],
    );
  }
}

Usage

The code the reference images render:

final example = ColoredBox(
  color: FlScope.of(context).colors.surface,
  child: SingleChildScrollView(
    padding: EdgeInsetsDirectional.all(FlScope.of(context).space.lg),
    child: Builder(
      builder: (context) {
        final width = FlEventCard.measureTimes(context, [
          (variant.dir == TextDirection.rtl ? "٠٩:٣٠" : "09:30"),
          (variant.dir == TextDirection.rtl ? "١٢:٣٠" : "12:30"),
          (variant.dir == TextDirection.rtl ? "اليوم كله" : "All day"),
          (variant.dir == TextDirection.rtl ? "٢٢:٠٠" : "22:00"),
          (variant.dir == TextDirection.rtl ? "١٠:٠٠" : "10:00"),
          (variant.dir == TextDirection.rtl ? "١٤:٠٠" : "14:00"),
          (variant.dir == TextDirection.rtl ? "خميس ٠٦:٠٠" : "Thu 06:00"),
        ]);
        return Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          spacing: FlScope.of(context).space.sm,
          children: [
            FlEventCard(
              title: (variant.dir == TextDirection.rtl
                  ? "اجتماع الفريق"
                  : "Team check-in"),
              start: (variant.dir == TextDirection.rtl ? "٠٩:٣٠" : "09:30"),
              end: (variant.dir == TextDirection.rtl ? "١٠:٠٠" : "10:00"),
              timeLabel: (variant.dir == TextDirection.rtl
                  ? "من ٠٩:٣٠ إلى ١٠:٠٠"
                  : "from 09:30 to 10:00"),
              timeWidth: width,
              location: (variant.dir == TextDirection.rtl
                  ? "قاعة ريفولي"
                  : "Room Rivoli"),
              description: (variant.dir == TextDirection.rtl
                  ? "تقدّم العمل والعوائق."
                  : "Sprint progress and blockers."),
              attendees: [
                for (final initials in const ["CM", "LB", "ND", "TR"])
                  FlAvatar(initials: initials, variant: FlAvatarVariant.soft),
              ],
              attendeesLabel: (variant.dir == TextDirection.rtl
                  ? "٤ مشاركين"
                  : "4 attendees"),
              onPressed: () {},
            ),
            FlEventCard(
              title: (variant.dir == TextDirection.rtl
                  ? "غداء مع كاميل"
                  : "Lunch with Camille"),
              start: (variant.dir == TextDirection.rtl ? "١٢:٣٠" : "12:30"),
              end: (variant.dir == TextDirection.rtl ? "١٤:٠٠" : "14:00"),
              timeLabel: (variant.dir == TextDirection.rtl
                  ? "من ١٢:٣٠ إلى ١٤:٠٠"
                  : "from 12:30 to 14:00"),
              timeWidth: width,
              location: (variant.dir == TextDirection.rtl
                  ? "لو بوتي زنك"
                  : "The Corner Bistro"),
              currentLabel: (variant.dir == TextDirection.rtl
                  ? "جارٍ الآن"
                  : "In progress"),
              onPressed: () {},
            ),
            FlEventCard(
              title: (variant.dir == TextDirection.rtl ? "إجازة" : "Time off"),
              start: (variant.dir == TextDirection.rtl
                  ? "اليوم كله"
                  : "All day"),
              timeLabel: (variant.dir == TextDirection.rtl
                  ? "طوال اليوم"
                  : "all day"),
              timeWidth: width,
              onPressed: () {},
            ),
            FlEventCard(
              title: (variant.dir == TextDirection.rtl
                  ? "مناوبة ليلية"
                  : "Night shift"),
              start: (variant.dir == TextDirection.rtl ? "٢٢:٠٠" : "22:00"),
              end: (variant.dir == TextDirection.rtl
                  ? "خميس ٠٦:٠٠"
                  : "Thu 06:00"),
              timeLabel: (variant.dir == TextDirection.rtl
                  ? "من ٢٢:٠٠ إلى ٠٦:٠٠ يوم الخميس ٢٩ أكتوبر"
                  : "from 22:00 to 06:00 Thursday, October 29"),
              timeWidth: width,
              location: (variant.dir == TextDirection.rtl
                  ? "مستشفى سان لوي"
                  : "St Louis Hospital"),
              onPressed: () {},
            ),
          ],
        );
      },
    ),
  ),
);

API

FlEventCardVariant: enum {row, tile}
FlEventCardVariant.row: static final FlEventCardVariant
FlEventCardVariant.tile: static final FlEventCardVariant
FlEventCard: class extends StatelessWidget
FlEventCard.new: const new({super.key, required String title, required String start, String? end, required String timeLabel, double? timeWidth, String? location, String? description, List<FlAvatar> attendees, String? attendeesLabel, String? currentLabel, VoidCallback? onPressed, String separator, FlEventCardVariant variant, Color? color})
FlEventCard.color: get Color?
FlEventCard.variant: get FlEventCardVariant
FlEventCard.title: get String
FlEventCard.start: get String
FlEventCard.end: get String?
FlEventCard.timeLabel: get String
FlEventCard.timeWidth: get double?
FlEventCard.location: get String?
FlEventCard.description: get String?
FlEventCard.attendees: get List<FlAvatar>
FlEventCard.attendeesLabel: get String?
FlEventCard.currentLabel: get String?
FlEventCard.onPressed: get VoidCallback?
FlEventCard.separator: get String
FlEventCard.measureTimes: static double(BuildContext context, Iterable<String> times)
FlEventCard.build: Widget(BuildContext context)

Reference renders

The 16 images published with version 0.2.3, rendered by the shared harness on macOS with Flutter 3.47.7. fliin verify event-card compares your copy to them.

iOS · Light
Event card, iOS, Light, text 1.0×, Left to right
Text 1.0× · Left to right
Event card, iOS, Light, text 1.0×, Right to left
Text 1.0× · Right to left
Event card, iOS, Light, text 2.0×, Left to right
Text 2.0× · Left to right
Event card, iOS, Light, text 2.0×, Right to left
Text 2.0× · Right to left
iOS · Dark
Event card, iOS, Dark, text 1.0×, Left to right
Text 1.0× · Left to right
Event card, iOS, Dark, text 1.0×, Right to left
Text 1.0× · Right to left
Event card, iOS, Dark, text 2.0×, Left to right
Text 2.0× · Left to right
Event card, iOS, Dark, text 2.0×, Right to left
Text 2.0× · Right to left
Android · Light
Event card, Android, Light, text 1.0×, Left to right
Text 1.0× · Left to right
Event card, Android, Light, text 1.0×, Right to left
Text 1.0× · Right to left
Event card, Android, Light, text 2.0×, Left to right
Text 2.0× · Left to right
Event card, Android, Light, text 2.0×, Right to left
Text 2.0× · Right to left
Android · Dark
Event card, Android, Dark, text 1.0×, Left to right
Text 1.0× · Left to right
Event card, Android, Dark, text 1.0×, Right to left
Text 1.0× · Right to left
Event card, Android, Dark, text 2.0×, Left to right
Text 2.0× · Left to right
Event card, Android, Dark, text 2.0×, Right to left
Text 2.0× · Right to left

Use it to

  • show a meeting in a card with its opening and closing times in a column
  • show who attends a meeting with their avatars
  • show the description or agenda of an event
  • show which event is happening now
  • open a calendar event from its card
Not for
  • an event in a grouped list with dividers: use the event row (event-row)
  • the whole agenda for the day or week: use the agenda (agenda)
  • a task to check off: use a task row (task-row)
States
  • Upcoming
  • Current
  • All day
  • Overnight

Arrows to move, Enter to open, Escape to close.