├── .gitignore
├── LICENSE
├── Makefile
├── README.md
├── analysis_options.yaml
├── android
├── .gitignore
├── Gemfile
├── Gemfile.lock
├── app
│ ├── build.gradle
│ └── src
│ │ ├── debug
│ │ └── AndroidManifest.xml
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── ic_launcher-playstore.png
│ │ ├── kotlin
│ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── vizier
│ │ │ │ └── MainActivity.kt
│ │ └── res
│ │ │ ├── drawable-v21
│ │ │ └── launch_background.xml
│ │ │ ├── drawable
│ │ │ └── launch_background.xml
│ │ │ ├── mipmap-anydpi-v26
│ │ │ ├── ic_launcher.xml
│ │ │ └── ic_launcher_round.xml
│ │ │ ├── mipmap-hdpi
│ │ │ ├── ic_launcher_foreground.png
│ │ │ ├── ic_launcher_round.png
│ │ │ └── logo_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ ├── ic_launcher_foreground.png
│ │ │ ├── ic_launcher_round.png
│ │ │ └── logo_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ ├── ic_launcher_foreground.png
│ │ │ ├── ic_launcher_round.png
│ │ │ └── logo_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ ├── ic_launcher_foreground.png
│ │ │ ├── ic_launcher_round.png
│ │ │ └── logo_launcher.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ ├── ic_launcher_foreground.png
│ │ │ ├── ic_launcher_round.png
│ │ │ └── logo_launcher.png
│ │ │ ├── values-night
│ │ │ └── styles.xml
│ │ │ └── values
│ │ │ ├── ic_launcher_background.xml
│ │ │ └── styles.xml
│ │ └── profile
│ │ └── AndroidManifest.xml
├── build.gradle
├── fastlane
│ ├── Appfile
│ └── Fastfile
├── gradle.properties
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
└── settings.gradle
├── assets
├── fonts
│ └── Ubuntu
│ │ ├── Ubuntu-Bold.ttf
│ │ ├── Ubuntu-Light.ttf
│ │ ├── Ubuntu-Medium.ttf
│ │ └── Ubuntu-Regular.ttf
├── mocks
│ ├── finances
│ │ ├── investments_image.png
│ │ └── my_account_image.png
│ ├── portfolio
│ │ ├── google_logo.png
│ │ ├── netflix_logo.png
│ │ ├── nike_logo.png
│ │ └── tesla_logo.png
│ ├── transactions
│ │ ├── apple_logo.png
│ │ ├── nike_logo.png
│ │ ├── paypal_logo.png
│ │ ├── uber_eats_logo.png
│ │ └── vodafone_logo.png
│ └── user
│ │ └── avatar.png
└── svgs
│ ├── all_money.svg
│ ├── baner_boy.svg
│ ├── bitcoin.svg
│ ├── card_face.svg
│ ├── chip.svg
│ ├── loans.svg
│ ├── manage_money.svg
│ ├── money_login.svg
│ ├── mortgage.svg
│ ├── mortgage_details.svg
│ ├── retirement_goals.svg
│ ├── retirement_goals_details.svg
│ └── stay_focused.svg
├── build.yaml
├── ios
├── .gitignore
├── Flutter
│ ├── AppFrameworkInfo.plist
│ ├── Debug.xcconfig
│ └── Release.xcconfig
├── Gemfile
├── Gemfile.lock
├── Podfile
├── Podfile.lock
├── Runner.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ └── WorkspaceSettings.xcsettings
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── WorkspaceSettings.xcsettings
├── Runner
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ ├── Contents.json
│ │ │ ├── Icon-App-20x20@1x.png
│ │ │ ├── Icon-App-20x20@2x.png
│ │ │ ├── Icon-App-20x20@3x.png
│ │ │ ├── Icon-App-29x29@1x.png
│ │ │ ├── Icon-App-29x29@2x.png
│ │ │ ├── Icon-App-29x29@3x.png
│ │ │ ├── Icon-App-40x40@1x.png
│ │ │ ├── Icon-App-40x40@2x.png
│ │ │ ├── Icon-App-40x40@3x.png
│ │ │ ├── Icon-App-60x60@2x.png
│ │ │ ├── Icon-App-60x60@3x.png
│ │ │ ├── Icon-App-76x76@1x.png
│ │ │ ├── Icon-App-76x76@2x.png
│ │ │ ├── Icon-App-83.5x83.5@2x.png
│ │ │ └── ItunesArtwork@2x.png
│ │ ├── Contents.json
│ │ └── LaunchImage.imageset
│ │ │ ├── Contents.json
│ │ │ ├── LaunchImage.pdf
│ │ │ └── README.md
│ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ ├── Info.plist
│ └── Runner-Bridging-Header.h
└── fastlane
│ ├── Appfile
│ └── Fastfile
├── l10n.yaml
├── lib
├── config
│ ├── constants
│ │ ├── animation_constants.dart
│ │ ├── api_constants.dart
│ │ └── app_constants.dart
│ ├── formatters
│ │ ├── card_date_input_formatter.dart
│ │ └── card_number_input_formatter.dart
│ ├── injector
│ │ ├── di.dart
│ │ └── module
│ │ │ └── common_module.dart
│ ├── router
│ │ └── app_router.dart
│ └── styles
│ │ ├── colors
│ │ ├── app_colors.dart
│ │ └── app_colors_border.dart
│ │ ├── decorations
│ │ ├── app_decorations.dart
│ │ ├── app_decorations_button.dart
│ │ └── app_decorations_input.dart
│ │ ├── dimensions
│ │ ├── app_dimensions.dart
│ │ ├── app_dimensions_padding.dart
│ │ └── app_dimensions_radius.dart
│ │ ├── images
│ │ ├── app_images.dart
│ │ └── svg_images.dart
│ │ ├── text_styles
│ │ ├── app_text_styles.dart
│ │ └── app_text_styles_button.dart
│ │ └── theme
│ │ ├── app_theme.dart
│ │ ├── dark_theme.dart
│ │ └── light_theme.dart
├── cubits
│ ├── account_financial_breakdown
│ │ ├── account_financial_breakdown_cubit.dart
│ │ └── account_financial_breakdown_state.dart
│ ├── authentication
│ │ ├── authentication_cubit.dart
│ │ ├── authentication_state.dart
│ │ └── login
│ │ │ ├── authentication_login_cubit.dart
│ │ │ └── authentication_login_state.dart
│ ├── card_form
│ │ ├── add
│ │ │ ├── card_add_cubit.dart
│ │ │ └── card_add_state.dart
│ │ ├── card_form_cubit.dart
│ │ └── card_form_state.dart
│ ├── chart_tabs
│ │ ├── chart_tab.dart
│ │ ├── chart_tabs_cubit.dart
│ │ └── chart_tabs_state.dart
│ ├── company_listing
│ │ ├── details
│ │ │ ├── company_listing_details_cubit.dart
│ │ │ └── company_listing_details_state.dart
│ │ └── history
│ │ │ ├── company_listing_history_cubit.dart
│ │ │ └── company_listing_history_state.dart
│ ├── financial_history
│ │ ├── financial_history_cubit.dart
│ │ └── financial_history_state.dart
│ ├── goals
│ │ ├── goals_cubit.dart
│ │ └── goals_state.dart
│ ├── my_finances
│ │ ├── my_finances_cubit.dart
│ │ └── my_finances_state.dart
│ ├── my_portfolio
│ │ ├── my_portfolio_cubit.dart
│ │ └── my_portfolio_state.dart
│ ├── offers
│ │ ├── details
│ │ │ ├── offer_details_cubit.dart
│ │ │ └── offer_details_state.dart
│ │ └── list
│ │ │ ├── offer_list_cubit.dart
│ │ │ └── offer_list_state.dart
│ ├── portfolio_watchlist
│ │ ├── portfolio_watchlist_cubit.dart
│ │ └── portfolio_watchlist_state.dart
│ ├── retirement_plan
│ │ ├── retirement_plan_cubit.dart
│ │ └── retirement_plan_state.dart
│ ├── transaction_history
│ │ ├── transaction_history_cubit.dart
│ │ └── transaction_history_state.dart
│ ├── user
│ │ ├── notifications
│ │ │ ├── user_notifications_cubit.dart
│ │ │ └── user_notifications_state.dart
│ │ ├── user_cubit.dart
│ │ └── user_state.dart
│ └── wallet
│ │ ├── wallet_cubit.dart
│ │ └── wallet_state.dart
├── data
│ ├── data_sources
│ │ ├── authentication
│ │ │ ├── authentication_data_source.dart
│ │ │ └── dummy_authentication_data_source.dart
│ │ ├── finances
│ │ │ ├── dummy_finances_data_source.dart
│ │ │ └── finances_data_source.dart
│ │ ├── offers
│ │ │ ├── dummy_offers_data_source.dart
│ │ │ └── offers_data_source.dart
│ │ ├── portfolio
│ │ │ ├── dummy_portfolio_data_source.dart
│ │ │ └── portfolio_data_source.dart
│ │ ├── user
│ │ │ ├── dummy_user_data_source.dart
│ │ │ └── user_data_source.dart
│ │ └── wallet
│ │ │ ├── dummy_wallet_data_source.dart
│ │ │ └── wallet_data_source.dart
│ ├── errors
│ │ └── app_error.dart
│ ├── factory
│ │ └── chart_factory.dart
│ ├── models
│ │ ├── account
│ │ │ ├── account_model.dart
│ │ │ └── breakdown
│ │ │ │ └── account_breakdown_model.dart
│ │ ├── company_asset
│ │ │ └── company_asset_model.dart
│ │ ├── company_listing
│ │ │ ├── details
│ │ │ │ └── company_listing_details_item_model.dart
│ │ │ └── history
│ │ │ │ ├── company_listing_history_model.dart
│ │ │ │ ├── data
│ │ │ │ └── company_listing_history_data_model.dart
│ │ │ │ └── value
│ │ │ │ └── company_listing_history_value_model.dart
│ │ ├── finances_overview
│ │ │ └── finances_overview_model.dart
│ │ ├── financial_history
│ │ │ ├── financial_history_model.dart
│ │ │ └── history_data
│ │ │ │ └── financial_history_data_model.dart
│ │ ├── goal
│ │ │ └── goal_model.dart
│ │ ├── offer
│ │ │ ├── offer_model.dart
│ │ │ ├── offer_type.dart
│ │ │ └── slider_item
│ │ │ │ ├── offer_slider_model.dart
│ │ │ │ └── offer_slider_type.dart
│ │ ├── portfolio_overview
│ │ │ └── portfolio_overview_model.dart
│ │ ├── retirement_plan
│ │ │ ├── data
│ │ │ │ └── retirement_plan_data_model.dart
│ │ │ └── retirement_plan_model.dart
│ │ ├── transaction
│ │ │ ├── category
│ │ │ │ └── transaction_category_model.dart
│ │ │ └── transaction_model.dart
│ │ ├── user
│ │ │ └── user_model.dart
│ │ └── wallet
│ │ │ └── wallet_model.dart
│ ├── repositories
│ │ ├── authentication
│ │ │ ├── authentication_repository.dart
│ │ │ └── data_authentication_repository.dart
│ │ ├── finances
│ │ │ ├── data_finances_repository.dart
│ │ │ └── finances_repository.dart
│ │ ├── offers
│ │ │ ├── data_offers_repository.dart
│ │ │ └── offers_repository.dart
│ │ ├── portfolio
│ │ │ ├── data_portfolio_repository.dart
│ │ │ └── portfolio_repository.dart
│ │ ├── user
│ │ │ ├── data_user_repository.dart
│ │ │ └── user_repository.dart
│ │ └── wallet
│ │ │ ├── data_wallet_repository.dart
│ │ │ └── wallet_repository.dart
│ ├── requests
│ │ └── authentication
│ │ │ └── authentication_request.dart
│ ├── responses
│ │ ├── authentication
│ │ │ └── authentication_response.dart
│ │ ├── response_status.dart
│ │ └── user
│ │ │ └── notifications
│ │ │ └── user_notifications_response.dart
│ └── storages
│ │ ├── common_storage.dart
│ │ ├── secure_storage.dart
│ │ ├── storage.dart
│ │ ├── storage_keys.dart
│ │ └── token_storage.dart
├── extensions
│ ├── core_extensions.dart
│ ├── extensions.dart
│ ├── model_extensions.dart
│ └── ui_extensions.dart
├── l10n
│ ├── app_en.arb
│ └── app_loc.dart
├── main.dart
├── mocks
│ ├── factories
│ │ ├── duration_factory.dart
│ │ ├── transaction_category_factory.dart
│ │ └── transaction_factory.dart
│ ├── finances_mocks.dart
│ ├── mock_factory.dart
│ ├── offers_mocks.dart
│ ├── portfolio_mocks.dart
│ ├── user_mocks.dart
│ └── wallet_mocks.dart
├── ui
│ ├── app_coordinator.dart
│ ├── main_app.dart
│ ├── modals
│ │ ├── alert_dialog
│ │ │ ├── adaptive_alert_dialog.dart
│ │ │ ├── adaptive_alert_dialog_action.dart
│ │ │ └── adaptive_alert_dialog_factory.dart
│ │ └── bottom_actions_sheet
│ │ │ ├── bottom_actions_sheet.dart
│ │ │ ├── bottom_actions_sheet_factory.dart
│ │ │ └── widget
│ │ │ └── bottom_sheet_action_cell.dart
│ ├── models
│ │ ├── card_account_type.dart
│ │ ├── chart_multi_pie_item.dart
│ │ └── chart_multi_pie_section.dart
│ ├── pages
│ │ ├── app
│ │ │ └── main_app_page.dart
│ │ ├── authentication
│ │ │ └── login
│ │ │ │ ├── authentication_login_page.dart
│ │ │ │ └── widgets
│ │ │ │ └── login_header.dart
│ │ ├── bottom_navigation
│ │ │ ├── bottom_navigation_item.dart
│ │ │ └── bottom_navigation_page.dart
│ │ ├── company_listing_details
│ │ │ ├── company_listing_page.dart
│ │ │ └── widgets
│ │ │ │ ├── company_listing_assets.dart
│ │ │ │ ├── company_listing_buttons.dart
│ │ │ │ ├── company_listing_footer.dart
│ │ │ │ └── company_listing_history_chart.dart
│ │ ├── credit_card
│ │ │ ├── form
│ │ │ │ ├── credit_card_form.dart
│ │ │ │ └── credit_card_form_page.dart
│ │ │ └── overview
│ │ │ │ ├── credit_card_overview.dart
│ │ │ │ └── widgets
│ │ │ │ ├── credit_card_list.dart
│ │ │ │ └── credit_card_transactions_list.dart
│ │ ├── finances
│ │ │ ├── finances_page.dart
│ │ │ └── widgets
│ │ │ │ ├── finances_header.dart
│ │ │ │ ├── finances_history_chart.dart
│ │ │ │ └── finances_status_summary.dart
│ │ ├── financial_breakdown
│ │ │ ├── financial_breakdown_page.dart
│ │ │ ├── financial_breakdown_page_arguments.dart
│ │ │ └── widgets
│ │ │ │ ├── financial_breakdown_chart.dart
│ │ │ │ ├── financial_breakdown_transaction_cell.dart
│ │ │ │ └── financial_breakdown_transactions_summary.dart
│ │ ├── home
│ │ │ ├── add
│ │ │ │ ├── home_add_content.dart
│ │ │ │ └── widgets
│ │ │ │ │ ├── home_add_accounts_section.dart
│ │ │ │ │ ├── home_add_action_cell.dart
│ │ │ │ │ └── home_add_other_services_section.dart
│ │ │ ├── home_page.dart
│ │ │ ├── home_tab_item.dart
│ │ │ ├── my_future
│ │ │ │ ├── home_my_future_content.dart
│ │ │ │ └── widgets
│ │ │ │ │ ├── home_my_future_assets_header.dart
│ │ │ │ │ └── home_my_future_retirement_chart.dart
│ │ │ ├── my_wallet
│ │ │ │ ├── home_my_wallet_content.dart
│ │ │ │ └── widgets
│ │ │ │ │ ├── home_my_wallet_footer_banner.dart
│ │ │ │ │ ├── home_my_wallet_goal_cell.dart
│ │ │ │ │ ├── home_my_wallet_goals_section.dart
│ │ │ │ │ └── home_my_wallet_summary.dart
│ │ │ └── widgets
│ │ │ │ ├── home_app_bar.dart
│ │ │ │ └── home_tab_bar.dart
│ │ ├── offers
│ │ │ ├── details
│ │ │ │ ├── offer_details_page.dart
│ │ │ │ └── widgets
│ │ │ │ │ ├── offer_details_header.dart
│ │ │ │ │ ├── offer_details_slider.dart
│ │ │ │ │ ├── offer_details_sliders.dart
│ │ │ │ │ └── offer_details_summary.dart
│ │ │ ├── offers_page.dart
│ │ │ └── widgets
│ │ │ │ └── offer_cell.dart
│ │ ├── onboarding
│ │ │ ├── cubit
│ │ │ │ ├── onboarding_cubit.dart
│ │ │ │ └── onboarding_state.dart
│ │ │ ├── onboarding_item.dart
│ │ │ ├── onboarding_page.dart
│ │ │ └── widgets
│ │ │ │ └── onboarding_item_content.dart
│ │ ├── portfolio
│ │ │ ├── portfolio_page.dart
│ │ │ └── widgets
│ │ │ │ ├── portfolio_digital_currencies_banner.dart
│ │ │ │ ├── portfolio_my_watchlist_cell.dart
│ │ │ │ └── portfolio_my_watchlist_section.dart
│ │ └── profile
│ │ │ ├── profile_page.dart
│ │ │ └── widgets
│ │ │ ├── profile_action_button.dart
│ │ │ ├── profile_app_bar.dart
│ │ │ ├── profile_header.dart
│ │ │ └── profile_switch_button.dart
│ └── widgets
│ │ ├── account_summary_cell.dart
│ │ ├── adaptive
│ │ ├── adaptive_app_bar.dart
│ │ ├── adaptive_button.dart
│ │ ├── adaptive_loading_button.dart
│ │ └── adaptive_text_field.dart
│ │ ├── animated_expand.dart
│ │ ├── animated_flip.dart
│ │ ├── animated_progress_bar.dart
│ │ ├── animated_text.dart
│ │ ├── arrow_change_value.dart
│ │ ├── asset_performance_item.dart
│ │ ├── chart_container.dart
│ │ ├── chart_tabs_bar.dart
│ │ ├── credit_card
│ │ ├── animated_credit_card.dart
│ │ ├── credit_card_back.dart
│ │ ├── credit_card_container.dart
│ │ ├── credit_card_cvv.dart
│ │ ├── credit_card_expiry.dart
│ │ ├── credit_card_front.dart
│ │ └── credit_card_number.dart
│ │ ├── legend
│ │ ├── legends.dart
│ │ └── models
│ │ │ ├── legend.dart
│ │ │ ├── legend_item.dart
│ │ │ └── legend_settings.dart
│ │ ├── performance_percentage_box.dart
│ │ ├── progress_bar.dart
│ │ ├── ripple_remover.dart
│ │ ├── section_header.dart
│ │ ├── transaction_cell.dart
│ │ └── unfocus_keyboard_outside.dart
└── utils
│ ├── adaptive_widget_util.dart
│ ├── currency_formatter_util.dart
│ ├── date_formatter_util.dart
│ ├── dummy_util.dart
│ ├── percentage_formatter_util.dart
│ └── validation
│ ├── validation_builder.dart
│ └── validators_util.dart
├── pubspec.lock
└── pubspec.yaml
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 |
23 | # Flutter/Dart/Pub related
24 | **/doc/api/
25 | **/ios/Flutter/.last_build_id
26 | .dart_tool/
27 | .flutter-plugins
28 | .flutter-plugins-dependencies
29 | .packages
30 | .pub-cache/
31 | .pub/
32 | /build/
33 | *.freezed.dart
34 | *.g.dart
35 | *.config.dart
36 | *.gr.dart
37 |
38 | # Web related
39 | lib/generated_plugin_registrant.dart
40 |
41 | # Symbolication related
42 | app.*.symbols
43 |
44 | # Obfuscation related
45 | app.*.map.json
46 |
47 | # Android Studio will place build artifacts here
48 | /android/app/debug
49 | /android/app/profile
50 | /android/app/release
51 |
52 | #FVM
53 | .fvm/
54 |
55 | #Generated
56 | *.freezed*
57 | *.g*
58 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Merixstudio
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | .DEFAULT_GOAL := help
2 |
3 | fvm_run_build_runner: ## Rebuilds all auto generated Dart files
4 | fvm flutter pub run build_runner build --delete-conflicting-outputs
5 |
6 | run_build_runner: ## Rebuilds all auto generated Dart files
7 | flutter pub run build_runner build --delete-conflicting-outputs
8 |
9 | help:
10 | @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
--------------------------------------------------------------------------------
/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | include: package:lint/analysis_options.yaml
2 |
3 | analyzer:
4 | exclude:
5 | - "**/*.g.dart"
6 | - "**/*.freezed.dart"
7 | - "**/app_icons.dart"
8 | - "**/*.config.dart"
9 | - "**/*.gr.dart"
10 | errors:
11 | invalid_annotation_target: ignore
12 |
13 | linter:
14 | rules:
15 | always_use_package_imports: true
16 | close_sinks: true
17 | literal_only_boolean_expressions: true
18 | avoid_returning_this: true
19 | always_put_control_body_on_new_line: true
20 | prefer_foreach: true
21 | prefer_single_quotes: true
22 | lowercase_with_underscores: true
23 | use_to_and_as_if_applicable: true
24 | use_named_constants: true
25 | use_is_even_rather_than_modulo: true
26 | use_if_null_to_convert_nulls_to_bools: true
27 | unawaited_futures: true
28 | prefer_null_aware_method_calls: true
29 | avoid_multiple_declarations_per_line: true
30 | avoid_double_and_int_checks: true
31 | always_put_required_named_parameters_first: true
32 | only_throw_errors: true
33 | cascade_invocations: true
34 | sort_pub_dependencies: false
35 | avoid_escaping_inner_quotes: false
36 | depend_on_referenced_packages: false
37 |
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
9 | # Remember to never publicly share your keystore.
10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
11 | key.properties
12 | **/*.keystore
13 | **/*.jks
14 |
--------------------------------------------------------------------------------
/android/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 |
3 | gem "fastlane"
4 |
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
7 |
15 |
19 |
23 |
24 |
25 |
26 |
27 |
28 |
30 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/android/app/src/main/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/android/app/src/main/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/com/example/vizier/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.example.vizier
2 |
3 | import io.flutter.embedding.android.FlutterActivity
4 |
5 | class MainActivity: FlutterActivity() {
6 | }
7 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-v21/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | -
6 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | -
6 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/logo_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/android/app/src/main/res/mipmap-hdpi/logo_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/logo_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/android/app/src/main/res/mipmap-mdpi/logo_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/logo_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/android/app/src/main/res/mipmap-xhdpi/logo_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/logo_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/android/app/src/main/res/mipmap-xxhdpi/logo_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/logo_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/android/app/src/main/res/mipmap-xxxhdpi/logo_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #19103F
4 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
16 |
20 | #1B0E41
21 |
22 |
--------------------------------------------------------------------------------
/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.6.10'
3 | repositories {
4 | google()
5 | mavenCentral()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:4.1.0'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | }
12 | }
13 |
14 | allprojects {
15 | repositories {
16 | google()
17 | mavenCentral()
18 | }
19 | }
20 |
21 | rootProject.buildDir = '../build'
22 | subprojects {
23 | project.buildDir = "${rootProject.buildDir}/${project.name}"
24 | }
25 | subprojects {
26 | project.evaluationDependsOn(':app')
27 | }
28 |
29 | task clean(type: Delete) {
30 | delete rootProject.buildDir
31 | }
32 |
--------------------------------------------------------------------------------
/android/fastlane/Appfile:
--------------------------------------------------------------------------------
1 | json_key_file("") # Path to the json secret file - Follow https://docs.fastlane.tools/actions/supply/#setup to get one
2 | package_name("com.merixstudio.vizier") # e.g. com.krausefx.app
3 |
--------------------------------------------------------------------------------
/android/fastlane/Fastfile:
--------------------------------------------------------------------------------
1 | # This file contains the fastlane.tools configuration
2 | # You can find the documentation at https://docs.fastlane.tools
3 | #
4 | # For a list of all available actions, check out
5 | #
6 | # https://docs.fastlane.tools/actions
7 | #
8 | # For a list of all available plugins, check out
9 | #
10 | # https://docs.fastlane.tools/plugins/available-plugins
11 | #
12 |
13 | # Uncomment the line if you want fastlane to automatically update itself
14 | # update_fastlane
15 |
16 | default_platform(:android)
17 |
18 | platform :android do
19 | desc "Runs all the tests"
20 | lane :test do
21 | gradle(task: "test")
22 | end
23 |
24 | desc "Submit a new Beta Build to Crashlytics Beta"
25 | lane :beta do
26 | gradle(task: "clean assembleRelease")
27 | crashlytics
28 |
29 | # sh "your_script.sh"
30 | # You can also use other beta testing services here
31 | end
32 |
33 | desc "Deploy a new version to the Google Play"
34 | lane :deploy do
35 | gradle(task: "clean assembleRelease")
36 | upload_to_play_store
37 | end
38 | end
39 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.useAndroidX=true
3 | android.enableJetifier=true
4 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Jun 23 08:50:38 CEST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip
7 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
4 | def properties = new Properties()
5 |
6 | assert localPropertiesFile.exists()
7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
8 |
9 | def flutterSdkPath = properties.getProperty("flutter.sdk")
10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
12 |
--------------------------------------------------------------------------------
/assets/fonts/Ubuntu/Ubuntu-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/assets/fonts/Ubuntu/Ubuntu-Bold.ttf
--------------------------------------------------------------------------------
/assets/fonts/Ubuntu/Ubuntu-Light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/assets/fonts/Ubuntu/Ubuntu-Light.ttf
--------------------------------------------------------------------------------
/assets/fonts/Ubuntu/Ubuntu-Medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/assets/fonts/Ubuntu/Ubuntu-Medium.ttf
--------------------------------------------------------------------------------
/assets/fonts/Ubuntu/Ubuntu-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/assets/fonts/Ubuntu/Ubuntu-Regular.ttf
--------------------------------------------------------------------------------
/assets/mocks/finances/investments_image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/assets/mocks/finances/investments_image.png
--------------------------------------------------------------------------------
/assets/mocks/finances/my_account_image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/assets/mocks/finances/my_account_image.png
--------------------------------------------------------------------------------
/assets/mocks/portfolio/google_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/assets/mocks/portfolio/google_logo.png
--------------------------------------------------------------------------------
/assets/mocks/portfolio/netflix_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/assets/mocks/portfolio/netflix_logo.png
--------------------------------------------------------------------------------
/assets/mocks/portfolio/nike_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/assets/mocks/portfolio/nike_logo.png
--------------------------------------------------------------------------------
/assets/mocks/portfolio/tesla_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/assets/mocks/portfolio/tesla_logo.png
--------------------------------------------------------------------------------
/assets/mocks/transactions/apple_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/assets/mocks/transactions/apple_logo.png
--------------------------------------------------------------------------------
/assets/mocks/transactions/nike_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/assets/mocks/transactions/nike_logo.png
--------------------------------------------------------------------------------
/assets/mocks/transactions/paypal_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/assets/mocks/transactions/paypal_logo.png
--------------------------------------------------------------------------------
/assets/mocks/transactions/uber_eats_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/assets/mocks/transactions/uber_eats_logo.png
--------------------------------------------------------------------------------
/assets/mocks/transactions/vodafone_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/assets/mocks/transactions/vodafone_logo.png
--------------------------------------------------------------------------------
/assets/mocks/user/avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/assets/mocks/user/avatar.png
--------------------------------------------------------------------------------
/assets/svgs/card_face.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/build.yaml:
--------------------------------------------------------------------------------
1 | targets:
2 | $default:
3 | builders:
4 | json_serializable:
5 | options:
6 | any_map: true
7 | explicit_to_json: true
8 | field_rename: snake
9 |
--------------------------------------------------------------------------------
/ios/.gitignore:
--------------------------------------------------------------------------------
1 | **/dgph
2 | *.mode1v3
3 | *.mode2v3
4 | *.moved-aside
5 | *.pbxuser
6 | *.perspectivev3
7 | **/*sync/
8 | .sconsign.dblite
9 | .tags*
10 | **/.vagrant/
11 | **/DerivedData/
12 | Icon?
13 | **/Pods/
14 | **/.symlinks/
15 | profile
16 | xcuserdata
17 | **/.generated/
18 | Flutter/App.framework
19 | Flutter/Flutter.framework
20 | Flutter/Flutter.podspec
21 | Flutter/Generated.xcconfig
22 | Flutter/ephemeral/
23 | Flutter/app.flx
24 | Flutter/app.zip
25 | Flutter/flutter_assets/
26 | Flutter/flutter_export_environment.sh
27 | ServiceDefinitions.json
28 | Runner/GeneratedPluginRegistrant.*
29 |
30 | # Exceptions to above rules.
31 | !default.mode1v3
32 | !default.mode2v3
33 | !default.pbxuser
34 | !default.perspectivev3
35 |
--------------------------------------------------------------------------------
/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 11.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/ios/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 |
3 | gem "fastlane"
4 | gem "cocoapods"
5 |
--------------------------------------------------------------------------------
/ios/Podfile:
--------------------------------------------------------------------------------
1 | platform :ios, '11.0'
2 |
3 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
4 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
5 |
6 | project 'Runner', {
7 | 'Debug' => :debug,
8 | 'Profile' => :release,
9 | 'Release' => :release,
10 | }
11 |
12 | def flutter_root
13 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
14 | unless File.exist?(generated_xcode_build_settings_path)
15 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
16 | end
17 |
18 | File.foreach(generated_xcode_build_settings_path) do |line|
19 | matches = line.match(/FLUTTER_ROOT\=(.*)/)
20 | return matches[1].strip if matches
21 | end
22 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
23 | end
24 |
25 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
26 |
27 | flutter_ios_podfile_setup
28 |
29 | target 'Runner' do
30 | use_frameworks!
31 | use_modular_headers!
32 |
33 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
34 | end
35 |
36 | post_install do |installer|
37 | installer.pods_project.targets.each do |target|
38 | flutter_additional_ios_build_settings(target)
39 | end
40 | end
41 |
--------------------------------------------------------------------------------
/ios/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - Flutter (1.0.0)
3 | - flutter_secure_storage (3.3.1):
4 | - Flutter
5 | - shared_preferences_ios (0.0.1):
6 | - Flutter
7 |
8 | DEPENDENCIES:
9 | - Flutter (from `Flutter`)
10 | - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
11 | - shared_preferences_ios (from `.symlinks/plugins/shared_preferences_ios/ios`)
12 |
13 | EXTERNAL SOURCES:
14 | Flutter:
15 | :path: Flutter
16 | flutter_secure_storage:
17 | :path: ".symlinks/plugins/flutter_secure_storage/ios"
18 | shared_preferences_ios:
19 | :path: ".symlinks/plugins/shared_preferences_ios/ios"
20 |
21 | SPEC CHECKSUMS:
22 | Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
23 | flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec
24 | shared_preferences_ios: 548a61f8053b9b8a49ac19c1ffbc8b92c50d68ad
25 |
26 | PODFILE CHECKSUM: 985e5b058f26709dc81f9ae74ea2b2775bdbcefe
27 |
28 | COCOAPODS: 1.11.3
29 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Flutter
3 |
4 | @UIApplicationMain
5 | @objc class AppDelegate: FlutterAppDelegate {
6 | override func application(
7 | _ application: UIApplication,
8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
9 | ) -> Bool {
10 | GeneratedPluginRegistrant.register(with: self)
11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/merixstudio/flutter-vizier-challenge/0cc01b5cc0795a9301a0fe73cc1b158f72fd8451/ios/Runner/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "LaunchImage.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | },
12 | "properties" : {
13 | "preserves-vector-representation" : true
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | 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.
--------------------------------------------------------------------------------
/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleDisplayName
8 | Vizier
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | vizier
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | $(FLUTTER_BUILD_NAME)
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | $(FLUTTER_BUILD_NUMBER)
25 | LSRequiresIPhoneOS
26 |
27 | UILaunchStoryboardName
28 | LaunchScreen
29 | UIMainStoryboardFile
30 | Main
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 |
35 | UISupportedInterfaceOrientations~ipad
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationPortraitUpsideDown
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UIViewControllerBasedStatusBarAppearance
43 |
44 | CADisableMinimumFrameDurationOnPhone
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
2 |
--------------------------------------------------------------------------------
/ios/fastlane/Appfile:
--------------------------------------------------------------------------------
1 | app_identifier("com.merixstudio.vizier") # The bundle identifier of your app
2 | # apple_id("[[APPLE_ID]]") # Your Apple email address
3 |
4 |
5 | # For more information about the Appfile, see:
6 | # https://docs.fastlane.tools/advanced/#appfile
7 |
--------------------------------------------------------------------------------
/ios/fastlane/Fastfile:
--------------------------------------------------------------------------------
1 | # This file contains the fastlane.tools configuration
2 | # You can find the documentation at https://docs.fastlane.tools
3 | #
4 | # For a list of all available actions, check out
5 | #
6 | # https://docs.fastlane.tools/actions
7 | #
8 | # For a list of all available plugins, check out
9 | #
10 | # https://docs.fastlane.tools/plugins/available-plugins
11 | #
12 |
13 | # Uncomment the line if you want fastlane to automatically update itself
14 | # update_fastlane
15 |
16 | default_platform(:ios)
17 |
18 | platform :ios do
19 | desc "Description of what the lane does"
20 | lane :custom_lane do
21 | # add actions here: https://docs.fastlane.tools/actions
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/l10n.yaml:
--------------------------------------------------------------------------------
1 | arb-dir: lib/l10n
2 | template-arb-file: app_en.arb
3 | output-localization-file: app_localizations.dart
--------------------------------------------------------------------------------
/lib/config/constants/animation_constants.dart:
--------------------------------------------------------------------------------
1 | part of 'app_constants.dart';
2 |
3 | class _AnimationConstants {
4 | const _AnimationConstants();
5 |
6 | Duration get defaultDuration => const Duration(
7 | milliseconds: 300,
8 | );
9 | Duration get pieChartSweep => const Duration(
10 | seconds: 1,
11 | );
12 | }
13 |
--------------------------------------------------------------------------------
/lib/config/constants/api_constants.dart:
--------------------------------------------------------------------------------
1 | part of 'app_constants.dart';
2 |
3 | class _ApiConstants {
4 | const _ApiConstants();
5 |
6 | Duration get dummyLoadingDurationBuffor => Duration(
7 | seconds: DI.resolve().randomInt(
8 | maxNumber: 0,
9 | ),
10 | );
11 |
12 | Duration get dummyLoadingDuration => Duration.zero;
13 | }
14 |
--------------------------------------------------------------------------------
/lib/config/constants/app_constants.dart:
--------------------------------------------------------------------------------
1 | import 'package:vizier/config/injector/di.dart';
2 | import 'package:vizier/utils/dummy_util.dart';
3 |
4 | part 'animation_constants.dart';
5 | part 'api_constants.dart';
6 |
7 | class AppConstants {
8 | const AppConstants._();
9 |
10 | static const _AnimationConstants animation = _AnimationConstants();
11 | static const _ApiConstants api = _ApiConstants();
12 | }
13 |
--------------------------------------------------------------------------------
/lib/config/formatters/card_date_input_formatter.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/services.dart';
2 |
3 | class CardDateInputFormatter extends TextInputFormatter {
4 | @override
5 | TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
6 | if (newValue.selection.baseOffset == 0) {
7 | return newValue;
8 | }
9 | final String text = newValue.text;
10 | final StringBuffer buffer = StringBuffer();
11 | for (int i = 0; i < text.length; i++) {
12 | buffer.write(text[i]);
13 | final int nonZeroIndex = i + 1;
14 | if (nonZeroIndex.isEven && nonZeroIndex != text.length) {
15 | buffer.write('/');
16 | }
17 | }
18 | final String newText = buffer.toString();
19 | return newValue.copyWith(
20 | text: newText,
21 | selection: TextSelection.collapsed(
22 | offset: newText.length,
23 | ),
24 | );
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/lib/config/formatters/card_number_input_formatter.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/services.dart';
2 |
3 | class CardNumberInputFormatter extends TextInputFormatter {
4 | @override
5 | TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
6 | if (newValue.selection.baseOffset == 0) {
7 | return newValue;
8 | }
9 | final String text = newValue.text;
10 | final StringBuffer buffer = StringBuffer();
11 | for (int i = 0; i < text.length; i++) {
12 | buffer.write(text[i]);
13 | final int nonZeroIndex = i + 1;
14 | if (nonZeroIndex % 4 == 0 && nonZeroIndex != text.length) {
15 | buffer.write(' ');
16 | }
17 | }
18 | final String newText = buffer.toString();
19 | return newValue.copyWith(
20 | text: newText,
21 | selection: TextSelection.collapsed(
22 | offset: newText.length,
23 | ),
24 | );
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/lib/config/injector/di.dart:
--------------------------------------------------------------------------------
1 | import 'package:get_it/get_it.dart';
2 | import 'package:injectable/injectable.dart';
3 | import 'package:vizier/config/injector/di.config.dart';
4 |
5 | @InjectableInit()
6 | class DI {
7 | DI._();
8 |
9 | final GetIt _getIt = GetIt.I;
10 |
11 | static final DI instance = DI._();
12 |
13 | Future setupInjection() async => $initGetIt(_getIt);
14 |
15 | // Use this to get registered instance
16 | static T resolve() => instance._getIt.get();
17 | }
18 |
--------------------------------------------------------------------------------
/lib/config/injector/module/common_module.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_secure_storage/flutter_secure_storage.dart';
2 | import 'package:injectable/injectable.dart';
3 | import 'package:shared_preferences/shared_preferences.dart';
4 |
5 | @module
6 | abstract class CommonModule {
7 | @preResolve // if you need to pre resolve the value
8 | Future get prefs => SharedPreferences.getInstance();
9 |
10 | @injectable
11 | FlutterSecureStorage get flutterSecureStorage => const FlutterSecureStorage();
12 | }
13 |
--------------------------------------------------------------------------------
/lib/config/styles/colors/app_colors_border.dart:
--------------------------------------------------------------------------------
1 | part of 'app_colors.dart';
2 |
3 | class _Border {
4 | const _Border();
5 |
6 | Color get success => AppColors.success100;
7 | Color get info => AppColors.info100;
8 | Color get error => AppColors.error300;
9 | }
10 |
--------------------------------------------------------------------------------
/lib/config/styles/decorations/app_decorations.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:vizier/config/styles/colors/app_colors.dart';
3 | import 'package:vizier/config/styles/dimensions/app_dimensions.dart';
4 | import 'package:vizier/config/styles/text_styles/app_text_styles.dart';
5 |
6 | part 'app_decorations_button.dart';
7 | part 'app_decorations_input.dart';
8 |
9 | class AppDecorations {
10 | const AppDecorations._();
11 |
12 | static const _Button button = _Button();
13 | static const _Input input = _Input();
14 |
15 | static BoxDecoration defaultBorder() {
16 | return BoxDecoration(
17 | border: Border.all(
18 | color: AppColors.gray400,
19 | ),
20 | borderRadius: AppDimensions.radius.borderedRadius(),
21 | );
22 | }
23 |
24 | static BoxDecoration navyBox() {
25 | return BoxDecoration(
26 | borderRadius: BorderRadius.circular(12.0),
27 | color: AppColors.navy,
28 | );
29 | }
30 |
31 | static BoxDecoration primaryBox() {
32 | return navyBox().copyWith(
33 | color: AppColors.primary100,
34 | );
35 | }
36 |
37 | static ShapeBorder get bottomSheetShape => const RoundedRectangleBorder(
38 | borderRadius: BorderRadius.vertical(
39 | top: Radius.circular(24.0),
40 | ),
41 | );
42 | }
43 |
--------------------------------------------------------------------------------
/lib/config/styles/decorations/app_decorations_button.dart:
--------------------------------------------------------------------------------
1 | part of 'app_decorations.dart';
2 |
3 | class _Button {
4 | const _Button();
5 |
6 | BorderRadius get _borderRadius => BorderRadius.circular(8.0);
7 |
8 | BoxDecoration primary({
9 | bool isDisabled = false,
10 | }) {
11 | return BoxDecoration(
12 | borderRadius: _borderRadius,
13 | color: AppColors.primary100,
14 | );
15 | }
16 |
17 | BoxDecoration secondary({
18 | bool isDisabled = false,
19 | }) {
20 | return BoxDecoration(
21 | border: Border.all(
22 | color: AppColors.primary100,
23 | width: 2.0,
24 | ),
25 | borderRadius: _borderRadius,
26 | color: AppColors.white,
27 | );
28 | }
29 |
30 | BoxDecoration disabled() {
31 | return BoxDecoration(
32 | borderRadius: _borderRadius,
33 | color: AppColors.gray500,
34 | );
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/lib/config/styles/decorations/app_decorations_input.dart:
--------------------------------------------------------------------------------
1 | part of 'app_decorations.dart';
2 |
3 | class _Input {
4 | const _Input();
5 |
6 | InputDecoration standard({
7 | required bool isValid,
8 | String? labelText,
9 | }) {
10 | return InputDecoration(
11 | border: _inputBorder(
12 | color: AppColors.gray400,
13 | ),
14 | contentPadding: AppDimensions.padding.defaultHorizontal(),
15 | disabledBorder: _inputBorder(
16 | color: AppColors.gray400,
17 | ),
18 | enabledBorder: _inputBorder(
19 | color: AppColors.gray400,
20 | ),
21 | errorBorder: _inputBorder(
22 | color: AppColors.error100,
23 | ),
24 | focusedErrorBorder: _inputBorder(
25 | color: AppColors.error100,
26 | ),
27 | errorStyle: AppTextStyles.caption2().copyWith(
28 | color: AppColors.error100,
29 | ),
30 | floatingLabelStyle: AppTextStyles.caption2().copyWith(
31 | color: isValid ? AppColors.navy : AppColors.error100,
32 | ),
33 | focusedBorder: _inputBorder(
34 | color: AppColors.primary100,
35 | ),
36 | hintStyle: AppTextStyles.text2().copyWith(
37 | color: AppColors.navy,
38 | ),
39 | labelText: labelText,
40 | labelStyle: AppTextStyles.text2().copyWith(
41 | color: AppColors.gray200,
42 | ),
43 | );
44 | }
45 | }
46 |
47 | InputBorder _inputBorder({
48 | required Color color,
49 | }) {
50 | return OutlineInputBorder(
51 | borderSide: BorderSide(
52 | color: color,
53 | ),
54 | borderRadius: AppDimensions.radius.defaultRadius(),
55 | );
56 | }
57 |
--------------------------------------------------------------------------------
/lib/config/styles/dimensions/app_dimensions.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | part 'app_dimensions_padding.dart';
4 | part 'app_dimensions_radius.dart';
5 |
6 | class AppDimensions {
7 | const AppDimensions._();
8 |
9 | static const _Padding padding = _Padding();
10 | static const _Radius radius = _Radius();
11 | }
12 |
--------------------------------------------------------------------------------
/lib/config/styles/dimensions/app_dimensions_padding.dart:
--------------------------------------------------------------------------------
1 | part of 'app_dimensions.dart';
2 |
3 | class _Padding {
4 | const _Padding();
5 |
6 | double get defaultValue => 16.0;
7 | double get smallestValue => 4.0;
8 | double get smallValue => 8.0;
9 | double get bigValue => 24.0;
10 | double get biggerValue => 32.0;
11 | double get biggestValue => 48.0;
12 |
13 | EdgeInsets defaultHorizontal() {
14 | return EdgeInsets.symmetric(
15 | horizontal: defaultValue,
16 | );
17 | }
18 |
19 | EdgeInsets smallHorizontal() {
20 | return EdgeInsets.symmetric(
21 | horizontal: smallValue,
22 | );
23 | }
24 |
25 | EdgeInsets bigHorizontal() {
26 | return EdgeInsets.symmetric(
27 | horizontal: bigValue,
28 | );
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/lib/config/styles/dimensions/app_dimensions_radius.dart:
--------------------------------------------------------------------------------
1 | part of 'app_dimensions.dart';
2 |
3 | class _Radius {
4 | const _Radius();
5 |
6 | double get defaultValue => 8.0;
7 | double get borderedButton => 12.0;
8 |
9 | BorderRadius defaultRadius() {
10 | return BorderRadius.circular(defaultValue);
11 | }
12 |
13 | BorderRadius borderedRadius() {
14 | return BorderRadius.circular(borderedButton);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/lib/config/styles/images/app_images.dart:
--------------------------------------------------------------------------------
1 | part 'svg_images.dart';
2 |
3 | class AppImages {
4 | static const _SvgImages svg = _SvgImages();
5 | }
6 |
--------------------------------------------------------------------------------
/lib/config/styles/images/svg_images.dart:
--------------------------------------------------------------------------------
1 | part of 'app_images.dart';
2 |
3 | class _SvgImages {
4 | const _SvgImages();
5 |
6 | String get _path => 'assets/svgs';
7 | String get manageMoney => '$_path/manage_money.svg';
8 | String get allMoney => '$_path/all_money.svg';
9 | String get chip => '$_path/chip.svg';
10 | String get stayFocused => '$_path/stay_focused.svg';
11 | String get moneyLogin => '$_path/money_login.svg';
12 | String get banerBoy => '$_path/baner_boy.svg';
13 | String get bitcoin => '$_path/bitcoin.svg';
14 | String get cardFace => '$_path/card_face.svg';
15 | String get mortgage => '$_path/mortgage.svg';
16 | String get retirementGoals => '$_path/retirement_goals.svg';
17 | String get mortgageDetails => '$_path/mortgage_details.svg';
18 | String get retirementGoalsDetails => '$_path/retirement_goals_details.svg';
19 | }
20 |
--------------------------------------------------------------------------------
/lib/config/styles/text_styles/app_text_styles_button.dart:
--------------------------------------------------------------------------------
1 | part of 'app_text_styles.dart';
2 |
3 | class _Button {
4 | const _Button();
5 |
6 | TextStyle defaultStyle() {
7 | return AppTextStyles.defaultStyle().copyWith(
8 | color: AppColors.black,
9 | fontSize: 14.0,
10 | fontWeight: FontWeight.bold,
11 | letterSpacing: 0.5,
12 | );
13 | }
14 |
15 | TextStyle primary({
16 | bool isDisabled = false,
17 | }) {
18 | return defaultStyle().copyWith(
19 | color: AppColors.white,
20 | );
21 | }
22 |
23 | TextStyle secondary({
24 | bool isDisabled = false,
25 | }) {
26 | return defaultStyle().copyWith(
27 | color: AppColors.primary100,
28 | );
29 | }
30 |
31 | TextStyle disabled() {
32 | return defaultStyle().copyWith(
33 | color: AppColors.gray200,
34 | );
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/lib/config/styles/theme/app_theme.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:vizier/config/styles/colors/app_colors.dart';
3 | import 'package:vizier/config/styles/text_styles/app_text_styles.dart';
4 |
5 | part 'dark_theme.dart';
6 | part 'light_theme.dart';
7 |
8 | enum ThemeType { light, dark }
9 |
10 | class AppTheme {
11 | final ThemeType type;
12 |
13 | AppTheme._(this.type);
14 |
15 | factory AppTheme.fromType(ThemeType type) => AppTheme._(type);
16 |
17 | ThemeData get themeData {
18 | switch (type) {
19 | case ThemeType.dark:
20 | return darkTheme;
21 | case ThemeType.light:
22 | default:
23 | return lightTheme;
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/lib/config/styles/theme/dark_theme.dart:
--------------------------------------------------------------------------------
1 | part of 'app_theme.dart';
2 |
3 | ThemeData get darkTheme {
4 | return lightTheme;
5 | }
6 |
--------------------------------------------------------------------------------
/lib/cubits/account_financial_breakdown/account_financial_breakdown_state.dart:
--------------------------------------------------------------------------------
1 | part of 'account_financial_breakdown_cubit.dart';
2 |
3 | @freezed
4 | class AccountFinancialBreakdownState with _$AccountFinancialBreakdownState {
5 | const AccountFinancialBreakdownState._();
6 | const factory AccountFinancialBreakdownState.initial() = _Initial;
7 | const factory AccountFinancialBreakdownState.loading() = _Loading;
8 | const factory AccountFinancialBreakdownState.loaded({
9 | required DateTime from,
10 | required DateTime to,
11 | required List sections,
12 | required List transactionCategories,
13 | }) = _Loaded;
14 | const factory AccountFinancialBreakdownState.failure({
15 | required AppError appError,
16 | }) = _Failure;
17 |
18 | List? get sections => mapOrNull(
19 | loaded: (state) => state.sections,
20 | );
21 |
22 | List? get transactionCategories => mapOrNull(
23 | loaded: (state) => state.transactionCategories,
24 | );
25 |
26 | DateTime? get from => mapOrNull(
27 | loaded: (state) => state.from,
28 | );
29 |
30 | DateTime? get to => mapOrNull(
31 | loaded: (state) => state.to,
32 | );
33 | }
34 |
--------------------------------------------------------------------------------
/lib/cubits/authentication/authentication_cubit.dart:
--------------------------------------------------------------------------------
1 | import 'package:bloc/bloc.dart';
2 | import 'package:freezed_annotation/freezed_annotation.dart';
3 | import 'package:injectable/injectable.dart';
4 | import 'package:vizier/data/storages/token_storage.dart';
5 |
6 | part 'authentication_state.dart';
7 | part 'authentication_cubit.freezed.dart';
8 |
9 | @injectable
10 | class AuthenticationCubit extends Cubit {
11 | final TokenStorage tokenStorage;
12 |
13 | AuthenticationCubit({
14 | required this.tokenStorage,
15 | }) : super(const AuthenticationState.initial());
16 |
17 | Future checkAuth() async {
18 | final bool hasToken = await tokenStorage.hasToken();
19 | if (hasToken) {
20 | emit(
21 | const AuthenticationState.authenticated(),
22 | );
23 | } else {
24 | emit(
25 | const AuthenticationState.unauthenticated(),
26 | );
27 | }
28 | }
29 |
30 | Future authenticate({
31 | required String accessToken,
32 | }) async {
33 | await tokenStorage.storeAccessToken(accessToken);
34 | emit(
35 | const AuthenticationState.authenticated(),
36 | );
37 | }
38 |
39 | Future logout() async {
40 | await tokenStorage.clear();
41 | emit(
42 | const AuthenticationState.logout(),
43 | );
44 | emit(
45 | const AuthenticationState.unauthenticated(),
46 | );
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/lib/cubits/authentication/authentication_state.dart:
--------------------------------------------------------------------------------
1 | part of 'authentication_cubit.dart';
2 |
3 | @freezed
4 | class AuthenticationState with _$AuthenticationState {
5 | const AuthenticationState._();
6 | const factory AuthenticationState.initial() = _Initial;
7 | const factory AuthenticationState.loading() = _Loading;
8 | const factory AuthenticationState.authenticated() = _Authenticated;
9 | const factory AuthenticationState.unauthenticated() = _Unauthenticated;
10 | const factory AuthenticationState.error(Error error) = _Error;
11 | const factory AuthenticationState.logout() = _Logout;
12 |
13 | bool get isLoading => this is _Loading;
14 |
15 | bool get isLogged => maybeWhen(
16 | authenticated: () => true,
17 | orElse: () => false,
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/lib/cubits/authentication/login/authentication_login_cubit.dart:
--------------------------------------------------------------------------------
1 | import 'package:bloc/bloc.dart';
2 | import 'package:freezed_annotation/freezed_annotation.dart';
3 | import 'package:injectable/injectable.dart';
4 | import 'package:vizier/data/errors/app_error.dart';
5 | import 'package:vizier/data/repositories/authentication/authentication_repository.dart';
6 | import 'package:vizier/data/requests/authentication/authentication_request.dart';
7 | import 'package:vizier/data/responses/authentication/authentication_response.dart';
8 | import 'package:vizier/data/responses/response_status.dart';
9 |
10 | part 'authentication_login_cubit.freezed.dart';
11 | part 'authentication_login_state.dart';
12 |
13 | @injectable
14 | class AuthenticationLoginCubit extends Cubit {
15 | final AuthenticationRepository authenticationRepository;
16 |
17 | AuthenticationLoginCubit({
18 | required this.authenticationRepository,
19 | }) : super(const AuthenticationLoginState.initial());
20 |
21 | Future login(AuthenticationRequest request) async {
22 | emit(
23 | const AuthenticationLoginState.loading(),
24 | );
25 |
26 | final ResponseStatus responseStatus = await authenticationRepository.login(request);
27 |
28 | responseStatus.result(
29 | onSuccess: (response) {
30 | emit(
31 | AuthenticationLoginState.success(
32 | token: response.token,
33 | ),
34 | );
35 | },
36 | onError: (error) => emit(
37 | AuthenticationLoginState.error(error),
38 | ),
39 | );
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/lib/cubits/authentication/login/authentication_login_state.dart:
--------------------------------------------------------------------------------
1 | part of 'authentication_login_cubit.dart';
2 |
3 | @freezed
4 | class AuthenticationLoginState with _$AuthenticationLoginState {
5 | const AuthenticationLoginState._();
6 | const factory AuthenticationLoginState.initial() = _Initial;
7 | const factory AuthenticationLoginState.loading() = _Loading;
8 | const factory AuthenticationLoginState.success({
9 | required String token,
10 | }) = _Success;
11 | const factory AuthenticationLoginState.error(AppError error) = _Error;
12 |
13 | bool get isLoading => maybeMap(
14 | loading: (_) => true,
15 | orElse: () => false,
16 | );
17 | }
18 |
--------------------------------------------------------------------------------
/lib/cubits/card_form/add/card_add_cubit.dart:
--------------------------------------------------------------------------------
1 | import 'package:bloc/bloc.dart';
2 | import 'package:freezed_annotation/freezed_annotation.dart';
3 | import 'package:injectable/injectable.dart';
4 | import 'package:vizier/data/errors/app_error.dart';
5 | import 'package:vizier/data/models/account/account_model.dart';
6 | import 'package:vizier/data/repositories/wallet/wallet_repository.dart';
7 | import 'package:vizier/data/responses/response_status.dart';
8 |
9 | part 'card_add_state.dart';
10 | part 'card_add_cubit.freezed.dart';
11 |
12 | @injectable
13 | class CardAddCubit extends Cubit {
14 | final WalletRepository walletRepository;
15 |
16 | CardAddCubit({
17 | required this.walletRepository,
18 | }) : super(const CardAddState.initial());
19 |
20 | Future add(AccountModel account) async {
21 | emit(
22 | const CardAddState.loading(),
23 | );
24 |
25 | final ResponseStatus response = await walletRepository.addWalletAccount(
26 | account: account,
27 | );
28 | response.result(
29 | onSuccess: (_) => emit(
30 | const CardAddState.success(),
31 | ),
32 | onError: (error) => emit(
33 | CardAddState.failure(
34 | error: error,
35 | ),
36 | ),
37 | );
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/lib/cubits/card_form/add/card_add_state.dart:
--------------------------------------------------------------------------------
1 | part of 'card_add_cubit.dart';
2 |
3 | @freezed
4 | class CardAddState with _$CardAddState {
5 | const CardAddState._();
6 |
7 | const factory CardAddState.initial() = _Initial;
8 | const factory CardAddState.loading() = _Loading;
9 | const factory CardAddState.success() = _Success;
10 | const factory CardAddState.failure({
11 | required AppError error,
12 | }) = _Error;
13 |
14 | bool get isLoading => maybeWhen(
15 | loading: () => true,
16 | orElse: () => false,
17 | );
18 |
19 | bool get isSuccess => maybeWhen(
20 | success: () => true,
21 | orElse: () => false,
22 | );
23 | }
24 |
--------------------------------------------------------------------------------
/lib/cubits/card_form/card_form_cubit.dart:
--------------------------------------------------------------------------------
1 | import 'package:bloc/bloc.dart';
2 | import 'package:freezed_annotation/freezed_annotation.dart';
3 | import 'package:injectable/injectable.dart';
4 | import 'package:vizier/data/models/account/account_model.dart';
5 | import 'package:vizier/ui/models/card_account_type.dart';
6 |
7 | part 'card_form_state.dart';
8 | part 'card_form_cubit.freezed.dart';
9 |
10 | @injectable
11 | class CardFormCubit extends Cubit {
12 | CardFormCubit() : super(CardFormState.initial());
13 |
14 | void updateBilling(String billing) => emit(
15 | state.copyWith(
16 | billing: billing,
17 | ),
18 | );
19 |
20 | void updateCvv(String cvv) => emit(
21 | state.copyWith(
22 | cvv: cvv,
23 | ),
24 | );
25 |
26 | void updateExpiry(String expiry) => emit(
27 | state.copyWith(
28 | expiry: expiry,
29 | ),
30 | );
31 |
32 | void updateName(String name) => emit(
33 | state.copyWith(
34 | name: name,
35 | ),
36 | );
37 |
38 | void updateNumber(String number) => emit(
39 | state.copyWith(
40 | number: number,
41 | ),
42 | );
43 |
44 | void updateType(CardAccountType type) => emit(
45 | state.copyWith(
46 | type: type,
47 | ),
48 | );
49 | }
50 |
--------------------------------------------------------------------------------
/lib/cubits/card_form/card_form_state.dart:
--------------------------------------------------------------------------------
1 | part of 'card_form_cubit.dart';
2 |
3 | @freezed
4 | class CardFormState with _$CardFormState {
5 | const factory CardFormState({
6 | required String billing,
7 | required String cvv,
8 | required String expiry,
9 | required String name,
10 | required String number,
11 | required CardAccountType type,
12 | }) = _CardFormState;
13 |
14 | const CardFormState._();
15 |
16 | factory CardFormState.initial() => const CardFormState(
17 | billing: '',
18 | cvv: '',
19 | expiry: '',
20 | name: '',
21 | number: '',
22 | type: CardAccountType.front,
23 | );
24 |
25 | AccountModel get account => AccountModel(
26 | balance: 0.0,
27 | change: 0.0,
28 | expiry: expiry,
29 | logo: '',
30 | name: name,
31 | number: number,
32 | );
33 | }
34 |
--------------------------------------------------------------------------------
/lib/cubits/chart_tabs/chart_tab.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:vizier/l10n/app_loc.dart';
3 |
4 | enum ChartTab { week, month, year, all }
5 |
6 | extension ChartTabExtension on ChartTab {
7 | String title(BuildContext context) {
8 | switch (this) {
9 | case ChartTab.week:
10 | return AppLoc.of(context).chartTabWeek;
11 | case ChartTab.month:
12 | return AppLoc.of(context).chartTabMonth;
13 | case ChartTab.year:
14 | return AppLoc.of(context).chartTabYear;
15 | case ChartTab.all:
16 | return AppLoc.of(context).chartTabAll;
17 | }
18 | }
19 |
20 | int days() {
21 | switch (this) {
22 | case ChartTab.week:
23 | return DateTime.daysPerWeek;
24 | case ChartTab.month:
25 | return DateTime.monthsPerYear;
26 | case ChartTab.year:
27 | return DateTime.monthsPerYear * 30;
28 | case ChartTab.all:
29 | return 0;
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/lib/cubits/chart_tabs/chart_tabs_cubit.dart:
--------------------------------------------------------------------------------
1 | import 'package:bloc/bloc.dart';
2 | import 'package:freezed_annotation/freezed_annotation.dart';
3 | import 'package:injectable/injectable.dart';
4 | import 'package:vizier/cubits/chart_tabs/chart_tab.dart';
5 |
6 | part 'chart_tabs_state.dart';
7 | part 'chart_tabs_cubit.freezed.dart';
8 |
9 | @injectable
10 | class ChartTabsCubit extends Cubit {
11 | ChartTabsCubit()
12 | : super(
13 | const ChartTabsState.tab(ChartTab.week),
14 | );
15 |
16 | void changeTab(ChartTab tab) {
17 | emit(
18 | ChartTabsState.tab(tab),
19 | );
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/lib/cubits/chart_tabs/chart_tabs_state.dart:
--------------------------------------------------------------------------------
1 | part of 'chart_tabs_cubit.dart';
2 |
3 | @freezed
4 | class ChartTabsState with _$ChartTabsState {
5 | const factory ChartTabsState.tab(ChartTab selectedTab) = _Tab;
6 | }
7 |
--------------------------------------------------------------------------------
/lib/cubits/company_listing/details/company_listing_details_cubit.dart:
--------------------------------------------------------------------------------
1 | import 'package:bloc/bloc.dart';
2 | import 'package:freezed_annotation/freezed_annotation.dart';
3 | import 'package:injectable/injectable.dart';
4 | import 'package:vizier/data/errors/app_error.dart';
5 | import 'package:vizier/data/models/company_asset/company_asset_model.dart';
6 | import 'package:vizier/data/models/company_listing/details/company_listing_details_item_model.dart';
7 | import 'package:vizier/data/repositories/portfolio/portfolio_repository.dart';
8 | import 'package:vizier/data/responses/response_status.dart';
9 |
10 | part 'company_listing_details_state.dart';
11 | part 'company_listing_details_cubit.freezed.dart';
12 |
13 | @injectable
14 | class CompanyListingDetailsCubit extends Cubit {
15 | final PortfolioRepository portfolioRepository;
16 |
17 | CompanyListingDetailsCubit({
18 | required this.portfolioRepository,
19 | }) : super(const CompanyListingDetailsState.initial());
20 |
21 | Future fetchData({
22 | required CompanyAssetModel companyAsset,
23 | }) async {
24 | emit(
25 | const CompanyListingDetailsState.loading(),
26 | );
27 |
28 | final ResponseStatus> response = await portfolioRepository.details();
29 | response.result(
30 | onSuccess: (data) => emit(
31 | CompanyListingDetailsState.loaded(
32 | details: data,
33 | ),
34 | ),
35 | onError: (error) => emit(
36 | CompanyListingDetailsState.failure(
37 | error: error,
38 | ),
39 | ),
40 | );
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/lib/cubits/company_listing/details/company_listing_details_state.dart:
--------------------------------------------------------------------------------
1 | part of 'company_listing_details_cubit.dart';
2 |
3 | @freezed
4 | class CompanyListingDetailsState with _$CompanyListingDetailsState {
5 | const CompanyListingDetailsState._();
6 |
7 | const factory CompanyListingDetailsState.initial() = _Initial;
8 | const factory CompanyListingDetailsState.loading() = _Loading;
9 | const factory CompanyListingDetailsState.loaded({
10 | required List details,
11 | }) = _Loaded;
12 | const factory CompanyListingDetailsState.failure({
13 | required AppError error,
14 | }) = _Error;
15 |
16 | bool get isLoading => maybeMap(
17 | loading: (_) => true,
18 | orElse: () => false,
19 | );
20 |
21 | List get details => maybeWhen(
22 | loaded: (data) => data,
23 | orElse: () => [],
24 | );
25 | }
26 |
--------------------------------------------------------------------------------
/lib/cubits/company_listing/history/company_listing_history_state.dart:
--------------------------------------------------------------------------------
1 | part of 'company_listing_history_cubit.dart';
2 |
3 | @freezed
4 | class CompanyListingHistoryState with _$CompanyListingHistoryState {
5 | const CompanyListingHistoryState._();
6 |
7 | const factory CompanyListingHistoryState.initial() = _Initial;
8 | const factory CompanyListingHistoryState.loading() = _Loading;
9 | const factory CompanyListingHistoryState.loaded({
10 | required CompanyListingHistoryModel companyListingHistoryModel,
11 | }) = _Loaded;
12 | const factory CompanyListingHistoryState.failure({
13 | required AppError error,
14 | }) = _Error;
15 |
16 | bool get isLoading => maybeMap(
17 | loading: (_) => true,
18 | orElse: () => false,
19 | );
20 |
21 | CompanyListingHistoryModel? get companyListingHistoryModel => maybeMap(
22 | loaded: (state) => state.companyListingHistoryModel,
23 | orElse: () => null,
24 | );
25 | }
26 |
--------------------------------------------------------------------------------
/lib/cubits/financial_history/financial_history_state.dart:
--------------------------------------------------------------------------------
1 | part of 'financial_history_cubit.dart';
2 |
3 | @freezed
4 | class FinancialHistoryState with _$FinancialHistoryState {
5 | const FinancialHistoryState._();
6 |
7 | const factory FinancialHistoryState.initial() = _Initial;
8 | const factory FinancialHistoryState.loading() = _Loading;
9 | const factory FinancialHistoryState.loaded({
10 | required FinancialHistoryModel financialHistory,
11 | }) = _Loaded;
12 | const factory FinancialHistoryState.failure({
13 | required AppError error,
14 | }) = _Error;
15 |
16 | bool get isLoading => maybeMap(
17 | loading: (_) => true,
18 | orElse: () => false,
19 | );
20 |
21 | FinancialHistoryModel? get financialHistory => maybeMap(
22 | loaded: (state) => state.financialHistory,
23 | orElse: () => null,
24 | );
25 | }
26 |
--------------------------------------------------------------------------------
/lib/cubits/goals/goals_cubit.dart:
--------------------------------------------------------------------------------
1 | import 'package:bloc/bloc.dart';
2 | import 'package:freezed_annotation/freezed_annotation.dart';
3 | import 'package:injectable/injectable.dart';
4 | import 'package:vizier/data/errors/app_error.dart';
5 | import 'package:vizier/data/models/goal/goal_model.dart';
6 | import 'package:vizier/data/repositories/wallet/wallet_repository.dart';
7 | import 'package:vizier/data/responses/response_status.dart';
8 |
9 | part 'goals_state.dart';
10 | part 'goals_cubit.freezed.dart';
11 |
12 | @injectable
13 | class GoalsCubit extends Cubit {
14 | final WalletRepository walletRepository;
15 |
16 | GoalsCubit({
17 | required this.walletRepository,
18 | }) : super(const GoalsState.initial());
19 |
20 | Future fetchData() async {
21 | emit(
22 | const GoalsState.loading(),
23 | );
24 |
25 | final ResponseStatus> response = await walletRepository.goals();
26 | response.result(
27 | onSuccess: (data) => emit(
28 | GoalsState.loaded(
29 | goals: data,
30 | ),
31 | ),
32 | onError: (error) => emit(
33 | GoalsState.failure(
34 | error: error,
35 | ),
36 | ),
37 | );
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/lib/cubits/goals/goals_state.dart:
--------------------------------------------------------------------------------
1 | part of 'goals_cubit.dart';
2 |
3 | @freezed
4 | class GoalsState with _$GoalsState {
5 | const factory GoalsState.initial() = _Initial;
6 | const factory GoalsState.loading() = _Loading;
7 | const factory GoalsState.loaded({
8 | required List goals,
9 | }) = _Loaded;
10 | const factory GoalsState.failure({
11 | required AppError error,
12 | }) = _Failure;
13 | }
14 |
--------------------------------------------------------------------------------
/lib/cubits/my_finances/my_finances_cubit.dart:
--------------------------------------------------------------------------------
1 | import 'package:bloc/bloc.dart';
2 | import 'package:freezed_annotation/freezed_annotation.dart';
3 | import 'package:injectable/injectable.dart';
4 | import 'package:vizier/data/errors/app_error.dart';
5 | import 'package:vizier/data/models/finances_overview/finances_overview_model.dart';
6 | import 'package:vizier/data/repositories/finances/finances_repository.dart';
7 | import 'package:vizier/data/responses/response_status.dart';
8 |
9 | part 'my_finances_state.dart';
10 | part 'my_finances_cubit.freezed.dart';
11 |
12 | @injectable
13 | class MyFinancesCubit extends Cubit {
14 | final FinancesRepository financesRepository;
15 |
16 | MyFinancesCubit({
17 | required this.financesRepository,
18 | }) : super(const MyFinancesState.initial());
19 |
20 | Future fetchData() async {
21 | emit(
22 | const MyFinancesState.loading(),
23 | );
24 |
25 | final ResponseStatus response = await financesRepository.overview();
26 | response.result(
27 | onSuccess: (data) => emit(
28 | MyFinancesState.loaded(
29 | financesOverview: data,
30 | ),
31 | ),
32 | onError: (error) => emit(
33 | MyFinancesState.failure(
34 | error: error,
35 | ),
36 | ),
37 | );
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/lib/cubits/my_finances/my_finances_state.dart:
--------------------------------------------------------------------------------
1 | part of 'my_finances_cubit.dart';
2 |
3 | @freezed
4 | class MyFinancesState with _$MyFinancesState {
5 | const MyFinancesState._();
6 |
7 | const factory MyFinancesState.initial() = _Initial;
8 | const factory MyFinancesState.loading() = _Loading;
9 | const factory MyFinancesState.loaded({
10 | required FinancesOverviewModel financesOverview,
11 | }) = _Loaded;
12 | const factory MyFinancesState.failure({
13 | required AppError error,
14 | }) = _Error;
15 |
16 | bool get isLoading => maybeMap(
17 | loading: (_) => true,
18 | orElse: () => false,
19 | );
20 | }
21 |
--------------------------------------------------------------------------------
/lib/cubits/my_portfolio/my_portfolio_cubit.dart:
--------------------------------------------------------------------------------
1 | import 'package:bloc/bloc.dart';
2 | import 'package:freezed_annotation/freezed_annotation.dart';
3 | import 'package:injectable/injectable.dart';
4 | import 'package:vizier/data/errors/app_error.dart';
5 | import 'package:vizier/data/models/portfolio_overview/portfolio_overview_model.dart';
6 | import 'package:vizier/data/repositories/portfolio/portfolio_repository.dart';
7 | import 'package:vizier/data/responses/response_status.dart';
8 |
9 | part 'my_portfolio_state.dart';
10 | part 'my_portfolio_cubit.freezed.dart';
11 |
12 | @injectable
13 | class MyPortfolioCubit extends Cubit {
14 | final PortfolioRepository portfolioRepository;
15 |
16 | MyPortfolioCubit({
17 | required this.portfolioRepository,
18 | }) : super(const MyPortfolioState.initial());
19 |
20 | Future fetchData() async {
21 | emit(
22 | const MyPortfolioState.loading(),
23 | );
24 |
25 | final ResponseStatus response = await portfolioRepository.overview();
26 | response.result(
27 | onSuccess: (data) => emit(
28 | MyPortfolioState.loaded(
29 | portfolioOverview: data,
30 | ),
31 | ),
32 | onError: (error) => emit(
33 | MyPortfolioState.failure(
34 | error: error,
35 | ),
36 | ),
37 | );
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/lib/cubits/my_portfolio/my_portfolio_state.dart:
--------------------------------------------------------------------------------
1 | part of 'my_portfolio_cubit.dart';
2 |
3 | @freezed
4 | class MyPortfolioState with _$MyPortfolioState {
5 | const MyPortfolioState._();
6 |
7 | const factory MyPortfolioState.initial() = _Initial;
8 | const factory MyPortfolioState.loading() = _Loading;
9 | const factory MyPortfolioState.loaded({
10 | required PortfolioOverviewModel portfolioOverview,
11 | }) = _Loaded;
12 | const factory MyPortfolioState.failure({
13 | required AppError error,
14 | }) = _Error;
15 |
16 | bool get isLoading => maybeMap(
17 | loading: (_) => true,
18 | orElse: () => false,
19 | );
20 |
21 | PortfolioOverviewModel? get portfolioOverview => maybeMap(
22 | loaded: (state) => state.portfolioOverview,
23 | orElse: () => null,
24 | );
25 | }
26 |
--------------------------------------------------------------------------------
/lib/cubits/offers/details/offer_details_cubit.dart:
--------------------------------------------------------------------------------
1 | import 'dart:math';
2 |
3 | import 'package:bloc/bloc.dart';
4 | import 'package:freezed_annotation/freezed_annotation.dart';
5 | import 'package:injectable/injectable.dart';
6 | import 'package:vizier/data/models/offer/offer_model.dart';
7 | import 'package:vizier/data/models/offer/slider_item/offer_slider_model.dart';
8 |
9 | part 'offer_details_state.dart';
10 | part 'offer_details_cubit.freezed.dart';
11 |
12 | @injectable
13 | class OfferDetailsCubit extends Cubit {
14 | OfferDetailsCubit() : super(OfferDetailsState.initial());
15 |
16 | void initial(OfferModel offer) => emit(
17 | state.copyWith(
18 | expectedValue: offer.expectedValue,
19 | sliders: offer.sliders,
20 | ),
21 | );
22 |
23 | void updateSlider(OfferSliderModel slider, double value) {
24 | emit(
25 | state.copyWith(
26 | sliders: state.sliders
27 | .map(
28 | (e) => e == slider
29 | ? e.copyWith(
30 | current: value,
31 | )
32 | : e,
33 | )
34 | .toList(),
35 | ),
36 | );
37 |
38 | emit(
39 | state.copyWith(
40 | calculatedValue: _calculateValue(),
41 | ),
42 | );
43 | }
44 |
45 | double _calculateValue() {
46 | //TODO (MT): Change logic
47 | final double leftToGoal = max((state.expectedValue ?? 0.0) - state.sliders.last.actualValue, 0);
48 | final double estPerMonth = state.sliders.first.actualValue * 1.3;
49 | return estPerMonth + leftToGoal / 300;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/lib/cubits/offers/details/offer_details_state.dart:
--------------------------------------------------------------------------------
1 | part of 'offer_details_cubit.dart';
2 |
3 | @freezed
4 | class OfferDetailsState with _$OfferDetailsState {
5 | const factory OfferDetailsState({
6 | required List sliders,
7 | double? expectedValue,
8 | double? calculatedValue,
9 | }) = _OfferDetailsState;
10 |
11 | factory OfferDetailsState.initial() => const OfferDetailsState(
12 | sliders: [],
13 | );
14 | }
15 |
--------------------------------------------------------------------------------
/lib/cubits/offers/list/offer_list_cubit.dart:
--------------------------------------------------------------------------------
1 | import 'package:bloc/bloc.dart';
2 | import 'package:freezed_annotation/freezed_annotation.dart';
3 | import 'package:injectable/injectable.dart';
4 | import 'package:vizier/data/errors/app_error.dart';
5 | import 'package:vizier/data/models/offer/offer_model.dart';
6 | import 'package:vizier/data/repositories/offers/offers_repository.dart';
7 | import 'package:vizier/data/responses/response_status.dart';
8 |
9 | part 'offer_list_state.dart';
10 | part 'offer_list_cubit.freezed.dart';
11 |
12 | @injectable
13 | class OfferListCubit extends Cubit {
14 | final OffersRepository offersRepository;
15 |
16 | OfferListCubit({
17 | required this.offersRepository,
18 | }) : super(const OfferListState.loading());
19 |
20 | Future fetchData() async {
21 | emit(
22 | const OfferListState.loading(),
23 | );
24 |
25 | final ResponseStatus> response = await offersRepository.all();
26 | response.result(
27 | onSuccess: (data) => emit(
28 | OfferListState.loaded(
29 | offers: data,
30 | ),
31 | ),
32 | onError: (error) => emit(
33 | OfferListState.failure(
34 | error: error,
35 | ),
36 | ),
37 | );
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/lib/cubits/offers/list/offer_list_state.dart:
--------------------------------------------------------------------------------
1 | part of 'offer_list_cubit.dart';
2 |
3 | @freezed
4 | class OfferListState with _$OfferListState {
5 | const OfferListState._();
6 |
7 | const factory OfferListState.loaded({
8 | required List offers,
9 | }) = _Loaded;
10 | const factory OfferListState.loading() = _Loading;
11 | const factory OfferListState.failure({
12 | required AppError error,
13 | }) = _Error;
14 | }
15 |
--------------------------------------------------------------------------------
/lib/cubits/portfolio_watchlist/portfolio_watchlist_cubit.dart:
--------------------------------------------------------------------------------
1 | import 'package:bloc/bloc.dart';
2 | import 'package:freezed_annotation/freezed_annotation.dart';
3 | import 'package:injectable/injectable.dart';
4 | import 'package:vizier/data/errors/app_error.dart';
5 | import 'package:vizier/data/models/company_asset/company_asset_model.dart';
6 | import 'package:vizier/data/repositories/portfolio/portfolio_repository.dart';
7 | import 'package:vizier/data/responses/response_status.dart';
8 |
9 | part 'portfolio_watchlist_state.dart';
10 | part 'portfolio_watchlist_cubit.freezed.dart';
11 |
12 | @injectable
13 | class PortfolioWatchlistCubit extends Cubit {
14 | final PortfolioRepository portfolioRepository;
15 |
16 | PortfolioWatchlistCubit({
17 | required this.portfolioRepository,
18 | }) : super(const PortfolioWatchlistState.initial());
19 |
20 | Future fetchData() async {
21 | emit(
22 | const PortfolioWatchlistState.loading(),
23 | );
24 |
25 | final ResponseStatus> response = await portfolioRepository.watchlist();
26 | response.result(
27 | onSuccess: (data) => emit(
28 | PortfolioWatchlistState.loaded(
29 | companyAssets: data,
30 | ),
31 | ),
32 | onError: (error) => emit(
33 | PortfolioWatchlistState.failure(
34 | error: error,
35 | ),
36 | ),
37 | );
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/lib/cubits/portfolio_watchlist/portfolio_watchlist_state.dart:
--------------------------------------------------------------------------------
1 | part of 'portfolio_watchlist_cubit.dart';
2 |
3 | @freezed
4 | class PortfolioWatchlistState with _$PortfolioWatchlistState {
5 | const PortfolioWatchlistState._();
6 |
7 | const factory PortfolioWatchlistState.initial() = _Initial;
8 | const factory PortfolioWatchlistState.loading() = _Loading;
9 | const factory PortfolioWatchlistState.loaded({
10 | required List companyAssets,
11 | }) = _Loaded;
12 | const factory PortfolioWatchlistState.failure({
13 | required AppError error,
14 | }) = _Error;
15 |
16 | bool get isLoading => maybeMap(
17 | loading: (_) => true,
18 | orElse: () => false,
19 | );
20 |
21 | List? get companyAssets => maybeMap(
22 | loaded: (state) => state.companyAssets,
23 | orElse: () => null,
24 | );
25 | }
26 |
--------------------------------------------------------------------------------
/lib/cubits/retirement_plan/retirement_plan_state.dart:
--------------------------------------------------------------------------------
1 | part of 'retirement_plan_cubit.dart';
2 |
3 | @freezed
4 | class RetirementPlanState with _$RetirementPlanState {
5 | const RetirementPlanState._();
6 |
7 | const factory RetirementPlanState.initial() = _Initial;
8 | const factory RetirementPlanState.loading() = _Loading;
9 | const factory RetirementPlanState.loaded({
10 | required RetirementPlanModel retirementPlan,
11 | }) = _Loaded;
12 | const factory RetirementPlanState.failure({
13 | required AppError error,
14 | }) = _Error;
15 |
16 | bool get isLoading => maybeMap(
17 | loading: (_) => true,
18 | orElse: () => false,
19 | );
20 |
21 | RetirementPlanModel? get retirementPlan => maybeMap(
22 | loaded: (state) => state.retirementPlan,
23 | orElse: () => null,
24 | );
25 | }
26 |
--------------------------------------------------------------------------------
/lib/cubits/transaction_history/transaction_history_state.dart:
--------------------------------------------------------------------------------
1 | part of 'transaction_history_cubit.dart';
2 |
3 | @freezed
4 | class TransactionHistoryState with _$TransactionHistoryState {
5 | const TransactionHistoryState._();
6 |
7 | const factory TransactionHistoryState.initial() = _Initial;
8 | const factory TransactionHistoryState.loading() = _Loading;
9 | const factory TransactionHistoryState.loaded({
10 | required List transactions,
11 | }) = _Loaded;
12 | const factory TransactionHistoryState.failure({
13 | required AppError error,
14 | }) = _Failure;
15 |
16 | List? get transactions => mapOrNull(
17 | loaded: (state) => state.transactions,
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/lib/cubits/user/notifications/user_notifications_cubit.dart:
--------------------------------------------------------------------------------
1 | import 'package:bloc/bloc.dart';
2 | import 'package:freezed_annotation/freezed_annotation.dart';
3 | import 'package:injectable/injectable.dart';
4 | import 'package:vizier/data/errors/app_error.dart';
5 | import 'package:vizier/data/repositories/user/user_repository.dart';
6 | import 'package:vizier/data/responses/response_status.dart';
7 | import 'package:vizier/data/responses/user/notifications/user_notifications_response.dart';
8 |
9 | part 'user_notifications_state.dart';
10 | part 'user_notifications_cubit.freezed.dart';
11 |
12 | @injectable
13 | class UserNotificationsCubit extends Cubit {
14 | final UserRepository userRepository;
15 |
16 | UserNotificationsCubit({
17 | required this.userRepository,
18 | }) : super(const UserNotificationsState.initial());
19 |
20 | Future fetchData() async {
21 | emit(
22 | const UserNotificationsState.loading(),
23 | );
24 | final ResponseStatus response = await userRepository.notifications();
25 | response.result(
26 | onSuccess: (data) => emit(
27 | UserNotificationsState.loaded(
28 | areNotificationsEnabled: data.areNotificationsEnabled,
29 | ),
30 | ),
31 | onError: (error) => emit(
32 | UserNotificationsState.failure(
33 | appError: error,
34 | ),
35 | ),
36 | );
37 | }
38 |
39 | Future update({
40 | required bool areNotificationsEnabled,
41 | }) async {
42 | emit(
43 | UserNotificationsState.loaded(
44 | areNotificationsEnabled: areNotificationsEnabled,
45 | ),
46 | );
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/lib/cubits/user/notifications/user_notifications_state.dart:
--------------------------------------------------------------------------------
1 | part of 'user_notifications_cubit.dart';
2 |
3 | @freezed
4 | class UserNotificationsState with _$UserNotificationsState {
5 | const UserNotificationsState._();
6 |
7 | const factory UserNotificationsState.initial() = _Initial;
8 | const factory UserNotificationsState.loading() = _Loading;
9 | const factory UserNotificationsState.loaded({
10 | required bool areNotificationsEnabled,
11 | }) = _Loaded;
12 | const factory UserNotificationsState.failure({
13 | required AppError appError,
14 | }) = _Failure;
15 |
16 | bool? get areNotificationsEnabled => maybeMap(
17 | loaded: (state) => state.areNotificationsEnabled,
18 | orElse: () => null,
19 | );
20 |
21 | bool get isLoading => maybeMap(
22 | loading: (_) => true,
23 | orElse: () => false,
24 | );
25 | }
26 |
--------------------------------------------------------------------------------
/lib/cubits/user/user_cubit.dart:
--------------------------------------------------------------------------------
1 | import 'package:bloc/bloc.dart';
2 | import 'package:freezed_annotation/freezed_annotation.dart';
3 | import 'package:injectable/injectable.dart';
4 | import 'package:vizier/data/errors/app_error.dart';
5 | import 'package:vizier/data/models/user/user_model.dart';
6 | import 'package:vizier/data/repositories/user/user_repository.dart';
7 | import 'package:vizier/data/responses/response_status.dart';
8 |
9 | part 'user_state.dart';
10 | part 'user_cubit.freezed.dart';
11 |
12 | @injectable
13 | class UserCubit extends Cubit {
14 | final UserRepository userRepository;
15 |
16 | UserCubit({
17 | required this.userRepository,
18 | }) : super(const UserState.initial());
19 |
20 | Future fetchMe() async {
21 | _emitLoading();
22 | final ResponseStatus responseStatus = await userRepository.me();
23 | responseStatus.result(
24 | onSuccess: (response) {
25 | emit(
26 | UserState.loaded(response),
27 | );
28 | },
29 | onError: (error) => _emitError(error),
30 | );
31 | }
32 |
33 | void logout() {
34 | emit(
35 | const UserState.initial(),
36 | );
37 | }
38 |
39 | void _emitLoading() {
40 | if (state.user != null) {
41 | emit(
42 | UserState.upating(state.user!),
43 | );
44 | } else {
45 | emit(
46 | const UserState.loading(),
47 | );
48 | }
49 | }
50 |
51 | void _emitError(AppError appError) {
52 | if (state.user != null) {
53 | emit(
54 | UserState.errorWithData(
55 | userModel: state.user!,
56 | appError: appError,
57 | ),
58 | );
59 | } else {
60 | emit(
61 | UserState.error(appError),
62 | );
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/lib/cubits/user/user_state.dart:
--------------------------------------------------------------------------------
1 | part of 'user_cubit.dart';
2 |
3 | @freezed
4 | class UserState with _$UserState {
5 | const UserState._();
6 | const factory UserState.initial() = _Initial;
7 | const factory UserState.loading() = _Loading;
8 | const factory UserState.loaded(UserModel userModel) = _Loaded;
9 | const factory UserState.upating(UserModel userModel) = _Updating;
10 | const factory UserState.errorWithData({
11 | required UserModel userModel,
12 | required AppError appError,
13 | }) = _LoadedWithData;
14 | const factory UserState.error(AppError appError) = _Error;
15 |
16 | UserModel? get user => maybeMap(
17 | loaded: (state) => state.userModel,
18 | upating: (state) => state.userModel,
19 | errorWithData: (state) => state.userModel,
20 | orElse: () => null,
21 | );
22 | }
23 |
--------------------------------------------------------------------------------
/lib/cubits/wallet/wallet_cubit.dart:
--------------------------------------------------------------------------------
1 | import 'package:bloc/bloc.dart';
2 | import 'package:freezed_annotation/freezed_annotation.dart';
3 | import 'package:injectable/injectable.dart';
4 | import 'package:vizier/data/errors/app_error.dart';
5 | import 'package:vizier/data/models/wallet/wallet_model.dart';
6 | import 'package:vizier/data/repositories/wallet/wallet_repository.dart';
7 | import 'package:vizier/data/responses/response_status.dart';
8 |
9 | part 'wallet_state.dart';
10 | part 'wallet_cubit.freezed.dart';
11 |
12 | @injectable
13 | class WalletCubit extends Cubit {
14 | final WalletRepository walletRepository;
15 |
16 | WalletCubit({
17 | required this.walletRepository,
18 | }) : super(const WalletState.initial());
19 |
20 | Future fetchData() async {
21 | emit(
22 | const WalletState.loading(),
23 | );
24 |
25 | final ResponseStatus response = await walletRepository.wallet();
26 | response.result(
27 | onSuccess: (data) => emit(
28 | WalletState.loaded(
29 | wallet: data,
30 | ),
31 | ),
32 | onError: (error) => emit(
33 | WalletState.failure(
34 | error: error,
35 | ),
36 | ),
37 | );
38 | }
39 |
40 | void logout() {
41 | emit(
42 | const WalletState.initial(),
43 | );
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/lib/cubits/wallet/wallet_state.dart:
--------------------------------------------------------------------------------
1 | part of 'wallet_cubit.dart';
2 |
3 | @freezed
4 | class WalletState with _$WalletState {
5 | const WalletState._();
6 |
7 | const factory WalletState.initial() = _Initial;
8 | const factory WalletState.loading() = _Loading;
9 | const factory WalletState.loaded({
10 | required WalletModel wallet,
11 | }) = _Loaded;
12 | const factory WalletState.failure({
13 | required AppError error,
14 | }) = _Failure;
15 |
16 | bool get isLoading => maybeMap(
17 | loading: (state) => true,
18 | orElse: () => false,
19 | );
20 |
21 | WalletModel? get wallet => mapOrNull(
22 | loaded: (state) => state.wallet,
23 | );
24 |
25 | double? get assetsChange => mapOrNull(
26 | loaded: (state) => state.wallet.accounts.map((e) => e.change).reduce(
27 | (value, element) => value + element,
28 | ),
29 | );
30 |
31 | double? get assetsPercentageChange => mapOrNull(
32 | loaded: (state) => state.assetsChange != null ? (state.assetsChange! / state.wallet.balance * 100) : 0.0,
33 | );
34 |
35 | int? get goalProgress => mapOrNull(
36 | loaded: (state) => (state.wallet.balance / state.wallet.goal * 100).ceil(),
37 | );
38 | }
39 |
--------------------------------------------------------------------------------
/lib/data/data_sources/authentication/authentication_data_source.dart:
--------------------------------------------------------------------------------
1 | import 'package:vizier/data/requests/authentication/authentication_request.dart';
2 | import 'package:vizier/data/responses/authentication/authentication_response.dart';
3 | import 'package:vizier/data/responses/response_status.dart';
4 |
5 | abstract class AuthenticationDataSource {
6 | Future> getLogin(AuthenticationRequest request);
7 | }
8 |
--------------------------------------------------------------------------------
/lib/data/data_sources/authentication/dummy_authentication_data_source.dart:
--------------------------------------------------------------------------------
1 | import 'package:injectable/injectable.dart';
2 | import 'package:vizier/config/constants/app_constants.dart';
3 | import 'package:vizier/data/data_sources/authentication/authentication_data_source.dart';
4 | import 'package:vizier/data/requests/authentication/authentication_request.dart';
5 | import 'package:vizier/data/responses/authentication/authentication_response.dart';
6 | import 'package:vizier/data/responses/response_status.dart';
7 | import 'package:vizier/utils/dummy_util.dart';
8 |
9 | @Injectable(as: AuthenticationDataSource)
10 | class DummyAuthenticationDataSource extends AuthenticationDataSource {
11 | final DummyUtil dummyUtil;
12 |
13 | DummyAuthenticationDataSource({
14 | required this.dummyUtil,
15 | });
16 |
17 | @override
18 | Future> getLogin(
19 | AuthenticationRequest request,
20 | ) async {
21 | await Future.delayed(AppConstants.api.dummyLoadingDuration);
22 | return ResponseStatus.success(
23 | AuthenticationResponse(
24 | token: dummyUtil.randomString(),
25 | ),
26 | );
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/lib/data/data_sources/finances/finances_data_source.dart:
--------------------------------------------------------------------------------
1 | import 'package:vizier/data/models/finances_overview/finances_overview_model.dart';
2 | import 'package:vizier/data/models/financial_history/financial_history_model.dart';
3 | import 'package:vizier/data/models/retirement_plan/retirement_plan_model.dart';
4 | import 'package:vizier/data/responses/response_status.dart';
5 |
6 | abstract class FinancesDataSource {
7 | Future> overview();
8 | Future> history({
9 | required int daysBack,
10 | });
11 | Future> retirementPlan({
12 | required int daysTo,
13 | });
14 | }
15 |
--------------------------------------------------------------------------------
/lib/data/data_sources/offers/dummy_offers_data_source.dart:
--------------------------------------------------------------------------------
1 | import 'package:injectable/injectable.dart';
2 | import 'package:vizier/data/data_sources/offers/offers_data_source.dart';
3 | import 'package:vizier/data/models/offer/offer_model.dart';
4 | import 'package:vizier/data/responses/response_status.dart';
5 | import 'package:vizier/mocks/mock_factory.dart';
6 |
7 | @Injectable(as: OffersDataSource)
8 | class DummyOffersDataSource extends OffersDataSource {
9 | final MockFactory mockFactory;
10 |
11 | DummyOffersDataSource({
12 | required this.mockFactory,
13 | });
14 |
15 | @override
16 | Future>> all() async {
17 | return ResponseStatus.success(
18 | mockFactory.offers.prepareAll(),
19 | );
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/lib/data/data_sources/offers/offers_data_source.dart:
--------------------------------------------------------------------------------
1 | import 'package:vizier/data/models/offer/offer_model.dart';
2 | import 'package:vizier/data/responses/response_status.dart';
3 |
4 | abstract class OffersDataSource {
5 | Future>> all();
6 | }
7 |
--------------------------------------------------------------------------------
/lib/data/data_sources/portfolio/portfolio_data_source.dart:
--------------------------------------------------------------------------------
1 | import 'package:vizier/data/models/company_asset/company_asset_model.dart';
2 | import 'package:vizier/data/models/company_listing/details/company_listing_details_item_model.dart';
3 | import 'package:vizier/data/models/company_listing/history/company_listing_history_model.dart';
4 | import 'package:vizier/data/models/portfolio_overview/portfolio_overview_model.dart';
5 | import 'package:vizier/data/responses/response_status.dart';
6 |
7 | abstract class PortfolioDataSource {
8 | Future>> watchlist();
9 | Future> overview();
10 | Future>> details();
11 | Future> history({
12 | required CompanyAssetModel companyAsset,
13 | required int daysBack,
14 | });
15 | }
16 |
--------------------------------------------------------------------------------
/lib/data/data_sources/user/dummy_user_data_source.dart:
--------------------------------------------------------------------------------
1 | import 'package:injectable/injectable.dart';
2 | import 'package:vizier/config/constants/app_constants.dart';
3 | import 'package:vizier/data/data_sources/user/user_data_source.dart';
4 | import 'package:vizier/data/models/user/user_model.dart';
5 | import 'package:vizier/data/responses/response_status.dart';
6 | import 'package:vizier/data/responses/user/notifications/user_notifications_response.dart';
7 | import 'package:vizier/mocks/mock_factory.dart';
8 |
9 | @Injectable(as: UserDataSource)
10 | class DummyUserDataSource extends UserDataSource {
11 | final MockFactory mockFactory;
12 |
13 | DummyUserDataSource({
14 | required this.mockFactory,
15 | });
16 |
17 | @override
18 | Future> me() async {
19 | await Future.delayed(AppConstants.api.dummyLoadingDuration);
20 |
21 | return ResponseStatus.success(
22 | mockFactory.user.prepareUser(),
23 | );
24 | }
25 |
26 | @override
27 | Future> notifications() async {
28 | await Future.delayed(AppConstants.api.dummyLoadingDuration);
29 |
30 | return ResponseStatus.success(
31 | mockFactory.user.prepareUserNotificationsResponse(),
32 | );
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/lib/data/data_sources/user/user_data_source.dart:
--------------------------------------------------------------------------------
1 | import 'package:vizier/data/models/user/user_model.dart';
2 | import 'package:vizier/data/responses/response_status.dart';
3 | import 'package:vizier/data/responses/user/notifications/user_notifications_response.dart';
4 |
5 | abstract class UserDataSource {
6 | Future> me();
7 | Future> notifications();
8 | }
9 |
--------------------------------------------------------------------------------
/lib/data/data_sources/wallet/wallet_data_source.dart:
--------------------------------------------------------------------------------
1 | import 'package:vizier/data/models/account/account_model.dart';
2 | import 'package:vizier/data/models/account/breakdown/account_breakdown_model.dart';
3 | import 'package:vizier/data/models/goal/goal_model.dart';
4 | import 'package:vizier/data/models/transaction/transaction_model.dart';
5 | import 'package:vizier/data/models/wallet/wallet_model.dart';
6 | import 'package:vizier/data/responses/response_status.dart';
7 |
8 | abstract class WalletDataSource {
9 | Future> addWalletAccount({
10 | required AccountModel account,
11 | });
12 | Future> accountBreakdown({
13 | required int daysBack,
14 | required AccountModel account,
15 | });
16 | Future>> goals();
17 | Future> wallet();
18 | Future>> transactionHistory({
19 | required AccountModel accountModel,
20 | });
21 | }
22 |
--------------------------------------------------------------------------------
/lib/data/errors/app_error.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:freezed_annotation/freezed_annotation.dart';
3 | import 'package:vizier/l10n/app_loc.dart';
4 | part 'app_error.freezed.dart';
5 |
6 | @freezed
7 | class AppError with _$AppError implements Exception {
8 | AppError._();
9 |
10 | factory AppError.mockFailure() = _MockFailure;
11 | factory AppError.networkFailure() = _NetworkError;
12 | factory AppError.serverFailure({
13 | required int? statusCode,
14 | required Map? json,
15 | }) = _ServerError;
16 | factory AppError.unknownFailure(dynamic error) = _UnknownError;
17 |
18 | @override
19 | String toString() {
20 | return 'Use localizedTitle or localizedContent methods instead of toString()';
21 | }
22 |
23 | String localizedTitle(BuildContext context) {
24 | return when(
25 | mockFailure: () => AppLoc.of(context).appErrorMockTitle,
26 | networkFailure: () => AppLoc.of(context).appErrorNetworkTitle,
27 | serverFailure: (_, __) => AppLoc.of(context).appErrorServerTitle,
28 | unknownFailure: (_) => AppLoc.of(context).appErrorUnknownTitle,
29 | );
30 | }
31 |
32 | String localizedMessage(BuildContext context) {
33 | return when(
34 | mockFailure: () => AppLoc.of(context).appErrorMockMessage,
35 | networkFailure: () => AppLoc.of(context).appErrorNetworkMessage,
36 | serverFailure: (statusCode, json) {
37 | return AppLoc.of(context).appErrorServerMessage(statusCode.toString(), json.toString());
38 | },
39 | unknownFailure: (error) => error.toString(),
40 | );
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/lib/data/models/account/account_model.dart:
--------------------------------------------------------------------------------
1 | import 'package:freezed_annotation/freezed_annotation.dart';
2 |
3 | part 'account_model.g.dart';
4 | part 'account_model.freezed.dart';
5 |
6 | @freezed
7 | class AccountModel with _$AccountModel {
8 | const factory AccountModel({
9 | required String logo,
10 | required String name,
11 | required String number,
12 | required double balance,
13 | required double change,
14 | required String expiry,
15 | }) = _AccountModel;
16 |
17 | const AccountModel._();
18 |
19 | factory AccountModel.fromJson(Map json) => _$AccountModelFromJson(json);
20 | }
21 |
--------------------------------------------------------------------------------
/lib/data/models/account/breakdown/account_breakdown_model.dart:
--------------------------------------------------------------------------------
1 | import 'package:freezed_annotation/freezed_annotation.dart';
2 | import 'package:vizier/data/models/account/account_model.dart';
3 | import 'package:vizier/data/models/transaction/category/transaction_category_model.dart';
4 |
5 | part 'account_breakdown_model.g.dart';
6 | part 'account_breakdown_model.freezed.dart';
7 |
8 | @freezed
9 | class AccountBreakdownModel with _$AccountBreakdownModel {
10 | const factory AccountBreakdownModel({
11 | required DateTime from,
12 | required DateTime to,
13 | required List transactionCategories,
14 | required AccountModel account,
15 | }) = _AccountBreakdownModel;
16 |
17 | const AccountBreakdownModel._();
18 |
19 | factory AccountBreakdownModel.fromJson(Map json) => _$AccountBreakdownModelFromJson(json);
20 | }
21 |
--------------------------------------------------------------------------------
/lib/data/models/company_asset/company_asset_model.dart:
--------------------------------------------------------------------------------
1 | import 'package:freezed_annotation/freezed_annotation.dart';
2 | import 'package:vizier/extensions/extensions.dart';
3 |
4 | part 'company_asset_model.g.dart';
5 | part 'company_asset_model.freezed.dart';
6 |
7 | @freezed
8 | class CompanyAssetModel with _$CompanyAssetModel {
9 | const factory CompanyAssetModel({
10 | required String shortName,
11 | required String name,
12 | required String logo,
13 | required double currentValue,
14 | required double changePercentage,
15 | }) = _CompanyAssetModel;
16 |
17 | const CompanyAssetModel._();
18 |
19 | factory CompanyAssetModel.fromJson(Map json) => _$CompanyAssetModelFromJson(json);
20 |
21 | String get fullName => [shortName, name].where((element) => element.isNotBlank).join(' ');
22 | }
23 |
--------------------------------------------------------------------------------
/lib/data/models/company_listing/details/company_listing_details_item_model.dart:
--------------------------------------------------------------------------------
1 | import 'package:freezed_annotation/freezed_annotation.dart';
2 |
3 | part 'company_listing_details_item_model.g.dart';
4 | part 'company_listing_details_item_model.freezed.dart';
5 |
6 | @freezed
7 | class CompanyListingDetailsItemModel with _$CompanyListingDetailsItemModel {
8 | const factory CompanyListingDetailsItemModel({
9 | required String description,
10 | required String index,
11 | required String title,
12 | }) = _CompanyListingDetailsItemModel;
13 |
14 | const CompanyListingDetailsItemModel._();
15 |
16 | factory CompanyListingDetailsItemModel.fromJson(Map json) =>
17 | _$CompanyListingDetailsItemModelFromJson(json);
18 | }
19 |
--------------------------------------------------------------------------------
/lib/data/models/company_listing/history/company_listing_history_model.dart:
--------------------------------------------------------------------------------
1 | import 'package:freezed_annotation/freezed_annotation.dart';
2 | import 'package:vizier/data/models/company_listing/history/data/company_listing_history_data_model.dart';
3 |
4 | part 'company_listing_history_model.g.dart';
5 | part 'company_listing_history_model.freezed.dart';
6 |
7 | @freezed
8 | class CompanyListingHistoryModel with _$CompanyListingHistoryModel {
9 | const factory CompanyListingHistoryModel({
10 | required List history,
11 | required DateTime from,
12 | required DateTime to,
13 | required int daysBack,
14 | }) = _CompanyListingHistoryModel;
15 |
16 | const CompanyListingHistoryModel._();
17 |
18 | factory CompanyListingHistoryModel.fromJson(Map json) => _$CompanyListingHistoryModelFromJson(json);
19 | }
20 |
--------------------------------------------------------------------------------
/lib/data/models/company_listing/history/data/company_listing_history_data_model.dart:
--------------------------------------------------------------------------------
1 | import 'dart:math';
2 |
3 | import 'package:freezed_annotation/freezed_annotation.dart';
4 | import 'package:vizier/data/models/company_listing/history/value/company_listing_history_value_model.dart';
5 |
6 | part 'company_listing_history_data_model.g.dart';
7 | part 'company_listing_history_data_model.freezed.dart';
8 |
9 | @freezed
10 | class CompanyListingHistoryDataModel with _$CompanyListingHistoryDataModel {
11 | const factory CompanyListingHistoryDataModel({
12 | required DateTime date,
13 | required bool isProfit,
14 | required CompanyListingHistoryValueModel value1,
15 | required CompanyListingHistoryValueModel value2,
16 | }) = _CompanyListingHistoryDataModel;
17 |
18 | double get maxValues => max(max(value1.min, value1.max), max(value2.min, value2.max));
19 |
20 | double get minValues => min(min(value1.min, value2.max), min(value2.min, value2.max));
21 |
22 | const CompanyListingHistoryDataModel._();
23 |
24 | factory CompanyListingHistoryDataModel.fromJson(Map json) =>
25 | _$CompanyListingHistoryDataModelFromJson(json);
26 | }
27 |
--------------------------------------------------------------------------------
/lib/data/models/company_listing/history/value/company_listing_history_value_model.dart:
--------------------------------------------------------------------------------
1 | import 'package:freezed_annotation/freezed_annotation.dart';
2 |
3 | part 'company_listing_history_value_model.g.dart';
4 | part 'company_listing_history_value_model.freezed.dart';
5 |
6 | @freezed
7 | class CompanyListingHistoryValueModel with _$CompanyListingHistoryValueModel {
8 | const factory CompanyListingHistoryValueModel({
9 | required double min,
10 | required double max,
11 | }) = _CompanyListingHistoryValueModel;
12 |
13 | const CompanyListingHistoryValueModel._();
14 |
15 | factory CompanyListingHistoryValueModel.fromJson(Map json) =>
16 | _$CompanyListingHistoryValueModelFromJson(json);
17 | }
18 |
--------------------------------------------------------------------------------
/lib/data/models/finances_overview/finances_overview_model.dart:
--------------------------------------------------------------------------------
1 | import 'package:freezed_annotation/freezed_annotation.dart';
2 |
3 | part 'finances_overview_model.g.dart';
4 | part 'finances_overview_model.freezed.dart';
5 |
6 | @freezed
7 | class FinancesOverviewModel with _$FinancesOverviewModel {
8 | const factory FinancesOverviewModel({
9 | required double cashBalance,
10 | required double spent,
11 | required DateTime since,
12 | }) = _FinancesOverviewModel;
13 |
14 | const FinancesOverviewModel._();
15 |
16 | factory FinancesOverviewModel.fromJson(Map json) => _$FinancesOverviewModelFromJson(json);
17 | }
18 |
--------------------------------------------------------------------------------
/lib/data/models/financial_history/financial_history_model.dart:
--------------------------------------------------------------------------------
1 | import 'package:freezed_annotation/freezed_annotation.dart';
2 | import 'package:vizier/data/models/financial_history/history_data/financial_history_data_model.dart';
3 |
4 | part 'financial_history_model.g.dart';
5 | part 'financial_history_model.freezed.dart';
6 |
7 | @freezed
8 | class FinancialHistoryModel with _$FinancialHistoryModel {
9 | const factory FinancialHistoryModel({
10 | required List history,
11 | required DateTime from,
12 | required DateTime to,
13 | required int daysBack,
14 | }) = _FinancialHistoryModel;
15 |
16 | const FinancialHistoryModel._();
17 |
18 | factory FinancialHistoryModel.fromJson(Map json) => _$FinancialHistoryModelFromJson(json);
19 | }
20 |
--------------------------------------------------------------------------------
/lib/data/models/financial_history/history_data/financial_history_data_model.dart:
--------------------------------------------------------------------------------
1 | import 'dart:math';
2 |
3 | import 'package:freezed_annotation/freezed_annotation.dart';
4 |
5 | part 'financial_history_data_model.g.dart';
6 | part 'financial_history_data_model.freezed.dart';
7 |
8 | @freezed
9 | class FinancialHistoryDataModel with _$FinancialHistoryDataModel {
10 | const factory FinancialHistoryDataModel({
11 | required DateTime date,
12 | required double balance,
13 | required double spent,
14 | }) = _FinancialHistoryDataModel;
15 |
16 | const FinancialHistoryDataModel._();
17 |
18 | double get maxBalanceOrSpent => max(balance, spent);
19 |
20 | factory FinancialHistoryDataModel.fromJson(Map json) => _$FinancialHistoryDataModelFromJson(json);
21 | }
22 |
--------------------------------------------------------------------------------
/lib/data/models/goal/goal_model.dart:
--------------------------------------------------------------------------------
1 | import 'package:freezed_annotation/freezed_annotation.dart';
2 |
3 | part 'goal_model.g.dart';
4 | part 'goal_model.freezed.dart';
5 |
6 | @freezed
7 | class GoalModel with _$GoalModel {
8 | const factory GoalModel({
9 | required String name,
10 | required double goal,
11 | required double change,
12 | required int reached,
13 | }) = _GoalModel;
14 |
15 | const GoalModel._();
16 |
17 | factory GoalModel.fromJson(Map json) => _$GoalModelFromJson(json);
18 | }
19 |
--------------------------------------------------------------------------------
/lib/data/models/offer/offer_model.dart:
--------------------------------------------------------------------------------
1 | import 'package:freezed_annotation/freezed_annotation.dart';
2 | import 'package:vizier/data/models/offer/offer_type.dart';
3 | import 'package:vizier/data/models/offer/slider_item/offer_slider_model.dart';
4 |
5 | part 'offer_model.g.dart';
6 | part 'offer_model.freezed.dart';
7 |
8 | @freezed
9 | class OfferModel with _$OfferModel {
10 | const factory OfferModel({
11 | required double expectedValue,
12 | required String label,
13 | required String image,
14 | required String detailsImage,
15 | required List sliders,
16 | required OfferType type,
17 | }) = _OfferModel;
18 |
19 | const OfferModel._();
20 |
21 | factory OfferModel.fromJson(Map json) => _$OfferModelFromJson(json);
22 | }
23 |
--------------------------------------------------------------------------------
/lib/data/models/offer/offer_type.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:vizier/l10n/app_loc.dart';
3 |
4 | enum OfferType {
5 | retirementGoals,
6 | mortgage,
7 | loans,
8 | }
9 |
10 | extension OfferTypeExtension on OfferType {
11 | String leftContent(BuildContext context) {
12 | switch (this) {
13 | case OfferType.retirementGoals:
14 | return AppLoc.of(context).offerTypeRetirementGoalsLeftContent;
15 | case OfferType.mortgage:
16 | return AppLoc.of(context).offerTypeMortgagesLeftContent;
17 | case OfferType.loans:
18 | return AppLoc.of(context).offerTypeLoansLeftContent;
19 | }
20 | }
21 |
22 | String rightContent(BuildContext context) {
23 | switch (this) {
24 | default:
25 | return AppLoc.of(context).offerTypeRightContent;
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/lib/data/models/offer/slider_item/offer_slider_model.dart:
--------------------------------------------------------------------------------
1 | import 'package:freezed_annotation/freezed_annotation.dart';
2 | import 'package:vizier/data/models/offer/slider_item/offer_slider_type.dart';
3 |
4 | part 'offer_slider_model.g.dart';
5 | part 'offer_slider_model.freezed.dart';
6 |
7 | @freezed
8 | class OfferSliderModel with _$OfferSliderModel {
9 | const factory OfferSliderModel({
10 | required double current,
11 | required int frequency,
12 | required String label,
13 | required int maxValue,
14 | required OfferSliderType type,
15 | }) = _OfferSliderModel;
16 |
17 | const OfferSliderModel._();
18 |
19 | factory OfferSliderModel.fromJson(Map json) => _$OfferSliderModelFromJson(json);
20 |
21 | double get actualValue => current * frequency;
22 | }
23 |
--------------------------------------------------------------------------------
/lib/data/models/offer/slider_item/offer_slider_type.dart:
--------------------------------------------------------------------------------
1 | enum OfferSliderType {
2 | price,
3 | year,
4 | month,
5 | }
6 |
--------------------------------------------------------------------------------
/lib/data/models/portfolio_overview/portfolio_overview_model.dart:
--------------------------------------------------------------------------------
1 | import 'package:freezed_annotation/freezed_annotation.dart';
2 |
3 | part 'portfolio_overview_model.g.dart';
4 | part 'portfolio_overview_model.freezed.dart';
5 |
6 | @freezed
7 | class PortfolioOverviewModel with _$PortfolioOverviewModel {
8 | const factory PortfolioOverviewModel({
9 | required double assetsBalance,
10 | required double assetsChange,
11 | required double assetsPercentageChange,
12 | required double digitalCurrenciesBalance,
13 | required double digitalCurrenciesPercentageChange,
14 | }) = _PortfolioOverviewModel;
15 |
16 | const PortfolioOverviewModel._();
17 |
18 | factory PortfolioOverviewModel.fromJson(Map json) => _$PortfolioOverviewModelFromJson(json);
19 | }
20 |
--------------------------------------------------------------------------------
/lib/data/models/retirement_plan/data/retirement_plan_data_model.dart:
--------------------------------------------------------------------------------
1 | import 'package:freezed_annotation/freezed_annotation.dart';
2 |
3 | part 'retirement_plan_data_model.g.dart';
4 | part 'retirement_plan_data_model.freezed.dart';
5 |
6 | @freezed
7 | class RetirementPlanDataModel with _$RetirementPlanDataModel {
8 | const factory RetirementPlanDataModel({
9 | required DateTime date,
10 | required double value,
11 | }) = _RetirementPlanDataModel;
12 |
13 | const RetirementPlanDataModel._();
14 |
15 | factory RetirementPlanDataModel.fromJson(Map json) => _$RetirementPlanDataModelFromJson(json);
16 | }
17 |
--------------------------------------------------------------------------------
/lib/data/models/retirement_plan/retirement_plan_model.dart:
--------------------------------------------------------------------------------
1 | import 'package:freezed_annotation/freezed_annotation.dart';
2 | import 'package:vizier/data/models/retirement_plan/data/retirement_plan_data_model.dart';
3 |
4 | part 'retirement_plan_model.g.dart';
5 | part 'retirement_plan_model.freezed.dart';
6 |
7 | @freezed
8 | class RetirementPlanModel with _$RetirementPlanModel {
9 | const factory RetirementPlanModel({
10 | required List data,
11 | required DateTime from,
12 | required DateTime to,
13 | }) = _RetirementPlanModel;
14 |
15 | const RetirementPlanModel._();
16 |
17 | factory RetirementPlanModel.fromJson(Map json) => _$RetirementPlanModelFromJson(json);
18 | }
19 |
--------------------------------------------------------------------------------
/lib/data/models/transaction/category/transaction_category_model.dart:
--------------------------------------------------------------------------------
1 | import 'package:freezed_annotation/freezed_annotation.dart';
2 |
3 | part 'transaction_category_model.g.dart';
4 | part 'transaction_category_model.freezed.dart';
5 |
6 | @freezed
7 | class TransactionCategoryModel with _$TransactionCategoryModel {
8 | const factory TransactionCategoryModel({
9 | required String colorHex,
10 | required String name,
11 | required double value,
12 | required double percent,
13 | }) = _TransactionCategoryModel;
14 |
15 | const TransactionCategoryModel._();
16 |
17 | factory TransactionCategoryModel.fromJson(Map json) => _$TransactionCategoryModelFromJson(json);
18 | }
19 |
--------------------------------------------------------------------------------
/lib/data/models/transaction/transaction_model.dart:
--------------------------------------------------------------------------------
1 | import 'package:freezed_annotation/freezed_annotation.dart';
2 |
3 | part 'transaction_model.g.dart';
4 | part 'transaction_model.freezed.dart';
5 |
6 | @freezed
7 | class TransactionModel with _$TransactionModel {
8 | const factory TransactionModel({
9 | required String categoryName,
10 | required DateTime date,
11 | required String name,
12 | required double value,
13 | String? backgroundColorHex,
14 | String? image,
15 | }) = _TransactionModel;
16 |
17 | const TransactionModel._();
18 |
19 | factory TransactionModel.fromJson(Map json) => _$TransactionModelFromJson(json);
20 | }
21 |
--------------------------------------------------------------------------------
/lib/data/models/user/user_model.dart:
--------------------------------------------------------------------------------
1 | import 'package:freezed_annotation/freezed_annotation.dart';
2 |
3 | part 'user_model.g.dart';
4 | part 'user_model.freezed.dart';
5 |
6 | @freezed
7 | class UserModel with _$UserModel {
8 | const factory UserModel({
9 | required String avatar,
10 | required String email,
11 | required String firstName,
12 | required String lastName,
13 | }) = _UserModel;
14 |
15 | const UserModel._();
16 |
17 | factory UserModel.fromJson(Map json) => _$UserModelFromJson(json);
18 |
19 | String get fullName => '$firstName $lastName';
20 | }
21 |
--------------------------------------------------------------------------------
/lib/data/models/wallet/wallet_model.dart:
--------------------------------------------------------------------------------
1 | import 'package:freezed_annotation/freezed_annotation.dart';
2 | import 'package:vizier/data/models/account/account_model.dart';
3 |
4 | part 'wallet_model.g.dart';
5 | part 'wallet_model.freezed.dart';
6 |
7 | @freezed
8 | class WalletModel with _$WalletModel {
9 | const factory WalletModel({
10 | required double balance,
11 | required double goal,
12 | required List accounts,
13 | required DateTime date,
14 | }) = _WalletModel;
15 |
16 | const WalletModel._();
17 |
18 | factory WalletModel.fromJson(Map json) => _$WalletModelFromJson(json);
19 | }
20 |
--------------------------------------------------------------------------------
/lib/data/repositories/authentication/authentication_repository.dart:
--------------------------------------------------------------------------------
1 | import 'package:vizier/data/requests/authentication/authentication_request.dart';
2 | import 'package:vizier/data/responses/authentication/authentication_response.dart';
3 | import 'package:vizier/data/responses/response_status.dart';
4 |
5 | abstract class AuthenticationRepository {
6 | Future> login(AuthenticationRequest request);
7 | }
8 |
--------------------------------------------------------------------------------
/lib/data/repositories/authentication/data_authentication_repository.dart:
--------------------------------------------------------------------------------
1 | import 'package:injectable/injectable.dart';
2 | import 'package:vizier/data/data_sources/authentication/authentication_data_source.dart';
3 | import 'package:vizier/data/repositories/authentication/authentication_repository.dart';
4 | import 'package:vizier/data/requests/authentication/authentication_request.dart';
5 | import 'package:vizier/data/responses/authentication/authentication_response.dart';
6 | import 'package:vizier/data/responses/response_status.dart';
7 |
8 | @Injectable(as: AuthenticationRepository)
9 | class DataAuthenticationRepository extends AuthenticationRepository {
10 | final AuthenticationDataSource authenticationDataSource;
11 |
12 | DataAuthenticationRepository(this.authenticationDataSource);
13 |
14 | @override
15 | Future> login(
16 | AuthenticationRequest request,
17 | ) async {
18 | try {
19 | final ResponseStatus response =
20 | await authenticationDataSource.getLogin(request);
21 | return ResponseStatus.success(response.data!);
22 | } catch (error) {
23 | return ResponseStatus.error(error);
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/lib/data/repositories/finances/finances_repository.dart:
--------------------------------------------------------------------------------
1 | import 'package:vizier/data/models/finances_overview/finances_overview_model.dart';
2 | import 'package:vizier/data/models/financial_history/financial_history_model.dart';
3 | import 'package:vizier/data/models/retirement_plan/retirement_plan_model.dart';
4 | import 'package:vizier/data/responses/response_status.dart';
5 |
6 | abstract class FinancesRepository {
7 | Future> overview();
8 | Future> history({
9 | required int daysBack,
10 | });
11 | Future> retirementPlan({
12 | required int daysTo,
13 | });
14 | }
15 |
--------------------------------------------------------------------------------
/lib/data/repositories/offers/data_offers_repository.dart:
--------------------------------------------------------------------------------
1 | import 'package:injectable/injectable.dart';
2 | import 'package:vizier/data/data_sources/offers/offers_data_source.dart';
3 | import 'package:vizier/data/models/offer/offer_model.dart';
4 | import 'package:vizier/data/repositories/offers/offers_repository.dart';
5 | import 'package:vizier/data/responses/response_status.dart';
6 |
7 | @Injectable(as: OffersRepository)
8 | class DataOffersRepository extends OffersRepository {
9 | final OffersDataSource offersDataSource;
10 |
11 | DataOffersRepository({
12 | required this.offersDataSource,
13 | });
14 |
15 | @override
16 | Future>> all() async {
17 | try {
18 | final ResponseStatus> response =
19 | await offersDataSource.all();
20 | return ResponseStatus>.success(response.data!);
21 | } catch (error) {
22 | return ResponseStatus>.error(error);
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/lib/data/repositories/offers/offers_repository.dart:
--------------------------------------------------------------------------------
1 | import 'package:vizier/data/models/offer/offer_model.dart';
2 | import 'package:vizier/data/responses/response_status.dart';
3 |
4 | abstract class OffersRepository {
5 | Future>> all();
6 | }
7 |
--------------------------------------------------------------------------------
/lib/data/repositories/portfolio/portfolio_repository.dart:
--------------------------------------------------------------------------------
1 | import 'package:vizier/data/models/company_asset/company_asset_model.dart';
2 | import 'package:vizier/data/models/company_listing/details/company_listing_details_item_model.dart';
3 | import 'package:vizier/data/models/company_listing/history/company_listing_history_model.dart';
4 | import 'package:vizier/data/models/portfolio_overview/portfolio_overview_model.dart';
5 | import 'package:vizier/data/responses/response_status.dart';
6 |
7 | abstract class PortfolioRepository {
8 | Future>> watchlist();
9 | Future> overview();
10 | Future>> details();
11 | Future> history({
12 | required CompanyAssetModel companyAsset,
13 | required int daysBack,
14 | });
15 | }
16 |
--------------------------------------------------------------------------------
/lib/data/repositories/user/data_user_repository.dart:
--------------------------------------------------------------------------------
1 | import 'package:injectable/injectable.dart';
2 | import 'package:vizier/data/data_sources/user/user_data_source.dart';
3 | import 'package:vizier/data/models/user/user_model.dart';
4 | import 'package:vizier/data/repositories/user/user_repository.dart';
5 | import 'package:vizier/data/responses/response_status.dart';
6 | import 'package:vizier/data/responses/user/notifications/user_notifications_response.dart';
7 |
8 | @Injectable(as: UserRepository)
9 | class DataUserRepository extends UserRepository {
10 | final UserDataSource userDataSource;
11 |
12 | DataUserRepository({
13 | required this.userDataSource,
14 | });
15 |
16 | @override
17 | Future> me() async {
18 | try {
19 | final ResponseStatus response = await userDataSource.me();
20 | return ResponseStatus.success(response.data!);
21 | } catch (error) {
22 | return ResponseStatus.error(error);
23 | }
24 | }
25 |
26 | @override
27 | Future> notifications() async {
28 | try {
29 | final ResponseStatus response =
30 | await userDataSource.notifications();
31 | return ResponseStatus.success(response.data!);
32 | } catch (error) {
33 | return ResponseStatus.error(error);
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/lib/data/repositories/user/user_repository.dart:
--------------------------------------------------------------------------------
1 | import 'package:vizier/data/models/user/user_model.dart';
2 | import 'package:vizier/data/responses/response_status.dart';
3 | import 'package:vizier/data/responses/user/notifications/user_notifications_response.dart';
4 |
5 | abstract class UserRepository {
6 | Future> me();
7 | Future> notifications();
8 | }
9 |
--------------------------------------------------------------------------------
/lib/data/repositories/wallet/wallet_repository.dart:
--------------------------------------------------------------------------------
1 | import 'package:vizier/data/models/account/account_model.dart';
2 | import 'package:vizier/data/models/account/breakdown/account_breakdown_model.dart';
3 | import 'package:vizier/data/models/goal/goal_model.dart';
4 | import 'package:vizier/data/models/transaction/transaction_model.dart';
5 | import 'package:vizier/data/models/wallet/wallet_model.dart';
6 | import 'package:vizier/data/responses/response_status.dart';
7 |
8 | abstract class WalletRepository {
9 | Future> addWalletAccount({
10 | required AccountModel account,
11 | });
12 | Future> accountBreakdown({
13 | required int daysBack,
14 | required AccountModel account,
15 | });
16 | Future>> goals();
17 | Future> wallet();
18 | Future>> transactionHistory({
19 | required AccountModel accountModel,
20 | });
21 | }
22 |
--------------------------------------------------------------------------------
/lib/data/requests/authentication/authentication_request.dart:
--------------------------------------------------------------------------------
1 | import 'package:freezed_annotation/freezed_annotation.dart';
2 |
3 | part 'authentication_request.g.dart';
4 | part 'authentication_request.freezed.dart';
5 |
6 | @freezed
7 | class AuthenticationRequest with _$AuthenticationRequest {
8 | const factory AuthenticationRequest({
9 | required String email,
10 | required String password,
11 | }) = _AuthenticationRequest;
12 |
13 | factory AuthenticationRequest.fromJson(Map json) => _$AuthenticationRequestFromJson(json);
14 | }
15 |
--------------------------------------------------------------------------------
/lib/data/responses/authentication/authentication_response.dart:
--------------------------------------------------------------------------------
1 | import 'package:json_annotation/json_annotation.dart';
2 |
3 | part 'authentication_response.g.dart';
4 |
5 | @JsonSerializable(
6 | createToJson: false,
7 | )
8 | class AuthenticationResponse {
9 | final String token;
10 |
11 | AuthenticationResponse({
12 | required this.token,
13 | });
14 |
15 | factory AuthenticationResponse.fromJson(Map json) => _$AuthenticationResponseFromJson(json);
16 | }
17 |
--------------------------------------------------------------------------------
/lib/data/responses/response_status.dart:
--------------------------------------------------------------------------------
1 | import 'package:vizier/data/errors/app_error.dart';
2 |
3 | class ResponseStatus {
4 | final T? data;
5 | final AppError? error;
6 |
7 | ResponseStatus._({
8 | this.data,
9 | this.error,
10 | });
11 |
12 | factory ResponseStatus.success(T data) {
13 | return ResponseStatus._(
14 | data: data,
15 | );
16 | }
17 |
18 | factory ResponseStatus.error(Object error) {
19 | final AppError appError = AppError.unknownFailure(error);
20 | return ResponseStatus._(
21 | error: appError,
22 | );
23 | }
24 |
25 | void result({
26 | required Function(T) onSuccess,
27 | required Function(AppError) onError,
28 | }) {
29 | if (data != null) {
30 | onSuccess(data as T);
31 | } else if (error != null) {
32 | onError(error!);
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/lib/data/responses/user/notifications/user_notifications_response.dart:
--------------------------------------------------------------------------------
1 | import 'package:json_annotation/json_annotation.dart';
2 |
3 | part 'user_notifications_response.g.dart';
4 |
5 | @JsonSerializable(
6 | createToJson: false,
7 | )
8 | class UserNotificationsResponse {
9 | final bool areNotificationsEnabled;
10 |
11 | UserNotificationsResponse({
12 | required this.areNotificationsEnabled,
13 | });
14 |
15 | factory UserNotificationsResponse.fromJson(Map json) => _$UserNotificationsResponseFromJson(json);
16 | }
17 |
--------------------------------------------------------------------------------
/lib/data/storages/common_storage.dart:
--------------------------------------------------------------------------------
1 | import 'package:injectable/injectable.dart';
2 | import 'package:vizier/data/storages/storage.dart';
3 | import 'package:vizier/data/storages/storage_keys.dart';
4 |
5 |
6 | @injectable
7 | class CommonStorage {
8 | final Storage storage;
9 |
10 | CommonStorage({
11 | required this.storage,
12 | });
13 |
14 | Future getIsFirstLaunch() async {
15 | final bool? isFirstLaunch = await storage.getBool(
16 | key: StorageKeys.firstLaunch,
17 | );
18 | return isFirstLaunch ?? true;
19 | }
20 |
21 | Future storeIsFirstLaunch({
22 | required bool isFirstLaunch,
23 | }) async {
24 | return storage.putBool(
25 | key: StorageKeys.firstLaunch,
26 | value: isFirstLaunch,
27 | );
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/lib/data/storages/secure_storage.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_secure_storage/flutter_secure_storage.dart';
2 | import 'package:injectable/injectable.dart';
3 |
4 |
5 |
6 | @injectable
7 | class SecureStorage {
8 | final FlutterSecureStorage flutterSecureStorage;
9 |
10 | SecureStorage({
11 | required this.flutterSecureStorage,
12 | });
13 |
14 | Future putString({
15 | required String key,
16 | required String value,
17 | }) async {
18 | return flutterSecureStorage.write(
19 | key: key,
20 | value: value,
21 | );
22 | }
23 |
24 | Future getString({
25 | required String key,
26 | }) async {
27 | return flutterSecureStorage.read(
28 | key: key,
29 | );
30 | }
31 |
32 | Future remove({
33 | required String key,
34 | }) async {
35 | return flutterSecureStorage.delete(
36 | key: key,
37 | );
38 | }
39 |
40 | Future removeAll() async {
41 | return flutterSecureStorage.deleteAll();
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/lib/data/storages/storage.dart:
--------------------------------------------------------------------------------
1 | import 'package:injectable/injectable.dart';
2 | import 'package:shared_preferences/shared_preferences.dart';
3 |
4 | @injectable
5 | class Storage {
6 | final SharedPreferences sharedPreferences;
7 |
8 | Storage({
9 | required this.sharedPreferences,
10 | });
11 |
12 | Future putBool({
13 | required String key,
14 | required bool value,
15 | }) async {
16 | return
17 | sharedPreferences.setBool(key, value);
18 | }
19 |
20 | Future getBool({
21 | required String key,
22 | }) async {
23 | return sharedPreferences.getBool(key);
24 | }
25 |
26 | Future putString({
27 | required String key,
28 | required String value,
29 | }) async {
30 | return sharedPreferences.setString(key, value);
31 | }
32 |
33 | Future getString({
34 | required String key,
35 | }) async {
36 | return sharedPreferences.getString(key);
37 | }
38 |
39 | Future putInt({
40 | required String key,
41 | required int value,
42 | }) async {
43 | return sharedPreferences.setInt(key, value);
44 | }
45 |
46 | Future getInt({
47 | required String key,
48 | }) async {
49 | return sharedPreferences.getInt(key);
50 | }
51 |
52 | Future putDouble({
53 | required String key,
54 | required double value,
55 | }) async {
56 | return sharedPreferences.setDouble(key, value);
57 | }
58 |
59 | Future getDouble({
60 | required String key,
61 | }) async {
62 | return sharedPreferences.getDouble(key);
63 | }
64 |
65 | Future remove({
66 | required String key,
67 | }) async {
68 | return sharedPreferences.remove(key);
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/lib/data/storages/storage_keys.dart:
--------------------------------------------------------------------------------
1 | abstract class StorageKeys {
2 | const StorageKeys._();
3 |
4 | static const String firstLaunch = 'key-first-launch';
5 | static const String accessToken = 'key-access-token';
6 | }
7 |
--------------------------------------------------------------------------------
/lib/data/storages/token_storage.dart:
--------------------------------------------------------------------------------
1 | import 'package:injectable/injectable.dart';
2 | import 'package:vizier/data/storages/secure_storage.dart';
3 | import 'package:vizier/data/storages/storage_keys.dart';
4 |
5 | @injectable
6 | class TokenStorage {
7 | final SecureStorage secureStorage;
8 |
9 | TokenStorage({
10 | required this.secureStorage,
11 | });
12 |
13 | Future storeAccessToken(String accessToken) {
14 | return secureStorage.putString(
15 | key: StorageKeys.accessToken,
16 | value: accessToken,
17 | );
18 | }
19 |
20 | Future getAccessToken() {
21 | return secureStorage.getString(
22 | key: StorageKeys.accessToken,
23 | );
24 | }
25 |
26 | Future hasToken() async {
27 | final String? accessToken = await getAccessToken();
28 | return accessToken != null;
29 | }
30 |
31 | Future removeAccessToken() {
32 | return secureStorage.remove(
33 | key: StorageKeys.accessToken,
34 | );
35 | }
36 |
37 | Future clear() {
38 | return Future.wait([
39 | removeAccessToken(),
40 | ]);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/lib/extensions/extensions.dart:
--------------------------------------------------------------------------------
1 | import 'dart:math';
2 |
3 | import 'package:collection/collection.dart';
4 | import 'package:flutter/material.dart';
5 | import 'package:vizier/data/models/company_listing/history/data/company_listing_history_data_model.dart';
6 | import 'package:vizier/data/models/financial_history/history_data/financial_history_data_model.dart';
7 |
8 | part 'core_extensions.dart';
9 | part 'model_extensions.dart';
10 | part 'ui_extensions.dart';
11 |
--------------------------------------------------------------------------------
/lib/extensions/model_extensions.dart:
--------------------------------------------------------------------------------
1 | part of 'extensions.dart';
2 |
3 | extension ListFinancialHistoryDataModelMapper
4 | on List {
5 | double get highestBalanceOrSpent =>
6 | (copy().sorted(
7 | (a, b) => a.maxBalanceOrSpent.compareTo(b.maxBalanceOrSpent),
8 | )).lastOrNull?.maxBalanceOrSpent ??
9 | 0.0;
10 |
11 | List sortedByDate() => copy().sorted(
12 | (a, b) => a.date.compareTo(b.date),
13 | );
14 | }
15 |
16 | extension ListPortfolioCurrenciesHistoryDataModelMapper
17 | on List {
18 | double get highestValues =>
19 | (copy().sorted(
20 | (a, b) => a.maxValues.compareTo(b.maxValues),
21 | )).lastOrNull?.maxValues ??
22 | 0.0;
23 |
24 | double get lowestValues =>
25 | (copy().sorted(
26 | (a, b) => a.minValues.compareTo(b.minValues),
27 | )).firstOrNull?.minValues ??
28 | 0.0;
29 |
30 | List sortedByDate() => copy().sorted(
31 | (a, b) => a.date.compareTo(b.date),
32 | );
33 | }
34 |
--------------------------------------------------------------------------------
/lib/extensions/ui_extensions.dart:
--------------------------------------------------------------------------------
1 | part of 'extensions.dart';
2 |
3 | extension ListTextPainterExtensions on List {
4 | void calculate(Size size) {
5 | for (int i = 0; i < length; i++) {
6 | this[i].layout(
7 | maxWidth: size.width,
8 | );
9 | }
10 | }
11 |
12 | double get biggestHeight => isNotEmpty
13 | ? (copy().sorted((a, b) => a.height.compareTo(b.height))).last.height
14 | : 0.0;
15 |
16 | double get biggestWidth => isNotEmpty
17 | ? (copy().sorted((a, b) => a.width.compareTo(b.width))).last.width
18 | : 0.0;
19 |
20 | double get firstHeightOrZero => isNotEmpty ? first.height : 0.0;
21 |
22 | double get lastHeightOrZero => isNotEmpty ? last.height : 0.0;
23 |
24 | double get averageWidthOrZero =>
25 | isNotEmpty ? (first.width + last.width).half : 0.0;
26 | }
27 |
--------------------------------------------------------------------------------
/lib/l10n/app_loc.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_gen/gen_l10n/app_localizations.dart';
3 |
4 | class AppLoc {
5 | const AppLoc._();
6 |
7 | static AppLocalizations of(BuildContext context) {
8 | if (AppLocalizations.of(context) != null) {
9 | return AppLocalizations.of(context)!;
10 | } else {
11 | throw _AppLocalizationsContextNotAvailableException();
12 | }
13 | }
14 | }
15 |
16 | class _AppLocalizationsContextNotAvailableException implements Exception {
17 | @override
18 | String toString() {
19 | return 'Provided context is ether null or doesn\'t contain AppLocalizations';
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:vizier/config/injector/di.dart';
3 | import 'package:vizier/data/storages/common_storage.dart';
4 | import 'package:vizier/data/storages/token_storage.dart';
5 | import 'package:vizier/ui/main_app.dart';
6 |
7 | Future main() async {
8 | WidgetsFlutterBinding.ensureInitialized();
9 | await DI.instance.setupInjection();
10 | final bool isFirstLaunch = await DI.resolve().getIsFirstLaunch();
11 | final bool isSessionActive = await DI.resolve().hasToken();
12 |
13 | runApp(
14 | MainApp(
15 | isFirstTimeOpened: isFirstLaunch,
16 | isSessionActive: isSessionActive,
17 | ),
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/lib/mocks/factories/duration_factory.dart:
--------------------------------------------------------------------------------
1 | part of '../mock_factory.dart';
2 |
3 | class _DurationFactory {
4 | final DummyUtil dummyUtil;
5 |
6 | _DurationFactory({
7 | required this.dummyUtil,
8 | });
9 |
10 | static _DurationFactory instance = _DurationFactory(
11 | dummyUtil: DI.resolve(),
12 | );
13 |
14 | Duration standard(int days) {
15 | switch (days) {
16 | case DateTime.daysPerWeek:
17 | return const Duration(
18 | days: 6,
19 | );
20 | case DateTime.monthsPerYear:
21 | return const Duration(
22 | days: 30,
23 | );
24 | case DateTime.monthsPerYear * 30:
25 | return const Duration(
26 | days: DateTime.monthsPerYear * 30,
27 | );
28 | default:
29 | return const Duration(
30 | days: DateTime.monthsPerYear * 30 * 4,
31 | );
32 | }
33 | }
34 |
35 | Duration indexBased(int days, int index) {
36 | switch (days) {
37 | case DateTime.daysPerWeek:
38 | return Duration(
39 | days: index,
40 | );
41 | case DateTime.monthsPerYear:
42 | return Duration(
43 | days: 7 * index,
44 | );
45 | case DateTime.monthsPerYear * 30:
46 | return Duration(
47 | days: 90 * index,
48 | );
49 | default:
50 | return Duration(
51 | days: 365 * index,
52 | );
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/lib/mocks/factories/transaction_category_factory.dart:
--------------------------------------------------------------------------------
1 | part of '../mock_factory.dart';
2 |
3 | class _TransactionCategoryFactory {
4 | final DummyUtil dummyUtil;
5 |
6 | _TransactionCategoryFactory({
7 | required this.dummyUtil,
8 | });
9 |
10 | static _TransactionCategoryFactory instance = _TransactionCategoryFactory(
11 | dummyUtil: DI.resolve(),
12 | );
13 |
14 | final List _names = [
15 | 'Life',
16 | 'Housing',
17 | 'Debt repayment',
18 | 'Savings',
19 | 'Transporation',
20 | ]..shuffle();
21 |
22 | static const List _colorsFromLowestValue = [
23 | 'FFFFD6B4',
24 | 'FFFF9843',
25 | 'FFFF7000',
26 | 'FFB783FD',
27 | 'FF8043F9',
28 | ];
29 |
30 | List transactionCategories() {
31 | final List generatedValues = List.generate(
32 | _names.length,
33 | (index) => dummyUtil.randomDouble(
34 | minNumber: 100,
35 | maxNumber: 1500,
36 | ),
37 | ).sorted((a, b) => a.compareTo(b));
38 | final double summaryValues = generatedValues.reduce(
39 | (value, element) => value + element,
40 | );
41 | return List.generate(
42 | generatedValues.length,
43 | (index) => TransactionCategoryModel(
44 | colorHex: _colorsFromLowestValue[index],
45 | name: _names[index],
46 | value: generatedValues[index],
47 | percent: generatedValues[index] / summaryValues * 100,
48 | ),
49 | );
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/lib/mocks/offers_mocks.dart:
--------------------------------------------------------------------------------
1 | part of 'mock_factory.dart';
2 |
3 | class _OffersMocks {
4 | final double goal;
5 |
6 | _OffersMocks({
7 | required this.goal,
8 | });
9 |
10 | List prepareAll() {
11 | return [
12 | OfferModel(
13 | expectedValue: goal,
14 | label: 'Retirement goals',
15 | image: AppImages.svg.retirementGoals,
16 | detailsImage: AppImages.svg.retirementGoalsDetails,
17 | sliders: [
18 | const OfferSliderModel(
19 | current: 0.4,
20 | frequency: 100,
21 | label: 'Mothly saving plan',
22 | maxValue: 10000,
23 | type: OfferSliderType.price,
24 | ),
25 | const OfferSliderModel(
26 | current: 0.6,
27 | frequency: 1000,
28 | label: 'Current asset worth',
29 | maxValue: 100000,
30 | type: OfferSliderType.price,
31 | ),
32 | ],
33 | type: OfferType.retirementGoals,
34 | ),
35 | OfferModel(
36 | expectedValue: goal * 0.3,
37 | label: 'Mortgage',
38 | image: AppImages.svg.mortgage,
39 | detailsImage: AppImages.svg.mortgageDetails,
40 | sliders: [
41 | const OfferSliderModel(
42 | current: 0.2,
43 | frequency: 10000,
44 | label: 'Purchase price',
45 | maxValue: 1000000,
46 | type: OfferSliderType.price,
47 | ),
48 | const OfferSliderModel(
49 | current: 0.3,
50 | frequency: 1,
51 | label: 'Repayment time',
52 | maxValue: 30,
53 | type: OfferSliderType.year,
54 | ),
55 | ],
56 | type: OfferType.mortgage,
57 | ),
58 | ];
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/lib/mocks/user_mocks.dart:
--------------------------------------------------------------------------------
1 | part of 'mock_factory.dart';
2 |
3 | class _UserMocks {
4 | final DummyUtil dummyUtil;
5 |
6 | _UserMocks({
7 | required this.dummyUtil,
8 | });
9 |
10 | UserModel prepareUser() {
11 | return const UserModel(
12 | avatar: 'assets/mocks/user/avatar.png',
13 | email: 'John_S@gmail.com',
14 | firstName: 'John',
15 | lastName: 'Smith',
16 | );
17 | }
18 |
19 | UserNotificationsResponse prepareUserNotificationsResponse() {
20 | return UserNotificationsResponse(
21 | areNotificationsEnabled: dummyUtil.randomBool(),
22 | );
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/lib/ui/app_coordinator.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_bloc/flutter_bloc.dart';
3 | import 'package:vizier/config/router/app_router.dart';
4 | import 'package:vizier/cubits/authentication/authentication_cubit.dart';
5 | import 'package:vizier/cubits/user/user_cubit.dart';
6 | import 'package:vizier/cubits/wallet/wallet_cubit.dart';
7 |
8 | //This class should add listeners to global cubits if
9 | //there is need to use Global context (eg. show page after push notification)
10 | class AppCoordinator extends StatelessWidget {
11 | final AppRouter appRouter;
12 | final Widget child;
13 |
14 | const AppCoordinator({
15 | required this.appRouter,
16 | required this.child,
17 | super.key,
18 | });
19 |
20 | @override
21 | Widget build(BuildContext context) {
22 | return MultiBlocListener(
23 | listeners: [
24 | _authenticationListener(),
25 | ],
26 | child: child,
27 | );
28 | }
29 |
30 | BlocListener _authenticationListener() {
31 | return BlocListener(
32 | listener: (context, state) {
33 | state.maybeMap(
34 | authenticated: (_) => context.read().fetchMe(),
35 | logout: (_) {
36 | context.read().logout();
37 | context.read().logout();
38 | appRouter.pushAndPopUntil(
39 | const AuthenticationLoginPageRoute(),
40 | predicate: (_) => false,
41 | );
42 | },
43 | orElse: () => null,
44 | );
45 | },
46 | );
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/lib/ui/modals/bottom_actions_sheet/bottom_actions_sheet.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:vizier/config/styles/colors/app_colors.dart';
3 | import 'package:vizier/config/styles/dimensions/app_dimensions.dart';
4 | import 'package:vizier/config/styles/text_styles/app_text_styles.dart';
5 | import 'package:vizier/ui/widgets/adaptive/adaptive_button.dart';
6 |
7 | part 'widget/bottom_sheet_action_cell.dart';
8 |
9 | class BottomActionsSheet extends StatelessWidget {
10 | final List actions;
11 |
12 | const BottomActionsSheet({
13 | required this.actions,
14 | super.key,
15 | });
16 |
17 | @override
18 | Widget build(BuildContext context) {
19 | return Padding(
20 | padding: EdgeInsets.symmetric(
21 | horizontal: AppDimensions.padding.bigValue,
22 | vertical: AppDimensions.padding.defaultValue,
23 | ),
24 | child: Column(
25 | mainAxisSize: MainAxisSize.min,
26 | crossAxisAlignment: CrossAxisAlignment.start,
27 | children: [
28 | Center(
29 | child: _buildStick(),
30 | ),
31 | SizedBox(
32 | height: AppDimensions.padding.smallValue,
33 | ),
34 | ...actions,
35 | ],
36 | ),
37 | );
38 | }
39 |
40 | Widget _buildStick() {
41 | return Container(
42 | decoration: BoxDecoration(
43 | borderRadius: BorderRadius.circular(2.5),
44 | color: AppColors.gray400,
45 | ),
46 | height: 4.0,
47 | width: 51.0,
48 | );
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/lib/ui/modals/bottom_actions_sheet/bottom_actions_sheet_factory.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:vizier/config/styles/decorations/app_decorations.dart';
3 | import 'package:vizier/l10n/app_loc.dart';
4 | import 'package:vizier/ui/modals/bottom_actions_sheet/bottom_actions_sheet.dart';
5 |
6 | abstract class BottomActionsSheetFactory {
7 | const BottomActionsSheetFactory._();
8 |
9 | static void _showBottomSheet(
10 | BuildContext context, {
11 | required Widget child,
12 | }) {
13 | showModalBottomSheet(
14 | shape: AppDecorations.bottomSheetShape,
15 | context: context,
16 | builder: (context) => child,
17 | );
18 | }
19 |
20 | static void showWalletMoreModal(
21 | BuildContext context, {
22 | required VoidCallback onCardsOverviewPressed,
23 | }) {
24 | _showBottomSheet(
25 | context,
26 | child: BottomActionsSheet(
27 | actions: [
28 | BottomSheetActionCell(
29 | title: AppLoc.of(context).financesHistoryChartBottomSheetCardsOverviewButton,
30 | onPressed: () {
31 | Navigator.of(context).pop();
32 | onCardsOverviewPressed();
33 | },
34 | ),
35 | ],
36 | ),
37 | );
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/lib/ui/modals/bottom_actions_sheet/widget/bottom_sheet_action_cell.dart:
--------------------------------------------------------------------------------
1 | part of '../bottom_actions_sheet.dart';
2 |
3 | class BottomSheetActionCell extends StatelessWidget {
4 | final String title;
5 | final VoidCallback onPressed;
6 |
7 | const BottomSheetActionCell({
8 | required this.title,
9 | required this.onPressed,
10 | super.key,
11 | });
12 |
13 | @override
14 | Widget build(BuildContext context) {
15 | return AdaptiveButton(
16 | onPressed: onPressed,
17 | child: Text(
18 | title,
19 | style: AppTextStyles.caption1(),
20 | ),
21 | );
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/lib/ui/models/card_account_type.dart:
--------------------------------------------------------------------------------
1 | enum CardAccountType {
2 | front,
3 | back,
4 | }
5 |
--------------------------------------------------------------------------------
/lib/ui/models/chart_multi_pie_item.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class ChartMultiPieItem {
4 | final double amount;
5 | final Color color;
6 | final String name;
7 |
8 | const ChartMultiPieItem({
9 | required this.amount,
10 | required this.color,
11 | required this.name,
12 | });
13 | }
14 |
--------------------------------------------------------------------------------
/lib/ui/models/chart_multi_pie_section.dart:
--------------------------------------------------------------------------------
1 | import 'package:vizier/ui/models/chart_multi_pie_item.dart';
2 |
3 | class ChartMultiPieSection {
4 | final List items;
5 |
6 | const ChartMultiPieSection({
7 | required this.items,
8 | });
9 | }
10 |
--------------------------------------------------------------------------------
/lib/ui/pages/app/main_app_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:auto_route/auto_route.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_gen/gen_l10n/app_localizations.dart';
4 | import 'package:vizier/config/router/app_router.dart';
5 | import 'package:vizier/config/styles/theme/app_theme.dart';
6 |
7 | class MainAppPage extends StatefulWidget {
8 | final AppRouter appRouter;
9 | final bool isFirstTimeOpened;
10 | final bool isSessionActive;
11 |
12 | const MainAppPage({
13 | required this.appRouter,
14 | required this.isFirstTimeOpened,
15 | required this.isSessionActive,
16 | super.key,
17 | });
18 |
19 | @override
20 | _MainAppPageState createState() => _MainAppPageState();
21 | }
22 |
23 | class _MainAppPageState extends State {
24 | @override
25 | Widget build(BuildContext context) {
26 | return MaterialApp.router(
27 | localizationsDelegates: const [
28 | AppLocalizations.delegate,
29 | ],
30 | routerDelegate: widget.appRouter.delegate(
31 | initialRoutes: [
32 | _prepareInitialRoute(),
33 | ],
34 | ),
35 | routeInformationParser: widget.appRouter.defaultRouteParser(),
36 | theme: AppTheme.fromType(ThemeType.light).themeData,
37 | );
38 | }
39 |
40 | PageRouteInfo _prepareInitialRoute() {
41 | if (widget.isFirstTimeOpened) {
42 | return const OnboardingPageRoute();
43 | } else {
44 | if (widget.isSessionActive) {
45 | return const BottomNavigationPageRoute();
46 | }
47 | return const AuthenticationLoginPageRoute();
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/lib/ui/pages/authentication/login/widgets/login_header.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_svg/flutter_svg.dart';
3 | import 'package:vizier/config/styles/colors/app_colors.dart';
4 | import 'package:vizier/config/styles/images/app_images.dart';
5 | import 'package:vizier/config/styles/text_styles/app_text_styles.dart';
6 | import 'package:vizier/l10n/app_loc.dart';
7 |
8 | class LoginHeader extends StatelessWidget {
9 | const LoginHeader({super.key});
10 |
11 | @override
12 | Widget build(BuildContext context) {
13 | return Column(
14 | children: [
15 | SvgPicture.asset(
16 | AppImages.svg.moneyLogin,
17 | ),
18 | const SizedBox(
19 | height: 20.0,
20 | ),
21 | _buildTitle(context),
22 | const SizedBox(
23 | height: 16.0,
24 | ),
25 | _buildSubTitle(context),
26 | ],
27 | );
28 | }
29 |
30 | Widget _buildTitle(BuildContext context) {
31 | return Text(
32 | AppLoc.of(context).logInPageHeaderTitle,
33 | style: AppTextStyles.h2(),
34 | );
35 | }
36 |
37 | Widget _buildSubTitle(BuildContext context) {
38 | return Text(
39 | AppLoc.of(context).logInPageHeaderSubtitle,
40 | style: AppTextStyles.text2().copyWith(
41 | color: AppColors.gray200,
42 | ),
43 | );
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/lib/ui/pages/bottom_navigation/bottom_navigation_item.dart:
--------------------------------------------------------------------------------
1 | import 'package:auto_route/auto_route.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:vizier/config/router/app_router.dart';
4 | import 'package:vizier/l10n/app_loc.dart';
5 |
6 | enum BottomNavigationItem { home, finances, portfolio, offers }
7 |
8 | extension BottomNavigationItemExtension on BottomNavigationItem {
9 | String title(BuildContext context) {
10 | switch (this) {
11 | case BottomNavigationItem.home:
12 | return AppLoc.of(context).bottomBarItemHomeTitle;
13 | case BottomNavigationItem.finances:
14 | return AppLoc.of(context).bottomBarItemFinancesTitle;
15 | case BottomNavigationItem.portfolio:
16 | return AppLoc.of(context).bottomBarItemPortfolioTitle;
17 | case BottomNavigationItem.offers:
18 | return AppLoc.of(context).bottomBarItemOffersTitle;
19 | }
20 | }
21 |
22 | IconData get icon {
23 | //TODO (MT): Change icons
24 | switch (this) {
25 | case BottomNavigationItem.home:
26 | return Icons.home;
27 | case BottomNavigationItem.finances:
28 | return Icons.pie_chart_outline;
29 | case BottomNavigationItem.portfolio:
30 | return Icons.account_balance_wallet;
31 | case BottomNavigationItem.offers:
32 | return Icons.flag;
33 | }
34 | }
35 |
36 | PageRouteInfo get route {
37 | switch (this) {
38 | case BottomNavigationItem.home:
39 | return const HomePageRoute();
40 | case BottomNavigationItem.finances:
41 | return const FinancesPageRoute();
42 | case BottomNavigationItem.portfolio:
43 | return const PortfolioPageRoute();
44 | case BottomNavigationItem.offers:
45 | return const OffersPageRoute();
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/lib/ui/pages/bottom_navigation/bottom_navigation_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:auto_route/auto_route.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:vizier/ui/pages/bottom_navigation/bottom_navigation_item.dart';
4 | import 'package:vizier/ui/widgets/ripple_remover.dart';
5 |
6 | class BottomNavigationPage extends StatefulWidget {
7 | static const String route = 'bottom_navigation';
8 |
9 | const BottomNavigationPage({super.key});
10 |
11 | @override
12 | _BottomNavigationPageState createState() => _BottomNavigationPageState();
13 | }
14 |
15 | class _BottomNavigationPageState extends State {
16 | @override
17 | Widget build(BuildContext context) {
18 | return AutoTabsScaffold(
19 | routes: BottomNavigationItem.values
20 | .map(
21 | (e) => e.route,
22 | )
23 | .toList(),
24 | bottomNavigationBuilder: (_, tabsRouter) => RippleRemover(
25 | child: _buildBottomNavigationBar(
26 | tabsRouter: tabsRouter,
27 | ),
28 | ),
29 | );
30 | }
31 |
32 | BottomNavigationBar _buildBottomNavigationBar({
33 | required TabsRouter tabsRouter,
34 | }) {
35 | return BottomNavigationBar(
36 | currentIndex: tabsRouter.activeIndex,
37 | onTap: tabsRouter.setActiveIndex,
38 | items: BottomNavigationItem.values
39 | .map(
40 | (e) => BottomNavigationBarItem(
41 | icon: Icon(e.icon),
42 | label: e.title(context),
43 | ),
44 | )
45 | .toList(),
46 | );
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/lib/ui/pages/company_listing_details/widgets/company_listing_buttons.dart:
--------------------------------------------------------------------------------
1 | part of '../company_listing_page.dart';
2 |
3 | class _CompanyListingButtons extends StatelessWidget {
4 | final VoidCallback onBuyPressed;
5 | final VoidCallback onSellPressed;
6 |
7 | const _CompanyListingButtons({
8 | required this.onBuyPressed,
9 | required this.onSellPressed,
10 | });
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | return Row(
15 | children: [
16 | Expanded(
17 | child: AdaptiveButton(
18 | onPressed: onSellPressed,
19 | decoration: AppDecorations.button.secondary().copyWith(
20 | color: Colors.transparent,
21 | ),
22 | child: Text(
23 | AppLoc.of(context).portfolioCurrenciesSellButton,
24 | style: AppTextStyles.button.primary(),
25 | ),
26 | ),
27 | ),
28 | SizedBox(
29 | width: AppDimensions.padding.defaultValue,
30 | ),
31 | Expanded(
32 | child: AdaptiveButton(
33 | onPressed: onBuyPressed,
34 | decoration: AppDecorations.button.primary(),
35 | child: Text(
36 | AppLoc.of(context).portfolioCurrenciesBuyButton,
37 | style: AppTextStyles.button.primary(),
38 | ),
39 | ),
40 | ),
41 | ],
42 | );
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/lib/ui/pages/company_listing_details/widgets/company_listing_history_chart.dart:
--------------------------------------------------------------------------------
1 | part of '../company_listing_page.dart';
2 |
3 | class _CompanyListingHistoryChart extends StatelessWidget {
4 | final CompanyListingHistoryModel? data;
5 | final bool isLoading;
6 | final Function(ChartTab tab) onTabSelected;
7 | final ChartTab selectedTab;
8 |
9 | const _CompanyListingHistoryChart({
10 | required this.isLoading,
11 | required this.onTabSelected,
12 | required this.selectedTab,
13 | this.data,
14 | });
15 |
16 | @override
17 | Widget build(BuildContext context) {
18 | final CompanyListingHistoryModel? data = this.data;
19 | return ChartContainer(
20 | isLoading: isLoading,
21 | selectedTab: selectedTab,
22 | onTabSelected: onTabSelected,
23 | chart: Padding(
24 | padding: EdgeInsets.only(
25 | top: AppDimensions.padding.smallValue,
26 | ),
27 | child: data != null
28 | ? Chart(
29 | layers: ChartFactory.fromPortfolioCurrenciesHistoryModel(data),
30 | padding: const EdgeInsets.only(
31 | left: 20.0,
32 | bottom: 8.0,
33 | ),
34 | )
35 | : const SizedBox.shrink(),
36 | ),
37 | );
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/lib/ui/pages/credit_card/overview/widgets/credit_card_list.dart:
--------------------------------------------------------------------------------
1 | part of '../credit_card_overview.dart';
2 |
3 | class _CreditCardList extends StatelessWidget {
4 | final List accounts;
5 | final PageController controller;
6 | final int currentIndex;
7 | final void Function(AccountModel, int) onCardChanged;
8 |
9 | const _CreditCardList({
10 | required this.accounts,
11 | required this.controller,
12 | required this.currentIndex,
13 | required this.onCardChanged,
14 | });
15 |
16 | @override
17 | Widget build(BuildContext context) {
18 | return PageView.builder(
19 | controller: controller,
20 | onPageChanged: (page) => onCardChanged(accounts[page], page),
21 | itemCount: accounts.length,
22 | itemBuilder: (_, index) {
23 | final AccountModel account = accounts[index];
24 | return AnimatedScale(
25 | duration: AppConstants.animation.defaultDuration,
26 | scale: currentIndex == index ? 1.0 : 0.95,
27 | child: AnimatedOpacity(
28 | duration: AppConstants.animation.defaultDuration,
29 | opacity: currentIndex == index ? 1.0 : 0.5,
30 | child: AnimatedCreditCard(
31 | balance: CurrencyFormatterUtil.instance.format(
32 | value: account.balance,
33 | ),
34 | expiry: account.expiry,
35 | logo: account.logo,
36 | number: account.number,
37 | type: CardAccountType.front,
38 | ),
39 | ),
40 | );
41 | },
42 | );
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/lib/ui/pages/credit_card/overview/widgets/credit_card_transactions_list.dart:
--------------------------------------------------------------------------------
1 | part of '../credit_card_overview.dart';
2 |
3 | class _CreditCardTransactionsList extends StatelessWidget {
4 | final List transactions;
5 |
6 | const _CreditCardTransactionsList({
7 | required this.transactions,
8 | });
9 |
10 | @override
11 | Widget build(BuildContext context) {
12 | return ListView.separated(
13 | itemBuilder: (_, index) {
14 | final TransactionModel transaction = transactions[index];
15 | return TransactionCell(
16 | transactionModel: transaction,
17 | );
18 | },
19 | itemCount: transactions.length,
20 | padding: AppDimensions.padding.defaultHorizontal().copyWith(
21 | bottom: MediaQuery.of(context).viewPadding.bottom,
22 | ),
23 | separatorBuilder: (_, __) => SizedBox(
24 | height: AppDimensions.padding.bigValue,
25 | ),
26 | );
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/lib/ui/pages/finances/widgets/finances_header.dart:
--------------------------------------------------------------------------------
1 | part of '../finances_page.dart';
2 |
3 | class _FinancesHeader extends StatelessWidget {
4 | final double cashBalance;
5 |
6 | const _FinancesHeader({
7 | required this.cashBalance,
8 | });
9 |
10 | @override
11 | Widget build(BuildContext context) {
12 | return Column(
13 | children: [
14 | _buildTitle(context),
15 | _buildDescription(context),
16 | ],
17 | );
18 | }
19 |
20 | Widget _buildTitle(BuildContext context) {
21 | return Text(
22 | CurrencyFormatterUtil.instance.format(
23 | value: cashBalance,
24 | ),
25 | style: Theme.of(context).textTheme.headline1,
26 | );
27 | }
28 |
29 | Widget _buildDescription(BuildContext context) {
30 | return Text(
31 | AppLoc.of(context).financesHeaderDescription,
32 | style: AppTextStyles.caption2Bold().copyWith(
33 | color: AppColors.navy.withOpacity(0.5),
34 | ),
35 | );
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/lib/ui/pages/finances/widgets/finances_status_summary.dart:
--------------------------------------------------------------------------------
1 | part of '../finances_page.dart';
2 |
3 | class _FinancesStatusSummary extends StatelessWidget {
4 | final double spent;
5 | final DateTime since;
6 |
7 | const _FinancesStatusSummary({
8 | required this.spent,
9 | required this.since,
10 | });
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | return Container(
15 | decoration: AppDecorations.defaultBorder(),
16 | padding: EdgeInsets.all(
17 | AppDimensions.padding.defaultValue,
18 | ),
19 | child: Column(
20 | children: [
21 | _buildTitle(context),
22 | _buildSpentAmount(context),
23 | _buildSince(context),
24 | ],
25 | ),
26 | );
27 | }
28 |
29 | Widget _buildTitle(BuildContext context) {
30 | return Text(
31 | AppLoc.of(context).financesStatusSummaryTitle,
32 | style: AppTextStyles.caption2Bold().copyWith(
33 | color: AppColors.error300,
34 | ),
35 | );
36 | }
37 |
38 | Widget _buildSpentAmount(BuildContext context) {
39 | return Text(
40 | CurrencyFormatterUtil.instance.format(
41 | value: spent,
42 | ),
43 | style: Theme.of(context).textTheme.headline4,
44 | );
45 | }
46 |
47 | Widget _buildSince(BuildContext context) {
48 | final String date = DateFormatterUtil.instance.format(
49 | date: since,
50 | pattern: 'MMMM d',
51 | ) ??
52 | '';
53 | return Text(
54 | AppLoc.of(context).financesStatusSummarySince(date),
55 | style: AppTextStyles.caption2().copyWith(
56 | color: AppColors.navy.withOpacity(0.6),
57 | ),
58 | );
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/lib/ui/pages/financial_breakdown/financial_breakdown_page_arguments.dart:
--------------------------------------------------------------------------------
1 | import 'package:vizier/data/models/account/account_model.dart';
2 |
3 | class FinancialBreakdownPageArguments {
4 | final AccountModel account;
5 |
6 | FinancialBreakdownPageArguments({
7 | required this.account,
8 | });
9 | }
10 |
--------------------------------------------------------------------------------
/lib/ui/pages/financial_breakdown/widgets/financial_breakdown_transactions_summary.dart:
--------------------------------------------------------------------------------
1 | part of '../financial_breakdown_page.dart';
2 |
3 | class _FinancialBreakdownTransactionsSummary extends StatelessWidget {
4 | final List transactionCategories;
5 |
6 | const _FinancialBreakdownTransactionsSummary({
7 | required this.transactionCategories,
8 | });
9 |
10 | @override
11 | Widget build(BuildContext context) {
12 | return Container(
13 | decoration: const BoxDecoration(
14 | borderRadius: BorderRadius.vertical(
15 | top: Radius.circular(24.0),
16 | ),
17 | color: AppColors.white,
18 | ),
19 | padding: EdgeInsets.all(AppDimensions.padding.bigValue),
20 | child: SafeArea(
21 | child: _buildTransactionsList(),
22 | ),
23 | );
24 | }
25 |
26 | Widget _buildTransactionsList() {
27 | return ListView.builder(
28 | itemBuilder: (context, index) => _FinancialBreakdownTransactionCell(
29 | transactionCategory: transactionCategories[index],
30 | ),
31 | itemCount: transactionCategories.length,
32 | physics: const NeverScrollableScrollPhysics(),
33 | shrinkWrap: true,
34 | );
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/lib/ui/pages/home/add/widgets/home_add_accounts_section.dart:
--------------------------------------------------------------------------------
1 | part of '../home_add_content.dart';
2 |
3 | class _HomeAddAccountsSection extends StatelessWidget {
4 | final VoidCallback onMorePressed;
5 |
6 | const _HomeAddAccountsSection({
7 | required this.onMorePressed,
8 | });
9 |
10 | @override
11 | Widget build(BuildContext context) {
12 | return Column(
13 | children: [
14 | SectionHeader(
15 | title: AppLoc.of(context).homeAddAccountsSectionTitle,
16 | onMorePressed: onMorePressed,
17 | ),
18 | DecoratedBox(
19 | decoration: AppDecorations.defaultBorder(),
20 | child: _buildActions(context),
21 | ),
22 | ],
23 | );
24 | }
25 |
26 | Widget _buildActions(BuildContext context) {
27 | return Column();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/lib/ui/pages/home/add/widgets/home_add_action_cell.dart:
--------------------------------------------------------------------------------
1 | part of '../home_add_content.dart';
2 |
3 | class _HomeAddActionCell extends StatelessWidget {
4 | final String title;
5 | final IconData icon;
6 | final VoidCallback onPressed;
7 |
8 | const _HomeAddActionCell({
9 | required this.title,
10 | required this.icon,
11 | required this.onPressed,
12 | });
13 |
14 | @override
15 | Widget build(BuildContext context) {
16 | return AdaptiveButton(
17 | onPressed: onPressed,
18 | padding: const EdgeInsets.symmetric(
19 | horizontal: 8.0,
20 | vertical: 12.0,
21 | ),
22 | child: Row(
23 | children: [
24 | _buildIcon(),
25 | const SizedBox(
26 | width: 12.0,
27 | ),
28 | _buildTitle(context),
29 | ],
30 | ),
31 | );
32 | }
33 |
34 | Widget _buildIcon() {
35 | return CircleAvatar(
36 | backgroundColor: AppColors.primary100.withOpacity(0.16),
37 | radius: 21.0,
38 | child: Icon(
39 | icon,
40 | color: AppColors.primary100,
41 | ),
42 | );
43 | }
44 |
45 | Widget _buildTitle(BuildContext context) {
46 | return Text(
47 | title,
48 | style: Theme.of(context).textTheme.headline6,
49 | );
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/lib/ui/pages/home/home_tab_item.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:vizier/l10n/app_loc.dart';
3 | import 'package:vizier/ui/pages/home/add/home_add_content.dart';
4 | import 'package:vizier/ui/pages/home/my_future/home_my_future_content.dart';
5 | import 'package:vizier/ui/pages/home/my_wallet/home_my_wallet_content.dart';
6 |
7 | enum HomeTabItem { myWallet, myFuture, add }
8 |
9 | extension HomeTabItemExtension on HomeTabItem {
10 | String title(BuildContext context) {
11 | switch (this) {
12 | case HomeTabItem.myWallet:
13 | return AppLoc.of(context).homeTabItemWalletTitle;
14 | case HomeTabItem.myFuture:
15 | return AppLoc.of(context).homeTabItemFutureTitle;
16 | case HomeTabItem.add:
17 | return AppLoc.of(context).homeTabItemAddTitle;
18 | }
19 | }
20 |
21 | Widget content(BuildContext context) {
22 | switch (this) {
23 | case HomeTabItem.myWallet:
24 | return const HomeMyWalletContent();
25 | case HomeTabItem.myFuture:
26 | return const HomeMyFutureContent();
27 | case HomeTabItem.add:
28 | return const HomeAddContent();
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/lib/ui/pages/home/my_future/widgets/home_my_future_assets_header.dart:
--------------------------------------------------------------------------------
1 | part of '../home_my_future_content.dart';
2 |
3 | class _HomeMyFutureAssetsHeader extends StatelessWidget {
4 | final double? assetChange;
5 | final double? assetPercentageChange;
6 | final DateTime? date;
7 | final double? goal;
8 | final int? goalProgress;
9 |
10 | const _HomeMyFutureAssetsHeader({
11 | required this.assetChange,
12 | required this.assetPercentageChange,
13 | required this.date,
14 | required this.goal,
15 | required this.goalProgress,
16 | });
17 |
18 | @override
19 | Widget build(BuildContext context) {
20 | return Container(
21 | decoration: AppDecorations.defaultBorder(),
22 | padding: EdgeInsets.all(AppDimensions.padding.defaultValue),
23 | child: Column(
24 | children: [
25 | AssetPerformanceItem(
26 | assetChange: assetChange,
27 | assetPercentageChange: assetPercentageChange,
28 | title: AppLoc.of(context).homeMyFutureAssetPerformanceTitle,
29 | content: DateFormatterUtil.instance.formatDay(
30 | date: date,
31 | ),
32 | ),
33 | SizedBox(
34 | height: AppDimensions.padding.bigValue,
35 | ),
36 | ProgressBar(
37 | currentProgress: goalProgress ?? 0,
38 | goal: goal != null
39 | ? CurrencyFormatterUtil.instance.format(
40 | value: goal!,
41 | )
42 | : null,
43 | summary: PercentageFormatterUtil.instance.format(
44 | value: goalProgress?.toDouble() ?? 0,
45 | decimalDigits: 0,
46 | ),
47 | ),
48 | ],
49 | ),
50 | );
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/lib/ui/pages/home/my_future/widgets/home_my_future_retirement_chart.dart:
--------------------------------------------------------------------------------
1 | part of '../home_my_future_content.dart';
2 |
3 | class _HomeMyFutureRetirementChart extends StatelessWidget {
4 | final RetirementPlanModel? data;
5 | final String timeInterval;
6 | final ChartTab selectedTab;
7 | final Function(ChartTab tab) onTabSelected;
8 |
9 | const _HomeMyFutureRetirementChart({
10 | required this.data,
11 | required this.timeInterval,
12 | required this.selectedTab,
13 | required this.onTabSelected,
14 | });
15 |
16 | @override
17 | Widget build(BuildContext context) {
18 | return ChartContainer(
19 | title: AppLoc.of(context).homeMyFutureChartTitle,
20 | content: timeInterval,
21 | selectedTab: selectedTab,
22 | onTabSelected: onTabSelected,
23 | chart: data != null
24 | ? _buildChart(
25 | context,
26 | data: data!,
27 | )
28 | : const SizedBox.shrink(),
29 | );
30 | }
31 |
32 | Widget _buildChart(
33 | BuildContext context, {
34 | required RetirementPlanModel data,
35 | }) {
36 | return Chart(
37 | layers: ChartFactory.fromRetirementPlanModel(
38 | data,
39 | daysTo: selectedTab.days(),
40 | ),
41 | padding: const EdgeInsets.only(
42 | bottom: 8.0,
43 | left: 20.0,
44 | ),
45 | );
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/lib/ui/pages/home/my_wallet/widgets/home_my_wallet_goals_section.dart:
--------------------------------------------------------------------------------
1 | part of '../home_my_wallet_content.dart';
2 |
3 | class _HomeMyWalletGoalsSection extends StatelessWidget {
4 | final List goals;
5 | final VoidCallback onMorePressed;
6 |
7 | const _HomeMyWalletGoalsSection({
8 | required this.goals,
9 | required this.onMorePressed,
10 | });
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | return Column(
15 | children: [
16 | SectionHeader(
17 | title: AppLoc.of(context).homeMyWalletSummaryGoalsSectionTitle,
18 | onMorePressed: onMorePressed,
19 | ),
20 | _buildGoalsList(context)
21 | ],
22 | );
23 | }
24 |
25 | Widget _buildGoalsList(BuildContext context) {
26 | return Row(
27 | crossAxisAlignment: CrossAxisAlignment.start,
28 | children: goals
29 | .getRange(0, 2)
30 | .map(
31 | (goal) => Expanded(
32 | child: _HomeMyWalletGoalCell(
33 | title: goal.name,
34 | goal: goal.goal,
35 | change: goal.change,
36 | reached: goal.reached,
37 | onPressed: () =>
38 | AdaptiveAlertDialogFactory.showContentUnavailable(context),
39 | ),
40 | ),
41 | )
42 | .toList()
43 | ..insert(
44 | 1,
45 | SizedBox(
46 | width: AppDimensions.padding.defaultValue,
47 | ),
48 | ),
49 | );
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/lib/ui/pages/offers/details/widgets/offer_details_header.dart:
--------------------------------------------------------------------------------
1 | part of '../offer_details_page.dart';
2 |
3 | class _OfferDetailsHeader extends StatelessWidget {
4 | final String leftTitle;
5 | final String leftContent;
6 | final String rightTitle;
7 | final String rightContent;
8 |
9 | const _OfferDetailsHeader({
10 | required this.leftTitle,
11 | required this.leftContent,
12 | required this.rightTitle,
13 | required this.rightContent,
14 | });
15 |
16 | @override
17 | Widget build(BuildContext context) {
18 | return _OfferDetailsSummary(
19 | left: Column(
20 | // TODO (AK) add logic
21 | children: [
22 | Text(
23 | leftTitle,
24 | style: AppTextStyles.h4(),
25 | ),
26 | Text(
27 | leftContent,
28 | style: AppTextStyles.caption2Bold().copyWith(
29 | color: AppColors.navy.withOpacity(0.6),
30 | ),
31 | ),
32 | ],
33 | ),
34 | right: Column(
35 | children: [
36 | Text(
37 | rightTitle,
38 | style: AppTextStyles.h4(),
39 | ),
40 | Text(
41 | rightContent,
42 | style: AppTextStyles.caption2Bold().copyWith(
43 | color: AppColors.success100,
44 | ),
45 | ),
46 | ],
47 | ),
48 | );
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/lib/ui/pages/offers/details/widgets/offer_details_summary.dart:
--------------------------------------------------------------------------------
1 | part of '../offer_details_page.dart';
2 |
3 | class _OfferDetailsSummary extends StatelessWidget {
4 | final Widget left;
5 | final Widget right;
6 |
7 | const _OfferDetailsSummary({
8 | required this.left,
9 | required this.right,
10 | });
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | return IntrinsicHeight(
15 | child: DecoratedBox(
16 | decoration: AppDecorations.defaultBorder(),
17 | child: Row(
18 | children: [
19 | Expanded(
20 | child: Padding(
21 | padding: const EdgeInsets.all(16.0),
22 | child: Center(
23 | child: left,
24 | ),
25 | ),
26 | ),
27 | Container(
28 | width: 1.0,
29 | color: AppColors.gray400,
30 | ),
31 | Expanded(
32 | child: Padding(
33 | padding: const EdgeInsets.all(16.0),
34 | child: Center(
35 | child: right,
36 | ),
37 | ),
38 | ),
39 | ],
40 | ),
41 | ),
42 | );
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/lib/ui/pages/onboarding/cubit/onboarding_cubit.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_bloc/flutter_bloc.dart';
2 | import 'package:freezed_annotation/freezed_annotation.dart';
3 | import 'package:injectable/injectable.dart';
4 | import 'package:vizier/data/storages/common_storage.dart';
5 | import 'package:vizier/ui/pages/onboarding/onboarding_item.dart';
6 |
7 | part 'onboarding_state.dart';
8 |
9 | part 'onboarding_cubit.freezed.dart';
10 |
11 | @injectable
12 | class OnboardingCubit extends Cubit {
13 | CommonStorage storage;
14 |
15 | OnboardingCubit(this.storage) : super(OnboardingState.initial());
16 |
17 | void saveFirstTimeOpened({required bool isOpened}) {
18 | storage.storeIsFirstLaunch(isFirstLaunch: isOpened);
19 | emit(
20 | state.copyWith(
21 | firstTimeOpened: isOpened,
22 | ),
23 | );
24 | }
25 |
26 | void changePage(int currentPage) {
27 | emit(
28 | state.copyWith(
29 | currentPage: currentPage,
30 | ),
31 | );
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/lib/ui/pages/onboarding/cubit/onboarding_state.dart:
--------------------------------------------------------------------------------
1 | part of 'onboarding_cubit.dart';
2 |
3 | @freezed
4 | class OnboardingState with _$OnboardingState {
5 | factory OnboardingState({
6 | required bool firstTimeOpened,
7 | required int currentPage,
8 | }) = _OnboardingState;
9 |
10 | const OnboardingState._();
11 |
12 | factory OnboardingState.initial() => OnboardingState(
13 | firstTimeOpened: true,
14 | currentPage: 0,
15 | );
16 |
17 | bool get isLastPage => OnboardingItem.values.length == (currentPage + 1);
18 | }
19 |
--------------------------------------------------------------------------------
/lib/ui/pages/onboarding/widgets/onboarding_item_content.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_svg/flutter_svg.dart';
3 | import 'package:vizier/config/styles/colors/app_colors.dart';
4 | import 'package:vizier/config/styles/dimensions/app_dimensions.dart';
5 |
6 | class OnboardingItemContent extends StatelessWidget {
7 | final int pageIndex;
8 | final String title;
9 | final String description;
10 | final String imageAsset;
11 |
12 | const OnboardingItemContent({
13 | required this.pageIndex,
14 | required this.title,
15 | required this.description,
16 | required this.imageAsset,
17 | });
18 |
19 | @override
20 | Widget build(BuildContext context) {
21 | return Column(
22 | children: [
23 | const Spacer(),
24 | _buildTitle(context),
25 | SizedBox(
26 | height: AppDimensions.padding.defaultValue,
27 | ),
28 | _buildDescription(context),
29 | const Spacer(),
30 | SvgPicture.asset(imageAsset),
31 | ],
32 | );
33 | }
34 |
35 | Widget _buildTitle(BuildContext context) {
36 | return Text(
37 | title,
38 | style: Theme.of(context).textTheme.headline2,
39 | textAlign: TextAlign.center,
40 | );
41 | }
42 |
43 | Widget _buildDescription(BuildContext context) {
44 | return Text(
45 | description,
46 | style: Theme.of(context).textTheme.bodyText2?.copyWith(
47 | color: AppColors.gray200,
48 | ),
49 | textAlign: TextAlign.center,
50 | );
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/lib/ui/pages/portfolio/widgets/portfolio_my_watchlist_section.dart:
--------------------------------------------------------------------------------
1 | part of '../portfolio_page.dart';
2 |
3 | class _PortfolioMyWatchlistSection extends StatelessWidget {
4 | final List? companyAssets;
5 | final void Function(CompanyAssetModel) onCompanyPressed;
6 | final VoidCallback onMorePressed;
7 |
8 | const _PortfolioMyWatchlistSection({
9 | required this.companyAssets,
10 | required this.onCompanyPressed,
11 | required this.onMorePressed,
12 | });
13 |
14 | @override
15 | Widget build(BuildContext context) {
16 | return Column(
17 | children: [
18 | SectionHeader(
19 | title: AppLoc.of(context).portfolioMyWatchlistSectionTitle,
20 | onMorePressed: onMorePressed,
21 | ),
22 | if (companyAssets?.isNotEmpty ?? false)
23 | Container(
24 | clipBehavior: Clip.antiAlias,
25 | decoration: AppDecorations.defaultBorder(),
26 | child: _buildCompanyAssetsList(),
27 | ),
28 | ],
29 | );
30 | }
31 |
32 | Widget _buildCompanyAssetsList() {
33 | return ListView.separated(
34 | itemBuilder: (context, index) {
35 | final CompanyAssetModel companyAsset = companyAssets![index];
36 | return PortfolioMyWatchlistCell(
37 | companyAsset: companyAsset,
38 | onPressed: onCompanyPressed,
39 | );
40 | },
41 | itemCount: companyAssets!.length,
42 | physics: const NeverScrollableScrollPhysics(),
43 | separatorBuilder: (_, __) => const Divider(),
44 | shrinkWrap: true,
45 | );
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/lib/ui/pages/profile/widgets/profile_action_button.dart:
--------------------------------------------------------------------------------
1 | part of '../profile_page.dart';
2 |
3 | class _ProfileActionButton extends StatelessWidget {
4 | final String title;
5 | final VoidCallback onPressed;
6 |
7 | const _ProfileActionButton({
8 | required this.title,
9 | required this.onPressed,
10 | });
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | return AdaptiveButton(
15 | padding: EdgeInsets.symmetric(
16 | horizontal: AppDimensions.padding.defaultValue,
17 | vertical: 18.0,
18 | ),
19 | onPressed: onPressed,
20 | child: _buildContent(
21 | context,
22 | ),
23 | );
24 | }
25 |
26 | Widget _buildContent(BuildContext context) {
27 | return Row(
28 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
29 | children: [
30 | _buildTitle(context),
31 | const Icon(
32 | Icons.arrow_forward_ios,
33 | color: AppColors.navy,
34 | size: 12.0,
35 | ),
36 | ],
37 | );
38 | }
39 |
40 | Widget _buildTitle(BuildContext context) {
41 | return Text(
42 | title,
43 | style: Theme.of(context).textTheme.headline6,
44 | );
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/lib/ui/pages/profile/widgets/profile_app_bar.dart:
--------------------------------------------------------------------------------
1 | part of '../profile_page.dart';
2 |
3 | class _ProfileAppBar extends AdaptiveAppBar {
4 | _ProfileAppBar(
5 | super.context, {
6 | required VoidCallback onLogoutPressed,
7 | }) : super(
8 | actions: [
9 | _buildLogoutButton(
10 | context,
11 | onPressed: onLogoutPressed,
12 | )
13 | ],
14 | centerTitle: false,
15 | title: Text(
16 | AppLoc.of(context).profilePageTitle,
17 | ),
18 | );
19 |
20 | static Widget _buildLogoutButton(
21 | BuildContext context, {
22 | required VoidCallback onPressed,
23 | }) {
24 | return AdaptiveButton(
25 | onPressed: onPressed,
26 | child: Text(
27 | AppLoc.of(context).profilePageLogoutButton,
28 | style: Theme.of(context).textTheme.headline6?.copyWith(
29 | color: AppColors.primary100,
30 | ),
31 | ),
32 | );
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/lib/ui/pages/profile/widgets/profile_header.dart:
--------------------------------------------------------------------------------
1 | part of '../profile_page.dart';
2 |
3 | class _ProfileHeader extends StatelessWidget {
4 | final UserModel? user;
5 |
6 | const _ProfileHeader({
7 | required this.user,
8 | });
9 |
10 | @override
11 | Widget build(BuildContext context) {
12 | return Column(
13 | children: [
14 | if (user != null) ...[
15 | _buildAvatar(
16 | avatar: user!.avatar,
17 | ),
18 | const SizedBox(
19 | height: 12.0,
20 | ),
21 | _buildFullName(
22 | context,
23 | fullName: user!.fullName,
24 | ),
25 | _buildEmail(
26 | context,
27 | email: user!.email,
28 | ),
29 | ]
30 | ],
31 | );
32 | }
33 |
34 | Widget _buildAvatar({
35 | required String avatar,
36 | }) {
37 | return CircleAvatar(
38 | backgroundColor: AppColors.white,
39 | backgroundImage: AssetImage(avatar),
40 | radius: 40.0,
41 | );
42 | }
43 |
44 | Widget _buildFullName(
45 | BuildContext context, {
46 | required String fullName,
47 | }) {
48 | return Text(
49 | fullName,
50 | style: Theme.of(context).textTheme.headline5,
51 | textAlign: TextAlign.center,
52 | );
53 | }
54 |
55 | Widget _buildEmail(
56 | BuildContext context, {
57 | required String email,
58 | }) {
59 | return Text(
60 | email,
61 | style: Theme.of(context).textTheme.bodyText2?.copyWith(
62 | color: AppColors.navy.withOpacity(0.5),
63 | ),
64 | textAlign: TextAlign.center,
65 | );
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/lib/ui/widgets/animated_progress_bar.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:vizier/config/constants/app_constants.dart';
3 | import 'package:vizier/ui/widgets/progress_bar.dart';
4 |
5 | class AnimatedProgressBar extends StatefulWidget {
6 | // Value between 0 and 100
7 | final int currentProgress;
8 | final Duration? duration;
9 | final String? summary;
10 |
11 | const AnimatedProgressBar({
12 | required this.currentProgress,
13 | this.duration,
14 | this.summary,
15 | super.key,
16 | });
17 |
18 | @override
19 | State createState() => _AnimatedProgressBarState();
20 | }
21 |
22 | class _AnimatedProgressBarState extends State
23 | with TickerProviderStateMixin {
24 | late final AnimationController animationController = AnimationController(
25 | duration: widget.duration ?? AppConstants.animation.defaultDuration,
26 | vsync: this,
27 | );
28 | late final Animation animation;
29 |
30 | @override
31 | void initState() {
32 | super.initState();
33 | animation = IntTween(
34 | begin: 0,
35 | end: widget.currentProgress,
36 | ).animate(animationController);
37 | animationController.forward();
38 | }
39 |
40 | @override
41 | void dispose() {
42 | animationController.dispose();
43 | super.dispose();
44 | }
45 |
46 | @override
47 | Widget build(BuildContext context) {
48 | return AnimatedBuilder(
49 | animation: animation,
50 | builder: (_, __) => ProgressBar(
51 | currentProgress: animation.value,
52 | summary: widget.summary,
53 | ),
54 | );
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/lib/ui/widgets/arrow_change_value.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:vizier/config/styles/colors/app_colors.dart';
3 | import 'package:vizier/config/styles/text_styles/app_text_styles.dart';
4 |
5 | class ArrowChangeValue extends StatelessWidget {
6 | final String change;
7 | final bool isNegative;
8 | final Color? changeColor;
9 | final TextStyle? changeStyle;
10 | final bool arrowOnRightSide;
11 |
12 | const ArrowChangeValue({
13 | required this.change,
14 | required this.isNegative,
15 | this.changeColor,
16 | this.changeStyle,
17 | this.arrowOnRightSide = false,
18 | super.key,
19 | });
20 |
21 | @override
22 | Widget build(BuildContext context) {
23 | return Row(
24 | children: [
25 | if (!arrowOnRightSide) _buildIcon(context),
26 | _buildTitle(context),
27 | if (arrowOnRightSide) _buildIcon(context),
28 | ],
29 | );
30 | }
31 |
32 | Widget _buildIcon(BuildContext context) {
33 | return Icon(
34 | isNegative ? Icons.arrow_drop_down : Icons.arrow_drop_up,
35 | color: changeColor ?? AppColors.white,
36 | size: 20.0,
37 | );
38 | }
39 |
40 | Widget _buildTitle(BuildContext context) {
41 | return Text(
42 | change,
43 | style: (changeStyle ?? AppTextStyles.caption1Bold()).copyWith(
44 | color: changeColor ?? AppColors.white,
45 | ),
46 | );
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/lib/ui/widgets/credit_card/animated_credit_card.dart:
--------------------------------------------------------------------------------
1 | import 'dart:ui';
2 |
3 | import 'package:flutter/material.dart';
4 | import 'package:flutter_svg/flutter_svg.dart';
5 | import 'package:vizier/config/styles/colors/app_colors.dart';
6 | import 'package:vizier/config/styles/dimensions/app_dimensions.dart';
7 | import 'package:vizier/config/styles/images/app_images.dart';
8 | import 'package:vizier/config/styles/text_styles/app_text_styles.dart';
9 | import 'package:vizier/extensions/extensions.dart';
10 | import 'package:vizier/l10n/app_loc.dart';
11 | import 'package:vizier/ui/models/card_account_type.dart';
12 | import 'package:vizier/ui/widgets/animated_flip.dart';
13 | import 'package:vizier/ui/widgets/animated_text.dart';
14 |
15 | part 'credit_card_back.dart';
16 | part 'credit_card_container.dart';
17 | part 'credit_card_cvv.dart';
18 | part 'credit_card_expiry.dart';
19 | part 'credit_card_front.dart';
20 | part 'credit_card_number.dart';
21 |
22 | class AnimatedCreditCard extends StatelessWidget {
23 | final String balance;
24 | final String cvv;
25 | final String expiry;
26 | final String logo;
27 | final String number;
28 | final CardAccountType type;
29 |
30 | const AnimatedCreditCard({
31 | required this.expiry,
32 | required this.number,
33 | required this.type,
34 | this.balance = '',
35 | this.cvv = '',
36 | this.logo = '',
37 | super.key,
38 | });
39 |
40 | @override
41 | Widget build(BuildContext context) {
42 | return AnimatedFlip(
43 | back: _CreditCardBack(
44 | cvv: cvv,
45 | ),
46 | front: _CreditCardFront(
47 | balance: balance,
48 | expiry: expiry,
49 | logo: logo,
50 | number: number,
51 | ),
52 | isFront: type == CardAccountType.front,
53 | );
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/lib/ui/widgets/credit_card/credit_card_back.dart:
--------------------------------------------------------------------------------
1 | part of 'animated_credit_card.dart';
2 |
3 | class _CreditCardBack extends StatelessWidget {
4 | final String cvv;
5 |
6 | const _CreditCardBack({
7 | required this.cvv,
8 | });
9 |
10 | @override
11 | Widget build(BuildContext context) {
12 | return _CreditCardContainer(
13 | child: Column(
14 | crossAxisAlignment: CrossAxisAlignment.stretch,
15 | children: [
16 | Expanded(
17 | child: _buildTop(),
18 | ),
19 | _buildCvv(),
20 | const Spacer(),
21 | ],
22 | ),
23 | );
24 | }
25 |
26 | Widget _buildTop() {
27 | return Column(
28 | children: [
29 | const Spacer(),
30 | Container(
31 | color: AppColors.black,
32 | height: 40.0,
33 | ),
34 | const Spacer(),
35 | ],
36 | );
37 | }
38 |
39 | Widget _buildCvv() {
40 | return Padding(
41 | padding: AppDimensions.padding.defaultHorizontal(),
42 | child: Row(
43 | children: [
44 | Expanded(
45 | child: Container(
46 | color: AppColors.white,
47 | height: 40.0,
48 | ),
49 | ),
50 | const SizedBox(
51 | width: 28.0,
52 | ),
53 | _CreditCardCvv(
54 | cvv: cvv,
55 | ),
56 | ],
57 | ),
58 | );
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/lib/ui/widgets/credit_card/credit_card_container.dart:
--------------------------------------------------------------------------------
1 | part of 'animated_credit_card.dart';
2 |
3 | class _CreditCardContainer extends StatelessWidget {
4 | final Widget child;
5 |
6 | const _CreditCardContainer({
7 | required this.child,
8 | });
9 |
10 | @override
11 | Widget build(BuildContext context) {
12 | return AspectRatio(
13 | aspectRatio: 1.75,
14 | child: DecoratedBox(
15 | decoration: const BoxDecoration(
16 | borderRadius: BorderRadius.all(Radius.circular(12.0)),
17 | color: AppColors.primary100,
18 | ),
19 | child: child,
20 | ),
21 | );
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/lib/ui/widgets/credit_card/credit_card_cvv.dart:
--------------------------------------------------------------------------------
1 | part of 'animated_credit_card.dart';
2 |
3 | class _CreditCardCvv extends StatelessWidget {
4 | final String cvv;
5 |
6 | const _CreditCardCvv({
7 | required this.cvv,
8 | });
9 |
10 | @override
11 | Widget build(BuildContext context) {
12 | final String mask = cvv.mask('***');
13 | return Row(
14 | children: List.generate(
15 | mask.length,
16 | (index) => _buildLetter(mask[index]),
17 | ),
18 | );
19 | }
20 |
21 | Widget _buildLetter(String text) {
22 | return SizedBox(
23 | width: 16.0,
24 | child: AnimatedText(
25 | text: text,
26 | style: AppTextStyles.caption1Bold().copyWith(
27 | color: AppColors.white,
28 | ),
29 | ),
30 | );
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/lib/ui/widgets/credit_card/credit_card_expiry.dart:
--------------------------------------------------------------------------------
1 | part of 'animated_credit_card.dart';
2 |
3 | class _CreditCardExpiry extends StatelessWidget {
4 | final String expiry;
5 |
6 | const _CreditCardExpiry({
7 | required this.expiry,
8 | });
9 |
10 | @override
11 | Widget build(BuildContext context) {
12 | final String mask = expiry.mask('**/**');
13 | return Row(
14 | children: List.generate(
15 | mask.length,
16 | (index) => _buildLetter(mask[index]),
17 | ),
18 | );
19 | }
20 |
21 | Widget _buildLetter(String text) {
22 | return SizedBox(
23 | width: 10.0,
24 | child: AnimatedText(
25 | text: text,
26 | style: AppTextStyles.caption2().copyWith(
27 | color: AppColors.white,
28 | ),
29 | ),
30 | );
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/lib/ui/widgets/credit_card/credit_card_number.dart:
--------------------------------------------------------------------------------
1 | part of 'animated_credit_card.dart';
2 |
3 | class _CreditCardNumber extends StatelessWidget {
4 | final String number;
5 |
6 | const _CreditCardNumber({
7 | required this.number,
8 | });
9 |
10 | @override
11 | Widget build(BuildContext context) {
12 | final String mask = number.mask('**** **** **** ****');
13 | return Row(
14 | children: List.generate(
15 | mask.length,
16 | (index) => Expanded(
17 | child: FittedBox(
18 | child: _buildLetter(mask[index]),
19 | ),
20 | ),
21 | ),
22 | );
23 | }
24 |
25 | Widget _buildLetter(String text) {
26 | return AnimatedText(
27 | text: text,
28 | style: AppTextStyles.h3().copyWith(
29 | color: AppColors.white,
30 | fontWeight: FontWeight.w500,
31 | fontFeatures: [
32 | const FontFeature.tabularFigures(),
33 | ],
34 | shadows: [
35 | Shadow(
36 | color: AppColors.black.withOpacity(0.2),
37 | offset: const Offset(0.0, 2.0),
38 | ),
39 | ],
40 | ),
41 | );
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/lib/ui/widgets/legend/models/legend.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | part 'legend_item.dart';
4 | part 'legend_settings.dart';
5 |
6 | class Legend {
7 | final List items;
8 | final LegendSettings settings;
9 |
10 | const Legend({
11 | required this.items,
12 | required this.settings,
13 | });
14 | }
15 |
--------------------------------------------------------------------------------
/lib/ui/widgets/legend/models/legend_item.dart:
--------------------------------------------------------------------------------
1 | part of 'legend.dart';
2 |
3 | class LegendItem {
4 | final Color color;
5 | final String label;
6 |
7 | const LegendItem({
8 | required this.color,
9 | required this.label,
10 | });
11 | }
12 |
--------------------------------------------------------------------------------
/lib/ui/widgets/legend/models/legend_settings.dart:
--------------------------------------------------------------------------------
1 | part of 'legend.dart';
2 |
3 | class LegendSettings {
4 | final EdgeInsets padding;
5 | final double paddingBetweenItems;
6 | final TextStyle textStyle;
7 | final double sizeIcon;
8 |
9 | const LegendSettings({
10 | required this.padding,
11 | required this.paddingBetweenItems,
12 | required this.sizeIcon,
13 | required this.textStyle,
14 | });
15 |
16 | const LegendSettings.fromTextStyle(this.textStyle)
17 | : padding = EdgeInsets.zero,
18 | paddingBetweenItems = 8.0,
19 | sizeIcon = 8.0;
20 | }
21 |
--------------------------------------------------------------------------------
/lib/ui/widgets/performance_percentage_box.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:vizier/config/styles/colors/app_colors.dart';
3 | import 'package:vizier/ui/widgets/arrow_change_value.dart';
4 | import 'package:vizier/utils/percentage_formatter_util.dart';
5 |
6 | class PerformancePercentageBox extends StatelessWidget {
7 | final double value;
8 |
9 | const PerformancePercentageBox({
10 | required this.value,
11 | super.key,
12 | });
13 |
14 | @override
15 | Widget build(BuildContext context) {
16 | return Container(
17 | decoration: BoxDecoration(
18 | borderRadius: BorderRadius.circular(4.0),
19 | color: value.isNegative ? AppColors.error100 : AppColors.success100,
20 | ),
21 | padding: const EdgeInsets.all(4.0),
22 | child: ArrowChangeValue(
23 | change: PercentageFormatterUtil.instance.format(
24 | value: value,
25 | ),
26 | isNegative: value.isNegative,
27 | ),
28 | );
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/lib/ui/widgets/ripple_remover.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:flutter/material.dart';
4 |
5 | class RippleRemover extends StatelessWidget {
6 | final Widget child;
7 | final bool isActive;
8 |
9 | RippleRemover({
10 | required this.child,
11 | }) : isActive = Platform.isIOS;
12 |
13 | @override
14 | Widget build(BuildContext context) {
15 | if (isActive) {
16 | return Theme(
17 | data: Theme.of(context).copyWith(
18 | highlightColor: Colors.transparent,
19 | splashColor: Colors.transparent,
20 | ),
21 | child: child,
22 | );
23 | } else {
24 | return child;
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/lib/ui/widgets/section_header.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:vizier/config/styles/colors/app_colors.dart';
3 | import 'package:vizier/config/styles/dimensions/app_dimensions.dart';
4 | import 'package:vizier/ui/widgets/adaptive/adaptive_button.dart';
5 |
6 | class SectionHeader extends StatelessWidget {
7 | final String title;
8 | final VoidCallback? onMorePressed;
9 |
10 | const SectionHeader({
11 | required this.title,
12 | this.onMorePressed,
13 | super.key,
14 | });
15 |
16 | @override
17 | Widget build(BuildContext context) {
18 | return Row(
19 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
20 | children: [
21 | _buildTitle(context),
22 | if (onMorePressed != null) _buildMoreButton(context),
23 | ],
24 | );
25 | }
26 |
27 | Widget _buildTitle(BuildContext context) {
28 | return Text(
29 | title,
30 | style: Theme.of(context).textTheme.headline6,
31 | );
32 | }
33 |
34 | Widget _buildMoreButton(BuildContext context) {
35 | return Transform.translate(
36 | offset: Offset(AppDimensions.padding.defaultValue, 0.0),
37 | child: AdaptiveButton(
38 | decoration: const BoxDecoration(
39 | shape: BoxShape.circle,
40 | ),
41 | padding: EdgeInsets.all(
42 | AppDimensions.padding.defaultValue,
43 | ),
44 | onPressed: onMorePressed,
45 | child: const Icon(
46 | Icons.more_horiz,
47 | color: AppColors.black,
48 | ),
49 | ),
50 | );
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/lib/ui/widgets/unfocus_keyboard_outside.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class UnfocusKeyboardOutside extends StatelessWidget {
4 | final Widget child;
5 |
6 | const UnfocusKeyboardOutside({
7 | required this.child,
8 | super.key,
9 | });
10 |
11 | @override
12 | Widget build(BuildContext context) {
13 | return GestureDetector(
14 | onTap: () => FocusScope.of(context).unfocus(),
15 | child: child,
16 | );
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/lib/utils/adaptive_widget_util.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | enum Platform { material, cupertino, adaptive }
4 | enum AdaptiveWidgetType { material, cupertino }
5 |
6 | class AdaptiveWidgetUtil {
7 | const AdaptiveWidgetUtil._();
8 |
9 | static AdaptiveWidgetType getWidgetTypeOf(
10 | BuildContext context, {
11 | required Platform platform,
12 | }) {
13 | switch (platform) {
14 | case Platform.adaptive:
15 | final ThemeData theme = Theme.of(context);
16 | switch (theme.platform) {
17 | case TargetPlatform.iOS:
18 | return AdaptiveWidgetType.cupertino;
19 | case TargetPlatform.android:
20 | case TargetPlatform.fuchsia:
21 | default:
22 | return AdaptiveWidgetType.material;
23 | }
24 | case Platform.cupertino:
25 | return AdaptiveWidgetType.cupertino;
26 | case Platform.material:
27 | default:
28 | return AdaptiveWidgetType.material;
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/lib/utils/currency_formatter_util.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:injectable/injectable.dart';
3 | import 'package:intl/intl.dart';
4 | import 'package:vizier/config/injector/di.dart';
5 | import 'package:vizier/config/styles/colors/app_colors.dart';
6 |
7 | @singleton
8 | class CurrencyFormatterUtil {
9 | static CurrencyFormatterUtil get instance => DI.resolve();
10 |
11 | final NumberFormat numberFormat = NumberFormat.currency(
12 | symbol: '€',
13 | );
14 |
15 | String format({
16 | required double value,
17 | }) {
18 | return numberFormat.format(value);
19 | }
20 |
21 | String formatWithChangePrefix({
22 | required double value,
23 | }) {
24 | if (value.isNegative) {
25 | return format(
26 | value: value,
27 | );
28 | }
29 | return '+ ${format(value: value)}';
30 | }
31 |
32 | Color changeColor({
33 | required double value,
34 | }) {
35 | return value.isNegative ? AppColors.error300 : AppColors.success100;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/lib/utils/dummy_util.dart:
--------------------------------------------------------------------------------
1 | import 'dart:math';
2 |
3 | import 'package:injectable/injectable.dart';
4 |
5 | @injectable
6 | class DummyUtil {
7 | final Random _random = Random();
8 |
9 | static const String _chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz1234567890';
10 |
11 | int randomInt({
12 | int minNumber = 0,
13 | int maxNumber = 10,
14 | }) =>
15 | _random.nextInt(maxNumber - minNumber) + minNumber;
16 |
17 | double randomDouble({
18 | int minNumber = 0,
19 | int maxNumber = 10,
20 | }) =>
21 | randomInt(minNumber: minNumber, maxNumber: maxNumber) + _random.nextDouble();
22 |
23 | String randomString({
24 | int length = 64,
25 | }) =>
26 | String.fromCharCodes(
27 | Iterable.generate(
28 | length,
29 | (_) => _chars.codeUnitAt(
30 | _random.nextInt(_chars.length),
31 | ),
32 | ),
33 | );
34 |
35 | bool randomBool() => _random.nextBool();
36 | }
37 |
--------------------------------------------------------------------------------
/lib/utils/percentage_formatter_util.dart:
--------------------------------------------------------------------------------
1 | import 'package:injectable/injectable.dart';
2 | import 'package:intl/intl.dart';
3 | import 'package:vizier/config/injector/di.dart';
4 |
5 | @singleton
6 | class PercentageFormatterUtil {
7 | static PercentageFormatterUtil get instance => DI.resolve();
8 |
9 | final NumberFormat numberFormat = NumberFormat.decimalPercentPattern(
10 | decimalDigits: 2,
11 | );
12 |
13 | String format({
14 | required double value,
15 | int decimalDigits = 2,
16 | }) {
17 | if (decimalDigits != 2) {
18 | return NumberFormat.decimalPercentPattern(
19 | decimalDigits: decimalDigits,
20 | ).format(value / 100.0);
21 | }
22 | return numberFormat.format(value.abs() / 100.0);
23 | }
24 |
25 | String formatWithChangePrefix({
26 | required double value,
27 | }) {
28 | if (value.isNegative) {
29 | return format(
30 | value: value,
31 | );
32 | }
33 | return '+ ${format(value: value)}';
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/lib/utils/validation/validators_util.dart:
--------------------------------------------------------------------------------
1 | // ignore: avoid_classes_with_only_static_members
2 | abstract class ValidatorsUtil {
3 | static final RegExp _emailRegExp = RegExp(
4 | r'^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$',
5 | );
6 |
7 | static bool isValidEmail(String? email) {
8 | return email != null && _emailRegExp.hasMatch(email);
9 | }
10 |
11 | static bool isNotEmpty(String text) {
12 | return text.isNotEmpty;
13 | }
14 |
15 | static bool isNotBlank(String? text) {
16 | if (text != null) {
17 | return isNotEmpty(text.trim());
18 | } else {
19 | return false;
20 | }
21 | }
22 |
23 | static bool isNotLongerThan(String text, int maxCharacters) {
24 | return text.length <= maxCharacters;
25 | }
26 |
27 | static bool isNotLessThan(String text, int minCharacters) {
28 | return text.length >= minCharacters;
29 | }
30 |
31 | static bool isGreaterThan(String text, int number) {
32 | final int? intValue = int.tryParse(text);
33 | if (intValue != null) {
34 | return intValue > number;
35 | }
36 | return true;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: vizier
2 | description: A new Flutter project.
3 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev
4 | version: 1.0.0+1
5 |
6 | environment:
7 | sdk: ">=2.17.0 <3.0.0"
8 |
9 | dependencies:
10 | flutter:
11 | sdk: flutter
12 | #Localizations
13 | flutter_localizations:
14 | sdk: flutter
15 | intl: ^0.17.0
16 | #Bloc
17 | bloc: ^8.1.0
18 | flutter_bloc: ^8.1.1
19 | #Code generation
20 | freezed_annotation: ^2.1.0
21 | json_annotation: ^4.6.0
22 | #Dependency Injection
23 | injectable: ^1.5.3
24 | get_it: ^7.2.0
25 | #Storages
26 | flutter_secure_storage: ^6.0.0
27 | shared_preferences: ^2.0.15
28 | #Routing
29 | auto_route: ^5.0.1
30 | #UI
31 | flutter_svg: ^1.1.4
32 | mrx_charts: ^0.1.3
33 |
34 | dev_dependencies:
35 | auto_route_generator: ^5.0.2
36 | build_runner: ^2.2.0
37 | flutter_lints: ^2.0.1
38 | freezed: ^2.1.0+1
39 | injectable_generator: ^1.5.4
40 | json_serializable: ^6.3.1
41 | lint: ^1.10.0
42 |
43 | flutter:
44 | uses-material-design: true
45 | generate: true
46 | assets:
47 | - assets/svgs/
48 | - assets/mocks/finances/
49 | - assets/mocks/user/
50 | - assets/mocks/portfolio/
51 | - assets/mocks/transactions/
52 | fonts:
53 | - family: Ubuntu
54 | fonts:
55 | - asset: assets/fonts/ubuntu/Ubuntu-Light.ttf
56 | weight: 300
57 | - asset: assets/fonts/ubuntu/Ubuntu-Regular.ttf
58 | weight: 400
59 | - asset: assets/fonts/ubuntu/Ubuntu-Medium.ttf
60 | weight: 500
61 | - asset: assets/fonts/ubuntu/Ubuntu-Bold.ttf
62 | weight: 700
63 |
--------------------------------------------------------------------------------