A Flutter app for discovering, swiping, saving, and revisiting food recommendations. The app integrates with the shared backend for authentication, preferences, food discovery, favorites, chat recommendations, and profile management.
- Features
- Prerequisites
- Installation
- Configuration
- Running The App
- Project Structure
- API Integration
- Food Location Flow
- Testing
- Dependencies
- Troubleshooting
- Swipe-based food discovery with card gestures and like/dislike actions.
- Favorites screen that reloads liked foods from the backend.
- Food detail screen with image, rating, price, tags, description, and map location link.
- Profile screen for user details, preferences, logout, and account deletion.
- Onboarding flow for cuisine, budget, spice, dietary type, and allergens.
- Chat recommendations backed by the LLM chat API.
- Responsive Flutter UI for iOS, Android, web, and desktop-capable builds.
- AWS Cognito sign-up, confirmation, sign-in, forgot-password, token refresh, and delete-user flows.
- ID token authentication for backend APIs.
- Access token use where Cognito requires it.
- SharedPreferences-backed local session storage.
- Automatic session refresh through
AuthenticatedHttpClient.
- Food discovery fetches personalized results by Cognito user id first, then falls back to preference filters.
- Preferences sync to the backend and are also saved locally.
- Swipe preferences are queued through the backend swipe endpoint.
- Favorites are synced from the backend and cached in
FavoritesStore. - Backend image keys are expanded to public S3 image URLs.
- Flutter SDK with Dart SDK support for
sdk: ^3.10.7. - Git.
- Xcode and CocoaPods for iOS development on macOS.
- Android Studio or Android SDK for Android development.
Useful checks:
flutter --version
dart --version
flutter doctorgit clone https://github.com/NUS-MTechSE-DMSS/swipe2eat-ui.git
cd swipe2eat-ui
flutter pub getFor iOS:
cd ios
pod install
cd ..The backend base URL is read from ApiConfig.baseUrl, which uses the API_BASE_URL Dart define.
Environment files live in config/env/:
config/env/dev.json
config/env/staging.json
config/env/prod.json
Example run using an environment file:
flutter run --dart-define-from-file=config/env/dev.jsonAndroid builds also define product flavors in android/app/build.gradle.kts:
flutter run --flavor dev --dart-define-from-file=config/env/dev.jsonList devices:
flutter devicesiOS simulator:
flutter run -d <simulator_id> --dart-define-from-file=config/env/dev.jsonAndroid emulator:
flutter run -d <emulator_id> --flavor dev --dart-define-from-file=config/env/dev.jsonWeb:
flutter run -d chrome --dart-define-from-file=config/env/dev.jsonlib/
app.dart
main.dart
core/
config/api_config.dart
navigation/
services/
state/favorites_store.dart
theme/
utils/
widgets/
features/
auth/
chat/
discover/
favorites/
onboarding/
profile/
models/
test/
core/
features/
models/
test_helpers/
integration_test/
app_smoke_test.dart
favorites_location_link_test.dart
The app uses authenticated backend calls through AuthenticatedHttpClient where a session is required.
AWS Cognito endpoint:
https://cognito-idp.ap-southeast-1.amazonaws.com/
Implemented Cognito operations:
SignUpConfirmSignUpResendConfirmationCodeForgotPasswordConfirmForgotPasswordInitiateAuthfor sign-inInitiateAuthfor refresh-token authDeleteUser
Primary personalized request:
GET /food/?userId={cognitoUserId}
Fallback request when personalized results are empty:
GET /food/?budget=medium&cuisines=Thai&cuisines=Japanese&spiceLevel=3
The parser accepts list responses directly, or wrapped in data or foods.
GET /preference/food/users/{cognitoUserId}
Favorites can be returned as food objects directly or nested under a food key. The favorites parser preserves address when the backend provides it.
POST /preference/food/swipe
This records like/dislike actions for the authenticated user.
GET /preference/users/{cognitoUserId}
PUT /preference/users/{cognitoUserId}
GET /preference/dietary/options
GET /preference/dietary/users/{cognitoUserId}
Preferences are saved locally as a fallback when sync fails.
GET /user/{cognitoUserId}
GET /user/me
PUT /user/me
POST /user/create-user
POST /user/logout
Food details show two related location values:
- Static place label: the grey text under the dish title always shows
item.restaurant, mapped from backendrestaurantName. - Map link: the blue underlined row uses
item.addresswhen present. Ifaddressis missing, it falls back toitem.restaurant.
Sequence:
Backend food JSON
-> FoodService or FavoritesScreen parser
-> FoodItem(restaurant, address)
-> FoodDetailScreen
-> choose address if present, otherwise restaurant
-> render blue map link
-> tap opens Google Maps search via url_launcher
Google Maps URL format:
https://www.google.com/maps/search/?api=1&query=<encoded location>
This means a food item like Thai Fried Rice at Dunman Food Centre still gets a map link even if the backend did not send a full address.
Current local verification:
flutter analyze
flutter test
flutter test integration_test/favorites_location_link_test.dartAs of this update:
flutter testpasses 298 unit/widget tests.integration_test/favorites_location_link_test.darthas 2 passing integration tests for the food location link flow.integration_test/app_smoke_test.dartcovers basic app launch/auth navigation.
See test/TESTSUITE_README.md for the test layout and focused test commands.
Runtime dependencies:
flutterhttp: ^1.2.2shared_preferences: ^2.2.3url_launcher: ^6.3.0cupertino_icons: ^1.0.8
Development dependencies:
flutter_testintegration_testflutter_lints: ^6.0.0mockito: ^5.4.4build_runner: ^2.4.9
For exact versions, see pubspec.yaml.
Ensure Flutter is installed and on your PATH:
flutter --versioncd ios
pod install
cd ..
flutter clean
flutter pub getflutter doctor
flutter devicesFor Android, also check USB debugging and Android licenses:
flutter doctor --android-licenses- Confirm
API_BASE_URLpoints to the intended backend. - Confirm Cognito sign-in succeeds before testing authenticated screens.
- Clear simulator app data when testing a fresh auth state.
- Re-run with the expected environment file:
flutter run --dart-define-from-file=config/env/dev.jsonExpected behavior:
- If
addressis present, the blue map row shows the address. - If
addressis missing butrestaurantNameis present, the blue map row shows the restaurant/place name. - If both are missing or restaurant is
Unknown, no map link is shown.
Run the regression test:
flutter test integration_test/favorites_location_link_test.dart