Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
91 commits
Select commit Hold shift + click to select a range
b36f303
fix: removed widget_test
AlexOliveira123 Sep 14, 2024
e47ad0a
chore: fvm
AlexOliveira123 Sep 14, 2024
05b1ab0
chore: add flutter_bloc as dependency
AlexOliveira123 Sep 14, 2024
68ff962
feat: add appbar widget and restaurant tour page initial layout
AlexOliveira123 Sep 14, 2024
8122274
feat: add circular loading
AlexOliveira123 Sep 14, 2024
930013d
feat: add widgets file to export circular loading
AlexOliveira123 Sep 14, 2024
dd9df92
feat: add restaurant item widget
AlexOliveira123 Sep 14, 2024
d11cf57
feat: add star icon widget
AlexOliveira123 Sep 14, 2024
7af2a77
feat: add status widget
AlexOliveira123 Sep 14, 2024
1f50bdf
feat: add starts widget
AlexOliveira123 Sep 14, 2024
881aa07
feat: move restaurant item to restaurant tour context
AlexOliveira123 Sep 14, 2024
36f426b
feat: add restaurant detail initial layout
AlexOliveira123 Sep 14, 2024
934a527
feat: add category entity
AlexOliveira123 Sep 14, 2024
03be17d
feat: add user entity
AlexOliveira123 Sep 14, 2024
9c65f1d
feat: add review entity
AlexOliveira123 Sep 14, 2024
d9e16ba
feat: add restaurant entity
AlexOliveira123 Sep 14, 2024
7b4db41
feat: add get restaurants usecase
AlexOliveira123 Sep 14, 2024
77a3fc0
feat: add domain error enum on domain helpers
AlexOliveira123 Sep 14, 2024
408cb0a
feat: add category model
AlexOliveira123 Sep 14, 2024
081d944
feat: add user model
AlexOliveira123 Sep 14, 2024
3c67f30
feat: add review model
AlexOliveira123 Sep 14, 2024
852e66e
feat: add restaurant model
AlexOliveira123 Sep 14, 2024
0970dcd
feat: add http adapter
AlexOliveira123 Sep 15, 2024
7ba5143
feat: add http adapter
AlexOliveira123 Sep 15, 2024
b022cd0
feat: add http client factory
AlexOliveira123 Sep 15, 2024
c45a824
feat: add api url factory
AlexOliveira123 Sep 15, 2024
2ba37bf
feat: add graphql get restaurants use case
AlexOliveira123 Sep 15, 2024
0434fe5
feat: add get restaurants factory
AlexOliveira123 Sep 15, 2024
05f7582
feat: graphql get restaurants use case adjustments
AlexOliveira123 Sep 16, 2024
db95a33
refact: add headers via depencency injection
AlexOliveira123 Sep 16, 2024
2972282
feat: add cubit restaurant tour presenter initial impl
AlexOliveira123 Sep 16, 2024
07aad5b
feat: add presentation factory file
AlexOliveira123 Sep 16, 2024
4b64e25
feat: add presentation states
AlexOliveira123 Sep 16, 2024
eadcfe3
feat: add restaurant tour presenter factory
AlexOliveira123 Sep 16, 2024
3e1c0d7
feat: presenter initial impl ou restaurant tour page
AlexOliveira123 Sep 16, 2024
4de2deb
feat: add restaurant tour page factory
AlexOliveira123 Sep 16, 2024
e4fafee
feat: add restaurant list widget on tour page
AlexOliveira123 Sep 16, 2024
2670dac
feat: add cache protocols
AlexOliveira123 Sep 16, 2024
332b1ab
chore: add shared preferences as dependency
AlexOliveira123 Sep 16, 2024
66d9b21
feat: add local storage adapter
AlexOliveira123 Sep 16, 2024
b10f264
refact: move http folder factory to cache folder factory
AlexOliveira123 Sep 16, 2024
9346186
refact: factories file adjustments
AlexOliveira123 Sep 16, 2024
5464aa2
feat: fill detail page with restaurant entity data
AlexOliveira123 Sep 16, 2024
65be3a7
refact: remove app widget from main file
AlexOliveira123 Sep 16, 2024
66b8b3a
refact: remove query file
AlexOliveira123 Sep 16, 2024
cc422b0
refact: change from graphql_get_restaurants to remote_get_restaurants
AlexOliveira123 Sep 16, 2024
110e1e5
feat: add save, get, update protocols
AlexOliveira123 Sep 16, 2024
6f9df0d
feat: add cache data usecases
AlexOliveira123 Sep 16, 2024
7bd10a8
refact: add error content ui to your own widget
AlexOliveira123 Sep 16, 2024
ec4104d
feat: add get favorite restaurants on restaurant tour presenter
AlexOliveira123 Sep 16, 2024
0b0daf6
feat: add save restaurants use case on restaurant tour presenter
AlexOliveira123 Sep 16, 2024
6427862
feat: match favorite restaurants on presenter
AlexOliveira123 Sep 16, 2024
acefe04
feat: handling errors on restaurant tour ui
AlexOliveira123 Sep 16, 2024
5330656
feat: add general ui adjusments
AlexOliveira123 Sep 16, 2024
1322b46
feat: add null check fromJson models
AlexOliveira123 Sep 17, 2024
1cd12f0
refact: remove unnecessary protocol
AlexOliveira123 Sep 17, 2024
77eb364
feat: add name prop on restaurant model toJson
AlexOliveira123 Sep 17, 2024
8f2a4e1
fix: models
AlexOliveira123 Sep 17, 2024
c59c1ab
feat: add no image widget
AlexOliveira123 Sep 17, 2024
5390eb4
refact: remove unnecessary fields on restaurant entity
AlexOliveira123 Sep 17, 2024
7f0699e
refactor: ui general adjustments
AlexOliveira123 Sep 17, 2024
808736a
refact: data layer improvements
AlexOliveira123 Sep 17, 2024
0d76b30
feat: cubit adjustments
AlexOliveira123 Sep 17, 2024
fb452d9
chore: change authorization token
AlexOliveira123 Sep 17, 2024
7c39b44
refactor: removed unnused restaurant model
AlexOliveira123 Sep 17, 2024
dfbd71b
refactor: move typography to core folder
AlexOliveira123 Sep 17, 2024
7727179
refactor: move image code from detail page to your own file
AlexOliveira123 Sep 17, 2024
2a9139c
chore: add .env config to hide confidencial data
AlexOliveira123 Sep 17, 2024
dedac72
refactor: app adjustments
AlexOliveira123 Sep 17, 2024
86d3adb
feat: add force material transparency on detail page
AlexOliveira123 Sep 17, 2024
46f13be
chore: add mocktail as dependency
AlexOliveira123 Sep 17, 2024
33e0efe
test: add factories on tests
AlexOliveira123 Sep 17, 2024
92e321c
test: add local get favorite restaurants tests
AlexOliveira123 Sep 17, 2024
78b2444
test: add local save favorite restaurant tests
AlexOliveira123 Sep 17, 2024
33a4320
test: add remote get restaurant tests
AlexOliveira123 Sep 17, 2024
7bb08c6
test: add http adapter tests
AlexOliveira123 Sep 17, 2024
00f1087
feat: get restaurants adjustments
AlexOliveira123 Sep 17, 2024
9cccbbf
test: add factories json
AlexOliveira123 Sep 17, 2024
f78618f
test: add category modal tests
AlexOliveira123 Sep 17, 2024
18c5494
test: add user model tests
AlexOliveira123 Sep 17, 2024
d5e3f55
test: add review model tests
AlexOliveira123 Sep 17, 2024
a22f2f2
test: add local restaurant model tests
AlexOliveira123 Sep 17, 2024
abf6600
test: add remote restaurant model tests
AlexOliveira123 Sep 17, 2024
52ee670
test: add local storage adapter tests
AlexOliveira123 Sep 17, 2024
21390ad
test: add restaurant tour presenter tests
AlexOliveira123 Sep 18, 2024
6e4d6e6
chore: add bloc_test as dev dependency
AlexOliveira123 Sep 18, 2024
0b2989d
test: add restaurant tour page tests
AlexOliveira123 Sep 18, 2024
192db15
feat: update README
AlexOliveira123 Sep 18, 2024
b9a3683
refactor: duplicated code to a helper method on restaurant tour prese…
AlexOliveira123 Sep 18, 2024
f2cba73
refactor: improve add favorite restaurant error message
AlexOliveira123 Sep 18, 2024
5bc6273
test: improve presentation function names
AlexOliveira123 Sep 18, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .fvm/fvm_config.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
{
"flutterSdkVersion": "3.22.3",
"flavors": {}
"flutterSdkVersion": "3.22.3"
}
4 changes: 4 additions & 0 deletions .fvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"flutter": "3.22.3",
"flavors": {}
}
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,8 @@ app.*.map.json
/android/app/release

# fvm
.fvm/flutter_sdk

# FVM Version Cache
.fvm/

.env
14 changes: 7 additions & 7 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"dart.flutterSdkPath": ".fvm/flutter_sdk",
"search.exclude": {
"**/.fvm": true
},
"files.watcherExclude": {
"**/.fvm": true
}
"dart.flutterSdkPath": ".fvm/versions/3.22.3",
"search.exclude": {
"**/.fvm": true
},
"files.watcherExclude": {
"**/.fvm": true
}
}
209 changes: 48 additions & 161 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,49 @@
# Restaurant Tour

Welcome to Superformula's Coding challenge, we are excited to see what you can build!
## Overview

This take home test aims to evaluate your skills in building a Flutter application. We are looking for a well-structured and well-tested application that demonstrates your knowledge of Flutter and the Dart language.
This project is a solution to the **Superformula's Coding Challenge**, designed to demonstrate skills in Flutter development and architecture. The focus of the project is on creating a scalable, well-structured, and well-tested Flutter application that allows users to explore restaurants using the Yelp GraphQL API.

We are not looking for pixel perfect designs, but we are looking for a well-structured application that demonstrates your skills and best practices developing a flutter application. We know there are many ways to solve a problem, and we are interested in seeing how you approach this one. If you have any questions, please don't hesitate to ask.
## Key Features

Things we'll be looking on your submission:
- App structure for scalability
- Error and optional (?) handling
- Widget tree optimization
- State management
- Test coverage
- **Restaurant Tour Page**: Displays a list of restaurants, allowing users to view details and add favorites. The app also shows restaurants by categories such as price, name, and rating.
- **Restaurant Detail Page**: Provides detailed information about the selected restaurant, including user reviews, restaurant category, and other essential details.
- **Favorites Feature**: Users can favorite businesses, with favorites being stored locally using **SharedPreferences**.

Think of the app you'll be building as the final product, do not over engineer it for possible future features, but do not under engineer it either. We are looking for a balance. We want that the functionalities that you implement are well thought out and implemented.
## Architecture and State Management

As an example, for the favorites feature you can simply use SharedPreferences, you don't need to use a complex database solution, but we're looking for a solid shared preferences implementation.
This application follows the principles of **Clean Architecture** to ensure scalability, separation of concerns, and maintainability. The following layers were implemented:

1. **Domain Layer**: Contains the business logic, including the use of usecases and entities.
2. **Data Layer**: Responsible for data fetching and caching, using the Yelp GraphQL API and storing API keys using the `flutter_dotenv` package for secure management.
3. **Presentation Layer**: Flutter widgets and state management using **flutter_bloc** for managing UI states, and reactions.

I utilized several design patterns to create a solid structure, such as:
- **Factory Pattern**: For creating complex objects and handling dependencies dynamically.
- **Adapter Pattern**: To allow integration of different API responses with internal models.
- **Strategy Pattern**: For handling various business logic strategies.

In addition, I applied **SOLID** principles where appropriate, ensuring that classes and components are modular, extensible, and maintainable.

Be sure to read **all** of this document carefully, and follow the guidelines within.
### State Management

The state management in this project is handled using the **flutter_bloc** library.

### API Key Management

The **flutter_dotenv** package is used to securely store and manage the API Key needed for communicating with the Yelp GraphQL API. The API key is stored in an environment file, which is then loaded into the application at runtime.

## Testing

A comprehensive test strategy was implemented to cover different parts of the application. The project includes:
- **Unit Tests**: For testing business logic and data manipulation within usecases and adapters.
- **Widget Tests**: For testing the UI components.

## Steps to run the application

## Vendorized Flutter
## 1. Install fvm

3. We use [fvm](https://fvm.app/) for managing the flutter version within the project. Using terminal, while being on the test repository, install the tools dependencies by running the following commands:
1. [fvm](https://fvm.app/) for managing the flutter version within the project. Using terminal, while being on the test repository, install the tools dependencies by running the following commands:

```sh
dart pub global activate fvm
Expand All @@ -35,168 +55,35 @@ Be sure to read **all** of this document carefully, and follow the guidelines wi
export PATH="$PATH":"$HOME/.pub-cache/bin" # Add this to your environment variables
```

4. Install the project's flutter version using `fvm`.
2. Install the project's flutter version using `fvm`.

```sh
fvm use
```

5. From now on, you will run all the flutter commands with the `fvm` prefix. Get all the projects dependencies.
3. From now on, you will run all the flutter commands with the `fvm` prefix. Get all the projects dependencies.

```sh
fvm flutter pub get
```

More information on the approach can be found here:

> hhttps://fvm.app/docs/getting_started/installation

From the root directory:


### IDE Setup

<details>
<summary>Use with VSCode</summary>
<p>

If you're a VScode user link the new Flutter SDK path in your settings
`$projectRoot/.vscode/settings.json` (create if it doesn't exist yet)

```json
{
"dart.flutterSdkPath": ".fvm/flutter_sdk"
}
```


</p>
</details>

<details>
<summary>Use with IntelliJ / Android Studio</summary>
<p>

Go to `Preferences > Languages & Frameworks > Flutter` and set the Flutter SDK path to `$projectRoot/.fvm/flutter_sdk`

<img width="800" alt="IntelliJ Settings" src="https://user-images.githubusercontent.com/1096485/64658026-3a1fdd00-d436-11e9-9457-556059f68e2c.png">

</p>
</details>

## Requirements

### App Structure

#### Restaurant List Page

- Tab Bar
- List of favorites (stored client side)
- List of businesses
- Hero image
- Name
- Price
- Category
- Rating (rounded to the nearest value)
- Open/Closed

#### Restaurant Detail View

- Ability to favorite a business
- Name
- Hero image
- Price and category
- Address
- Rating
- Total reviews
- List of reviews
- User name
- Rating
- User image
- Review Text (These are just snippets of the full review, usually like 3-4 lines long)

#### Misc.

- Clear documentation on the structure and architecture of your application.
- Clear and logical commit messages.
- We suggest following [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/)

## Test Coverage

To demonstrate your experience writing different types of tests in Flutter please do the following:

- We are looking to see how you write tests in Flutter. We are not looking for 100% coverage but we are looking for a good mix of unit and widget tests.
- We are specially looking for you to cover at least one file for each domain layer (interface, application, repositories, etc).

Feel free to add more tests as you see fit but the above is the minimum requirement.

## Design

- See this [Figma File](https://www.figma.com/file/KsEhQUp66m9yeVkvQ0hSZm/Flutter-Test?node-id=0%3A1) for design information related to the overall look and feel of the application. We do not expect pixel-perfection but would like the application to visually be close to what is specified in the Figma file.

![List View](screenshots/listview.png)
![Detail View](screenshots/detailview.png)

## API

The [Yelp GraphQL API](https://www.yelp.com/developers/graphql/guides/intro) is used as the API for this Application. We have provided the boilerplate of the API requests and backing data models to save you some time. To successfully make a request to the Yelp GraphQL API, please follow these steps:

1. Please go to https://www.yelp.com/signup and sign up for a developer account.
1. Once signed up, navigate to https://www.yelp.com/developers/v3/manage_app.
1. Create a new app by filling out the required information.
1. Once your app is created, scroll down and join the `Developer Beta`. This allows you to use the GraphQL API.
1. Copy your API Key from your app page and paste it on `line 5` [yelp_repository.dart](app/lib/yelp_repository.dart) replacing the `<PUT YOUR API KEY HERE>` with your key.
1. Run the app and tap the `Fetch Restaurants` button. If you see a log like `Fetched x restaurants` you are all set!

## Technical Requirements

### State Management

Please restrict your usage of state management or dependency injection to the following options:

1. [provider](https://pub.dev/packages/provider)
2. [Riverpod](https://pub.dev/packages/riverpod)
3. [bloc](https://pub.dev/packages/bloc)
4. [get_it](https://pub.dev/packages/get_it)/[get_it_mixins](https://pub.dev/packages/get_it_mixin)
5. [Mobx](https://pub.dev/packages/mobx)

We ask this because this challenge values consistency and efficiency over ingenuity. Using commonly used libraries ensures that we can review your code in a timely manner and allows us to provide better feedback.

## Coding Values

At **Superformula** we strive to build applications that have

- Consistent architecture
- Extensible, clean code
- Solid testing
- Good security & performance best practices

### Clear, consistent architecture

Approach your submission as if it were a real world app. This includes Use any libraries that you would normally choose.

_Please note: we're interested in your code & the way you solve the problem, not how well you can use a particular library or feature._

### Easy to understand

Writing boring code that is easy to follow is essential at **Superformula**.

We're interested in your method and how you approach the problem just as much as we're interested in the end result.

### Solid testing approach
### 2. Create the environment file

While the purpose of this challenge is not to gauge whether you can achieve 100% test coverage, we do seek to evaluate whether you know how & what to test.
1. Create a .env file in the root of your project with the following content:

## Q&A
```bash
API_KEY=API_KEY
BASE_URL=BASE_URL

> Where should I send back the result when I'm done?
### 3. Run on iOS simulator

Please fork this repo and then send us a pull request to our repo when you think you are done. There is no deadline for this task unless otherwise noted to you directly.
1. Open the iOS simulator via terminal:

> What if I have a question?
```bash
open -a Simulator

Just create a new issue in this repo and we will respond and get back to you quickly.
2. With the iOS simulator running, go back to the Flutter project root directory and run:

## Review
```bash
flutter run

The coding challenge is a take-home test upon which we'll be conducting a thorough code review once complete. The review will consist of meeting some more of our mobile engineers and giving a review of the solution you have designed. Please be prepared to share your screen and run/demo the application to the group. During this process, the engineers will be asking questions.
1 change: 1 addition & 0 deletions ios/Flutter/Debug.xcconfig
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"
1 change: 1 addition & 0 deletions ios/Flutter/Release.xcconfig
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"
44 changes: 44 additions & 0 deletions ios/Podfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '12.0'

# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'

project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}

def flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end

File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end

require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)

flutter_ios_podfile_setup

target 'Runner' do
use_frameworks!
use_modular_headers!

flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
target 'RunnerTests' do
inherit! :search_paths
end
end

post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
end
end
23 changes: 23 additions & 0 deletions ios/Podfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
PODS:
- Flutter (1.0.0)
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS

DEPENDENCIES:
- Flutter (from `Flutter`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)

EXTERNAL SOURCES:
Flutter:
:path: Flutter
shared_preferences_foundation:
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"

SPEC CHECKSUMS:
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78

PODFILE CHECKSUM: 819463e6a0290f5a72f145ba7cde16e8b6ef0796

COCOAPODS: 1.13.0
Loading