diff --git a/.codecov.yml b/.codecov.yml new file mode 100644 index 0000000..814fab4 --- /dev/null +++ b/.codecov.yml @@ -0,0 +1,5 @@ +ignore: + - '**/**/**/*.g.dart' + - '**/**/**/*.freezed.dart' + - '**/**/**/**/*.g.dart' + - '**/**/**/**/*.freezed.dart' diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..48204cd --- /dev/null +++ b/.env.example @@ -0,0 +1 @@ +API_KEY= diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..d387dde --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,45 @@ +name: release + +on: + push: + tags: + - 'v*' + +env: + flutter_version: "2.2.0" + +jobs: + build_deploy: + name: Build apk and release + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - name: Cache Flutter dependencies + uses: actions/cache@v1 + with: + path: /opt/hostedtoolcache/flutter + key: ${{ runner.OS }}-flutter-install-cache-${{ env.flutter_version }} + - uses: subosito/flutter-action@v1 + with: + flutter-version: ${{ env.flutter_version }} + channel: 'stable' + - run: flutter pub get + # build Android version + - name: Create env file + run: | + touch .env + echo API_KEY=${{ secrets.API_KEY }} >> .env + cat .env + - run: flutter build apk --split-per-abi + # This action will create a github release and optionally upload an artifact to it. + # https://github.com/ncipollo/release-action + - name: Extract release notes + id: extract-release-notes + uses: ffurrer2/extract-release-notes@v1 + - name: Create a Release APK + uses: ncipollo/release-action@v1 + with: + artifacts: "build/app/outputs/apk/release/*.apk" + token: ${{ secrets.GITHUB_TOKEN }} + body: ${{ steps.extract-release-notes.outputs.release_notes }} + \ No newline at end of file diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..1534211 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,128 @@ +#The name of your workflow. +name: test +# Trigger the workflow on push or pull request +on: [push,pull_request_review] +env: + flutter_version: "2.2.0" + +#A workflow run is made up of one or more jobs. Jobs run in parallel by default. +jobs: + + unit-testing: + #The type of machine to run the job on. [windows,macos, ubuntu , self-hosted] + runs-on: ubuntu-latest + #sequence of tasks called + steps: + # The branch or tag ref that triggered the workflow will be checked out. + # https://github.com/actions/checkout + - uses: actions/checkout@v1 + # Setup a flutter environment. + # https://github.com/marketplace/actions/flutter-action + - name: Cache Flutter dependencies + uses: actions/cache@v1 + with: + path: /opt/hostedtoolcache/flutter + key: ${{ runner.OS }}-flutter-install-cache-${{ env.flutter_version }} + - uses: subosito/flutter-action@v1 + with: + flutter-version: '${{ env.flutter_version }}' + channel: 'stable' + - name: Create env file + run: | + touch .env + echo API_KEY=${{ secrets.API_KEY }} >> .env + cat .env + - run: flutter pub get + # run static analys code + - run: flutter analyze + # run flutter widgets tests and unit tests + - run: flutter test --coverage + # Upload coverage reports to Codecov + # https://github.com/marketplace/actions/codecov + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v1 + with: + token: ${{ secrets.CODECOV_TOKEN }} + file: coverage/lcov.info + ios-integration: + #creates a build matrix for your jobs + strategy: + #set of different configurations of the virtual environment. + matrix: + device: + - "iPhone 8 (14.4)" + - "iPhone 12 Pro Max (14.4)" + fail-fast: false + runs-on: macos-latest + #Identifies any jobs that must complete successfully before this job will run. + needs: unit-testing + steps: + - name: List all simulators + run: xcrun instruments -s + # get UUID simulator and boot a simulator on mac from command line + - name: Start Simulator + run: | + UDID=$( + xcrun instruments -s | + awk \ + -F ' *[][]' \ + -v 'device=${{ matrix.device }}' \ + '$1 == device { print $2 }' + ) + xcrun simctl boot "${UDID:?No Simulator with this name found}" + - uses: actions/checkout@v1 + - name: Cache Flutter dependencies + uses: actions/cache@v1 + with: + path: /opt/hostedtoolcache/flutter + key: ${{ runner.OS }}-flutter-install-cache-${{ env.flutter_version }} + - uses: subosito/flutter-action@v1 + with: + flutter-version: '${{ env.flutter_version }}' + channel: 'stable' + + - name: Create env file + run: | + touch .env + echo API_KEY=${{ secrets.API_KEY }} >> .env + cat .env + - run: flutter pub get + # Run flutter integrate tests + - name: Run Flutter Driver tests + run: flutter drive --driver=test_driver/integration_test.dart --target=integration_test/main_test.dart + + android-integration: + runs-on: macos-latest + #creates a build matrix for your jobs + strategy: + #set of different configurations of the virtual environment. + matrix: + api-level: [21, 29] + target: [default] + needs: unit-testing + steps: + - uses: actions/checkout@v1 + - name: Cache Flutter dependencies + uses: actions/cache@v1 + with: + path: /opt/hostedtoolcache/flutter + key: ${{ runner.OS }}-flutter-install-cache-${{ env.flutter_version }} + - uses: subosito/flutter-action@v1 + with: + flutter-version: '${{ env.flutter_version }}' + channel: 'stable' + - name: Create env file + run: | + touch .env + echo API_KEY=${{ secrets.API_KEY }} >> .env + cat .env + - name: Run Flutter Driver tests + #GitHub Action for installing, configuring and running Android Emulators (work only Mac OS) + #https://github.com/ReactiveCircus/android-emulator-runner + uses: reactivecircus/android-emulator-runner@v1 + with: + api-level: ${{ matrix.api-level }} + target: ${{ matrix.target }} + arch: x86_64 + profile: Nexus 6 + script: flutter drive --driver=test_driver/integration_test.dart --target=integration_test/main_test.dart \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..356a171 --- /dev/null +++ b/.gitignore @@ -0,0 +1,46 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Folder generated by flutter test --coverage +coverage/ + +.env \ No newline at end of file diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..f0274b3 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 1aafb3a8b9b0c36241c5f5b34ee914770f015818 + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..b3b8f77 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,20 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "app_crypto", + "request": "launch", + "type": "dart" + }, + { + "name": "App Crypto", + "program": "lib/main.dart", + "request": "launch", + "type": "dart", + "args": [] + } + ] +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..bea92c7 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,21 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +## [1.0.0] - 2021-05-27 +### First version + +## Features +- API REST (CryptoWatch) +- Linear Graph View (Hour, Day, Week, etc) +- OHLC Graph +- Search +- Light / Dark Theme +- Multi Lenguage +- Exchange Selection +- Favorite Pair + + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9a9baaf --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Salvador Valverde + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..717aa8f --- /dev/null +++ b/README.md @@ -0,0 +1,117 @@ + +# Flutter Crypto APP +Complete Flutter Application with Riverpod & Freezed + Dio for API REST. + +[![test](https://github.com/salvadordeveloper/flutter-crypto-app/actions/workflows/tests.yml/badge.svg)](https://github.com/salvadordeveloper/flutter-crypto-app/actions/workflows/tests.yml) +[![build](https://github.com/salvadordeveloper/flutter-crypto-app/actions/workflows/release.yml/badge.svg)](https://github.com/salvadordeveloper/flutter-crypto-app/actions/workflows/release.yml) +[![codecov](https://codecov.io/gh/salvadordeveloper/flutter-crypto-app/branch/main/graph/badge.svg?token=UYU0OB442S)](https://codecov.io/gh/salvadordeveloper/flutter-crypto-app) +[![Flutter version](https://img.shields.io/badge/flutter-2.2.0-blue?logo=flutter)](https://flutter.dev/docs/get-started/install) +[![GitHub license](https://img.shields.io/github/license/chinnonsantos/full_testing_flutter)](https://choosealicense.com/licenses/mit/) + + + +## Features +- API REST (CryptoWatch) +- Linear Graph View (Hour, Day, Week, etc) +- OHLC Graph +- Search +- Light / Dark Theme +- Multi Lenguage +- Exchange Selection +- Favorite Pair + +### Stack +- Flutter 2.2.0 +- Riverpod + Hooks +- Freezed +- Dio + +### Testing +- Unit Testing (flutter_test) +- Integration Testing (integration_test) +- Mock Data (http_mock_adapter) +- Github Actions (iOS & Android Integration Test) + +## Screenshots + + +| Home | Details | Settings | +| --- | --- | --- | +|||| +|||| + +## Setup project + +Download project +```bash +git clone https://github.com/salvadordeveloper/flutter-crypto-app +``` + +Get flutter dependencies +```bash +flutter pub get +``` + +You need to create an account at https://cryptowat.ch/ to get a personal API KEY + +Rename the env.example file to .env and put there you API KEY +```bash +API_KEY={CryptoWatch_KEY} +``` + +Run the app +```bash +flutter run +``` + +If you have any error with generated files try to run this +```bash +flutter pub run build_runner build --delete-conflicting-outputs +``` + + +### Testing + +Unit Test +```bash +flutter test +``` +Integration Test +```bash +flutter drive --driver=test_driver/integration_test.dart --target=integration_test/main_test.dart +``` + +## Resources +[Flutter Docs](https://flutter.dev/docs) + +[Riverpod Docs](https://riverpod.dev/docs/getting_started/) + +[Cryptowatch Docs](https://docs.cryptowat.ch/rest-api/) + + +## Licence + +``` +MIT License + +Copyright (c) 2021 Salvador Valverde + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +``` + diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000..362ae93 --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,10 @@ +#include: package:effective_dart/analysis_options.yaml + +analyzer: + enable-experiment: + - non-nullable + exclude: + - "**/*.g.dart" + - "**/*.freezed.dart" + + \ No newline at end of file diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..0a741cb --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,11 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..a2e9347 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,63 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 29 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.cryptocurrency_app" + minSdkVersion 18 + targetSdkVersion 29 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.debug + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..a3a8e8f --- /dev/null +++ b/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..e6ac00f --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/cryptocurrency_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/cryptocurrency_app/MainActivity.kt new file mode 100644 index 0000000..3de56c3 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/cryptocurrency_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.cryptocurrency_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} diff --git a/android/app/src/main/res/drawable/launch_background.xml b/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 0000000..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..db77bb4 Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-hdpi/launcher_icon.png b/android/app/src/main/res/mipmap-hdpi/launcher_icon.png new file mode 100644 index 0000000..dcf58c0 Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/launcher_icon.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..17987b7 Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/launcher_icon.png b/android/app/src/main/res/mipmap-mdpi/launcher_icon.png new file mode 100644 index 0000000..068fcb6 Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/launcher_icon.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..09d4391 Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png b/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png new file mode 100644 index 0000000..e8e6efe Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..d5f1c8d Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png b/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png new file mode 100644 index 0000000..80e4301 Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..4d6372e Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png b/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png new file mode 100644 index 0000000..73c1df6 Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png differ diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..a3a8e8f --- /dev/null +++ b/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/android/build.gradle b/android/build.gradle new file mode 100644 index 0000000..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..94adc3a --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx1536M +android.useAndroidX=true +android.enableJetifier=true diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..44e62bc --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,11 @@ +include ':app' + +def localPropertiesFile = new File(rootProject.projectDir, "local.properties") +def properties = new Properties() + +assert localPropertiesFile.exists() +localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } + +def flutterSdkPath = properties.getProperty("flutter.sdk") +assert flutterSdkPath != null, "flutter.sdk not set in local.properties" +apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/assets/icon/icon.png b/assets/icon/icon.png new file mode 100644 index 0000000..269d06a Binary files /dev/null and b/assets/icon/icon.png differ diff --git a/assets/translations/en.json b/assets/translations/en.json new file mode 100644 index 0000000..bbfd6ff --- /dev/null +++ b/assets/translations/en.json @@ -0,0 +1,50 @@ +{ + "homeTitle" : "Home", + "openChart" : "Open Chart", + + "searchTitle" : "Search", + "searchBar" : "Search coin...", + "noResults" : "No results", + + "settingsTitle": "Settings", + + "languageSection" : "Language", + "language": "Language", + "dataSection" : "Data", + "exchange" : "Exchange", + "topPair" : "Top Pair", + "designSection" : "Design", + "appTheme" : "App theme", + + "spanish" : "Spanish", + "english" : "English", + + "summary" : "Summary", + "orderbook" : "Orderbook", + "trades" : "Trades", + "ohlc" : "OHLC", + + "price" : "Price", + "last" : "Last", + "high" : "High", + "low" : "Low", + "change" : "Change", + "volume" : "Volume", + "quoteVolume" : "Quote Volume", + "time" : "Time", + "amount" : "Amount", + "bid" : "Bid", + "ask" : "Ask", + + "errorRequestCancelled" : "Request to API server was cancelled", + "errorConnectionTimeout" : "Connection timeout with API server", + "errorInternetConnection" : "Connection to API server failed due to internet connection", + "errorReceiveTimeout" : "Receive timeout in connection with API server", + "errorSendTimeout" : "Send timout in connection iwth API server", + "errorBadRequest": "Bad request", + "errorRequestNotFound": "The requested resource was not found", + "errorIntenalServer" : "Internal server error", + "errorSomethingWentWrong" : "Something went wrong" + + +} \ No newline at end of file diff --git a/assets/translations/es.json b/assets/translations/es.json new file mode 100644 index 0000000..5f7973e --- /dev/null +++ b/assets/translations/es.json @@ -0,0 +1,50 @@ +{ + "homeTitle" : "Inicio", + "openChart" : "Abrir grafica", + + "searchTitle" : "Buscar", + "searchBar" : "Buscar moneda...", + "noResults" : "Sin resultados", + + "settingsTitle": "Ajustes", + + "languageSection" : "Lenguage", + "language": "Idioma", + "dataSection" : "Datos", + "exchange" : "Exchange", + "topPair" : "Top Par", + "designSection" : "Diseño", + "appTheme" : "Tema", + + "spanish" : "Español", + "english" : "Ingles", + + + "summary" : "Resumen", + "orderbook" : "Orderbook", + "trades" : "Trades", + "ohlc" : "OHLC", + + "price" : "Precio", + "last" : "Ultimo", + "high" : "Más alto", + "low" : "Más bajo", + "change" : "Cambio", + "volume" : "Volumen", + "quoteVolume" : "Quote Volume", + "time" : "Tiempo", + "amount" : "Cantidad", + "bid" : "Bid", + "ask" : "Ask", + + "errorRequestCancelled" : "Request to API server was cancelled", + "errorConnectionTimeout" : "Connection timeout with API server", + "errorInternetConnection" : "Connection to API server failed due to internet connection", + "errorReceiveTimeout" : "Receive timeout in connection with API server", + "errorSendTimeout" : "Send timout in connection iwth API server", + "errorBadRequest": "Bad request", + "errorRequestNotFound": "The requested resource was not found", + "errorIntenalServer" : "Internal server error", + "errorSomethingWentWrong" : "Something went wrong" + +} \ No newline at end of file diff --git a/integration_test/data/api_data.dart b/integration_test/data/api_data.dart new file mode 100644 index 0000000..e022137 --- /dev/null +++ b/integration_test/data/api_data.dart @@ -0,0 +1,137 @@ +class ApiData { + static final Map exchanges = { + "result": [ + { + "id": 17, + "symbol": "mexbt", + "name": "meXBT", + "route": "https://api.cryptowat.ch/exchanges/mexbt", + "active": false + }, + { + "id": 62, + "symbol": "coinone", + "name": "Coinone", + "route": "https://api.cryptowat.ch/exchanges/coinone", + "active": true + }, + ], + "allowance": {"cost": 0, "remaining": 100, "upgrade": ""} + }; + + static final Map pairs = { + "result": [ + { + "id": 579, + "exchange": "binance", + "pair": "btcusdt", + "active": true, + "route": "https://api.cryptowat.ch/markets/binance/btcusdt" + }, + { + "id": 580, + "exchange": "binance", + "pair": "ethbtc", + "active": true, + "route": "https://api.cryptowat.ch/markets/binance/ethbtc" + }, + { + "id": 581, + "exchange": "binance", + "pair": "ltcbtc", + "active": true, + "route": "https://api.cryptowat.ch/markets/binance/ltcbtc" + }, + { + "id": 582, + "exchange": "binance", + "pair": "neobtc", + "active": true, + "route": "https://api.cryptowat.ch/markets/binance/neobtc" + }, + ], + "allowance": {"cost": 0, "remaining": 100, "upgrade": ""} + }; + + static final Map pair_btcusdt_summary = { + "result": { + "price": { + "last": 35503.33, + "high": 43861.94, + "low": 30000, + "change": {"percentage": -0.18764266402587584, "absolute": -8200.75} + }, + "volume": 257132.87322650044, + "volumeQuote": 10096197214.14349 + }, + "allowance": {"cost": 0, "remaining": 100, "upgrade": ""} + }; + + static final Map pair_btcusdt_oderbook = { + "result": { + "asks": [ + [35922.59, 0.004088], + [35925.23, 0.003071], + [35925.71, 0.012824], + [35927.12, 0.000556], + [35927.58, 0.2178], + ], + "bids": [ + [35904.23, 0.153095], + [35900.35, 0.082238], + [35898, 0.12], + [35897.99, 0.006152], + [35897.68, 0.04332], + ], + "seqNum": 429614 + }, + "allowance": {"cost": 0, "remaining": 100, "upgrade": ""} + }; + + static final Map pair_btcusdt_trades = { + "result": [ + [0, 1621433110, 34452.66, 0.008464], + [0, 1621433110, 34454.43, 0.016662], + [0, 1621433110, 34485.69, 0.00476], + [0, 1621433110, 34475.97, 0.000401], + [0, 1621433110, 34456.09, 0.0011], + [0, 1621433110, 34456.09, 0.004997], + ], + "allowance": {"cost": 0, "remaining": 100, "upgrade": ""} + }; + + static final Map pair_btcusdt_graph = { + "result": { + "14400": [ + [ + 1607054400, + 19422.34, + 19527, + 19122.74, + 19162.62, + 8683.588417, + 167917416.81467284 + ], + [ + 1607097600, + 18835.47, + 19146.22, + 18686.38, + 18943.35, + 14717.586675, + 278732315.17076141 + ], + [ + 1607112000, + 18944.06, + 19078.68, + 18817, + 19038.73, + 8799.851665, + 166925728.42698553 + ], + ] + }, + "allowance": {"cost": 0, "remaining": 100, "upgrade": ""} + }; +} diff --git a/integration_test/main_test.dart b/integration_test/main_test.dart new file mode 100644 index 0000000..2627e0b --- /dev/null +++ b/integration_test/main_test.dart @@ -0,0 +1,8 @@ +import 'package:integration_test/integration_test.dart'; + +import 'search_test.dart' as app; + +void main() { + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + app.main(); +} diff --git a/integration_test/search_test.dart b/integration_test/search_test.dart new file mode 100644 index 0000000..75b55ec --- /dev/null +++ b/integration_test/search_test.dart @@ -0,0 +1,104 @@ +import 'dart:async'; +import 'package:cryptocurrency_app/constants/keys.dart'; +import 'package:cryptocurrency_app/main.dart' as app; +import 'package:cryptocurrency_app/repository/crypto_repository.dart'; +import 'package:dio/dio.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:http_mock_adapter/http_mock_adapter.dart'; +import 'data/api_data.dart'; + +void main() { + final dioAdapter = DioAdapter(); + final dio = Dio(); + setUpAll(() { + dio.httpClientAdapter = dioAdapter; + + //Get graph + dioAdapter.onGet('/markets/binance/btcusdt/ohlc', (request) { + request.reply(200, ApiData.pair_btcusdt_graph); + }); + + //Get trades + dioAdapter.onGet('/markets/binance/btcusdt/trades', (request) { + request.reply(200, ApiData.pair_btcusdt_trades); + }); + + //Get orderbook + dioAdapter.onGet('/markets/binance/btcusdt/orderbook', (request) { + request.reply(200, ApiData.pair_btcusdt_oderbook); + }); + + //Get sumary of btcusdt + dioAdapter.onGet('/markets/binance/btcusdt/summary', (request) { + print(request.toString()); + request.reply(200, ApiData.pair_btcusdt_summary); + }); + + //Get list of pairs from Binance + dioAdapter.onGet('/markets/binance', (request) { + print(request.toString()); + + request.reply(200, ApiData.pairs); + }); + }); + + group('Search Screen Test', () { + testWidgets('Search screen loading data', (tester) async { + WidgetsFlutterBinding.ensureInitialized(); + await EasyLocalization.ensureInitialized(); + + runApp(EasyLocalization( + supportedLocales: [Locale('en'), Locale('es')], + path: 'assets/translations', + fallbackLocale: Locale('en'), + child: ProviderScope( + overrides: [clientProvider.overrideWithValue(dio)], + child: app.MyApp(), + ))); + + await tester.pumpAndSettle(); + final searchButton = find.byKey(Keys.NAV_SEARCH); + + await pumpUntilFound(tester, searchButton); + + await tester.tap(searchButton); + + await tester.pumpAndSettle(); + + final results = await find.byKey(Keys.PAIR_TILE); + + expect(results, findsNWidgets(4)); + + final searchTextField = await find.byKey(Keys.SEARCH_TEXT_FIELD); + await tester.showKeyboard(searchTextField); + tester.testTextInput.enterText("btcusdt"); + await tester.testTextInput.receiveAction(TextInputAction.done); + + await tester.pumpAndSettle(); + final resultsFiltered = await find.byKey(Keys.PAIR_TILE); + expect(resultsFiltered, findsOneWidget); + }); + }); +} + +Future pumpUntilFound( + WidgetTester tester, + Finder finder, { + Duration timeout = const Duration(seconds: 30), +}) async { + var timerDone = false; + final timer = + Timer(timeout, () => throw TimeoutException("Pump until has timed out")); + while (timerDone != true) { + await tester.pump(); + + final found = tester.any(finder); + if (found) { + timerDone = true; + } + } + timer.cancel(); +} diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 0000000..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.0 + + diff --git a/ios/Flutter/Debug.xcconfig b/ios/Flutter/Debug.xcconfig new file mode 100644 index 0000000..ec97fc6 --- /dev/null +++ b/ios/Flutter/Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "Generated.xcconfig" diff --git a/ios/Flutter/Release.xcconfig b/ios/Flutter/Release.xcconfig new file mode 100644 index 0000000..c4855bf --- /dev/null +++ b/ios/Flutter/Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "Generated.xcconfig" diff --git a/ios/Podfile b/ios/Podfile new file mode 100644 index 0000000..1e8c3c9 --- /dev/null +++ b/ios/Podfile @@ -0,0 +1,41 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.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__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/ios/Podfile.lock b/ios/Podfile.lock new file mode 100644 index 0000000..ec2e8c3 --- /dev/null +++ b/ios/Podfile.lock @@ -0,0 +1,34 @@ +PODS: + - Flutter (1.0.0) + - flutter_secure_storage (3.3.1): + - Flutter + - integration_test (0.0.1): + - Flutter + - shared_preferences (0.0.1): + - Flutter + +DEPENDENCIES: + - Flutter (from `Flutter`) + - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) + - integration_test (from `.symlinks/plugins/integration_test/ios`) + - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) + +EXTERNAL SOURCES: + Flutter: + :path: Flutter + flutter_secure_storage: + :path: ".symlinks/plugins/flutter_secure_storage/ios" + integration_test: + :path: ".symlinks/plugins/integration_test/ios" + shared_preferences: + :path: ".symlinks/plugins/shared_preferences/ios" + +SPEC CHECKSUMS: + Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c + flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec + integration_test: 6eb66a19f7104200dcfdd62bc0077e1b09686e4f + shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d + +PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c + +COCOAPODS: 1.10.1 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..be8ea1e --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,575 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 51; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + E52D63AAC42E7D57198ABF57 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 13C8C2662A08886B38F840BE /* Pods_Runner.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 13C8C2662A08886B38F840BE /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 470256A2C406E78196483DCD /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + CFC9D2888BE8ADB8479E4A6F /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + F5B1D7DFF146D5EFF0E036BF /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + E52D63AAC42E7D57198ABF57 /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + C2A5875E2C18837D1F86EA8F /* Pods */, + A2BBB35B63AD12E0DD726378 /* Frameworks */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + A2BBB35B63AD12E0DD726378 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 13C8C2662A08886B38F840BE /* Pods_Runner.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + C2A5875E2C18837D1F86EA8F /* Pods */ = { + isa = PBXGroup; + children = ( + 470256A2C406E78196483DCD /* Pods-Runner.debug.xcconfig */, + F5B1D7DFF146D5EFF0E036BF /* Pods-Runner.release.xcconfig */, + CFC9D2888BE8ADB8479E4A6F /* Pods-Runner.profile.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + EE7B0F0FC718AE4532930190 /* [CP] Check Pods Manifest.lock */, + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + 709721392DE5A8A9401AB1A3 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 709721392DE5A8A9401AB1A3 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; + EE7B0F0FC718AE4532930190 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = M63FJ72T54; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.cryptocurrencyApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = M63FJ72T54; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.cryptocurrencyApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = M63FJ72T54; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.cryptocurrencyApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Runner.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..21a3cc1 --- /dev/null +++ b/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift new file mode 100644 index 0000000..70693e4 --- /dev/null +++ b/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import UIKit +import Flutter + +@UIApplicationMain +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d36b1fa --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000..a5f2764 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 0000000..b1d570a Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000..ea03a51 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000..e65f800 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000..dd8732e Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000..83f1b19 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 0000000..c0b52c8 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 0000000..ea03a51 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000..5f11aab Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000..bebe66c Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000..bebe66c Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000..1861e6d Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000..44d0b2b Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 0000000..5e7d1dc Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000..4d4bc55 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 0000000..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 0000000..89c2725 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/ios/Runner/Base.lproj/LaunchScreen.storyboard b/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Runner/Base.lproj/Main.storyboard b/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 0000000..f3c2851 --- /dev/null +++ b/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist new file mode 100644 index 0000000..4e835c7 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,51 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + Crypto App + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + CFBundleLocalizations + + en + es + + + + diff --git a/ios/Runner/Runner-Bridging-Header.h b/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 0000000..308a2a5 --- /dev/null +++ b/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/lib/constants/app_theme.dart b/lib/constants/app_theme.dart new file mode 100644 index 0000000..4334fb8 --- /dev/null +++ b/lib/constants/app_theme.dart @@ -0,0 +1,74 @@ +import 'package:flutter/material.dart'; + +class AppTheme { + static final ThemeData light = ThemeData( + iconTheme: IconThemeData(color: Colors.black87), + bottomNavigationBarTheme: BottomNavigationBarThemeData( + backgroundColor: Colors.blueGrey, + selectedItemColor: Colors.white, + unselectedItemColor: Colors.white70), + appBarTheme: AppBarTheme( + color: Colors.blueGrey, + brightness: Brightness.dark, + ), + scaffoldBackgroundColor: Colors.white, + accentColor: Colors.black54, + brightness: Brightness.light, + cardColor: Colors.grey[500], + unselectedWidgetColor: Colors.black45, + focusColor: Colors.black, + primarySwatch: Colors.blueGrey, + textTheme: TextTheme( + headline1: TextStyle( + color: Colors.black, fontSize: 40, fontWeight: FontWeight.w500), + headline2: TextStyle( + color: Colors.black, fontSize: 34, fontWeight: FontWeight.w400), + headline3: TextStyle( + color: Colors.black, fontSize: 22, fontWeight: FontWeight.w500), + headline4: TextStyle( + color: Colors.black54, fontSize: 16, fontWeight: FontWeight.bold), + headline5: TextStyle( + color: Colors.black, fontSize: 19, fontWeight: FontWeight.w700), + headline6: TextStyle( + color: Colors.black, fontSize: 13, fontWeight: FontWeight.w400), + subtitle1: TextStyle( + color: Colors.black87, fontSize: 14, fontWeight: FontWeight.normal), + subtitle2: TextStyle( + color: Colors.black, fontSize: 16, fontWeight: FontWeight.bold), + ), + ); + + static final ThemeData dark = ThemeData( + primaryColor: Colors.black12, + bottomNavigationBarTheme: BottomNavigationBarThemeData( + backgroundColor: Colors.black, + selectedItemColor: Colors.white, + unselectedItemColor: Colors.white70), + appBarTheme: AppBarTheme( + color: Colors.black, + brightness: Brightness.dark, + ), + scaffoldBackgroundColor: Colors.black, + accentColor: Colors.white54, + brightness: Brightness.dark, + focusColor: Colors.white, + primarySwatch: Colors.blueGrey, + textTheme: TextTheme( + headline1: TextStyle( + color: Colors.white, fontSize: 40, fontWeight: FontWeight.w500), + headline2: TextStyle( + color: Colors.white, fontSize: 34, fontWeight: FontWeight.w400), + headline3: TextStyle( + color: Colors.white, fontSize: 22, fontWeight: FontWeight.w500), + headline4: TextStyle( + color: Colors.white70, fontSize: 16, fontWeight: FontWeight.bold), + headline5: TextStyle( + color: Colors.white, fontSize: 19, fontWeight: FontWeight.w700), + headline6: TextStyle( + color: Colors.white, fontSize: 13, fontWeight: FontWeight.w400), + subtitle1: TextStyle( + color: Colors.white70, fontSize: 14, fontWeight: FontWeight.normal), + subtitle2: TextStyle( + color: Colors.white, fontSize: 16, fontWeight: FontWeight.bold)), + ); +} diff --git a/lib/constants/exceptions.dart b/lib/constants/exceptions.dart new file mode 100644 index 0000000..f3e7089 --- /dev/null +++ b/lib/constants/exceptions.dart @@ -0,0 +1,47 @@ +import 'package:dio/dio.dart'; +import '../../generated/locale_keys.g.dart'; + +class DataException implements Exception { + DataException({required this.message}); + + DataException.fromDioError(DioError dioError) { + switch (dioError.type) { + case DioErrorType.cancel: + message = LocaleKeys.errorRequestCancelled; + break; + case DioErrorType.connectTimeout: + message = LocaleKeys.errorConnectionTimeout; + break; + case DioErrorType.receiveTimeout: + message = LocaleKeys.errorReceiveTimeout; + break; + case DioErrorType.response: + message = _handleError(dioError.response!.statusCode!); + break; + case DioErrorType.sendTimeout: + message = LocaleKeys.errorSendTimeout; + break; + default: + message = LocaleKeys.errorInternetConnection; + break; + } + } + + String message = ""; + + String _handleError(int statusCode) { + switch (statusCode) { + case 400: + return LocaleKeys.errorBadRequest; + case 404: + return LocaleKeys.errorRequestNotFound; + case 500: + return LocaleKeys.errorIntenalServer; + default: + return LocaleKeys.errorSomethingWentWrong; + } + } + + @override + String toString() => message; +} diff --git a/lib/constants/keys.dart b/lib/constants/keys.dart new file mode 100644 index 0000000..d7bea3c --- /dev/null +++ b/lib/constants/keys.dart @@ -0,0 +1,17 @@ +import 'package:flutter/material.dart'; + +class Keys { + static final NAV_BAR = Key('nav_bar'); + static final NAV_HOME = Key('nav_home'); + static final NAV_SEARCH = Key('nav_search'); + static final NAV_SETTINGS = Key('nav_settings'); + + static final HOME_SCREEN = Key('home_screen'); + static final SEARCH_SCREEN = Key('search_screen'); + static final SETTINGS_SCREEN = Key('settings_screen'); + static final DETAILS_SCREEN = Key('details_screen'); + + static final SEARCH_TEXT_FIELD = Key('seach_text_field'); + + static final PAIR_TILE = Key('pair_tile'); +} diff --git a/lib/constants/utils.dart b/lib/constants/utils.dart new file mode 100644 index 0000000..49d07b8 --- /dev/null +++ b/lib/constants/utils.dart @@ -0,0 +1,78 @@ +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; + +import '../models/graph/graph/graph.dart'; + +ThemeMode getThemeMode(String type) { + ThemeMode themeMode = ThemeMode.system; + switch (type) { + case "System": + themeMode = ThemeMode.system; + break; + case "Dark": + themeMode = ThemeMode.dark; + break; + case "Light": + themeMode = ThemeMode.light; + break; + } + return themeMode; +} + +final themeModes = ["System", "Dark", "Light"]; + +final String defaultLenguage = "English"; +final String defaultExchange = "binance"; +final String defaultPair = "btcusdt"; +final String defaultTheme = "System"; + +List getPoints(Graph graph) { + if (graph.pairs[0].points.length > 0) + return graph.pairs[0].points.map((e) => e.closePrice).toList(); + else + return []; +} + +String epochToString(String epoch) { + final DateTime timeStamp = + DateTime.fromMillisecondsSinceEpoch(int.parse(epoch) * 1000); + return DateFormat('dd/MM/yyyy').format(timeStamp); +} + +final List demoGraphData = const [ + 86, + 45, + 59, + 65, + 1, + 62, + 26, + 41, + 88, + 60, + 17, + 18, + 58, + 67, + 55, + 56, + 97, + 96, + 22, + 57, + 29, + 69, + 19, + 30, + 47, + 63, + 33, + 37, + 40, + 51, + 53, + 91, + 71, + 92, + 28, +]; diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart new file mode 100644 index 0000000..1fd8b8e --- /dev/null +++ b/lib/generated/locale_keys.g.dart @@ -0,0 +1,44 @@ +// DO NOT EDIT. This is code generated via package:easy_localization/generate.dart + +abstract class LocaleKeys { + static const homeTitle = 'homeTitle'; + static const openChart = 'openChart'; + static const searchTitle = 'searchTitle'; + static const searchBar = 'searchBar'; + static const noResults = 'noResults'; + static const settingsTitle = 'settingsTitle'; + static const languageSection = 'languageSection'; + static const language = 'language'; + static const dataSection = 'dataSection'; + static const exchange = 'exchange'; + static const topPair = 'topPair'; + static const designSection = 'designSection'; + static const appTheme = 'appTheme'; + static const spanish = 'spanish'; + static const english = 'english'; + static const summary = 'summary'; + static const orderbook = 'orderbook'; + static const trades = 'trades'; + static const ohlc = 'ohlc'; + static const price = 'price'; + static const last = 'last'; + static const high = 'high'; + static const low = 'low'; + static const change = 'change'; + static const volume = 'volume'; + static const quoteVolume = 'quoteVolume'; + static const time = 'time'; + static const amount = 'amount'; + static const bid = 'bid'; + static const ask = 'ask'; + static const errorRequestCancelled = 'errorRequestCancelled'; + static const errorConnectionTimeout = 'errorConnectionTimeout'; + static const errorInternetConnection = 'errorInternetConnection'; + static const errorReceiveTimeout = 'errorReceiveTimeout'; + static const errorSendTimeout = 'errorSendTimeout'; + static const errorBadRequest = 'errorBadRequest'; + static const errorRequestNotFound = 'errorRequestNotFound'; + static const errorIntenalServer = 'errorIntenalServer'; + static const errorSomethingWentWrong = 'errorSomethingWentWrong'; + +} diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..5f2092e --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,44 @@ +import 'package:cryptocurrency_app/constants/app_theme.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart' as DotEnv; +import 'provider/settings_provider.dart'; +import 'ui/home.dart'; +import 'package:cryptocurrency_app/constants/utils.dart' as Utils; + +void main() async { + await DotEnv.load(fileName: ".env"); + WidgetsFlutterBinding.ensureInitialized(); + await EasyLocalization.ensureInitialized(); + + runApp(EasyLocalization( + supportedLocales: [Locale('en'), Locale('es')], + path: 'assets/translations', + fallbackLocale: Locale('en'), + child: ProviderScope(child: MyApp()))); +} + +class MyApp extends HookWidget { + MyApp({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final settings = useProvider(cryptoSettings); + + final themeMode = settings.maybeWhen( + data: (data) => Utils.getThemeMode(data.themeMode), + orElse: () => ThemeMode.system); + + return MaterialApp( + debugShowCheckedModeBanner: false, + localizationsDelegates: context.localizationDelegates, + supportedLocales: context.supportedLocales, + locale: context.locale, + home: Home(), + themeMode: themeMode, + theme: AppTheme.light, + darkTheme: AppTheme.dark); + } +} diff --git a/lib/models/allowance/allowance.dart b/lib/models/allowance/allowance.dart new file mode 100644 index 0000000..fc653e1 --- /dev/null +++ b/lib/models/allowance/allowance.dart @@ -0,0 +1,15 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'allowance.freezed.dart'; +part 'allowance.g.dart'; + +@freezed +abstract class Allowance with _$Allowance { + const factory Allowance({ + required double cost, + required double remaining, + }) = _Allowance; + + factory Allowance.fromJson(Map json) => + _$AllowanceFromJson(json); +} diff --git a/lib/models/allowance/allowance.freezed.dart b/lib/models/allowance/allowance.freezed.dart new file mode 100644 index 0000000..4ce60e2 --- /dev/null +++ b/lib/models/allowance/allowance.freezed.dart @@ -0,0 +1,179 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides + +part of 'allowance.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +Allowance _$AllowanceFromJson(Map json) { + return _Allowance.fromJson(json); +} + +/// @nodoc +class _$AllowanceTearOff { + const _$AllowanceTearOff(); + + _Allowance call({required double cost, required double remaining}) { + return _Allowance( + cost: cost, + remaining: remaining, + ); + } + + Allowance fromJson(Map json) { + return Allowance.fromJson(json); + } +} + +/// @nodoc +const $Allowance = _$AllowanceTearOff(); + +/// @nodoc +mixin _$Allowance { + double get cost => throw _privateConstructorUsedError; + double get remaining => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $AllowanceCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $AllowanceCopyWith<$Res> { + factory $AllowanceCopyWith(Allowance value, $Res Function(Allowance) then) = + _$AllowanceCopyWithImpl<$Res>; + $Res call({double cost, double remaining}); +} + +/// @nodoc +class _$AllowanceCopyWithImpl<$Res> implements $AllowanceCopyWith<$Res> { + _$AllowanceCopyWithImpl(this._value, this._then); + + final Allowance _value; + // ignore: unused_field + final $Res Function(Allowance) _then; + + @override + $Res call({ + Object? cost = freezed, + Object? remaining = freezed, + }) { + return _then(_value.copyWith( + cost: cost == freezed + ? _value.cost + : cost // ignore: cast_nullable_to_non_nullable + as double, + remaining: remaining == freezed + ? _value.remaining + : remaining // ignore: cast_nullable_to_non_nullable + as double, + )); + } +} + +/// @nodoc +abstract class _$AllowanceCopyWith<$Res> implements $AllowanceCopyWith<$Res> { + factory _$AllowanceCopyWith( + _Allowance value, $Res Function(_Allowance) then) = + __$AllowanceCopyWithImpl<$Res>; + @override + $Res call({double cost, double remaining}); +} + +/// @nodoc +class __$AllowanceCopyWithImpl<$Res> extends _$AllowanceCopyWithImpl<$Res> + implements _$AllowanceCopyWith<$Res> { + __$AllowanceCopyWithImpl(_Allowance _value, $Res Function(_Allowance) _then) + : super(_value, (v) => _then(v as _Allowance)); + + @override + _Allowance get _value => super._value as _Allowance; + + @override + $Res call({ + Object? cost = freezed, + Object? remaining = freezed, + }) { + return _then(_Allowance( + cost: cost == freezed + ? _value.cost + : cost // ignore: cast_nullable_to_non_nullable + as double, + remaining: remaining == freezed + ? _value.remaining + : remaining // ignore: cast_nullable_to_non_nullable + as double, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$_Allowance implements _Allowance { + const _$_Allowance({required this.cost, required this.remaining}); + + factory _$_Allowance.fromJson(Map json) => + _$_$_AllowanceFromJson(json); + + @override + final double cost; + @override + final double remaining; + + @override + String toString() { + return 'Allowance(cost: $cost, remaining: $remaining)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other is _Allowance && + (identical(other.cost, cost) || + const DeepCollectionEquality().equals(other.cost, cost)) && + (identical(other.remaining, remaining) || + const DeepCollectionEquality() + .equals(other.remaining, remaining))); + } + + @override + int get hashCode => + runtimeType.hashCode ^ + const DeepCollectionEquality().hash(cost) ^ + const DeepCollectionEquality().hash(remaining); + + @JsonKey(ignore: true) + @override + _$AllowanceCopyWith<_Allowance> get copyWith => + __$AllowanceCopyWithImpl<_Allowance>(this, _$identity); + + @override + Map toJson() { + return _$_$_AllowanceToJson(this); + } +} + +abstract class _Allowance implements Allowance { + const factory _Allowance({required double cost, required double remaining}) = + _$_Allowance; + + factory _Allowance.fromJson(Map json) = + _$_Allowance.fromJson; + + @override + double get cost => throw _privateConstructorUsedError; + @override + double get remaining => throw _privateConstructorUsedError; + @override + @JsonKey(ignore: true) + _$AllowanceCopyWith<_Allowance> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/models/allowance/allowance.g.dart b/lib/models/allowance/allowance.g.dart new file mode 100644 index 0000000..5e56ba5 --- /dev/null +++ b/lib/models/allowance/allowance.g.dart @@ -0,0 +1,20 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'allowance.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$_Allowance _$_$_AllowanceFromJson(Map json) { + return _$_Allowance( + cost: (json['cost'] as num).toDouble(), + remaining: (json['remaining'] as num).toDouble(), + ); +} + +Map _$_$_AllowanceToJson(_$_Allowance instance) => + { + 'cost': instance.cost, + 'remaining': instance.remaining, + }; diff --git a/lib/models/exchanges/exchange/exchange.dart b/lib/models/exchanges/exchange/exchange.dart new file mode 100644 index 0000000..6cc7544 --- /dev/null +++ b/lib/models/exchanges/exchange/exchange.dart @@ -0,0 +1,17 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'exchange.freezed.dart'; +part 'exchange.g.dart'; + +@freezed +abstract class Exchange with _$Exchange { + const factory Exchange( + {required int id, + required String symbol, + required String name, + required String route, + required bool active}) = _Exchange; + + factory Exchange.fromJson(Map json) => + _$ExchangeFromJson(json); +} diff --git a/lib/models/exchanges/exchange/exchange.freezed.dart b/lib/models/exchanges/exchange/exchange.freezed.dart new file mode 100644 index 0000000..74afbb3 --- /dev/null +++ b/lib/models/exchanges/exchange/exchange.freezed.dart @@ -0,0 +1,247 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides + +part of 'exchange.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +Exchange _$ExchangeFromJson(Map json) { + return _Exchange.fromJson(json); +} + +/// @nodoc +class _$ExchangeTearOff { + const _$ExchangeTearOff(); + + _Exchange call( + {required int id, + required String symbol, + required String name, + required String route, + required bool active}) { + return _Exchange( + id: id, + symbol: symbol, + name: name, + route: route, + active: active, + ); + } + + Exchange fromJson(Map json) { + return Exchange.fromJson(json); + } +} + +/// @nodoc +const $Exchange = _$ExchangeTearOff(); + +/// @nodoc +mixin _$Exchange { + int get id => throw _privateConstructorUsedError; + String get symbol => throw _privateConstructorUsedError; + String get name => throw _privateConstructorUsedError; + String get route => throw _privateConstructorUsedError; + bool get active => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $ExchangeCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ExchangeCopyWith<$Res> { + factory $ExchangeCopyWith(Exchange value, $Res Function(Exchange) then) = + _$ExchangeCopyWithImpl<$Res>; + $Res call({int id, String symbol, String name, String route, bool active}); +} + +/// @nodoc +class _$ExchangeCopyWithImpl<$Res> implements $ExchangeCopyWith<$Res> { + _$ExchangeCopyWithImpl(this._value, this._then); + + final Exchange _value; + // ignore: unused_field + final $Res Function(Exchange) _then; + + @override + $Res call({ + Object? id = freezed, + Object? symbol = freezed, + Object? name = freezed, + Object? route = freezed, + Object? active = freezed, + }) { + return _then(_value.copyWith( + id: id == freezed + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int, + symbol: symbol == freezed + ? _value.symbol + : symbol // ignore: cast_nullable_to_non_nullable + as String, + name: name == freezed + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + route: route == freezed + ? _value.route + : route // ignore: cast_nullable_to_non_nullable + as String, + active: active == freezed + ? _value.active + : active // ignore: cast_nullable_to_non_nullable + as bool, + )); + } +} + +/// @nodoc +abstract class _$ExchangeCopyWith<$Res> implements $ExchangeCopyWith<$Res> { + factory _$ExchangeCopyWith(_Exchange value, $Res Function(_Exchange) then) = + __$ExchangeCopyWithImpl<$Res>; + @override + $Res call({int id, String symbol, String name, String route, bool active}); +} + +/// @nodoc +class __$ExchangeCopyWithImpl<$Res> extends _$ExchangeCopyWithImpl<$Res> + implements _$ExchangeCopyWith<$Res> { + __$ExchangeCopyWithImpl(_Exchange _value, $Res Function(_Exchange) _then) + : super(_value, (v) => _then(v as _Exchange)); + + @override + _Exchange get _value => super._value as _Exchange; + + @override + $Res call({ + Object? id = freezed, + Object? symbol = freezed, + Object? name = freezed, + Object? route = freezed, + Object? active = freezed, + }) { + return _then(_Exchange( + id: id == freezed + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int, + symbol: symbol == freezed + ? _value.symbol + : symbol // ignore: cast_nullable_to_non_nullable + as String, + name: name == freezed + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + route: route == freezed + ? _value.route + : route // ignore: cast_nullable_to_non_nullable + as String, + active: active == freezed + ? _value.active + : active // ignore: cast_nullable_to_non_nullable + as bool, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$_Exchange implements _Exchange { + const _$_Exchange( + {required this.id, + required this.symbol, + required this.name, + required this.route, + required this.active}); + + factory _$_Exchange.fromJson(Map json) => + _$_$_ExchangeFromJson(json); + + @override + final int id; + @override + final String symbol; + @override + final String name; + @override + final String route; + @override + final bool active; + + @override + String toString() { + return 'Exchange(id: $id, symbol: $symbol, name: $name, route: $route, active: $active)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other is _Exchange && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id)) && + (identical(other.symbol, symbol) || + const DeepCollectionEquality().equals(other.symbol, symbol)) && + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.route, route) || + const DeepCollectionEquality().equals(other.route, route)) && + (identical(other.active, active) || + const DeepCollectionEquality().equals(other.active, active))); + } + + @override + int get hashCode => + runtimeType.hashCode ^ + const DeepCollectionEquality().hash(id) ^ + const DeepCollectionEquality().hash(symbol) ^ + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(route) ^ + const DeepCollectionEquality().hash(active); + + @JsonKey(ignore: true) + @override + _$ExchangeCopyWith<_Exchange> get copyWith => + __$ExchangeCopyWithImpl<_Exchange>(this, _$identity); + + @override + Map toJson() { + return _$_$_ExchangeToJson(this); + } +} + +abstract class _Exchange implements Exchange { + const factory _Exchange( + {required int id, + required String symbol, + required String name, + required String route, + required bool active}) = _$_Exchange; + + factory _Exchange.fromJson(Map json) = _$_Exchange.fromJson; + + @override + int get id => throw _privateConstructorUsedError; + @override + String get symbol => throw _privateConstructorUsedError; + @override + String get name => throw _privateConstructorUsedError; + @override + String get route => throw _privateConstructorUsedError; + @override + bool get active => throw _privateConstructorUsedError; + @override + @JsonKey(ignore: true) + _$ExchangeCopyWith<_Exchange> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/models/exchanges/exchange/exchange.g.dart b/lib/models/exchanges/exchange/exchange.g.dart new file mode 100644 index 0000000..79ed7f8 --- /dev/null +++ b/lib/models/exchanges/exchange/exchange.g.dart @@ -0,0 +1,26 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'exchange.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$_Exchange _$_$_ExchangeFromJson(Map json) { + return _$_Exchange( + id: json['id'] as int, + symbol: json['symbol'] as String, + name: json['name'] as String, + route: json['route'] as String, + active: json['active'] as bool, + ); +} + +Map _$_$_ExchangeToJson(_$_Exchange instance) => + { + 'id': instance.id, + 'symbol': instance.symbol, + 'name': instance.name, + 'route': instance.route, + 'active': instance.active, + }; diff --git a/lib/models/exchanges/exchanges_response/exchanges_response.dart b/lib/models/exchanges/exchanges_response/exchanges_response.dart new file mode 100644 index 0000000..3a1b7d2 --- /dev/null +++ b/lib/models/exchanges/exchanges_response/exchanges_response.dart @@ -0,0 +1,14 @@ +import 'package:cryptocurrency_app/models/exchanges/exchange/exchange.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'exchanges_response.freezed.dart'; +part 'exchanges_response.g.dart'; + +@freezed +abstract class ExchangesResponse with _$ExchangesResponse { + const factory ExchangesResponse({required List result}) = + _ExchangesResponse; + + factory ExchangesResponse.fromJson(Map json) => + _$ExchangesResponseFromJson(json); +} diff --git a/lib/models/exchanges/exchanges_response/exchanges_response.freezed.dart b/lib/models/exchanges/exchanges_response/exchanges_response.freezed.dart new file mode 100644 index 0000000..a0a717d --- /dev/null +++ b/lib/models/exchanges/exchanges_response/exchanges_response.freezed.dart @@ -0,0 +1,163 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides + +part of 'exchanges_response.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +ExchangesResponse _$ExchangesResponseFromJson(Map json) { + return _ExchangesResponse.fromJson(json); +} + +/// @nodoc +class _$ExchangesResponseTearOff { + const _$ExchangesResponseTearOff(); + + _ExchangesResponse call({required List result}) { + return _ExchangesResponse( + result: result, + ); + } + + ExchangesResponse fromJson(Map json) { + return ExchangesResponse.fromJson(json); + } +} + +/// @nodoc +const $ExchangesResponse = _$ExchangesResponseTearOff(); + +/// @nodoc +mixin _$ExchangesResponse { + List get result => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $ExchangesResponseCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ExchangesResponseCopyWith<$Res> { + factory $ExchangesResponseCopyWith( + ExchangesResponse value, $Res Function(ExchangesResponse) then) = + _$ExchangesResponseCopyWithImpl<$Res>; + $Res call({List result}); +} + +/// @nodoc +class _$ExchangesResponseCopyWithImpl<$Res> + implements $ExchangesResponseCopyWith<$Res> { + _$ExchangesResponseCopyWithImpl(this._value, this._then); + + final ExchangesResponse _value; + // ignore: unused_field + final $Res Function(ExchangesResponse) _then; + + @override + $Res call({ + Object? result = freezed, + }) { + return _then(_value.copyWith( + result: result == freezed + ? _value.result + : result // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc +abstract class _$ExchangesResponseCopyWith<$Res> + implements $ExchangesResponseCopyWith<$Res> { + factory _$ExchangesResponseCopyWith( + _ExchangesResponse value, $Res Function(_ExchangesResponse) then) = + __$ExchangesResponseCopyWithImpl<$Res>; + @override + $Res call({List result}); +} + +/// @nodoc +class __$ExchangesResponseCopyWithImpl<$Res> + extends _$ExchangesResponseCopyWithImpl<$Res> + implements _$ExchangesResponseCopyWith<$Res> { + __$ExchangesResponseCopyWithImpl( + _ExchangesResponse _value, $Res Function(_ExchangesResponse) _then) + : super(_value, (v) => _then(v as _ExchangesResponse)); + + @override + _ExchangesResponse get _value => super._value as _ExchangesResponse; + + @override + $Res call({ + Object? result = freezed, + }) { + return _then(_ExchangesResponse( + result: result == freezed + ? _value.result + : result // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$_ExchangesResponse implements _ExchangesResponse { + const _$_ExchangesResponse({required this.result}); + + factory _$_ExchangesResponse.fromJson(Map json) => + _$_$_ExchangesResponseFromJson(json); + + @override + final List result; + + @override + String toString() { + return 'ExchangesResponse(result: $result)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other is _ExchangesResponse && + (identical(other.result, result) || + const DeepCollectionEquality().equals(other.result, result))); + } + + @override + int get hashCode => + runtimeType.hashCode ^ const DeepCollectionEquality().hash(result); + + @JsonKey(ignore: true) + @override + _$ExchangesResponseCopyWith<_ExchangesResponse> get copyWith => + __$ExchangesResponseCopyWithImpl<_ExchangesResponse>(this, _$identity); + + @override + Map toJson() { + return _$_$_ExchangesResponseToJson(this); + } +} + +abstract class _ExchangesResponse implements ExchangesResponse { + const factory _ExchangesResponse({required List result}) = + _$_ExchangesResponse; + + factory _ExchangesResponse.fromJson(Map json) = + _$_ExchangesResponse.fromJson; + + @override + List get result => throw _privateConstructorUsedError; + @override + @JsonKey(ignore: true) + _$ExchangesResponseCopyWith<_ExchangesResponse> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/models/exchanges/exchanges_response/exchanges_response.g.dart b/lib/models/exchanges/exchanges_response/exchanges_response.g.dart new file mode 100644 index 0000000..a27bdb3 --- /dev/null +++ b/lib/models/exchanges/exchanges_response/exchanges_response.g.dart @@ -0,0 +1,21 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'exchanges_response.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$_ExchangesResponse _$_$_ExchangesResponseFromJson(Map json) { + return _$_ExchangesResponse( + result: (json['result'] as List) + .map((e) => Exchange.fromJson(e as Map)) + .toList(), + ); +} + +Map _$_$_ExchangesResponseToJson( + _$_ExchangesResponse instance) => + { + 'result': instance.result, + }; diff --git a/lib/models/graph/graph/graph.dart b/lib/models/graph/graph/graph.dart new file mode 100644 index 0000000..73f2595 --- /dev/null +++ b/lib/models/graph/graph/graph.dart @@ -0,0 +1,18 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +import '../pair_graph/pair_graph.dart'; + +part 'graph.freezed.dart'; + +@freezed +abstract class Graph with _$Graph { + const factory Graph({required List pairs}) = _Graph; + + factory Graph.fromJson(dynamic json) { + List pairs = []; + json.forEach((k, v) { + pairs.add(PairGraph.fromJson(v, k)); + }); + return Graph(pairs: pairs); + } +} diff --git a/lib/models/graph/graph/graph.freezed.dart b/lib/models/graph/graph/graph.freezed.dart new file mode 100644 index 0000000..096307e --- /dev/null +++ b/lib/models/graph/graph/graph.freezed.dart @@ -0,0 +1,134 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides + +part of 'graph.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +/// @nodoc +class _$GraphTearOff { + const _$GraphTearOff(); + + _Graph call({required List pairs}) { + return _Graph( + pairs: pairs, + ); + } +} + +/// @nodoc +const $Graph = _$GraphTearOff(); + +/// @nodoc +mixin _$Graph { + List get pairs => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $GraphCopyWith get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $GraphCopyWith<$Res> { + factory $GraphCopyWith(Graph value, $Res Function(Graph) then) = + _$GraphCopyWithImpl<$Res>; + $Res call({List pairs}); +} + +/// @nodoc +class _$GraphCopyWithImpl<$Res> implements $GraphCopyWith<$Res> { + _$GraphCopyWithImpl(this._value, this._then); + + final Graph _value; + // ignore: unused_field + final $Res Function(Graph) _then; + + @override + $Res call({ + Object? pairs = freezed, + }) { + return _then(_value.copyWith( + pairs: pairs == freezed + ? _value.pairs + : pairs // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc +abstract class _$GraphCopyWith<$Res> implements $GraphCopyWith<$Res> { + factory _$GraphCopyWith(_Graph value, $Res Function(_Graph) then) = + __$GraphCopyWithImpl<$Res>; + @override + $Res call({List pairs}); +} + +/// @nodoc +class __$GraphCopyWithImpl<$Res> extends _$GraphCopyWithImpl<$Res> + implements _$GraphCopyWith<$Res> { + __$GraphCopyWithImpl(_Graph _value, $Res Function(_Graph) _then) + : super(_value, (v) => _then(v as _Graph)); + + @override + _Graph get _value => super._value as _Graph; + + @override + $Res call({ + Object? pairs = freezed, + }) { + return _then(_Graph( + pairs: pairs == freezed + ? _value.pairs + : pairs // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc + +class _$_Graph implements _Graph { + const _$_Graph({required this.pairs}); + + @override + final List pairs; + + @override + String toString() { + return 'Graph(pairs: $pairs)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other is _Graph && + (identical(other.pairs, pairs) || + const DeepCollectionEquality().equals(other.pairs, pairs))); + } + + @override + int get hashCode => + runtimeType.hashCode ^ const DeepCollectionEquality().hash(pairs); + + @JsonKey(ignore: true) + @override + _$GraphCopyWith<_Graph> get copyWith => + __$GraphCopyWithImpl<_Graph>(this, _$identity); +} + +abstract class _Graph implements Graph { + const factory _Graph({required List pairs}) = _$_Graph; + + @override + List get pairs => throw _privateConstructorUsedError; + @override + @JsonKey(ignore: true) + _$GraphCopyWith<_Graph> get copyWith => throw _privateConstructorUsedError; +} diff --git a/lib/models/graph/graph_response/graph_response.dart b/lib/models/graph/graph_response/graph_response.dart new file mode 100644 index 0000000..24127bc --- /dev/null +++ b/lib/models/graph/graph_response/graph_response.dart @@ -0,0 +1,17 @@ +import 'package:cryptocurrency_app/models/allowance/allowance.dart'; +import 'package:cryptocurrency_app/models/graph/graph/graph.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'graph_response.freezed.dart'; + +@freezed +abstract class GraphResponse with _$GraphResponse { + const factory GraphResponse( + {required Graph result, required Allowance allowance}) = _GraphResponse; + + factory GraphResponse.fromJson(Map json) { + final result = Graph.fromJson(json['result']); + final allowance = Allowance.fromJson(json['allowance']); + return GraphResponse(result: result, allowance: allowance); + } +} diff --git a/lib/models/graph/graph_response/graph_response.freezed.dart b/lib/models/graph/graph_response/graph_response.freezed.dart new file mode 100644 index 0000000..5464d15 --- /dev/null +++ b/lib/models/graph/graph_response/graph_response.freezed.dart @@ -0,0 +1,186 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides + +part of 'graph_response.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +/// @nodoc +class _$GraphResponseTearOff { + const _$GraphResponseTearOff(); + + _GraphResponse call({required Graph result, required Allowance allowance}) { + return _GraphResponse( + result: result, + allowance: allowance, + ); + } +} + +/// @nodoc +const $GraphResponse = _$GraphResponseTearOff(); + +/// @nodoc +mixin _$GraphResponse { + Graph get result => throw _privateConstructorUsedError; + Allowance get allowance => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $GraphResponseCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $GraphResponseCopyWith<$Res> { + factory $GraphResponseCopyWith( + GraphResponse value, $Res Function(GraphResponse) then) = + _$GraphResponseCopyWithImpl<$Res>; + $Res call({Graph result, Allowance allowance}); + + $GraphCopyWith<$Res> get result; + $AllowanceCopyWith<$Res> get allowance; +} + +/// @nodoc +class _$GraphResponseCopyWithImpl<$Res> + implements $GraphResponseCopyWith<$Res> { + _$GraphResponseCopyWithImpl(this._value, this._then); + + final GraphResponse _value; + // ignore: unused_field + final $Res Function(GraphResponse) _then; + + @override + $Res call({ + Object? result = freezed, + Object? allowance = freezed, + }) { + return _then(_value.copyWith( + result: result == freezed + ? _value.result + : result // ignore: cast_nullable_to_non_nullable + as Graph, + allowance: allowance == freezed + ? _value.allowance + : allowance // ignore: cast_nullable_to_non_nullable + as Allowance, + )); + } + + @override + $GraphCopyWith<$Res> get result { + return $GraphCopyWith<$Res>(_value.result, (value) { + return _then(_value.copyWith(result: value)); + }); + } + + @override + $AllowanceCopyWith<$Res> get allowance { + return $AllowanceCopyWith<$Res>(_value.allowance, (value) { + return _then(_value.copyWith(allowance: value)); + }); + } +} + +/// @nodoc +abstract class _$GraphResponseCopyWith<$Res> + implements $GraphResponseCopyWith<$Res> { + factory _$GraphResponseCopyWith( + _GraphResponse value, $Res Function(_GraphResponse) then) = + __$GraphResponseCopyWithImpl<$Res>; + @override + $Res call({Graph result, Allowance allowance}); + + @override + $GraphCopyWith<$Res> get result; + @override + $AllowanceCopyWith<$Res> get allowance; +} + +/// @nodoc +class __$GraphResponseCopyWithImpl<$Res> + extends _$GraphResponseCopyWithImpl<$Res> + implements _$GraphResponseCopyWith<$Res> { + __$GraphResponseCopyWithImpl( + _GraphResponse _value, $Res Function(_GraphResponse) _then) + : super(_value, (v) => _then(v as _GraphResponse)); + + @override + _GraphResponse get _value => super._value as _GraphResponse; + + @override + $Res call({ + Object? result = freezed, + Object? allowance = freezed, + }) { + return _then(_GraphResponse( + result: result == freezed + ? _value.result + : result // ignore: cast_nullable_to_non_nullable + as Graph, + allowance: allowance == freezed + ? _value.allowance + : allowance // ignore: cast_nullable_to_non_nullable + as Allowance, + )); + } +} + +/// @nodoc + +class _$_GraphResponse implements _GraphResponse { + const _$_GraphResponse({required this.result, required this.allowance}); + + @override + final Graph result; + @override + final Allowance allowance; + + @override + String toString() { + return 'GraphResponse(result: $result, allowance: $allowance)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other is _GraphResponse && + (identical(other.result, result) || + const DeepCollectionEquality().equals(other.result, result)) && + (identical(other.allowance, allowance) || + const DeepCollectionEquality() + .equals(other.allowance, allowance))); + } + + @override + int get hashCode => + runtimeType.hashCode ^ + const DeepCollectionEquality().hash(result) ^ + const DeepCollectionEquality().hash(allowance); + + @JsonKey(ignore: true) + @override + _$GraphResponseCopyWith<_GraphResponse> get copyWith => + __$GraphResponseCopyWithImpl<_GraphResponse>(this, _$identity); +} + +abstract class _GraphResponse implements GraphResponse { + const factory _GraphResponse( + {required Graph result, required Allowance allowance}) = _$_GraphResponse; + + @override + Graph get result => throw _privateConstructorUsedError; + @override + Allowance get allowance => throw _privateConstructorUsedError; + @override + @JsonKey(ignore: true) + _$GraphResponseCopyWith<_GraphResponse> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/models/graph/pair_graph/pair_graph.dart b/lib/models/graph/pair_graph/pair_graph.dart new file mode 100644 index 0000000..8cf35df --- /dev/null +++ b/lib/models/graph/pair_graph/pair_graph.dart @@ -0,0 +1,19 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +import '../points/points.dart'; + +part 'pair_graph.freezed.dart'; + +@freezed +abstract class PairGraph with _$PairGraph { + const factory PairGraph( + {required String period, required List points}) = _PairGraph; + + factory PairGraph.fromJson(dynamic json, String period) { + List points = []; + json.forEach((v) { + points.add(Points.fromJson(v)); + }); + return PairGraph(period: period, points: points); + } +} diff --git a/lib/models/graph/pair_graph/pair_graph.freezed.dart b/lib/models/graph/pair_graph/pair_graph.freezed.dart new file mode 100644 index 0000000..5685666 --- /dev/null +++ b/lib/models/graph/pair_graph/pair_graph.freezed.dart @@ -0,0 +1,158 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides + +part of 'pair_graph.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +/// @nodoc +class _$PairGraphTearOff { + const _$PairGraphTearOff(); + + _PairGraph call({required String period, required List points}) { + return _PairGraph( + period: period, + points: points, + ); + } +} + +/// @nodoc +const $PairGraph = _$PairGraphTearOff(); + +/// @nodoc +mixin _$PairGraph { + String get period => throw _privateConstructorUsedError; + List get points => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $PairGraphCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $PairGraphCopyWith<$Res> { + factory $PairGraphCopyWith(PairGraph value, $Res Function(PairGraph) then) = + _$PairGraphCopyWithImpl<$Res>; + $Res call({String period, List points}); +} + +/// @nodoc +class _$PairGraphCopyWithImpl<$Res> implements $PairGraphCopyWith<$Res> { + _$PairGraphCopyWithImpl(this._value, this._then); + + final PairGraph _value; + // ignore: unused_field + final $Res Function(PairGraph) _then; + + @override + $Res call({ + Object? period = freezed, + Object? points = freezed, + }) { + return _then(_value.copyWith( + period: period == freezed + ? _value.period + : period // ignore: cast_nullable_to_non_nullable + as String, + points: points == freezed + ? _value.points + : points // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc +abstract class _$PairGraphCopyWith<$Res> implements $PairGraphCopyWith<$Res> { + factory _$PairGraphCopyWith( + _PairGraph value, $Res Function(_PairGraph) then) = + __$PairGraphCopyWithImpl<$Res>; + @override + $Res call({String period, List points}); +} + +/// @nodoc +class __$PairGraphCopyWithImpl<$Res> extends _$PairGraphCopyWithImpl<$Res> + implements _$PairGraphCopyWith<$Res> { + __$PairGraphCopyWithImpl(_PairGraph _value, $Res Function(_PairGraph) _then) + : super(_value, (v) => _then(v as _PairGraph)); + + @override + _PairGraph get _value => super._value as _PairGraph; + + @override + $Res call({ + Object? period = freezed, + Object? points = freezed, + }) { + return _then(_PairGraph( + period: period == freezed + ? _value.period + : period // ignore: cast_nullable_to_non_nullable + as String, + points: points == freezed + ? _value.points + : points // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc + +class _$_PairGraph implements _PairGraph { + const _$_PairGraph({required this.period, required this.points}); + + @override + final String period; + @override + final List points; + + @override + String toString() { + return 'PairGraph(period: $period, points: $points)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other is _PairGraph && + (identical(other.period, period) || + const DeepCollectionEquality().equals(other.period, period)) && + (identical(other.points, points) || + const DeepCollectionEquality().equals(other.points, points))); + } + + @override + int get hashCode => + runtimeType.hashCode ^ + const DeepCollectionEquality().hash(period) ^ + const DeepCollectionEquality().hash(points); + + @JsonKey(ignore: true) + @override + _$PairGraphCopyWith<_PairGraph> get copyWith => + __$PairGraphCopyWithImpl<_PairGraph>(this, _$identity); +} + +abstract class _PairGraph implements PairGraph { + const factory _PairGraph( + {required String period, required List points}) = _$_PairGraph; + + @override + String get period => throw _privateConstructorUsedError; + @override + List get points => throw _privateConstructorUsedError; + @override + @JsonKey(ignore: true) + _$PairGraphCopyWith<_PairGraph> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/models/graph/points/points.dart b/lib/models/graph/points/points.dart new file mode 100644 index 0000000..1758e2b --- /dev/null +++ b/lib/models/graph/points/points.dart @@ -0,0 +1,27 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'points.freezed.dart'; + +@freezed +abstract class Points with _$Points { + const factory Points( + {required double closeTime, + required double openTime, + required double highPrice, + required double lowPrice, + required double closePrice, + required double volume, + required double quoteVolume}) = _Points; + + factory Points.fromJson(dynamic json) { + return _Points( + closeTime: json[0].toDouble(), + openTime: json[1].toDouble(), + highPrice: json[2].toDouble(), + lowPrice: json[3].toDouble(), + closePrice: json[4].toDouble(), + volume: json[5].toDouble(), + quoteVolume: json[6].toDouble(), + ); + } +} diff --git a/lib/models/graph/points/points.freezed.dart b/lib/models/graph/points/points.freezed.dart new file mode 100644 index 0000000..80ae281 --- /dev/null +++ b/lib/models/graph/points/points.freezed.dart @@ -0,0 +1,290 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides + +part of 'points.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +/// @nodoc +class _$PointsTearOff { + const _$PointsTearOff(); + + _Points call( + {required double closeTime, + required double openTime, + required double highPrice, + required double lowPrice, + required double closePrice, + required double volume, + required double quoteVolume}) { + return _Points( + closeTime: closeTime, + openTime: openTime, + highPrice: highPrice, + lowPrice: lowPrice, + closePrice: closePrice, + volume: volume, + quoteVolume: quoteVolume, + ); + } +} + +/// @nodoc +const $Points = _$PointsTearOff(); + +/// @nodoc +mixin _$Points { + double get closeTime => throw _privateConstructorUsedError; + double get openTime => throw _privateConstructorUsedError; + double get highPrice => throw _privateConstructorUsedError; + double get lowPrice => throw _privateConstructorUsedError; + double get closePrice => throw _privateConstructorUsedError; + double get volume => throw _privateConstructorUsedError; + double get quoteVolume => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $PointsCopyWith get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $PointsCopyWith<$Res> { + factory $PointsCopyWith(Points value, $Res Function(Points) then) = + _$PointsCopyWithImpl<$Res>; + $Res call( + {double closeTime, + double openTime, + double highPrice, + double lowPrice, + double closePrice, + double volume, + double quoteVolume}); +} + +/// @nodoc +class _$PointsCopyWithImpl<$Res> implements $PointsCopyWith<$Res> { + _$PointsCopyWithImpl(this._value, this._then); + + final Points _value; + // ignore: unused_field + final $Res Function(Points) _then; + + @override + $Res call({ + Object? closeTime = freezed, + Object? openTime = freezed, + Object? highPrice = freezed, + Object? lowPrice = freezed, + Object? closePrice = freezed, + Object? volume = freezed, + Object? quoteVolume = freezed, + }) { + return _then(_value.copyWith( + closeTime: closeTime == freezed + ? _value.closeTime + : closeTime // ignore: cast_nullable_to_non_nullable + as double, + openTime: openTime == freezed + ? _value.openTime + : openTime // ignore: cast_nullable_to_non_nullable + as double, + highPrice: highPrice == freezed + ? _value.highPrice + : highPrice // ignore: cast_nullable_to_non_nullable + as double, + lowPrice: lowPrice == freezed + ? _value.lowPrice + : lowPrice // ignore: cast_nullable_to_non_nullable + as double, + closePrice: closePrice == freezed + ? _value.closePrice + : closePrice // ignore: cast_nullable_to_non_nullable + as double, + volume: volume == freezed + ? _value.volume + : volume // ignore: cast_nullable_to_non_nullable + as double, + quoteVolume: quoteVolume == freezed + ? _value.quoteVolume + : quoteVolume // ignore: cast_nullable_to_non_nullable + as double, + )); + } +} + +/// @nodoc +abstract class _$PointsCopyWith<$Res> implements $PointsCopyWith<$Res> { + factory _$PointsCopyWith(_Points value, $Res Function(_Points) then) = + __$PointsCopyWithImpl<$Res>; + @override + $Res call( + {double closeTime, + double openTime, + double highPrice, + double lowPrice, + double closePrice, + double volume, + double quoteVolume}); +} + +/// @nodoc +class __$PointsCopyWithImpl<$Res> extends _$PointsCopyWithImpl<$Res> + implements _$PointsCopyWith<$Res> { + __$PointsCopyWithImpl(_Points _value, $Res Function(_Points) _then) + : super(_value, (v) => _then(v as _Points)); + + @override + _Points get _value => super._value as _Points; + + @override + $Res call({ + Object? closeTime = freezed, + Object? openTime = freezed, + Object? highPrice = freezed, + Object? lowPrice = freezed, + Object? closePrice = freezed, + Object? volume = freezed, + Object? quoteVolume = freezed, + }) { + return _then(_Points( + closeTime: closeTime == freezed + ? _value.closeTime + : closeTime // ignore: cast_nullable_to_non_nullable + as double, + openTime: openTime == freezed + ? _value.openTime + : openTime // ignore: cast_nullable_to_non_nullable + as double, + highPrice: highPrice == freezed + ? _value.highPrice + : highPrice // ignore: cast_nullable_to_non_nullable + as double, + lowPrice: lowPrice == freezed + ? _value.lowPrice + : lowPrice // ignore: cast_nullable_to_non_nullable + as double, + closePrice: closePrice == freezed + ? _value.closePrice + : closePrice // ignore: cast_nullable_to_non_nullable + as double, + volume: volume == freezed + ? _value.volume + : volume // ignore: cast_nullable_to_non_nullable + as double, + quoteVolume: quoteVolume == freezed + ? _value.quoteVolume + : quoteVolume // ignore: cast_nullable_to_non_nullable + as double, + )); + } +} + +/// @nodoc + +class _$_Points implements _Points { + const _$_Points( + {required this.closeTime, + required this.openTime, + required this.highPrice, + required this.lowPrice, + required this.closePrice, + required this.volume, + required this.quoteVolume}); + + @override + final double closeTime; + @override + final double openTime; + @override + final double highPrice; + @override + final double lowPrice; + @override + final double closePrice; + @override + final double volume; + @override + final double quoteVolume; + + @override + String toString() { + return 'Points(closeTime: $closeTime, openTime: $openTime, highPrice: $highPrice, lowPrice: $lowPrice, closePrice: $closePrice, volume: $volume, quoteVolume: $quoteVolume)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other is _Points && + (identical(other.closeTime, closeTime) || + const DeepCollectionEquality() + .equals(other.closeTime, closeTime)) && + (identical(other.openTime, openTime) || + const DeepCollectionEquality() + .equals(other.openTime, openTime)) && + (identical(other.highPrice, highPrice) || + const DeepCollectionEquality() + .equals(other.highPrice, highPrice)) && + (identical(other.lowPrice, lowPrice) || + const DeepCollectionEquality() + .equals(other.lowPrice, lowPrice)) && + (identical(other.closePrice, closePrice) || + const DeepCollectionEquality() + .equals(other.closePrice, closePrice)) && + (identical(other.volume, volume) || + const DeepCollectionEquality().equals(other.volume, volume)) && + (identical(other.quoteVolume, quoteVolume) || + const DeepCollectionEquality() + .equals(other.quoteVolume, quoteVolume))); + } + + @override + int get hashCode => + runtimeType.hashCode ^ + const DeepCollectionEquality().hash(closeTime) ^ + const DeepCollectionEquality().hash(openTime) ^ + const DeepCollectionEquality().hash(highPrice) ^ + const DeepCollectionEquality().hash(lowPrice) ^ + const DeepCollectionEquality().hash(closePrice) ^ + const DeepCollectionEquality().hash(volume) ^ + const DeepCollectionEquality().hash(quoteVolume); + + @JsonKey(ignore: true) + @override + _$PointsCopyWith<_Points> get copyWith => + __$PointsCopyWithImpl<_Points>(this, _$identity); +} + +abstract class _Points implements Points { + const factory _Points( + {required double closeTime, + required double openTime, + required double highPrice, + required double lowPrice, + required double closePrice, + required double volume, + required double quoteVolume}) = _$_Points; + + @override + double get closeTime => throw _privateConstructorUsedError; + @override + double get openTime => throw _privateConstructorUsedError; + @override + double get highPrice => throw _privateConstructorUsedError; + @override + double get lowPrice => throw _privateConstructorUsedError; + @override + double get closePrice => throw _privateConstructorUsedError; + @override + double get volume => throw _privateConstructorUsedError; + @override + double get quoteVolume => throw _privateConstructorUsedError; + @override + @JsonKey(ignore: true) + _$PointsCopyWith<_Points> get copyWith => throw _privateConstructorUsedError; +} diff --git a/lib/models/markets/favorite_pair/favorite_pair.dart b/lib/models/markets/favorite_pair/favorite_pair.dart new file mode 100644 index 0000000..22430c7 --- /dev/null +++ b/lib/models/markets/favorite_pair/favorite_pair.dart @@ -0,0 +1,14 @@ +import 'package:cryptocurrency_app/models/markets/pair/pair.dart'; +import 'package:cryptocurrency_app/models/pair/pair_summary/pair_summary.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +part 'favorite_pair.freezed.dart'; +part 'favorite_pair.g.dart'; + +@freezed +abstract class FavoritePair with _$FavoritePair { + const factory FavoritePair( + {required Pair pair, required PairSummary pairSummary}) = _FavoritePair; + + factory FavoritePair.fromJson(Map json) => + _$FavoritePairFromJson(json); +} diff --git a/lib/models/markets/favorite_pair/favorite_pair.freezed.dart b/lib/models/markets/favorite_pair/favorite_pair.freezed.dart new file mode 100644 index 0000000..fb6cf8b --- /dev/null +++ b/lib/models/markets/favorite_pair/favorite_pair.freezed.dart @@ -0,0 +1,204 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides + +part of 'favorite_pair.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +FavoritePair _$FavoritePairFromJson(Map json) { + return _FavoritePair.fromJson(json); +} + +/// @nodoc +class _$FavoritePairTearOff { + const _$FavoritePairTearOff(); + + _FavoritePair call({required Pair pair, required PairSummary pairSummary}) { + return _FavoritePair( + pair: pair, + pairSummary: pairSummary, + ); + } + + FavoritePair fromJson(Map json) { + return FavoritePair.fromJson(json); + } +} + +/// @nodoc +const $FavoritePair = _$FavoritePairTearOff(); + +/// @nodoc +mixin _$FavoritePair { + Pair get pair => throw _privateConstructorUsedError; + PairSummary get pairSummary => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $FavoritePairCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $FavoritePairCopyWith<$Res> { + factory $FavoritePairCopyWith( + FavoritePair value, $Res Function(FavoritePair) then) = + _$FavoritePairCopyWithImpl<$Res>; + $Res call({Pair pair, PairSummary pairSummary}); + + $PairCopyWith<$Res> get pair; + $PairSummaryCopyWith<$Res> get pairSummary; +} + +/// @nodoc +class _$FavoritePairCopyWithImpl<$Res> implements $FavoritePairCopyWith<$Res> { + _$FavoritePairCopyWithImpl(this._value, this._then); + + final FavoritePair _value; + // ignore: unused_field + final $Res Function(FavoritePair) _then; + + @override + $Res call({ + Object? pair = freezed, + Object? pairSummary = freezed, + }) { + return _then(_value.copyWith( + pair: pair == freezed + ? _value.pair + : pair // ignore: cast_nullable_to_non_nullable + as Pair, + pairSummary: pairSummary == freezed + ? _value.pairSummary + : pairSummary // ignore: cast_nullable_to_non_nullable + as PairSummary, + )); + } + + @override + $PairCopyWith<$Res> get pair { + return $PairCopyWith<$Res>(_value.pair, (value) { + return _then(_value.copyWith(pair: value)); + }); + } + + @override + $PairSummaryCopyWith<$Res> get pairSummary { + return $PairSummaryCopyWith<$Res>(_value.pairSummary, (value) { + return _then(_value.copyWith(pairSummary: value)); + }); + } +} + +/// @nodoc +abstract class _$FavoritePairCopyWith<$Res> + implements $FavoritePairCopyWith<$Res> { + factory _$FavoritePairCopyWith( + _FavoritePair value, $Res Function(_FavoritePair) then) = + __$FavoritePairCopyWithImpl<$Res>; + @override + $Res call({Pair pair, PairSummary pairSummary}); + + @override + $PairCopyWith<$Res> get pair; + @override + $PairSummaryCopyWith<$Res> get pairSummary; +} + +/// @nodoc +class __$FavoritePairCopyWithImpl<$Res> extends _$FavoritePairCopyWithImpl<$Res> + implements _$FavoritePairCopyWith<$Res> { + __$FavoritePairCopyWithImpl( + _FavoritePair _value, $Res Function(_FavoritePair) _then) + : super(_value, (v) => _then(v as _FavoritePair)); + + @override + _FavoritePair get _value => super._value as _FavoritePair; + + @override + $Res call({ + Object? pair = freezed, + Object? pairSummary = freezed, + }) { + return _then(_FavoritePair( + pair: pair == freezed + ? _value.pair + : pair // ignore: cast_nullable_to_non_nullable + as Pair, + pairSummary: pairSummary == freezed + ? _value.pairSummary + : pairSummary // ignore: cast_nullable_to_non_nullable + as PairSummary, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$_FavoritePair implements _FavoritePair { + const _$_FavoritePair({required this.pair, required this.pairSummary}); + + factory _$_FavoritePair.fromJson(Map json) => + _$_$_FavoritePairFromJson(json); + + @override + final Pair pair; + @override + final PairSummary pairSummary; + + @override + String toString() { + return 'FavoritePair(pair: $pair, pairSummary: $pairSummary)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other is _FavoritePair && + (identical(other.pair, pair) || + const DeepCollectionEquality().equals(other.pair, pair)) && + (identical(other.pairSummary, pairSummary) || + const DeepCollectionEquality() + .equals(other.pairSummary, pairSummary))); + } + + @override + int get hashCode => + runtimeType.hashCode ^ + const DeepCollectionEquality().hash(pair) ^ + const DeepCollectionEquality().hash(pairSummary); + + @JsonKey(ignore: true) + @override + _$FavoritePairCopyWith<_FavoritePair> get copyWith => + __$FavoritePairCopyWithImpl<_FavoritePair>(this, _$identity); + + @override + Map toJson() { + return _$_$_FavoritePairToJson(this); + } +} + +abstract class _FavoritePair implements FavoritePair { + const factory _FavoritePair( + {required Pair pair, required PairSummary pairSummary}) = _$_FavoritePair; + + factory _FavoritePair.fromJson(Map json) = + _$_FavoritePair.fromJson; + + @override + Pair get pair => throw _privateConstructorUsedError; + @override + PairSummary get pairSummary => throw _privateConstructorUsedError; + @override + @JsonKey(ignore: true) + _$FavoritePairCopyWith<_FavoritePair> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/models/markets/favorite_pair/favorite_pair.g.dart b/lib/models/markets/favorite_pair/favorite_pair.g.dart new file mode 100644 index 0000000..b09078f --- /dev/null +++ b/lib/models/markets/favorite_pair/favorite_pair.g.dart @@ -0,0 +1,21 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'favorite_pair.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$_FavoritePair _$_$_FavoritePairFromJson(Map json) { + return _$_FavoritePair( + pair: Pair.fromJson(json['pair'] as Map), + pairSummary: + PairSummary.fromJson(json['pairSummary'] as Map), + ); +} + +Map _$_$_FavoritePairToJson(_$_FavoritePair instance) => + { + 'pair': instance.pair, + 'pairSummary': instance.pairSummary, + }; diff --git a/lib/models/markets/market_response/market_response.dart b/lib/models/markets/market_response/market_response.dart new file mode 100644 index 0000000..ae089d1 --- /dev/null +++ b/lib/models/markets/market_response/market_response.dart @@ -0,0 +1,14 @@ +import 'package:cryptocurrency_app/models/allowance/allowance.dart'; +import 'package:cryptocurrency_app/models/markets/pair/pair.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +part 'market_response.g.dart'; +part 'market_response.freezed.dart'; + +@freezed +abstract class MarketResponse with _$MarketResponse { + const factory MarketResponse( + {required List result, + required Allowance allowance}) = _MarketResponse; + factory MarketResponse.fromJson(Map json) => + _$MarketResponseFromJson(json); +} diff --git a/lib/models/markets/market_response/market_response.freezed.dart b/lib/models/markets/market_response/market_response.freezed.dart new file mode 100644 index 0000000..e934fdb --- /dev/null +++ b/lib/models/markets/market_response/market_response.freezed.dart @@ -0,0 +1,198 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides + +part of 'market_response.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +MarketResponse _$MarketResponseFromJson(Map json) { + return _MarketResponse.fromJson(json); +} + +/// @nodoc +class _$MarketResponseTearOff { + const _$MarketResponseTearOff(); + + _MarketResponse call( + {required List result, required Allowance allowance}) { + return _MarketResponse( + result: result, + allowance: allowance, + ); + } + + MarketResponse fromJson(Map json) { + return MarketResponse.fromJson(json); + } +} + +/// @nodoc +const $MarketResponse = _$MarketResponseTearOff(); + +/// @nodoc +mixin _$MarketResponse { + List get result => throw _privateConstructorUsedError; + Allowance get allowance => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $MarketResponseCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $MarketResponseCopyWith<$Res> { + factory $MarketResponseCopyWith( + MarketResponse value, $Res Function(MarketResponse) then) = + _$MarketResponseCopyWithImpl<$Res>; + $Res call({List result, Allowance allowance}); + + $AllowanceCopyWith<$Res> get allowance; +} + +/// @nodoc +class _$MarketResponseCopyWithImpl<$Res> + implements $MarketResponseCopyWith<$Res> { + _$MarketResponseCopyWithImpl(this._value, this._then); + + final MarketResponse _value; + // ignore: unused_field + final $Res Function(MarketResponse) _then; + + @override + $Res call({ + Object? result = freezed, + Object? allowance = freezed, + }) { + return _then(_value.copyWith( + result: result == freezed + ? _value.result + : result // ignore: cast_nullable_to_non_nullable + as List, + allowance: allowance == freezed + ? _value.allowance + : allowance // ignore: cast_nullable_to_non_nullable + as Allowance, + )); + } + + @override + $AllowanceCopyWith<$Res> get allowance { + return $AllowanceCopyWith<$Res>(_value.allowance, (value) { + return _then(_value.copyWith(allowance: value)); + }); + } +} + +/// @nodoc +abstract class _$MarketResponseCopyWith<$Res> + implements $MarketResponseCopyWith<$Res> { + factory _$MarketResponseCopyWith( + _MarketResponse value, $Res Function(_MarketResponse) then) = + __$MarketResponseCopyWithImpl<$Res>; + @override + $Res call({List result, Allowance allowance}); + + @override + $AllowanceCopyWith<$Res> get allowance; +} + +/// @nodoc +class __$MarketResponseCopyWithImpl<$Res> + extends _$MarketResponseCopyWithImpl<$Res> + implements _$MarketResponseCopyWith<$Res> { + __$MarketResponseCopyWithImpl( + _MarketResponse _value, $Res Function(_MarketResponse) _then) + : super(_value, (v) => _then(v as _MarketResponse)); + + @override + _MarketResponse get _value => super._value as _MarketResponse; + + @override + $Res call({ + Object? result = freezed, + Object? allowance = freezed, + }) { + return _then(_MarketResponse( + result: result == freezed + ? _value.result + : result // ignore: cast_nullable_to_non_nullable + as List, + allowance: allowance == freezed + ? _value.allowance + : allowance // ignore: cast_nullable_to_non_nullable + as Allowance, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$_MarketResponse implements _MarketResponse { + const _$_MarketResponse({required this.result, required this.allowance}); + + factory _$_MarketResponse.fromJson(Map json) => + _$_$_MarketResponseFromJson(json); + + @override + final List result; + @override + final Allowance allowance; + + @override + String toString() { + return 'MarketResponse(result: $result, allowance: $allowance)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other is _MarketResponse && + (identical(other.result, result) || + const DeepCollectionEquality().equals(other.result, result)) && + (identical(other.allowance, allowance) || + const DeepCollectionEquality() + .equals(other.allowance, allowance))); + } + + @override + int get hashCode => + runtimeType.hashCode ^ + const DeepCollectionEquality().hash(result) ^ + const DeepCollectionEquality().hash(allowance); + + @JsonKey(ignore: true) + @override + _$MarketResponseCopyWith<_MarketResponse> get copyWith => + __$MarketResponseCopyWithImpl<_MarketResponse>(this, _$identity); + + @override + Map toJson() { + return _$_$_MarketResponseToJson(this); + } +} + +abstract class _MarketResponse implements MarketResponse { + const factory _MarketResponse( + {required List result, + required Allowance allowance}) = _$_MarketResponse; + + factory _MarketResponse.fromJson(Map json) = + _$_MarketResponse.fromJson; + + @override + List get result => throw _privateConstructorUsedError; + @override + Allowance get allowance => throw _privateConstructorUsedError; + @override + @JsonKey(ignore: true) + _$MarketResponseCopyWith<_MarketResponse> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/models/markets/market_response/market_response.g.dart b/lib/models/markets/market_response/market_response.g.dart new file mode 100644 index 0000000..2e4943f --- /dev/null +++ b/lib/models/markets/market_response/market_response.g.dart @@ -0,0 +1,22 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'market_response.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$_MarketResponse _$_$_MarketResponseFromJson(Map json) { + return _$_MarketResponse( + result: (json['result'] as List) + .map((e) => Pair.fromJson(e as Map)) + .toList(), + allowance: Allowance.fromJson(json['allowance'] as Map), + ); +} + +Map _$_$_MarketResponseToJson(_$_MarketResponse instance) => + { + 'result': instance.result, + 'allowance': instance.allowance, + }; diff --git a/lib/models/markets/pair/pair.dart b/lib/models/markets/pair/pair.dart new file mode 100644 index 0000000..0477026 --- /dev/null +++ b/lib/models/markets/pair/pair.dart @@ -0,0 +1,16 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; +part 'pair.g.dart'; +part 'pair.freezed.dart'; + +@freezed +abstract class Pair with _$Pair { + const factory Pair({ + int? id, + required String exchange, + required String pair, + bool? active, + String? route, + }) = _Pair; + + factory Pair.fromJson(Map json) => _$PairFromJson(json); +} diff --git a/lib/models/markets/pair/pair.freezed.dart b/lib/models/markets/pair/pair.freezed.dart new file mode 100644 index 0000000..9d44b03 --- /dev/null +++ b/lib/models/markets/pair/pair.freezed.dart @@ -0,0 +1,248 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides + +part of 'pair.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +Pair _$PairFromJson(Map json) { + return _Pair.fromJson(json); +} + +/// @nodoc +class _$PairTearOff { + const _$PairTearOff(); + + _Pair call( + {int? id, + required String exchange, + required String pair, + bool? active, + String? route}) { + return _Pair( + id: id, + exchange: exchange, + pair: pair, + active: active, + route: route, + ); + } + + Pair fromJson(Map json) { + return Pair.fromJson(json); + } +} + +/// @nodoc +const $Pair = _$PairTearOff(); + +/// @nodoc +mixin _$Pair { + int? get id => throw _privateConstructorUsedError; + String get exchange => throw _privateConstructorUsedError; + String get pair => throw _privateConstructorUsedError; + bool? get active => throw _privateConstructorUsedError; + String? get route => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $PairCopyWith get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $PairCopyWith<$Res> { + factory $PairCopyWith(Pair value, $Res Function(Pair) then) = + _$PairCopyWithImpl<$Res>; + $Res call( + {int? id, String exchange, String pair, bool? active, String? route}); +} + +/// @nodoc +class _$PairCopyWithImpl<$Res> implements $PairCopyWith<$Res> { + _$PairCopyWithImpl(this._value, this._then); + + final Pair _value; + // ignore: unused_field + final $Res Function(Pair) _then; + + @override + $Res call({ + Object? id = freezed, + Object? exchange = freezed, + Object? pair = freezed, + Object? active = freezed, + Object? route = freezed, + }) { + return _then(_value.copyWith( + id: id == freezed + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int?, + exchange: exchange == freezed + ? _value.exchange + : exchange // ignore: cast_nullable_to_non_nullable + as String, + pair: pair == freezed + ? _value.pair + : pair // ignore: cast_nullable_to_non_nullable + as String, + active: active == freezed + ? _value.active + : active // ignore: cast_nullable_to_non_nullable + as bool?, + route: route == freezed + ? _value.route + : route // ignore: cast_nullable_to_non_nullable + as String?, + )); + } +} + +/// @nodoc +abstract class _$PairCopyWith<$Res> implements $PairCopyWith<$Res> { + factory _$PairCopyWith(_Pair value, $Res Function(_Pair) then) = + __$PairCopyWithImpl<$Res>; + @override + $Res call( + {int? id, String exchange, String pair, bool? active, String? route}); +} + +/// @nodoc +class __$PairCopyWithImpl<$Res> extends _$PairCopyWithImpl<$Res> + implements _$PairCopyWith<$Res> { + __$PairCopyWithImpl(_Pair _value, $Res Function(_Pair) _then) + : super(_value, (v) => _then(v as _Pair)); + + @override + _Pair get _value => super._value as _Pair; + + @override + $Res call({ + Object? id = freezed, + Object? exchange = freezed, + Object? pair = freezed, + Object? active = freezed, + Object? route = freezed, + }) { + return _then(_Pair( + id: id == freezed + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int?, + exchange: exchange == freezed + ? _value.exchange + : exchange // ignore: cast_nullable_to_non_nullable + as String, + pair: pair == freezed + ? _value.pair + : pair // ignore: cast_nullable_to_non_nullable + as String, + active: active == freezed + ? _value.active + : active // ignore: cast_nullable_to_non_nullable + as bool?, + route: route == freezed + ? _value.route + : route // ignore: cast_nullable_to_non_nullable + as String?, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$_Pair implements _Pair { + const _$_Pair( + {this.id, + required this.exchange, + required this.pair, + this.active, + this.route}); + + factory _$_Pair.fromJson(Map json) => + _$_$_PairFromJson(json); + + @override + final int? id; + @override + final String exchange; + @override + final String pair; + @override + final bool? active; + @override + final String? route; + + @override + String toString() { + return 'Pair(id: $id, exchange: $exchange, pair: $pair, active: $active, route: $route)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other is _Pair && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id)) && + (identical(other.exchange, exchange) || + const DeepCollectionEquality() + .equals(other.exchange, exchange)) && + (identical(other.pair, pair) || + const DeepCollectionEquality().equals(other.pair, pair)) && + (identical(other.active, active) || + const DeepCollectionEquality().equals(other.active, active)) && + (identical(other.route, route) || + const DeepCollectionEquality().equals(other.route, route))); + } + + @override + int get hashCode => + runtimeType.hashCode ^ + const DeepCollectionEquality().hash(id) ^ + const DeepCollectionEquality().hash(exchange) ^ + const DeepCollectionEquality().hash(pair) ^ + const DeepCollectionEquality().hash(active) ^ + const DeepCollectionEquality().hash(route); + + @JsonKey(ignore: true) + @override + _$PairCopyWith<_Pair> get copyWith => + __$PairCopyWithImpl<_Pair>(this, _$identity); + + @override + Map toJson() { + return _$_$_PairToJson(this); + } +} + +abstract class _Pair implements Pair { + const factory _Pair( + {int? id, + required String exchange, + required String pair, + bool? active, + String? route}) = _$_Pair; + + factory _Pair.fromJson(Map json) = _$_Pair.fromJson; + + @override + int? get id => throw _privateConstructorUsedError; + @override + String get exchange => throw _privateConstructorUsedError; + @override + String get pair => throw _privateConstructorUsedError; + @override + bool? get active => throw _privateConstructorUsedError; + @override + String? get route => throw _privateConstructorUsedError; + @override + @JsonKey(ignore: true) + _$PairCopyWith<_Pair> get copyWith => throw _privateConstructorUsedError; +} diff --git a/lib/models/markets/pair/pair.g.dart b/lib/models/markets/pair/pair.g.dart new file mode 100644 index 0000000..b4c702c --- /dev/null +++ b/lib/models/markets/pair/pair.g.dart @@ -0,0 +1,25 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'pair.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$_Pair _$_$_PairFromJson(Map json) { + return _$_Pair( + id: json['id'] as int?, + exchange: json['exchange'] as String, + pair: json['pair'] as String, + active: json['active'] as bool?, + route: json['route'] as String?, + ); +} + +Map _$_$_PairToJson(_$_Pair instance) => { + 'id': instance.id, + 'exchange': instance.exchange, + 'pair': instance.pair, + 'active': instance.active, + 'route': instance.route, + }; diff --git a/lib/models/orderbook/orderbook/orderbook.dart b/lib/models/orderbook/orderbook/orderbook.dart new file mode 100644 index 0000000..532b296 --- /dev/null +++ b/lib/models/orderbook/orderbook/orderbook.dart @@ -0,0 +1,35 @@ +import 'package:cryptocurrency_app/models/orderbook/price/price.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +part 'orderbook.freezed.dart'; + +@freezed +abstract class OrderBook with _$OrderBook { + const factory OrderBook( + List asks, + List bids, + int seqNum, + ) = _OrderBook; + + factory OrderBook.fromJson(Map json) { + List asks = []; + json['asks'].forEach((v) { + asks.add(Price( + price: double.parse(v[0].toString()), + amount: double.parse(v[1].toString()))); + }); + + List bids = []; + json['bids'].forEach((v) { + bids.add( + Price( + price: double.parse(v[0].toString()), + amount: double.parse( + v[1].toString(), + ), + ), + ); + }); + final seqNum = json['seqNum']; + return OrderBook(asks, bids, seqNum); + } +} diff --git a/lib/models/orderbook/orderbook/orderbook.freezed.dart b/lib/models/orderbook/orderbook/orderbook.freezed.dart new file mode 100644 index 0000000..d89e6a8 --- /dev/null +++ b/lib/models/orderbook/orderbook/orderbook.freezed.dart @@ -0,0 +1,177 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides + +part of 'orderbook.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +/// @nodoc +class _$OrderBookTearOff { + const _$OrderBookTearOff(); + + _OrderBook call(List asks, List bids, int seqNum) { + return _OrderBook( + asks, + bids, + seqNum, + ); + } +} + +/// @nodoc +const $OrderBook = _$OrderBookTearOff(); + +/// @nodoc +mixin _$OrderBook { + List get asks => throw _privateConstructorUsedError; + List get bids => throw _privateConstructorUsedError; + int get seqNum => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $OrderBookCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $OrderBookCopyWith<$Res> { + factory $OrderBookCopyWith(OrderBook value, $Res Function(OrderBook) then) = + _$OrderBookCopyWithImpl<$Res>; + $Res call({List asks, List bids, int seqNum}); +} + +/// @nodoc +class _$OrderBookCopyWithImpl<$Res> implements $OrderBookCopyWith<$Res> { + _$OrderBookCopyWithImpl(this._value, this._then); + + final OrderBook _value; + // ignore: unused_field + final $Res Function(OrderBook) _then; + + @override + $Res call({ + Object? asks = freezed, + Object? bids = freezed, + Object? seqNum = freezed, + }) { + return _then(_value.copyWith( + asks: asks == freezed + ? _value.asks + : asks // ignore: cast_nullable_to_non_nullable + as List, + bids: bids == freezed + ? _value.bids + : bids // ignore: cast_nullable_to_non_nullable + as List, + seqNum: seqNum == freezed + ? _value.seqNum + : seqNum // ignore: cast_nullable_to_non_nullable + as int, + )); + } +} + +/// @nodoc +abstract class _$OrderBookCopyWith<$Res> implements $OrderBookCopyWith<$Res> { + factory _$OrderBookCopyWith( + _OrderBook value, $Res Function(_OrderBook) then) = + __$OrderBookCopyWithImpl<$Res>; + @override + $Res call({List asks, List bids, int seqNum}); +} + +/// @nodoc +class __$OrderBookCopyWithImpl<$Res> extends _$OrderBookCopyWithImpl<$Res> + implements _$OrderBookCopyWith<$Res> { + __$OrderBookCopyWithImpl(_OrderBook _value, $Res Function(_OrderBook) _then) + : super(_value, (v) => _then(v as _OrderBook)); + + @override + _OrderBook get _value => super._value as _OrderBook; + + @override + $Res call({ + Object? asks = freezed, + Object? bids = freezed, + Object? seqNum = freezed, + }) { + return _then(_OrderBook( + asks == freezed + ? _value.asks + : asks // ignore: cast_nullable_to_non_nullable + as List, + bids == freezed + ? _value.bids + : bids // ignore: cast_nullable_to_non_nullable + as List, + seqNum == freezed + ? _value.seqNum + : seqNum // ignore: cast_nullable_to_non_nullable + as int, + )); + } +} + +/// @nodoc + +class _$_OrderBook implements _OrderBook { + const _$_OrderBook(this.asks, this.bids, this.seqNum); + + @override + final List asks; + @override + final List bids; + @override + final int seqNum; + + @override + String toString() { + return 'OrderBook(asks: $asks, bids: $bids, seqNum: $seqNum)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other is _OrderBook && + (identical(other.asks, asks) || + const DeepCollectionEquality().equals(other.asks, asks)) && + (identical(other.bids, bids) || + const DeepCollectionEquality().equals(other.bids, bids)) && + (identical(other.seqNum, seqNum) || + const DeepCollectionEquality().equals(other.seqNum, seqNum))); + } + + @override + int get hashCode => + runtimeType.hashCode ^ + const DeepCollectionEquality().hash(asks) ^ + const DeepCollectionEquality().hash(bids) ^ + const DeepCollectionEquality().hash(seqNum); + + @JsonKey(ignore: true) + @override + _$OrderBookCopyWith<_OrderBook> get copyWith => + __$OrderBookCopyWithImpl<_OrderBook>(this, _$identity); +} + +abstract class _OrderBook implements OrderBook { + const factory _OrderBook(List asks, List bids, int seqNum) = + _$_OrderBook; + + @override + List get asks => throw _privateConstructorUsedError; + @override + List get bids => throw _privateConstructorUsedError; + @override + int get seqNum => throw _privateConstructorUsedError; + @override + @JsonKey(ignore: true) + _$OrderBookCopyWith<_OrderBook> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/models/orderbook/orderbook_response/orderbook_response.dart b/lib/models/orderbook/orderbook_response/orderbook_response.dart new file mode 100644 index 0000000..c5fe9c9 --- /dev/null +++ b/lib/models/orderbook/orderbook_response/orderbook_response.dart @@ -0,0 +1,13 @@ +import 'package:cryptocurrency_app/models/orderbook/orderbook/orderbook.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +part 'orderbook_response.freezed.dart'; + +@freezed +abstract class OrderBookResponse with _$OrderBookResponse { + const factory OrderBookResponse(OrderBook result) = _OrderBookResponse; + + factory OrderBookResponse.fromJson(Map json) { + final result = new OrderBook.fromJson(json['result']); + return OrderBookResponse(result); + } +} diff --git a/lib/models/orderbook/orderbook_response/orderbook_response.freezed.dart b/lib/models/orderbook/orderbook_response/orderbook_response.freezed.dart new file mode 100644 index 0000000..3f1c965 --- /dev/null +++ b/lib/models/orderbook/orderbook_response/orderbook_response.freezed.dart @@ -0,0 +1,154 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides + +part of 'orderbook_response.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +/// @nodoc +class _$OrderBookResponseTearOff { + const _$OrderBookResponseTearOff(); + + _OrderBookResponse call(OrderBook result) { + return _OrderBookResponse( + result, + ); + } +} + +/// @nodoc +const $OrderBookResponse = _$OrderBookResponseTearOff(); + +/// @nodoc +mixin _$OrderBookResponse { + OrderBook get result => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $OrderBookResponseCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $OrderBookResponseCopyWith<$Res> { + factory $OrderBookResponseCopyWith( + OrderBookResponse value, $Res Function(OrderBookResponse) then) = + _$OrderBookResponseCopyWithImpl<$Res>; + $Res call({OrderBook result}); + + $OrderBookCopyWith<$Res> get result; +} + +/// @nodoc +class _$OrderBookResponseCopyWithImpl<$Res> + implements $OrderBookResponseCopyWith<$Res> { + _$OrderBookResponseCopyWithImpl(this._value, this._then); + + final OrderBookResponse _value; + // ignore: unused_field + final $Res Function(OrderBookResponse) _then; + + @override + $Res call({ + Object? result = freezed, + }) { + return _then(_value.copyWith( + result: result == freezed + ? _value.result + : result // ignore: cast_nullable_to_non_nullable + as OrderBook, + )); + } + + @override + $OrderBookCopyWith<$Res> get result { + return $OrderBookCopyWith<$Res>(_value.result, (value) { + return _then(_value.copyWith(result: value)); + }); + } +} + +/// @nodoc +abstract class _$OrderBookResponseCopyWith<$Res> + implements $OrderBookResponseCopyWith<$Res> { + factory _$OrderBookResponseCopyWith( + _OrderBookResponse value, $Res Function(_OrderBookResponse) then) = + __$OrderBookResponseCopyWithImpl<$Res>; + @override + $Res call({OrderBook result}); + + @override + $OrderBookCopyWith<$Res> get result; +} + +/// @nodoc +class __$OrderBookResponseCopyWithImpl<$Res> + extends _$OrderBookResponseCopyWithImpl<$Res> + implements _$OrderBookResponseCopyWith<$Res> { + __$OrderBookResponseCopyWithImpl( + _OrderBookResponse _value, $Res Function(_OrderBookResponse) _then) + : super(_value, (v) => _then(v as _OrderBookResponse)); + + @override + _OrderBookResponse get _value => super._value as _OrderBookResponse; + + @override + $Res call({ + Object? result = freezed, + }) { + return _then(_OrderBookResponse( + result == freezed + ? _value.result + : result // ignore: cast_nullable_to_non_nullable + as OrderBook, + )); + } +} + +/// @nodoc + +class _$_OrderBookResponse implements _OrderBookResponse { + const _$_OrderBookResponse(this.result); + + @override + final OrderBook result; + + @override + String toString() { + return 'OrderBookResponse(result: $result)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other is _OrderBookResponse && + (identical(other.result, result) || + const DeepCollectionEquality().equals(other.result, result))); + } + + @override + int get hashCode => + runtimeType.hashCode ^ const DeepCollectionEquality().hash(result); + + @JsonKey(ignore: true) + @override + _$OrderBookResponseCopyWith<_OrderBookResponse> get copyWith => + __$OrderBookResponseCopyWithImpl<_OrderBookResponse>(this, _$identity); +} + +abstract class _OrderBookResponse implements OrderBookResponse { + const factory _OrderBookResponse(OrderBook result) = _$_OrderBookResponse; + + @override + OrderBook get result => throw _privateConstructorUsedError; + @override + @JsonKey(ignore: true) + _$OrderBookResponseCopyWith<_OrderBookResponse> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/models/orderbook/price/price.dart b/lib/models/orderbook/price/price.dart new file mode 100644 index 0000000..88cf8c7 --- /dev/null +++ b/lib/models/orderbook/price/price.dart @@ -0,0 +1,7 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; +part 'price.freezed.dart'; + +@freezed +abstract class Price with _$Price { + const factory Price({required double price, required double amount}) = _Price; +} diff --git a/lib/models/orderbook/price/price.freezed.dart b/lib/models/orderbook/price/price.freezed.dart new file mode 100644 index 0000000..2d13ea5 --- /dev/null +++ b/lib/models/orderbook/price/price.freezed.dart @@ -0,0 +1,155 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides + +part of 'price.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +/// @nodoc +class _$PriceTearOff { + const _$PriceTearOff(); + + _Price call({required double price, required double amount}) { + return _Price( + price: price, + amount: amount, + ); + } +} + +/// @nodoc +const $Price = _$PriceTearOff(); + +/// @nodoc +mixin _$Price { + double get price => throw _privateConstructorUsedError; + double get amount => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $PriceCopyWith get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $PriceCopyWith<$Res> { + factory $PriceCopyWith(Price value, $Res Function(Price) then) = + _$PriceCopyWithImpl<$Res>; + $Res call({double price, double amount}); +} + +/// @nodoc +class _$PriceCopyWithImpl<$Res> implements $PriceCopyWith<$Res> { + _$PriceCopyWithImpl(this._value, this._then); + + final Price _value; + // ignore: unused_field + final $Res Function(Price) _then; + + @override + $Res call({ + Object? price = freezed, + Object? amount = freezed, + }) { + return _then(_value.copyWith( + price: price == freezed + ? _value.price + : price // ignore: cast_nullable_to_non_nullable + as double, + amount: amount == freezed + ? _value.amount + : amount // ignore: cast_nullable_to_non_nullable + as double, + )); + } +} + +/// @nodoc +abstract class _$PriceCopyWith<$Res> implements $PriceCopyWith<$Res> { + factory _$PriceCopyWith(_Price value, $Res Function(_Price) then) = + __$PriceCopyWithImpl<$Res>; + @override + $Res call({double price, double amount}); +} + +/// @nodoc +class __$PriceCopyWithImpl<$Res> extends _$PriceCopyWithImpl<$Res> + implements _$PriceCopyWith<$Res> { + __$PriceCopyWithImpl(_Price _value, $Res Function(_Price) _then) + : super(_value, (v) => _then(v as _Price)); + + @override + _Price get _value => super._value as _Price; + + @override + $Res call({ + Object? price = freezed, + Object? amount = freezed, + }) { + return _then(_Price( + price: price == freezed + ? _value.price + : price // ignore: cast_nullable_to_non_nullable + as double, + amount: amount == freezed + ? _value.amount + : amount // ignore: cast_nullable_to_non_nullable + as double, + )); + } +} + +/// @nodoc + +class _$_Price implements _Price { + const _$_Price({required this.price, required this.amount}); + + @override + final double price; + @override + final double amount; + + @override + String toString() { + return 'Price(price: $price, amount: $amount)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other is _Price && + (identical(other.price, price) || + const DeepCollectionEquality().equals(other.price, price)) && + (identical(other.amount, amount) || + const DeepCollectionEquality().equals(other.amount, amount))); + } + + @override + int get hashCode => + runtimeType.hashCode ^ + const DeepCollectionEquality().hash(price) ^ + const DeepCollectionEquality().hash(amount); + + @JsonKey(ignore: true) + @override + _$PriceCopyWith<_Price> get copyWith => + __$PriceCopyWithImpl<_Price>(this, _$identity); +} + +abstract class _Price implements Price { + const factory _Price({required double price, required double amount}) = + _$_Price; + + @override + double get price => throw _privateConstructorUsedError; + @override + double get amount => throw _privateConstructorUsedError; + @override + @JsonKey(ignore: true) + _$PriceCopyWith<_Price> get copyWith => throw _privateConstructorUsedError; +} diff --git a/lib/models/pair/change/change.dart b/lib/models/pair/change/change.dart new file mode 100644 index 0000000..292e273 --- /dev/null +++ b/lib/models/pair/change/change.dart @@ -0,0 +1,11 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; +part 'change.freezed.dart'; +part 'change.g.dart'; + +@freezed +abstract class Change with _$Change { + const factory Change({required double percentage, required double absolute}) = + _Change; + + factory Change.fromJson(Map json) => _$ChangeFromJson(json); +} diff --git a/lib/models/pair/change/change.freezed.dart b/lib/models/pair/change/change.freezed.dart new file mode 100644 index 0000000..3900a75 --- /dev/null +++ b/lib/models/pair/change/change.freezed.dart @@ -0,0 +1,176 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides + +part of 'change.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +Change _$ChangeFromJson(Map json) { + return _Change.fromJson(json); +} + +/// @nodoc +class _$ChangeTearOff { + const _$ChangeTearOff(); + + _Change call({required double percentage, required double absolute}) { + return _Change( + percentage: percentage, + absolute: absolute, + ); + } + + Change fromJson(Map json) { + return Change.fromJson(json); + } +} + +/// @nodoc +const $Change = _$ChangeTearOff(); + +/// @nodoc +mixin _$Change { + double get percentage => throw _privateConstructorUsedError; + double get absolute => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $ChangeCopyWith get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ChangeCopyWith<$Res> { + factory $ChangeCopyWith(Change value, $Res Function(Change) then) = + _$ChangeCopyWithImpl<$Res>; + $Res call({double percentage, double absolute}); +} + +/// @nodoc +class _$ChangeCopyWithImpl<$Res> implements $ChangeCopyWith<$Res> { + _$ChangeCopyWithImpl(this._value, this._then); + + final Change _value; + // ignore: unused_field + final $Res Function(Change) _then; + + @override + $Res call({ + Object? percentage = freezed, + Object? absolute = freezed, + }) { + return _then(_value.copyWith( + percentage: percentage == freezed + ? _value.percentage + : percentage // ignore: cast_nullable_to_non_nullable + as double, + absolute: absolute == freezed + ? _value.absolute + : absolute // ignore: cast_nullable_to_non_nullable + as double, + )); + } +} + +/// @nodoc +abstract class _$ChangeCopyWith<$Res> implements $ChangeCopyWith<$Res> { + factory _$ChangeCopyWith(_Change value, $Res Function(_Change) then) = + __$ChangeCopyWithImpl<$Res>; + @override + $Res call({double percentage, double absolute}); +} + +/// @nodoc +class __$ChangeCopyWithImpl<$Res> extends _$ChangeCopyWithImpl<$Res> + implements _$ChangeCopyWith<$Res> { + __$ChangeCopyWithImpl(_Change _value, $Res Function(_Change) _then) + : super(_value, (v) => _then(v as _Change)); + + @override + _Change get _value => super._value as _Change; + + @override + $Res call({ + Object? percentage = freezed, + Object? absolute = freezed, + }) { + return _then(_Change( + percentage: percentage == freezed + ? _value.percentage + : percentage // ignore: cast_nullable_to_non_nullable + as double, + absolute: absolute == freezed + ? _value.absolute + : absolute // ignore: cast_nullable_to_non_nullable + as double, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$_Change implements _Change { + const _$_Change({required this.percentage, required this.absolute}); + + factory _$_Change.fromJson(Map json) => + _$_$_ChangeFromJson(json); + + @override + final double percentage; + @override + final double absolute; + + @override + String toString() { + return 'Change(percentage: $percentage, absolute: $absolute)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other is _Change && + (identical(other.percentage, percentage) || + const DeepCollectionEquality() + .equals(other.percentage, percentage)) && + (identical(other.absolute, absolute) || + const DeepCollectionEquality() + .equals(other.absolute, absolute))); + } + + @override + int get hashCode => + runtimeType.hashCode ^ + const DeepCollectionEquality().hash(percentage) ^ + const DeepCollectionEquality().hash(absolute); + + @JsonKey(ignore: true) + @override + _$ChangeCopyWith<_Change> get copyWith => + __$ChangeCopyWithImpl<_Change>(this, _$identity); + + @override + Map toJson() { + return _$_$_ChangeToJson(this); + } +} + +abstract class _Change implements Change { + const factory _Change( + {required double percentage, required double absolute}) = _$_Change; + + factory _Change.fromJson(Map json) = _$_Change.fromJson; + + @override + double get percentage => throw _privateConstructorUsedError; + @override + double get absolute => throw _privateConstructorUsedError; + @override + @JsonKey(ignore: true) + _$ChangeCopyWith<_Change> get copyWith => throw _privateConstructorUsedError; +} diff --git a/lib/models/pair/change/change.g.dart b/lib/models/pair/change/change.g.dart new file mode 100644 index 0000000..3f8f5f5 --- /dev/null +++ b/lib/models/pair/change/change.g.dart @@ -0,0 +1,19 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'change.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$_Change _$_$_ChangeFromJson(Map json) { + return _$_Change( + percentage: (json['percentage'] as num).toDouble(), + absolute: (json['absolute'] as num).toDouble(), + ); +} + +Map _$_$_ChangeToJson(_$_Change instance) => { + 'percentage': instance.percentage, + 'absolute': instance.absolute, + }; diff --git a/lib/models/pair/pair_response/pair_response.dart b/lib/models/pair/pair_response/pair_response.dart new file mode 100644 index 0000000..5954bf7 --- /dev/null +++ b/lib/models/pair/pair_response/pair_response.dart @@ -0,0 +1,15 @@ +import 'package:cryptocurrency_app/models/allowance/allowance.dart'; +import 'package:cryptocurrency_app/models/pair/pair_summary/pair_summary.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'pair_response.freezed.dart'; +part 'pair_response.g.dart'; + +@freezed +abstract class PairResponse with _$PairResponse { + const factory PairResponse(PairSummary result, Allowance allowance) = + _PairResponse; + + factory PairResponse.fromJson(Map json) => + _$PairResponseFromJson(json); +} diff --git a/lib/models/pair/pair_response/pair_response.freezed.dart b/lib/models/pair/pair_response/pair_response.freezed.dart new file mode 100644 index 0000000..f35cb59 --- /dev/null +++ b/lib/models/pair/pair_response/pair_response.freezed.dart @@ -0,0 +1,204 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides + +part of 'pair_response.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +PairResponse _$PairResponseFromJson(Map json) { + return _PairResponse.fromJson(json); +} + +/// @nodoc +class _$PairResponseTearOff { + const _$PairResponseTearOff(); + + _PairResponse call(PairSummary result, Allowance allowance) { + return _PairResponse( + result, + allowance, + ); + } + + PairResponse fromJson(Map json) { + return PairResponse.fromJson(json); + } +} + +/// @nodoc +const $PairResponse = _$PairResponseTearOff(); + +/// @nodoc +mixin _$PairResponse { + PairSummary get result => throw _privateConstructorUsedError; + Allowance get allowance => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $PairResponseCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $PairResponseCopyWith<$Res> { + factory $PairResponseCopyWith( + PairResponse value, $Res Function(PairResponse) then) = + _$PairResponseCopyWithImpl<$Res>; + $Res call({PairSummary result, Allowance allowance}); + + $PairSummaryCopyWith<$Res> get result; + $AllowanceCopyWith<$Res> get allowance; +} + +/// @nodoc +class _$PairResponseCopyWithImpl<$Res> implements $PairResponseCopyWith<$Res> { + _$PairResponseCopyWithImpl(this._value, this._then); + + final PairResponse _value; + // ignore: unused_field + final $Res Function(PairResponse) _then; + + @override + $Res call({ + Object? result = freezed, + Object? allowance = freezed, + }) { + return _then(_value.copyWith( + result: result == freezed + ? _value.result + : result // ignore: cast_nullable_to_non_nullable + as PairSummary, + allowance: allowance == freezed + ? _value.allowance + : allowance // ignore: cast_nullable_to_non_nullable + as Allowance, + )); + } + + @override + $PairSummaryCopyWith<$Res> get result { + return $PairSummaryCopyWith<$Res>(_value.result, (value) { + return _then(_value.copyWith(result: value)); + }); + } + + @override + $AllowanceCopyWith<$Res> get allowance { + return $AllowanceCopyWith<$Res>(_value.allowance, (value) { + return _then(_value.copyWith(allowance: value)); + }); + } +} + +/// @nodoc +abstract class _$PairResponseCopyWith<$Res> + implements $PairResponseCopyWith<$Res> { + factory _$PairResponseCopyWith( + _PairResponse value, $Res Function(_PairResponse) then) = + __$PairResponseCopyWithImpl<$Res>; + @override + $Res call({PairSummary result, Allowance allowance}); + + @override + $PairSummaryCopyWith<$Res> get result; + @override + $AllowanceCopyWith<$Res> get allowance; +} + +/// @nodoc +class __$PairResponseCopyWithImpl<$Res> extends _$PairResponseCopyWithImpl<$Res> + implements _$PairResponseCopyWith<$Res> { + __$PairResponseCopyWithImpl( + _PairResponse _value, $Res Function(_PairResponse) _then) + : super(_value, (v) => _then(v as _PairResponse)); + + @override + _PairResponse get _value => super._value as _PairResponse; + + @override + $Res call({ + Object? result = freezed, + Object? allowance = freezed, + }) { + return _then(_PairResponse( + result == freezed + ? _value.result + : result // ignore: cast_nullable_to_non_nullable + as PairSummary, + allowance == freezed + ? _value.allowance + : allowance // ignore: cast_nullable_to_non_nullable + as Allowance, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$_PairResponse implements _PairResponse { + const _$_PairResponse(this.result, this.allowance); + + factory _$_PairResponse.fromJson(Map json) => + _$_$_PairResponseFromJson(json); + + @override + final PairSummary result; + @override + final Allowance allowance; + + @override + String toString() { + return 'PairResponse(result: $result, allowance: $allowance)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other is _PairResponse && + (identical(other.result, result) || + const DeepCollectionEquality().equals(other.result, result)) && + (identical(other.allowance, allowance) || + const DeepCollectionEquality() + .equals(other.allowance, allowance))); + } + + @override + int get hashCode => + runtimeType.hashCode ^ + const DeepCollectionEquality().hash(result) ^ + const DeepCollectionEquality().hash(allowance); + + @JsonKey(ignore: true) + @override + _$PairResponseCopyWith<_PairResponse> get copyWith => + __$PairResponseCopyWithImpl<_PairResponse>(this, _$identity); + + @override + Map toJson() { + return _$_$_PairResponseToJson(this); + } +} + +abstract class _PairResponse implements PairResponse { + const factory _PairResponse(PairSummary result, Allowance allowance) = + _$_PairResponse; + + factory _PairResponse.fromJson(Map json) = + _$_PairResponse.fromJson; + + @override + PairSummary get result => throw _privateConstructorUsedError; + @override + Allowance get allowance => throw _privateConstructorUsedError; + @override + @JsonKey(ignore: true) + _$PairResponseCopyWith<_PairResponse> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/models/pair/pair_response/pair_response.g.dart b/lib/models/pair/pair_response/pair_response.g.dart new file mode 100644 index 0000000..489b9a4 --- /dev/null +++ b/lib/models/pair/pair_response/pair_response.g.dart @@ -0,0 +1,20 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'pair_response.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$_PairResponse _$_$_PairResponseFromJson(Map json) { + return _$_PairResponse( + PairSummary.fromJson(json['result'] as Map), + Allowance.fromJson(json['allowance'] as Map), + ); +} + +Map _$_$_PairResponseToJson(_$_PairResponse instance) => + { + 'result': instance.result, + 'allowance': instance.allowance, + }; diff --git a/lib/models/pair/pair_summary/pair_summary.dart b/lib/models/pair/pair_summary/pair_summary.dart new file mode 100644 index 0000000..f7be514 --- /dev/null +++ b/lib/models/pair/pair_summary/pair_summary.dart @@ -0,0 +1,17 @@ +import 'package:cryptocurrency_app/models/pair/price/price.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'pair_summary.freezed.dart'; +part 'pair_summary.g.dart'; + +@freezed +abstract class PairSummary with _$PairSummary { + const factory PairSummary({ + required Price price, + required double volume, + required double volumeQuote, + }) = _PairSummary; + + factory PairSummary.fromJson(Map json) => + _$PairSummaryFromJson(json); +} diff --git a/lib/models/pair/pair_summary/pair_summary.freezed.dart b/lib/models/pair/pair_summary/pair_summary.freezed.dart new file mode 100644 index 0000000..a170c78 --- /dev/null +++ b/lib/models/pair/pair_summary/pair_summary.freezed.dart @@ -0,0 +1,219 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides + +part of 'pair_summary.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +PairSummary _$PairSummaryFromJson(Map json) { + return _PairSummary.fromJson(json); +} + +/// @nodoc +class _$PairSummaryTearOff { + const _$PairSummaryTearOff(); + + _PairSummary call( + {required Price price, + required double volume, + required double volumeQuote}) { + return _PairSummary( + price: price, + volume: volume, + volumeQuote: volumeQuote, + ); + } + + PairSummary fromJson(Map json) { + return PairSummary.fromJson(json); + } +} + +/// @nodoc +const $PairSummary = _$PairSummaryTearOff(); + +/// @nodoc +mixin _$PairSummary { + Price get price => throw _privateConstructorUsedError; + double get volume => throw _privateConstructorUsedError; + double get volumeQuote => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $PairSummaryCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $PairSummaryCopyWith<$Res> { + factory $PairSummaryCopyWith( + PairSummary value, $Res Function(PairSummary) then) = + _$PairSummaryCopyWithImpl<$Res>; + $Res call({Price price, double volume, double volumeQuote}); + + $PriceCopyWith<$Res> get price; +} + +/// @nodoc +class _$PairSummaryCopyWithImpl<$Res> implements $PairSummaryCopyWith<$Res> { + _$PairSummaryCopyWithImpl(this._value, this._then); + + final PairSummary _value; + // ignore: unused_field + final $Res Function(PairSummary) _then; + + @override + $Res call({ + Object? price = freezed, + Object? volume = freezed, + Object? volumeQuote = freezed, + }) { + return _then(_value.copyWith( + price: price == freezed + ? _value.price + : price // ignore: cast_nullable_to_non_nullable + as Price, + volume: volume == freezed + ? _value.volume + : volume // ignore: cast_nullable_to_non_nullable + as double, + volumeQuote: volumeQuote == freezed + ? _value.volumeQuote + : volumeQuote // ignore: cast_nullable_to_non_nullable + as double, + )); + } + + @override + $PriceCopyWith<$Res> get price { + return $PriceCopyWith<$Res>(_value.price, (value) { + return _then(_value.copyWith(price: value)); + }); + } +} + +/// @nodoc +abstract class _$PairSummaryCopyWith<$Res> + implements $PairSummaryCopyWith<$Res> { + factory _$PairSummaryCopyWith( + _PairSummary value, $Res Function(_PairSummary) then) = + __$PairSummaryCopyWithImpl<$Res>; + @override + $Res call({Price price, double volume, double volumeQuote}); + + @override + $PriceCopyWith<$Res> get price; +} + +/// @nodoc +class __$PairSummaryCopyWithImpl<$Res> extends _$PairSummaryCopyWithImpl<$Res> + implements _$PairSummaryCopyWith<$Res> { + __$PairSummaryCopyWithImpl( + _PairSummary _value, $Res Function(_PairSummary) _then) + : super(_value, (v) => _then(v as _PairSummary)); + + @override + _PairSummary get _value => super._value as _PairSummary; + + @override + $Res call({ + Object? price = freezed, + Object? volume = freezed, + Object? volumeQuote = freezed, + }) { + return _then(_PairSummary( + price: price == freezed + ? _value.price + : price // ignore: cast_nullable_to_non_nullable + as Price, + volume: volume == freezed + ? _value.volume + : volume // ignore: cast_nullable_to_non_nullable + as double, + volumeQuote: volumeQuote == freezed + ? _value.volumeQuote + : volumeQuote // ignore: cast_nullable_to_non_nullable + as double, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$_PairSummary implements _PairSummary { + const _$_PairSummary( + {required this.price, required this.volume, required this.volumeQuote}); + + factory _$_PairSummary.fromJson(Map json) => + _$_$_PairSummaryFromJson(json); + + @override + final Price price; + @override + final double volume; + @override + final double volumeQuote; + + @override + String toString() { + return 'PairSummary(price: $price, volume: $volume, volumeQuote: $volumeQuote)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other is _PairSummary && + (identical(other.price, price) || + const DeepCollectionEquality().equals(other.price, price)) && + (identical(other.volume, volume) || + const DeepCollectionEquality().equals(other.volume, volume)) && + (identical(other.volumeQuote, volumeQuote) || + const DeepCollectionEquality() + .equals(other.volumeQuote, volumeQuote))); + } + + @override + int get hashCode => + runtimeType.hashCode ^ + const DeepCollectionEquality().hash(price) ^ + const DeepCollectionEquality().hash(volume) ^ + const DeepCollectionEquality().hash(volumeQuote); + + @JsonKey(ignore: true) + @override + _$PairSummaryCopyWith<_PairSummary> get copyWith => + __$PairSummaryCopyWithImpl<_PairSummary>(this, _$identity); + + @override + Map toJson() { + return _$_$_PairSummaryToJson(this); + } +} + +abstract class _PairSummary implements PairSummary { + const factory _PairSummary( + {required Price price, + required double volume, + required double volumeQuote}) = _$_PairSummary; + + factory _PairSummary.fromJson(Map json) = + _$_PairSummary.fromJson; + + @override + Price get price => throw _privateConstructorUsedError; + @override + double get volume => throw _privateConstructorUsedError; + @override + double get volumeQuote => throw _privateConstructorUsedError; + @override + @JsonKey(ignore: true) + _$PairSummaryCopyWith<_PairSummary> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/models/pair/pair_summary/pair_summary.g.dart b/lib/models/pair/pair_summary/pair_summary.g.dart new file mode 100644 index 0000000..c2212c0 --- /dev/null +++ b/lib/models/pair/pair_summary/pair_summary.g.dart @@ -0,0 +1,22 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'pair_summary.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$_PairSummary _$_$_PairSummaryFromJson(Map json) { + return _$_PairSummary( + price: Price.fromJson(json['price'] as Map), + volume: (json['volume'] as num).toDouble(), + volumeQuote: (json['volumeQuote'] as num).toDouble(), + ); +} + +Map _$_$_PairSummaryToJson(_$_PairSummary instance) => + { + 'price': instance.price, + 'volume': instance.volume, + 'volumeQuote': instance.volumeQuote, + }; diff --git a/lib/models/pair/price/price.dart b/lib/models/pair/price/price.dart new file mode 100644 index 0000000..ff77cc0 --- /dev/null +++ b/lib/models/pair/price/price.dart @@ -0,0 +1,16 @@ +import 'package:cryptocurrency_app/models/pair/change/change.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +part 'price.freezed.dart'; +part 'price.g.dart'; + +@freezed +abstract class Price with _$Price { + const factory Price({ + required double last, + required double high, + required double low, + required Change change, + }) = _Price; + + factory Price.fromJson(Map json) => _$PriceFromJson(json); +} diff --git a/lib/models/pair/price/price.freezed.dart b/lib/models/pair/price/price.freezed.dart new file mode 100644 index 0000000..210c3f7 --- /dev/null +++ b/lib/models/pair/price/price.freezed.dart @@ -0,0 +1,235 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides + +part of 'price.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +Price _$PriceFromJson(Map json) { + return _Price.fromJson(json); +} + +/// @nodoc +class _$PriceTearOff { + const _$PriceTearOff(); + + _Price call( + {required double last, + required double high, + required double low, + required Change change}) { + return _Price( + last: last, + high: high, + low: low, + change: change, + ); + } + + Price fromJson(Map json) { + return Price.fromJson(json); + } +} + +/// @nodoc +const $Price = _$PriceTearOff(); + +/// @nodoc +mixin _$Price { + double get last => throw _privateConstructorUsedError; + double get high => throw _privateConstructorUsedError; + double get low => throw _privateConstructorUsedError; + Change get change => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $PriceCopyWith get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $PriceCopyWith<$Res> { + factory $PriceCopyWith(Price value, $Res Function(Price) then) = + _$PriceCopyWithImpl<$Res>; + $Res call({double last, double high, double low, Change change}); + + $ChangeCopyWith<$Res> get change; +} + +/// @nodoc +class _$PriceCopyWithImpl<$Res> implements $PriceCopyWith<$Res> { + _$PriceCopyWithImpl(this._value, this._then); + + final Price _value; + // ignore: unused_field + final $Res Function(Price) _then; + + @override + $Res call({ + Object? last = freezed, + Object? high = freezed, + Object? low = freezed, + Object? change = freezed, + }) { + return _then(_value.copyWith( + last: last == freezed + ? _value.last + : last // ignore: cast_nullable_to_non_nullable + as double, + high: high == freezed + ? _value.high + : high // ignore: cast_nullable_to_non_nullable + as double, + low: low == freezed + ? _value.low + : low // ignore: cast_nullable_to_non_nullable + as double, + change: change == freezed + ? _value.change + : change // ignore: cast_nullable_to_non_nullable + as Change, + )); + } + + @override + $ChangeCopyWith<$Res> get change { + return $ChangeCopyWith<$Res>(_value.change, (value) { + return _then(_value.copyWith(change: value)); + }); + } +} + +/// @nodoc +abstract class _$PriceCopyWith<$Res> implements $PriceCopyWith<$Res> { + factory _$PriceCopyWith(_Price value, $Res Function(_Price) then) = + __$PriceCopyWithImpl<$Res>; + @override + $Res call({double last, double high, double low, Change change}); + + @override + $ChangeCopyWith<$Res> get change; +} + +/// @nodoc +class __$PriceCopyWithImpl<$Res> extends _$PriceCopyWithImpl<$Res> + implements _$PriceCopyWith<$Res> { + __$PriceCopyWithImpl(_Price _value, $Res Function(_Price) _then) + : super(_value, (v) => _then(v as _Price)); + + @override + _Price get _value => super._value as _Price; + + @override + $Res call({ + Object? last = freezed, + Object? high = freezed, + Object? low = freezed, + Object? change = freezed, + }) { + return _then(_Price( + last: last == freezed + ? _value.last + : last // ignore: cast_nullable_to_non_nullable + as double, + high: high == freezed + ? _value.high + : high // ignore: cast_nullable_to_non_nullable + as double, + low: low == freezed + ? _value.low + : low // ignore: cast_nullable_to_non_nullable + as double, + change: change == freezed + ? _value.change + : change // ignore: cast_nullable_to_non_nullable + as Change, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$_Price implements _Price { + const _$_Price( + {required this.last, + required this.high, + required this.low, + required this.change}); + + factory _$_Price.fromJson(Map json) => + _$_$_PriceFromJson(json); + + @override + final double last; + @override + final double high; + @override + final double low; + @override + final Change change; + + @override + String toString() { + return 'Price(last: $last, high: $high, low: $low, change: $change)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other is _Price && + (identical(other.last, last) || + const DeepCollectionEquality().equals(other.last, last)) && + (identical(other.high, high) || + const DeepCollectionEquality().equals(other.high, high)) && + (identical(other.low, low) || + const DeepCollectionEquality().equals(other.low, low)) && + (identical(other.change, change) || + const DeepCollectionEquality().equals(other.change, change))); + } + + @override + int get hashCode => + runtimeType.hashCode ^ + const DeepCollectionEquality().hash(last) ^ + const DeepCollectionEquality().hash(high) ^ + const DeepCollectionEquality().hash(low) ^ + const DeepCollectionEquality().hash(change); + + @JsonKey(ignore: true) + @override + _$PriceCopyWith<_Price> get copyWith => + __$PriceCopyWithImpl<_Price>(this, _$identity); + + @override + Map toJson() { + return _$_$_PriceToJson(this); + } +} + +abstract class _Price implements Price { + const factory _Price( + {required double last, + required double high, + required double low, + required Change change}) = _$_Price; + + factory _Price.fromJson(Map json) = _$_Price.fromJson; + + @override + double get last => throw _privateConstructorUsedError; + @override + double get high => throw _privateConstructorUsedError; + @override + double get low => throw _privateConstructorUsedError; + @override + Change get change => throw _privateConstructorUsedError; + @override + @JsonKey(ignore: true) + _$PriceCopyWith<_Price> get copyWith => throw _privateConstructorUsedError; +} diff --git a/lib/models/pair/price/price.g.dart b/lib/models/pair/price/price.g.dart new file mode 100644 index 0000000..4d62e17 --- /dev/null +++ b/lib/models/pair/price/price.g.dart @@ -0,0 +1,23 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'price.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$_Price _$_$_PriceFromJson(Map json) { + return _$_Price( + last: (json['last'] as num).toDouble(), + high: (json['high'] as num).toDouble(), + low: (json['low'] as num).toDouble(), + change: Change.fromJson(json['change'] as Map), + ); +} + +Map _$_$_PriceToJson(_$_Price instance) => { + 'last': instance.last, + 'high': instance.high, + 'low': instance.low, + 'change': instance.change, + }; diff --git a/lib/models/settings/settings_details/settings_details.dart b/lib/models/settings/settings_details/settings_details.dart new file mode 100644 index 0000000..9bd8137 --- /dev/null +++ b/lib/models/settings/settings_details/settings_details.dart @@ -0,0 +1,13 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'settings_details.freezed.dart'; + +@freezed +abstract class SettingsDetails with _$SettingsDetails { + const factory SettingsDetails({ + required String currentLanguage, + required String favoriteExchange, + required String favoritePair, + required String themeMode, + }) = _SettingsDetails; +} diff --git a/lib/models/settings/settings_details/settings_details.freezed.dart b/lib/models/settings/settings_details/settings_details.freezed.dart new file mode 100644 index 0000000..4d7680d --- /dev/null +++ b/lib/models/settings/settings_details/settings_details.freezed.dart @@ -0,0 +1,224 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides + +part of 'settings_details.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +/// @nodoc +class _$SettingsDetailsTearOff { + const _$SettingsDetailsTearOff(); + + _SettingsDetails call( + {required String currentLanguage, + required String favoriteExchange, + required String favoritePair, + required String themeMode}) { + return _SettingsDetails( + currentLanguage: currentLanguage, + favoriteExchange: favoriteExchange, + favoritePair: favoritePair, + themeMode: themeMode, + ); + } +} + +/// @nodoc +const $SettingsDetails = _$SettingsDetailsTearOff(); + +/// @nodoc +mixin _$SettingsDetails { + String get currentLanguage => throw _privateConstructorUsedError; + String get favoriteExchange => throw _privateConstructorUsedError; + String get favoritePair => throw _privateConstructorUsedError; + String get themeMode => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $SettingsDetailsCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $SettingsDetailsCopyWith<$Res> { + factory $SettingsDetailsCopyWith( + SettingsDetails value, $Res Function(SettingsDetails) then) = + _$SettingsDetailsCopyWithImpl<$Res>; + $Res call( + {String currentLanguage, + String favoriteExchange, + String favoritePair, + String themeMode}); +} + +/// @nodoc +class _$SettingsDetailsCopyWithImpl<$Res> + implements $SettingsDetailsCopyWith<$Res> { + _$SettingsDetailsCopyWithImpl(this._value, this._then); + + final SettingsDetails _value; + // ignore: unused_field + final $Res Function(SettingsDetails) _then; + + @override + $Res call({ + Object? currentLanguage = freezed, + Object? favoriteExchange = freezed, + Object? favoritePair = freezed, + Object? themeMode = freezed, + }) { + return _then(_value.copyWith( + currentLanguage: currentLanguage == freezed + ? _value.currentLanguage + : currentLanguage // ignore: cast_nullable_to_non_nullable + as String, + favoriteExchange: favoriteExchange == freezed + ? _value.favoriteExchange + : favoriteExchange // ignore: cast_nullable_to_non_nullable + as String, + favoritePair: favoritePair == freezed + ? _value.favoritePair + : favoritePair // ignore: cast_nullable_to_non_nullable + as String, + themeMode: themeMode == freezed + ? _value.themeMode + : themeMode // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +abstract class _$SettingsDetailsCopyWith<$Res> + implements $SettingsDetailsCopyWith<$Res> { + factory _$SettingsDetailsCopyWith( + _SettingsDetails value, $Res Function(_SettingsDetails) then) = + __$SettingsDetailsCopyWithImpl<$Res>; + @override + $Res call( + {String currentLanguage, + String favoriteExchange, + String favoritePair, + String themeMode}); +} + +/// @nodoc +class __$SettingsDetailsCopyWithImpl<$Res> + extends _$SettingsDetailsCopyWithImpl<$Res> + implements _$SettingsDetailsCopyWith<$Res> { + __$SettingsDetailsCopyWithImpl( + _SettingsDetails _value, $Res Function(_SettingsDetails) _then) + : super(_value, (v) => _then(v as _SettingsDetails)); + + @override + _SettingsDetails get _value => super._value as _SettingsDetails; + + @override + $Res call({ + Object? currentLanguage = freezed, + Object? favoriteExchange = freezed, + Object? favoritePair = freezed, + Object? themeMode = freezed, + }) { + return _then(_SettingsDetails( + currentLanguage: currentLanguage == freezed + ? _value.currentLanguage + : currentLanguage // ignore: cast_nullable_to_non_nullable + as String, + favoriteExchange: favoriteExchange == freezed + ? _value.favoriteExchange + : favoriteExchange // ignore: cast_nullable_to_non_nullable + as String, + favoritePair: favoritePair == freezed + ? _value.favoritePair + : favoritePair // ignore: cast_nullable_to_non_nullable + as String, + themeMode: themeMode == freezed + ? _value.themeMode + : themeMode // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc + +class _$_SettingsDetails implements _SettingsDetails { + const _$_SettingsDetails( + {required this.currentLanguage, + required this.favoriteExchange, + required this.favoritePair, + required this.themeMode}); + + @override + final String currentLanguage; + @override + final String favoriteExchange; + @override + final String favoritePair; + @override + final String themeMode; + + @override + String toString() { + return 'SettingsDetails(currentLanguage: $currentLanguage, favoriteExchange: $favoriteExchange, favoritePair: $favoritePair, themeMode: $themeMode)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other is _SettingsDetails && + (identical(other.currentLanguage, currentLanguage) || + const DeepCollectionEquality() + .equals(other.currentLanguage, currentLanguage)) && + (identical(other.favoriteExchange, favoriteExchange) || + const DeepCollectionEquality() + .equals(other.favoriteExchange, favoriteExchange)) && + (identical(other.favoritePair, favoritePair) || + const DeepCollectionEquality() + .equals(other.favoritePair, favoritePair)) && + (identical(other.themeMode, themeMode) || + const DeepCollectionEquality() + .equals(other.themeMode, themeMode))); + } + + @override + int get hashCode => + runtimeType.hashCode ^ + const DeepCollectionEquality().hash(currentLanguage) ^ + const DeepCollectionEquality().hash(favoriteExchange) ^ + const DeepCollectionEquality().hash(favoritePair) ^ + const DeepCollectionEquality().hash(themeMode); + + @JsonKey(ignore: true) + @override + _$SettingsDetailsCopyWith<_SettingsDetails> get copyWith => + __$SettingsDetailsCopyWithImpl<_SettingsDetails>(this, _$identity); +} + +abstract class _SettingsDetails implements SettingsDetails { + const factory _SettingsDetails( + {required String currentLanguage, + required String favoriteExchange, + required String favoritePair, + required String themeMode}) = _$_SettingsDetails; + + @override + String get currentLanguage => throw _privateConstructorUsedError; + @override + String get favoriteExchange => throw _privateConstructorUsedError; + @override + String get favoritePair => throw _privateConstructorUsedError; + @override + String get themeMode => throw _privateConstructorUsedError; + @override + @JsonKey(ignore: true) + _$SettingsDetailsCopyWith<_SettingsDetails> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/models/settings/settings_state/settings_state.dart b/lib/models/settings/settings_state/settings_state.dart new file mode 100644 index 0000000..694f979 --- /dev/null +++ b/lib/models/settings/settings_state/settings_state.dart @@ -0,0 +1,13 @@ +import 'package:cryptocurrency_app/models/settings/settings_details/settings_details.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'settings_state.freezed.dart'; + +@freezed +abstract class SettingsState with _$SettingsState { + const factory SettingsState.initial() = _SettingsStateInitial; + const factory SettingsState.loading() = _SettingsStateLoading; + const factory SettingsState.data({required SettingsDetails details}) = + _SetttingsStateData; + const factory SettingsState.error({String? error}) = _SettingsStateError; +} diff --git a/lib/models/settings/settings_state/settings_state.freezed.dart b/lib/models/settings/settings_state/settings_state.freezed.dart new file mode 100644 index 0000000..ea594b0 --- /dev/null +++ b/lib/models/settings/settings_state/settings_state.freezed.dart @@ -0,0 +1,542 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides + +part of 'settings_state.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +/// @nodoc +class _$SettingsStateTearOff { + const _$SettingsStateTearOff(); + + _SettingsStateInitial initial() { + return const _SettingsStateInitial(); + } + + _SettingsStateLoading loading() { + return const _SettingsStateLoading(); + } + + _SetttingsStateData data({required SettingsDetails details}) { + return _SetttingsStateData( + details: details, + ); + } + + _SettingsStateError error({String? error}) { + return _SettingsStateError( + error: error, + ); + } +} + +/// @nodoc +const $SettingsState = _$SettingsStateTearOff(); + +/// @nodoc +mixin _$SettingsState { + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() loading, + required TResult Function(SettingsDetails details) data, + required TResult Function(String? error) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? loading, + TResult Function(SettingsDetails details)? data, + TResult Function(String? error)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(_SettingsStateInitial value) initial, + required TResult Function(_SettingsStateLoading value) loading, + required TResult Function(_SetttingsStateData value) data, + required TResult Function(_SettingsStateError value) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_SettingsStateInitial value)? initial, + TResult Function(_SettingsStateLoading value)? loading, + TResult Function(_SetttingsStateData value)? data, + TResult Function(_SettingsStateError value)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $SettingsStateCopyWith<$Res> { + factory $SettingsStateCopyWith( + SettingsState value, $Res Function(SettingsState) then) = + _$SettingsStateCopyWithImpl<$Res>; +} + +/// @nodoc +class _$SettingsStateCopyWithImpl<$Res> + implements $SettingsStateCopyWith<$Res> { + _$SettingsStateCopyWithImpl(this._value, this._then); + + final SettingsState _value; + // ignore: unused_field + final $Res Function(SettingsState) _then; +} + +/// @nodoc +abstract class _$SettingsStateInitialCopyWith<$Res> { + factory _$SettingsStateInitialCopyWith(_SettingsStateInitial value, + $Res Function(_SettingsStateInitial) then) = + __$SettingsStateInitialCopyWithImpl<$Res>; +} + +/// @nodoc +class __$SettingsStateInitialCopyWithImpl<$Res> + extends _$SettingsStateCopyWithImpl<$Res> + implements _$SettingsStateInitialCopyWith<$Res> { + __$SettingsStateInitialCopyWithImpl( + _SettingsStateInitial _value, $Res Function(_SettingsStateInitial) _then) + : super(_value, (v) => _then(v as _SettingsStateInitial)); + + @override + _SettingsStateInitial get _value => super._value as _SettingsStateInitial; +} + +/// @nodoc + +class _$_SettingsStateInitial implements _SettingsStateInitial { + const _$_SettingsStateInitial(); + + @override + String toString() { + return 'SettingsState.initial()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || (other is _SettingsStateInitial); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() loading, + required TResult Function(SettingsDetails details) data, + required TResult Function(String? error) error, + }) { + return initial(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? loading, + TResult Function(SettingsDetails details)? data, + TResult Function(String? error)? error, + required TResult orElse(), + }) { + if (initial != null) { + return initial(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_SettingsStateInitial value) initial, + required TResult Function(_SettingsStateLoading value) loading, + required TResult Function(_SetttingsStateData value) data, + required TResult Function(_SettingsStateError value) error, + }) { + return initial(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_SettingsStateInitial value)? initial, + TResult Function(_SettingsStateLoading value)? loading, + TResult Function(_SetttingsStateData value)? data, + TResult Function(_SettingsStateError value)? error, + required TResult orElse(), + }) { + if (initial != null) { + return initial(this); + } + return orElse(); + } +} + +abstract class _SettingsStateInitial implements SettingsState { + const factory _SettingsStateInitial() = _$_SettingsStateInitial; +} + +/// @nodoc +abstract class _$SettingsStateLoadingCopyWith<$Res> { + factory _$SettingsStateLoadingCopyWith(_SettingsStateLoading value, + $Res Function(_SettingsStateLoading) then) = + __$SettingsStateLoadingCopyWithImpl<$Res>; +} + +/// @nodoc +class __$SettingsStateLoadingCopyWithImpl<$Res> + extends _$SettingsStateCopyWithImpl<$Res> + implements _$SettingsStateLoadingCopyWith<$Res> { + __$SettingsStateLoadingCopyWithImpl( + _SettingsStateLoading _value, $Res Function(_SettingsStateLoading) _then) + : super(_value, (v) => _then(v as _SettingsStateLoading)); + + @override + _SettingsStateLoading get _value => super._value as _SettingsStateLoading; +} + +/// @nodoc + +class _$_SettingsStateLoading implements _SettingsStateLoading { + const _$_SettingsStateLoading(); + + @override + String toString() { + return 'SettingsState.loading()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || (other is _SettingsStateLoading); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() loading, + required TResult Function(SettingsDetails details) data, + required TResult Function(String? error) error, + }) { + return loading(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? loading, + TResult Function(SettingsDetails details)? data, + TResult Function(String? error)? error, + required TResult orElse(), + }) { + if (loading != null) { + return loading(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_SettingsStateInitial value) initial, + required TResult Function(_SettingsStateLoading value) loading, + required TResult Function(_SetttingsStateData value) data, + required TResult Function(_SettingsStateError value) error, + }) { + return loading(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_SettingsStateInitial value)? initial, + TResult Function(_SettingsStateLoading value)? loading, + TResult Function(_SetttingsStateData value)? data, + TResult Function(_SettingsStateError value)? error, + required TResult orElse(), + }) { + if (loading != null) { + return loading(this); + } + return orElse(); + } +} + +abstract class _SettingsStateLoading implements SettingsState { + const factory _SettingsStateLoading() = _$_SettingsStateLoading; +} + +/// @nodoc +abstract class _$SetttingsStateDataCopyWith<$Res> { + factory _$SetttingsStateDataCopyWith( + _SetttingsStateData value, $Res Function(_SetttingsStateData) then) = + __$SetttingsStateDataCopyWithImpl<$Res>; + $Res call({SettingsDetails details}); + + $SettingsDetailsCopyWith<$Res> get details; +} + +/// @nodoc +class __$SetttingsStateDataCopyWithImpl<$Res> + extends _$SettingsStateCopyWithImpl<$Res> + implements _$SetttingsStateDataCopyWith<$Res> { + __$SetttingsStateDataCopyWithImpl( + _SetttingsStateData _value, $Res Function(_SetttingsStateData) _then) + : super(_value, (v) => _then(v as _SetttingsStateData)); + + @override + _SetttingsStateData get _value => super._value as _SetttingsStateData; + + @override + $Res call({ + Object? details = freezed, + }) { + return _then(_SetttingsStateData( + details: details == freezed + ? _value.details + : details // ignore: cast_nullable_to_non_nullable + as SettingsDetails, + )); + } + + @override + $SettingsDetailsCopyWith<$Res> get details { + return $SettingsDetailsCopyWith<$Res>(_value.details, (value) { + return _then(_value.copyWith(details: value)); + }); + } +} + +/// @nodoc + +class _$_SetttingsStateData implements _SetttingsStateData { + const _$_SetttingsStateData({required this.details}); + + @override + final SettingsDetails details; + + @override + String toString() { + return 'SettingsState.data(details: $details)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other is _SetttingsStateData && + (identical(other.details, details) || + const DeepCollectionEquality().equals(other.details, details))); + } + + @override + int get hashCode => + runtimeType.hashCode ^ const DeepCollectionEquality().hash(details); + + @JsonKey(ignore: true) + @override + _$SetttingsStateDataCopyWith<_SetttingsStateData> get copyWith => + __$SetttingsStateDataCopyWithImpl<_SetttingsStateData>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() loading, + required TResult Function(SettingsDetails details) data, + required TResult Function(String? error) error, + }) { + return data(details); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? loading, + TResult Function(SettingsDetails details)? data, + TResult Function(String? error)? error, + required TResult orElse(), + }) { + if (data != null) { + return data(details); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_SettingsStateInitial value) initial, + required TResult Function(_SettingsStateLoading value) loading, + required TResult Function(_SetttingsStateData value) data, + required TResult Function(_SettingsStateError value) error, + }) { + return data(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_SettingsStateInitial value)? initial, + TResult Function(_SettingsStateLoading value)? loading, + TResult Function(_SetttingsStateData value)? data, + TResult Function(_SettingsStateError value)? error, + required TResult orElse(), + }) { + if (data != null) { + return data(this); + } + return orElse(); + } +} + +abstract class _SetttingsStateData implements SettingsState { + const factory _SetttingsStateData({required SettingsDetails details}) = + _$_SetttingsStateData; + + SettingsDetails get details => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + _$SetttingsStateDataCopyWith<_SetttingsStateData> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$SettingsStateErrorCopyWith<$Res> { + factory _$SettingsStateErrorCopyWith( + _SettingsStateError value, $Res Function(_SettingsStateError) then) = + __$SettingsStateErrorCopyWithImpl<$Res>; + $Res call({String? error}); +} + +/// @nodoc +class __$SettingsStateErrorCopyWithImpl<$Res> + extends _$SettingsStateCopyWithImpl<$Res> + implements _$SettingsStateErrorCopyWith<$Res> { + __$SettingsStateErrorCopyWithImpl( + _SettingsStateError _value, $Res Function(_SettingsStateError) _then) + : super(_value, (v) => _then(v as _SettingsStateError)); + + @override + _SettingsStateError get _value => super._value as _SettingsStateError; + + @override + $Res call({ + Object? error = freezed, + }) { + return _then(_SettingsStateError( + error: error == freezed + ? _value.error + : error // ignore: cast_nullable_to_non_nullable + as String?, + )); + } +} + +/// @nodoc + +class _$_SettingsStateError implements _SettingsStateError { + const _$_SettingsStateError({this.error}); + + @override + final String? error; + + @override + String toString() { + return 'SettingsState.error(error: $error)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other is _SettingsStateError && + (identical(other.error, error) || + const DeepCollectionEquality().equals(other.error, error))); + } + + @override + int get hashCode => + runtimeType.hashCode ^ const DeepCollectionEquality().hash(error); + + @JsonKey(ignore: true) + @override + _$SettingsStateErrorCopyWith<_SettingsStateError> get copyWith => + __$SettingsStateErrorCopyWithImpl<_SettingsStateError>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() loading, + required TResult Function(SettingsDetails details) data, + required TResult Function(String? error) error, + }) { + return error(this.error); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? loading, + TResult Function(SettingsDetails details)? data, + TResult Function(String? error)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(this.error); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_SettingsStateInitial value) initial, + required TResult Function(_SettingsStateLoading value) loading, + required TResult Function(_SetttingsStateData value) data, + required TResult Function(_SettingsStateError value) error, + }) { + return error(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_SettingsStateInitial value)? initial, + TResult Function(_SettingsStateLoading value)? loading, + TResult Function(_SetttingsStateData value)? data, + TResult Function(_SettingsStateError value)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(this); + } + return orElse(); + } +} + +abstract class _SettingsStateError implements SettingsState { + const factory _SettingsStateError({String? error}) = _$_SettingsStateError; + + String? get error => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + _$SettingsStateErrorCopyWith<_SettingsStateError> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/models/trades/trade/trade.dart b/lib/models/trades/trade/trade.dart new file mode 100644 index 0000000..eee6686 --- /dev/null +++ b/lib/models/trades/trade/trade.dart @@ -0,0 +1,16 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; +part 'trade.freezed.dart'; + +@freezed +abstract class Trade with _$Trade { + const factory Trade( + String id, String timestamp, String price, String amount) = _Trade; + + factory Trade.fromJson(List json) { + final id = json[0].toString(); + final timestamp = json[1].toString(); + final price = json[2].toString(); + final amount = json[3].toString(); + return Trade(id, timestamp, price, amount); + } +} diff --git a/lib/models/trades/trade/trade.freezed.dart b/lib/models/trades/trade/trade.freezed.dart new file mode 100644 index 0000000..f456a68 --- /dev/null +++ b/lib/models/trades/trade/trade.freezed.dart @@ -0,0 +1,194 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides + +part of 'trade.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +/// @nodoc +class _$TradeTearOff { + const _$TradeTearOff(); + + _Trade call(String id, String timestamp, String price, String amount) { + return _Trade( + id, + timestamp, + price, + amount, + ); + } +} + +/// @nodoc +const $Trade = _$TradeTearOff(); + +/// @nodoc +mixin _$Trade { + String get id => throw _privateConstructorUsedError; + String get timestamp => throw _privateConstructorUsedError; + String get price => throw _privateConstructorUsedError; + String get amount => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $TradeCopyWith get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $TradeCopyWith<$Res> { + factory $TradeCopyWith(Trade value, $Res Function(Trade) then) = + _$TradeCopyWithImpl<$Res>; + $Res call({String id, String timestamp, String price, String amount}); +} + +/// @nodoc +class _$TradeCopyWithImpl<$Res> implements $TradeCopyWith<$Res> { + _$TradeCopyWithImpl(this._value, this._then); + + final Trade _value; + // ignore: unused_field + final $Res Function(Trade) _then; + + @override + $Res call({ + Object? id = freezed, + Object? timestamp = freezed, + Object? price = freezed, + Object? amount = freezed, + }) { + return _then(_value.copyWith( + id: id == freezed + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String, + timestamp: timestamp == freezed + ? _value.timestamp + : timestamp // ignore: cast_nullable_to_non_nullable + as String, + price: price == freezed + ? _value.price + : price // ignore: cast_nullable_to_non_nullable + as String, + amount: amount == freezed + ? _value.amount + : amount // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +abstract class _$TradeCopyWith<$Res> implements $TradeCopyWith<$Res> { + factory _$TradeCopyWith(_Trade value, $Res Function(_Trade) then) = + __$TradeCopyWithImpl<$Res>; + @override + $Res call({String id, String timestamp, String price, String amount}); +} + +/// @nodoc +class __$TradeCopyWithImpl<$Res> extends _$TradeCopyWithImpl<$Res> + implements _$TradeCopyWith<$Res> { + __$TradeCopyWithImpl(_Trade _value, $Res Function(_Trade) _then) + : super(_value, (v) => _then(v as _Trade)); + + @override + _Trade get _value => super._value as _Trade; + + @override + $Res call({ + Object? id = freezed, + Object? timestamp = freezed, + Object? price = freezed, + Object? amount = freezed, + }) { + return _then(_Trade( + id == freezed + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String, + timestamp == freezed + ? _value.timestamp + : timestamp // ignore: cast_nullable_to_non_nullable + as String, + price == freezed + ? _value.price + : price // ignore: cast_nullable_to_non_nullable + as String, + amount == freezed + ? _value.amount + : amount // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc + +class _$_Trade implements _Trade { + const _$_Trade(this.id, this.timestamp, this.price, this.amount); + + @override + final String id; + @override + final String timestamp; + @override + final String price; + @override + final String amount; + + @override + String toString() { + return 'Trade(id: $id, timestamp: $timestamp, price: $price, amount: $amount)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other is _Trade && + (identical(other.id, id) || + const DeepCollectionEquality().equals(other.id, id)) && + (identical(other.timestamp, timestamp) || + const DeepCollectionEquality() + .equals(other.timestamp, timestamp)) && + (identical(other.price, price) || + const DeepCollectionEquality().equals(other.price, price)) && + (identical(other.amount, amount) || + const DeepCollectionEquality().equals(other.amount, amount))); + } + + @override + int get hashCode => + runtimeType.hashCode ^ + const DeepCollectionEquality().hash(id) ^ + const DeepCollectionEquality().hash(timestamp) ^ + const DeepCollectionEquality().hash(price) ^ + const DeepCollectionEquality().hash(amount); + + @JsonKey(ignore: true) + @override + _$TradeCopyWith<_Trade> get copyWith => + __$TradeCopyWithImpl<_Trade>(this, _$identity); +} + +abstract class _Trade implements Trade { + const factory _Trade( + String id, String timestamp, String price, String amount) = _$_Trade; + + @override + String get id => throw _privateConstructorUsedError; + @override + String get timestamp => throw _privateConstructorUsedError; + @override + String get price => throw _privateConstructorUsedError; + @override + String get amount => throw _privateConstructorUsedError; + @override + @JsonKey(ignore: true) + _$TradeCopyWith<_Trade> get copyWith => throw _privateConstructorUsedError; +} diff --git a/lib/models/trades/trades_response.dart/trades_response.dart b/lib/models/trades/trades_response.dart/trades_response.dart new file mode 100644 index 0000000..7ce0057 --- /dev/null +++ b/lib/models/trades/trades_response.dart/trades_response.dart @@ -0,0 +1,15 @@ +import 'package:cryptocurrency_app/models/trades/trade/trade.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +part 'trades_response.freezed.dart'; + +@freezed +abstract class TradesResponse with _$TradesResponse { + const factory TradesResponse({List? result}) = _TradesResponse; + factory TradesResponse.fromJson(Map json) { + final List result = []; + json['result'].forEach((v) { + result.add(new Trade.fromJson(v)); + }); + return TradesResponse(result: result); + } +} diff --git a/lib/models/trades/trades_response.dart/trades_response.freezed.dart b/lib/models/trades/trades_response.dart/trades_response.freezed.dart new file mode 100644 index 0000000..809e38e --- /dev/null +++ b/lib/models/trades/trades_response.dart/trades_response.freezed.dart @@ -0,0 +1,142 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides + +part of 'trades_response.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +/// @nodoc +class _$TradesResponseTearOff { + const _$TradesResponseTearOff(); + + _TradesResponse call({List? result}) { + return _TradesResponse( + result: result, + ); + } +} + +/// @nodoc +const $TradesResponse = _$TradesResponseTearOff(); + +/// @nodoc +mixin _$TradesResponse { + List? get result => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $TradesResponseCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $TradesResponseCopyWith<$Res> { + factory $TradesResponseCopyWith( + TradesResponse value, $Res Function(TradesResponse) then) = + _$TradesResponseCopyWithImpl<$Res>; + $Res call({List? result}); +} + +/// @nodoc +class _$TradesResponseCopyWithImpl<$Res> + implements $TradesResponseCopyWith<$Res> { + _$TradesResponseCopyWithImpl(this._value, this._then); + + final TradesResponse _value; + // ignore: unused_field + final $Res Function(TradesResponse) _then; + + @override + $Res call({ + Object? result = freezed, + }) { + return _then(_value.copyWith( + result: result == freezed + ? _value.result + : result // ignore: cast_nullable_to_non_nullable + as List?, + )); + } +} + +/// @nodoc +abstract class _$TradesResponseCopyWith<$Res> + implements $TradesResponseCopyWith<$Res> { + factory _$TradesResponseCopyWith( + _TradesResponse value, $Res Function(_TradesResponse) then) = + __$TradesResponseCopyWithImpl<$Res>; + @override + $Res call({List? result}); +} + +/// @nodoc +class __$TradesResponseCopyWithImpl<$Res> + extends _$TradesResponseCopyWithImpl<$Res> + implements _$TradesResponseCopyWith<$Res> { + __$TradesResponseCopyWithImpl( + _TradesResponse _value, $Res Function(_TradesResponse) _then) + : super(_value, (v) => _then(v as _TradesResponse)); + + @override + _TradesResponse get _value => super._value as _TradesResponse; + + @override + $Res call({ + Object? result = freezed, + }) { + return _then(_TradesResponse( + result: result == freezed + ? _value.result + : result // ignore: cast_nullable_to_non_nullable + as List?, + )); + } +} + +/// @nodoc + +class _$_TradesResponse implements _TradesResponse { + const _$_TradesResponse({this.result}); + + @override + final List? result; + + @override + String toString() { + return 'TradesResponse(result: $result)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other is _TradesResponse && + (identical(other.result, result) || + const DeepCollectionEquality().equals(other.result, result))); + } + + @override + int get hashCode => + runtimeType.hashCode ^ const DeepCollectionEquality().hash(result); + + @JsonKey(ignore: true) + @override + _$TradesResponseCopyWith<_TradesResponse> get copyWith => + __$TradesResponseCopyWithImpl<_TradesResponse>(this, _$identity); +} + +abstract class _TradesResponse implements TradesResponse { + const factory _TradesResponse({List? result}) = _$_TradesResponse; + + @override + List? get result => throw _privateConstructorUsedError; + @override + @JsonKey(ignore: true) + _$TradesResponseCopyWith<_TradesResponse> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/provider/crypto_provider.dart b/lib/provider/crypto_provider.dart new file mode 100644 index 0000000..d85a089 --- /dev/null +++ b/lib/provider/crypto_provider.dart @@ -0,0 +1,133 @@ +import 'package:cryptocurrency_app/constants/exceptions.dart'; +import 'package:cryptocurrency_app/provider/time_provider.dart'; +import 'package:cryptocurrency_app/models/exchanges/exchange/exchange.dart'; +import 'package:cryptocurrency_app/models/graph/graph/graph.dart'; +import 'package:cryptocurrency_app/models/markets/favorite_pair/favorite_pair.dart'; +import 'package:cryptocurrency_app/models/markets/pair/pair.dart'; +import 'package:cryptocurrency_app/models/orderbook/orderbook/orderbook.dart'; +import 'package:cryptocurrency_app/models/pair/pair_summary/pair_summary.dart'; +import 'package:cryptocurrency_app/models/trades/trade/trade.dart'; +import 'package:cryptocurrency_app/provider/settings_provider.dart'; +import 'package:cryptocurrency_app/repository/crypto_repository.dart'; +import 'package:dio/dio.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import '../../generated/locale_keys.g.dart'; + +final pairsProvider = FutureProvider>((ref) async { + final settings = ref.watch(cryptoSettings); + String exchangeName = settings.maybeWhen( + data: (details) => details.favoriteExchange, + orElse: () => + throw DataException(message: LocaleKeys.errorSomethingWentWrong)); + List pairs = await ref.read(cryptoRepository).getPairs(exchangeName); + return pairs; +}); + +final searchTextProvider = StateProvider((ref) => ""); + +final pairsSearchProvider = FutureProvider>((ref) async { + final pairs = ref.watch(pairsProvider); + final search = ref.watch(searchTextProvider).state; + + List list = []; + pairs.maybeWhen( + data: (data) { + if (search.isNotEmpty) + list = + data.where((element) => element.pair.contains(search)).toList(); + else + list = data; + }, + orElse: () => {}); + return list; +}); + +final exchangesProvider = FutureProvider>((ref) async { + final cancelToken = CancelToken(); + ref.onDispose(() => cancelToken.cancel()); + + List exchanges = + await ref.read(cryptoRepository).getExchanges(cancelToken: cancelToken); + return exchanges; +}); + +final favoritePairProvider = FutureProvider((ref) async { + final cancelToken = CancelToken(); + ref.onDispose(() => cancelToken.cancel()); + + final settings = ref.watch(cryptoSettings); + String exchangeName = settings.maybeWhen( + data: (details) => details.favoriteExchange, orElse: () => ""); + String pairName = settings.maybeWhen( + data: (details) => details.favoritePair, orElse: () => ""); + + if (exchangeName.isEmpty || pairName.isEmpty) { + throw DataException(message: LocaleKeys.errorSomethingWentWrong); + } + + Pair pair = Pair(pair: pairName, exchange: exchangeName); + try { + PairSummary pairSummary = await ref + .read(cryptoRepository) + .getPairSummary(exchangeName, pairName, cancelToken: cancelToken); + return FavoritePair(pair: pair, pairSummary: pairSummary); + } on DataException catch (error) { + if (error.message == LocaleKeys.errorRequestNotFound) { + ref.read(cryptoSettings.notifier).verifyFavoritePair(); + } + throw error; + } +}); + +final pairSummaryProvider = + FutureProvider.family((ref, pair) async { + final cancelToken = CancelToken(); + ref.onDispose(() => cancelToken.cancel()); + + final pairSummary = await ref + .read(cryptoRepository) + .getPairSummary(pair.exchange, pair.pair, cancelToken: cancelToken); + return pairSummary; +}); + +final pairOrderBookProvider = + FutureProvider.family((ref, pair) async { + final cancelToken = CancelToken(); + ref.onDispose(() => cancelToken.cancel()); + + final orderBook = await ref + .read(cryptoRepository) + .getOrderBook(pair.exchange, pair.pair, cancelToken: cancelToken); + + return orderBook; +}); + +final tradesProvider = + FutureProvider.family, Pair>((ref, pair) async { + final cancelToken = CancelToken(); + ref.onDispose(() => cancelToken.cancel()); + + final trades = await ref + .read(cryptoRepository) + .getTrades(pair.exchange, pair.pair, cancelToken: cancelToken); + return trades; +}); + +final graphDataProvider = FutureProvider.family((ref, pair) async { + String interval = ref.watch(timeDataProvider).state.periods; + String fromHours = ref.watch(timeDataProvider).state.before; + String before = ""; + if (fromHours.isNotEmpty) { + before = (DateTime.now() + .subtract(Duration(hours: int.parse(fromHours))) + .toUtc() + .millisecondsSinceEpoch ~/ + 1000) + .toString(); + } + + final graph = await ref.read(cryptoRepository).getPairGraph( + pair.exchange, pair.pair, + periods: interval, before: before); + return graph; +}); diff --git a/lib/provider/navigation_provider.dart b/lib/provider/navigation_provider.dart new file mode 100644 index 0000000..50619cc --- /dev/null +++ b/lib/provider/navigation_provider.dart @@ -0,0 +1,31 @@ +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +final navigationProvider = StateNotifierProvider((ref) => NavigationNotifier()); + +enum NavigationBarEvent { HOME, SEARCH, SETTINGS } + +class NavigationNotifier extends StateNotifier { + NavigationNotifier() : super(defaultPage); + + static const defaultPage = PageModel(NavigationBarEvent.HOME, 0); + + void selectPage(int i) { + switch (i) { + case 0: + state = PageModel(NavigationBarEvent.HOME, i); + break; + case 1: + state = PageModel(NavigationBarEvent.SEARCH, i); + break; + case 2: + state = PageModel(NavigationBarEvent.SETTINGS, i); + break; + } + } +} + +class PageModel { + const PageModel(this.page, this.index); + final NavigationBarEvent page; + final index; +} diff --git a/lib/provider/settings_provider.dart b/lib/provider/settings_provider.dart new file mode 100644 index 0000000..f40d36f --- /dev/null +++ b/lib/provider/settings_provider.dart @@ -0,0 +1,85 @@ +import 'package:cryptocurrency_app/constants/exceptions.dart'; +import 'package:cryptocurrency_app/constants/utils.dart' as Utils; +import 'package:cryptocurrency_app/models/markets/pair/pair.dart'; +import 'package:cryptocurrency_app/models/settings/settings_details/settings_details.dart'; +import 'package:cryptocurrency_app/models/settings/settings_state/settings_state.dart'; +import 'package:cryptocurrency_app/repository/crypto_repository.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import '../../generated/locale_keys.g.dart'; + +final flutterDatabase = + Provider((ref) => FlutterSecureStorage()); + +final cryptoSettings = StateNotifierProvider( + (ref) => SettingsNotifier(ref.read)); + +class SettingsNotifier extends StateNotifier { + final Reader read; + + late SettingsDetails details; + + SettingsNotifier(this.read) : super(SettingsState.initial()) { + loadData(); + } + + void loadData() async { + state = SettingsState.loading(); + final language = (await read(flutterDatabase).read(key: "language")) ?? + Utils.defaultLenguage; + final exchange = (await read(flutterDatabase).read(key: "exchange")) ?? + Utils.defaultExchange; + final pair = + (await read(flutterDatabase).read(key: "pair")) ?? Utils.defaultPair; + final theme = + (await read(flutterDatabase).read(key: "theme")) ?? Utils.defaultTheme; + details = SettingsDetails( + currentLanguage: language, + favoriteExchange: exchange, + favoritePair: pair, + themeMode: theme); + state = SettingsState.data(details: details); + } + + void setLenguage(String language) async { + state = SettingsState.loading(); + await read(flutterDatabase).write(key: "language", value: language); + details = details.copyWith(currentLanguage: language); + state = SettingsState.data(details: details); + } + + Future setFavoriteExchange(String exchange) async { + state = SettingsState.loading(); + await read(flutterDatabase).write(key: "exchange", value: exchange); + details = details.copyWith(favoriteExchange: exchange); + state = SettingsState.data(details: details); + verifyFavoritePair(); + } + + Future verifyFavoritePair() async { + try { + await read(cryptoRepository) + .getPairSummary(details.favoriteExchange, details.favoritePair); + } on DataException catch (error) { + if (error.message == LocaleKeys.errorRequestNotFound) { + List pairs = + await read(cryptoRepository).getPairs(details.favoriteExchange); + setFavoritePair(pairs.first.pair); + } + } + } + + Future setFavoritePair(String pair) async { + state = SettingsState.loading(); + await read(flutterDatabase).write(key: "pair", value: pair); + details = details.copyWith(favoritePair: pair); + state = SettingsState.data(details: details); + } + + void setTheme(String theme) async { + state = SettingsState.loading(); + await read(flutterDatabase).write(key: "theme", value: theme); + details = details.copyWith(themeMode: theme); + state = SettingsState.data(details: details); + } +} diff --git a/lib/provider/time_provider.dart b/lib/provider/time_provider.dart new file mode 100644 index 0000000..268ffa8 --- /dev/null +++ b/lib/provider/time_provider.dart @@ -0,0 +1,20 @@ +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +class TimeGraphData { + String name; + String periods; + String before; + TimeGraphData(this.name, this.periods, this.before); +} + +final timeList = [ + TimeGraphData("1H", "60", "1"), + TimeGraphData("1D", "300", "24"), + TimeGraphData("1W", "1800", "168"), + TimeGraphData("1M", "3600", "730"), + TimeGraphData("1Y", "86400", "8760"), + TimeGraphData("ALL", "", "") +]; + +final timeDataProvider = + StateProvider((ref) => TimeGraphData("1M", "60", "12")); diff --git a/lib/repository/crypto_repository.dart b/lib/repository/crypto_repository.dart new file mode 100644 index 0000000..e33a04c --- /dev/null +++ b/lib/repository/crypto_repository.dart @@ -0,0 +1,118 @@ +import 'package:cryptocurrency_app/constants/exceptions.dart'; +import 'package:cryptocurrency_app/models/exchanges/exchange/exchange.dart'; +import 'package:cryptocurrency_app/models/exchanges/exchanges_response/exchanges_response.dart'; +import 'package:cryptocurrency_app/models/graph/graph/graph.dart'; +import 'package:cryptocurrency_app/models/graph/graph_response/graph_response.dart'; +import 'package:cryptocurrency_app/models/markets/market_response/market_response.dart'; +import 'package:cryptocurrency_app/models/markets/pair/pair.dart'; +import 'package:cryptocurrency_app/models/orderbook/orderbook/orderbook.dart'; +import 'package:cryptocurrency_app/models/orderbook/orderbook_response/orderbook_response.dart'; +import 'package:cryptocurrency_app/models/pair/pair_response/pair_response.dart'; +import 'package:cryptocurrency_app/models/pair/pair_summary/pair_summary.dart'; +import 'package:cryptocurrency_app/models/trades/trade/trade.dart'; +import 'package:cryptocurrency_app/models/trades/trades_response.dart/trades_response.dart'; +import 'package:dio/dio.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +import 'package:flutter_dotenv/flutter_dotenv.dart'; + +final clientProvider = Provider((ref) => Dio(BaseOptions(headers: { + "X-CW-API-Key": env['API_KEY'], + }, baseUrl: 'https://api.cryptowat.ch'))); + +final cryptoRepository = + Provider((ref) => CryptoRepositoryAPI(ref.read)); + +abstract class CryptoRepository { + Future> getPairs(String market); + Future getPairSummary(String makeret, String pair); + Future getPairGraph(String market, String pair, + {String periods, String after, String before}); + Future> getExchanges(); + Future getOrderBook(String market, String pair); + Future> getTrades(String market, String pair); +} + +class CryptoRepositoryAPI implements CryptoRepository { + final Reader read; + CryptoRepositoryAPI(this.read); + + @override + Future> getPairs(String market, {CancelToken? cancelToken}) async { + try { + final response = await read(clientProvider) + .get('/markets/$market', cancelToken: cancelToken); + return MarketResponse.fromJson(response.data).result; + } on DioError catch (error) { + throw DataException.fromDioError(error); + } + } + + @override + Future getPairSummary(String market, String pair, + {CancelToken? cancelToken}) async { + try { + final response = await read(clientProvider) + .get('/markets/$market/$pair/summary', cancelToken: cancelToken); + return PairResponse.fromJson(response.data).result; + } on DioError catch (error) { + throw DataException.fromDioError(error); + } + } + + @override + Future getOrderBook(String market, String pair, + {CancelToken? cancelToken}) async { + try { + final response = await read(clientProvider) + .get('/markets/$market/$pair/orderbook', cancelToken: cancelToken); + return OrderBookResponse.fromJson(response.data).result; + } on DioError catch (error) { + throw DataException.fromDioError(error); + } + } + + @override + Future> getTrades(String market, String pair, + {CancelToken? cancelToken}) async { + try { + final response = await read(clientProvider) + .get('/markets/$market/$pair/trades', cancelToken: cancelToken); + return TradesResponse.fromJson(response.data).result!; + } on DioError catch (error) { + throw DataException.fromDioError(error); + } + } + + @override + Future getPairGraph(String market, String pair, + {String periods = "", + String after = "", + String before = "", + CancelToken? cancelToken}) async { + try { + final response = await read(clientProvider).get( + '/markets/$market/$pair/ohlc', + queryParameters: { + "periods": periods, + "after": after, + "before": before + }, + cancelToken: cancelToken); + return GraphResponse.fromJson(response.data).result; + } on DioError catch (error) { + throw DataException.fromDioError(error); + } + } + + @override + Future> getExchanges({CancelToken? cancelToken}) async { + try { + final response = await read(clientProvider) + .get('/exchanges', cancelToken: cancelToken); + return ExchangesResponse.fromJson(response.data).result; + } on DioError catch (error) { + throw DataException.fromDioError(error); + } + } +} diff --git a/lib/ui/home.dart b/lib/ui/home.dart new file mode 100644 index 0000000..78855de --- /dev/null +++ b/lib/ui/home.dart @@ -0,0 +1,65 @@ +import 'package:cryptocurrency_app/constants/keys.dart'; +import 'package:cryptocurrency_app/provider/navigation_provider.dart'; +import 'package:cryptocurrency_app/ui/screens/home.dart'; +import 'package:cryptocurrency_app/ui/screens/search.dart'; +import 'package:cryptocurrency_app/ui/screens/settings.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:easy_localization/easy_localization.dart'; + +import '../generated/locale_keys.g.dart'; + +class Home extends HookWidget { + const Home({Key? key}) : super(key: key); + @override + Widget build(BuildContext context) { + final navigation = useProvider(navigationProvider); + + return Scaffold( + body: currentScreen(navigation.index), + bottomNavigationBar: BottomNavigationBar( + key: Keys.NAV_BAR, + currentIndex: navigation.index, + onTap: (index) { + context.read(navigationProvider.notifier).selectPage(index); + }, + items: [ + BottomNavigationBarItem( + label: LocaleKeys.homeTitle.tr(), + icon: Icon( + Icons.home, + key: Keys.NAV_HOME, + ), + ), + BottomNavigationBarItem( + label: LocaleKeys.searchTitle.tr(), + icon: Icon( + Icons.search, + key: Keys.NAV_SEARCH, + ), + ), + BottomNavigationBarItem( + label: LocaleKeys.settingsTitle.tr(), + icon: Icon( + Icons.settings, + key: Keys.NAV_SETTINGS, + ), + ), + ]), + ); + } + + Widget currentScreen(int index) { + switch (index) { + case 0: + return HomeScreen(); + case 1: + return SearchScreen(); + case 2: + return SettingScreen(); + default: + return HomeScreen(); + } + } +} diff --git a/lib/ui/screens/details.dart b/lib/ui/screens/details.dart new file mode 100644 index 0000000..64cc9ce --- /dev/null +++ b/lib/ui/screens/details.dart @@ -0,0 +1,70 @@ +import 'package:cryptocurrency_app/constants/keys.dart'; +import 'package:cryptocurrency_app/constants/utils.dart' as Utils; +import 'package:cryptocurrency_app/models/markets/pair/pair.dart'; +import 'package:cryptocurrency_app/provider/crypto_provider.dart'; +import 'package:cryptocurrency_app/ui/widgets/details/details_widget.dart'; +import 'package:cryptocurrency_app/ui/widgets/details/time_bar_selector.dart'; +import 'package:cryptocurrency_app/ui/widgets/line_chart.dart'; +import 'package:cryptocurrency_app/ui/widgets/title_price.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +class DetailsScreen extends HookWidget { + final Pair pair; + DetailsScreen({required this.pair}); + + @override + Widget build(BuildContext context) { + final graph = useProvider(graphDataProvider(pair)); + + return Scaffold( + key: Keys.DETAILS_SCREEN, + appBar: AppBar( + actions: [ + Container( + width: 120, + margin: EdgeInsets.symmetric(vertical: 6, horizontal: 5), + ) + ], + ), + body: Container( + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + height: 5, + ), + Container( + padding: EdgeInsets.symmetric(horizontal: 15), + child: TitlePrice(pair: pair)), + SizedBox( + height: 20, + ), + Container( + height: 250, + child: graph.when( + data: (data) => + LineChartWidget(data: Utils.getPoints(data)), + loading: () => LineChartWidget(loading: true), + error: (e, ex) => LineChartWidget(error: true)), + ), + SizedBox( + height: 20, + ), + TimeBarSelector(), + SizedBox( + height: 15, + ), + DetailsWidget(pair: pair), + SizedBox( + height: 30, + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/ui/screens/home.dart b/lib/ui/screens/home.dart new file mode 100644 index 0000000..d761929 --- /dev/null +++ b/lib/ui/screens/home.dart @@ -0,0 +1,91 @@ +import 'package:cryptocurrency_app/constants/keys.dart'; +import 'package:cryptocurrency_app/provider/crypto_provider.dart'; +import 'package:cryptocurrency_app/ui/widgets/favorite_pair.dart'; +import 'package:cryptocurrency_app/ui/widgets/pair_tile.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/src/widgets/framework.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:easy_localization/easy_localization.dart'; +import '../../generated/locale_keys.g.dart'; + +class HomeScreen extends HookWidget { + @override + Widget build(BuildContext context) { + final pairs = useProvider(pairsProvider); + final favoritePair = useProvider(favoritePairProvider); + return Container( + key: Keys.HOME_SCREEN, + child: Column( + children: [ + AppBar( + toolbarHeight: 65, + centerTitle: false, + title: Text( + LocaleKeys.homeTitle.tr(), + style: TextStyle(color: Colors.white, fontSize: 25), + ), + actions: [ + Container( + margin: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(50)), + width: 45, + child: Icon( + Icons.person_outline, + size: 30, + color: Colors.black, + ), + ), + ], + ), + Expanded( + child: Column( + children: [ + Container( + height: 190, + child: favoritePair.when( + data: (data) { + return FavoritePairWidget(data); + }, + loading: () => Center( + child: CircularProgressIndicator(), + ), + error: (error, e) => Center( + child: Text(error.toString().tr()), + ), + ), + ), + Expanded( + child: pairs.when( + data: (data) { + return Container( + child: ListView.builder( + padding: EdgeInsets.only(top: 0.0), + itemCount: data.length, + itemBuilder: (ctx, int idx) => ProviderScope( + overrides: [ + currentPair.overrideWithValue(data[idx]), + ], + child: const PairTile(), + ), + ), + ); + }, + loading: () => Center( + child: CircularProgressIndicator(), + ), + error: (error, e) => Center( + child: Text(error.toString().tr()), + ), + ), + ) + ], + ), + ), + ], + ), + ); + } +} diff --git a/lib/ui/screens/search.dart b/lib/ui/screens/search.dart new file mode 100644 index 0000000..5ebc4d0 --- /dev/null +++ b/lib/ui/screens/search.dart @@ -0,0 +1,77 @@ +import 'package:cryptocurrency_app/constants/keys.dart'; +import 'package:cryptocurrency_app/provider/crypto_provider.dart'; +import 'package:cryptocurrency_app/ui/widgets/pair_tile.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:easy_localization/easy_localization.dart'; +import '../../generated/locale_keys.g.dart'; + +class SearchScreen extends HookWidget { + @override + Widget build(BuildContext context) { + final pairs = useProvider(pairsSearchProvider); + + return Container( + key: Keys.SEARCH_SCREEN, + child: Column( + children: [ + AppBar( + title: Text(LocaleKeys.searchTitle.tr()), + ), + Expanded( + child: Column( + children: [ + Container( + height: 50, + padding: EdgeInsets.symmetric(horizontal: 15), + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(5)), + color: Theme.of(context).cardColor, + ), + child: TextFormField( + key: Keys.SEARCH_TEXT_FIELD, + initialValue: context.read(searchTextProvider).state, + style: TextStyle(color: Colors.white, fontSize: 21), + decoration: new InputDecoration( + prefixIcon: new Icon(Icons.search, + color: Colors.white, size: 32), + hintText: LocaleKeys.searchBar.tr(), + hintStyle: new TextStyle(color: Colors.white), + border: InputBorder.none), + onChanged: (value) => + {context.read(searchTextProvider).state = value}, + ), + ), + Expanded( + child: pairs.maybeWhen( + data: (data) { + return Stack( + children: [ + ListView.builder( + padding: EdgeInsets.zero, + itemCount: data.length, + itemBuilder: (ctx, int id) => ProviderScope( + overrides: [ + currentPair.overrideWithValue(data[id]), + ], + child: const PairTile(), + ), + ), + if (data.length == 0) + Center(child: Text(LocaleKeys.noResults.tr())) + ], + ); + }, + orElse: () => Center( + child: CircularProgressIndicator(), + )), + ) + ], + ), + ), + ], + ), + ); + } +} diff --git a/lib/ui/screens/settings.dart b/lib/ui/screens/settings.dart new file mode 100644 index 0000000..1fe8a86 --- /dev/null +++ b/lib/ui/screens/settings.dart @@ -0,0 +1,265 @@ +import 'package:cryptocurrency_app/constants/keys.dart'; +import 'package:cryptocurrency_app/models/exchanges/exchange/exchange.dart'; +import 'package:cryptocurrency_app/models/markets/pair/pair.dart'; +import 'package:cryptocurrency_app/provider/crypto_provider.dart'; +import 'package:cryptocurrency_app/provider/settings_provider.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:settings_ui/settings_ui.dart'; +import '../../generated/locale_keys.g.dart'; +import 'package:cryptocurrency_app/constants/utils.dart' as Utils; + +class SettingScreen extends HookWidget { + @override + Widget build(BuildContext context) { + final settings = useProvider(cryptoSettings); + final exchanges = useProvider(exchangesProvider); + final pairs = useProvider(pairsProvider); + + final details = + settings.maybeWhen(data: (details) => details, orElse: () => null); + + return details != null + ? Container( + key: Keys.SETTINGS_SCREEN, + child: Column( + children: [ + AppBar( + title: Text( + LocaleKeys.settingsTitle.tr(), + ), + ), + Expanded( + child: SettingsList( + contentPadding: EdgeInsets.zero, + sections: [ + SettingsSection( + title: LocaleKeys.languageSection.tr(), + tiles: [ + SettingsTile( + title: LocaleKeys.language.tr(), + subtitle: details.currentLanguage.tr(), + leading: Icon(Icons.language), + onPressed: (BuildContext ctx) => + showLenguageSelectionDialog( + context, details.currentLanguage)), + ], + ), + SettingsSection( + title: LocaleKeys.dataSection.tr(), + tiles: [ + SettingsTile( + title: LocaleKeys.exchange.tr(), + subtitle: details.favoriteExchange, + leading: Icon(Icons.graphic_eq), + onPressed: (BuildContext context) => + showExchangeSelectDialog(context, exchanges), + ), + SettingsTile( + title: LocaleKeys.topPair.tr(), + subtitle: details.favoritePair, + leading: Icon(Icons.language), + onPressed: (BuildContext context) => + showTopPairSelectDialog(context, pairs)), + ], + ), + SettingsSection( + title: LocaleKeys.designSection.tr(), + tiles: [ + SettingsTile( + title: LocaleKeys.appTheme.tr(), + subtitle: details.themeMode, + leading: Icon(Icons.graphic_eq), + onPressed: (BuildContext context) => + showThemeSelectDialog( + context, details.themeMode), + ), + ], + ), + ], + ), + ), + ], + ), + ) + : CircularProgressIndicator(); + } + + void showLenguageSelectionDialog( + BuildContext context, String currentLenguage) { + showDialog( + context: context, + builder: (_) => AlertDialog( + title: Text(LocaleKeys.language.tr()), + content: Container( + height: 100, + child: Column( + children: [ + Row( + children: [ + Radio( + value: currentLenguage, + groupValue: LocaleKeys.english, + onChanged: (value) async { + await context.setLocale(Locale('en')); + + context + .read(cryptoSettings.notifier) + .setLenguage(LocaleKeys.english); + + Navigator.pop(context); + }, + ), + Text( + LocaleKeys.english.tr(), + style: TextStyle(fontSize: 18), + ) + ], + ), + Row( + children: [ + Radio( + value: currentLenguage, + groupValue: LocaleKeys.spanish, + onChanged: (value) async { + await context.setLocale(Locale('es')); + context + .read(cryptoSettings.notifier) + .setLenguage(LocaleKeys.spanish); + Navigator.pop(context); + }, + ), + Text( + LocaleKeys.spanish.tr(), + style: TextStyle(fontSize: 18), + ), + ], + ), + ], + ), + ), + ), + ); + } + + void showExchangeSelectDialog( + BuildContext context, AsyncValue> exchanges) { + showDialog( + context: context, + builder: (context) { + return AlertDialog( + content: Container( + height: 300, + width: 200, + child: exchanges.maybeWhen( + data: (data) => ListView.builder( + itemCount: data.length, + itemBuilder: (context, index) { + return GestureDetector( + onTap: () { + context + .read(cryptoSettings.notifier) + .setFavoriteExchange(data[index].symbol); + + Navigator.pop(context); + }, + child: Container( + padding: EdgeInsets.symmetric(vertical: 3), + child: Text( + data[index].name, + style: TextStyle(fontSize: 18), + ), + ), + ); + }, + ), + orElse: () => CircularProgressIndicator()), + ), + ); + }); + } + + void showTopPairSelectDialog( + BuildContext context, AsyncValue> pairs) { + showDialog( + context: context, + builder: (context) { + return AlertDialog( + content: Container( + height: 300, + width: 200, + child: pairs.maybeWhen( + data: (data) { + return ListView.builder( + itemCount: data.length, + itemBuilder: (context, index) { + return Container( + child: Row( + children: [ + GestureDetector( + onTap: () { + context + .read(cryptoSettings.notifier) + .setFavoritePair(data[index].pair); + Navigator.pop(context); + }, + child: Container( + padding: EdgeInsets.symmetric(vertical: 3), + child: Text(data[index].pair, + style: TextStyle(fontSize: 18)), + ), + ) + ], + ), + ); + }, + ); + }, + orElse: () => Center( + child: CircularProgressIndicator(), + ))), + ); + }); + } + + void showThemeSelectDialog(BuildContext context, currentTheme) { + showDialog( + context: context, + builder: (context) { + return AlertDialog( + content: Container( + height: 150, + child: Column( + children: Utils.themeModes + .map((data) => GestureDetector( + onTap: () { + context + .read(cryptoSettings.notifier) + .setTheme(data); + Navigator.pop(context); + }, + child: Row( + children: [ + Radio( + onChanged: (value) { + context + .read(cryptoSettings.notifier) + .setTheme(value!); + Navigator.pop(context); + }, + value: data, + groupValue: currentTheme, + ), + Text(data, style: TextStyle(fontSize: 18)) + ], + ), + )) + .toList(), + ), + ), + ); + }); + } +} diff --git a/lib/ui/widgets/details/details_widget.dart b/lib/ui/widgets/details/details_widget.dart new file mode 100644 index 0000000..f906759 --- /dev/null +++ b/lib/ui/widgets/details/details_widget.dart @@ -0,0 +1,100 @@ +import 'package:cryptocurrency_app/models/markets/pair/pair.dart'; +import 'package:cryptocurrency_app/provider/crypto_provider.dart'; +import 'package:cryptocurrency_app/ui/widgets/details/summary_section.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:easy_localization/easy_localization.dart'; +import '../../../generated/locale_keys.g.dart'; + +import 'ohlc_section.dart'; +import 'order_book_section.dart'; +import 'trades_section.dart'; + +class DetailsWidget extends HookWidget { + final Pair pair; + const DetailsWidget({Key? key, required this.pair}) : super(key: key); + + @override + Widget build(BuildContext context) { + final _controller = useTabController(initialLength: 4); + final graph = useProvider(graphDataProvider(pair)); + final summary = useProvider(pairSummaryProvider(pair)); + final orderBook = useProvider(pairOrderBookProvider(pair)); + final trades = useProvider(tradesProvider(pair)); + + return Container( + child: Column( + children: [ + TabBar( + labelColor: Theme.of(context).focusColor, + unselectedLabelColor: Theme.of(context).unselectedWidgetColor, + unselectedLabelStyle: Theme.of(context).textTheme.headline4, + labelStyle: Theme.of(context).textTheme.headline4, + indicatorWeight: 4, + indicatorSize: TabBarIndicatorSize.label, + indicatorColor: Theme.of(context).focusColor, + isScrollable: true, + controller: _controller, + tabs: [ + Container( + width: 100, + child: Tab( + text: LocaleKeys.summary.tr(), + )), + Tab( + text: LocaleKeys.orderbook.tr(), + ), + Tab(text: LocaleKeys.trades.tr()), + Tab( + text: LocaleKeys.ohlc.tr(), + ), + ], + ), + Container( + height: 300, + child: TabBarView( + controller: _controller, + children: [ + summary.when( + data: (data) => SummarySection(data: data), + loading: () => Center( + child: CircularProgressIndicator(), + ), + error: (error, e) => Center( + child: Text(error.toString().tr()), + )), + orderBook.when( + data: (data) => OrderBookSection(data: data), + loading: () => Center( + child: CircularProgressIndicator(), + ), + error: (error, e) => Center( + child: Text(error.toString().tr()), + )), + trades.when( + data: (data) => TradesSection(data: data), + loading: () => Center( + child: CircularProgressIndicator(), + ), + error: (error, e) => Center( + child: Text(error.toString().tr()), + )), + graph.when( + data: (data) => OHLCSection( + data: data, + ), + loading: () => Center( + child: CircularProgressIndicator(), + ), + error: (error, e) => Center( + child: Text(error.toString().tr()), + )), + ], + ), + ), + ], + ), + ); + } +} diff --git a/lib/ui/widgets/details/ohlc_section.dart b/lib/ui/widgets/details/ohlc_section.dart new file mode 100644 index 0000000..b66b740 --- /dev/null +++ b/lib/ui/widgets/details/ohlc_section.dart @@ -0,0 +1,30 @@ +import 'package:cryptocurrency_app/models/graph/graph/graph.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/src/widgets/framework.dart'; +import 'package:flutter_candlesticks/flutter_candlesticks.dart'; + +class OHLCSection extends StatelessWidget { + final Graph data; + const OHLCSection({Key? key, required this.data}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + margin: EdgeInsets.symmetric(horizontal: 30, vertical: 40), + child: new OHLCVGraph( + data: data.pairs[0].points + .map((e) => { + "open": e.openTime, + "high": e.highPrice, + "low": e.lowPrice, + "close": e.closePrice, + "volumeto": e.volume + }) + .toList(), + enableGridLines: true, + volumeProp: 0.2, + gridLineAmount: 5, + gridLineColor: Colors.grey[300]!, + gridLineLabelColor: Colors.grey)); + } +} diff --git a/lib/ui/widgets/details/order_book_section.dart b/lib/ui/widgets/details/order_book_section.dart new file mode 100644 index 0000000..7a3bfa7 --- /dev/null +++ b/lib/ui/widgets/details/order_book_section.dart @@ -0,0 +1,96 @@ +import 'package:cryptocurrency_app/models/orderbook/orderbook/orderbook.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/src/widgets/framework.dart'; +import 'package:easy_localization/easy_localization.dart'; +import '../../../generated/locale_keys.g.dart'; + +class OrderBookSection extends StatelessWidget { + final OrderBook data; + OrderBookSection({Key? key, required this.data}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10), + child: Column( + mainAxisSize: MainAxisSize.max, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Text( + LocaleKeys.bid.tr(), + style: Theme.of(context).textTheme.subtitle2, + ), + Text( + LocaleKeys.ask.tr(), + style: Theme.of(context).textTheme.subtitle2, + ) + ], + ), + SizedBox( + height: 10, + ), + Container( + height: 220, + child: Row( + children: [ + Flexible( + flex: 1, + child: ListView.builder( + itemCount: data.bids.length, + itemBuilder: (context, index) { + return Container( + margin: EdgeInsets.symmetric(vertical: 2), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + data.bids[index].amount.toString(), + style: Theme.of(context).textTheme.subtitle1, + ), + Text( + data.bids[index].price.toString(), + style: Theme.of(context).textTheme.subtitle1, + ) + ], + ), + ); + }, + ), + ), + SizedBox( + width: 30, + ), + Flexible( + flex: 1, + child: ListView.builder( + itemCount: data.asks.length, + itemBuilder: (context, index) { + return Container( + margin: EdgeInsets.symmetric(vertical: 2), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + data.asks[index].amount.toString(), + style: Theme.of(context).textTheme.subtitle1, + ), + Text( + data.asks[index].price.toString(), + style: Theme.of(context).textTheme.subtitle1, + ) + ], + ), + ); + }, + ), + ) + ], + ), + ) + ], + ), + ); + } +} diff --git a/lib/ui/widgets/details/summary_section.dart b/lib/ui/widgets/details/summary_section.dart new file mode 100644 index 0000000..189782e --- /dev/null +++ b/lib/ui/widgets/details/summary_section.dart @@ -0,0 +1,121 @@ +import 'package:cryptocurrency_app/models/pair/pair_summary/pair_summary.dart'; +import 'package:flutter/material.dart'; +import 'package:easy_localization/easy_localization.dart'; +import '../../../generated/locale_keys.g.dart'; + +class SummarySection extends StatelessWidget { + final PairSummary data; + const SummarySection({Key? key, required this.data}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + padding: EdgeInsets.symmetric(horizontal: 20, vertical: 15), + child: Column( + children: [ + Row( + children: [ + Text( + LocaleKeys.price.tr(), + style: Theme.of(context).textTheme.subtitle2, + ) + ], + ), + SizedBox(height: 5), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + LocaleKeys.last.tr(), + style: Theme.of(context).textTheme.subtitle1, + ), + Text( + data.price.last.toString(), + style: Theme.of(context).textTheme.subtitle1, + ) + ], + ), + SizedBox(height: 5), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + LocaleKeys.high.tr(), + style: Theme.of(context).textTheme.subtitle1, + ), + Text( + data.price.high.toString(), + style: Theme.of(context).textTheme.subtitle1, + ) + ], + ), + SizedBox(height: 5), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + LocaleKeys.low.tr(), + style: Theme.of(context).textTheme.subtitle1, + ), + Text( + data.price.low.toString(), + style: Theme.of(context).textTheme.subtitle1, + ) + ], + ), + SizedBox(height: 5), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + LocaleKeys.change.tr(), + style: Theme.of(context).textTheme.subtitle1, + ), + Text( + data.price.change.absolute.toString(), + style: Theme.of(context).textTheme.subtitle1, + ) + ], + ), + SizedBox(height: 10), + Row( + children: [ + Text( + LocaleKeys.volume.tr(), + style: Theme.of(context).textTheme.subtitle2, + ) + ], + ), + SizedBox(height: 5), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + LocaleKeys.volume.tr(), + style: Theme.of(context).textTheme.subtitle1, + ), + Text( + data.volume.toString(), + style: Theme.of(context).textTheme.subtitle1, + ) + ], + ), + SizedBox(height: 5), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + LocaleKeys.quoteVolume.tr(), + style: Theme.of(context).textTheme.subtitle1, + ), + Text( + data.volumeQuote.toString(), + style: Theme.of(context).textTheme.subtitle1, + ) + ], + ), + ], + ), + ); + } +} diff --git a/lib/ui/widgets/details/time_bar_selector.dart b/lib/ui/widgets/details/time_bar_selector.dart new file mode 100644 index 0000000..5f5bc10 --- /dev/null +++ b/lib/ui/widgets/details/time_bar_selector.dart @@ -0,0 +1,54 @@ +import 'package:cryptocurrency_app/provider/time_provider.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/src/widgets/framework.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +class TimeBarSelector extends HookWidget { + @override + Widget build(BuildContext context) { + final time = useProvider(timeDataProvider); + + return Container( + padding: EdgeInsets.symmetric(horizontal: 15), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + crossAxisAlignment: CrossAxisAlignment.center, + children: timeList + .mapIndexed( + (e, i) => InkWell( + onTap: () { + time.state = e; + }, + child: Container( + padding: EdgeInsets.symmetric(vertical: 3, horizontal: 8), + decoration: BoxDecoration( + color: time.state.name == e.name + ? Theme.of(context).cardColor + : Colors.transparent, + borderRadius: BorderRadius.all(Radius.circular(5))), + child: Center( + child: Text( + e.name, + style: time.state.name == e.name + ? Theme.of(context) + .textTheme + .headline3! + .apply(color: Colors.white) + : Theme.of(context).textTheme.headline4, + ), + ), + ), + ), + ) + .toList()), + ); + } +} + +extension IndexedIterable on Iterable { + Iterable mapIndexed(T Function(E e, int i) f) { + var i = 0; + return map((e) => f(e, i++)); + } +} diff --git a/lib/ui/widgets/details/trades_section.dart b/lib/ui/widgets/details/trades_section.dart new file mode 100644 index 0000000..59ed979 --- /dev/null +++ b/lib/ui/widgets/details/trades_section.dart @@ -0,0 +1,86 @@ +import 'package:cryptocurrency_app/models/trades/trade/trade.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/src/widgets/framework.dart'; +import 'package:easy_localization/easy_localization.dart'; +import '../../../generated/locale_keys.g.dart'; +import '../../../constants/utils.dart' as Utils; + +class TradesSection extends StatelessWidget { + final List data; + const TradesSection({Key? key, required this.data}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10), + child: Column( + children: [ + Row( + children: [ + Expanded( + child: Text( + LocaleKeys.time.tr(), + style: Theme.of(context).textTheme.subtitle2, + ), + ), + Expanded( + child: Text( + LocaleKeys.price.tr(), + textAlign: TextAlign.center, + style: Theme.of(context).textTheme.subtitle2, + ), + ), + Expanded( + child: Text( + LocaleKeys.amount.tr(), + textAlign: TextAlign.right, + style: Theme.of(context).textTheme.subtitle2, + ), + ) + ], + ), + SizedBox( + height: 4, + ), + Container( + height: 250, + child: ListView.builder( + itemCount: 4, + itemBuilder: (context, index) { + return Container( + padding: EdgeInsets.symmetric(vertical: 2), + child: Row( + children: [ + Expanded( + flex: 1, + child: Text( + Utils.epochToString(data[index].timestamp), + style: Theme.of(context).textTheme.subtitle1, + ), + ), + Expanded( + flex: 1, + child: Text( + data[index].price, + textAlign: TextAlign.center, + style: Theme.of(context).textTheme.subtitle1, + ), + ), + Expanded( + flex: 1, + child: Text( + data[index].amount, + textAlign: TextAlign.right, + style: Theme.of(context).textTheme.subtitle1, + ), + ) + ], + ), + ); + }), + ), + ], + ), + ); + } +} diff --git a/lib/ui/widgets/favorite_pair.dart b/lib/ui/widgets/favorite_pair.dart new file mode 100644 index 0000000..9cf6005 --- /dev/null +++ b/lib/ui/widgets/favorite_pair.dart @@ -0,0 +1,70 @@ +import 'package:cryptocurrency_app/models/markets/favorite_pair/favorite_pair.dart'; +import 'package:cryptocurrency_app/ui/screens/details.dart'; +import 'package:cryptocurrency_app/ui/widgets/title_price.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/src/widgets/framework.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:easy_localization/easy_localization.dart'; +import '../../generated/locale_keys.g.dart'; +class FavoritePairWidget extends HookWidget { + final FavoritePair data; + FavoritePairWidget(this.data); + + @override + Widget build(BuildContext context) { + return Container( + padding: EdgeInsets.symmetric(horizontal: 15), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + height: 5, + ), + TitlePrice(pair: data.pair), + Container( + margin: EdgeInsets.only(top: 10), + color: Theme.of(context).dividerColor, + height: 1, + width: double.infinity, + ), + InkWell( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => DetailsScreen( + pair: data.pair, + ), + ), + ); + }, + child: Container( + padding: EdgeInsets.symmetric(vertical: 10), + child: Row( + children: [ + Icon( + Icons.add_chart, + size: 30, + color: Theme.of(context).iconTheme.color, + ), + SizedBox(width: 10), + Text(LocaleKeys.openChart.tr(), + style: Theme.of(context).textTheme.headline3), + ], + ), + ), + ), + Container( + padding: EdgeInsets.symmetric(vertical: 5), + color: Theme.of(context).dividerColor, + height: 1, + width: double.infinity, + ), + SizedBox( + height: 10, + ), + ], + ), + ); + } +} diff --git a/lib/ui/widgets/line_chart.dart b/lib/ui/widgets/line_chart.dart new file mode 100644 index 0000000..a909f8d --- /dev/null +++ b/lib/ui/widgets/line_chart.dart @@ -0,0 +1,111 @@ +import 'package:fl_chart/fl_chart.dart'; +import 'package:flutter/material.dart'; +import 'dart:math'; +import '../../generated/locale_keys.g.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:cryptocurrency_app/constants/utils.dart' as Utils; + +class LineChartWidget extends StatelessWidget { + final List data; + final Color color; + final bool loading; + final bool error; + + const LineChartWidget( + {Key? key, + this.data = const [], + this.color = const Color(0xff02d39a), + this.loading = false, + this.error = false}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return Stack(alignment: AlignmentDirectional.center, children: [ + Opacity( + opacity: data.length > 0 && !loading & !error ? 1 : 0.3, + child: Container( + width: double.infinity, + child: LineChart( + mainData(data.length > 0 && !loading & !error + ? data + : Utils.demoGraphData), + swapAnimationDuration: Duration(seconds: 0), + ), + ), + ), + if (loading) + Center( + child: CircularProgressIndicator(), + ) + else if (error || data.length == 0) + Center( + child: Text(LocaleKeys.noResults.tr(), + style: Theme.of(context).textTheme.headline3), + ) + ]); + } + + LineChartData mainData(List data) { + return LineChartData( + gridData: FlGridData( + show: true, + drawVerticalLine: false, + drawHorizontalLine: false, + horizontalInterval: 4, + getDrawingHorizontalLine: (value) { + return FlLine( + color: const Color(0xff37434d), + strokeWidth: 1, + ); + }, + getDrawingVerticalLine: (value) { + return FlLine( + color: const Color(0xff37434d), + strokeWidth: 1, + ); + }, + ), + titlesData: FlTitlesData( + show: false, + ), + borderData: FlBorderData( + show: false, + ), + minX: 0, + maxX: data.length.toDouble() - 1, + minY: data.reduce(min).toDouble(), + maxY: data.reduce(max).toDouble(), + lineBarsData: [ + LineChartBarData( + spots: listData(data), + colors: [color], + barWidth: 3, + isStrokeCapRound: true, + dotData: FlDotData( + show: false, + ), + belowBarData: BarAreaData( + show: true, + gradientFrom: Offset(0, .9), + gradientTo: Offset(0, 0.5), + colors: [color.withOpacity(.01), color.withOpacity(.3)], + ), + ), + ], + ); + } + + List listData(List data) { + return data + .mapIndexed((e, i) => FlSpot(i.toDouble(), e.toDouble())) + .toList(); + } +} + +extension IndexedIterable on Iterable { + Iterable mapIndexed(T Function(E e, int i) f) { + var i = 0; + return map((e) => f(e, i++)); + } +} diff --git a/lib/ui/widgets/pair_tile.dart b/lib/ui/widgets/pair_tile.dart new file mode 100644 index 0000000..97e47a8 --- /dev/null +++ b/lib/ui/widgets/pair_tile.dart @@ -0,0 +1,134 @@ +import 'package:auto_size_text/auto_size_text.dart'; +import 'package:cryptocurrency_app/constants/keys.dart'; +import 'package:cryptocurrency_app/models/markets/pair/pair.dart'; +import 'package:cryptocurrency_app/provider/crypto_provider.dart'; +import 'package:cryptocurrency_app/ui/screens/details.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:cryptocurrency_app/constants/utils.dart' as Utils; + +import 'line_chart.dart'; + +final currentPair = ScopedProvider(null); + +class PairTile extends HookWidget { + const PairTile(); + + @override + Widget build(BuildContext context) { + final pair = useProvider(currentPair); + final summary = useProvider(pairSummaryProvider(pair)); + final graph = useProvider(graphDataProvider(pair)); + + return Container( + key: Keys.PAIR_TILE, + child: GestureDetector( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => DetailsScreen( + pair: pair, + ))); + }, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 15), + height: 100, + child: summary.when( + data: (final summary) { + return Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + flex: 3, + child: Container( + padding: EdgeInsets.symmetric(vertical: 15), + width: 80, + child: AutoSizeText(pair.pair, + textAlign: TextAlign.start, + minFontSize: 0, + stepGranularity: 0.1, + maxLines: 1, + style: Theme.of(context).textTheme.headline5), + ), + ), + Expanded( + flex: 4, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 5), + height: 50, + child: graph.when( + data: (data) => LineChartWidget( + color: summary.price.change.absolute < 0 + ? Colors.red + : const Color(0xff02d39a), + data: Utils.getPoints(data), + ), + loading: () => LineChartWidget(loading: true), + error: (e, ex) => LineChartWidget(error: true)), + ), + ), + Expanded( + flex: 4, + child: Container( + padding: EdgeInsets.only(top: 25, left: 10), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + AutoSizeText( + summary.price.last.toStringAsFixed(2), + minFontSize: 10, + style: Theme.of(context).textTheme.headline5, + ), + SizedBox( + height: 5, + ), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Expanded( + child: AutoSizeText( + summary.price.change.absolute + .toStringAsFixed(5), + textAlign: TextAlign.end, + minFontSize: 0, + stepGranularity: 0.1, + maxLines: 1, + style: Theme.of(context) + .textTheme + .headline5! + .apply( + color: summary.price.change + .absolute >= + 0 + ? Colors.green + : Colors.red)), + ), + AutoSizeText( + ' (${summary.price.change.percentage.toStringAsFixed(2)}%)', + textAlign: TextAlign.end, + minFontSize: 0, + stepGranularity: 0.1, + maxLines: 1, + style: Theme.of(context) + .textTheme + .headline6), + ]), + ], + ), + ), + ), + ], + ); + }, + loading: () => Center(child: CircularProgressIndicator()), + error: (error, stk) => + Center(child: Text(error.toString().tr()))), + ), + ), + ); + } +} diff --git a/lib/ui/widgets/title_price.dart b/lib/ui/widgets/title_price.dart new file mode 100644 index 0000000..973b3f3 --- /dev/null +++ b/lib/ui/widgets/title_price.dart @@ -0,0 +1,63 @@ +import 'package:auto_size_text/auto_size_text.dart'; +import 'package:cryptocurrency_app/models/markets/pair/pair.dart'; +import 'package:cryptocurrency_app/provider/crypto_provider.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/src/widgets/framework.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:easy_localization/easy_localization.dart'; + +class TitlePrice extends HookWidget { + final Pair pair; + + TitlePrice({required this.pair}); + + @override + Widget build(BuildContext context) { + final data = useProvider(pairSummaryProvider(pair)); + + return data.when( + data: (data) { + return Container( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AutoSizeText(pair.pair, + maxLines: 1, style: Theme.of(context).textTheme.headline2), + AutoSizeText(data.price.last.toString(), + maxLines: 1, style: Theme.of(context).textTheme.headline1), + if (true) + Row(children: [ + AutoSizeText(data.price.change.absolute.toStringAsFixed(5), + textAlign: TextAlign.start, + minFontSize: 0, + stepGranularity: 0.1, + maxLines: 1, + style: TextStyle( + color: data.price.change.absolute >= 0 + ? Colors.green + : Colors.red, + fontSize: + Theme.of(context).textTheme.headline5?.fontSize, + fontWeight: FontWeight.w800)), + AutoSizeText( + ' (${data.price.change.percentage.toStringAsFixed(2)}%)', + textAlign: TextAlign.start, + minFontSize: 0, + stepGranularity: 0.1, + maxLines: 1, + style: Theme.of(context).textTheme.headline4), + ]), + ], + ), + ); + }, + loading: () => Center( + child: CircularProgressIndicator(), + ), + error: (error, e) => Center( + child: Text(error.toString().tr()), + ), + ); + } +} diff --git a/pubspec.lock b/pubspec.lock new file mode 100644 index 0000000..d2a7d8b --- /dev/null +++ b/pubspec.lock @@ -0,0 +1,783 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + url: "https://pub.dartlang.org" + source: hosted + version: "21.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + url: "https://pub.dartlang.org" + source: hosted + version: "1.5.0" + archive: + dependency: transitive + description: + name: archive + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.2" + args: + dependency: transitive + description: + name: args + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + async: + dependency: transitive + description: + name: async + url: "https://pub.dartlang.org" + source: hosted + version: "2.6.1" + auto_size_text: + dependency: "direct main" + description: + name: auto_size_text + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0-nullsafety.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + build: + dependency: transitive + description: + name: build + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + build_config: + dependency: transitive + description: + name: build_config + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + build_daemon: + dependency: transitive + description: + name: build_daemon + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" + build_resolvers: + dependency: transitive + description: + name: build_resolvers + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.2" + build_runner: + dependency: "direct dev" + description: + name: build_runner + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.3" + build_runner_core: + dependency: transitive + description: + name: build_runner_core + url: "https://pub.dartlang.org" + source: hosted + version: "7.0.0" + built_collection: + dependency: transitive + description: + name: built_collection + url: "https://pub.dartlang.org" + source: hosted + version: "5.0.0" + built_value: + dependency: transitive + description: + name: built_value + url: "https://pub.dartlang.org" + source: hosted + version: "8.0.6" + characters: + dependency: transitive + description: + name: characters + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + charcode: + dependency: transitive + description: + name: charcode + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + cli_util: + dependency: transitive + description: + name: cli_util + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.0" + clock: + dependency: transitive + description: + name: clock + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + code_builder: + dependency: transitive + description: + name: code_builder + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.0" + collection: + dependency: transitive + description: + name: collection + url: "https://pub.dartlang.org" + source: hosted + version: "1.15.0" + convert: + dependency: transitive + description: + name: convert + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" + crypto: + dependency: transitive + description: + name: crypto + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.3" + dart_style: + dependency: transitive + description: + name: dart_style + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + dio: + dependency: "direct main" + description: + name: dio + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.0" + easy_localization: + dependency: "direct main" + description: + name: easy_localization + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" + easy_logger: + dependency: transitive + description: + name: easy_logger + url: "https://pub.dartlang.org" + source: hosted + version: "0.0.2" + equatable: + dependency: transitive + description: + name: equatable + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.2" + fake_async: + dependency: transitive + description: + name: fake_async + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + ffi: + dependency: transitive + description: + name: ffi + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + file: + dependency: transitive + description: + name: file + url: "https://pub.dartlang.org" + source: hosted + version: "6.1.0" + fixnum: + dependency: transitive + description: + name: fixnum + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + fl_chart: + dependency: "direct main" + description: + name: fl_chart + url: "https://pub.dartlang.org" + source: hosted + version: "0.36.1" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_candlesticks: + dependency: "direct main" + description: + path: "." + ref: HEAD + resolved-ref: c4af17340db1a60cc4db13808cc14dff5e2e0a8a + url: "https://github.com/salvadordeveloper/flutter-candlesticks.git" + source: git + version: "0.1.4" + flutter_dotenv: + dependency: "direct main" + description: + name: flutter_dotenv + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.0-nullsafety.1" + flutter_driver: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + flutter_hooks: + dependency: "direct main" + description: + name: flutter_hooks + url: "https://pub.dartlang.org" + source: hosted + version: "0.17.0" + flutter_launcher_icons: + dependency: "direct dev" + description: + name: flutter_launcher_icons + url: "https://pub.dartlang.org" + source: hosted + version: "0.9.0" + flutter_localizations: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + flutter_riverpod: + dependency: transitive + description: + name: flutter_riverpod + url: "https://pub.dartlang.org" + source: hosted + version: "0.14.0+3" + flutter_secure_storage: + dependency: "direct main" + description: + name: flutter_secure_storage + url: "https://pub.dartlang.org" + source: hosted + version: "4.2.0" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + freezed: + dependency: "direct dev" + description: + name: freezed + url: "https://pub.dartlang.org" + source: hosted + version: "0.14.2" + freezed_annotation: + dependency: "direct main" + description: + name: freezed_annotation + url: "https://pub.dartlang.org" + source: hosted + version: "0.14.2" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + fuchsia_remote_debug_protocol: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + glob: + dependency: transitive + description: + name: glob + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + graphs: + dependency: transitive + description: + name: graphs + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + hooks_riverpod: + dependency: "direct main" + description: + name: hooks_riverpod + url: "https://pub.dartlang.org" + source: hosted + version: "0.14.0+4" + http_mock_adapter: + dependency: "direct dev" + description: + name: http_mock_adapter + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.1" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" + http_parser: + dependency: transitive + description: + name: http_parser + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.0" + image: + dependency: transitive + description: + name: image + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.2" + integration_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + intl: + dependency: transitive + description: + name: intl + url: "https://pub.dartlang.org" + source: hosted + version: "0.17.0" + io: + dependency: transitive + description: + name: io + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + js: + dependency: transitive + description: + name: js + url: "https://pub.dartlang.org" + source: hosted + version: "0.6.3" + json_annotation: + dependency: transitive + description: + name: json_annotation + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.1" + json_serializable: + dependency: "direct dev" + description: + name: json_serializable + url: "https://pub.dartlang.org" + source: hosted + version: "4.1.2" + logging: + dependency: transitive + description: + name: logging + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" + matcher: + dependency: transitive + description: + name: matcher + url: "https://pub.dartlang.org" + source: hosted + version: "0.12.10" + meta: + dependency: transitive + description: + name: meta + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.0" + mime: + dependency: transitive + description: + name: mime + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + mockito: + dependency: "direct main" + description: + name: mockito + url: "https://pub.dartlang.org" + source: hosted + version: "5.0.9" + package_config: + dependency: transitive + description: + name: package_config + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + path: + dependency: transitive + description: + name: path + url: "https://pub.dartlang.org" + source: hosted + version: "1.8.0" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + pedantic: + dependency: transitive + description: + name: pedantic + url: "https://pub.dartlang.org" + source: hosted + version: "1.11.0" + petitparser: + dependency: transitive + description: + name: petitparser + url: "https://pub.dartlang.org" + source: hosted + version: "4.1.0" + platform: + dependency: transitive + description: + name: platform + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + pool: + dependency: transitive + description: + name: pool + url: "https://pub.dartlang.org" + source: hosted + version: "1.5.0" + process: + dependency: transitive + description: + name: process + url: "https://pub.dartlang.org" + source: hosted + version: "4.2.1" + pub_semver: + dependency: transitive + description: + name: pub_semver + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + riverpod: + dependency: transitive + description: + name: riverpod + url: "https://pub.dartlang.org" + source: hosted + version: "0.14.0+3" + settings_ui: + dependency: "direct main" + description: + name: settings_ui + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + shared_preferences: + dependency: transitive + description: + name: shared_preferences + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.5" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + shared_preferences_macos: + dependency: transitive + description: + name: shared_preferences_macos + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + shelf: + dependency: transitive + description: + name: shelf + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.4" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_gen: + dependency: transitive + description: + name: source_gen + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + source_span: + dependency: transitive + description: + name: source_span + url: "https://pub.dartlang.org" + source: hosted + version: "1.8.1" + stack_trace: + dependency: transitive + description: + name: stack_trace + url: "https://pub.dartlang.org" + source: hosted + version: "1.10.0" + state_notifier: + dependency: transitive + description: + name: state_notifier + url: "https://pub.dartlang.org" + source: hosted + version: "0.7.0" + stream_channel: + dependency: transitive + description: + name: stream_channel + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + stream_transform: + dependency: transitive + description: + name: stream_transform + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + string_scanner: + dependency: transitive + description: + name: string_scanner + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + sync_http: + dependency: transitive + description: + name: sync_http + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + test_api: + dependency: transitive + description: + name: test_api + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.0" + timing: + dependency: transitive + description: + name: timing + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + typed_data: + dependency: transitive + description: + name: typed_data + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.0" + vector_math: + dependency: transitive + description: + name: vector_math + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + vm_service: + dependency: transitive + description: + name: vm_service + url: "https://pub.dartlang.org" + source: hosted + version: "6.2.0" + watcher: + dependency: transitive + description: + name: watcher + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + webdriver: + dependency: transitive + description: + name: webdriver + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" + win32: + dependency: transitive + description: + name: win32 + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.1" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.0" + xml: + dependency: transitive + description: + name: xml + url: "https://pub.dartlang.org" + source: hosted + version: "5.1.0" + yaml: + dependency: transitive + description: + name: yaml + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.0" +sdks: + dart: ">=2.13.0 <3.0.0" + flutter: ">=1.26.0-17.6.pre" diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 0000000..bf3788b --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,96 @@ +name: cryptocurrency_app +description: A new Flutter project. + +# The following line prevents the package from being accidentally published to +# pub.dev using `pub publish`. This is preferred for private packages. +publish_to: "none" # Remove this line if you wish to publish to pub.dev + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +version: 1.0.0+1 + +environment: + sdk: '>=2.12.0 <3.0.0' + +dependencies: + flutter: + sdk: flutter + cupertino_icons: ^1.0.0 + flutter_hooks: + hooks_riverpod: + dio: ^4.0.0 + flutter_dotenv: ^4.0.0-nullsafety.1 + fl_chart: ^0.36.1 + settings_ui: ^1.0.0 + auto_size_text: ^3.0.0-nullsafety.0 + flutter_secure_storage: ^4.1.0 + easy_localization: ^3.0.0 + freezed_annotation: + flutter_candlesticks: + git: https://github.com/salvadordeveloper/flutter-candlesticks.git + mockito: ^5.0.9 + +dev_dependencies: + integration_test: + sdk: flutter + flutter_test: + sdk: flutter + http_mock_adapter: ^0.2.1 + build_runner: + freezed: + json_serializable: + flutter_launcher_icons: ^0.9.0 + +flutter_icons: + android: "launcher_icon" + ios: true + image_path: "assets/icon/icon.png" + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec +# The following section is specific to Flutter. +flutter: + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + assets: + - assets/translations/ + - assets/icon/icon.png + - .env + # To add assets to your application, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware. + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/assets-and-images/#from-packages + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/custom-fonts/#from-packages diff --git a/run_all_tests.sh b/run_all_tests.sh new file mode 100755 index 0000000..534fa9b --- /dev/null +++ b/run_all_tests.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +# start the app and write the uri to a file +#flutter run --vmservice-out-file="test_driver/uri.txt" + + +flutter drive --driver=test_driver/integration_test.dart --target=integration_test/main_test.dart \ No newline at end of file diff --git a/screenshots/1_dark.jpeg b/screenshots/1_dark.jpeg new file mode 100644 index 0000000..a9c9c3f Binary files /dev/null and b/screenshots/1_dark.jpeg differ diff --git a/screenshots/1_light.jpeg b/screenshots/1_light.jpeg new file mode 100644 index 0000000..1cd2d7e Binary files /dev/null and b/screenshots/1_light.jpeg differ diff --git a/screenshots/2_dark.jpeg b/screenshots/2_dark.jpeg new file mode 100644 index 0000000..2378b4d Binary files /dev/null and b/screenshots/2_dark.jpeg differ diff --git a/screenshots/2_light.jpeg b/screenshots/2_light.jpeg new file mode 100644 index 0000000..8e59e46 Binary files /dev/null and b/screenshots/2_light.jpeg differ diff --git a/screenshots/3_dark.jpeg b/screenshots/3_dark.jpeg new file mode 100644 index 0000000..279e0bd Binary files /dev/null and b/screenshots/3_dark.jpeg differ diff --git a/screenshots/3_light.jpeg b/screenshots/3_light.jpeg new file mode 100644 index 0000000..96498c1 Binary files /dev/null and b/screenshots/3_light.jpeg differ diff --git a/screenshots/4_dark.jpeg b/screenshots/4_dark.jpeg new file mode 100644 index 0000000..8f78a3d Binary files /dev/null and b/screenshots/4_dark.jpeg differ diff --git a/screenshots/4_light.jpeg b/screenshots/4_light.jpeg new file mode 100644 index 0000000..23ed358 Binary files /dev/null and b/screenshots/4_light.jpeg differ diff --git a/screenshots/cover.png b/screenshots/cover.png new file mode 100644 index 0000000..3c2066d Binary files /dev/null and b/screenshots/cover.png differ diff --git a/test/api_test.dart b/test/api_test.dart new file mode 100644 index 0000000..8c35497 --- /dev/null +++ b/test/api_test.dart @@ -0,0 +1,225 @@ +import 'package:cryptocurrency_app/models/exchanges/exchange/exchange.dart'; +import 'package:cryptocurrency_app/models/exchanges/exchanges_response/exchanges_response.dart'; +import 'package:cryptocurrency_app/models/graph/graph/graph.dart'; +import 'package:cryptocurrency_app/models/graph/graph_response/graph_response.dart'; +import 'package:cryptocurrency_app/models/markets/market_response/market_response.dart'; +import 'package:cryptocurrency_app/models/markets/pair/pair.dart'; +import 'package:cryptocurrency_app/models/orderbook/orderbook/orderbook.dart'; +import 'package:cryptocurrency_app/models/orderbook/orderbook_response/orderbook_response.dart'; +import 'package:cryptocurrency_app/models/pair/pair_response/pair_response.dart'; +import 'package:cryptocurrency_app/models/pair/pair_summary/pair_summary.dart'; +import 'package:cryptocurrency_app/models/trades/trade/trade.dart'; +import 'package:cryptocurrency_app/models/trades/trades_response.dart/trades_response.dart'; +import 'package:cryptocurrency_app/repository/crypto_repository.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:http_mock_adapter/http_mock_adapter.dart'; +import 'data/api_data.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart' as DotEnv; +import 'package:flutter_dotenv/flutter_dotenv.dart'; + +Future main() async { + TestWidgetsFlutterBinding.ensureInitialized(); + await DotEnv.load(); + late ProviderContainer container; + late DioAdapter dioAdapter; + + setUpAll(() async { + container = + ProviderContainer(overrides: [clientProvider.overrideWithValue(Dio())]); + dioAdapter = DioAdapter(); + container.read(clientProvider).httpClientAdapter = dioAdapter; + }); + + test('Dio loads API_KEY from .env', () { + final container = ProviderContainer(); + final headers = container.read(clientProvider).options.headers; + expect(headers['X-CW-API-Key'], env['API_KEY']); + // stuff + }); + group('getPairs', () { + test('getPairsSucess', () async { + List? pairs = MarketResponse.fromJson(ApiData.pairs).result; + + const market = 'binance'; + const path = '/markets/$market'; + + dioAdapter.onGet(path, (request) { + request.reply(200, ApiData.pairs); + }); + + final response = await container.read(cryptoRepository).getPairs(market); + expect(pairs, response); + }); + test('getPairsFailed', () async { + const market = 'binance'; + const path = '/markets/$market'; + + dioAdapter.onGet(path, (request) { + request.reply(404, {}); + }); + + expect( + () async => await container.read(cryptoRepository).getPairs(market), + throwsException); + }); + }); + + group('getPairSummary', () { + test('getPairSummarySucess', () async { + PairSummary? pairSummary = + PairResponse.fromJson(ApiData.pair_btcusdt_summary).result; + + const market = 'binance'; + const pair = 'btcusdt'; + const path = '/markets/$market/$pair/summary'; + + dioAdapter.onGet(path, (request) { + request.reply(200, ApiData.pair_btcusdt_summary); + }); + + final response = + await container.read(cryptoRepository).getPairSummary(market, pair); + expect(pairSummary, response); + }); + test('getPairsSummaryFail', () async { + const market = 'binance'; + const pair = 'btcusdt'; + const path = '/markets/$market/$pair/summary'; + + dioAdapter.onGet(path, (request) { + request.reply(404, {}); + }); + + expect( + () async => await container + .read(cryptoRepository) + .getPairSummary(market, pair), + throwsException); + }); + }); + + group('getPairOrdeBook', () { + test('getPairOrdeBookSucess', () async { + OrderBook? pairSummary = + OrderBookResponse.fromJson(ApiData.pair_btcusdt_oderbook).result; + + const market = 'binance'; + const pair = 'btcusdt'; + const path = '/markets/$market/$pair/orderbook'; + + dioAdapter.onGet(path, (request) { + request.reply(200, ApiData.pair_btcusdt_oderbook); + }); + + final response = + await container.read(cryptoRepository).getOrderBook(market, pair); + expect(pairSummary, response); + }); + test('getPairOrdeBookFail', () async { + const market = 'binance'; + const pair = 'btcusdt'; + const path = '/markets/$market/$pair/orderbook'; + + dioAdapter.onGet(path, (request) { + request.reply(404, {}); + }); + + expect( + () async => + await container.read(cryptoRepository).getOrderBook(market, pair), + throwsException); + }); + }); + + group('getPairTrades', () { + test('getPairTradesSucess', () async { + List? trades = + TradesResponse.fromJson(ApiData.pair_btcusdt_trades).result; + + const market = 'binance'; + const pair = 'btcusdt'; + const path = '/markets/$market/$pair/trades'; + + dioAdapter.onGet(path, (request) { + request.reply(200, ApiData.pair_btcusdt_trades); + }); + + final response = + await container.read(cryptoRepository).getTrades(market, pair); + expect(trades, response); + }); + test('getPairTradesFail', () async { + const market = 'binance'; + const pair = 'btcusdt'; + const path = '/markets/$market/$pair/trades'; + + dioAdapter.onGet(path, (request) { + request.reply(404, {}); + }); + + expect( + () async => + await container.read(cryptoRepository).getTrades(market, pair), + throwsException); + }); + }); + + group('getPairGraph', () { + test('getPairGraphSucess', () async { + Graph? graph = GraphResponse.fromJson(ApiData.pair_btcusdt_graph).result; + + const market = 'binance'; + const pair = 'btcusdt'; + const path = '/markets/$market/$pair/ohlc'; + + dioAdapter.onGet(path, (request) { + request.reply(200, ApiData.pair_btcusdt_graph); + }, queryParameters: {"periods": "", "after": "", "before": ""}); + + final response = + await container.read(cryptoRepository).getPairGraph(market, pair); + expect(graph, response); + }); + test('getPairGraphFail', () async { + const market = 'binance'; + const pair = 'btcusdt'; + const path = '/markets/$market/$pair/ohlc'; + + dioAdapter.onGet(path, (request) { + request.reply(404, {}); + }, queryParameters: {"periods": "", "after": "", "before": ""}); + + expect( + () async => + await container.read(cryptoRepository).getPairGraph(market, pair), + throwsException); + }); + }); + + group('getExchanges', () { + test('getExchangesSucess', () async { + List? exchange = + ExchangesResponse.fromJson(ApiData.exchanges).result; + + const path = '/exchanges'; + dioAdapter.onGet(path, (request) { + request.reply(200, ApiData.exchanges); + }); + + final response = await container.read(cryptoRepository).getExchanges(); + expect(exchange, response); + }); + + test('getExchangesFail', () async { + const path = '/exchanges'; + dioAdapter.onGet(path, (request) { + request.reply(404, {}); + }); + + expect(() async => await container.read(cryptoRepository).getExchanges(), + throwsException); + }); + }); +} diff --git a/test/data/api_data.dart b/test/data/api_data.dart new file mode 100644 index 0000000..e022137 --- /dev/null +++ b/test/data/api_data.dart @@ -0,0 +1,137 @@ +class ApiData { + static final Map exchanges = { + "result": [ + { + "id": 17, + "symbol": "mexbt", + "name": "meXBT", + "route": "https://api.cryptowat.ch/exchanges/mexbt", + "active": false + }, + { + "id": 62, + "symbol": "coinone", + "name": "Coinone", + "route": "https://api.cryptowat.ch/exchanges/coinone", + "active": true + }, + ], + "allowance": {"cost": 0, "remaining": 100, "upgrade": ""} + }; + + static final Map pairs = { + "result": [ + { + "id": 579, + "exchange": "binance", + "pair": "btcusdt", + "active": true, + "route": "https://api.cryptowat.ch/markets/binance/btcusdt" + }, + { + "id": 580, + "exchange": "binance", + "pair": "ethbtc", + "active": true, + "route": "https://api.cryptowat.ch/markets/binance/ethbtc" + }, + { + "id": 581, + "exchange": "binance", + "pair": "ltcbtc", + "active": true, + "route": "https://api.cryptowat.ch/markets/binance/ltcbtc" + }, + { + "id": 582, + "exchange": "binance", + "pair": "neobtc", + "active": true, + "route": "https://api.cryptowat.ch/markets/binance/neobtc" + }, + ], + "allowance": {"cost": 0, "remaining": 100, "upgrade": ""} + }; + + static final Map pair_btcusdt_summary = { + "result": { + "price": { + "last": 35503.33, + "high": 43861.94, + "low": 30000, + "change": {"percentage": -0.18764266402587584, "absolute": -8200.75} + }, + "volume": 257132.87322650044, + "volumeQuote": 10096197214.14349 + }, + "allowance": {"cost": 0, "remaining": 100, "upgrade": ""} + }; + + static final Map pair_btcusdt_oderbook = { + "result": { + "asks": [ + [35922.59, 0.004088], + [35925.23, 0.003071], + [35925.71, 0.012824], + [35927.12, 0.000556], + [35927.58, 0.2178], + ], + "bids": [ + [35904.23, 0.153095], + [35900.35, 0.082238], + [35898, 0.12], + [35897.99, 0.006152], + [35897.68, 0.04332], + ], + "seqNum": 429614 + }, + "allowance": {"cost": 0, "remaining": 100, "upgrade": ""} + }; + + static final Map pair_btcusdt_trades = { + "result": [ + [0, 1621433110, 34452.66, 0.008464], + [0, 1621433110, 34454.43, 0.016662], + [0, 1621433110, 34485.69, 0.00476], + [0, 1621433110, 34475.97, 0.000401], + [0, 1621433110, 34456.09, 0.0011], + [0, 1621433110, 34456.09, 0.004997], + ], + "allowance": {"cost": 0, "remaining": 100, "upgrade": ""} + }; + + static final Map pair_btcusdt_graph = { + "result": { + "14400": [ + [ + 1607054400, + 19422.34, + 19527, + 19122.74, + 19162.62, + 8683.588417, + 167917416.81467284 + ], + [ + 1607097600, + 18835.47, + 19146.22, + 18686.38, + 18943.35, + 14717.586675, + 278732315.17076141 + ], + [ + 1607112000, + 18944.06, + 19078.68, + 18817, + 19038.73, + 8799.851665, + 166925728.42698553 + ], + ] + }, + "allowance": {"cost": 0, "remaining": 100, "upgrade": ""} + }; +} diff --git a/test/exception_test.dart b/test/exception_test.dart new file mode 100644 index 0000000..136cf8c --- /dev/null +++ b/test/exception_test.dart @@ -0,0 +1,104 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:cryptocurrency_app/constants/exceptions.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:easy_localization/src/localization.dart'; +import 'package:easy_localization/src/translations.dart'; +import '../lib/generated/locale_keys.g.dart'; + +void main() { + setUpAll(() { + File('assets/translations/en.json').readAsString().then((String contents) { + Map data = jsonDecode(contents); + Localization.load(Locale('en'), translations: Translations(data)); + }); + }); + + test('Create DataException', () { + final exception = + DataException(message: LocaleKeys.errorSomethingWentWrong); + expect(exception.toString(), LocaleKeys.errorSomethingWentWrong); + }); + + test('Exception Dio Cancel', () { + final error = DioError( + requestOptions: RequestOptions(path: ""), type: DioErrorType.cancel); + final exception = DataException.fromDioError(error); + expect(exception.toString(), LocaleKeys.errorRequestCancelled); + }); + + test('Exception Connection Timeout', () { + final error = DioError( + requestOptions: RequestOptions(path: ""), + type: DioErrorType.connectTimeout); + final exception = DataException.fromDioError(error); + expect(exception.toString(), LocaleKeys.errorConnectionTimeout); + }); + + test('Exception other', () { + final error = DioError( + requestOptions: RequestOptions(path: ""), type: DioErrorType.other); + final exception = DataException.fromDioError(error); + expect(exception.toString(), LocaleKeys.errorInternetConnection); + }); + + test('Exception Receive Timeout', () { + final error = DioError( + requestOptions: RequestOptions(path: ""), + type: DioErrorType.receiveTimeout); + final exception = DataException.fromDioError(error); + expect(exception.toString(), LocaleKeys.errorReceiveTimeout); + }); + + test('Exception Response 400', () { + final error = DioError( + requestOptions: RequestOptions(path: ""), + type: DioErrorType.response, + response: Response( + requestOptions: RequestOptions( + path: "", + ), + statusCode: 400)); + final exception = DataException.fromDioError(error); + expect(exception.toString(), LocaleKeys.errorBadRequest); + }); + + test('Exception Response 404', () { + final error = DioError( + requestOptions: RequestOptions(path: ""), + type: DioErrorType.response, + response: Response( + requestOptions: RequestOptions( + path: "", + ), + statusCode: 404)); + final exception = DataException.fromDioError(error); + expect(exception.toString(), LocaleKeys.errorRequestNotFound); + }); + + test('Exception Response 500', () { + final error = DioError( + requestOptions: RequestOptions(path: ""), + type: DioErrorType.response, + response: Response( + requestOptions: RequestOptions( + path: "", + ), + statusCode: 500)); + final exception = DataException.fromDioError(error); + expect(exception.toString(), LocaleKeys.errorIntenalServer); + }); + + test('Exception Send Timeout', () { + final error = DioError( + requestOptions: RequestOptions( + path: "", + ), + type: DioErrorType.sendTimeout); + final exception = DataException.fromDioError(error); + expect(exception.toString(), LocaleKeys.errorSendTimeout); + }); +} diff --git a/test/widget_test.dart b/test/widget_test.dart new file mode 100644 index 0000000..570e0e4 --- /dev/null +++ b/test/widget_test.dart @@ -0,0 +1,8 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility that Flutter provides. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +void main() {} diff --git a/test_driver/integration_test.dart b/test_driver/integration_test.dart new file mode 100644 index 0000000..b38629c --- /dev/null +++ b/test_driver/integration_test.dart @@ -0,0 +1,3 @@ +import 'package:integration_test/integration_test_driver.dart'; + +Future main() => integrationDriver();