4

I have built a calendar with user's appointments using table_calendar in flutter. In my current code, I can only return all appointments of the user. Now, I am trying to fetch all appointments within a same month only and display them below the calendar. That is to say, when I swap the month on the calendar, I should only see a list of appointments within the month I am currently looking at.

Currently, I am fetching all appointment records of the user from backend. To achieve my goal, which way will be easier:

by defining the 'change month button' with date info of the first day of that month and using it to select corresponding data in backend

OR

still retrieving all appointment records and filter them in frontend somehow?

Can anyone please help me achieving my goal with specific solution?

(As shown in my current output below, while I am at October, I am still seeing the appointment in June). Current Output

Frontend code:

import 'package:flutter/material.dart';
import 'package:table_calendar/table_calendar.dart';
import 'package:frontend/util/authentication.dart';
import 'package:frontend/util/serverDetails.dart';
import 'package:http/http.dart' as http;
import 'package:frontend/components/appointment.dart';
import 'package:frontend/screens/appointmentdetail.dart';
import 'dart:convert';
import 'package:intl/intl.dart';
import 'package:frontend/main.dart';
import 'package:frontend/screens/appointmentlist.dart';

class Appointments extends StatefulWidget {
  @override
  _AppointmentsState createState() => _AppointmentsState();
}

class _AppointmentsState extends State<Appointments>
    with TickerProviderStateMixin {
  var _calendarController;
  Map<DateTime, List> _events;
  List<Appointment> _samemonthevents = List<Appointment>();
  AnimationController _animationController;

  @override
  void initState() {
    super.initState();
    _events = Map<DateTime, List>();
    _calendarController = CalendarController();

    getSameMonthAppointments();
    _animationController = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 400),
    );
    _animationController.forward();
  }

  @override
  void dispose() {
    _calendarController.dispose();
    super.dispose();
  }

  getSameMonthAppointments() async {
    String currentToken = await Authentication.getCurrentToken();
    print(currentToken);
    if (currentToken == null) {
      print('bouncing');
      Authentication.bounceUser(context);
    } else {
      String auth = "Bearer " + currentToken;
      String url = ServerDetails.ip +
          ':' +
          ServerDetails.port +
          ServerDetails.api +
          'me/appointments';
      print(url);
      Map<String, String> headers = {"Authorization": auth};
      print(headers);
      var jsonResponse = null;
      var response = await http.get(url, headers: headers);
      print(response.body);
      if (response.statusCode == 200) {
        print("200" + response.body);
        jsonResponse = json.decode(response.body);
        if (jsonResponse != null) {
          setState(() {
            for (var doc in jsonResponse) {
              _samemonthevents.add(Appointment.fromJson(doc));
            }
          });
        }
      } else {
        print(response.body);
      }
    }
  }

  void _onVisibleDaysChanged(
      DateTime first, DateTime last, CalendarFormat format) {
    print('CALLBACK: _onVisibleDaysChanged');
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: PreferredSize(
          preferredSize: Size.fromHeight(60.0),
          child: AppBar(
            leading: new IconButton(
                icon: new Icon(Icons.arrow_back),
                color: Colors.black,
                onPressed: () {
                  setState(() {});
                  Navigator.push(context,
                      MaterialPageRoute(builder: (context) => MainPage()));
                }),
            centerTitle: true,
            title: Text("Appointment", style: TextStyle(color: Colors.black)),
            backgroundColor: Colors.white,
            brightness: Brightness.light,
            automaticallyImplyLeading: false,
//          backgroundColor: Color(0x44000000),
            elevation: 0.5,
            actions: <Widget>[
              IconButton(
                color: Colors.black,
                icon: Icon(Icons.list),
                onPressed: () {
                  setState(() {});
                  Navigator.push(
                      context,
                      MaterialPageRoute(
                          builder: (context) => AppointmentList()));
                },
              )
            ],
          ),
        ),
        body: new Builder(builder: (BuildContext context) {
          return new Column(children: <Widget>[
            _buildTableCalendarWithBuilders(),
            const SizedBox(height: 8.0),
            const SizedBox(height: 8.0),
            //_buildEventList()
            //_buildsameMonthEventList()
            Expanded(child: _buildsameMonthEventList()),
          ]);
        }));
  }

  // More advanced TableCalendar configuration (using Builders & Styles)
  Widget _buildTableCalendarWithBuilders() {
    return TableCalendar(
      calendarController: _calendarController,
      events: _events,
      //holidays: _holidays,
      initialCalendarFormat: CalendarFormat.month,
      formatAnimation: FormatAnimation.slide,
      startingDayOfWeek: StartingDayOfWeek.sunday,
      availableGestures: AvailableGestures.all,
      availableCalendarFormats: const {CalendarFormat.month: ''},
      calendarStyle: CalendarStyle(
        outsideDaysVisible: false,
        weekendStyle: TextStyle().copyWith(color: Colors.blue[800]),
        holidayStyle: TextStyle().copyWith(color: Colors.blue[800]),
      ),
      daysOfWeekStyle: DaysOfWeekStyle(
        weekendStyle: TextStyle().copyWith(color: Colors.blue[600]),
      ),
      headerStyle: HeaderStyle(
        centerHeaderTitle: true,
        formatButtonVisible: false,
      ),
      builders: CalendarBuilders(
        selectedDayBuilder: (context, date, _) {
          return FadeTransition(
            opacity: Tween(begin: 0.0, end: 1.0).animate(_animationController),
            child: Container(
              margin: const EdgeInsets.all(4.0),
              alignment: Alignment.center,
              decoration: BoxDecoration(
                  color: Colors.blue[300],
                  borderRadius: BorderRadius.circular(36.0),
                  border: Border.all(width: 2, color: Colors.blue[300])),
              child: Text(
                '${date.day}',
                style: TextStyle().copyWith(
                    fontSize: 20.0,
                    color: Colors.black,
                    fontWeight: FontWeight.bold),
              ),
            ),
          );
        },
        todayDayBuilder: (context, date, _) {
          return Container(
            margin: const EdgeInsets.all(4.0),
            alignment: Alignment.center,
            decoration: BoxDecoration(
                color: Colors.white,
                borderRadius: BorderRadius.circular(36.0),
                border: Border.all(width: 2, color: Colors.white)),
            child: Text(
              '${date.day}',
              style: TextStyle().copyWith(
                  fontSize: 20.0,
                  color: Colors.black,
                  fontWeight: FontWeight.bold),
            ),
          );
        },
        markersBuilder: (context, date, events, holidays) {
          final children = <Widget>[];

          if (events.isNotEmpty) {
            children.add(
              Positioned(
                child: _buildEventsMarker(date, events),
              ),
            );
          }

          if (holidays.isNotEmpty) {
            children.add(
              Positioned(
                right: -2,
                top: -2,
                child: _buildHolidaysMarker(),
              ),
            );
          }

          return children;
        },
      ),
      onVisibleDaysChanged: _onVisibleDaysChanged,
    );
  }

  Widget _buildEventsMarker(DateTime date, List events) {
    return AnimatedContainer(
      duration: const Duration(milliseconds: 300),
      margin: const EdgeInsets.all(4.0),
      alignment: Alignment.center,
      decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(36.0),
          border: Border.all(width: 2, color: Colors.blue[300])),
    );
  }

  Widget _buildHolidaysMarker() {
    return Icon(
      Icons.add_box,
      size: 20.0,
      color: Colors.blueGrey[800],
    );
  }

  Widget _buildsameMonthEventList() {
    return Scaffold(
        appBar: PreferredSize(
          preferredSize: Size.fromHeight(22.0),
          child: AppBar(
            centerTitle: true,
            title: Text("Appointments of Current Month",
                style: TextStyle(color: Colors.black, fontSize: 18)),
            backgroundColor: Colors.yellow[200],
            brightness: Brightness.light,
            automaticallyImplyLeading: false,
//          backgroundColor: Color(0x44000000),
            elevation: 0.5,
          ),
        ),
        body: (_samemonthevents.length == 0)
            ? Text("No appointment record in current month!",
                textAlign: TextAlign.center,
                style: TextStyle(color: Colors.black, fontSize: 16))
            : ListView(
                children: _samemonthevents
                    .map((event) => Container(
                        decoration: BoxDecoration(
                          border: Border.all(width: 0.8),
                          borderRadius: BorderRadius.circular(12.0),
                        ),
                        margin: const EdgeInsets.symmetric(
                            horizontal: 8.0, vertical: 4.0),
                        child: (event is Appointment)
                            ? ListTile(
                                leading: Column(children: <Widget>[
                                  //Show Weekday, Month and day of Appiontment
                                  Text(
                                      DateFormat('EE').format(event.date) +
                                          '  ' +
                                          DateFormat.MMMd().format(event.date),
                                      style: TextStyle(
                                        color: Colors.blue.withOpacity(1.0),
                                        fontWeight: FontWeight.bold,
                                      )),
                                  //Show Start Time of Appointment
                                  Text(DateFormat.jm().format(event.date),
                                      textAlign: TextAlign.center,
                                      overflow: TextOverflow.ellipsis,
                                      style: TextStyle(
                                        fontWeight: FontWeight.bold,
                                        height: 1.5,
                                      )),
                                  //Show End Time of Appointment
                                  Text(
                                    DateFormat.jm().format(event.date.add(
                                        Duration(
                                            minutes: event.duration ?? 0))),
                                    style: TextStyle(
                                        color: Colors.black.withOpacity(0.6)),
                                  ),
                                ]), //Text(DateFormat.Hm().format(event.date)),//DateFormat.Hm().format(now)
                                title: Text(event.title),
                                trailing: event.status == 'UNCONFIRMED'
                                    ? Column(children: <Widget>[
                                        //event.status=='CONFIRMED' ?
                                        Icon(Icons.error,
                                            color: Colors.pink,
                                            //size:25.0,
                                            semanticLabel:
                                                'Unconfirmed Appointment'), //:Container(width:0,height:0),
                                        Icon(Icons.arrow_right),
                                      ])
                                    : Icon(Icons.arrow_right),
                                onTap: () {
                                  setState(() {});
                                  Navigator.push(
                                      context,
                                      MaterialPageRoute(
                                          builder: (context) =>
                                              AppointmentDetail(event)));
                                },
                              )
                            : null))
                    .toList()));
  }
}

Backend Code:

AppointmentAPI.java

    @GET
    @Path("me/appointments")
    @Secured(UserRole.PATIENT)
    @JSONP(queryParam = "callback")
    @Produces(MediaType.APPLICATION_JSON)
    public Response listMyAppointments(
            @Context SecurityContext sc,
            @QueryParam("since") String since,
            @QueryParam("until") String until,
            @QueryParam("is_confirmed") Boolean is_confirmed) {

        String uid = sc.getUserPrincipal().getName();
        List<Appointment> results = retrieveUserAppointments(uid, since, until, is_confirmed);

        return Response.ok(results).build();
    }

AppointmentMapper.java

    List<Appointment> getAppointmentsByUserId(
            @Param("uid")  String uid,
            @Param("since")  String since,
            @Param("until")  String until,
            @Param("status") AppointmentStatus status);

AppointmentMapper.xml

<mapper namespace="com.sec.db.AppointmentMapper">
    <select id="getAppointmentById" parameterType="String" resultType="com.sec.entity.Appointment">
        SELECT * FROM Appointment WHERE id= #{id}
    </select>

    <select id="getAppointmentsByUserId" resultType="com.sec.entity.Appointment">
        SELECT *
        FROM Appointment
        WHERE uid= #{uid}
        <choose>
            <when test="since != null and until != null">
                AND date BETWEEN #{since} AND #{until}
            </when>
            <when test="since != null and until == null">
                AND date > #{since}
            </when>
            <when test="since == null and until != null">
                <![CDATA[
                AND date < #{until}
                ]]>
            </when>
        </choose>
        <choose>
            <when test="status == null">
                AND status != 'CANCELLED'
            </when>
            <otherwise>
                AND status = #{status}
            </otherwise>
        </choose>
    </select>

Json Response Example:

### Response

    Status: 200 OK

```JSON
[
  {
    "date": "2020-06-22T14:15:00Z",
    "date_change": "2018-05-14T10:17:40Z",
    "date_create": "2018-05-14T10:17:40Z",
    "detail": "Inflisaport Insertion",
    "duration": 15,
    "id": "2",
    "note": "Looking forward to see you! Take care",
    "status": "CONFIRMED",
    "title": "Private Hospital",
    "uid": "1"
  }
]
Fred
  • 73
  • 2
  • 7
  • need full json response to reproduce this error. please post your full json string. thanks. – chunhunghan Oct 19 '20 at 01:34
  • Sure! But there is no error, getSameMonthAppointments in this case basically just performed as getAppointments, which fetch all records from the database and doesn't take any date input from _onVisibleDaysChanged function. The getSameMonthAppointments in this case is just named for thought yet. – Fred Oct 19 '20 at 02:14
  • Json Response example has been updated! – Fred Oct 19 '20 at 02:20
  • The main issue is that I don't now how to fetch the first date of each month to represent the month correspondingly by '_onVisibleDaysChanged' function. if I can gain that, I could select expected data in database using: SELECT * FROM Appointment WHERE uid= #{uid} AND MONTH(date) = MONTH(#{date}) AND YEAR(date) = YEAR(#{date}) – Fred Oct 19 '20 at 02:29

1 Answers1

3

You can copy paste run full code below
Step 1: You can use a variable current to control current year/month
Step 2: You can in _onVisibleDaysChanged, call setState and set current
Step 3: In _buildsameMonthEventList, do filter with every events year/month with current's year/month

code snippet

DateTime current = DateTime.now();
...
void _onVisibleDaysChanged(
      DateTime first, DateTime last, CalendarFormat format) {
    setState(() {
      current = first;
    });
    print('CALLBACK: _onVisibleDaysChanged first ${first.toIso8601String()}');
  }
...  
 Widget _buildsameMonthEventList() {
    var _samemontheventsFilter = _samemonthevents.where((element) =>
        element.date.year == current.year &&
        element.date.month == current.month);

    return Scaffold(
        ...
        body: (_samemontheventsFilter.length == 0)
            ? Text("No appointment record in current month!",
                textAlign: TextAlign.center,
                style: TextStyle(color: Colors.black, fontSize: 16))
            : ListView(
                children: _samemontheventsFilter
                    .map((event) => Container(  

working demo

enter image description here

full code

import 'package:flutter/material.dart';
import 'package:table_calendar/table_calendar.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:intl/intl.dart';

List<Appointment> appointmentFromJson(String str) => List<Appointment>.from(
    json.decode(str).map((x) => Appointment.fromJson(x)));

String appointmentToJson(List<Appointment> data) =>
    json.encode(List<dynamic>.from(data.map((x) => x.toJson())));

class Appointment {
  Appointment({
    this.date,
    this.dateChange,
    this.dateCreate,
    this.detail,
    this.duration,
    this.id,
    this.note,
    this.status,
    this.title,
    this.uid,
  });

  DateTime date;
  DateTime dateChange;
  DateTime dateCreate;
  String detail;
  int duration;
  String id;
  String note;
  String status;
  String title;
  String uid;

  factory Appointment.fromJson(Map<String, dynamic> json) => Appointment(
        date: DateTime.parse(json["date"]),
        dateChange: DateTime.parse(json["date_change"]),
        dateCreate: DateTime.parse(json["date_create"]),
        detail: json["detail"],
        duration: json["duration"],
        id: json["id"],
        note: json["note"],
        status: json["status"],
        title: json["title"],
        uid: json["uid"],
      );

  Map<String, dynamic> toJson() => {
        "date": date.toIso8601String(),
        "date_change": dateChange.toIso8601String(),
        "date_create": dateCreate.toIso8601String(),
        "detail": detail,
        "duration": duration,
        "id": id,
        "note": note,
        "status": status,
        "title": title,
        "uid": uid,
      };
}

class Appointments extends StatefulWidget {
  @override
  _AppointmentsState createState() => _AppointmentsState();
}

class _AppointmentsState extends State<Appointments>
    with TickerProviderStateMixin {
  var _calendarController;
  Map<DateTime, List> _events;
  List<Appointment> _samemonthevents = List<Appointment>();
  AnimationController _animationController;
  DateTime current = DateTime.now();

  @override
  void initState() {
    super.initState();
    _events = Map<DateTime, List>();
    _calendarController = CalendarController();

    getSameMonthAppointments();
    _animationController = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 400),
    );
    _animationController.forward();
  }

  @override
  void dispose() {
    _calendarController.dispose();
    super.dispose();
  }

  getSameMonthAppointments() async {
    String jsonString = '''
    [
  {
    "date": "2020-09-01T11:15:00Z",
    "date_change": "2018-05-14T10:17:40Z",
    "date_create": "2018-05-14T10:17:40Z",
    "detail": "Inflisaport Insertion",
    "duration": 15,
    "id": "2",
    "note": "Looking forward to see you! Take care",
    "status": "CONFIRMED",
    "title": "Private Hospital",
    "uid": "1"
  },
  {
    "date": "2020-09-22T01:15:00Z",
    "date_change": "2018-05-14T10:17:40Z",
    "date_create": "2018-05-14T10:17:40Z",
    "detail": "Inflisaport Insertion",
    "duration": 15,
    "id": "2",
    "note": "Looking forward to see you! Take care",
    "status": "CONFIRMED",
    "title": "Private Hospital",
    "uid": "1"
  },
  {
    "date": "2020-10-01T07:15:00Z",
    "date_change": "2018-05-14T10:17:40Z",
    "date_create": "2018-05-14T10:17:40Z",
    "detail": "Inflisaport Insertion",
    "duration": 15,
    "id": "2",
    "note": "Looking forward to see you! Take care",
    "status": "CONFIRMED",
    "title": "Private Hospital",
    "uid": "1"
  },
  {
    "date": "2020-10-22T09:15:00Z",
    "date_change": "2018-05-14T10:17:40Z",
    "date_create": "2018-05-14T10:17:40Z",
    "detail": "Inflisaport Insertion",
    "duration": 15,
    "id": "2",
    "note": "Looking forward to see you! Take care",
    "status": "CONFIRMED",
    "title": "Private Hospital",
    "uid": "1"
  },
  {
    "date": "2020-10-30T10:15:00Z",
    "date_change": "2018-05-14T10:17:40Z",
    "date_create": "2018-05-14T10:17:40Z",
    "detail": "Inflisaport Insertion",
    "duration": 15,
    "id": "2",
    "note": "Looking forward to see you! Take care",
    "status": "CONFIRMED",
    "title": "Private Hospital",
    "uid": "1"
  }
]
    ''';

    http.Response response = http.Response(jsonString, 200);
    if (response.statusCode == 200) {
      _samemonthevents = appointmentFromJson(response.body);
    }
  }

  void _onVisibleDaysChanged(
      DateTime first, DateTime last, CalendarFormat format) {
    setState(() {
      current = first;
    });
    print('CALLBACK: _onVisibleDaysChanged first ${first.toIso8601String()}');
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: PreferredSize(
          preferredSize: Size.fromHeight(60.0),
          child: AppBar(
            leading: IconButton(
                icon: Icon(Icons.arrow_back),
                color: Colors.black,
                onPressed: () {
                  setState(() {});
                  /* Navigator.push(context,
                      MaterialPageRoute(builder: (context) => MainPage()));*/
                }),
            centerTitle: true,
            title: Text("Appointment", style: TextStyle(color: Colors.black)),
            backgroundColor: Colors.white,
            brightness: Brightness.light,
            automaticallyImplyLeading: false,
//          backgroundColor: Color(0x44000000),
            elevation: 0.5,
            actions: <Widget>[
              IconButton(
                color: Colors.black,
                icon: Icon(Icons.list),
                onPressed: () {
                  setState(() {});
                  /* Navigator.push(
                      context,
                      MaterialPageRoute(
                          builder: (context) => AppointmentList()));*/
                },
              )
            ],
          ),
        ),
        body: Builder(builder: (BuildContext context) {
          return Column(children: <Widget>[
            _buildTableCalendarWithBuilders(),
            const SizedBox(height: 8.0),
            const SizedBox(height: 8.0),
            //_buildEventList()
            //_buildsameMonthEventList()
            Expanded(child: _buildsameMonthEventList()),
          ]);
        }));
  }

  // More advanced TableCalendar configuration (using Builders & Styles)
  Widget _buildTableCalendarWithBuilders() {
    return TableCalendar(
      calendarController: _calendarController,
      events: _events,
      //holidays: _holidays,
      initialCalendarFormat: CalendarFormat.month,
      formatAnimation: FormatAnimation.slide,
      startingDayOfWeek: StartingDayOfWeek.sunday,
      availableGestures: AvailableGestures.all,
      availableCalendarFormats: const {CalendarFormat.month: ''},
      calendarStyle: CalendarStyle(
        outsideDaysVisible: false,
        weekendStyle: TextStyle().copyWith(color: Colors.blue[800]),
        holidayStyle: TextStyle().copyWith(color: Colors.blue[800]),
      ),
      daysOfWeekStyle: DaysOfWeekStyle(
        weekendStyle: TextStyle().copyWith(color: Colors.blue[600]),
      ),
      headerStyle: HeaderStyle(
        centerHeaderTitle: true,
        formatButtonVisible: false,
      ),
      builders: CalendarBuilders(
        selectedDayBuilder: (context, date, _) {
          return FadeTransition(
            opacity: Tween(begin: 0.0, end: 1.0).animate(_animationController),
            child: Container(
              margin: const EdgeInsets.all(4.0),
              alignment: Alignment.center,
              decoration: BoxDecoration(
                  color: Colors.blue[300],
                  borderRadius: BorderRadius.circular(36.0),
                  border: Border.all(width: 2, color: Colors.blue[300])),
              child: Text(
                '${date.day}',
                style: TextStyle().copyWith(
                    fontSize: 20.0,
                    color: Colors.black,
                    fontWeight: FontWeight.bold),
              ),
            ),
          );
        },
        todayDayBuilder: (context, date, _) {
          return Container(
            margin: const EdgeInsets.all(4.0),
            alignment: Alignment.center,
            decoration: BoxDecoration(
                color: Colors.white,
                borderRadius: BorderRadius.circular(36.0),
                border: Border.all(width: 2, color: Colors.white)),
            child: Text(
              '${date.day}',
              style: TextStyle().copyWith(
                  fontSize: 20.0,
                  color: Colors.black,
                  fontWeight: FontWeight.bold),
            ),
          );
        },
        markersBuilder: (context, date, events, holidays) {
          final children = <Widget>[];

          if (events.isNotEmpty) {
            children.add(
              Positioned(
                child: _buildEventsMarker(date, events),
              ),
            );
          }

          if (holidays.isNotEmpty) {
            children.add(
              Positioned(
                right: -2,
                top: -2,
                child: _buildHolidaysMarker(),
              ),
            );
          }

          return children;
        },
      ),
      onVisibleDaysChanged: _onVisibleDaysChanged,
    );
  }

  Widget _buildEventsMarker(DateTime date, List events) {
    return AnimatedContainer(
      duration: const Duration(milliseconds: 300),
      margin: const EdgeInsets.all(4.0),
      alignment: Alignment.center,
      decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(36.0),
          border: Border.all(width: 2, color: Colors.blue[300])),
    );
  }

  Widget _buildHolidaysMarker() {
    return Icon(
      Icons.add_box,
      size: 20.0,
      color: Colors.blueGrey[800],
    );
  }

  Widget _buildsameMonthEventList() {
    var _samemontheventsFilter = _samemonthevents.where((element) =>
        element.date.year == current.year &&
        element.date.month == current.month);

    return Scaffold(
        appBar: PreferredSize(
          preferredSize: Size.fromHeight(22.0),
          child: AppBar(
            centerTitle: true,
            title: Text("Appointments of Current Month",
                style: TextStyle(color: Colors.black, fontSize: 18)),
            backgroundColor: Colors.yellow[200],
            brightness: Brightness.light,
            automaticallyImplyLeading: false,
//          backgroundColor: Color(0x44000000),
            elevation: 0.5,
          ),
        ),
        body: (_samemontheventsFilter.length == 0)
            ? Text("No appointment record in current month!",
                textAlign: TextAlign.center,
                style: TextStyle(color: Colors.black, fontSize: 16))
            : ListView(
                children: _samemontheventsFilter
                    .map((event) => Container(
                        decoration: BoxDecoration(
                          border: Border.all(width: 0.8),
                          borderRadius: BorderRadius.circular(12.0),
                        ),
                        margin: const EdgeInsets.symmetric(
                            horizontal: 8.0, vertical: 4.0),
                        child: (event is Appointment)
                            ? ListTile(
                                leading: SizedBox(
                                  width: 90,
                                  child: Column(children: <Widget>[
                                    //Show Weekday, Month and day of Appiontment
                                    Text(
                                        DateFormat('EE').format(event.date) +
                                            '  ' +
                                            DateFormat.MMMd().format(event.date),
                                        style: TextStyle(
                                          color: Colors.blue.withOpacity(1.0),
                                          fontWeight: FontWeight.bold,
                                        )),
                                    //Show Start Time of Appointment
                                    Text(DateFormat.jm().format(event.date),
                                        textAlign: TextAlign.center,
                                        overflow: TextOverflow.ellipsis,
                                        style: TextStyle(
                                          fontWeight: FontWeight.bold,
                                          height: 1.5,
                                        )),
                                    //Show End Time of Appointment
                                    Text(
                                      DateFormat.jm().format(event.date.add(
                                          Duration(
                                              minutes: event.duration ?? 0))),
                                      style: TextStyle(
                                          color: Colors.black.withOpacity(0.6)),
                                    ),
                                  ]),
                                ), //Text(DateFormat.Hm().format(event.date)),//DateFormat.Hm().format(now)
                                title: Text(event.title),
                                trailing: event.status == 'UNCONFIRMED'
                                    ? Column(children: <Widget>[
                                        //event.status=='CONFIRMED' ?
                                        Icon(Icons.error,
                                            color: Colors.pink,
                                            //size:25.0,
                                            semanticLabel:
                                                'Unconfirmed Appointment'), //:Container(width:0,height:0),
                                        Icon(Icons.arrow_right),
                                      ])
                                    : Icon(Icons.arrow_right),
                                onTap: () {
                                  setState(() {});
                                  /* Navigator.push(
                        context,
                        MaterialPageRoute(
                            builder: (context) =>
                                AppointmentDetail(event)));*/
                                },
                              )
                            : null))
                    .toList()));
  }
}

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: Appointments(),
    );
  }
}
chunhunghan
  • 51,087
  • 5
  • 102
  • 120
  • There is also a little issue that I noticed, that 'Private Hospital' isn't centered... Is there anyway to fix it? – Fred Oct 19 '20 at 03:18
  • DateTime format issue. use SizedBox to force a static width ListTile( leading: SizedBox( width: 90, child: Column(children: [ //Show Weekday, Month and day of Appiontment Text( – chunhunghan Oct 19 '20 at 03:39
  • Oh my god! You are so efficient!!! If you have any interest, please do have a look over my new question! Many thanks again! Link below: https://stackoverflow.com/questions/64415647/anyway-to-enable-remember-me-function-using-sharedpreferences-in-flutter – Fred Oct 19 '20 at 03:52
  • This solution is so elegant! 0 error, great work! Words could barely express my gratitude to you, savior of the day! – Fred Oct 19 '20 at 04:22
  • Well, It seems there is an error. As you may notice, in the original demo, those date with appointment will marked with a blue circle, which is based on the _buildEventsMarker. Now, since the input has been modified to the first date of each month, this function turns to be invalid. – Fred Oct 19 '20 at 04:42
  • To fix this, just add the original part back then it will work as expected! Wonderful! – Fred Oct 19 '20 at 04:45
  • I just posted a new question [link](https://stackoverflow.com/questions/64435599/how-to-produce-a-list-of-30-days-date-in-flutter) about making an upcoming 30 days list of appointment related to this calendar! I saw you answer before in [link](https://stackoverflow.com/questions/57422219/dart-flutter-list-of-days-in-a-date-range) and tried your solution. Can you please help me with this? Much appreciated! – Fred Oct 19 '20 at 21:59
  • Now event is replased with eventloader. can you please same code with updated version of this library sir. – Abhay kumar bhumihar Jun 17 '22 at 13:41
  • Hello sir, can you please share same demo with updated library . i will very thankful to you. – Abhay kumar bhumihar Jun 17 '22 at 14:06