Sprint 3 App Implementation and Definition - Isarquis/M-viles-Group13 GitHub Wiki
Natalia Ricaurte - Features
-
Product list:Display of all available products, Filtering by category and product type, Search functionality,Product details
-
Authentication: Email/password-based login and registration with validation, Firebase Auth integration, Session persistence and logout|
-
Home Page: Personalized product recommendations based on search history, Horizontally scrollable list showing latest product entries, Local search suggestions and filtering, Search terms stored for recommendations.
David Zamora - Features
-
Product detail: Display the information related to a product, allows placing bids, renting offers and buying a product. It also allows the user to see the bidders and rent offerers of the product.
-
Map: displays the products that are available in the map near a user location. The user can select any of the products and see the details of it and the ones of the seller. User can also navigate to the details of the product to then buy it.
-
Profile: users can check the latest sold, and bought products, the ones that are rented, and accept or reject renting offers and bids
Nicolas Riveros - Features
-
Earn: Displays product details for selling, including image, name, price, description, and owner info (name, email, phone), with a placeholder "Sell" button for future functionality.
-
Product Posting: Form for users to post products with name, description, price, category, transaction types (Rent, Buy, Bidding), image upload (gallery or camera), and geolocation integration.
Pablo Peñaranda - Features
-
Authetication: email/password based login and register. Registration creates the profile of the user. There is validation, pesistance of the session and logout.
-
Profile View: Access the profile screen to review the details of the currently logged-in user.
Pablo Méndez - Features
- Product list:Display of all available products, meant to show general details.
Isabella Sarquis - Features
-
Map: Find close to you products in a 400m radio. The map and markers persist when there is no wifi connection. Location is cached in cased is not available at all time.
-
Post product: Form for the user to post a product either if he wants to put it on sell, rent or for bidding or if the user is looking for a product not found in the discovery.
-
Discover and filter products: List of products organized by distance to the user. The products can be filtered depending on it's type, either if its for rent or buying. Products can also be filtered by "earn" in case the user want's to check if someone needs a product he has.
SCENARIO BEFORE IMPROVEMENTS
Event Description
When the user accessed the Profile page (ProfileView widget), the app attempted to fetch all user information and posted products directly from Firestore without validating internet connectivity. If the device was offline, no data was shown — neither the user's personal information nor their product listings — resulting in an empty, broken profile appearance.
There was no mechanism for loading previously seen data or maintaining product images between sessions. If the connection was lost mid-session, the profile became unusable until reconnected.
System Response (Before Improvements)
- The profile loaded data exclusively from Firestore in real-time.
- No user-friendly message was displayed when offline.
- No fallback to previously cached or saved data existed.
- All product images were loaded dynamically from online URLs without local copies.
Data Involved
- Stored Data Type: User profile info (name, email, phone, profile picture), product listings (title, price, image, status, type).
- Storage Location: Firestore Cloud Database.
- Local Cache: None, neither for textual data nor for images.
Caching and Retry Strategy: None. Data was fetched directly from Firestore each time. If offline, the operation failed silently.
Antipattern
- Full Dependency on Live Data:
The app's functionality was entirely dependent on an active internet connection without fallback strategies.
Improved System Behavior Strategy
- The app now handles offline and online states through a combined Hive persistence and image local storage strategy.
- Profile information and product listings are stored in Hive after the initial load.
- Product and profile images are downloaded and stored in the device's ApplicationDocumentsDirectory.
- If no internet connection is detected, the app loads the user's profile and product data directly from Hive without requiring Firestore access.
- Images are loaded from local storage rather than network URLs when offline.
Code Changes
- Added downloadAndSaveImage() method to download product and profile images locally.
Applied downloadImagesForProducts() to postedProducts, rentedProducts, boughtProducts.
Updated loadUserData() to first check for offline mode and load from Hive if needed.
Stored profile info and products locally using Hive for persistence.
APP RESULTS - OFFLINE
- Profile details are now available offline.
- Posted, rented, sold, and bought products are displayed even without internet.
- Images are loaded from local storage and do not depend on network connection.
- User experience remains consistent regardless of connectivity.
before
after
SCENARIO BEFORE IMPROVEMENTS
Event Description
When the user attempts to log in or register through Firebase Authentication and the internet connection is lost (the device enters airplane mode), the app initially accepted the login attempt without providing feedback. The operation silently failed, with no visual indicators (such as loading spinners) or user-facing error messages. As a result, users remained on the login page with no indication of whether their request was processed, failed, or queued.

System Response (Before Improvements)
- The app did not notify users of connectivity failure. The interface remained static, appearing unresponsive or broken.

Data Involved
-
Stored Data Type: User credentials (email/password) entered in form fields.
-
Storage Location: No local storage was used to persist this action or provide recovery.
Caching and Retry Strategy: None, The login operation was not deferred or cached. No attempt to resume was made.
Antipattern: Message with Exception Trace (MET)
This antipattern occurs when technical error messages intended for debugging (such as Firebase or HTTP exception traces) are shown directly to end users. These messages contain internal exception names, bracketed codes, or raw error formats that confuse non-technical users.
The previous implementation violated good UX practices by exposing raw exception messages from FirebaseAuth, such as [firebase_auth/network-request-failed]..., directly to the user. This represents the “Message with Exception Trace (MET)” antipattern. These messages are technical, confusing, and provide no actionable guidance.
APP

Improved System Behavior Strategy
- The system now checks for network availability via connectivity_plus, Authentication attempts are wrapped in a try-catch block to trap exceptions like network-request-failed, A loading indicator (CircularProgressIndicator) is used during the network operation to provide visual feedback.

- A modal AlertDialog is displayed to the user, explaining the connectivity issue clearly, and catch errors gracefully and show a user-friendly message instead of raw Firebase exception traces.

APP RESULTS - OFFLINE

When the user navigates to the Product List page (ProductList widget), the app fetches all products from Firestore using the _loadProducts() method. If the device is offline, the app shows a loading animation briefly (loading.gif) and after a short delay, it correctly displays all the previously loaded products, including titles, prices, and images. This correct loading is mainly thanks to the cached_network_image package, which keeps the images cached locally after being loaded once online. However, no explicit user feedback is given to indicate that the app is working offline.
This shows the simple process of loading that's been managed without connectivity
System Response (Before Improvements)
- No active connectivity check is performed before trying to load Firestore products.
- No error message, alert, or offline banner is displayed to inform the user about the network state.
- Thanks to cached_network_image, most images are displayed normally even if offline — only if they were previously cached.
- No true local storage database (like Hive or SQLite) was implemented for product persistence.
- Data loading appears slow during connection issues because the app waits on Firestore first.
Data Involved
- Stored Data Type: Product objects with fields like title, price, image, type, category, and status.
- Storage Location: Firestore Cloud Database.
- Local Cache: Images cached temporarily by the cached_network_image package
Caching and Retry Strategy: There is non.
- Image Caching: Done automatically by cached_network_image.
- Data Caching: None implemented (no Hive, no SQLite).
- Retry Strategy: None; no retries after failed fetch attempts.
Antipattern
- Non-Informative Message (NIM): There is no banner, or alert showing the user that the app is working offline.
- Stuck Progress Notification (SPN) (mild):The loading spinner stays longer when offline because Firestore loading is attempted first.
APP
Improved System Behavior Strategy
A proper connectivity_plus check is now performed before attempting to fetch products from Firestore. If the device has no internet connection, the app avoids calling Firestore immediately and relies on cached data if available.When the app detects offline status, a visible offline warning (a small red banner saying "You are offline. Showing stored products.") is now shown to inform the user clearly about the network state. This solves the problem of non-informative behavior. Product images are cached using cached_network_image, ensuring that even if the app is offline, previously viewed images are still displayed. This caching uses a disk cache and an LRU (Least Recently Used) eviction policy automatically managed by the library.
Here we can see the check connectivity and the cached network image.


APP RESULTS - OFFLINE
SCENARIO BEFORE IMPROVEMENTS
Event Description
The homepage displays a list of “Recently Added” products. These are calculated from _allProducts loaded via _loadProducts(). If there is no connection, _allProducts will be empty (or null), and the "Recently Added" section will be blank, potentially causing layout issues or bad UX. Like we see in the code But it doesn’t account for the case where _allProducts is empty because Firestore couldn’t load.
System Response (Before Improvements)
- No verification of network connectivity. No fallback logic in case of offline mode or server failure. No user feedback shown when products fail to load. The system proceeds with rendering, even if _allProducts is empty.


Data Involved
-
Stored Data Type: List of Product objects with fields like title, price, image, category, createdAt.
-
Storage Location: Initially fetched from Firestore, no local storage used before.
Caching and Retry Strategy: No caching strategy or retry logic existed. The app tried to fetch directly from Firestore and silently failed if offline. Not implemented prior to improvements. Users had to manually reopen the app or retry later.
Antipattern: Nonexistent Notification of Problem when Performing an Action (NNPPA)
Nonexistent notification of a problem when performing an action. This antipattern occurs when the app performs a connectivity-dependent action, such as fetching data from a remote backend, fails due to lack of connection, but does not inform the user that the action failed or why. As a result, the interface behaves silently, leading the user to misinterpret the state of the system.
This antipattern occurs when an app fails to perform a connectivity-dependent operation and does not notify the user of the problem, offering no context, retry suggestion, or visual feedback. In this case, the app silently fails to retrieve data from Firestore. The "Recently Added" and "Recommended" section appears empty. The user is not informed that the issue stems from lack of connectivity.
APP
Is an empty space in silent with our messages
Improved System Behavior Strategy
To solve this issue, the system now incorporates offline-first resilience with appropriate feedback mechanisms, uses connectivity_plus to check for internet access before fetching products from Firestore. On successful online fetch, products are persisted locally using Hive (offline_products box). If the device is offline, the app attempts to load cached data instead.When connected, the app fetches the product list from Firestore and persists the data locally in Hive for future offline use. The _loadCachedProducts() method loads this data if the app detects the device is offline. If no network and no cached data exist, _allProducts is set to empty, _isOffline is flagged as true, and a clear message ("Not internet connection") is displayed.
In this code is easy to see the implementation of the load cache and load where the box.put is saving the products to Hive, then reading products from Hive (offline mode)


APP RESULTS - OFFLINE
- When there is cached information:
- When there is non cached information:
Event Description
When the user accessed the Nearby Products Map, if the device lost internet connection, the app immediately failed to load the map tiles and product markers.
The system displayed an infinite loading state without clear error messaging, leaving the user unaware of the connectivity problem. If the user lost connection after initially loading the map, the app would remain stuck in a loading state without recovering or notifying the user, causing confusion and preventing further interaction.
System Response Before Improvements
- The Google Map was not shown, but the user did not know why or when it was going to be shown.
- No user-friendly message was shown when there was no connection.
- Losing connection forced the loss of all previously loaded map and product data.
- No graceful fallback or offline behavior.
Data Involved
- Stored Data Type: Product markers, user's current location, selected product details.
- Storage Location: Only in memory (RAM), not persisted or cached across sessions.
- Caching and Retry Strategy: None. Once connection was lost, all data was discarded without retry.
Antipatterns
- Loading Screen without Guidance:
No informative message for users when internet was unavailable. The app kept loading the map indefinitely with no resolution.
Improved System Behavior Strategy
Improved Implementation
The app now gracefully handles connectivity changes:
- If the device has no internet before loading, a friendly message is shown instead of an infinite loading map.
- If the device loses connection after map and markers are already loaded, the content persists on screen without disappearing.
- When a user taps a product marker without internet, an informative offline message appears instead of attempting to fetch new data.
- The app uses connectivity_plus to listen to real-time connection status.
- AutomaticKeepAliveClientMixin was implemented to preserve the loaded map and markers across navigation changes.
Code Changes
Before
This implementation did not validate internet connection before loading the map. It also did not handle offline states correctly, leading to infinite loading behavior when the network was unavailable. Additionally, markers and selected product details would fail silently without user feedback.
After
This method checks the internet status as soon as the widget is initialized. It sets the hasConnection variable based on whether the device is connected or not. This prevents the UI from attempting to fetch or render data when offline, ensuring that the app avoids unnecessary Firestore requests or widget building when the user has no internet access.
This function listens to real-time connectivity changes and updates the hasConnection flag accordingly. It enables the app to dynamically respond to changes, such as showing a reconnection message or restoring interactivity once the user regains internet access.
This block ensures that if the user opens the map screen without an internet connection and the map has not been loaded before, a clear offline message is shown instead of trying to build the map or access Firestore. This condition improves the UX by preventing confusion and maintaining the stability of the view.
State preservation strategy
This mixin ensures that the widget and its state are not disposed of when the user navigates away and returns to the screen. It keeps everything in memory, including the map controller, product list, and connectivity flags, so that the user doesn’t experience a reload or reset when returning to the page.
This asynchronous block ensures that product data is loaded right after the widget is inserted into the tree. Wrapping it in Future.microtask prevents race conditions with BuildContext, and avoids blocking the UI thread. Once the data is loaded, it sets mapLoaded = true, but only if the widget is still mounted.
This logic prevents the app from attempting to fetch and render seller details when there is no internet connection. It replaces the overlay with a simple message, which avoids potential exceptions and ensures the user understands the limitation caused by offline mode.
Screenshots

The map kept loading forever.
Now A message is shown

if the map was loaded, we use wantKeepAlive true to persist the information, and when a marker is clicked on, the overlays lets the user know that there is no connection.

The map is loaded but there is no connection, and a marker is clicked, the overlay displays a message.
The PostProduct screen in the Uni Marketplace Flutter application allows users to create and publish product listings for sale, rent, or bidding. Initially, the process lacked support for offline functionality, leaving users unable to publish products without an internet connection and providing minimal feedback. After significant improvements, the system now supports offline product publication, prevents duplicates, and provides clear user feedback, ensuring a good experience.
When a user attempted to publish a product using the PostProductScreen
without an internet connection (e.g., the device was in airplane mode), the app did not support offline functionality. The system simply displayed a "No internet" message and halted the operation. There was no mechanism to save the product for later upload, leaving users unable to proceed until they regained connectivity. Additionally, rapid button presses could lead to unintended duplicate submissions when the connection was restored, further complicating the process.
- The app did not allow product publication without an internet connection, showing only a "No internet" message.
- There was no option to save the product locally for later upload, forcing users to wait for a connection.
- The interface provided minimal feedback, with no loading indicators or detailed error messages to guide the user.
- If the user regained connectivity and pressed the "Post" button multiple times, the lack of duplicate prevention mechanisms resulted in multiple identical products being uploaded to Firestore (initially up to four duplicates, later reduced to three).

-
Stored Data Type: Product details entered in the form fields:
- Title
- Description
- Category
- Price
- Base bid (if bidding is enabled)
- Transaction types (Rent, Buy, Bidding)
- Contact email
- Image
- Location (latitude, longitude)
-
Storage Location:
- Online: Product data and image were uploaded directly to Firestore and S3, but only if an internet connection was available.
- Offline: No local storage was used, meaning the product data was not saved if there was no internet.
- Caching and Retry Strategy: There was no caching or retry mechanism. Without an internet connection, the publication attempt failed immediately, and no data was preserved for later upload.
The previous implementation exhibited the Lack of Offline Support (LOS) antipattern, where the app failed to provide functionality in the absence of an internet connection. This was evident in:
- The inability to save product data locally when offline, leaving users unable to proceed.
- The minimal feedback ("No internet") that did not offer actionable steps or alternatives.
- The absence of duplicate prevention, which caused multiple identical products to be uploaded when the connection was restored.

To address the identified issues, the following improvements were implemented:
-
Offline Product Saving:
- The app now supports offline functionality by saving product data locally in a SQLite database when there is no internet connection.
- A unique identifier (
attemptId
) is generated for each publication attempt to track and manage the product. TheDatabaseHelper
class handles local storage by saving the product in thepending_products
table, ensuring offline support:

-
Automatic Synchronization:
- An
OfflineSyncService
was introduced to monitor connectivity changes and automatically sync locally saved products to Firestore when the internet connection is restored. - The service ensures that each product is only synced once, preventing duplicates.
- An
The OfflineSyncService listens for connectivity changes and syncs pending products when the connection is restored

-
Duplicate Prevention:
- A debounce mechanism was added to the "Post" button to prevent multiple submissions from rapid clicks.
- The local database checks for existing
attemptId
s before saving a product, ensuring no duplicates are stored.
The PostProductScreen uses a debounce timer and a flag to prevent multiple submissions:

-
Visual Feedback:
- A loading indicator is displayed during the publication process to inform the user that the app is processing their request.
- The "Post" button is disabled while the operation is in progress to avoid accidental multiple submissions.
-
User-Friendly Feedback:
- When offline, the app saves the product locally and displays a message: "Producto guardado para subir después".
- Errors, such as invalid data or local storage failures, are communicated to the user in a clear, non-technical manner.
When the device is offline (e.g., in airplane mode):
- The user submits a product via
PostProductScreen
. - A loading indicator is displayed while the app processes the request.
- The system detects the lack of connectivity and saves the product to the local SQLite database (
pending_products
table). - A message is shown: "Product saved for later upload", informing the user that the product will be uploaded later.
- Duplicate submissions are prevented, ensuring only one entry is saved locally per attempt.
- When connectivity is restored, the
OfflineSyncService
automatically syncs the product to Firestore, ensuring no duplicates are created.
The message is displayed:

Uploaded after connecting to internet:

- Offline Support: The LOS antipattern is eliminated, allowing users to publish products without an internet connection.
-
Duplicate Prevention: Mechanisms like
attemptId
and button debouncing ensure only one product is published per attempt. - Improved UX: Users receive clear feedback through loading indicators and messages, keeping them informed of the process.
- Reliable Synchronization: Products are automatically synced to Firestore when the connection is restored, with safeguards against duplicates.
SCENARIO BEFORE IMPROVEMENTS
Event Description When the user is on airplane mode or turns of the device's wifi, the map will not load. Also, the closest products and users are not shown as there is no connection to the remote database.
System Response (Before Improvements)
The app keeps loading the map's space. It will never load. No location markers are showed. The user is not notified about what is happening and why is not working the functionality.
Data Involved
-
Stored Data Type: map, close products and users.
-
Storage Location: The map is cached. Products and users are stored locally using the room library. This creates a local relational database.
Caching and Retry Strategy:
- Antipattern:
- Nonexistent notification of problem when performing an action
- Lost content: The user and products information can not be fetched from the Firebase database.
- Map File Embedded Incorrectly: The map is not loaded.
Improved System Behavior Strategy
- First, using the Room library, local entities are created for product an user, in order to save the data.
This entities are used in the DAO's, which work as a layer to abstract data for the bussiness layer to work easier.
-
Finally, a local database is created in the app. It includes the DAOs previously created.
-
After this implementation, the repositories were modify to use the DAO's functions in case there is no internet connection. For example, to get a product by user:
-
Regarding the Map caching, by using google maps, once the map is created, it is automatically cached, assuring it can be shown when the is no internet connection.
Eventual connectivity diagram
SCENARIO BEFORE IMPROVEMENTS
Event Description When the user is on airplane mode or turns of the device's location, the map will not show the users location and the user is not notified about the irregular behavior.
System Response (Before Improvements) The app shows a whole world map with no specific focus. The centering button does not work. The app does not notify the user about the unexpected behaviour.
Data Involved
-
Stored Data Type: last location known.
-
Storage Location: No local storage was used.
Caching and Retry Strategy:
- Antipattern:
- Nonexistent notification of problem when performing an action
- Lost content (Lost functionality): The user can press the center map button, but the functionality will not work.
Improved System Behavior Strategy
- The location is saved in the caché. In case the app needs the user location and the location is not enabled, the app will use the cached one in the last connection. If the user has never allowed the location access, the app will show a default map and will notify the user that there is not a known location.
Eventual connectivity diagram
When user attempted to login or register and didn't have connection the app used to throw the Firebase exception message error. That lacked of visual feedback o anything that completely explained the user what happened.
-
A generic Toast shows the Firebase exception error text (technical message).
-
The user stays on the login screen with no clear indication that the login failed.
-
No retry mechanism or caching of the session attempt.
- Connectivity Detection: Before making auth.signInWithEmailAndPassword, check internet availability using a utility.
Created a function that checks for internet connectivity:
And then added it to Login & Register:
- Error Handling: Catch the exception and show user-friendly message.
- Session Persistance: Only save login session after succesful login.
Eventual connectivity diagram
Creating a product needs internet connection, as our database is in Firebase. When a user tries to upload a product with no network, the app stays in the create product screen, the button seems to work, but nothing changes and the user is not notified about what is happening.
ments
The user tries to upload a product with no internet connection, When pressing the create product button to post the information nothing changes, the loaded information stays in its text boxes and the screen stays in the post product feature. The user is not notified about what is happening.
All the attributes for creating a productm including the user id, the products name, price, image, category and type.
-
Storage Location:
- Online: Product data was stored in a remote database in Firebase.
- Offline: No local storage was used.
- Caching and Retry Strategy: There was no caching or retry mechanism.
Antipattern: Lack of Offline Support (LOS): the app failed to work in the absence of an internet connection.
- Store the product locally in the Local DB implemented and mentioned previously.
- Create a queue in order to post the product once the internet connection is restablised.
- Notify the user about the issue in order no help him solve the problem as soon as possible
- Exit the post product once pressed the post product button in order to not affect the rest of the app functionality and fluidity.
Business Question | Type | Rationale |
---|---|---|
What is the most popular price range for different academic materials? | 4 | Understanding popular price ranges allows distributors or sellers to price items competitively and design better promotions. |
Business questions to implement
Business Question | Type | Rationale |
---|---|---|
Which marketplace features (filters, entrepreneurship, messaging) are used the most and the least? | 3 | Posting a product is one of the core features. Measuring its usage frequency helps determine whether it needs UX improvements or better visibility. |
Given the data recompiled from the marketplace, which materials/type of materials are being sold the most? | 4 | Posting a product includes selecting a category and type. Analyzing this data reveals trends in what users post, helping inform marketing strategies and partnerships. |
Business Question | Type | Rationale |
---|---|---|
How does the app handle multiple users searching for the same material simultaneously? | 1 | Evaluates system scalability when users use search and filter features in the ProductList screen. |
How easy was it for you to find the product you were looking for? Did it take more than 5 seconds? | 2 | Measures efficiency of search/filtering mechanisms inside the ProductList screen to identify UX improvements. |
Business Question | Type | Rationale |
---|---|---|
How does the system handle 100+ concurrent login attempts while maintaining sub-second response times? | 1 | Tests whether coroutine threading and Firebase Auth can sustain performance during traffic spikes without degrading local SharedPreferences caching efficiency. |
What percentage of users abandon the registration flow when encountering >2 form validation errors? | 2 | FMeasures UX friction caused by validation design, identifying if error messaging or validation sequencing drives user dropouts. |
Business questions to implement
Business Question | Type | Rationale |
---|---|---|
Where do users spend the most time within the app, and how can we optimize these sections for better engagement? | 5 | With the analytics pipeline and the implementation of the session class, the time spent in each feature can be timed. |
Which listing attributes (images, descriptions, seller rating) impact purchase decisions the most? | 5 | When listing a product, clicks can be measured in each feature of the product, making possible to understand what attibute is more valuable for the buyer. |
Functionalities
The app must persist the logged-in user's profile along with their posted, sold, rented products, bids, and rent offers across sessions. This ensures that the user's basic information and activity history are available immediately, even without an active internet connection. If no connection is detected, the app loads the profile and products directly from local storage (Hive).
Implementation
- Database used: Hive (key-value storage for Flutter backed by native mechanisms).
- Storage type: Key/Value pairs where each value is a JSON-encoded map representing lists of products.
- Data format: JSON-encoded lists for posted, bought, and rented products. Each product includes fields like id, title, image, price, etc.
**Functionalities **
Functionalities include consulting and displaying products on the Homepage. To guarantee data availability without relying on constant network access, Hive was integrated to locally persist products retrieved from Firestore.
Implementation
- Database used: Hive (Key/Value NoSQL database for Flutter)
- Box created: offline_products
- Saving moment: Every time the application detects an active internet connection, products fetched from Firestore are saved locally.
- Reading moment: When offline, the app automatically loads products from the local Hive storage.
- Data stored: Each product is converted into a map (Map<String, dynamic>) format, maintaining key fields such as id, title, price, category, image, createdAt, among others.
In this code is easy to see the implementation of the load cache and load where the box.put is saving the products to Hive, then reading products from Hive (offline mode)


And here is the result of the strategy where the image that are shown are save in the box created:
So like this users can browse products even without internet access.Reduces network requests to Firestore, saving data usage and speeding up the UI. Displays an explicit message like "You are offline. Showing store data" to inform users.
Functionalities
In the LoginPage functionality, a "Remember Email" option was implemented. This feature ensures that the user's last entered email address is stored locally and can be pre-filled automatically the next time they open the login screen. This enhances user experience by reducing the need to manually retype credentials, especially in recurrent logins.
Implementation
- Database used: SharedPreferences (Key/Value storage for Flutter backed by native mechanisms).
- Storage type: Key/Value storage (String-based values).
- Data format: Simple String (saved_email: "[email protected]").
- Saving moment: After a successful login, if the "Remember Me" option is enabled, the email is saved locally using SharedPreferences.
In the code, the strategy can be easily seen, calling SharedPreferences.getInstance() and accessing .setString(), .getString(), or .remove() to handle the email persistence.

Functionalities
In the SearchBar functionality, a Search History mechanism was implemented. Every time a user types and submits a search term, that term is saved locally into a SQLite database. This allows the app to persist search queries and offer recent search suggestions or analyze search trends, even without internet connection.
Implementation
- Database used: SQLite (Relational database managed locally on the device).
- Storage type: Structured relational tables.
- Data format SQL table with the following structure:
CREATE TABLE search_terms( id INTEGER PRIMARY KEY AUTOINCREMENT, term TEXT NOT NULL, timestamp DATETIME DEFAULT CURRENT_TIMESTAMP );
Calling insertSearchTerm(term) in the SearchDatabaseService class. Calling getRecentSearchTerms(limit: 10) to retrieve the last 10 searches made.Managed automatically with sqflite, initializing the database and handling SQL execution (CREATE TABLE, INSERT, SELECT, DELETE).

Every time a user performs a search, the app saves the search term into the local database by inserting a new row. To display recent searches or recommendations, the app queries the database and sorts the terms by timestamp descending. Users or the system can clear the search history by deleting the stored records, helping manage local storage size.
Functionalities In the search functionality of the application, in addition to using a local relational database (SQLite) to manage the search terms, a local file backup strategy was implemented. This guarantees that even if the database becomes corrupted or if quick, lightweight access to the search history is needed, the user's recent search terms are available through a local file stored in the device.
Implementation
- Storage mechanism used: FileSystem (Dart's dart:io API).
- File name: search_backup.txt
- Storage type: Plain text file, each search term is appended line-by-line.
- Saving moment: Every time the user performs a search, the term is appended to the file.
This local file storage strategy offers a lightweight and resilient backup for user search history. By saving each search term in a plain text file, the app ensures fast access even if the main database fails. It improves offline support, reduces memory overhead, and provides a simple, reliable fallback that enhances the user experience and data durability.


Functionalities Functionalities include creating and managing product posts locally for the postProduct feature. To ensure offline functionality, Hive was integrated to persist pending products locally, allowing users to review and edit them before syncing with the server.
Implementation Database used: Hive (Key/Value NoSQL database for Flutter) Box created: pending_products Saving moment: When the user attempts to post a product while offline. Reading moment: When offline, the app loads pending products from the local Hive storage for review or editing. Data stored: Each product is stored as a map (Map<String, dynamic>) format, including key fields such as title, description, price, baseBid, transaction types, email, images, and latitude/longitude coordinates. Expiration policy: Products not synced within 7 days are automatically deleted from the box.
###SearchBar (Search History) - Relational Local Database - Feature: Earn - Nicolas Riveros
Functionalities In the Earn feature, a Search History mechanism is implemented using SQLite. Each time a user types and submits a search term, that term is saved locally in an SQLite database. This allows the app to persist search queries and offer recent search suggestions or analyze search trends, even without internet connection.
Implementation • Database used: SQLite (Relational database managed locally on the device). • Storage type: Structured relational tables. • Data format:SQL table • Saving moment: Every time the user performs a search, the term is inserted into the SQLite database. • Retrieving recent search terms: Use getRecentSearchTerms(limit: 10) to retrieve the last 10 searches made by the user.
This solution ensures that the user’s search history is available even when there is no connectivity, providing a smooth user experience and easy access to recent search terms.
Functionalities
In the EarnScreen functionality, the user is able to filter products by categories. To optimize user experience and enhance performance, a local storage mechanism has been implemented using Hive. This allows the app to persist the user’s last selected category for faster access, even in the case of low connectivity or app restart. By saving the selected category locally, the user’s preference is maintained between app sessions, which improves usability and responsiveness.
Implementation
• Database used: Hive (NoSQL lightweight database for local storage)
• Storage type: Key-Value pairs
• Data format:
• Key: selectedCategory
• Value: A string representing the category selected by the user (e.g., “All”, “Math”, “Science”, etc.)
Every time the user selects a category, this value is saved locally. Upon app restart or screen refresh, the selected category is retrieved from Hive and set as the default filter for the products. This reduces the need for fetching the category preference from remote servers, enhancing offline support and improving the responsiveness of the category filter.
- Shared Preferences
The implementation uses Android's SharedPreferences API as a lightweight local storage solution to persist user session data. This is particularly evident in two key components:


Functionalities
In order to understand user behavior, the application will track the time users spend in each major feature (e.g., Home, Map, Product Detail, map.). This information will be used for analytics purposes and to improve user experience based on engagement patterns. Also, it will be used to decide the importance of mantaining certain features.
Implementation
- Database used: Realm (key-value storage mechanisms).
- Storage type: Key/Value pairs, where each key represents a feature name and each value is a JSON-encoded map.
- Data format: JSON-encoded list of session records per feature.
Functionalities In order to support offline capabilities and improve app responsiveness, user and product data will be stored locally in a relational database using Room. This allows the app to continue functioning when there is no internet connection, providing seamless access to previously loaded products and user information.
This was used in multiple features in the application, including the map to fetch close products, listing products, main page and discover.
Implementation
- Database used: Room (SQLite)
- Storage type: Relational tables with entity relationships where needed.
- Data format: Structured objects mapped to tables via Room’s @Entity annotations.
Functionalities
The app must optimize the filtering of products in the product list screen by offloading the filtering process to a background isolate. This ensures that even as the number of available products grows significantly, the UI remains responsive when users apply filters or search criteria.
Implementation
-
Concurrency method used:
compute()
(Flutter's built-in helper for running functions in a background isolate). - Task type: Filtering the full list of products based on selected category and type criteria.
-
Data flow:
- Load the complete product list asynchronously from Firestore.
- When the user applies a filter, pass the full list and the selected criteria to a background isolate using compute().
- The isolate processes the filtering logic and returns the filtered list.
- The main isolate then updates the product list UI without blocking or freezing during heavy data operations.
Concurrency Strategy – compute() Function – Feature: Nearby Products Loading Optimization David Zamora
Functionalities
The app must optimize the loading of nearby products on the map by offloading the processing of product data to a background isolate. This ensures that even as the number of nearby products grows, the UI remains smooth and responsive, without lag during map rendering or marker placement.
Implementation
-
Concurrency method used:
compute()
(Flutter's built-in helper for running functions in a background isolate). - Task type: Transforming raw Firestore product data into lightweight marker objects for display on the map.
-
Data flow:
- Load raw product data asynchronously from Firestore.
- Pass the data to a separate isolate using
compute()
. - The isolate processes the data into
Marker
objects. - The main isolate receives the processed markers and updates the Google Map widget without blocking the UI.
Scope
In this feature, Dart’s Future was used to handle asynchronous tasks such as querying Firestore for products, saving search terms to SQLite, and writing backup files.This approach prevents the UI from freezing and ensures a smooth interaction by offloading time-consuming operations from the main thread.
Main Use Cases:
- Fetching product data from Firestore (FirestoreService.getAllProducts())
- Saving search terms locally into SQLite (SearchDatabaseService.insertSearchTerm())
- Writing search backups into local files (SearchFileService.appendSearchTerm())
Future was selected for its simplicity, native support in Dart, seamless integration with Flutter’s asynchronous lifecycle, and its efficiency for I/O-bound operations.This strategy significantly improves the responsiveness and performance of the app.
Decisions of Implementation
- Future was chosen because it is the fundamental async primitive in Dart.
- It is ideal for I/O-bound operations like network calls, database queries, and file operations.
- Using Future keeps the UI thread free, enhancing user experience without manual thread management.
- Integrates cleanly with Flutter’s setState and lifecycle methods like initState().
- Chaining .then() or using async/await syntax improves readability and error handling
**Coding Examples **
- FirestoreService: Fetching Products, a network call to Firestore is performed without blocking the main thread ,and the result is returned as a Future<List>

- **Saving Search Terms into SQLite: **Accesses the SQLite database asynchronously and the app remains responsive while the search term is saved.

- Writing a Backup File: so writes search terms to a backup text file asynchronously and avoids UI lags during file I/O operations.

The Uni Marketplace app will implement Dart's Isolate to improve multithreading for the productPost and earn features, enabling true parallelism for intensive tasks. In productPost, isolates will handle image compression for product uploads, ensuring the UI remains responsive during processing, while the existing async/await framework manages lighter tasks like form validation. For the earn feature, isolates will process large batches of user activity data for points calculation, preventing delays in UI updates, thus enhancing performance and user experience across both features.
The implementation demonstrates a modern approach to concurrency using Kotlin Coroutines:
Functionalities
The app must reduce redundant Firestore reads when users interact with nearby product markers on the map. By implementing an LRU (Least Recently Used) cache for user profiles, the system avoids repeatedly fetching the same user data, improving performance and responsiveness.
Implementation
- Caching method used: LRU Cache implemented using a
LinkedHashMap
with a fixed maximum size. - Cache type: In-memory, key-value structure where keys are user IDs and values are user objects.
- Data flow:
- When a marker is tapped, the app calls
getUserWithCache(userId)
instead of directly querying Firestore. - If the user is already in the cache, it is returned instantly and marked as recently used.
- If not, the user is fetched from Firestore, added to the cache, and the least recently used entry is evicted if the cache exceeds its size limit.
- When a marker is tapped, the app calls
- Cache size: Limited to a maximum of 20 user entries to balance memory usage and performance.
This implementation improves efficiency during repeated map interactions.
To improve the user experience and app resilience in offline scenarios, the app implements image caching using the cached_network_image Flutter package. This strategy ensures that product images are loaded quickly and persistently, even when the user is offline. This library automatically downloads images from the network and stores them in a local disk cache and memory cache.
Structure:
The images are first cached in memory for fast immediate reuse. When the memory cache exceeds its limit, the least recently used images are removed (LRU eviction). Disk caching persists images between sessions, meaning users can reopen the app and see previously loaded images without needing an internet connection.
Parameters:
Memory Cache: Stores most recent images for fast UI updates. Disk Cache: Stores files on device storage for offline usage. Eviction Policy: Old images are removed when cache size limits are reached.
Decisions of Implementation
This is implemented for the offline readiness once an image has been downloaded it is available offline via the disk cache, for the user experience to cached images render immediatly avoiding visual delays on repeated views, reducing network requests, also ached images load faster from local memory rather than refetching them online.
Coding using cached_network_image in ProductList:

To enhance performance and relevance in delivering personalized recommendations, the app uses a custom in-memory LRU (Least Recently Used) cache to store a limited number of recently matched recommended products based on user searches. This avoids redundant filtering operations and ensures relevant data is quickly accessible.
Structure:
The LRU cache is implemented using a LinkedHashMap, which maintains insertion order and allows constant-time access and removal. The cache stores key-value pairs where the product ID is the key, and the Product object is the value. The cache automatically removes the least recently accessed product when the defined capacity is reached.
Parameters:
- Capacity: The cache holds up to 5 products.
- Eviction Policy: When full, the oldest (least recently accessed) entry is removed to insert a new one (LRU).
- Access Update: Every get or put operation updates the order, making it the most recently used.
Decisions of Implementation
This caching strategy was chosen for recommended products, which are filtered based on recent user searches. The cache avoids recalculating recommendations every time and ensures fast display in the UI. It improves performance by limiting re-filtering logic.
Coding using cached_network_image in ProductList:


Caching Strategy – Layerd caching strategy – Feature: image Optimization on productPost - Nicolas Riveros
The Uni Marketplace app will introduce a layered caching strategy to optimize the productPost and earn features. For productPost, cached_network_image will cache product images for faster loading during offline posting. For the earn feature, an in-memory cache will store frequently accessed data, such as user points and reward statuses, and flutter_secure_storage will safeguard sensitive earn-related data, ensuring quick access and a seamless experience in low-connectivity scenarios.
Structure: To optimize the user experience and ensure access to location data even without internet connectivity, a location caching strategy is implemented. This allows the app to store the user's last known location locally, enabling it to display accurate location data even when there is no access to real-time GPS services or network connectivity.
Parameters:
Memory Cache: The last known location is stored in memory temporarily, providing quick access when the app needs to display the user's location without the need for constant re-fetching from the GPS sensor. This reduces latency and provides a smooth user experience when switching between screens that require location data.
**Disk Cache: ** In case of a longer absence of internet or GPS signal, the app stores the last known location in a local persistent storage (such as SharedPreferences or Room Database). This ensures that even after the app is restarted or when the device is offline, the user's last known location can still be accessed and displayed.
Decisions of Implementation This caching strategy makes sure that location data is always available when needed, providing a good experience for users who might be in areas with poor network coverage or GPS signal. By storing the last known location both in memory and disk cache, the app avoids delays or errors when retrieving the user's location in offline situations. This approach improves the app's reliability and responsiveness.
https://github.com/Isarquis/M-viles-Group13/milestones