Sprint 3 - ISIS3510-Team14/Wiki GitHub Wiki

Flutter team:

  • Maria Alejandra Estrada Garcia
  • Marilyn Stephany Joven Fonseca
  • David Cuevas Alba

Swift Team:

  • Ernesto José Duarte
  • Lina Gómez
  • Eduardo Herrera

  • This is the most challenging sprint because your team must deliver a functional prototype for each chosen platform.
  • This prototype must be free of eventual connectivity errors, and, therefore, it must pass the basement, elevator, and Q building tests.

Business Questions

Type 2:

  • What are the closest recycling points?: It’s type 2 because the user is going to interact with the map displayed on the app.

  • How effective is the ‘Daily Reminder to Recycle’ notification in encouraging users to login within the same day?: This is a type 2 question because it measures user interaction with the daily notification by tracking how many users log a recycling activity after receiving it. The data helps optimize notification timing to maximize engagement, and the notifications are shown to the user.

Type 3:

  • How frequently do users return to the app within 24 hours of their last login?: This is a type 3 question because it focuses on understanding user engagement with the app's core functionality. By analyzing this return frequency, the business can gauge the app's ability to retain users and make data-driven decisions on features or improvements that may increase user retention and re-engagement.

  • What percentage of users access the map through the navbar vs. the main page button?: This is a type 3 question because it focuses on understanding user engagement with the app's flow. By analyzing this return frequency (fraction), the business can measure the most accessible way of entering this feature and consider changes on the user interface given the proportions of usage.

  • How frequently do users choose to classify their garbage through the scan feature versus consulting the recycle information section?: This is a Type 3 question because it helps analyze user preferences and engagement with the app's core functionalities. By understanding the proportion of users who prefer the scan feature over the recycle information section, the app team can assess the value of each feature and explore potential enhancements based on user behavior.

Type 5:

  • What recycling information should we add or update based on user engagement data to different trash types to make the information more effective?: This is a Type 5 question, combining Type 3 (New or updated features) and Type 4 (Benefits from data). It focuses on analyzing user engagement data to identify which recycling information tips is the most effective and which need improvement, guiding updates or additions to enhance the feature's educational impact.

Eventual Connectivity Strategies

We've implemented connectivity strategies to manage various scenarios where network availability may be intermittent or lost. The primary goal is to ensure that core functionalities remain accessible and usable, even in offline conditions, by leveraging local storage and reactive network monitoring.

Flutter & Swift version

In both the Flutter and Swift versions of the app, we implemented the same eventual connectivity strategies to address various scenarios where network availability may be intermittent or lost. The goal is to provide a robust and seamless user experience by managing connectivity fluctuations effectively. Here are the key connectivity scenarios and design solutions for the app:

ID Connectivity Scenario 1
Event Description Users who have previously logged in with internet access can access the app offline. Profile and session data are stored locally, allowing offline login. However, first-time login requires internet access to authenticate via Auth0.
System Response - When Offline: The app checks for saved credentials and grants access to offline features.
- When Online: The app retrieves and updates credentials as necessary, allowing login through Auth0 if needed.
Possible Antipatterns - Blocked App (Antipattern #1): If the app doesn’t handle connectivity issues properly, it could fail, preventing access to offline features.
- Non-informative Message (Antipattern #3): Displaying generic error messages when credentials are missing could confuse users.
Caching + Retrieving Strategy Cache, Falling Back to Network: User credentials and session data are accessed from local storage first; network retrieval occurs only if data is unavailable or outdated.
Storage Type Shared Preferences (Flutter standard for local storage) and Keychain (Swift)
Storage Data Type Key-Value Pair (<String, String>): User credentials, tokens, and profile information.

ID Connectivity Scenario 2
Event Description The app continuously monitors internet connectivity. If the connection is lost during a critical operation (e.g., login or data submission), an alert is displayed. Core online features are disabled until connection is restored, at which point a "No internet connection" notification is shown.
System Response - When Offline: A message is displayed, and online-dependent actions are disabled.
- When Online: The app automatically restores functionalities.
Possible Antipatterns Lost Content (Antipattern #4): Data might appear incomplete if the app fails to handle cached data correctly during offline mode.
Caching + Retrieving Strategy Cache, Falling Back to Network: User credentials and session data are accessed from local storage first; network retrieval occurs only if data is unavailable or outdated.
Storage Type Cache Manager
Storage Data Type Boolean for connectivity status, Strings for offline messages and error handling.

ID Connectivity Scenario 3
Event Description To maintain session security, users can log out regardless of connection status. If online, the app logs out through Auth0 and clears local data. If offline, it shows a message indicating internet is required to log out and provides a retry option.
System Response - When Offline: A red dialog with a retry button displays, prompting the user to reconnect for logout.
- When Online: The logout request is processed through Auth0, and the user is redirected to the login screen after clearing local credentials.
Possible Antipatterns - Unavailable Functionality After Connection Recovery (Antipattern #7): If logout is delayed due to lack of connection, the app should ensure that functionality resumes once connected.
- Non-existent Result Notification (Antipattern #5): The app should avoid ambiguous notifications regarding logout success if offline.
Caching + Retrieving Strategy Cache, Falling Back to Network: Logout status and credentials are cached and in local storage upon network response, allowing quick access when needed.
Storage Type Shared Preferences for Flutter and Keychain for Swift
Storage Data Type Key-Value Pair (<String, String>): Token and session data indicating logout status.
ID Connectivity Scenario 4
Event Description Users attempt to perform a scan using the camera feature while offline. The app saves the scanned images temporarily to local storage. When internet connectivity is restored and users return to the home screen, a pop-up notifies them that the images are available for viewing, providing an option to review the stored images.
System Response - When Offline: The camera scan proceeds, and scanned images are saved locally in temporary storage.
- When Online: The app detects the restored connectivity and, upon navigating to the home screen, displays a pop-up indicating that previously scanned images are available. Users can view these images by selecting the option presented in the pop-up.
Possible Antipatterns - Unclear Behavior (Antipattern #8): If users aren’t informed of how to access their scans when the connection is back it maybe difficult to find them.
Caching + Retrieving Strategy Temporary Storage, with Pop-up Notification on Connectivity Restoration: Images are cached in local storage first, and users are notified of image availability only when the app detects internet connectivity.
Storage Type Device Temporary Storage (for offline storage of images)
Storage Data Type File: List of image files saved temporarily to be viewed once connectivity is restored.
ID Connectivity Scenario 5
Event Description Users attempt to access the map feature to view GreenPoints locations for the first time. If they are offline, a pop-up message informs them that an internet connection is required for the initial data fetch. However, if they are online during the initial access, the app fetches GreenPoints data from Firebase, caches it locally, and allows users to view the locations offline in future sessions.
System Response - When Offline (First Access): A pop-up is displayed, notifying users that an internet connection is needed to access GreenPoints information for the first time. Users cannot view the map or GreenPoints data until connectivity is restored.
- When Online (First Access): The app fetches data from Firebase, saves GreenPoints locations and information in cache, and displays the data on the map. For subsequent offline sessions, users can access the cached GreenPoints information even without an internet connection.
Possible Antipatterns - Unclear Initial Requirement (Antipattern #7): Not informing users that connectivity is necessary for initial access may lead to confusion if they try to access the map offline for the first time.
- Excessive Connectivity Requirement (Antipattern #3): Requiring an internet connection for each access after the initial fetch instead of caching the data could frustrate users in areas with limited connectivity.
Caching + Retrieving Strategy Firebase Data Caching for Offline Availability: On the first online access, the app retrieves GreenPoints data from Firebase, caches it locally, and automatically checks for updates when connectivity is available. The cached data allows seamless access to GreenPoints information during offline sessions.
Storage Type Local Device Cache (used for caching GreenPoints information retrieved from Firebase)
Storage Data Type Firestore documents: data format for storing GreenPoints locations, descriptions, and other details in the local cache.

Photos examples:

Camera Scan Feature


Here we can see what happens when the user tries to make a camera scan without an internet connection.


In this case the internet connection is lost mid scan, which requests the user to try again (which would result in the previous image)


This is what the user sees after storing their images for later use when they visit the home screen and there is an internet connection.


These are the cached images displayed for the user to scan when they are available.

Map Feature


Once the user access for the first time it should tell that there is no information in cache to be shown.


After the user has had accessed the map feature with WiFi it will show the map locations stored in cache.

Local Storage Strategies

Flutter version

In the Flutter implementation, the LoginScreen and ProfileScreen leverage a local storage strategy to manage user credentials and profile data using the shared_preferences package. This strategy allows for offline data persistence, enabling users to remain logged in even without an active internet connection.

  • LoginScreen: Manages user authentication, handles login state, and checks connectivity.
  • ProfileScreen: Displays user profile data retrieved from local storage.
  • StorageService: A service responsible for saving, retrieving, and clearing user credentials and other profile data locally.

Process:

  1. User Authentication:
  • When the user attempts to log in, the authenticate method is called. This method initiates the authentication process with Auth0, using the webAuthentication method.
  • If authentication is successful, it retrieves the user's credentials (such as ID token, email, name, and other information). These credentials are decoded using JWT Decoder to extract claims (like the user's name, email, picture, etc.).
  1. Saving Credentials to Local Storage:
  • After decoding the credentials, the app extracts essential user information (e.g., full_name, nickname, email, last_login, and picture).
  • The extracted information is stored in a Map<String, dynamic>, which is then passed to the saveUserCredentials method in the StorageService.
  • The StorageService serializes this data into a JSON string using jsonEncode and saves it locally on the device using the shared_preferences package.
  1. Checking for Stored Credentials:
  • During the app's initialization, the _checkIfLoggedIn method in LoginScreen attempts to retrieve stored credentials by calling the getUserCredentials method from StorageService.
  • The getUserCredentials method fetches the stored JSON string from shared_preferences, decodes it into a Map<String, dynamic>, and returns the result.
  • If stored credentials are found, the user is automatically navigated to the /home screen, avoiding the need to log in again.
  1. Handling User Logout:
  • If the user logs out, the app can clear the stored credentials using the clearUserData method in StorageService. This method removes the stored JSON string from shared_preferences.

Expected behavior: Users can seamlessly log in, view their profile, and maintain access to their data without re-authenticating every time they open the app, as long as their credentials are stored locally. The LoginScreen should recognize previously saved credentials upon launch, allowing automatic navigation to the main content of the app. ProfileScreen retrieves and displays the user’s profile data, ensuring that the experience feels continuous and stable. If the user logs out, all data should be cleared from local storage, and the app will prompt for login on the next launch.

Behavior under eventual connectivity: Such as intermittent or no internet access, the local storage strategy allows the app to operate in an offline-first mode. The LoginScreen can leverage stored credentials to bypass the login process even without an active internet connection, providing a smooth offline experience. However, actions requiring a network, such as updating profile data or logging out (if it triggers a server-side logout), may be temporarily delayed until connectivity is restored. Upon reconnection, these pending actions should sync with the server, ensuring data consistency across both the app and Auth0.

Swift Version

In the Swift implementation, the LoginView and ProfileView leverage a local storage strategy to manage user credentials and profile data using the Keychain. This strategy allows for offline data persistence, enabling users to remain logged in even without an active internet connection.

  • LoginView: Manages user authentication, handles login state, and checks connectivity.
  • ProfileView: Displays user profile data retrieved from local storage.
  • LoginViewModel: Handles the business logic for authentication and session management.
  • KeychainService: A service responsible for saving, retrieving, and clearing user credentials and other profile data securely in the Keychain.
  • ConnectivityManager: Monitors network connectivity status throughout the app.

Process:

  1. User Authentication:

    • When the user attempts to log in, the authenticate() method in LoginViewModel is called. This method initiates the authentication process with Auth0 using Auth0.webAuth().start.
    • If authentication is successful, it retrieves the user's credentials (such as ID token). The ID token is then decoded to extract claims (like the user's name, email, picture, etc.).
    • The extracted user profile information is stored in a UserProfile struct.
  2. Saving Credentials to Local Storage:

    • After decoding the credentials, the app extracts essential user information (e.g., name, nickname, email, picture).
    • The extracted information is stored in a UserProfile instance, which is then passed to the saveSession() method in LoginViewModel.
    • The saveSession() method uses the KeychainService to securely store the ID token and user profile in the Keychain.
  3. Checking for Stored Credentials:

    • During the app's initialization, the loadSession() method in LoginViewModel attempts to retrieve stored credentials by calling KeychainService.loadToken() and KeychainService.loadProfile().
    • If stored credentials are found, isAuthenticated is set to true, and the user is automatically navigated to the HomeView, avoiding the need to log in again.
  4. Handling User Logout:

    • When the user logs out, the app calls the logout() method in ProfileView.
    • This method clears the session both locally and optionally with Auth0, depending on connectivity.
    • The clearLocalSession() method in LoginViewModel is called to remove the stored token and profile from the Keychain.
    • isAuthenticated is set to false, which navigates the user back to the LoginView.

Expected Behavior: Users can seamlessly log in, view their profile, and maintain access to their data without re-authenticating every time they open the app, as long as their credentials are stored locally. The LoginView recognizes previously saved credentials upon launch, allowing automatic navigation to the main content of the app. ProfileView retrieves and displays the user’s profile data, ensuring that the experience feels continuous and stable. If the user logs out, all data is cleared from local storage, and the app will prompt for login on the next launch.

Behavior under Eventual Connectivity: In scenarios such as intermittent or no internet access, the local storage strategy allows the app to operate in an offline-first mode. The LoginView leverages stored credentials to bypass the login process even without an active internet connection, providing a smooth offline experience. However, actions requiring a network, such as updating profile data or logging out via Auth0 (if online logout is desired), may be temporarily delayed until connectivity is restored. Upon reconnection, these pending actions can sync with the server, ensuring data consistency across both the app and Auth0.

Caching Strategies

Flutter version

To achieve eventual connectivity in Flutter we decided to implement a caching strategy in the map feature, this to improve performance and user experience.

This specifically helps with the loading times and the offline access, as the map is fetching data from Firebase but this data is not constantly being updated, the app will have in cache the information if it has loaded before. This is specifically important when connectivity is inconsistent, for offline-first experience.

In other cases it is expected to reduce network usage and Battery efficiency by avoiding the constant fetching, as accessing the server takes up high network usage which can impact performance and cause delays in mobile environments.

Expected Behavior: Once the user access the map feature the app fetches all the information to be displayed in the list view, and when accessing directly to the information of a green point takes the info that was just brought and displays it in a new view.

Behavior with eventual connectivity: When the user access for the first time to the map and has no connection to internet a pop-up will be displayed saying that should be connected to access for the first time when data should be fetched from Firebase. If the user access this feature for the first time with connectivity, all the GreenPoints information will be stored in cache, for when the user access offline he can still get the locations and info of the green points.

To implement eventual connectivity in Flutter, we have designed a caching strategy for the camera scan feature. This approach improves user experience and performance, especially under inconsistent network conditions, by allowing offline access to previously captured images.

When users capture images while offline, the app saves these images locally. This allows users to continue using the feature even without a stable internet connection, ensuring they don’t lose access to their scans. When connectivity is restored, the app notifies users that their images are now viewable in the home screen gallery. This offline-first approach is critical for maintaining seamless functionality and a positive user experience.

This caching strategy also conserves network usage and battery efficiency, as it avoids unnecessary data transfers when connectivity is unreliable. Accessing the server repeatedly can strain network resources, slowing the app down and reducing mobile performance.

Expected Behavior: Once a user completes a scan, the captured image data is saved to local storage. If the user is online, these images are immediately uploaded to the server and available in the gallery.

Behavior with Eventual Connectivity: If the user performs a scan offline, the image is stored locally with a notification displayed in the home screen once internet connectivity returns. This notification allows users to review all stored images. Additionally, if a scan is performed while offline for the first time, a pop-up advises the user that a connection is required to view and sync data in the gallery upon returning online.

Swift version

To achieve eventual connectivity in Swift we decided to implement a caching strategy in the map feature, this to improve performance and user experience.

This specifically helps with the loading times and the offline access, as the map is fetching data from Firebase but this data is not constantly being updated, the app will have in cache the information if it has loaded before at least once before. This is specifically important when connectivity is inconsistent, for offline-first experience. So when the user first download the app the map would be downloaded for the first time.

Expected Behavior: Once the user access the map feature the app fetches all the information to be displayed in the list view and detailed view, and when accessing directly to the information of a green point it will take the information that was just brought in and displays it in a new detailed view and saves it to the caché in case there is lost connection.

Behavior with eventual connectivity: When the user access for the first time to the map and has no connection to internet a pop-up will be displayed saying that should be connected to access for the first time when data should be fetched from Firebase. If the user access this feature for the first time with connectivity, all the GreenPoints information will be stored in cache, for when the user access he can still get access to the locations of the green points, but will get the green points in a default order that is nor according its current position.

Multi-Threading Strategies

Flutter Version

Since Flutter is single-threaded by default, we use asynchronous functions and isolates to handle complex tasks without blocking the main UI thread, ensuring smooth and responsive performance in scenarios involving image capturing and caching.

In this app, multi-threading strategies are implemented using async functions for tasks that rely on network connectivity, such as fetching or uploading images. For tasks that could strain the main thread, like processing or caching large image files, isolates are used to manage these operations separately. This approach helps maintain the app’s responsiveness, allowing users to continue interacting with the interface smoothly while image processing and caching occur in the background.

Expected Behavior: When a user captures an image, the processing and caching occur in a background isolate, freeing the main thread for user interactions. For instance, when images are uploaded after a connection is restored, the async functions handle network requests without interrupting the UI.

Behavior with Eventual Connectivity: If the user captures images offline, these are cached locally through async operations and processed in the background. Once connectivity is re-established, a notification appears on the home screen to indicate that the images have synced with the server. This ensures that the app remains responsive even when performing complex tasks, providing a seamless user experience regardless of connectivity status.

Swift Version

Since Flutter is single-threaded by default, we use asynchronous functions and isolates to handle complex tasks without blocking the main UI thread, ensuring smooth and responsive performance in scenarios involving image capturing and caching.

In this app, multi-threading strategies are implemented using async functions for tasks that rely on network connectivity, such as fetching or uploading images. For tasks that could strain the main thread, like processing or caching large image files, isolates are used to manage these operations separately. This approach helps maintain the app’s responsiveness, allowing users to continue interacting with the interface smoothly while image processing and caching occur in the background.

Expected Behavior: When a user captures an image, the processing and caching occur in a background isolate, freeing the main thread for user interactions. For instance, when images are uploaded after a connection is restored, the async functions handle network requests without interrupting the UI.

Behavior with Eventual Connectivity: If the user captures images offline, these are cached locally through async operations and processed in the background. Once connectivity is re-established, a notification appears on the home screen to indicate that the images have synced with the server. This ensures that the app remains responsive even when performing complex tasks, providing a seamless user experience regardless of connectivity status.

List of implemented features (IF)

This are the implemented features for both apps:

Campus Recycling Map:

  • An interactive map that highlights the locations of recycling bins and other waste disposal points across the campus.
  • Users can find the nearest recycling bin, promoting convenience and accessibility.

App authentication

  • An interactive GUI that allows the user to log in and log out of the app using Auth0.

Verification through Camera:

  • Image recognition feature that uses the phone’s camera to verify that users are properly recycling.
  • Users must scan their recycling actions, and points are only awarded after successful verification, ensuring accountability.

Notifications:

  • Daily Reminder to Recycle: This notification can be scheduled to go off every day at a specific time.
  • End of Day Streak Reminder: This notification can be scheduled towards the end of the day to remind users to recycle and keep their streak.

Recycle view:

The Recycle View feature allows users to view recycling information, displaying the latest information when online and local data when offline, ensuring uninterrupted access.

Ethics video

Here you can watch it!

⚠️ **GitHub.com Fallback** ⚠️