diff --git a/.github/workflows/pr_status.yml b/.github/workflows/pr_status.yml index 4827269..b691df6 100644 --- a/.github/workflows/pr_status.yml +++ b/.github/workflows/pr_status.yml @@ -93,8 +93,11 @@ jobs: danger: name: Danger Code Review runs-on: ubuntu-latest - needs: [test] - if: always() + needs: [test, paths-filter] + if: | + needs.paths-filter.result == 'success' && + fromJson(needs.paths-filter.outputs.matrix).target[0] != null && + needs.test.result == 'success' permissions: pull-requests: write contents: read diff --git a/README.md b/README.md index 655453b..d4cf033 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,167 @@ -# exchanges-app +# Exchanges App A simple iOS application that displays a list of cryptocurrency exchanges and their details using the CoinMarketCap API. +This app have support to iOS 15+ and is built using Swift 6, UIKit, and follows the MVVM-C and TMA architecture. +[Figma Design](https://www.figma.com/design/OWVBNp9S0F6mbiXfdwOW9G/Exchanges-app?node-id=0-1&t=AvN5N9ABLPwF8tJy-1) + +--- + +## 📌 Summary +- [Exchanges App](#exchanges-app) + - [📌 Summary](#-summary) +- [Project Setup Guide](#project-setup-guide) + - [Requirements to setup the project](#requirements-to-setup-the-project) + - [Installation Steps](#installation-steps) + - [Dependencies of the project](#dependencies-of-the-project) + - [About the project structure](#about-the-project-structure) + - [Preview](#preview) + - [Exchange List](#exchange-list) + - [Exchange Detail](#exchange-detail) + - [Error](#error) +- [System Design](#system-design) + - [Functional requirements](#functional-requirements) + - [Non-functional requirements](#non-functional-requirements) + - [Data Entities Definitions](#data-entities-definitions) + - [Entity Relationship Diagram](#entity-relationship-diagram) + - [API Endpoints](#api-endpoints) + - [1. List Exchanges (Mapping)](#1-list-exchanges-mapping) + - [2. Exchange Metadata](#2-exchange-metadata) + - [3. Exchange Assets (Holdings)](#3-exchange-assets-holdings) + - [Error Handling \& Status Codes](#error-handling--status-codes) + - [High-Level Design (MVVM-C)](#high-level-design-mvvm-c) + - [Architectural Components](#architectural-components) + +--- + +# Project Setup Guide +## Requirements to setup the project +To set up the project, you will need the following tools installed on your machine: +- [Xcode 26.2+](https://xcodereleases.com/) +- [Homebrew](https://brew.sh/) (for installing dependencies) +- [RubyGems 3.6+](https://rubygems.org/) (for installing dependencies via Bundler) + +## Installation Steps +1. Create API Key: + - Sign up for a free account on [CoinMarketCap API](https://coinmarketcap.com/api/) + - Generate an API key from the dashboard. +2. create .env file in the root of the project and add your CoinMarketCap API key: +``` + TUIST_CM_API_BASE_URL=https://pro-api.coinmarketcap.com + TUIST_CM_API_KEY=ADD_COINMARKETCAP_API_KEY_HERE +``` +3. Install dependencies: + - Open Terminal and navigate to the project directory. + - Run `make local-setup` to install the required project dependencies. + - Run `make generate-project` to generate the project workspace. + +## Dependencies of the project +The project uses the following dependencies: +- [Tuist](https://tuist.io/) for project generation and management. +- [Fastlane](https://fastlane.tools/) for automating build and release processes. +- [SwiftLint](https://github.com/realm/SwiftLint) for code linting and formatting. +- [xcbeautify](https://github.com/tuist/xcbeautify) for beautifying Fastlane build output. +- [Slather](https://github.com/SlatherOrg/slather) for code coverage reports. +- [Danger](https://danger.systems/) for automated code review and quality checks. +- [networkin-package](https://github.com/vitor-rc1/networking-package) SPM parckge for abstracting network layer and API calls. This package was created by me and is used in this project to handle all network requests and responses, providing a clean and modular way to interact with the CoinMarketCap API. +- [Swinject](https://github.com/Swinject/Swinject) for dependency injection, allowing for better separation of concerns and easier testing. +- [Snapshot Testing](https://github.com/pointfreeco/swift-snapshot-testing) for testing the UI components and ensuring they render correctly across different states and configurations. + +## About the project structure +The project is organized into the following main directories: +- `Projects/`: Contains the Application and Features following the TMA architecture. + - `Sources/`: Contains code and utilities used only in the module, except for modules that are shared across multiple features. + - `Tests/`: Contains unit tests for the module. + - `Interfaces/`: Contains protocols and interfaces that define the contract for communication between modules. + - `Resources/`: Contains assets, storyboards, and other resources used by the module. + - `Testing/`: Contains test utilities and mocks used for unit testing to use between modules. +- `Tuist/`: Contains the Tuist configuration files for project generation. +- `fastlane/`: Contains Fastlane configuration files for automating build and release processes. +- `scripts/`: Contains custom scripts for setup, build, and other tasks. + +Using the TMA architecture, the project is organized into modules that represent different features of the app. Each module is self-contained and can be developed and tested independently, promoting separation of concerns and modularity. It's common to only have public code and concrete, but this bring a problem with tests, because we have to create duplicates spies and mocks for each module, so we have a shared Testing folder to avoid this problem. Below is a diagram illustrating the project structure and dependencies between modules: + +TMA Architecture Diagram + +The use of Tuist allows for easy project generation and management, while Fastlane automates the build and release processes, ensuring a smooth development workflow. SwiftLint helps maintain code quality and consistency across the codebase. + +The modules consist of: +- **App:** The main application module that contains the app delegate, scene delegate, and the main coordinator responsible for navigation. +- **Home:** The feature module responsible for displaying the list of cryptocurrency exchanges. +- **Detail:** The feature module responsible for displaying the details of a specific exchange. +- **DependencyInjection:** A shared module that contains the dependency injection container and related configurations. This module is used to manage dependencies across the app and features, ensuring a clean separation of concerns and easier testing. +- **DesisgnSystem:** A shared module that contains reusable UI components, styles, and assets. This module promotes consistency across the app and allows for easy maintenance of the design system. +- **Navigation:** A shared module that contains navigation-related components and utilities, such as coordinators and navigation controllers. This module helps centralize navigation logic and promotes a clean separation of concerns. + +## Preview +
+ 📸 Screenshots +The app consists of two main screens: the Exchange List and the Exchange Detail. Below are screenshots of each screen: + +### Exchange List + + + + + + + + + + + + + + + +
Exchange List ScreenExchange List ScreenExchange List Screen
LoadingPre loadedLoaded
Dark
+ + + + + + + + + + + + + + + +
Exchange List ScreenExchange List ScreenExchange List Screen
LoadingPre loadedLoaded
Light
+ +### Exchange Detail + + + + + + + + + +
Exchange Detail ScreenExchange Detail Screen
Detail DarkDetail Light
+ +### Error + + + + + + + + + +
Exchange List Error ScreenExchange List Error Screen
Error DarkError Light
+
+ +# System Design ## Functional requirements - **User can:** - view a list of cryptocurrency exchanges. - view details of a specific exchange. - - view details of a specific exchange using deeplinks - - visit the exchange's website from the app + - visit the exchange's website and twitter when have url - view the app in light and dark mode - view a loading indicator while data is being fetched - view an error message if data fetching fails @@ -19,6 +174,9 @@ A simple iOS application that displays a list of cryptocurrency exchanges and th - should be performant and load data quickly. - should consider scalability for future features and enhancements. - should follow best practices for iOS development. + - should support iOS 15 and later. + - should be built using Swift 6 and UIKit. + - should follow the MVVM-C architecture for better separation of concerns and testability. ## Data Entities Definitions - **PreLoadedExchanges:** A list of exchanges with basic information (id, name) that is preloaded in the app for quick access. @@ -32,7 +190,7 @@ A simple iOS application that displays a list of cryptocurrency exchanges and th ```mermaid erDiagram - PreLoadedExchange { + ExchangeSummary { Int id String name } @@ -128,7 +286,7 @@ The application architecture is based on the MVVM-C (Model-View-ViewModel + Coor - **Coordinator:** The "brain" of navigation. It removes the responsibility of flow control from View Controllers, making them independent and reusable. It handles the instantiation of ViewControllers and ViewModels. - **ViewModel:** Acts as a mediator between the Model and the View. It holds the business logic, formats data for display, and is completely unaware of the UI framework (UIKit/SwiftUI), which makes it ideal for Unit Testing. - **View (ViewController):** Responsible only for layout and capturing user interactions. It binds to the ViewModel to receive updates. -- **Network / API:** Handles all network requests and responses, abstracting the details of API communication. +- **Service / API:** Handles all network requests and responses, abstracting the details of API communication. Model: Represents the data structures and the business logic layer (Repositories and Services). diff --git a/readme-assets/dark/error.png b/readme-assets/dark/error.png new file mode 100644 index 0000000..febfedf Binary files /dev/null and b/readme-assets/dark/error.png differ diff --git a/readme-assets/dark/exchange-detail.png b/readme-assets/dark/exchange-detail.png new file mode 100644 index 0000000..6947990 Binary files /dev/null and b/readme-assets/dark/exchange-detail.png differ diff --git a/readme-assets/dark/exchange-list-loaded.png b/readme-assets/dark/exchange-list-loaded.png new file mode 100644 index 0000000..0437afe Binary files /dev/null and b/readme-assets/dark/exchange-list-loaded.png differ diff --git a/readme-assets/dark/exchange-list-loading.png b/readme-assets/dark/exchange-list-loading.png new file mode 100644 index 0000000..fde202b Binary files /dev/null and b/readme-assets/dark/exchange-list-loading.png differ diff --git a/readme-assets/dark/exchange-list-pre-loaded.png b/readme-assets/dark/exchange-list-pre-loaded.png new file mode 100644 index 0000000..6598c7c Binary files /dev/null and b/readme-assets/dark/exchange-list-pre-loaded.png differ diff --git a/readme-assets/graph-dependency.png b/readme-assets/graph-dependency.png new file mode 100644 index 0000000..f130151 Binary files /dev/null and b/readme-assets/graph-dependency.png differ diff --git a/readme-assets/light/error.png b/readme-assets/light/error.png new file mode 100644 index 0000000..ea105fc Binary files /dev/null and b/readme-assets/light/error.png differ diff --git a/readme-assets/light/exchange-detail.png b/readme-assets/light/exchange-detail.png new file mode 100644 index 0000000..15dc916 Binary files /dev/null and b/readme-assets/light/exchange-detail.png differ diff --git a/readme-assets/light/exchange-list-loaded.png b/readme-assets/light/exchange-list-loaded.png new file mode 100644 index 0000000..9b01412 Binary files /dev/null and b/readme-assets/light/exchange-list-loaded.png differ diff --git a/readme-assets/light/exchange-list-loading.png b/readme-assets/light/exchange-list-loading.png new file mode 100644 index 0000000..cd171ae Binary files /dev/null and b/readme-assets/light/exchange-list-loading.png differ diff --git a/readme-assets/light/exchange-list-pre-loaded.png b/readme-assets/light/exchange-list-pre-loaded.png new file mode 100644 index 0000000..2a938eb Binary files /dev/null and b/readme-assets/light/exchange-list-pre-loaded.png differ