# Projects

Jump to Project 2 - Flutter Giftr App

# 1. PWA - Suggest A Movie

Installable, Offline-first PWA built with the The Movie DB API (opens new window).

# List of Requirements

  1. 4 HTML pages - Home, Search Results, Suggested Movies, 404 page.
  2. There must be a service worker that manages all requests from the webpage.
  3. A cache managed from the Service Worker.
  4. All HTTP Requests from the browser are managed by the Service Worker.
  5. A second dynamic image cache can be used to hold the movie poster images returned requested from TMDB (opens new window).
  6. You need to have a default placeholder image for missing movie posters. Store it in the static cache. When an poster_path value in the API results is null, then replace it with the placeholder image.
  7. The user should be able to do a new search from any page in the app.
  8. Running a search should take the user to the search results page.
  9. Clicking on a movie card from any screen should take the user to the suggested movies screen.
  10. When navigating to the search results page, the current search term needs to be added to the query string.
  11. When navigating to the suggested movies page, the movie id AND the movie title should be put in the query string.
  12. All movie results should be displayed as cards that show a movie title, movie poster image, and at least two other values from the API results.
  13. There should be a common app header bar at the top of each screen.
  14. The button to do a search can be in the app header bar or in a footer bar.
  15. The app header bar and the optional footer should be fixed position at the top and bottom of the screen. The other content will scroll underneath both. Make sure that all the content can be seen when the user scrolls - do not leave content hidden under the header or footer.
  16. The main script should have listeners for being online / offline and pass a message to the service worker about a change in the online state.
  17. IndexedDB saves the results array from every call (both the search and the suggest). The search results go into one store and the suggested results go into a different store.
  18. The search results use the search keyword as the key path. The suggested results use the movie id as the key path.
//example object for search entry in search store.
{ keyword: 'buffy', results: [{}, {}, {}] }
//example object for suggested entry in suggested store.
{ movieid: 12365, results: [{}, {}, {}] }
1
2
3
4
  1. When the user does a search for a movie or suggestion the app should check first in the IndexedDB Store(s) for a match before attempting the call to the Movie DB API. If there is no match then make the API call.
  2. You can use the Materialize CSS or Bootstrap 5 framework or your own CSS, plus the Material Icon set, to build the interface.
  3. Customize your colour scheme.
  4. Apply a size limit to the dynamic image cache which will limit the number of movie poster images being dynamically cached. Keep the most recent 30 or 40 images in the cache.
  5. On the search results and suggested pages, show the keyword or the movie title as the page title, or part of it. This gives the user context for the cards being shown.
  6. The PWA must pass the Lighthouse tests in Chrome.
  7. The PWA must be installable.
  8. The PWA must work offline. When offline, the home page will work, a search will work (if previously run), a search will display a message about being unavailable if not previously run, a suggested list will work (if previously run), a suggested list will display a message about being unavailable if not previously run. The 404 page can be used instead of displaying a message on the search and suggested pages.
  9. The IndexedDB code can be in either your app.js or sw.js or both, as long as it checks the DB before doing the fetch and after a fetch it puts the new data into the DB.

# TMDB Endpoints

  • To search for a movie by keyword - /search/movie?api_key={your api key}&query={keyword}
  • To get a suggested list use either:
    • /movie/{movie-id}/similar
    • /movie/{movie-id}/recommendations

Here is a demo of a sample version the PWA in action with a discussion of the requirements. This demo is just to give you a general idea of what needs to be built. You need to customize it and make it your own.

And here is the SVG flowchart with the basic logic for the search within the webpage (not the service worker).

flowchart of program logic for interface

# Submission

  1. Create a private Github Repo and invite your professor to the repo.
  2. Submit the URL for your private Github repo that contains your project to BS LMS.

Due Week 7 (See BS LMS for exact date)

# 2. GIFTR Flutter App with API from MAD9124

Schitts Creek gift Rachel McAdams gift Kims Convienence gift

The final project is to create a Mobile Flutter App called Giftr. This is an app for saving gift ideas for people the user knows. In MAD9124 you are building the API and backend for this app. You will have the same partner for both MAD9124 and MAD9022 to build these. Both people should be working on both parts. Start by building your API because you will need this to test your app.

You can use the code from the static demo repo as the starter code for this app (opens new window).

Due Thursday April 21, 2022 by 11:59pm

This is the final deadline. There will be no extensions.

Counts for 25% of your MAD9022 final grade.

# Giftr 🎁 General Details

The starter code provides A LOT of the functionality, albeit in a simplified version. You will need to read this code and understand what it is doing to be able to modify it.

The starter demo version has many of the features working. However, it uses static Arrays instead of calls to the back end API. This means each time you navigate to a new page, you will be seeing the initial data again.

Both the login and signup buttons will log the user in and take them to the people list page. You need to update this to use the API that you build plus handle a proper JWT token. The JWT Token needs to be saved in SharedPreferences. On each page load, you need to make sure that a token exists inside of SharedPreferences. If the token does not exist, send the user back to the login screen.

Every call to the API will need to add the token from SharedPreferences in the Http Request headers. If any Http Request returns a response that says the user is not logged in, then you need to delete your SharedPreferences token and send the user back to the login screen.

The app needs to use global styling through a Theme that you create in a separate dart file that is imported and loaded through the MaterialApp theme: property.

The ListTile widgets displayed on the people and gifts pages, in the demo, represent the data from the static Arrays. You need to update these to get data from the API instead of the static Arrays.

Other than the login and register features, all the other requests to the API will need to use a fetch header x-api-key. Every request for people or gifts must be filtered by the user_id. More details about this header will be provided in the MAD9124 assignment description (opens new window).

Navigation in the demo version is done by updating a state variable inside main.dart and then replacing the entire Scaffold with a new version.

You can use this simple approach to navigation in your Flutter app, OR if you want, you may use the Navigator object and the push, pushNamed, and pop methods to manage a Stack of screens.

This app does NOT need a Drawer or a BottomNavigationBar, unless you want to put the logout button inside a Drawer.

# Screen Features

There are five screens in the Giftr App - Login/Sign up, People, Add/Edit Person, Gifts, Add Gift.

# Login/Sign Up Screen

This is the home screen EVERY time the app loads. It has a Form, two TextFormField widgets, two ElevatedButton widgets and a possible Toast widget.

The form fields are the email and password that the user needs to provide to login or signup.

The buttons are the two possible actions - login and sign up. Pressing either button needs to validate the entire form and then make an API call to the appropriate API endpoint. A successful call to either should accept a new JWT token that needs to be written to SharedPreferences so that it can be used throughout the rest of the app. Any Failed API call should display the reason for the failure in a Toast message, styled to look like an error message.

After a successful API call and saving of the token in SharedPreferences

# People Screen

The people page gives the user the ability to:

  • View the list of people that belong to the currently logged in user.
  • Add a new person from a FAB (navigate to the Add/Edit person screen)
  • Navigate to the gifts page to see the list of gift ideas for that one person.
  • You may optionally delete people with Dismissable widgets wrapped around your ListTile widgets

The people list needs to be created with a ListView.builder() constructor.

The people in your list should be displayed as ListTile widgets.

The people in the ListView must be sorted by the order that their birthdays appear in the year. By Month and by day.

The background of the ListTile widgets for birthdays that have past must be different that the birthdays that are still to come. The ones that are in the past should be more muted (less contrast) than the ones that are still to come.

In each ListTile, display the person's full name as the title, and the Month and Day of birth as the subtitle. There needs to be two IconButtons - one to navigate to the Add/Edit Person screen, and one to navigate to the Gifts screen. Remember, when navigating between the people and gifts you need to know who owns the people and ideas. This is why you have the token from the server saved in SharedPreferences - to include it in all your API calls.

There needs to be a way to logout from here. An IconButton in the AppBar or in a Drawer.

The FAB at the bottom right of the screen will navigate to the Add/Edit Person Screen.

# Add / Edit Person Screen

This single screen is used for both adding a new person OR editing an existing person.

There are two ways to arrive at this screen - clicking the edit icon for a person or clicking the FAB. If the user clicked the FAB then the person id sent to this screen will be empty (null or empty string). If the user clicked an edit icon then the actual person id should be sent to the screen. Use this value to determine which API endpoint to call.

If the user is editing a person, then display the current values for the person in the text fields.

Every person will require a name and date of birth. The id will be created server side.

There needs to be at least one button - a save button.

Deleting of people can be done either with a Dismissable widget on the People screen or with a delete button plus an AlertDialog on the Add/Edit person screen. AlertDialog video and reference (opens new window).

# Gifts Screen

On the gifts screen, you should show a list of gifts for the selected person along with the ability to delete an idea or add a new idea. The page also needs to display the name of the person that the ideas are for. The person name can be displayed in the AppBar or as part of the content in the Scaffold body.

The screen needs to use a ListView.builder() to create the scrollable list. The gift information for each gift needs to be displayed in a ListTile. The demo version has a basic display with a title and subtitle. You should use more widgets inside each ListTile to display all the information.

Each gift idea needs to include a title, a price, a store name, and a url for the store/product. The id will be created server side. More details about each gift property will be provided in the assignment notes in MAD9124.

There needs to be a way of navigating back to the people page from the gifts page. A back arrow in the AppBar is the standard method to do this.

There needs to be a FAB in the bottom right of the screen to navigate to the Add Gift screen.

You can have the user delete any gift idea by either using a Dismissable widget wrapped around your ListTile or by using an IconButton plus an AlertDialog for confirmation of the delete. As long as it is a two step process. Reference with video for AlertDialog (opens new window).

There must be a way to logout from the Gifts screen - either a IconButton in the AppBar or in a Drawer.

# Add Gift Screen

The id of the selected person must be passed to and available on this screen too.

The Add Gift Screen needs to include a form field for each a title, a price, a store name, and a url for the store/product. Be sure to reference

There is a save button to make the API call and add the gift for the selected person to the database.

There must be a cancel button or a back arrow in the AppBar to get back to the Gifts screen.

# Themeing

You MUST create at least one Theme for your Flutter app that is created in a separate dart file. It can be a dark or a light theme or both. If you define a dark theme then make sure that the background colours are generally dark and the text is light.

The Theme should be loaded via the theme: property inside the MaterialApp() widget.

The colours should be consistent throughout the app.

There must be good contrast between the text and the backgrounds throughout the app.

Your theme should contain default ThemeData for the Widgets that you are using eg: ListTile, ElevatedButton, AppBar, FloatingActionButton, DrawerHeader, Icon, IconButton, ColourScheme and TextTheme for TextStyles, InputDecoration, etc. inside your theme file. The goal is to do as much of your styling in the theme file, as possible.

REMEMBER

Be sure to frequently update your repo. Use git add and git commit every time you complete a step.

Always do your work in a feature branch, NOT the main branch. You can create as many feature branches as you want. They can be to add a feature, add a screen, update a theme, anything.

When you complete a feature, use git push to update it on the server. Treat this like your backup during development and early testing.

Be sure to add the protection for your main branch in your repo settings.

When you want to test your app, use pull requests and merge your feature branches into the main branch.

Have one person be in charge of doing the pull requests and merges. This person should test the app after EVERY merge.

# Submission

  1. Create a private Github Repo and invite your professor to the repo. There will be one repo to submit for each team.
  2. Submit the URL for your private Github repo that contains your project to BS LMS. In the notes for submission, you must include the name of your partner.
  3. If your Flutter App uses a publicly accessible API then please also submit that URL.
  4. If you do NOT have a publicly accessible API that your Flutter app is using then you also need to submit the link to your Repo for your API.
  5. Also invite Prof3ssorSt3v3 to your API repo please.

Due Week 15 (See BS LMS for exact date)

DEADLINE

Keep in mind that ALL submissions, even late ones, have to be submitted by Thursday April 21st. No submissions will be accepted after that.

Challenges

Here is a list of things that you can challenge yourself to add, either with your submission or after the semester.

  • Switching to the Navigator object to build a Stack of screens, instead of using a state variable in main.dart to switch the Scaffold's body.
  • Add a Launcher Icon using the CLI tool from week 13 notes.
  • Add a SplashScreen.
  • Add a custom RefreshIndicator and pull to refresh with data.
  • Add an export feature that would let the user send a list of gift ideas for a selected person via sms or email.
  • Add the ability to take a picture and store it in the app directory on the device for each gift. Use the gift unique id as part of the file name.
  • Add the ability to take a picture in the app, with the camera, and upload it to the server-side via your API. Then be able to download and display the images for people or users or gifts. This will require server-side changes too.
  • Check the Platform and use that to decide whether the add person and add gift buttons use a FAB or an Add + FlatButton in the AppBar. (Android or iOS).
Last Updated: 4/18/2022, 3:57:31 PM