Lanerope

Cross-Platform Mobile App
Project Overview
Welcome to Lanerope! Lanerope is a cross-platform mobile app developed using Flutter & hosted with Firebase. I began this project in May 2021, and continued working on it through the summer until mid-August 2021. The goals of this project were to learn a new programming language, familiarize myself with more coding techniques, learn about front-end design, and become more comfortable with project management & version control software. As of the last testing in September 2021, the app is stable on Android. While it has not been tested on iOS, all widgets and packages used are compatible with iOS. The full code can be found on my GitHub page at https://github.com/noahbetik/lanerope . In the meantime, please enjoy this feature overview! If you have any questions, please feel free to message me on LinkedIn, or toss me an email at noah.betik@gmail.com.
Features
  • Account management system using Firebase Authentication, including form validation
  • Announcements page with optional header images, and post-publishing editing for coaches
  • Admin Panel with a search feature to find any user of the app, group pages with the option to assign and reassign athletes to groups & basic athlete info & a system for coaches to subscribe to groups they manage
  • Fully functional direct-messaging system with picture messaging, controlled-access contacts (athletes may only message their own coach), and sent/delivered/received status updating
  • Calendar with events assignable to specific people or groups & support for recurring events
Skills Acquired
Programming/Software
May 2021 — Aug 2021
  • Dart progamming Language
  • Firebase database management (documents, collections, array unions)
  • Basic front-end design principles& debugging
  • State management patterns (ephemerally using StatefulWidget; BLoC state management pattern)
  • Real-time widget rebuilding using StreamBuilder & QuerySnapshots
  • Asynchronous programming, Future datatypes, and FutureBuilder
  • Experience with Git & GitHub, including basic Git operations, projects, issues, and wikis

Login Page

This is the login page, or the first screen that a user will see upon installing the app. After a user logs in, their login state is stored locally on the device using the "shared_preferences" package, meaning that once they log in, they will be directed to the home page upon opening the app until the log out again.

Note as well the button below to create an account!

Account Creation

This is the account creation page. Here the user fills in the required fields, as well as selects their role. While I didn't have time to get to validation to ensure that no athletes or parents masquerade as coaches, that would be a critical feature for production versions of this app.

RegEx expressions were used to ensure that an appropriate set of characters were used for each text field, while the "datetime_picker_formfield" package was used for date selection. This package is used everywhere else where datetime selection is needed.

Once an account is created, a new user is established in Firebase's Firebase Authentication. The unique UID generated is used in a Firestore Database as a document title to store all other user data such as name and birthdate.

Account Creation 2

Here's an example of a user entering an invalid password. Note the change in text underneath the password line as well as the change in colour of the border.


The image on the right is another valid account about to be created (go Raptors!). It will be used later for the messaging demo.

Announcements & Home Page

This is the announcements page, which also doubles as the home page. Coaches are able to write and publish announcements (as seen later) with an optional cover image, which can be viewed by anyone, but is only editable by other coaches (although in practice, only allowing the author to make changes is likely preferred). This is done by removing the icon button (the pencil icon to the right of the "view full" button) for anyone without the Coach/Admin role.

The image on the right is shown when a user presses the "View Full" button to view the entire announcement. This page is scrollable if the announcement is too long to fit on the screen uninterrupted. (and yes, the espresso was delicious!)

The announcements page is built using a StreamBuilder to dynamically pull any new announcements or changes and has support for multiple pages.

Announcement Editor

This is the announcement editor page, which only users with the Coach/Admin role have access to. The image selection is done using the "image_picker" and "image_cropper" packages, but it is possible to publish the announcement without a cover image. It should be noted that the multi-line textfield used for the main announcement text lacks support for 3rd party keyboards (most notably SwiftKey), but this appears to be an issue on Flutter's end.

Upon pressing publish, the announcement is added to Firestore, with accompanying pictures being stored in Firebase Storage. The Storage URL for the picture is stored in Firestore for later retrieval.

Admin Panel -- Overview

This is the Admin Panel, where coaches are able to organize groups before and during the season. On the left is a preview of all group pages, while on the right shows the expandable card with checkboxes to select which groups to subscribe to. When a user selects a group and presses "subscribe", that info is relayed to their user document in the Firestore database for future use, and a card for that group is created. A coach with no subscribed groups will have no group cards. In the future, the cover image will be selected by the coach, but for the summer project, I figured a bunny would be just fine :)

It should be noted that coaches also have an option in the app settings to lock the checkboxes and thus prevent future subscriptions with a switch.

Admin Panel -- Groups

By pressing the red floating button, a user can add a new group, as seen on the left. This is useful when initially setting up the app since every swim club has different names for their groups.

On the right is a card's expandable section which shows all the athletes and coaches affiliated with the group. The pencil icon can be used to view the info for that user as well as to reassign their group, as shown later. Note as well the search icon on the upper right!

Admin Panel -- Search Bar

The search bar can be used to find any user in the app, and is accessed by tapping the search bar shown oin the previous section. it initially shows all users before filtering out any users that do not contain the substring in the search query.

The Admin Panel uses the BLoC state management pattern to handle switching the view between the search function and also passes the value from the text controller to the filter. It uses two states (CardsShown and SearchShown) driven by three events (ShowSearch, ShowFilter, and Update Filter), with support for as many more as could be needed in future versions.

Admin Panel -- Athlete Info

Tapping the pencil icon for any athlete brings up their info that they submitted during their account creation. The dropdown menu also allows the coach to assign them to a different group. Changes take effect after pushing the "Submit" button, which pushes all changes to the relevant places in Firestore.

As a result, the Admin Panel is built using a FutureBuilder, which waits for the completion of a couple of asynchronous functions that pull the needed info from the database to build the cards. A spinning progress indicator is displayed instead while these functions are still running.

Calendar -- Overview

The calendar pages has a few different formats, which can be changed by pressing the button to the right of the month/year, as shown. Once events have been added by a coach, they appear as dots on the day they occur. By selecting a day, a user can view a list of events for that day. The calendar UI is based off of the "table_calendar" package, which provides all the visual elements, but requires events to be implemented by the developer.

The calendar uses the BLoC state management to handle displaying the list of events for a selected date.

Calendar -- Event Creation

Coaches can create an event by tapping on the floating red button on the bottom right. After giving the event start & end datetimes and a title, a coach can assign the event to a specific list of groups or individuals using the "People/Groups" textfield, as shown in the next section. Added entities are shown as chips below the textfield.

Calendar -- Assignees

Similarly to the search function used in the Admin Panel, this textfield uses the BLoC state management pattern to allocate the space below the textfield for either the other fields (show previously) or for a list of entities that match the filter text. The list is only displayed when the filter contains a non-empty string. To be precise, even if the textfield is in focus, the fields will still be displayed unless the user has typed something.

Coaches can select an entity either by tapping on it in the list, or by pressing space if the string matches a valid person or group. Strings that do not match a valid entity are indicated with a red border and message. Entities that have already been added cannot be added again, and display a corresponding message.

Calendar -- Time & Date Selection

Date and time selection for events, using the same package as previously mentioned. This needs to be done for a start datetime, end datetime, and a second date to end recurring events if that is selected.

Calendar -- Recurring Events

Upon choosing a recurring event frequency from the radio list, the following dialog pops up to prompt the user to select a date to stop the recurring event. Recurring events are stored in Firestore as a list of dates.

Calendar -- Extra Views

These pictures show a completed version of the fields for event creation, as well as a pop-up that is shown if a user clicks an existing event from the list shown.

Video coming soon!

Direct Messaging -- Video Tour

The direct messaging (DM) service is centered around Firebase and a StreamBuilder to provide live conversation updates. Conversations are stored using the two UIDs of the participants and contain a list of all messages as well as a conversation status (sent, delivered, received, error). Each "message" entry in the database contains the message text, the user who sent it, and a timestamp. This data is used to create the familiar formatting in the chat UI. A listview builder is used to lazily retrieve messages, while keep-alives are used on any picture messages to prevent them from reloading (which takes a noticeable amount of time) when the user scrolls away and then back to them.

New messages are indicated when the user is at their list of conversations by bolding the name and message of the relevant conversation.