├── .github
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bug_report.yaml
│ └── feature_request.yaml
└── workflows
│ ├── build-fat-apk-android-beta.yaml
│ ├── deploy-android-build.yaml
│ ├── deploy-ios-builds.yaml
│ └── test.yaml
├── .gitignore
├── .idx
└── dev.nix
├── .markdownlint.json
├── .metadata
├── .prettierrc
├── .vscode
├── extensions.json
├── launch.json
└── settings.json
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── RELEASE_TEMPLATE.md
├── analysis_options.yaml
├── android
├── .gitignore
├── app
│ ├── .gitignore
│ ├── build.gradle
│ └── src
│ │ ├── debug
│ │ └── AndroidManifest.xml
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── kotlin
│ │ │ └── mn
│ │ │ │ └── flow
│ │ │ │ └── flow
│ │ │ │ └── MainActivity.kt
│ │ └── res
│ │ │ ├── drawable-hdpi
│ │ │ ├── ic_launcher_background.png
│ │ │ ├── ic_launcher_foreground.png
│ │ │ ├── monochrome.png
│ │ │ └── notification_default.png
│ │ │ ├── drawable-mdpi
│ │ │ ├── ic_launcher_background.png
│ │ │ ├── ic_launcher_foreground.png
│ │ │ ├── monochrome.png
│ │ │ └── notification_default.png
│ │ │ ├── drawable-v21
│ │ │ └── launch_background.xml
│ │ │ ├── drawable-xhdpi
│ │ │ ├── ic_launcher_background.png
│ │ │ ├── ic_launcher_foreground.png
│ │ │ ├── monochrome.png
│ │ │ └── notification_default.png
│ │ │ ├── drawable-xxhdpi
│ │ │ ├── ic_launcher_background.png
│ │ │ ├── ic_launcher_foreground.png
│ │ │ ├── monochrome.png
│ │ │ └── notification_default.png
│ │ │ ├── drawable-xxxhdpi
│ │ │ ├── ic_launcher_background.png
│ │ │ ├── ic_launcher_foreground.png
│ │ │ ├── monochrome.png
│ │ │ └── notification_default.png
│ │ │ ├── drawable
│ │ │ ├── launch_background.xml
│ │ │ └── notification_default.png
│ │ │ ├── mipmap-anydpi-v26
│ │ │ └── ic_launcher.xml
│ │ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── raw
│ │ │ └── keep.xml
│ │ │ ├── values-night
│ │ │ └── styles.xml
│ │ │ └── values
│ │ │ └── styles.xml
│ │ └── profile
│ │ └── AndroidManifest.xml
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
├── proguard-rules.pro
└── settings.gradle
├── assets
├── fonts
│ ├── NotoEmoji-Regular.ttf
│ ├── NotoSans-Regular.ttf
│ ├── NotoSansArabic-Regular.ttf
│ ├── NotoSansHebrew-Regular.ttf
│ ├── OFL.txt
│ ├── Poppins-Bold.ttf
│ ├── Poppins-Italic.ttf
│ ├── Poppins-Medium.ttf
│ ├── Poppins-Regular.ttf
│ └── Poppins-SemiBold.ttf
├── images
│ ├── 2.0x
│ │ ├── flow.png
│ │ ├── map_square.png
│ │ └── pin.png
│ ├── 3.0x
│ │ ├── flow.png
│ │ └── pin.png
│ ├── 4.0x
│ │ └── flow.png
│ ├── external
│ │ └── ivy_wallet.png
│ ├── flow.png
│ ├── map_square.png
│ ├── missing.png
│ ├── missing.svg
│ ├── pin.png
│ └── pin.svg
└── l10n
│ ├── ar.json
│ ├── de_DE.json
│ ├── en.json
│ ├── es_ES.json
│ ├── fr_FR.json
│ ├── it_IT.json
│ ├── mn_MN.json
│ ├── ru_RU.json
│ └── tr_TR.json
├── devtools_options.yaml
├── ios
├── .gitignore
├── Flutter
│ ├── AppFrameworkInfo.plist
│ ├── Debug.xcconfig
│ └── Release.xcconfig
├── Podfile
├── Podfile.lock
├── Runner.xcodeproj
│ ├── project.pbxproj
│ ├── project.pbxproj.tmp
│ ├── 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-1024x1024@1x.png
│ │ │ ├── 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-50x50@1x.png
│ │ │ ├── Icon-App-50x50@2x.png
│ │ │ ├── Icon-App-57x57@1x.png
│ │ │ ├── Icon-App-57x57@2x.png
│ │ │ ├── Icon-App-60x60@2x.png
│ │ │ ├── Icon-App-60x60@3x.png
│ │ │ ├── Icon-App-72x72@1x.png
│ │ │ ├── Icon-App-72x72@2x.png
│ │ │ ├── Icon-App-76x76@1x.png
│ │ │ ├── Icon-App-76x76@2x.png
│ │ │ └── Icon-App-83.5x83.5@2x.png
│ │ └── LaunchImage.imageset
│ │ │ ├── Contents.json
│ │ │ ├── LaunchImage.png
│ │ │ ├── LaunchImage@2x.png
│ │ │ ├── LaunchImage@3x.png
│ │ │ └── README.md
│ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ ├── Info.plist
│ ├── LauncherIcons
│ │ ├── blissfulBerry-ipad-pro@2x.png
│ │ ├── blissfulBerry-ipad@2x.png
│ │ ├── blissfulBerry@2x.png
│ │ ├── blissfulBerry@3x.png
│ │ ├── bohemianBlue-ipad-pro@2x.png
│ │ ├── bohemianBlue-ipad@2x.png
│ │ ├── bohemianBlue@2x.png
│ │ ├── bohemianBlue@3x.png
│ │ ├── burntSienna-ipad-pro@2x.png
│ │ ├── burntSienna-ipad@2x.png
│ │ ├── burntSienna@2x.png
│ │ ├── burntSienna@3x.png
│ │ ├── cherryPlum-ipad-pro@2x.png
│ │ ├── cherryPlum-ipad@2x.png
│ │ ├── cherryPlum@2x.png
│ │ ├── cherryPlum@3x.png
│ │ ├── crispChristmasCranberries-ipad-pro@2x.png
│ │ ├── crispChristmasCranberries-ipad@2x.png
│ │ ├── crispChristmasCranberries@2x.png
│ │ ├── crispChristmasCranberries@3x.png
│ │ ├── egyptianBlue-ipad-pro@2x.png
│ │ ├── egyptianBlue-ipad@2x.png
│ │ ├── egyptianBlue@2x.png
│ │ ├── egyptianBlue@3x.png
│ │ ├── flagGreen-ipad-pro@2x.png
│ │ ├── flagGreen-ipad@2x.png
│ │ ├── flagGreen@2x.png
│ │ ├── flagGreen@3x.png
│ │ ├── hydraTurquoise-ipad-pro@2x.png
│ │ ├── hydraTurquoise-ipad@2x.png
│ │ ├── hydraTurquoise@2x.png
│ │ ├── hydraTurquoise@3x.png
│ │ ├── peacockBlue-ipad-pro@2x.png
│ │ ├── peacockBlue-ipad@2x.png
│ │ ├── peacockBlue@2x.png
│ │ ├── peacockBlue@3x.png
│ │ ├── shadeOfViolet-ipad-pro@2x.png
│ │ ├── shadeOfViolet-ipad@2x.png
│ │ ├── shadeOfViolet@2x.png
│ │ ├── shadeOfViolet@3x.png
│ │ ├── soilOfAvagddu-ipad-pro@2x.png
│ │ ├── soilOfAvagddu-ipad@2x.png
│ │ ├── soilOfAvagddu@2x.png
│ │ ├── soilOfAvagddu@3x.png
│ │ ├── spaceBattleBlue-ipad-pro@2x.png
│ │ ├── spaceBattleBlue-ipad@2x.png
│ │ ├── spaceBattleBlue@2x.png
│ │ ├── spaceBattleBlue@3x.png
│ │ ├── spreadsheetGreen-ipad-pro@2x.png
│ │ ├── spreadsheetGreen-ipad@2x.png
│ │ ├── spreadsheetGreen@2x.png
│ │ ├── spreadsheetGreen@3x.png
│ │ ├── tokiwaGreen-ipad-pro@2x.png
│ │ ├── tokiwaGreen-ipad@2x.png
│ │ ├── tokiwaGreen@2x.png
│ │ ├── tokiwaGreen@3x.png
│ │ ├── toyCamouflage-ipad-pro@2x.png
│ │ ├── toyCamouflage-ipad@2x.png
│ │ ├── toyCamouflage@2x.png
│ │ ├── toyCamouflage@3x.png
│ │ ├── tropicana-ipad-pro@2x.png
│ │ ├── tropicana-ipad@2x.png
│ │ ├── tropicana@2x.png
│ │ └── tropicana@3x.png
│ ├── Runner-Bridging-Header.h
│ └── Runner.entitlements
└── RunnerTests
│ └── RunnerTests.swift
├── launcher_icons
├── adaptive_background.png
├── adaptive_foreground.png
├── defaults-light
│ ├── blissfulBerry-ipad-pro@2x.png
│ ├── blissfulBerry-ipad@2x.png
│ ├── blissfulBerry@2x.png
│ ├── blissfulBerry@3x.png
│ ├── bohemianBlue-ipad-pro@2x.png
│ ├── bohemianBlue-ipad@2x.png
│ ├── bohemianBlue@2x.png
│ ├── bohemianBlue@3x.png
│ ├── burntSienna-ipad-pro@2x.png
│ ├── burntSienna-ipad@2x.png
│ ├── burntSienna@2x.png
│ ├── burntSienna@3x.png
│ ├── cherryPlum-ipad-pro@2x.png
│ ├── cherryPlum-ipad@2x.png
│ ├── cherryPlum@2x.png
│ ├── cherryPlum@3x.png
│ ├── crispChristmasCranberries-ipad-pro@2x.png
│ ├── crispChristmasCranberries-ipad@2x.png
│ ├── crispChristmasCranberries@2x.png
│ ├── crispChristmasCranberries@3x.png
│ ├── egyptianBlue-ipad-pro@2x.png
│ ├── egyptianBlue-ipad@2x.png
│ ├── egyptianBlue@2x.png
│ ├── egyptianBlue@3x.png
│ ├── flagGreen-ipad-pro@2x.png
│ ├── flagGreen-ipad@2x.png
│ ├── flagGreen@2x.png
│ ├── flagGreen@3x.png
│ ├── hydraTurquoise-ipad-pro@2x.png
│ ├── hydraTurquoise-ipad@2x.png
│ ├── hydraTurquoise@2x.png
│ ├── hydraTurquoise@3x.png
│ ├── peacockBlue-ipad-pro@2x.png
│ ├── peacockBlue-ipad@2x.png
│ ├── peacockBlue@2x.png
│ ├── peacockBlue@3x.png
│ ├── shadeOfViolet-ipad-pro@2x.png
│ ├── shadeOfViolet-ipad@2x.png
│ ├── shadeOfViolet@2x.png
│ ├── shadeOfViolet@3x.png
│ ├── soilOfAvagddu-ipad-pro@2x.png
│ ├── soilOfAvagddu-ipad@2x.png
│ ├── soilOfAvagddu@2x.png
│ ├── soilOfAvagddu@3x.png
│ ├── spaceBattleBlue-ipad-pro@2x.png
│ ├── spaceBattleBlue-ipad@2x.png
│ ├── spaceBattleBlue@2x.png
│ ├── spaceBattleBlue@3x.png
│ ├── spreadsheetGreen-ipad-pro@2x.png
│ ├── spreadsheetGreen-ipad@2x.png
│ ├── spreadsheetGreen@2x.png
│ ├── spreadsheetGreen@3x.png
│ ├── tokiwaGreen-ipad-pro@2x.png
│ ├── tokiwaGreen-ipad@2x.png
│ ├── tokiwaGreen@2x.png
│ ├── tokiwaGreen@3x.png
│ ├── toyCamouflage-ipad-pro@2x.png
│ ├── toyCamouflage-ipad@2x.png
│ ├── toyCamouflage@2x.png
│ ├── toyCamouflage@3x.png
│ ├── tropicana-ipad-pro@2x.png
│ ├── tropicana-ipad@2x.png
│ ├── tropicana@2x.png
│ └── tropicana@3x.png
├── flow.png
└── monochrome.png
├── lib
├── constants.dart
├── data
│ ├── chart_data.dart
│ ├── currencies.dart
│ ├── exchange_rates.dart
│ ├── exchange_rates_set.dart
│ ├── flow_analytics.dart
│ ├── flow_icon.dart
│ ├── flow_notification_payload.dart
│ ├── flow_notification_payload.g.dart
│ ├── flow_standard_report.dart
│ ├── github
│ │ └── contributor.dart
│ ├── icons.dart
│ ├── internal_nofications
│ │ └── internal_notification.dart
│ ├── money.dart
│ ├── multi_currency_flow.dart
│ ├── prefs
│ │ ├── frecency.dart
│ │ ├── frecency.g.dart
│ │ ├── frecency_group.dart
│ │ └── frecency_group.g.dart
│ ├── recurrence_mode.dart
│ ├── setup
│ │ ├── default_accounts.dart
│ │ └── default_categories.dart
│ ├── single_currency_flow.dart
│ ├── transaction_filter.dart
│ ├── transaction_filter.g.dart
│ └── transactions_filter
│ │ ├── group_range.dart
│ │ ├── search_data.dart
│ │ ├── search_data.g.dart
│ │ ├── sort_field.dart
│ │ └── time_range.dart
├── entity
│ ├── _base.dart
│ ├── account.dart
│ ├── account.g.dart
│ ├── backup_entry.dart
│ ├── budget.dart
│ ├── budget.g.dart
│ ├── category.dart
│ ├── category.g.dart
│ ├── profile.dart
│ ├── profile.g.dart
│ ├── recurring_transaction.dart
│ ├── recurring_transaction.g.dart
│ ├── transaction.dart
│ ├── transaction.g.dart
│ ├── transaction
│ │ ├── extensions
│ │ │ ├── base.dart
│ │ │ └── default
│ │ │ │ ├── geo.dart
│ │ │ │ ├── geo.g.dart
│ │ │ │ ├── recurring.dart
│ │ │ │ ├── recurring.g.dart
│ │ │ │ ├── transfer.dart
│ │ │ │ └── transfer.g.dart
│ │ ├── subtype.dart
│ │ ├── type.dart
│ │ └── wrapper.dart
│ ├── transaction_filter_preset.dart
│ ├── transaction_filter_preset.g.dart
│ ├── user_preferences.dart
│ └── user_preferences.g.dart
├── form_validators.dart
├── graceful_migrations.dart
├── l10n
│ ├── extensions.dart
│ ├── flow_localizations.dart
│ ├── localized_exception.dart
│ ├── named_enum.dart
│ └── supported_languages.dart
├── logging.dart
├── main.dart
├── objectbox.dart
├── objectbox
│ ├── actions.dart
│ ├── objectbox-model.json
│ └── objectbox.g.dart
├── prefs
│ ├── local_preferences.dart
│ ├── pending_transactions.dart
│ ├── theme.dart
│ └── transitive.dart
├── providers
│ ├── accounts_provider.dart
│ └── categories.dart
├── reports
│ ├── category_flow_report.dart
│ ├── interval_flow_report.dart
│ ├── range_forecast_report.dart
│ ├── report.dart
│ └── trends_report.dart
├── routes.dart
├── routes
│ ├── account
│ │ └── account_edit_page.dart
│ ├── account_page.dart
│ ├── accounts_page.dart
│ ├── categories_page.dart
│ ├── category
│ │ └── category_edit_page.dart
│ ├── category_page.dart
│ ├── community
│ │ └── contributors_page.dart
│ ├── debug
│ │ ├── debug_icloud_page.dart
│ │ ├── debug_log_page.dart
│ │ ├── debug_logs_page.dart
│ │ ├── debug_scheduled_notifications_page.dart
│ │ └── debug_theme_page.dart
│ ├── error_page.dart
│ ├── export
│ │ ├── export_history_page.dart
│ │ └── export_pdf_page.dart
│ ├── export_options_page.dart
│ ├── export_page.dart
│ ├── home
│ │ ├── accounts_tab.dart
│ │ ├── home_tab.dart
│ │ ├── profile_tab.dart
│ │ └── stats_tab.dart
│ ├── home_page.dart
│ ├── import_page.dart
│ ├── import_wizard
│ │ ├── csv.dart
│ │ ├── ivy.dart
│ │ ├── v1.dart
│ │ └── v2.dart
│ ├── preferences
│ │ ├── button_order_preferences_page.dart
│ │ ├── language_selection_sheet.dart
│ │ ├── money_formatting_preferences_page.dart
│ │ ├── numpad_preferences_page.dart
│ │ ├── pending_transactions_preferences_page.dart
│ │ ├── reminders_preferences_page.dart
│ │ ├── sections
│ │ │ ├── haptics.dart
│ │ │ ├── icloud.dart
│ │ │ ├── lock_app.dart
│ │ │ └── privacy.dart
│ │ ├── sync_preferences_page.dart
│ │ ├── theme_preferences_page.dart
│ │ ├── transaction_geo_preferences_page.dart
│ │ ├── transaction_list_item_appearance_preferences_page.dart
│ │ ├── transfer_preferences_page.dart
│ │ └── trash_bin_preferences_page.dart
│ ├── preferences_page.dart
│ ├── profile_page.dart
│ ├── setup
│ │ ├── setup_accounts_page.dart
│ │ ├── setup_categories_page.dart
│ │ ├── setup_currency_page.dart
│ │ ├── setup_onboarding_page.dart
│ │ ├── setup_profile_page.dart
│ │ └── setup_profile_picture_page.dart
│ ├── setup_page.dart
│ ├── stats
│ │ └── stats_by_group_page.dart
│ ├── support_page.dart
│ ├── transaction_page.dart
│ ├── transaction_page
│ │ ├── amount_text.dart
│ │ ├── description_section.dart
│ │ ├── input_amount_sheet.dart
│ │ ├── input_amount_sheet
│ │ │ ├── calculator_button.dart
│ │ │ └── input_value.dart
│ │ ├── section.dart
│ │ ├── select_account_sheet.dart
│ │ ├── select_category_sheet.dart
│ │ ├── select_recurrence.dart
│ │ ├── select_recurring_update_mode_sheet.dart
│ │ └── title_input.dart
│ ├── transactions_page.dart
│ └── utils
│ │ ├── crop_square_image_page.dart
│ │ └── edit_markdown_page.dart
├── services
│ ├── accounts.dart
│ ├── connectivity.dart
│ ├── exchange_rates.dart
│ ├── github.dart
│ ├── icloud_sync.dart
│ ├── internal_notifications.dart
│ ├── local_auth.dart
│ ├── notifications.dart
│ ├── recurring_transactions.dart
│ ├── sync.dart
│ ├── transactions.dart
│ └── user_preferences.dart
├── sync
│ ├── exception.dart
│ ├── export.dart
│ ├── export
│ │ ├── export_csv.dart
│ │ ├── export_csv
│ │ │ └── header_v1.dart
│ │ ├── export_pdf.dart
│ │ ├── export_pdf
│ │ │ └── headers.dart
│ │ ├── export_v1.dart
│ │ ├── export_v2.dart
│ │ └── mode.dart
│ ├── import.dart
│ ├── import
│ │ ├── base.dart
│ │ ├── external
│ │ │ └── ivy_wallet_csv.dart
│ │ ├── import_csv.dart
│ │ ├── import_v1.dart
│ │ └── import_v2.dart
│ ├── model
│ │ ├── base.dart
│ │ ├── csv
│ │ │ ├── csv_parsed_transaction.dart
│ │ │ ├── parsed_data.dart
│ │ │ └── parsers.dart
│ │ ├── external
│ │ │ └── ivy
│ │ │ │ ├── ivy_wallet_csv.dart
│ │ │ │ ├── ivy_wallet_transaction.dart
│ │ │ │ └── parsers.dart
│ │ ├── model_v1.dart
│ │ ├── model_v1.g.dart
│ │ ├── model_v2.dart
│ │ └── model_v2.g.dart
│ └── sync.dart
├── theme
│ ├── color_themes
│ │ ├── catppuccin
│ │ │ ├── frappe.dart
│ │ │ ├── frappe.json
│ │ │ ├── macchiato.dart
│ │ │ ├── macchiato.json
│ │ │ ├── mocha.dart
│ │ │ └── mocha.json
│ │ ├── flow
│ │ │ ├── flow_darks.dart
│ │ │ ├── flow_lights.dart
│ │ │ └── flow_oleds.dart
│ │ ├── palenight.dart
│ │ └── registry.dart
│ ├── flow_color_scheme.dart
│ ├── flow_custom_colors.dart
│ ├── flow_theme_group.dart
│ ├── helpers.dart
│ ├── names.dart
│ ├── navbar_theme.dart
│ ├── pie_theme_extension.dart
│ ├── primary_colors.dart
│ ├── text_theme.dart
│ └── theme.dart
├── utils
│ ├── csv_parser.dart
│ ├── extensions.dart
│ ├── extensions
│ │ ├── backup_entry.dart
│ │ ├── custom_popups.dart
│ │ ├── directionality.dart
│ │ ├── go_router.dart
│ │ ├── interval_report.dart
│ │ ├── iterables.dart
│ │ ├── num.dart
│ │ ├── recurring_transaction.dart
│ │ ├── string.dart
│ │ ├── toast.dart
│ │ ├── transaction.dart
│ │ └── transaction_filter.dart
│ ├── guess_preset_icon.dart
│ ├── is_desktop.dart
│ ├── jasonable.dart
│ ├── json
│ │ ├── time_range_converter.dart
│ │ └── utc_datetime_converter.dart
│ ├── line_break_normalizer.dart
│ ├── number_formatting.dart
│ ├── open_url.dart
│ ├── optional.dart
│ ├── pick_file.dart
│ ├── shortcut.dart
│ ├── simple_query_sorter.dart
│ └── utils.dart
└── widgets
│ ├── account
│ └── update_balance_options_sheet.dart
│ ├── account_card.dart
│ ├── account_card_skeleton.dart
│ ├── action_card.dart
│ ├── add_category_card.dart
│ ├── categories
│ └── no_categories.dart
│ ├── category
│ └── transactions_info.dart
│ ├── category_card.dart
│ ├── chart_legend.dart
│ ├── community
│ └── contributors
│ │ └── contributor_card.dart
│ ├── default_transaction_filter_head.dart
│ ├── delete_button.dart
│ ├── export
│ ├── export_history
│ │ ├── backup_entry_card.dart
│ │ └── no_backups.dart
│ └── export_success.dart
│ ├── flow_card.dart
│ ├── general
│ ├── blur_backgorund.dart
│ ├── button.dart
│ ├── context_menu.dart
│ ├── directional_chevron.dart
│ ├── directional_slidable.dart
│ ├── flow_icon.dart
│ ├── form_close_button.dart
│ ├── frame.dart
│ ├── info_text.dart
│ ├── list_header.dart
│ ├── map.dart
│ ├── markdown_view.dart
│ ├── modal_overflow_bar.dart
│ ├── modal_sheet.dart
│ ├── money_text.dart
│ ├── money_text_builder.dart
│ ├── money_text_raw.dart
│ ├── pending_transactions_header.dart
│ ├── profile_picture.dart
│ ├── rtl_flipper.dart
│ ├── spinner.dart
│ ├── surface.dart
│ ├── wavy_divider.dart
│ └── wavy_divider
│ │ └── wavy_divider_painter.dart
│ ├── geo_permission_missing_reminder.dart
│ ├── grouped_transactions_list_view.dart
│ ├── home
│ ├── greetings_bar.dart
│ ├── home
│ │ ├── account
│ │ │ ├── no_accounts.dart
│ │ │ └── total_balance.dart
│ │ ├── flow_cards.dart
│ │ ├── info_card.dart
│ │ └── no_transactions.dart
│ ├── navbar.dart
│ ├── navbar
│ │ ├── navbar_button.dart
│ │ └── new_transaction_button.dart
│ ├── preferences
│ │ ├── button_order_preferences
│ │ │ └── transaction_type_button.dart
│ │ ├── numpad_preferences
│ │ │ └── numpad_selector_radio.dart
│ │ ├── profile_card.dart
│ │ └── transfer_preferences
│ │ │ ├── combine_transfer_radio.dart.dart
│ │ │ └── demo_transaction_list_tile.dart
│ ├── privacy_toggler.dart
│ └── stats
│ │ ├── group_pie_chart.dart
│ │ ├── info_card_with_delta.dart
│ │ ├── most_spending_category.dart
│ │ ├── no_data.dart
│ │ ├── pie_graph_view.dart
│ │ ├── pie_percent_badge.dart
│ │ └── range_daily_chart.dart
│ ├── import
│ └── file_select_area.dart
│ ├── import_wizard
│ ├── backup_info.dart
│ ├── csv
│ │ ├── account_currency_list_tile.dart
│ │ └── backup_info_csv.dart
│ ├── import_item_list_tile.dart
│ ├── import_success.dart
│ ├── ivy_wallet
│ │ └── backup_info.dart
│ ├── v1
│ │ └── backup_info_v1.dart
│ └── v2
│ │ └── backup_info_v2.dart
│ ├── internal_notifications
│ ├── auto_backup_reminder.dart
│ ├── internal_notification_list_tile.dart
│ ├── internal_notification_section.dart
│ ├── rate_app_notification.dart
│ └── star_on_github_notification.dart
│ ├── location_picker_sheet.dart
│ ├── month_selector_sheet.dart
│ ├── no_result.dart
│ ├── notifications_permission_missing_reminder.dart
│ ├── numpad.dart
│ ├── numpad_button.dart
│ ├── rates_missing_warning.dart
│ ├── reports
│ ├── category_report_view.dart
│ └── interval_flow_report_view.dart
│ ├── setup
│ ├── accounts
│ │ ├── account_preset_card.dart
│ │ └── add_account_card.dart
│ ├── categories
│ │ └── category_preset_card.dart
│ ├── foss_slide.dart
│ ├── offline_slide.dart
│ └── welcome_slide.dart
│ ├── sheets
│ ├── month_selector_sheet
│ │ └── month_button.dart
│ ├── recurrence
│ │ ├── select_day_sheet.dart
│ │ └── selectors
│ │ │ └── weekday_selector.dart
│ ├── select_account_type_sheet.dart
│ ├── select_currency_icu_pattern.dart
│ ├── select_currency_sheet.dart
│ ├── select_flow_icon_sheet.dart
│ ├── select_flow_icon_sheet
│ │ ├── select_char_flow_icon_sheet.dart
│ │ ├── select_icon_flow_icon_sheet.dart
│ │ └── select_image_flow_icon_sheet.dart
│ ├── select_multi_currency_sheet.dart
│ ├── select_multi_transaction_type_sheet.dart
│ ├── select_time_range_mode_sheet.dart
│ ├── select_transaction_type_sheet.dart
│ ├── year_selector_sheet.dart
│ └── year_selector_sheet
│ │ └── year_button.dart
│ ├── square_map.dart
│ ├── theme_petal_selector.dart
│ ├── theme_petal_selector
│ └── theme_petal_painter.dart
│ ├── time_range_selector.dart
│ ├── transaction
│ └── type_selector.dart
│ ├── transaction_filter_head.dart
│ ├── transaction_filter_head
│ ├── create_filter_preset_sheet.dart
│ ├── select_filter_preset_sheet.dart
│ ├── select_filter_preset_sheet
│ │ ├── default_filter_preset_list_tile.dart
│ │ └── filter_preset_list_tile.dart
│ ├── select_group_range_sheet.dart
│ ├── select_multi_account_sheet.dart
│ ├── select_multi_category_sheet.dart
│ ├── select_transaction_filter_time_range_sheet.dart
│ ├── transaction_filter_chip.dart
│ └── transaction_search_sheet.dart
│ ├── transaction_list_tile.dart
│ ├── transaction_watcher.dart
│ ├── transactions_date_header.dart
│ ├── trend.dart
│ ├── utils
│ ├── should_execute_scheduled_task.dart
│ ├── time_and_range.dart
│ └── utils.dart
│ └── year_selector_bar.dart
├── linux
├── .gitignore
├── CMakeLists.txt
├── flutter
│ ├── CMakeLists.txt
│ ├── generated_plugin_registrant.cc
│ ├── generated_plugin_registrant.h
│ └── generated_plugins.cmake
├── main.cc
├── my_application.cc
└── my_application.h
├── logo@16.png
├── logo@32.png
├── macos
├── .gitignore
├── Flutter
│ ├── Flutter-Debug.xcconfig
│ ├── Flutter-Release.xcconfig
│ └── GeneratedPluginRegistrant.swift
├── Podfile
├── Podfile.lock
├── Runner.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── Runner
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ │ └── AppIcon.appiconset
│ │ │ ├── Contents.json
│ │ │ ├── app_icon_1024.png
│ │ │ ├── app_icon_128.png
│ │ │ ├── app_icon_256.png
│ │ │ ├── app_icon_32.png
│ │ │ ├── app_icon_512.png
│ │ │ └── app_icon_64.png
│ ├── Base.lproj
│ │ └── MainMenu.xib
│ ├── Configs
│ │ ├── AppInfo.xcconfig
│ │ ├── Debug.xcconfig
│ │ ├── Release.xcconfig
│ │ └── Warnings.xcconfig
│ ├── DebugProfile.entitlements
│ ├── Info.plist
│ ├── MainFlutterWindow.swift
│ ├── Release.entitlements
│ ├── en-IN.lproj
│ │ └── MainMenu.strings
│ ├── it.lproj
│ │ └── MainMenu.strings
│ ├── mn.lproj
│ │ └── MainMenu.strings
│ └── tr.lproj
│ │ └── MainMenu.strings
└── RunnerTests
│ └── RunnerTests.swift
├── pubspec.lock
├── pubspec.yaml
├── reformat_l10n_files.sh
├── regenerate_code.sh
├── scripts
└── reformat_l10n_files.dart
├── test
├── backup
│ ├── v1_export.dart
│ ├── v1_import.dart
│ ├── v1_populate.dart
│ └── v1_test.dart
├── database_test.dart
├── import
│ ├── csv_data_parser_test.dart
│ ├── invalid-1.csv
│ └── valid-1.csv
├── l10n
│ └── json_integrity_test.dart
├── objectbox_erase.dart
├── serialization
│ └── flow_notification_payload_test.dart
└── unit
│ └── should_execute_scheduled_task_test.dart
└── windows
├── .gitignore
├── CMakeLists.txt
├── flutter
├── CMakeLists.txt
├── generated_plugin_registrant.cc
├── generated_plugin_registrant.h
└── generated_plugins.cmake
└── runner
├── CMakeLists.txt
├── Runner.rc
├── flutter_window.cpp
├── flutter_window.h
├── main.cpp
├── resource.h
├── resources
└── app_icon.ico
├── runner.exe.manifest
├── utils.cpp
├── utils.h
├── win32_window.cpp
└── win32_window.h
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: flow-mn
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
7 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
8 | liberapay: # Replace with a single Liberapay username
9 | issuehunt: # Replace with a single IssueHunt username
10 | otechie: # Replace with a single Otechie username
11 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
12 | polar: # Replace with a single Polar username
13 | custom: https://buymeacoffee.com/sadespresso
14 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.yaml:
--------------------------------------------------------------------------------
1 | name: Feature Request
2 | description: Suggest an idea or improvement to Flow
3 | title: "[FEAT] "
4 | body:
5 | - type: textarea
6 | id: desc
7 | attributes:
8 | label: Description
9 | description: Describe your suggested feature and the main use cases
10 | validations:
11 | required: true
12 |
13 | - type: textarea
14 | id: context
15 | attributes:
16 | label: Additional Context
17 | description: Add any additonal context about the feature here
18 |
--------------------------------------------------------------------------------
/.github/workflows/test.yaml:
--------------------------------------------------------------------------------
1 | name: Run tests
2 | on:
3 | pull_request:
4 | push:
5 | branches:
6 | - "develop"
7 |
8 | jobs:
9 | test:
10 | runs-on: "ubuntu-latest"
11 | steps:
12 | - uses: actions/checkout@v4
13 | - uses: subosito/flutter-action@v2
14 | with:
15 | channel: stable
16 | - run: bash <(curl -s https://raw.githubusercontent.com/objectbox/objectbox-dart/main/install.sh)
17 | - run: flutter pub get
18 | - run: flutter test
19 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .build/
9 | .buildlog/
10 | .history
11 | .svn/
12 | .swiftpm/
13 | migrate_working_dir/
14 |
15 | # IntelliJ related
16 | *.iml
17 | *.ipr
18 | *.iws
19 | .idea/
20 |
21 | # The .vscode folder contains launch configuration and tasks you configure in
22 | # VS Code which you may wish to be included in version control, so this line
23 | # is commented out by default.
24 | #.vscode/
25 |
26 | # Flutter/Dart/Pub related
27 | **/doc/api/
28 | **/ios/Flutter/.last_build_id
29 | .dart_tool/
30 | .flutter-plugins
31 | .flutter-plugins-dependencies
32 | .packages
33 | .pub-cache/
34 | .pub/
35 | /build/
36 |
37 | # Symbolication related
38 | app.*.symbols
39 |
40 | # Obfuscation related
41 | app.*.map.json
42 |
43 | # Android Studio will place build artifacts here
44 | /android/app/debug
45 | /android/app/profile
46 | /android/app/release
47 |
48 | # ObjectBox unit testing
49 |
50 | .objectbox_test
51 |
52 | # Objectbox library
53 |
54 | /download
55 | lib/libobjectbox.dylib
56 | lib/libobjectbox.so
--------------------------------------------------------------------------------
/.idx/dev.nix:
--------------------------------------------------------------------------------
1 | {pkgs}: {
2 | channel = "stable-24.05";
3 | packages = [
4 | pkgs.jdk17
5 | pkgs.unzip
6 | ];
7 | idx.extensions = [
8 | "Dart-Code.dart-code"
9 | "Dart-Code.flutter"
10 | ];
11 | idx.previews = {
12 | previews = {
13 | android = {
14 | command = [
15 | "flutter"
16 | "run"
17 | "--machine"
18 | "-d"
19 | "android"
20 | "-d"
21 | "localhost:5555"
22 | ];
23 | manager = "flutter";
24 | };
25 | };
26 | };
27 | }
--------------------------------------------------------------------------------
/.markdownlint.json:
--------------------------------------------------------------------------------
1 | {
2 | "MD013": {
3 | "line_length": 120
4 | },
5 | "MD024": false,
6 | "MD041": false
7 | }
8 |
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: "78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9"
8 | channel: "stable"
9 |
10 | project_type: app
11 |
12 | # Tracks metadata for the flutter migrate command
13 | migration:
14 | platforms:
15 | - platform: root
16 | create_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
17 | base_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
18 | - platform: web
19 | create_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
20 | base_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
21 |
22 | # User provided section
23 |
24 | # List of Local paths (relative to this file) that should be
25 | # ignored by the migrate tool.
26 | #
27 | # Files that are not part of the templates will be ignored by default.
28 | unmanaged_files:
29 | - 'lib/main.dart'
30 | - 'ios/Runner.xcodeproj/project.pbxproj'
31 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "tabWidth": 4,
3 | "useTabs": false
4 | }
5 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "Dart-Code.dart-code",
4 | "Dart-Code.flutter",
5 | "davidanson.vscode-markdownlint"
6 | ]
7 | }
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "name": "Flow",
9 | "request": "launch",
10 | "type": "dart"
11 | }
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "cmake.configureOnOpen": false,
3 | "IDX.aI.enableInlineCompletion": true,
4 | "IDX.aI.enableCodebaseIndexing": true,
5 | "editor.tabSize": 2
6 | }
7 |
--------------------------------------------------------------------------------
/RELEASE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ## **PLEASE BACKUP BEFORE UPGRADING**
2 |
3 | You may permanently lose all of your data if something goes wrong with the update.
4 | Generally, everything should be fine unless specified otherwise in the release note.
5 | Project owner and/or any of the project contributors are not responsible for your
6 | data loss under any circumstances!
7 |
8 | ## What's Changed
9 |
10 | {{changelog}}
11 |
12 | ## Download
13 |
14 | * [Google Play](https://play.google.com/store/apps/details?id=mn.flow.flow?utm_source=gh-release-{{version}}) for Android
15 | * [App Store](https://apps.apple.com/mn/app/flow-expense-tracker/id6477741670?utm_source=gh-release-{{version}}) for iOS
16 |
17 | Also:
18 |
19 | * Download Fat APK build from [GitHub release](https://github.com/flow-mn/flow/releases/latest)
20 |
21 | Updates may take some time to appear on app stores after GitHub release
22 |
--------------------------------------------------------------------------------
/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | include: package:flutter_lints/flutter.yaml
2 |
3 | linter:
4 | rules:
5 | unawaited_futures: true
6 | prefer_double_quotes: true
7 | type_annotate_public_apis: true
8 | analyzer:
9 | exclude:
10 | - "example/**"
11 | - "build/**"
12 | - "**/*.g.dart"
13 | - "**/*.freezed.dart"
14 |
--------------------------------------------------------------------------------
/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 | build
--------------------------------------------------------------------------------
/android/app/.gitignore:
--------------------------------------------------------------------------------
1 | .cxx
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/mn/flow/flow/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package mn.flow.flow
2 |
3 | import io.flutter.embedding.android.FlutterFragmentActivity
4 |
5 | class MainActivity: FlutterFragmentActivity() {
6 | }
7 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-hdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/android/app/src/main/res/drawable-hdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-hdpi/monochrome.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/android/app/src/main/res/drawable-hdpi/monochrome.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-hdpi/notification_default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/android/app/src/main/res/drawable-hdpi/notification_default.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-mdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/android/app/src/main/res/drawable-mdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-mdpi/monochrome.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/android/app/src/main/res/drawable-mdpi/monochrome.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-mdpi/notification_default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/android/app/src/main/res/drawable-mdpi/notification_default.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-v21/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/android/app/src/main/res/drawable-xhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xhdpi/monochrome.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/android/app/src/main/res/drawable-xhdpi/monochrome.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xhdpi/notification_default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/android/app/src/main/res/drawable-xhdpi/notification_default.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xxhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/android/app/src/main/res/drawable-xxhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xxhdpi/monochrome.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/android/app/src/main/res/drawable-xxhdpi/monochrome.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xxhdpi/notification_default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/android/app/src/main/res/drawable-xxhdpi/notification_default.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xxxhdpi/monochrome.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/android/app/src/main/res/drawable-xxxhdpi/monochrome.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xxxhdpi/notification_default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/android/app/src/main/res/drawable-xxxhdpi/notification_default.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/notification_default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/android/app/src/main/res/drawable/notification_default.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/raw/keep.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
--------------------------------------------------------------------------------
/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | allprojects {
2 | repositories {
3 | google()
4 | mavenCentral()
5 | }
6 | }
7 |
8 | rootProject.buildDir = '../build'
9 | subprojects {
10 | project.buildDir = "${rootProject.buildDir}/${project.name}"
11 | }
12 | subprojects {
13 | project.evaluationDependsOn(':app')
14 | }
15 |
16 | tasks.register("clean", Delete) {
17 | delete rootProject.buildDir
18 | }
19 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx2560M
2 | android.useAndroidX=true
3 | android.enableJetifier=true
4 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip
6 | distributionSha256Sum=7ebdac923867a3cec0098302416d1e3c6c0c729fc4e2e05c10637a8af33a76c5
7 |
--------------------------------------------------------------------------------
/android/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # For https://pub.dev/packages/file_picker
2 | -keep class androidx.lifecycle.DefaultLifecycleObserver
3 |
4 | ## Gson rules
5 | # Gson uses generic type information stored in a class file when working with fields. Proguard
6 | # removes such information by default, so configure it to keep all of it.
7 | -keepattributes Signature
8 |
9 | # For using GSON @Expose annotation
10 | -keepattributes *Annotation*
11 |
12 | # Gson specific classes
13 | -dontwarn sun.misc.**
14 | #-keep class com.google.gson.stream.** { *; }
15 |
16 | # Prevent proguard from stripping interface information from TypeAdapter, TypeAdapterFactory,
17 | # JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
18 | -keep class * extends com.google.gson.TypeAdapter
19 | -keep class * implements com.google.gson.TypeAdapterFactory
20 | -keep class * implements com.google.gson.JsonSerializer
21 | -keep class * implements com.google.gson.JsonDeserializer
22 |
23 | # Prevent R8 from leaving Data object members always null
24 | -keepclassmembers,allowobfuscation class * {
25 | @com.google.gson.annotations.SerializedName ;
26 | }
27 |
28 | # Retain generic signatures of TypeToken and its subclasses with R8 version 3.0 and higher.
29 | -keep,allowobfuscation,allowshrinking class com.google.gson.reflect.TypeToken
30 | -keep,allowobfuscation,allowshrinking class * extends com.google.gson.reflect.TypeToken
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | def flutterSdkPath = {
3 | def properties = new Properties()
4 | file("local.properties").withInputStream { properties.load(it) }
5 | def flutterSdkPath = properties.getProperty("flutter.sdk")
6 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
7 | return flutterSdkPath
8 | }
9 | settings.ext.flutterSdkPath = flutterSdkPath()
10 |
11 | includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")
12 |
13 | repositories {
14 | google()
15 | mavenCentral()
16 | gradlePluginPortal()
17 | }
18 | }
19 |
20 | plugins {
21 | id "dev.flutter.flutter-plugin-loader" version "1.0.0"
22 | id "com.android.application" version "8.8.0" apply false
23 | id "org.jetbrains.kotlin.android" version "1.9.10" apply false
24 | }
25 |
26 | include ":app"
27 |
--------------------------------------------------------------------------------
/assets/fonts/NotoEmoji-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/assets/fonts/NotoEmoji-Regular.ttf
--------------------------------------------------------------------------------
/assets/fonts/NotoSans-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/assets/fonts/NotoSans-Regular.ttf
--------------------------------------------------------------------------------
/assets/fonts/NotoSansArabic-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/assets/fonts/NotoSansArabic-Regular.ttf
--------------------------------------------------------------------------------
/assets/fonts/NotoSansHebrew-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/assets/fonts/NotoSansHebrew-Regular.ttf
--------------------------------------------------------------------------------
/assets/fonts/Poppins-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/assets/fonts/Poppins-Bold.ttf
--------------------------------------------------------------------------------
/assets/fonts/Poppins-Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/assets/fonts/Poppins-Italic.ttf
--------------------------------------------------------------------------------
/assets/fonts/Poppins-Medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/assets/fonts/Poppins-Medium.ttf
--------------------------------------------------------------------------------
/assets/fonts/Poppins-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/assets/fonts/Poppins-Regular.ttf
--------------------------------------------------------------------------------
/assets/fonts/Poppins-SemiBold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/assets/fonts/Poppins-SemiBold.ttf
--------------------------------------------------------------------------------
/assets/images/2.0x/flow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/assets/images/2.0x/flow.png
--------------------------------------------------------------------------------
/assets/images/2.0x/map_square.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/assets/images/2.0x/map_square.png
--------------------------------------------------------------------------------
/assets/images/2.0x/pin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/assets/images/2.0x/pin.png
--------------------------------------------------------------------------------
/assets/images/3.0x/flow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/assets/images/3.0x/flow.png
--------------------------------------------------------------------------------
/assets/images/3.0x/pin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/assets/images/3.0x/pin.png
--------------------------------------------------------------------------------
/assets/images/4.0x/flow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/assets/images/4.0x/flow.png
--------------------------------------------------------------------------------
/assets/images/external/ivy_wallet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/assets/images/external/ivy_wallet.png
--------------------------------------------------------------------------------
/assets/images/flow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/assets/images/flow.png
--------------------------------------------------------------------------------
/assets/images/map_square.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/assets/images/map_square.png
--------------------------------------------------------------------------------
/assets/images/missing.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/assets/images/missing.png
--------------------------------------------------------------------------------
/assets/images/missing.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/assets/images/pin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/assets/images/pin.png
--------------------------------------------------------------------------------
/devtools_options.yaml:
--------------------------------------------------------------------------------
1 | description: This file stores settings for Dart & Flutter DevTools.
2 | documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
3 | extensions:
4 |
--------------------------------------------------------------------------------
/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 | 12.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/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 | @main
5 | @objc class AppDelegate: FlutterAppDelegate {
6 | override func application(
7 | _ application: UIApplication,
8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
9 | ) -> Bool {
10 | if #available(iOS 10.0, *) {
11 | UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
12 | }
13 |
14 | GeneratedPluginRegistrant.register(with: self)
15 |
16 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/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/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/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/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/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/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/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/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/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/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/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/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/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/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/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/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/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/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/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/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/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/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/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/LauncherIcons/blissfulBerry-ipad-pro@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/blissfulBerry-ipad-pro@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/blissfulBerry-ipad@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/blissfulBerry-ipad@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/blissfulBerry@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/blissfulBerry@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/blissfulBerry@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/blissfulBerry@3x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/bohemianBlue-ipad-pro@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/bohemianBlue-ipad-pro@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/bohemianBlue-ipad@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/bohemianBlue-ipad@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/bohemianBlue@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/bohemianBlue@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/bohemianBlue@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/bohemianBlue@3x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/burntSienna-ipad-pro@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/burntSienna-ipad-pro@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/burntSienna-ipad@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/burntSienna-ipad@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/burntSienna@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/burntSienna@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/burntSienna@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/burntSienna@3x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/cherryPlum-ipad-pro@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/cherryPlum-ipad-pro@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/cherryPlum-ipad@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/cherryPlum-ipad@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/cherryPlum@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/cherryPlum@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/cherryPlum@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/cherryPlum@3x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/crispChristmasCranberries-ipad-pro@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/crispChristmasCranberries-ipad-pro@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/crispChristmasCranberries-ipad@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/crispChristmasCranberries-ipad@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/crispChristmasCranberries@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/crispChristmasCranberries@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/crispChristmasCranberries@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/crispChristmasCranberries@3x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/egyptianBlue-ipad-pro@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/egyptianBlue-ipad-pro@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/egyptianBlue-ipad@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/egyptianBlue-ipad@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/egyptianBlue@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/egyptianBlue@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/egyptianBlue@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/egyptianBlue@3x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/flagGreen-ipad-pro@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/flagGreen-ipad-pro@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/flagGreen-ipad@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/flagGreen-ipad@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/flagGreen@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/flagGreen@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/flagGreen@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/flagGreen@3x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/hydraTurquoise-ipad-pro@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/hydraTurquoise-ipad-pro@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/hydraTurquoise-ipad@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/hydraTurquoise-ipad@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/hydraTurquoise@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/hydraTurquoise@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/hydraTurquoise@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/hydraTurquoise@3x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/peacockBlue-ipad-pro@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/peacockBlue-ipad-pro@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/peacockBlue-ipad@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/peacockBlue-ipad@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/peacockBlue@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/peacockBlue@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/peacockBlue@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/peacockBlue@3x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/shadeOfViolet-ipad-pro@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/shadeOfViolet-ipad-pro@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/shadeOfViolet-ipad@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/shadeOfViolet-ipad@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/shadeOfViolet@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/shadeOfViolet@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/shadeOfViolet@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/shadeOfViolet@3x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/soilOfAvagddu-ipad-pro@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/soilOfAvagddu-ipad-pro@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/soilOfAvagddu-ipad@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/soilOfAvagddu-ipad@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/soilOfAvagddu@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/soilOfAvagddu@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/soilOfAvagddu@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/soilOfAvagddu@3x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/spaceBattleBlue-ipad-pro@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/spaceBattleBlue-ipad-pro@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/spaceBattleBlue-ipad@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/spaceBattleBlue-ipad@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/spaceBattleBlue@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/spaceBattleBlue@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/spaceBattleBlue@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/spaceBattleBlue@3x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/spreadsheetGreen-ipad-pro@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/spreadsheetGreen-ipad-pro@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/spreadsheetGreen-ipad@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/spreadsheetGreen-ipad@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/spreadsheetGreen@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/spreadsheetGreen@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/spreadsheetGreen@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/spreadsheetGreen@3x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/tokiwaGreen-ipad-pro@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/tokiwaGreen-ipad-pro@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/tokiwaGreen-ipad@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/tokiwaGreen-ipad@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/tokiwaGreen@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/tokiwaGreen@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/tokiwaGreen@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/tokiwaGreen@3x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/toyCamouflage-ipad-pro@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/toyCamouflage-ipad-pro@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/toyCamouflage-ipad@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/toyCamouflage-ipad@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/toyCamouflage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/toyCamouflage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/toyCamouflage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/toyCamouflage@3x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/tropicana-ipad-pro@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/tropicana-ipad-pro@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/tropicana-ipad@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/tropicana-ipad@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/tropicana@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/tropicana@2x.png
--------------------------------------------------------------------------------
/ios/Runner/LauncherIcons/tropicana@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/ios/Runner/LauncherIcons/tropicana@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
2 |
--------------------------------------------------------------------------------
/ios/Runner/Runner.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | aps-environment
6 | development
7 | com.apple.developer.icloud-container-identifiers
8 |
9 | iCloud.mn.flow.flow
10 |
11 | com.apple.developer.icloud-services
12 |
13 | CloudKit
14 | CloudDocuments
15 |
16 | com.apple.developer.ubiquity-container-identifiers
17 |
18 | iCloud.mn.flow.flow
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/ios/RunnerTests/RunnerTests.swift:
--------------------------------------------------------------------------------
1 | import Flutter
2 | import UIKit
3 | import XCTest
4 |
5 | class RunnerTests: XCTestCase {
6 |
7 | func testExample() {
8 | // If you add code to the Runner application, consider adding tests here.
9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest.
10 | }
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/launcher_icons/adaptive_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/adaptive_background.png
--------------------------------------------------------------------------------
/launcher_icons/adaptive_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/adaptive_foreground.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/blissfulBerry-ipad-pro@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/blissfulBerry-ipad-pro@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/blissfulBerry-ipad@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/blissfulBerry-ipad@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/blissfulBerry@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/blissfulBerry@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/blissfulBerry@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/blissfulBerry@3x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/bohemianBlue-ipad-pro@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/bohemianBlue-ipad-pro@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/bohemianBlue-ipad@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/bohemianBlue-ipad@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/bohemianBlue@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/bohemianBlue@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/bohemianBlue@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/bohemianBlue@3x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/burntSienna-ipad-pro@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/burntSienna-ipad-pro@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/burntSienna-ipad@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/burntSienna-ipad@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/burntSienna@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/burntSienna@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/burntSienna@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/burntSienna@3x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/cherryPlum-ipad-pro@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/cherryPlum-ipad-pro@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/cherryPlum-ipad@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/cherryPlum-ipad@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/cherryPlum@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/cherryPlum@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/cherryPlum@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/cherryPlum@3x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/crispChristmasCranberries-ipad-pro@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/crispChristmasCranberries-ipad-pro@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/crispChristmasCranberries-ipad@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/crispChristmasCranberries-ipad@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/crispChristmasCranberries@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/crispChristmasCranberries@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/crispChristmasCranberries@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/crispChristmasCranberries@3x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/egyptianBlue-ipad-pro@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/egyptianBlue-ipad-pro@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/egyptianBlue-ipad@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/egyptianBlue-ipad@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/egyptianBlue@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/egyptianBlue@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/egyptianBlue@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/egyptianBlue@3x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/flagGreen-ipad-pro@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/flagGreen-ipad-pro@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/flagGreen-ipad@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/flagGreen-ipad@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/flagGreen@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/flagGreen@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/flagGreen@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/flagGreen@3x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/hydraTurquoise-ipad-pro@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/hydraTurquoise-ipad-pro@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/hydraTurquoise-ipad@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/hydraTurquoise-ipad@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/hydraTurquoise@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/hydraTurquoise@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/hydraTurquoise@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/hydraTurquoise@3x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/peacockBlue-ipad-pro@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/peacockBlue-ipad-pro@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/peacockBlue-ipad@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/peacockBlue-ipad@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/peacockBlue@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/peacockBlue@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/peacockBlue@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/peacockBlue@3x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/shadeOfViolet-ipad-pro@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/shadeOfViolet-ipad-pro@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/shadeOfViolet-ipad@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/shadeOfViolet-ipad@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/shadeOfViolet@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/shadeOfViolet@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/shadeOfViolet@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/shadeOfViolet@3x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/soilOfAvagddu-ipad-pro@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/soilOfAvagddu-ipad-pro@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/soilOfAvagddu-ipad@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/soilOfAvagddu-ipad@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/soilOfAvagddu@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/soilOfAvagddu@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/soilOfAvagddu@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/soilOfAvagddu@3x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/spaceBattleBlue-ipad-pro@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/spaceBattleBlue-ipad-pro@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/spaceBattleBlue-ipad@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/spaceBattleBlue-ipad@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/spaceBattleBlue@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/spaceBattleBlue@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/spaceBattleBlue@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/spaceBattleBlue@3x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/spreadsheetGreen-ipad-pro@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/spreadsheetGreen-ipad-pro@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/spreadsheetGreen-ipad@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/spreadsheetGreen-ipad@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/spreadsheetGreen@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/spreadsheetGreen@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/spreadsheetGreen@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/spreadsheetGreen@3x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/tokiwaGreen-ipad-pro@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/tokiwaGreen-ipad-pro@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/tokiwaGreen-ipad@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/tokiwaGreen-ipad@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/tokiwaGreen@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/tokiwaGreen@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/tokiwaGreen@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/tokiwaGreen@3x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/toyCamouflage-ipad-pro@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/toyCamouflage-ipad-pro@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/toyCamouflage-ipad@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/toyCamouflage-ipad@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/toyCamouflage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/toyCamouflage@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/toyCamouflage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/toyCamouflage@3x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/tropicana-ipad-pro@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/tropicana-ipad-pro@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/tropicana-ipad@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/tropicana-ipad@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/tropicana@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/tropicana@2x.png
--------------------------------------------------------------------------------
/launcher_icons/defaults-light/tropicana@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/defaults-light/tropicana@3x.png
--------------------------------------------------------------------------------
/launcher_icons/flow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/flow.png
--------------------------------------------------------------------------------
/launcher_icons/monochrome.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/launcher_icons/monochrome.png
--------------------------------------------------------------------------------
/lib/constants.dart:
--------------------------------------------------------------------------------
1 | import "package:flutter/foundation.dart";
2 | import "package:latlong2/latlong.dart";
3 |
4 | String? downloadedFrom;
5 |
6 | String appVersion = "0.0.0";
7 | const bool debugBuild = false;
8 |
9 | bool get flowDebugMode => kDebugMode || debugBuild;
10 |
11 | final Uri discordInviteLink = Uri.parse("https://discord.gg/Ndh9VDeZa4");
12 | final Uri maintainerKoFiLink = Uri.parse("https://flow.gege.mn/donate");
13 | final Uri website = Uri.parse("https://flow.gege.mn");
14 | final Uri flowGitHubRepoLink = Uri.parse("https://github.com/flow-mn/flow");
15 | final Uri flowGitHubIssuesLink = Uri.parse(
16 | "https://github.com/flow-mn/flow/issues",
17 | );
18 | final Uri maintainerGitHubLink = Uri.parse("https://github.com/sadespresso");
19 |
20 | const double sukhbaatarSquareCenterLat = 47.918828;
21 | const double sukhbaatarSquareCenterLong = 106.917604;
22 |
23 | const String appleAppStoreId = "6477741670";
24 |
25 | final Uri csvImportTemplateUrl = Uri.parse(
26 | "https://docs.google.com/spreadsheets/d/1wxdJ1T8PSvzayxvGs7bVyqQ9Zu0DPQ1YwiBLy1FluqE/edit?usp=sharing",
27 | );
28 |
29 | const LatLng sukhbaatarSquareCenter = LatLng(
30 | sukhbaatarSquareCenterLat,
31 | sukhbaatarSquareCenterLong,
32 | );
33 |
--------------------------------------------------------------------------------
/lib/data/chart_data.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/data/money.dart";
2 | import "package:flow/services/exchange_rates.dart";
3 |
4 | class ChartData implements Comparable> {
5 | final String key;
6 | final Money money;
7 | final String currency;
8 | final T? associatedData;
9 |
10 | double get displayTotal => money.amount.abs();
11 |
12 | ChartData({
13 | required this.key,
14 | required this.money,
15 | required this.currency,
16 | required this.associatedData,
17 | });
18 |
19 | @override
20 | int compareTo(ChartData other) {
21 | return money.tryCompareToWithExchange(
22 | other.money,
23 | ExchangeRatesService().getPrimaryCurrencyRates(),
24 | );
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/lib/data/exchange_rates.dart:
--------------------------------------------------------------------------------
1 | import "package:moment_dart/moment_dart.dart";
2 |
3 | /// Uses endpoints from here:
4 | class ExchangeRates {
5 | final DateTime date;
6 | final String baseCurrency;
7 | final Map rates;
8 |
9 | const ExchangeRates({
10 | required this.date,
11 | required this.baseCurrency,
12 | required this.rates,
13 | });
14 |
15 | factory ExchangeRates.fromJson(Map json) {
16 | final String baseCurrency = json.keys.firstWhere((key) => key != "date");
17 |
18 | return ExchangeRates(
19 | date: DateTime.parse(json["date"]),
20 | baseCurrency: baseCurrency,
21 | rates: Map.from(json[baseCurrency.toLowerCase()]),
22 | );
23 | }
24 |
25 | Map toJson() {
26 | return {"date": date.format(payload: "YYYY-MM-DD"), baseCurrency: rates};
27 | }
28 |
29 | double? getRate(String currency) {
30 | return rates[currency.toLowerCase()]?.toDouble();
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/lib/data/exchange_rates_set.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/data/exchange_rates.dart";
2 |
3 | class ExchangeRatesSet {
4 | final Map rates;
5 |
6 | ExchangeRatesSet(this.rates);
7 |
8 | void set(String baseCurrency, ExchangeRates exchangeRates) {
9 | rates[baseCurrency] = exchangeRates;
10 | }
11 |
12 | ExchangeRates? get(String baseCurrency) {
13 | return rates[baseCurrency];
14 | }
15 |
16 | factory ExchangeRatesSet.fromJson(Map json) {
17 | final Map rates = {};
18 |
19 | for (final String baseCurrency in json.keys) {
20 | rates[baseCurrency] = ExchangeRates.fromJson(json[baseCurrency]);
21 | }
22 |
23 | return ExchangeRatesSet(rates);
24 | }
25 |
26 | Map toJson() {
27 | final Map json = {};
28 |
29 | for (final MapEntry entry in rates.entries) {
30 | json[entry.key] = entry.value.toJson();
31 | }
32 |
33 | return json;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/lib/data/flow_analytics.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/data/multi_currency_flow.dart";
2 | import "package:moment_dart/moment_dart.dart";
3 |
4 | class FlowAnalytics {
5 | final TimeRange range;
6 |
7 | final Map> flow;
8 |
9 | const FlowAnalytics({required this.range, required this.flow});
10 | }
11 |
--------------------------------------------------------------------------------
/lib/data/flow_notification_payload.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'flow_notification_payload.dart';
4 |
5 | // **************************************************************************
6 | // JsonSerializableGenerator
7 | // **************************************************************************
8 |
9 | FlowNotificationPayload _$FlowNotificationPayloadFromJson(
10 | Map json,
11 | ) => FlowNotificationPayload(
12 | itemType: $enumDecode(
13 | _$FlowNotificationPayloadItemTypeEnumMap,
14 | json['itemType'],
15 | ),
16 | id: json['id'] as String?,
17 | extra: json['extra'] as String?,
18 | );
19 |
20 | Map _$FlowNotificationPayloadToJson(
21 | FlowNotificationPayload instance,
22 | ) => {
23 | 'itemType': _$FlowNotificationPayloadItemTypeEnumMap[instance.itemType]!,
24 | 'id': instance.id,
25 | 'extra': instance.extra,
26 | };
27 |
28 | const _$FlowNotificationPayloadItemTypeEnumMap = {
29 | FlowNotificationPayloadItemType.transaction: 'txn',
30 | FlowNotificationPayloadItemType.reminder: 'rmd',
31 | };
32 |
--------------------------------------------------------------------------------
/lib/data/github/contributor.dart:
--------------------------------------------------------------------------------
1 | /// Data class for GitHub contributor
2 | class GitHubContributor {
3 | final int id;
4 | final String login;
5 | final String avatarUrl;
6 | final int contributions;
7 | final String htmlUrl;
8 | final String nodeId;
9 |
10 | factory GitHubContributor.fromJson(Map json) {
11 | return GitHubContributor(
12 | id: json["id"] as int,
13 | login: json["login"] as String,
14 | avatarUrl: json["avatar_url"] as String,
15 | contributions: json["contributions"] as int,
16 | htmlUrl: json["html_url"] as String,
17 | nodeId: json["node_id"] as String,
18 | );
19 | }
20 | const GitHubContributor({
21 | required this.login,
22 | required this.avatarUrl,
23 | required this.contributions,
24 | required this.htmlUrl,
25 | required this.nodeId,
26 | required this.id,
27 | });
28 | }
29 |
--------------------------------------------------------------------------------
/lib/data/prefs/frecency.dart:
--------------------------------------------------------------------------------
1 | import "package:json_annotation/json_annotation.dart";
2 |
3 | part "frecency.g.dart";
4 |
5 | @JsonSerializable()
6 | class FrecencyData {
7 | final String uuid;
8 |
9 | final DateTime lastUsed;
10 |
11 | final int useCount;
12 |
13 | const FrecencyData({
14 | required this.uuid,
15 | required this.lastUsed,
16 | required this.useCount,
17 | });
18 |
19 | FrecencyData incremented([int increment = 1]) {
20 | return FrecencyData(
21 | useCount: useCount + increment,
22 | lastUsed: DateTime.now(),
23 | uuid: uuid,
24 | );
25 | }
26 |
27 | @JsonKey(includeFromJson: false, includeToJson: false)
28 | double get score {
29 | final Duration sinceLastUsed = DateTime.now().difference(lastUsed);
30 |
31 | return switch (sinceLastUsed) {
32 | >= const Duration(days: 60) => useCount * 0.2,
33 | >= const Duration(days: 30) => useCount * 0.5,
34 | >= const Duration(days: 14) => useCount * 0.67,
35 | >= const Duration(days: 7) => useCount * 0.875,
36 | >= const Duration(hours: 72) => useCount * 1.0,
37 | >= const Duration(hours: 24) => useCount * 2.0,
38 | >= const Duration(hours: 8) => useCount * 3.0,
39 | _ => useCount * 4.0,
40 | };
41 | }
42 |
43 | factory FrecencyData.fromJson(Map json) =>
44 | _$FrecencyDataFromJson(json);
45 | Map toJson() => _$FrecencyDataToJson(this);
46 | }
47 |
--------------------------------------------------------------------------------
/lib/data/prefs/frecency.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'frecency.dart';
4 |
5 | // **************************************************************************
6 | // JsonSerializableGenerator
7 | // **************************************************************************
8 |
9 | FrecencyData _$FrecencyDataFromJson(Map json) => FrecencyData(
10 | uuid: json['uuid'] as String,
11 | lastUsed: DateTime.parse(json['lastUsed'] as String),
12 | useCount: (json['useCount'] as num).toInt(),
13 | );
14 |
15 | Map _$FrecencyDataToJson(FrecencyData instance) =>
16 | {
17 | 'uuid': instance.uuid,
18 | 'lastUsed': instance.lastUsed.toIso8601String(),
19 | 'useCount': instance.useCount,
20 | };
21 |
--------------------------------------------------------------------------------
/lib/data/prefs/frecency_group.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/data/prefs/frecency.dart";
2 | import "package:flow/utils/utils.dart";
3 | import "package:json_annotation/json_annotation.dart";
4 |
5 | part "frecency_group.g.dart";
6 |
7 | @JsonSerializable()
8 | class FrecencyGroup {
9 | final List data;
10 |
11 | const FrecencyGroup(this.data);
12 |
13 | double getScore(String uuid) =>
14 | data.firstWhereOrNull((element) => element.uuid == uuid)?.score ?? 0.0;
15 |
16 | factory FrecencyGroup.fromJson(Map json) =>
17 | _$FrecencyGroupFromJson(json);
18 | Map toJson() => _$FrecencyGroupToJson(this);
19 | }
20 |
--------------------------------------------------------------------------------
/lib/data/prefs/frecency_group.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'frecency_group.dart';
4 |
5 | // **************************************************************************
6 | // JsonSerializableGenerator
7 | // **************************************************************************
8 |
9 | FrecencyGroup _$FrecencyGroupFromJson(Map json) =>
10 | FrecencyGroup(
11 | (json['data'] as List)
12 | .map((e) => FrecencyData.fromJson(e as Map))
13 | .toList(),
14 | );
15 |
16 | Map _$FrecencyGroupToJson(FrecencyGroup instance) =>
17 | {'data': instance.data};
18 |
--------------------------------------------------------------------------------
/lib/data/recurrence_mode.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/l10n/named_enum.dart";
2 | import "package:json_annotation/json_annotation.dart";
3 |
4 | @JsonEnum(valueField: "value")
5 | enum RecurrenceMode implements LocalizedEnum {
6 | everyDay("everyDay"),
7 | everyWeek("everyWeek"),
8 | every2Week("every2Week"),
9 | everyMonth("everyMonth"),
10 | everyYear("everyYear"),
11 | custom("custom");
12 |
13 | final String value;
14 |
15 | const RecurrenceMode(this.value);
16 |
17 | @override
18 | String get localizationEnumName => "RecurrenceMode";
19 |
20 | @override
21 | String get localizationEnumValue => value;
22 | }
23 |
--------------------------------------------------------------------------------
/lib/data/setup/default_accounts.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/data/flow_icon.dart";
2 | import "package:flow/entity/account.dart";
3 | import "package:flow/l10n/extensions.dart";
4 | import "package:material_symbols_icons/symbols.dart";
5 |
6 | List getAccountPresets(String currency) {
7 | return [
8 | Account.preset(
9 | name: "setup.accounts.preset.main".tr(),
10 | currency: currency,
11 | iconCode: FlowIconData.icon(Symbols.credit_card_rounded).toString(),
12 | uuid: "864df1dc-fe59-47e0-8423-98d8f86453b6",
13 | ),
14 | Account.preset(
15 | name: "setup.accounts.preset.cash".tr(),
16 | currency: currency,
17 | iconCode: FlowIconData.icon(Symbols.payments_rounded).toString(),
18 | uuid: "d7ef9672-256b-4097-a55a-27a58c6f5ba5",
19 | ),
20 | Account.preset(
21 | name: "setup.accounts.preset.savings".tr(),
22 | currency: currency,
23 | iconCode: FlowIconData.icon(Symbols.savings_rounded).toString(),
24 | excludeFromTotalBalance: true,
25 | uuid: "c04e1cdd-842f-48c1-9c6c-d07fb2b09193",
26 | ),
27 | ];
28 | }
29 |
--------------------------------------------------------------------------------
/lib/data/transactions_filter/group_range.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/entity/transaction.dart";
2 | import "package:flow/l10n/named_enum.dart";
3 | import "package:json_annotation/json_annotation.dart";
4 | import "package:moment_dart/moment_dart.dart";
5 |
6 | @JsonEnum(valueField: "value")
7 | enum TransactionGroupRange implements LocalizedEnum {
8 | hour("hour"),
9 |
10 | /// Default
11 | day("day"),
12 | week("week"),
13 | month("month"),
14 | year("year"),
15 | allTime("allTime");
16 |
17 | final String value;
18 |
19 | const TransactionGroupRange(this.value);
20 |
21 | @override
22 | String get localizationEnumName => "TransactionGroupRange";
23 |
24 | @override
25 | String get localizationEnumValue => name;
26 |
27 | TimeRange fromTransaction(Transaction t) => switch (this) {
28 | TransactionGroupRange.hour => HourTimeRange.fromDateTime(t.transactionDate),
29 | TransactionGroupRange.day => DayTimeRange.fromDateTime(t.transactionDate),
30 | TransactionGroupRange.week => LocalWeekTimeRange(t.transactionDate),
31 | TransactionGroupRange.month => MonthTimeRange.fromDateTime(
32 | t.transactionDate,
33 | ),
34 | TransactionGroupRange.year => YearTimeRange.fromDateTime(t.transactionDate),
35 | TransactionGroupRange.allTime => TimeRange.allTime(),
36 | };
37 | }
38 |
--------------------------------------------------------------------------------
/lib/data/transactions_filter/search_data.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'search_data.dart';
4 |
5 | // **************************************************************************
6 | // JsonSerializableGenerator
7 | // **************************************************************************
8 |
9 | TransactionSearchData _$TransactionSearchDataFromJson(
10 | Map json,
11 | ) => TransactionSearchData(
12 | keyword: json['keyword'] as String?,
13 | mode:
14 | $enumDecodeNullable(_$TransactionSearchModeEnumMap, json['mode']) ??
15 | TransactionSearchMode.smart,
16 | smartMatchThreshold:
17 | (json['smartMatchThreshold'] as num?)?.toDouble() ?? 80.0,
18 | includeDescription: json['includeDescription'] as bool? ?? true,
19 | );
20 |
21 | Map _$TransactionSearchDataToJson(
22 | TransactionSearchData instance,
23 | ) => {
24 | 'keyword': instance.keyword,
25 | 'mode': _$TransactionSearchModeEnumMap[instance.mode]!,
26 | 'includeDescription': instance.includeDescription,
27 | 'smartMatchThreshold': instance.smartMatchThreshold,
28 | };
29 |
30 | const _$TransactionSearchModeEnumMap = {
31 | TransactionSearchMode.smart: 'smart',
32 | TransactionSearchMode.substring: 'substring',
33 | TransactionSearchMode.exact: 'exact',
34 | TransactionSearchMode.none: 'none',
35 | };
36 |
--------------------------------------------------------------------------------
/lib/data/transactions_filter/sort_field.dart:
--------------------------------------------------------------------------------
1 | import "package:json_annotation/json_annotation.dart";
2 |
3 | @JsonEnum(valueField: "value")
4 | enum TransactionSortField {
5 | /// Default
6 | transactionDate("transactionDate"),
7 | amount("amount"),
8 | createdDate("createdDate");
9 |
10 | final String value;
11 |
12 | const TransactionSortField(this.value);
13 | }
14 |
--------------------------------------------------------------------------------
/lib/entity/_base.dart:
--------------------------------------------------------------------------------
1 | import "package:objectbox/objectbox.dart";
2 |
3 | abstract class EntityBase {
4 | String get uuid;
5 | }
6 |
7 | extension ToOneRelationSerializer on ToOne {
8 | String? relationToJson() => target?.uuid;
9 | String relationToJsonForced() => target!.uuid;
10 | }
11 |
--------------------------------------------------------------------------------
/lib/entity/category.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'category.dart';
4 |
5 | // **************************************************************************
6 | // JsonSerializableGenerator
7 | // **************************************************************************
8 |
9 | Category _$CategoryFromJson(Map json) => Category(
10 | name: json['name'] as String,
11 | iconCode: json['iconCode'] as String,
12 | createdDate: _$JsonConverterFromJson(
13 | json['createdDate'],
14 | const UTCDateTimeConverter().fromJson,
15 | ),
16 | )..uuid = json['uuid'] as String;
17 |
18 | Map _$CategoryToJson(Category instance) => {
19 | 'uuid': instance.uuid,
20 | 'createdDate': const UTCDateTimeConverter().toJson(instance.createdDate),
21 | 'name': instance.name,
22 | 'iconCode': instance.iconCode,
23 | };
24 |
25 | Value? _$JsonConverterFromJson(
26 | Object? json,
27 | Value? Function(Json json) fromJson,
28 | ) => json == null ? null : fromJson(json as Json);
29 |
--------------------------------------------------------------------------------
/lib/entity/profile.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/entity/_base.dart";
2 | import "package:flow/objectbox.dart";
3 | import "package:flow/utils/json/utc_datetime_converter.dart";
4 | import "package:json_annotation/json_annotation.dart";
5 | import "package:objectbox/objectbox.dart";
6 | import "package:uuid/uuid.dart";
7 |
8 | part "profile.g.dart";
9 |
10 | @Entity()
11 | @JsonSerializable(explicitToJson: true, converters: [UTCDateTimeConverter()])
12 | class Profile implements EntityBase {
13 | @JsonKey(includeFromJson: false, includeToJson: false)
14 | int id;
15 |
16 | @override
17 | @Unique()
18 | String uuid;
19 |
20 | static const int maxNameLength = 96;
21 |
22 | String name;
23 |
24 | @Property(type: PropertyType.date)
25 | DateTime createdDate;
26 |
27 | @Transient()
28 | String get imagePath => "$uuid.png";
29 |
30 | Profile({this.id = 0, DateTime? createdDate, required this.name})
31 | : createdDate = createdDate ?? DateTime.now(),
32 | uuid = const Uuid().v4();
33 |
34 | factory Profile.fromJson(Map json) =>
35 | _$ProfileFromJson(json);
36 | Map toJson() => _$ProfileToJson(this);
37 |
38 | static void createDefaultProfile() {
39 | ObjectBox().box().put(Profile(name: "Default Profile"));
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/lib/entity/profile.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'profile.dart';
4 |
5 | // **************************************************************************
6 | // JsonSerializableGenerator
7 | // **************************************************************************
8 |
9 | Profile _$ProfileFromJson(Map json) => Profile(
10 | createdDate: _$JsonConverterFromJson(
11 | json['createdDate'],
12 | const UTCDateTimeConverter().fromJson,
13 | ),
14 | name: json['name'] as String,
15 | )..uuid = json['uuid'] as String;
16 |
17 | Map _$ProfileToJson(Profile instance) => {
18 | 'uuid': instance.uuid,
19 | 'name': instance.name,
20 | 'createdDate': const UTCDateTimeConverter().toJson(instance.createdDate),
21 | };
22 |
23 | Value? _$JsonConverterFromJson(
24 | Object? json,
25 | Value? Function(Json json) fromJson,
26 | ) => json == null ? null : fromJson(json as Json);
27 |
--------------------------------------------------------------------------------
/lib/entity/transaction/extensions/base.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/utils/jasonable.dart";
2 |
3 | abstract class TransactionExtension implements Jasonable {
4 | final String uuid;
5 |
6 | String get extensionExistenceTag => "hasExtension:$key";
7 | String get extensionIdentifierTag => "$key:$uuid";
8 |
9 | String get key;
10 | String? get relatedTransactionUuid;
11 | set relatedTransactionUuid(String? uuid);
12 |
13 | void setRelatedTransactionUuid(String uuid) =>
14 | relatedTransactionUuid = relatedTransactionUuid;
15 |
16 | const TransactionExtension({required this.uuid});
17 | }
18 |
--------------------------------------------------------------------------------
/lib/entity/transaction/extensions/default/recurring.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'recurring.dart';
4 |
5 | // **************************************************************************
6 | // JsonSerializableGenerator
7 | // **************************************************************************
8 |
9 | Recurring _$RecurringFromJson(Map json) => Recurring(
10 | uuid: json['uuid'] as String,
11 | initialTransactionDate: DateTime.parse(
12 | json['initialTransactionDate'] as String,
13 | ),
14 | relatedTransactionUuid: json['relatedTransactionUuid'] as String?,
15 | locked: json['locked'] as bool? ?? false,
16 | );
17 |
18 | Map _$RecurringToJson(Recurring instance) => {
19 | 'uuid': instance.uuid,
20 | 'relatedTransactionUuid': instance.relatedTransactionUuid,
21 | 'initialTransactionDate': instance.initialTransactionDate.toIso8601String(),
22 | 'locked': instance.locked,
23 | 'key': instance.key,
24 | };
25 |
--------------------------------------------------------------------------------
/lib/entity/transaction/extensions/default/transfer.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'transfer.dart';
4 |
5 | // **************************************************************************
6 | // JsonSerializableGenerator
7 | // **************************************************************************
8 |
9 | Transfer _$TransferFromJson(Map json) => Transfer(
10 | uuid: json['uuid'] as String,
11 | fromAccountUuid: json['fromAccountUuid'] as String,
12 | toAccountUuid: json['toAccountUuid'] as String,
13 | relatedTransactionUuid: json['relatedTransactionUuid'] as String?,
14 | conversionRate: (json['conversionRate'] as num?)?.toDouble(),
15 | );
16 |
17 | Map _$TransferToJson(Transfer instance) => {
18 | 'uuid': instance.uuid,
19 | 'key': instance.key,
20 | 'fromAccountUuid': instance.fromAccountUuid,
21 | 'toAccountUuid': instance.toAccountUuid,
22 | 'conversionRate': instance.conversionRate,
23 | 'relatedTransactionUuid': instance.relatedTransactionUuid,
24 | };
25 |
--------------------------------------------------------------------------------
/lib/entity/transaction/subtype.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/l10n/named_enum.dart";
2 | import "package:json_annotation/json_annotation.dart";
3 |
4 | @JsonEnum(valueField: "value")
5 | enum TransactionSubtype implements LocalizedEnum {
6 | transactionFee("transactionFee"),
7 | givenLoan("loan.given"),
8 | receivedLoan("loan.received"),
9 | updateBalance("updateBalance");
10 |
11 | final String value;
12 |
13 | const TransactionSubtype(this.value);
14 |
15 | @override
16 | String get localizationEnumValue => name;
17 | @override
18 | String get localizationEnumName => "TransactionSubtype";
19 | }
20 |
--------------------------------------------------------------------------------
/lib/entity/transaction/type.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/l10n/named_enum.dart";
2 | import "package:json_annotation/json_annotation.dart";
3 |
4 | @JsonEnum(valueField: "value")
5 | enum TransactionType implements LocalizedEnum {
6 | transfer("transfer"),
7 | income("income"),
8 | expense("expense");
9 |
10 | final String value;
11 |
12 | const TransactionType(this.value);
13 |
14 | @override
15 | String get localizationEnumValue => name;
16 | @override
17 | String get localizationEnumName => "TransactionType";
18 | }
19 |
--------------------------------------------------------------------------------
/lib/entity/transaction_filter_preset.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'transaction_filter_preset.dart';
4 |
5 | // **************************************************************************
6 | // JsonSerializableGenerator
7 | // **************************************************************************
8 |
9 | TransactionFilterPreset _$TransactionFilterPresetFromJson(
10 | Map json,
11 | ) => TransactionFilterPreset(
12 | createdDate: _$JsonConverterFromJson(
13 | json['createdDate'],
14 | const UTCDateTimeConverter().fromJson,
15 | ),
16 | jsonTransactionFilter: json['jsonTransactionFilter'] as String,
17 | name: json['name'] as String,
18 | )..uuid = json['uuid'] as String;
19 |
20 | Map _$TransactionFilterPresetToJson(
21 | TransactionFilterPreset instance,
22 | ) => {
23 | 'uuid': instance.uuid,
24 | 'name': instance.name,
25 | 'jsonTransactionFilter': instance.jsonTransactionFilter,
26 | 'createdDate': const UTCDateTimeConverter().toJson(instance.createdDate),
27 | };
28 |
29 | Value? _$JsonConverterFromJson(
30 | Object? json,
31 | Value? Function(Json json) fromJson,
32 | ) => json == null ? null : fromJson(json as Json);
33 |
--------------------------------------------------------------------------------
/lib/form_validators.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/l10n/extensions.dart";
2 |
3 | String? validateRequiredField(String? input) {
4 | if (input == null || input.isEmpty || input.trim().isEmpty) {
5 | return "error.input.mustBeNotEmpty".tr();
6 | }
7 |
8 | return null;
9 | }
10 |
--------------------------------------------------------------------------------
/lib/l10n/extensions.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/l10n/flow_localizations.dart";
2 | import "package:flow/l10n/supported_languages.dart";
3 | import "package:flutter/widgets.dart";
4 |
5 | extension L10nHelper on BuildContext {
6 | FlowLocalizations get l => FlowLocalizations.of(this);
7 | }
8 |
9 | extension Underscore on Locale {
10 | /// Example outcome:
11 | /// * en
12 | /// * fr_FR
13 | /// * mn_Mong_MN
14 | String get code => [languageCode, scriptCode, countryCode].nonNulls.join("_");
15 |
16 | /// English name
17 | String get name => supportedLanguages[this]?.$1 ?? "Unknown";
18 |
19 | /// Language name in the language
20 | String get endonym => supportedLanguages[this]?.$2 ?? "Unknown";
21 | }
22 |
23 | extension L10nStringHelper on String {
24 | /// Returns localized version of [this].
25 | ///
26 | /// Same as calling context.l.get([this])
27 | String t(BuildContext context, [dynamic replace]) =>
28 | context.l.get(this, replace: replace);
29 |
30 | /// Returns localized version of [this].
31 | ///
32 | /// This does not require a context
33 | String tr([dynamic replace]) =>
34 | FlowLocalizations.getTransalation(this, replace: replace);
35 | }
36 |
--------------------------------------------------------------------------------
/lib/l10n/localized_exception.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/l10n/extensions.dart";
2 | import "package:flutter/material.dart";
3 |
4 | abstract class LocalizedException {
5 | final String l10nKey;
6 | final dynamic l10nArgs;
7 |
8 | String localizedString(BuildContext context) => l10nKey.t(context, l10nArgs);
9 |
10 | const LocalizedException({required this.l10nKey, this.l10nArgs});
11 | }
12 |
--------------------------------------------------------------------------------
/lib/l10n/named_enum.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/l10n/extensions.dart";
2 | import "package:flutter/material.dart";
3 |
4 | abstract class LocalizedEnum {
5 | String get localizationEnumValue;
6 | String get localizationEnumName;
7 | }
8 |
9 | extension LocalizedNameEnums on LocalizedEnum {
10 | String get localizedTextKey =>
11 | "enum.$localizationEnumName@$localizationEnumValue";
12 |
13 | String get localizedName => localizedTextKey.tr();
14 | String localizedNameContext(BuildContext context, [dynamic replace]) =>
15 | localizedTextKey.t(context, replace);
16 | }
17 |
--------------------------------------------------------------------------------
/lib/l10n/supported_languages.dart:
--------------------------------------------------------------------------------
1 | import "dart:ui";
2 |
3 | /// Locale - (English name, Endonym)
4 | ///
5 | /// * You have to include a country if the [Locale.countryCode] is not null.
6 | /// * Your file name must match `languageCode_scriptCode_countryCode` format. But both `scriptCode` and `countryCode` is optional.
7 | final Map supportedLanguages = {
8 | const Locale("mn", "MN"): ("Mongolian (Mongolia)", "Монгол (Монгол)"),
9 | const Locale("en"): ("English", "English"),
10 | const Locale("it", "IT"): ("Italian (Italy)", "Italiano (Italia)"),
11 | const Locale("tr", "TR"): ("Turkish (Turkey)", "Türkçe (Türkiye)"),
12 | const Locale("fr", "FR"): ("French (France)", "Français (France)"),
13 | const Locale("de", "DE"): ("German (Germany)", "Deutsch (Deutschland)"),
14 | const Locale("ru", "RU"): ("Russian (Russia)", "Русский (Россия)"),
15 | const Locale("es", "ES"): ("Spanish (Spain)", "Español (España)"),
16 | const Locale("ar"): ("Arabic", "العربية"),
17 | };
18 |
--------------------------------------------------------------------------------
/lib/logging.dart:
--------------------------------------------------------------------------------
1 | import "package:logging/logging.dart";
2 |
3 | final Logger mainLogger = Logger("Flow");
4 |
5 | final Logger startupLog = Logger("Flow Startup");
6 | final Logger themeLogger = Logger("Theme");
7 |
8 | final Logger syncLogger = Logger("Flow Sync");
9 |
--------------------------------------------------------------------------------
/lib/prefs/theme.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/theme/color_themes/registry.dart";
2 | import "package:local_settings/local_settings.dart";
3 | import "package:shared_preferences/shared_preferences.dart";
4 |
5 | class ThemeLocalPreferences {
6 | final SharedPreferencesWithCache _prefs;
7 |
8 | static ThemeLocalPreferences? _instance;
9 |
10 | factory ThemeLocalPreferences(SharedPreferences prefs) {
11 | if (_instance == null) {
12 | throw Exception(
13 | "You must initialize ThemeLocalPreferences by calling initialize().",
14 | );
15 | }
16 |
17 | return _instance!;
18 | }
19 |
20 | late final PrimitiveSettingsEntry themeName;
21 | late final BoolSettingsEntry themeChangesAppIcon;
22 |
23 | ThemeLocalPreferences._internal(this._prefs) {
24 | SettingsEntry.defaultPrefix = "flow.";
25 |
26 | themeName = PrimitiveSettingsEntry(
27 | key: "themeName",
28 | preferences: _prefs,
29 | initialValue: flowLights.schemes.first.name,
30 | );
31 | themeChangesAppIcon = BoolSettingsEntry(
32 | key: "themeChangesAppIcon",
33 | preferences: _prefs,
34 | initialValue: true,
35 | );
36 | }
37 |
38 | static ThemeLocalPreferences initialize(
39 | SharedPreferencesWithCache instance,
40 | ) => _instance ??= ThemeLocalPreferences._internal(instance);
41 | }
42 |
--------------------------------------------------------------------------------
/lib/routes/preferences/sections/haptics.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/l10n/extensions.dart";
2 | import "package:flow/prefs/local_preferences.dart";
3 | import "package:flow/routes/preferences_page.dart";
4 | import "package:flutter/material.dart";
5 | import "package:material_symbols_icons/symbols.dart";
6 |
7 | class Haptics extends StatefulWidget {
8 | const Haptics({super.key});
9 |
10 | @override
11 | State createState() => _HapticsState();
12 | }
13 |
14 | class _HapticsState extends State {
15 | @override
16 | Widget build(BuildContext context) {
17 | final bool enableHapticFeedback = LocalPreferences().enableHapticFeedback
18 | .get();
19 |
20 | return Column(
21 | mainAxisSize: MainAxisSize.min,
22 | children: [
23 | SwitchListTile(
24 | secondary: const Icon(Symbols.vibration_rounded),
25 | title: Text("preferences.hapticFeedback.description".t(context)),
26 | value: enableHapticFeedback,
27 | onChanged: updateEnableHapticFeedback,
28 | ),
29 | ],
30 | );
31 | }
32 |
33 | void updateEnableHapticFeedback(bool? newEnableHapticFeedback) async {
34 | if (newEnableHapticFeedback == null) return;
35 |
36 | await LocalPreferences().enableHapticFeedback.set(newEnableHapticFeedback);
37 |
38 | if (!mounted) return;
39 |
40 | PreferencesPage.of(context).reload();
41 | setState(() {});
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/lib/routes/preferences/sections/privacy.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/l10n/extensions.dart";
2 | import "package:flow/prefs/local_preferences.dart";
3 | import "package:flow/routes/preferences_page.dart";
4 | import "package:flutter/material.dart";
5 | import "package:material_symbols_icons/symbols.dart";
6 |
7 | class Privacy extends StatefulWidget {
8 | const Privacy({super.key});
9 |
10 | @override
11 | State createState() => _PrivacyState();
12 | }
13 |
14 | class _PrivacyState extends State {
15 | @override
16 | Widget build(BuildContext context) {
17 | final bool privacyMode = LocalPreferences().privacyMode.get();
18 |
19 | return SwitchListTile(
20 | secondary: const Icon(Symbols.password_rounded),
21 | title: Text("preferences.privacy.maskAtStartup".t(context)),
22 | value: privacyMode,
23 | onChanged: updatePrivacyMode,
24 | );
25 | }
26 |
27 | void updatePrivacyMode(bool? newPrivacyMode) async {
28 | if (newPrivacyMode == null) return;
29 |
30 | await LocalPreferences().privacyMode.set(newPrivacyMode);
31 |
32 | if (!mounted) return;
33 |
34 | PreferencesPage.of(context).reload();
35 | setState(() {});
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/lib/routes/transaction_page/section.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/theme/theme.dart";
2 | import "package:flow/widgets/general/frame.dart";
3 | import "package:flutter/material.dart";
4 |
5 | class Section extends StatelessWidget {
6 | final String? title;
7 | final Widget child;
8 | final Widget? titleOverride;
9 |
10 | const Section({
11 | super.key,
12 | this.title,
13 | this.titleOverride,
14 | required this.child,
15 | });
16 |
17 | @override
18 | Widget build(BuildContext context) {
19 | return Column(
20 | mainAxisSize: MainAxisSize.min,
21 | children: [
22 | Align(
23 | alignment: AlignmentDirectional.topStart,
24 | child: DefaultTextStyle(
25 | style: context.textTheme.labelMedium!.semi(context),
26 | child: Frame(child: titleOverride ?? Text(title ?? "A section")),
27 | ),
28 | ),
29 | child,
30 | ],
31 | );
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/lib/services/accounts.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/entity/account.dart";
2 | import "package:flow/objectbox.dart";
3 | import "package:flow/objectbox/objectbox.g.dart";
4 |
5 | class AccountsService {
6 | static AccountsService? _instance;
7 |
8 | factory AccountsService() => _instance ??= AccountsService._internal();
9 |
10 | AccountsService._internal() {
11 | // Constructor
12 | }
13 |
14 | Future getOne(int id) async {
15 | return ObjectBox().box().getAsync(id);
16 | }
17 |
18 | Future> getAll() async {
19 | return ObjectBox().box().getAllAsync();
20 | }
21 |
22 | Future findOne(dynamic identifier) async {
23 | if (identifier is int) {
24 | return await getOne(identifier);
25 | }
26 |
27 | if (identifier case String uuid) {
28 | final q = ObjectBox()
29 | .box()
30 | .query(Account_.uuid.equals(uuid))
31 | .build();
32 |
33 | final Account? result = await q.findFirstAsync();
34 |
35 | q.close();
36 | return result;
37 | }
38 |
39 | return null;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/lib/sync/exception.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/l10n/localized_exception.dart";
2 | import "package:flow/sync/sync.dart";
3 |
4 | class ImportException extends LocalizedException implements Exception {
5 | final String message;
6 |
7 | /// Sync Model version
8 | final int versionCode;
9 |
10 | const ImportException(
11 | this.message, {
12 | this.versionCode = latestSyncModelVersion,
13 | super.l10nKey = "error.unknown",
14 | super.l10nArgs,
15 | });
16 |
17 | @override
18 | String toString() {
19 | return "[Flow Sync Import v$versionCode] $message";
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/lib/sync/export/export_csv/header_v1.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/l10n/named_enum.dart";
2 |
3 | enum CSVHeader implements LocalizedEnum {
4 | uuid,
5 | title,
6 | notes,
7 | amount,
8 | currency,
9 | account,
10 | accountUuid,
11 | category,
12 | categoryUuid,
13 | type,
14 | subtype,
15 | createdDate,
16 | transactionDate,
17 | transactionDateIso8601,
18 | latitude,
19 | longitude,
20 | extra;
21 |
22 | @override
23 | String get localizationEnumValue => name;
24 | @override
25 | String get localizationEnumName => "CSVHeader";
26 | }
27 |
--------------------------------------------------------------------------------
/lib/sync/export/export_pdf/headers.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/l10n/named_enum.dart";
2 |
3 | enum PDFHeader implements LocalizedEnum {
4 | transactionDate,
5 | title,
6 | amount,
7 | account,
8 | category;
9 |
10 | @override
11 | String get localizationEnumValue => name;
12 | @override
13 | String get localizationEnumName => "PDFHeader";
14 | }
15 |
--------------------------------------------------------------------------------
/lib/sync/export/mode.dart:
--------------------------------------------------------------------------------
1 | enum ExportMode {
2 | /// Cannot be recovered from
3 | ///
4 | /// Intended for using in more complex software like Google Sheets
5 | csv(fileExt: "csv"),
6 |
7 | /// Can be fully recovered from
8 | ///
9 | /// Intended for full backups. Will be versioned, we plan to support
10 | /// importing older backups to newer versions.
11 | json(fileExt: "json"),
12 |
13 | /// Can be fully recovered from
14 | ///
15 | /// Includes [json] inside it, plus other files like images that cannot be
16 | /// fit into a JSON file.
17 | zip(fileExt: "zip"),
18 |
19 | /// Cannot be recovered from
20 | ///
21 | /// A non-official statement (kinda like bank statements)
22 | pdf(fileExt: "pdf");
23 |
24 | final String fileExt;
25 |
26 | const ExportMode({required this.fileExt});
27 |
28 | static ExportMode? tryParse(String value) {
29 | switch (value.toLowerCase()) {
30 | case "csv":
31 | return ExportMode.csv;
32 | case "json":
33 | return ExportMode.json;
34 | case "zip":
35 | return ExportMode.zip;
36 | case "pdf":
37 | return ExportMode.pdf;
38 | default:
39 | return null;
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/lib/sync/import/base.dart:
--------------------------------------------------------------------------------
1 | import "package:flutter/material.dart";
2 |
3 | abstract class Importer {
4 | T get data;
5 | ValueNotifier get progressNotifier;
6 |
7 | /// Before starting the import, it'll perform a safety backup, stored in
8 | /// `automated_backups` subfolder. If safety backups fails, will immediately
9 | /// halt, without making any changes to the state. You can alter this
10 | /// behaviour by setting [ignoreSafetyBackupFail] to true.
11 | ///
12 | /// Returns the path of the safety backup file.
13 | ///
14 | /// [ignoreSafetyBackupFail] - Forces to proceed in the import if safety
15 | /// backup fails
16 | Future execute({bool ignoreSafetyBackupFail = false});
17 | }
18 |
--------------------------------------------------------------------------------
/lib/sync/model/base.dart:
--------------------------------------------------------------------------------
1 | abstract class SyncModelBase {
2 | /// Version code for backup package. Useful for backwards-compatibility.
3 | /// We will increment this every time we make breaking changes to the structure.
4 | ///
5 | /// For example, let's say we changed the field name of two properties on
6 | /// [Transaction] entity. Now suddenly all the backups we made before this
7 | /// change couldn't be imported.
8 | ///
9 | /// We will ensure old data will be imported without any hassle.
10 | final int versionCode;
11 |
12 | /// Date and time of the export
13 | final DateTime exportDate;
14 |
15 | /// Current user's name
16 | final String username;
17 |
18 | /// Version of the app performed this backup
19 | final String appVersion;
20 |
21 | const SyncModelBase({
22 | required this.versionCode,
23 | required this.exportDate,
24 | required this.username,
25 | required this.appVersion,
26 | });
27 | }
28 |
--------------------------------------------------------------------------------
/lib/sync/model/model_v1.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/entity/account.dart";
2 | import "package:flow/entity/category.dart";
3 | import "package:flow/entity/transaction.dart";
4 | import "package:flow/sync/model/base.dart";
5 | import "package:json_annotation/json_annotation.dart";
6 |
7 | part "model_v1.g.dart";
8 |
9 | @JsonSerializable()
10 | class SyncModelV1 extends SyncModelBase {
11 | final List transactions;
12 | final List accounts;
13 | final List categories;
14 |
15 | const SyncModelV1({
16 | required super.versionCode,
17 | required super.exportDate,
18 | required super.username,
19 | required super.appVersion,
20 | required this.transactions,
21 | required this.accounts,
22 | required this.categories,
23 | });
24 |
25 | factory SyncModelV1.fromJson(Map json) =>
26 | _$SyncModelV1FromJson(json);
27 | Map toJson() => _$SyncModelV1ToJson(this);
28 | }
29 |
--------------------------------------------------------------------------------
/lib/sync/model/model_v1.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'model_v1.dart';
4 |
5 | // **************************************************************************
6 | // JsonSerializableGenerator
7 | // **************************************************************************
8 |
9 | SyncModelV1 _$SyncModelV1FromJson(Map json) => SyncModelV1(
10 | versionCode: (json['versionCode'] as num).toInt(),
11 | exportDate: DateTime.parse(json['exportDate'] as String),
12 | username: json['username'] as String,
13 | appVersion: json['appVersion'] as String,
14 | transactions: (json['transactions'] as List)
15 | .map((e) => Transaction.fromJson(e as Map))
16 | .toList(),
17 | accounts: (json['accounts'] as List)
18 | .map((e) => Account.fromJson(e as Map))
19 | .toList(),
20 | categories: (json['categories'] as List)
21 | .map((e) => Category.fromJson(e as Map))
22 | .toList(),
23 | );
24 |
25 | Map _$SyncModelV1ToJson(SyncModelV1 instance) =>
26 | {
27 | 'versionCode': instance.versionCode,
28 | 'exportDate': instance.exportDate.toIso8601String(),
29 | 'username': instance.username,
30 | 'appVersion': instance.appVersion,
31 | 'transactions': instance.transactions,
32 | 'accounts': instance.accounts,
33 | 'categories': instance.categories,
34 | };
35 |
--------------------------------------------------------------------------------
/lib/sync/sync.dart:
--------------------------------------------------------------------------------
1 | export "import.dart";
2 | export "export.dart";
3 |
4 | /// To be increased with everytime there's change
5 | /// in the structure of the database model.
6 | const int latestSyncModelVersion = 2;
7 |
--------------------------------------------------------------------------------
/lib/theme/color_themes/catppuccin/frappe.json:
--------------------------------------------------------------------------------
1 | [
2 | ["Flamingo", "0xffeebebe"],
3 | ["Rosewater", "0xfff2d5cf"],
4 | ["Mauve", "0xffca9ee6"],
5 | ["Pink", "0xfff4b8e4"],
6 | ["Red", "0xffe78284"],
7 | ["Maroon", "0xffea999c"],
8 | ["Peach", "0xffef9f76"],
9 | ["Yellow", "0xffe5c890"],
10 | ["Green", "0xffa6d189"],
11 | ["Teal", "0xff81c8be"],
12 | ["Sky", "0xff99d1db"],
13 | ["Sapphire", "0xff85c1dc"],
14 | ["Blue", "0xff8caaee"],
15 | ["Lavender", "0xffbabbf1"],
16 | ["Text", "0xffc6d0f5"],
17 | ["Subtext 1", "0xffb5bfe2"],
18 | ["Subtext 0", "0xffa5adce"],
19 | ["Overlay 2", "0xff949cbb"],
20 | ["Overlay 1", "0xff838ba7"],
21 | ["Overlay 0", "0xff737994"],
22 | ["Surface 2", "0xff626880"],
23 | ["Surface 1", "0xff51576d"],
24 | ["Surface 0", "0xff414559"],
25 | ["Base", "0xff303446"],
26 | ["Mantle", "0xff292c3c"],
27 | ["Crust", "0xff232634"]
28 | ]
29 |
--------------------------------------------------------------------------------
/lib/theme/color_themes/catppuccin/macchiato.json:
--------------------------------------------------------------------------------
1 | [
2 | ["Flamingo", "0xfff0c6c6"],
3 | ["Rosewater", "0xfff4dbd6"],
4 | ["Mauve", "0xffc6a0f6"],
5 | ["Pink", "0xfff5bde6"],
6 | ["Red", "0xffed8796"],
7 | ["Maroon", "0xffee99a0"],
8 | ["Peach", "0xfff5a97f"],
9 | ["Yellow", "0xffeed49f"],
10 | ["Green", "0xffa6da95"],
11 | ["Teal", "0xff8bd5ca"],
12 | ["Sky", "0xff91d7e3"],
13 | ["Sapphire", "0xff7dc4e4"],
14 | ["Blue", "0xff8aadf4"],
15 | ["Lavender", "0xffb7bdf8"],
16 | ["Text", "0xffcad3f5"],
17 | ["Subtext 1", "0xffb8c0e0"],
18 | ["Subtext 0", "0xffa5adcb"],
19 | ["Overlay 2", "0xff939ab7"],
20 | ["Overlay 1", "0xff8087a2"],
21 | ["Overlay 0", "0xff6e738d"],
22 | ["Surface 2", "0xff5b6078"],
23 | ["Surface 1", "0xff494d64"],
24 | ["Surface 0", "0xff363a4f"],
25 | ["Base", "0xff24273a"],
26 | ["Mantle", "0xff1e2030"],
27 | ["Crust", "0xff181926"]
28 | ]
29 |
--------------------------------------------------------------------------------
/lib/theme/color_themes/catppuccin/mocha.json:
--------------------------------------------------------------------------------
1 | [
2 | ["Flamingo", "0xfff2cdcd"],
3 | ["Rosewater", "0xfff5e0dc"],
4 | ["Mauve", "0xffcba6f7"],
5 | ["Pink", "0xfff5c2e7"],
6 | ["Red", "0xfff38ba8"],
7 | ["Maroon", "0xffeba0ac"],
8 | ["Peach", "0xfffab387"],
9 | ["Yellow", "0xfff9e2af"],
10 | ["Green", "0xffa6e3a1"],
11 | ["Teal", "0xff94e2d5"],
12 | ["Sky", "0xff89dceb"],
13 | ["Sapphire", "0xff74c7ec"],
14 | ["Blue", "0xff89b4fa"],
15 | ["Lavender", "0xffb4befe"],
16 | ["Text", "0xffcdd6f4"],
17 | ["Subtext 1", "0xffbac2de"],
18 | ["Subtext 0", "0xffa6adc8"],
19 | ["Overlay 2", "0xff9399b2"],
20 | ["Overlay 1", "0xff7f849c"],
21 | ["Overlay 0", "0xff6c7086"],
22 | ["Surface 2", "0xff585b70"],
23 | ["Surface 1", "0xff45475a"],
24 | ["Surface 0", "0xff313244"],
25 | ["Base", "0xff1e1e2e"],
26 | ["Mantle", "0xff181825"],
27 | ["Crust", "0xff11111b"]
28 | ]
29 |
--------------------------------------------------------------------------------
/lib/theme/color_themes/palenight.dart:
--------------------------------------------------------------------------------
1 | import "dart:ui";
2 |
3 | import "package:flow/theme/flow_color_scheme.dart";
4 |
5 | final FlowColorScheme palenight = FlowColorScheme(
6 | name: "palenight",
7 | isDark: true,
8 | surface: const Color(0xff292D3E),
9 | onSurface: const Color(0xfff5f6fa),
10 | primary: const Color(0xfff5f6fa),
11 | onPrimary: const Color(0xff444267),
12 | secondary: const Color(0xff202331),
13 | onSecondary: const Color(0xfff5f6fa),
14 | customColors: FlowCustomColors(
15 | income: Color(0xFFc3e88d),
16 | expense: Color(0xFFf07178),
17 | semi: Color(0xFF676E95),
18 | ),
19 | );
20 |
--------------------------------------------------------------------------------
/lib/theme/flow_custom_colors.dart:
--------------------------------------------------------------------------------
1 | import "package:flutter/material.dart";
2 |
3 | class FlowCustomColors extends ThemeExtension {
4 | /// Color for income
5 | final Color income;
6 |
7 | /// Color for expense
8 | final Color expense;
9 |
10 | /// Color for labels, secondary body texts
11 | final Color semi;
12 |
13 | const FlowCustomColors({
14 | required this.income,
15 | required this.expense,
16 | required this.semi,
17 | });
18 |
19 | @override
20 | FlowCustomColors copyWith({Color? income, Color? expense, Color? semi}) {
21 | return FlowCustomColors(
22 | income: income ?? this.income,
23 | expense: expense ?? this.expense,
24 | semi: semi ?? this.semi,
25 | );
26 | }
27 |
28 | @override
29 | FlowCustomColors lerp(FlowCustomColors? other, double t) {
30 | if (other is! FlowCustomColors) return this;
31 |
32 | return FlowCustomColors(
33 | income: Color.lerp(income, other.income, t)!,
34 | expense: Color.lerp(expense, other.expense, t)!,
35 | semi: Color.lerp(semi, other.semi, t)!,
36 | );
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/lib/theme/flow_theme_group.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/data/flow_icon.dart";
2 | import "package:flow/theme/flow_color_scheme.dart";
3 |
4 | class FlowThemeGroup {
5 | final String name;
6 | final FlowIconData? icon;
7 |
8 | final List schemes;
9 |
10 | const FlowThemeGroup({required this.schemes, required this.name, this.icon});
11 |
12 | Map get schemesMap {
13 | final Map map = {};
14 |
15 | for (final FlowColorScheme scheme in schemes) {
16 | map[scheme.name] = scheme;
17 | }
18 |
19 | return map;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/lib/theme/pie_theme_extension.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/logging.dart";
2 | import "package:flutter/material.dart";
3 | import "package:pie_menu/pie_menu.dart";
4 |
5 | class PieThemeExtension extends ThemeExtension {
6 | final PieTheme pieTheme;
7 |
8 | const PieThemeExtension({required this.pieTheme});
9 |
10 | @override
11 | ThemeExtension copyWith({PieTheme? pieTheme}) {
12 | return PieThemeExtension(pieTheme: pieTheme ?? this.pieTheme);
13 | }
14 |
15 | @override
16 | ThemeExtension lerp(
17 | ThemeExtension? other,
18 | double t,
19 | ) {
20 | mainLogger.warning(
21 | "[PieThemeExtension] lerp is not available for PieTheme",
22 | );
23 |
24 | return (t < 0.5 ? this : other) as PieThemeExtension;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/lib/utils/csv_parser.dart:
--------------------------------------------------------------------------------
1 | import "dart:convert";
2 | import "dart:io";
3 | import "dart:typed_data";
4 | import "package:charset/charset.dart";
5 | import "package:csv/csv.dart";
6 | import "package:flow/utils/line_break_normalizer.dart";
7 |
8 | Future> parseCsvFromFile(File file) async {
9 | final Uint8List bytes = file.readAsBytesSync();
10 |
11 | String? parsed;
12 |
13 | try {
14 | parsed = utf8.decode(bytes);
15 | } catch (e) {
16 | // Silent fail
17 | }
18 |
19 | if (parsed == null) {
20 | try {
21 | parsed = utf16.decode(bytes);
22 | } catch (e) {
23 | // Silent fail
24 | }
25 | }
26 |
27 | if (parsed == null) {
28 | try {
29 | parsed = utf32.decode(bytes);
30 | } catch (e) {
31 | // Silent fail
32 | }
33 | }
34 |
35 | if (parsed == null) {
36 | try {
37 | parsed = latin1.decode(bytes);
38 | } catch (e) {
39 | // Silent fail
40 | }
41 | }
42 |
43 | if (parsed == null) {
44 | throw Exception(
45 | "Unsupported text encoding. Please provide a CSV with one of following encodings: ascii, utf8, utf16, utf32, latin1",
46 | );
47 | }
48 |
49 | final String lineBreaksNormalized = LineBreakNormalizer.normalize(parsed);
50 |
51 | return CsvToListConverter(
52 | eol: LineBreakNormalizer.terminator,
53 | ).convert(lineBreaksNormalized);
54 | }
55 |
--------------------------------------------------------------------------------
/lib/utils/extensions.dart:
--------------------------------------------------------------------------------
1 | export "extensions/custom_popups.dart";
2 | export "extensions/go_router.dart";
3 | export "extensions/iterables.dart";
4 | export "extensions/num.dart";
5 | export "extensions/string.dart";
6 | export "extensions/toast.dart";
7 | export "extensions/transaction.dart";
8 | export "extensions/transaction_filter.dart";
9 |
--------------------------------------------------------------------------------
/lib/utils/extensions/directionality.dart:
--------------------------------------------------------------------------------
1 | import "package:flutter/material.dart";
2 |
3 | extension ContextDirectionality on BuildContext {
4 | bool get isRtl => Directionality.of(this) == TextDirection.rtl;
5 | bool get isLtr => Directionality.of(this) == TextDirection.ltr;
6 | }
7 |
--------------------------------------------------------------------------------
/lib/utils/extensions/go_router.dart:
--------------------------------------------------------------------------------
1 | // Ongoing issue about lack of `popUntil`
2 | // https://github.com/flutter/flutter/issues/131625
3 | import "package:go_router/go_router.dart";
4 |
5 | extension GoRouterExt on GoRouter {
6 | void popUntil(bool Function(GoRoute) predicate) {
7 | List routeStacks = [...routerDelegate.currentConfiguration.routes];
8 |
9 | for (int i = routeStacks.length - 1; i >= 0; i--) {
10 | RouteBase route = routeStacks[i];
11 | if (route is GoRoute) {
12 | if (predicate(route)) break;
13 | if (i != 0 && routeStacks[i - 1] is ShellRoute) {
14 | RouteMatchList matchList = routerDelegate.currentConfiguration;
15 | restore(matchList.remove(matchList.matches.last));
16 | } else {
17 | pop();
18 | }
19 | }
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/lib/utils/extensions/interval_report.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/l10n/extensions.dart";
2 | import "package:flow/reports/interval_flow_report.dart";
3 | import "package:flutter/material.dart";
4 |
5 | extension IntervalReportL10n on IntervalFlowReport {
6 | String averageTitle(BuildContext context) {
7 | if (interval == const Duration(hours: 1)) {
8 | return "tabs.stats.intervalReport.averages@hour".t(context);
9 | } else if (interval == const Duration(days: 1)) {
10 | return "tabs.stats.intervalReport.averages@day".t(context);
11 | } else if (interval == const Duration(days: 7)) {
12 | return "tabs.stats.intervalReport.averages@week".t(context);
13 | } else if (interval == const Duration(days: 30)) {
14 | return "tabs.stats.intervalReport.averages@month".t(context);
15 | } else if (interval == const Duration(days: 365)) {
16 | return "tabs.stats.intervalReport.averages@year".t(context);
17 | } else {
18 | return "avg, per (${interval.inSeconds} seconds)".t(context);
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/lib/utils/extensions/num.dart:
--------------------------------------------------------------------------------
1 | import "dart:math";
2 |
3 | extension NumberFormatter on num {
4 | /// Returns string with [decimalPlaces] decimal places.
5 | ///
6 | /// Example:
7 | /// `0.69.toStringAsFixed(2) => "69.00%"`
8 | String percent([int decimalPlaces = 1]) {
9 | return "${(this * 100).toStringAsFixed(decimalPlaces)}%";
10 | }
11 |
12 | /// No decimal places.
13 | ///
14 | /// Example:
15 | /// `0.69.percent2 => "69%"`
16 | String get percentInt => percent(0);
17 |
18 | /// One decimal places.
19 | ///
20 | /// Example:
21 | /// `0.691.percent2 => "69.1%"`
22 | String get percent1 => percent(1);
23 |
24 | /// Two decimal places.
25 | ///
26 | /// Example:
27 | /// `0.42.percent2 => "42.00%"`
28 | String get percent2 => percent(2);
29 |
30 | String get humanReadableBinarySize {
31 | const log1024 = 6.931471805599453;
32 | const formats = ["B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"];
33 |
34 | final int unitIndex = (log(toDouble()) / log1024).floor();
35 |
36 | return "${(this / pow(1024, unitIndex)).toStringAsFixed(1)} ${formats[unitIndex]}";
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/lib/utils/extensions/recurring_transaction.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/entity/recurring_transaction.dart";
2 | import "package:flow/entity/transaction/extensions/default/recurring.dart";
3 |
4 | extension RecurringTransactionHelpers on RecurringTransaction {
5 | String get extensionIdentifierTag => Recurring(
6 | uuid: uuid,
7 | initialTransactionDate: DateTime.now(),
8 | ).extensionIdentifierTag;
9 | }
10 |
--------------------------------------------------------------------------------
/lib/utils/extensions/string.dart:
--------------------------------------------------------------------------------
1 | extension Casings on String {
2 | static RegExp whitespaceMatcher = RegExp(r"\s");
3 |
4 | static List titleCaseLowercaseWords = [
5 | "a",
6 | "an",
7 | "the",
8 | "at",
9 | "by",
10 | "for",
11 | "in",
12 | "of",
13 | "on",
14 | "to",
15 | "up",
16 | "and",
17 | "as",
18 | "but",
19 | "or",
20 | "nor",
21 | ];
22 |
23 | String capitalize() {
24 | if (isEmpty) return this;
25 |
26 | return "${this[0].toUpperCase()}${substring(1).toLowerCase()}";
27 | }
28 |
29 | /// Does not preserve original whitespace characters.
30 | ///
31 | /// All whitespace will be replaced with a single space.
32 | String titleCase() {
33 | if (isEmpty) return this;
34 |
35 | return split(whitespaceMatcher)
36 | .map(
37 | (e) => titleCaseLowercaseWords.contains(e.toLowerCase())
38 | ? e.toLowerCase()
39 | : e.capitalize(),
40 | )
41 | .join(" ");
42 | }
43 |
44 | String get digitsObscured => replaceAll(RegExp(r"\d"), "*");
45 |
46 | /// Removes leading zeroes from a string.
47 | ///
48 | /// e.g.,
49 | /// 0a -> a
50 | /// 02 -> 2
51 | /// 03xe -> 3xe
52 | String get withoutLeadingZeroes => replaceAll(RegExp(r"^0*"), "");
53 | }
54 |
--------------------------------------------------------------------------------
/lib/utils/guess_preset_icon.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/data/flow_icon.dart";
2 | import "package:flow/data/setup/default_accounts.dart";
3 | import "package:flow/data/setup/default_categories.dart";
4 | import "package:flow/entity/account.dart";
5 | import "package:flow/entity/category.dart";
6 | import "package:material_symbols_icons/symbols.dart";
7 |
8 | /// Falls back to [fallback]
9 | FlowIconData guessPresetIcon(
10 | String name, {
11 | FlowIconData fallback = const IconFlowIcon(Symbols.circle_rounded),
12 | }) {
13 | name = name.trim().toLowerCase();
14 |
15 | for (final Account accountPreset in getAccountPresets("USD")) {
16 | if (accountPreset.name.toLowerCase() == name) {
17 | return accountPreset.icon;
18 | }
19 | }
20 |
21 | for (final Category categoryPreset in getCategoryPresets()) {
22 | if (categoryPreset.name.toLowerCase() == name) {
23 | return categoryPreset.icon;
24 | }
25 | }
26 |
27 | return fallback;
28 | }
29 |
--------------------------------------------------------------------------------
/lib/utils/is_desktop.dart:
--------------------------------------------------------------------------------
1 | import "dart:io";
2 |
3 | bool isDesktop() {
4 | return Platform.isWindows || Platform.isMacOS || Platform.isLinux;
5 | }
6 |
--------------------------------------------------------------------------------
/lib/utils/jasonable.dart:
--------------------------------------------------------------------------------
1 | abstract class Jasonable {
2 | Map toJson();
3 | }
4 |
--------------------------------------------------------------------------------
/lib/utils/json/time_range_converter.dart:
--------------------------------------------------------------------------------
1 | import "package:json_annotation/json_annotation.dart";
2 | import "package:moment_dart/moment_dart.dart";
3 |
4 | class TimeRangeConverter implements JsonConverter {
5 | const TimeRangeConverter();
6 |
7 | @override
8 | TimeRange fromJson(String serialized) {
9 | return TimeRange.parse(serialized);
10 | }
11 |
12 | @override
13 | String toJson(TimeRange range) {
14 | return range.encodeShort();
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/lib/utils/json/utc_datetime_converter.dart:
--------------------------------------------------------------------------------
1 | import "package:json_annotation/json_annotation.dart";
2 |
3 | class UTCDateTimeConverter implements JsonConverter {
4 | const UTCDateTimeConverter();
5 |
6 | @override
7 | DateTime fromJson(String dateTime) {
8 | return DateTime.parse(dateTime).toLocal();
9 | }
10 |
11 | @override
12 | String toJson(DateTime dateTime) {
13 | return dateTime.toUtc().toIso8601String();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/lib/utils/line_break_normalizer.dart:
--------------------------------------------------------------------------------
1 | import "dart:convert";
2 |
3 | /// Converts all line breaks to [terminator], and get rid of empty lines.
4 | class LineBreakNormalizer extends Converter {
5 | static const String terminator = "\n";
6 |
7 | const LineBreakNormalizer();
8 |
9 | @override
10 | String convert(String input) => normalize(input);
11 |
12 | @override
13 | Sink startChunkedConversion(Sink sink) {
14 | return LineBreakNormalizerSink(sink);
15 | }
16 |
17 | static String normalize(String input) => input
18 | .replaceAll("\r\n", terminator)
19 | .replaceAll("\r", terminator)
20 | .replaceAll(RegExp(r"\s+$", multiLine: true), "");
21 | }
22 |
23 | class LineBreakNormalizerSink implements ChunkedConversionSink {
24 | final Sink _sink;
25 |
26 | LineBreakNormalizerSink(this._sink);
27 |
28 | @override
29 | void close() {
30 | _sink.close();
31 | }
32 |
33 | @override
34 | void add(String chunk) {
35 | _sink.add(LineBreakNormalizer.normalize(chunk));
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/lib/utils/number_formatting.dart:
--------------------------------------------------------------------------------
1 | import "package:intl/intl.dart";
2 |
3 | String getDecimalSeparatorForCurrency(String? currency) {
4 | return currency == null
5 | ? "."
6 | : NumberFormat.simpleCurrency(name: currency).symbols.DECIMAL_SEP;
7 | }
8 |
--------------------------------------------------------------------------------
/lib/utils/open_url.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/logging.dart";
2 | import "package:url_launcher/url_launcher.dart";
3 |
4 | Future openUrl(
5 | Uri uri, [
6 | LaunchMode mode = LaunchMode.externalApplication,
7 | ]) async {
8 | try {
9 | return await launchUrl(uri);
10 | } catch (e) {
11 | mainLogger.warning("Failed to launch uri ($uri) due to $e");
12 | return false;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/lib/utils/optional.dart:
--------------------------------------------------------------------------------
1 | class Optional {
2 | final T? value;
3 |
4 | const Optional(this.value);
5 | }
6 |
--------------------------------------------------------------------------------
/lib/utils/shortcut.dart:
--------------------------------------------------------------------------------
1 | import "dart:io";
2 |
3 | import "package:flutter/material.dart";
4 | import "package:flutter/services.dart";
5 | import "package:flutter/widgets.dart";
6 |
7 | bool _shouldUseMeta() => Platform.isMacOS || Platform.isIOS;
8 |
9 | /// A SingleActivator that gets triggered if [key] is pressed with
10 | /// * `Meta` for macOS and iOS (iPadOS)
11 | /// * `Control` for other platforms
12 | ///
13 | /// It's also possible to pass [shift] and [alt] to the constructor.
14 | SingleActivator osSingleActivator(
15 | LogicalKeyboardKey key, [
16 | bool shift = false,
17 | bool alt = false,
18 | ]) {
19 | final meta = _shouldUseMeta();
20 | final control = !meta;
21 |
22 | return SingleActivator(
23 | key,
24 | control: control,
25 | meta: meta,
26 | shift: shift,
27 | alt: alt,
28 | );
29 | }
30 |
--------------------------------------------------------------------------------
/lib/utils/simple_query_sorter.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/data/currencies.dart";
2 | import "package:flow/entity/account.dart";
3 | import "package:flow/entity/category.dart";
4 | import "package:fuzzywuzzy/fuzzywuzzy.dart";
5 |
6 | List simpleSortByQuery(List items, String query) {
7 | final String normalizedQuery = query.trim().toLowerCase();
8 |
9 | if (normalizedQuery.isEmpty) return items;
10 |
11 | return extractAllSorted(
12 | query: normalizedQuery,
13 | choices: items,
14 | getter: (item) {
15 | if (item case Category category) {
16 | return category.name;
17 | }
18 |
19 | if (item case Account account) {
20 | return account.name;
21 | }
22 |
23 | if (item case CurrencyData currencyData) {
24 | return [
25 | currencyData.code,
26 | currencyData.name,
27 | currencyData.country,
28 | ].join(" ");
29 | }
30 |
31 | return item.toString();
32 | },
33 | ).map((result) => result.choice).toList();
34 | }
35 |
--------------------------------------------------------------------------------
/lib/utils/utils.dart:
--------------------------------------------------------------------------------
1 | export "csv_parser.dart";
2 | export "extensions.dart";
3 | export "is_desktop.dart";
4 | export "jasonable.dart";
5 | export "line_break_normalizer.dart";
6 | export "number_formatting.dart";
7 | export "open_url.dart";
8 | export "optional.dart";
9 | export "pick_file.dart";
10 | export "shortcut.dart";
11 | export "simple_query_sorter.dart";
12 |
--------------------------------------------------------------------------------
/lib/widgets/add_category_card.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/data/flow_icon.dart";
2 | import "package:flow/l10n/extensions.dart";
3 | import "package:flow/widgets/general/flow_icon.dart";
4 | import "package:flow/widgets/general/surface.dart";
5 | import "package:flutter/material.dart";
6 | import "package:go_router/go_router.dart";
7 | import "package:material_symbols_icons/symbols.dart";
8 |
9 | class AddCategoryCard extends StatelessWidget {
10 | final VoidCallback? onTapOverride;
11 |
12 | const AddCategoryCard({super.key, this.onTapOverride});
13 |
14 | static BorderRadius borderRadius = BorderRadius.circular(16.0);
15 |
16 | @override
17 | Widget build(BuildContext context) {
18 | return Surface(
19 | shape: RoundedRectangleBorder(borderRadius: borderRadius),
20 | builder: (context) => InkWell(
21 | borderRadius: borderRadius,
22 | onTap: onTapOverride ?? (() => context.push("/category/new")),
23 | child: Row(
24 | children: [
25 | FlowIcon(
26 | FlowIconData.icon(Symbols.add_rounded),
27 | size: 32.0,
28 | plated: true,
29 | ),
30 | const SizedBox(width: 12.0),
31 | Column(
32 | mainAxisSize: MainAxisSize.min,
33 | crossAxisAlignment: CrossAxisAlignment.start,
34 | children: [Text("category.new".t(context))],
35 | ),
36 | const Spacer(),
37 | ],
38 | ),
39 | ),
40 | );
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/lib/widgets/chart_legend.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/theme/theme.dart";
2 | import "package:flutter/material.dart";
3 |
4 | class ChartLegend extends StatelessWidget {
5 | final Color color;
6 | final String label;
7 |
8 | const ChartLegend({super.key, required this.color, required this.label});
9 |
10 | @override
11 | Widget build(BuildContext context) {
12 | return Row(
13 | mainAxisSize: MainAxisSize.min,
14 | children: [
15 | Container(
16 | width: 16.0,
17 | height: 16.0,
18 | decoration: BoxDecoration(
19 | color: color,
20 | borderRadius: BorderRadius.circular(4.0),
21 | border: Border.all(
22 | color: context.colorScheme.onSurface,
23 | width: 1.0,
24 | ),
25 | ),
26 | ),
27 | const SizedBox(width: 8.0),
28 | Text(label, style: context.textTheme.bodyMedium),
29 | ],
30 | );
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/lib/widgets/export/export_history/no_backups.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/data/flow_icon.dart";
2 | import "package:flow/l10n/extensions.dart";
3 | import "package:flow/theme/theme.dart";
4 | import "package:flow/widgets/general/flow_icon.dart";
5 | import "package:flutter/material.dart";
6 | import "package:material_symbols_icons/symbols.dart";
7 |
8 | class NoBackups extends StatelessWidget {
9 | const NoBackups({super.key});
10 |
11 | @override
12 | Widget build(BuildContext context) {
13 | return Padding(
14 | padding: const EdgeInsets.all(24.0),
15 | child: Center(
16 | child: Column(
17 | mainAxisSize: MainAxisSize.min,
18 | children: [
19 | Text(
20 | "sync.export.history.empty".t(context),
21 | textAlign: TextAlign.center,
22 | style: context.textTheme.headlineMedium,
23 | ),
24 | const SizedBox(height: 8.0),
25 | FlowIcon(
26 | FlowIconData.icon(Symbols.history_rounded),
27 | size: 128.0,
28 | color: context.colorScheme.primary,
29 | ),
30 | const SizedBox(height: 8.0),
31 | Text(
32 | "sync.export.history.empty.description".t(context),
33 | textAlign: TextAlign.center,
34 | ),
35 | ],
36 | ),
37 | ),
38 | );
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/lib/widgets/general/blur_backgorund.dart:
--------------------------------------------------------------------------------
1 | import "dart:ui";
2 |
3 | import "package:flutter/material.dart";
4 |
5 | class BlurBackground extends StatelessWidget {
6 | final bool blur;
7 | final Widget child;
8 |
9 | final double sigmaX;
10 | final double sigmaY;
11 |
12 | const BlurBackground({
13 | super.key,
14 | required this.blur,
15 | required this.child,
16 | this.sigmaX = 2.0,
17 | this.sigmaY = 2.0,
18 | });
19 |
20 | @override
21 | Widget build(BuildContext context) {
22 | return ClipRect(
23 | child: Stack(
24 | children: [
25 | child,
26 | if (blur)
27 | Positioned.fill(
28 | child: BackdropFilter(
29 | filter: ImageFilter.blur(sigmaX: sigmaX, sigmaY: sigmaY),
30 | child: Container(),
31 | ),
32 | ),
33 | ],
34 | ),
35 | );
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/lib/widgets/general/directional_chevron.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/widgets/general/rtl_flipper.dart";
2 | import "package:flutter/material.dart";
3 | import "package:material_symbols_icons/symbols.dart";
4 |
5 | class DirectionalChevron extends StatelessWidget {
6 | const DirectionalChevron({super.key});
7 |
8 | @override
9 | Widget build(BuildContext context) {
10 | return const RTLFlipper(child: Icon(Symbols.chevron_right_rounded));
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/lib/widgets/general/frame.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/theme/theme.dart";
2 | import "package:flutter/material.dart";
3 |
4 | class Frame extends StatelessWidget {
5 | final bool pad;
6 | final EdgeInsets padding;
7 | final Widget child;
8 | final bool withSurface;
9 |
10 | const Frame({
11 | super.key,
12 | this.pad = true,
13 | this.withSurface = false,
14 | this.padding = const EdgeInsets.symmetric(horizontal: 16.0),
15 | required this.child,
16 | });
17 |
18 | const Frame.standalone({
19 | super.key,
20 | this.withSurface = false,
21 | required this.child,
22 | }) : pad = true,
23 | padding = const EdgeInsets.all(16.0);
24 |
25 | @override
26 | Widget build(BuildContext context) {
27 | return Container(
28 | color: withSurface ? context.colorScheme.surface : null,
29 | padding: pad ? padding : EdgeInsets.zero,
30 | child: child,
31 | );
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/lib/widgets/general/info_text.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/theme/theme.dart";
2 | import "package:flutter/material.dart";
3 | import "package:material_symbols_icons/symbols.dart";
4 |
5 | class InfoText extends StatelessWidget {
6 | final Widget child;
7 |
8 | final IconData icon;
9 |
10 | const InfoText({
11 | super.key,
12 | required this.child,
13 | this.icon = Symbols.info_rounded,
14 | });
15 |
16 | @override
17 | Widget build(BuildContext context) {
18 | return Row(
19 | crossAxisAlignment: CrossAxisAlignment.center,
20 | children: [
21 | Icon(icon, fill: 0, color: context.flowColors.semi, size: 16.0),
22 | const SizedBox(width: 4.0),
23 | Flexible(
24 | child: DefaultTextStyle(
25 | style: context.textTheme.bodySmall!.semi(context),
26 | child: child,
27 | ),
28 | ),
29 | ],
30 | );
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/lib/widgets/general/list_header.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/theme/theme.dart";
2 | import "package:flutter/material.dart";
3 |
4 | class ListHeader extends StatelessWidget {
5 | final String title;
6 | final EdgeInsets padding;
7 |
8 | final TextStyle? style;
9 |
10 | const ListHeader(
11 | this.title, {
12 | super.key,
13 | this.style,
14 | this.padding = const EdgeInsets.symmetric(horizontal: 16.0),
15 | });
16 |
17 | @override
18 | Widget build(BuildContext context) {
19 | return Padding(
20 | padding: padding,
21 | child: Text(title, style: style ?? context.textTheme.titleSmall),
22 | );
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/lib/widgets/general/map.dart:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/lib/widgets/general/modal_overflow_bar.dart:
--------------------------------------------------------------------------------
1 | import "package:flutter/material.dart";
2 |
3 | class ModalOverflowBar extends StatelessWidget {
4 | final EdgeInsets padding;
5 | final List children;
6 |
7 | final double spacing;
8 | final MainAxisAlignment? alignment;
9 | final double overflowSpacing;
10 | final OverflowBarAlignment overflowAlignment;
11 | final VerticalDirection overflowDirection;
12 | final TextDirection? textDirection;
13 |
14 | const ModalOverflowBar({
15 | super.key,
16 | this.padding = const EdgeInsets.symmetric(horizontal: 16.0, vertical: 12.0),
17 | required this.children,
18 | this.alignment,
19 | this.spacing = 12.0,
20 | this.overflowSpacing = 12.0,
21 | this.overflowAlignment = OverflowBarAlignment.start,
22 | this.overflowDirection = VerticalDirection.down,
23 | this.textDirection,
24 | });
25 |
26 | @override
27 | Widget build(BuildContext context) {
28 | return Padding(
29 | padding: padding,
30 | child: OverflowBar(
31 | alignment: alignment,
32 | spacing: spacing,
33 | overflowSpacing: overflowSpacing,
34 | overflowAlignment: overflowAlignment,
35 | overflowDirection: overflowDirection,
36 | textDirection: textDirection,
37 | children: children,
38 | ),
39 | );
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/lib/widgets/general/rtl_flipper.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/utils/extensions/directionality.dart";
2 | import "package:flutter/material.dart";
3 |
4 | class RTLFlipper extends StatelessWidget {
5 | final Widget child;
6 |
7 | const RTLFlipper({super.key, required this.child});
8 |
9 | @override
10 | Widget build(BuildContext context) {
11 | return Transform.flip(flipX: context.isRtl, child: child);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/lib/widgets/general/spinner.dart:
--------------------------------------------------------------------------------
1 | import "package:flutter/material.dart";
2 |
3 | /// Indefinite waiting indicator
4 | class Spinner extends StatelessWidget {
5 | final bool center;
6 |
7 | const Spinner({super.key, this.center = false});
8 | const Spinner.center({super.key}) : center = true;
9 |
10 | @override
11 | Widget build(BuildContext context) {
12 | const child = CircularProgressIndicator();
13 |
14 | if (center) {
15 | return const Center(child: child);
16 | }
17 |
18 | return child;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/lib/widgets/general/wavy_divider.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/widgets/general/wavy_divider/wavy_divider_painter.dart";
2 | import "package:flutter/material.dart";
3 |
4 | class WavyDivider extends StatelessWidget {
5 | /// Height of the divider
6 | ///
7 | /// Visually, will be less than [height] due to usage of bezier curves
8 | final double height;
9 |
10 | /// Width of a single wave
11 | final double waveWidth;
12 |
13 | /// Color of the divider, defaults to theme's `dividerColor`
14 | final Color? color;
15 |
16 | /// Width of the stroke
17 | final double strokeWidth;
18 |
19 | const WavyDivider({
20 | super.key,
21 | this.height = 16.0,
22 | this.waveWidth = 16.0,
23 | this.strokeWidth = 2.0,
24 | this.color,
25 | });
26 |
27 | @override
28 | Widget build(BuildContext context) {
29 | final Color color = this.color ?? Theme.of(context).dividerColor;
30 |
31 | return SizedBox(
32 | width: double.infinity,
33 | height: height,
34 | child: ClipRect(
35 | child: CustomPaint(
36 | key: ValueKey(color),
37 | painter: WavyDividerPainter(
38 | color: color,
39 | height: height,
40 | waveWidth: waveWidth,
41 | strokeWidth: strokeWidth,
42 | ),
43 | ),
44 | ),
45 | );
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/lib/widgets/general/wavy_divider/wavy_divider_painter.dart:
--------------------------------------------------------------------------------
1 | import "package:flutter/material.dart";
2 |
3 | class WavyDividerPainter extends CustomPainter {
4 | /// Width of single semi-circle
5 | final double waveWidth;
6 |
7 | /// Height of the divider
8 | final double height;
9 |
10 | final Color color;
11 |
12 | final double strokeWidth;
13 |
14 | const WavyDividerPainter({
15 | super.repaint,
16 | required this.color,
17 | required this.height,
18 | required this.waveWidth,
19 | required this.strokeWidth,
20 | });
21 |
22 | @override
23 | void paint(Canvas canvas, Size size) {
24 | final paint = Paint()
25 | ..color = color
26 | ..strokeWidth = strokeWidth
27 | ..style = PaintingStyle.stroke
28 | ..strokeCap = StrokeCap.round;
29 |
30 | final double halfHeight = height * 0.5;
31 |
32 | final Path path = Path()..moveTo(0, halfHeight);
33 |
34 | final int iterations = (size.width / waveWidth).ceil();
35 |
36 | for (int i = 0; i < iterations; i++) {
37 | path.relativeQuadraticBezierTo(
38 | waveWidth * 0.5,
39 | halfHeight * (i % 2 == 0 ? 1 : -1),
40 | waveWidth,
41 | 0,
42 | );
43 | }
44 |
45 | canvas.drawPath(path, paint);
46 | }
47 |
48 | @override
49 | bool shouldRepaint(WavyDividerPainter oldDelegate) => false;
50 | }
51 |
--------------------------------------------------------------------------------
/lib/widgets/home/preferences/button_order_preferences/transaction_type_button.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/entity/transaction.dart";
2 | import "package:flow/theme/theme.dart";
3 | import "package:flutter/material.dart";
4 |
5 | class TransactionTypeButton extends StatelessWidget {
6 | final double opacity;
7 | final TransactionType type;
8 |
9 | const TransactionTypeButton({
10 | super.key,
11 | required this.type,
12 | this.opacity = 1.0,
13 | });
14 |
15 | @override
16 | Widget build(BuildContext context) {
17 | final Widget child = Container(
18 | decoration: BoxDecoration(
19 | shape: BoxShape.circle,
20 | color: type.actionBackgroundColor(context),
21 | ),
22 | padding: const EdgeInsets.all(16.0),
23 | child: Icon(type.icon, color: type.actionColor(context), weight: 800.0),
24 | );
25 |
26 | if (opacity == 1.0) {
27 | return child;
28 | }
29 |
30 | return Opacity(opacity: opacity, child: child);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/lib/widgets/home/preferences/transfer_preferences/demo_transaction_list_tile.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/data/flow_icon.dart";
2 | import "package:flow/entity/transaction.dart";
3 | import "package:flow/theme/theme.dart";
4 | import "package:flow/widgets/general/flow_icon.dart";
5 | import "package:flutter/material.dart";
6 | import "package:material_symbols_icons/symbols.dart";
7 |
8 | class DemoTransactionListTile extends StatelessWidget {
9 | final TransactionType type;
10 |
11 | const DemoTransactionListTile({super.key, required this.type});
12 |
13 | @override
14 | Widget build(BuildContext context) {
15 | final IconData icon = switch (type) {
16 | TransactionType.transfer => Symbols.sync_alt_rounded,
17 | _ => Symbols.circle_rounded,
18 | };
19 |
20 | return Row(
21 | children: [
22 | FlowIcon(FlowIconData.icon(icon), plated: true, fill: 0.0),
23 | const SizedBox(width: 4.0),
24 | Text("▅▅▅", style: context.textTheme.bodySmall?.semi(context)),
25 | const Spacer(),
26 | Text(
27 | type == TransactionType.expense ? "-▇" : "▇",
28 | style: context.textTheme.bodyLarge?.copyWith(
29 | color: type.color(context),
30 | fontWeight: FontWeight.bold,
31 | ),
32 | ),
33 | ],
34 | );
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/lib/widgets/home/privacy_toggler.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/prefs/transitive.dart";
2 | import "package:flutter/material.dart";
3 | import "package:material_symbols_icons/symbols.dart";
4 |
5 | class PrivacyToggler extends StatelessWidget {
6 | const PrivacyToggler({super.key});
7 |
8 | @override
9 | Widget build(BuildContext context) {
10 | return ValueListenableBuilder(
11 | valueListenable:
12 | TransitiveLocalPreferences().sessionPrivacyMode.valueNotifier,
13 | builder: (context, snapshot, _) {
14 | final bool obscure = snapshot == true;
15 |
16 | return IconButton(
17 | onPressed: () =>
18 | TransitiveLocalPreferences().sessionPrivacyMode.set(!obscure),
19 | icon: Icon(
20 | obscure
21 | ? Symbols.visibility_rounded
22 | : Symbols.visibility_off_rounded,
23 | ),
24 | );
25 | },
26 | );
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/lib/widgets/home/stats/info_card_with_delta.dart:
--------------------------------------------------------------------------------
1 | import "package:auto_size_text/auto_size_text.dart";
2 | import "package:flow/data/money.dart";
3 | import "package:flow/prefs/local_preferences.dart";
4 | import "package:flow/theme/theme.dart";
5 | import "package:flow/widgets/general/money_text.dart";
6 | import "package:flow/widgets/home/home/info_card.dart";
7 | import "package:flow/widgets/trend.dart";
8 | import "package:flutter/material.dart";
9 |
10 | class InfoCardWithDelta extends StatelessWidget {
11 | final Money money;
12 | final Money? previousMoney;
13 |
14 | final bool invertDelta;
15 |
16 | final AutoSizeGroup? autoSizeGroup;
17 |
18 | final String title;
19 |
20 | const InfoCardWithDelta({
21 | super.key,
22 | required this.money,
23 | required this.previousMoney,
24 | required this.autoSizeGroup,
25 | required this.title,
26 | this.invertDelta = false,
27 | });
28 |
29 | @override
30 | Widget build(BuildContext context) {
31 | return InfoCard(
32 | title: title,
33 | money: MoneyText(
34 | money,
35 | tapToToggleAbbreviation: true,
36 | initiallyAbbreviated: !LocalPreferences().preferFullAmounts.get(),
37 | autoSize: true,
38 | autoSizeGroup: autoSizeGroup,
39 | style: context.textTheme.displaySmall,
40 | ),
41 | delta: Trend.fromMoney(
42 | current: money,
43 | previous: previousMoney,
44 | invertDelta: invertDelta,
45 | ),
46 | );
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/lib/widgets/import_wizard/backup_info.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/sync/import/base.dart";
2 | import "package:flow/sync/import/external/ivy_wallet_csv.dart";
3 | import "package:flow/sync/import/import_csv.dart";
4 | import "package:flow/sync/import/import_v1.dart";
5 | import "package:flow/sync/import/import_v2.dart";
6 | import "package:flow/widgets/import_wizard/csv/backup_info_csv.dart";
7 | import "package:flow/widgets/import_wizard/ivy_wallet/backup_info.dart";
8 | import "package:flow/widgets/import_wizard/v1/backup_info_v1.dart";
9 | import "package:flow/widgets/import_wizard/v2/backup_info_v2.dart";
10 | import "package:flutter/widgets.dart";
11 |
12 | class BackupInfo extends StatelessWidget {
13 | final Importer importer;
14 | final VoidCallback onClickStart;
15 |
16 | const BackupInfo({
17 | super.key,
18 | required this.importer,
19 | required this.onClickStart,
20 | });
21 |
22 | @override
23 | Widget build(BuildContext context) => switch (importer) {
24 | ImportV1 v1 => BackupInfoV1(importer: v1, onClickStart: onClickStart),
25 | ImportV2 v2 => BackupInfoV2(importer: v2, onClickStart: onClickStart),
26 | ImportCSV csv => BackupInfoCSV(importer: csv, onClickStart: onClickStart),
27 | IvyWalletCsvImporter ivyImporter => BackupInfoIvyWalletCsv(
28 | importer: ivyImporter,
29 | onClickStart: onClickStart,
30 | ),
31 | _ => Container(),
32 | };
33 | }
34 |
--------------------------------------------------------------------------------
/lib/widgets/import_wizard/csv/account_currency_list_tile.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/theme/helpers.dart";
2 | import "package:flutter/material.dart";
3 | import "package:material_symbols_icons/symbols.dart";
4 |
5 | class AccountCurrencyListTile extends StatelessWidget {
6 | final String name;
7 | final String? currency;
8 |
9 | final VoidCallback? onTap;
10 |
11 | const AccountCurrencyListTile({
12 | super.key,
13 | required this.name,
14 | this.currency,
15 | this.onTap,
16 | });
17 |
18 | @override
19 | Widget build(BuildContext context) {
20 | return ListTile(
21 | title: Text(name),
22 | trailing: Row(
23 | mainAxisSize: MainAxisSize.min,
24 | children: [
25 | Text(
26 | currency ?? "---",
27 | style: context.textTheme.bodyLarge?.copyWith(
28 | fontFeatures: [const FontFeature.tabularFigures()],
29 | ),
30 | maxLines: 1,
31 | overflow: TextOverflow.ellipsis,
32 | ),
33 | const SizedBox(width: 8.0),
34 | Icon(Symbols.arrow_drop_down_rounded),
35 | ],
36 | ),
37 | onTap: onTap,
38 | );
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/lib/widgets/import_wizard/import_item_list_tile.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/data/flow_icon.dart";
2 | import "package:flow/widgets/general/flow_icon.dart";
3 | import "package:flow/widgets/general/surface.dart";
4 | import "package:flutter/widgets.dart";
5 |
6 | class ImportItemListTile extends StatelessWidget {
7 | final FlowIconData icon;
8 | final Widget label;
9 |
10 | const ImportItemListTile({
11 | super.key,
12 | required this.icon,
13 | required this.label,
14 | });
15 |
16 | @override
17 | Widget build(BuildContext context) {
18 | return Surface(
19 | builder: (context) => Padding(
20 | padding: const EdgeInsets.all(16.0),
21 | child: Row(
22 | mainAxisSize: MainAxisSize.max,
23 | children: [
24 | FlowIcon(icon, size: 24.0),
25 | const SizedBox(width: 8.0),
26 | Flexible(child: label),
27 | const SizedBox(width: 8.0),
28 | ],
29 | ),
30 | ),
31 | );
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/lib/widgets/internal_notifications/internal_notification_section.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/data/internal_nofications/internal_notification.dart";
2 | import "package:flow/widgets/internal_notifications/auto_backup_reminder.dart";
3 | import "package:flow/widgets/internal_notifications/rate_app_notification.dart";
4 | import "package:flow/widgets/internal_notifications/star_on_github_notification.dart";
5 | import "package:flutter/material.dart";
6 |
7 | class InternalNotificationSection extends StatelessWidget {
8 | final InternalNotification notification;
9 | final VoidCallback? onDismiss;
10 |
11 | const InternalNotificationSection({
12 | super.key,
13 | required this.notification,
14 | this.onDismiss,
15 | });
16 |
17 | @override
18 | Widget build(BuildContext context) => switch (notification) {
19 | AutoBackupReminder notification => AutoBackupReminderNotification(
20 | notification: notification,
21 | onDismiss: onDismiss,
22 | ),
23 | RateApp notification => RateAppNotification(
24 | notification: notification,
25 | onDismiss: onDismiss,
26 | ),
27 | StarOnGitHub notification => StarOnGithubNotification(
28 | notification: notification,
29 | onDismiss: onDismiss,
30 | ),
31 | _ => SizedBox.shrink(),
32 | };
33 | }
34 |
--------------------------------------------------------------------------------
/lib/widgets/internal_notifications/star_on_github_notification.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/constants.dart";
2 | import "package:flow/data/internal_nofications/internal_notification.dart";
3 | import "package:flow/l10n/extensions.dart";
4 | import "package:flow/utils/utils.dart";
5 | import "package:flow/widgets/internal_notifications/internal_notification_list_tile.dart";
6 | import "package:flutter/material.dart";
7 | import "package:material_symbols_icons/material_symbols_icons.dart";
8 |
9 | class StarOnGithubNotification extends StatelessWidget {
10 | final StarOnGitHub notification;
11 | final VoidCallback? onDismiss;
12 |
13 | const StarOnGithubNotification({
14 | super.key,
15 | required this.notification,
16 | this.onDismiss,
17 | });
18 |
19 | @override
20 | Widget build(BuildContext context) {
21 | return InternalNotificationListTile(
22 | onDismiss: onDismiss,
23 | icon: notification.icon,
24 | title: "tabs.home.reminders.starOnGitHub".t(context),
25 | subtitle: "⭐⭐⭐⭐⭐",
26 | action: TextButton.icon(
27 | onPressed: () {
28 | if (onDismiss != null) {
29 | onDismiss!();
30 | }
31 | openUrl(flowGitHubRepoLink);
32 | },
33 | label: Text("GitHub"),
34 | icon: Icon(Symbols.open_in_new_rounded),
35 | ),
36 | );
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/lib/widgets/no_result.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/l10n/extensions.dart";
2 | import "package:flow/theme/theme.dart";
3 | import "package:flutter/material.dart";
4 |
5 | class NoResult extends StatelessWidget {
6 | const NoResult({super.key});
7 |
8 | @override
9 | Widget build(BuildContext context) {
10 | return Padding(
11 | padding: const EdgeInsets.all(24.0),
12 | child: Center(
13 | child: Column(
14 | mainAxisSize: MainAxisSize.min,
15 | children: [
16 | Text(
17 | "transactions.query.noResult".t(context),
18 | textAlign: TextAlign.center,
19 | style: context.textTheme.headlineSmall,
20 | ),
21 | const SizedBox(height: 8.0),
22 | Text(
23 | "transactions.query.noResult.description".t(context),
24 | textAlign: TextAlign.center,
25 | ),
26 | ],
27 | ),
28 | ),
29 | );
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/lib/widgets/reports/category_report_view.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/reports/category_flow_report.dart";
2 | import "package:flutter/material.dart";
3 |
4 | class CategoryReportView extends StatelessWidget {
5 | final CategoryFlowReport report;
6 |
7 | const CategoryReportView({super.key, required this.report});
8 |
9 | @override
10 | Widget build(BuildContext context) {
11 | return const Placeholder();
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/lib/widgets/setup/categories/category_preset_card.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/entity/category.dart";
2 | import "package:flow/utils/optional.dart";
3 | import "package:flow/widgets/category_card.dart";
4 | import "package:flutter/material.dart";
5 | import "package:material_symbols_icons/symbols.dart";
6 |
7 | class CategoryPresetCard extends StatelessWidget {
8 | final Function(bool) onSelect;
9 | final bool selected;
10 | final bool preexisting;
11 |
12 | final Category category;
13 |
14 | const CategoryPresetCard({
15 | super.key,
16 | required this.onSelect,
17 | required this.selected,
18 | required this.category,
19 | required this.preexisting,
20 | });
21 |
22 | @override
23 | Widget build(BuildContext context) {
24 | return Opacity(
25 | opacity: selected ? 1.0 : 0.46,
26 | child: CategoryCard(
27 | category: category,
28 | onTapOverride: Optional(() => onSelect(!selected)),
29 | showAmount: false,
30 | trailing: preexisting
31 | ? null
32 | : Icon(selected ? Symbols.remove_rounded : Symbols.add_rounded),
33 | ),
34 | );
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/lib/widgets/setup/offline_slide.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/data/flow_icon.dart";
2 | import "package:flow/l10n/extensions.dart";
3 | import "package:flow/theme/theme.dart";
4 | import "package:flow/widgets/general/flow_icon.dart";
5 | import "package:flutter/material.dart";
6 | import "package:material_symbols_icons/symbols.dart";
7 |
8 | class OfflineSlide extends StatelessWidget {
9 | const OfflineSlide({super.key});
10 |
11 | @override
12 | Widget build(BuildContext context) {
13 | return Padding(
14 | padding: const EdgeInsets.all(16.0),
15 | child: Column(
16 | crossAxisAlignment: CrossAxisAlignment.start,
17 | children: [
18 | const Spacer(),
19 | Center(
20 | child: FlowIcon(
21 | FlowIconData.icon(Symbols.security_rounded),
22 | size: 160.0,
23 | plated: true,
24 | ),
25 | ),
26 | const Spacer(),
27 | Text(
28 | "setup.slides.offline".t(context),
29 | style: context.textTheme.displayMedium?.copyWith(
30 | color: context.colorScheme.primary,
31 | ),
32 | ),
33 | const SizedBox(height: 8.0),
34 | Text(
35 | "setup.slides.offline.description".t(context),
36 | style: context.textTheme.bodyLarge,
37 | ),
38 | const SizedBox(height: 16.0),
39 | ],
40 | ),
41 | );
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/lib/widgets/setup/welcome_slide.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/l10n/extensions.dart";
2 | import "package:flow/theme/theme.dart";
3 | import "package:flutter/material.dart";
4 |
5 | class WelcomeSlide extends StatelessWidget {
6 | const WelcomeSlide({super.key});
7 |
8 | @override
9 | Widget build(BuildContext context) {
10 | return Padding(
11 | padding: const EdgeInsets.all(24.0),
12 | child: Column(
13 | crossAxisAlignment: CrossAxisAlignment.start,
14 | children: [
15 | const Spacer(),
16 | Padding(
17 | padding: const EdgeInsets.symmetric(horizontal: 24.0),
18 | child: ClipRRect(
19 | borderRadius: BorderRadius.circular(24.0),
20 | child: Image.asset("assets/images/flow.png"),
21 | ),
22 | ),
23 | const Spacer(),
24 | Text(
25 | "appName".t(context),
26 | style: context.textTheme.displayMedium?.copyWith(
27 | color: context.colorScheme.primary,
28 | ),
29 | ),
30 | const SizedBox(height: 8.0),
31 | Text("appShortDesc".t(context), style: context.textTheme.bodyLarge),
32 | const SizedBox(height: 16.0),
33 | ],
34 | ),
35 | );
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/lib/widgets/sheets/recurrence/select_day_sheet.dart:
--------------------------------------------------------------------------------
1 | import "package:flutter/material.dart";
2 |
3 | class SelectDaySheet extends StatelessWidget {
4 | const SelectDaySheet({super.key});
5 |
6 | @override
7 | Widget build(BuildContext context) {
8 | return const Placeholder();
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/lib/widgets/sheets/select_account_type_sheet.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/entity/account.dart";
2 | import "package:flow/l10n/extensions.dart";
3 | import "package:flow/l10n/named_enum.dart";
4 | import "package:flow/widgets/general/directional_chevron.dart";
5 | import "package:flow/widgets/general/modal_sheet.dart";
6 | import "package:flutter/material.dart";
7 | import "package:go_router/go_router.dart";
8 |
9 | class SelectAccountTypeSheet extends StatelessWidget {
10 | final AccountType? currentlySelected;
11 |
12 | const SelectAccountTypeSheet({super.key, this.currentlySelected});
13 |
14 | @override
15 | Widget build(BuildContext context) {
16 | return ModalSheet.scrollable(
17 | title: Text("account.type".t(context)),
18 | child: Column(
19 | mainAxisSize: MainAxisSize.min,
20 | children: AccountType.values
21 | .where((value) => value != AccountType.creditLine)
22 | .map(
23 | (value) => ListTile(
24 | title: Text(value.localizedNameContext(context)),
25 | selected: currentlySelected == value,
26 | trailing: const DirectionalChevron(),
27 | onTap: () => context.pop(value),
28 | ),
29 | )
30 | .toList(),
31 | ),
32 | );
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/lib/widgets/transaction_filter_head.dart:
--------------------------------------------------------------------------------
1 | import "package:flow/data/transaction_filter.dart";
2 | import "package:flow/theme/theme.dart";
3 | import "package:flutter/material.dart";
4 |
5 | /// Renders a row of [TransactionFilterChip]s.
6 | class TransactionFilterHead extends StatelessWidget {
7 | final TransactionFilter value;
8 |
9 | /// Usually List of [TransactionFilterChip]s
10 | final List filterChips;
11 |
12 | final EdgeInsets? padding;
13 |
14 | const TransactionFilterHead({
15 | super.key,
16 | required this.filterChips,
17 | this.value = TransactionFilter.empty,
18 | this.padding,
19 | });
20 |
21 | @override
22 | Widget build(BuildContext context) {
23 | final List children = [];
24 |
25 | for (final chip in filterChips) {
26 | children.add(chip);
27 | children.add(const SizedBox(width: 12.0));
28 | }
29 |
30 | if (children.isNotEmpty && children.last is SizedBox) {
31 | children.removeLast();
32 | }
33 |
34 | return Container(
35 | height: 48.0,
36 | width: double.infinity,
37 | color: context.colorScheme.surface,
38 | child: SingleChildScrollView(
39 | padding: padding,
40 | scrollDirection: Axis.horizontal,
41 | child: Row(children: children),
42 | ),
43 | );
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/lib/widgets/utils/should_execute_scheduled_task.dart:
--------------------------------------------------------------------------------
1 | /// Returns whether this scheduled execution should run "now".
2 | ///
3 | /// Use [anchor] to specify a reference point ("now" point) for the comparison.
4 | ///
5 | /// Always returns `true` if [lastExecution] is `null`.
6 | ///
7 | /// Returns `false` if [interval] is negative.
8 | bool shouldExecuteScheduledTask(
9 | Duration interval,
10 | DateTime? lastExecution, {
11 | DateTime? anchor,
12 | }) {
13 | if (lastExecution == null) {
14 | return true;
15 | }
16 |
17 | if (interval.isNegative) {
18 | return false;
19 | }
20 |
21 | final DateTime now = anchor ?? DateTime.now();
22 |
23 | if (lastExecution.add(interval).isAfter(now)) {
24 | return false;
25 | }
26 |
27 | return true;
28 | }
29 |
--------------------------------------------------------------------------------
/linux/.gitignore:
--------------------------------------------------------------------------------
1 | flutter/ephemeral
2 |
--------------------------------------------------------------------------------
/linux/flutter/generated_plugin_registrant.h:
--------------------------------------------------------------------------------
1 | //
2 | // Generated file. Do not edit.
3 | //
4 |
5 | // clang-format off
6 |
7 | #ifndef GENERATED_PLUGIN_REGISTRANT_
8 | #define GENERATED_PLUGIN_REGISTRANT_
9 |
10 | #include
11 |
12 | // Registers Flutter plugins.
13 | void fl_register_plugins(FlPluginRegistry* registry);
14 |
15 | #endif // GENERATED_PLUGIN_REGISTRANT_
16 |
--------------------------------------------------------------------------------
/linux/flutter/generated_plugins.cmake:
--------------------------------------------------------------------------------
1 | #
2 | # Generated file, do not edit.
3 | #
4 |
5 | list(APPEND FLUTTER_PLUGIN_LIST
6 | desktop_drop
7 | file_saver
8 | file_selector_linux
9 | flutter_timezone
10 | objectbox_flutter_libs
11 | screen_retriever_linux
12 | url_launcher_linux
13 | window_manager
14 | )
15 |
16 | list(APPEND FLUTTER_FFI_PLUGIN_LIST
17 | )
18 |
19 | set(PLUGIN_BUNDLED_LIBRARIES)
20 |
21 | foreach(plugin ${FLUTTER_PLUGIN_LIST})
22 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin})
23 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
24 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $)
25 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
26 | endforeach(plugin)
27 |
28 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
29 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin})
30 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
31 | endforeach(ffi_plugin)
32 |
--------------------------------------------------------------------------------
/linux/main.cc:
--------------------------------------------------------------------------------
1 | #include "my_application.h"
2 |
3 | int main(int argc, char** argv) {
4 | g_autoptr(MyApplication) app = my_application_new();
5 | return g_application_run(G_APPLICATION(app), argc, argv);
6 | }
7 |
--------------------------------------------------------------------------------
/linux/my_application.h:
--------------------------------------------------------------------------------
1 | #ifndef FLUTTER_MY_APPLICATION_H_
2 | #define FLUTTER_MY_APPLICATION_H_
3 |
4 | #include
5 |
6 | G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION,
7 | GtkApplication)
8 |
9 | /**
10 | * my_application_new:
11 | *
12 | * Creates a new Flutter-based application.
13 | *
14 | * Returns: a new #MyApplication.
15 | */
16 | MyApplication* my_application_new();
17 |
18 | #endif // FLUTTER_MY_APPLICATION_H_
19 |
--------------------------------------------------------------------------------
/logo@16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/logo@16.png
--------------------------------------------------------------------------------
/logo@32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/logo@32.png
--------------------------------------------------------------------------------
/macos/.gitignore:
--------------------------------------------------------------------------------
1 | # Flutter-related
2 | **/Flutter/ephemeral/
3 | **/Pods/
4 |
5 | # Xcode-related
6 | **/dgph
7 | **/xcuserdata/
8 |
--------------------------------------------------------------------------------
/macos/Flutter/Flutter-Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "ephemeral/Flutter-Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/macos/Flutter/Flutter-Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "ephemeral/Flutter-Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/macos/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/macos/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import Cocoa
2 | import FlutterMacOS
3 |
4 | @main
5 | class AppDelegate: FlutterAppDelegate {
6 | override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
7 | return true
8 | }
9 |
10 | override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool {
11 | return true
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png
--------------------------------------------------------------------------------
/macos/Runner/Configs/AppInfo.xcconfig:
--------------------------------------------------------------------------------
1 | // Application-level settings for the Runner target.
2 | //
3 | // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the
4 | // future. If not, the values below would default to using the project name when this becomes a
5 | // 'flutter create' template.
6 |
7 | // The application's name. By default this is also the title of the Flutter window.
8 | PRODUCT_NAME = Flow
9 |
10 | // The application's bundle identifier
11 | PRODUCT_BUNDLE_IDENTIFIER = mn.flow.flow
12 |
13 | // The copyright displayed in application information
14 | PRODUCT_COPYRIGHT = Copyright © 2023 Batmend Ganbaatar and Authors of Flow All rights reserved.
15 |
--------------------------------------------------------------------------------
/macos/Runner/Configs/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "../../Flutter/Flutter-Debug.xcconfig"
2 | #include "Warnings.xcconfig"
3 |
4 | PRODUCT_NAME = Flow (dev)
--------------------------------------------------------------------------------
/macos/Runner/Configs/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "../../Flutter/Flutter-Release.xcconfig"
2 | #include "Warnings.xcconfig"
3 |
--------------------------------------------------------------------------------
/macos/Runner/Configs/Warnings.xcconfig:
--------------------------------------------------------------------------------
1 | WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings
2 | GCC_WARN_UNDECLARED_SELECTOR = YES
3 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES
4 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE
5 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES
6 | CLANG_WARN_PRAGMA_PACK = YES
7 | CLANG_WARN_STRICT_PROTOTYPES = YES
8 | CLANG_WARN_COMMA = YES
9 | GCC_WARN_STRICT_SELECTOR_MATCH = YES
10 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES
11 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES
12 | GCC_WARN_SHADOW = YES
13 | CLANG_WARN_UNREACHABLE_CODE = YES
14 |
--------------------------------------------------------------------------------
/macos/Runner/DebugProfile.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.cs.allow-jit
8 |
9 | com.apple.security.files.user-selected.read-only
10 |
11 | com.apple.security.network.client
12 |
13 | com.apple.security.network.server
14 |
15 | com.apple.security.application-groups
16 |
17 | NJH37247C9.flow
18 |
19 | com.apple.security.files.downloads.read-write
20 |
21 |
22 |
--------------------------------------------------------------------------------
/macos/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIconFile
10 |
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | $(FLUTTER_BUILD_NAME)
21 | CFBundleVersion
22 | $(FLUTTER_BUILD_NUMBER)
23 | LSMinimumSystemVersion
24 | $(MACOSX_DEPLOYMENT_TARGET)
25 | NSHumanReadableCopyright
26 | $(PRODUCT_COPYRIGHT)
27 | NSMainNibFile
28 | MainMenu
29 | NSPrincipalClass
30 | NSApplication
31 | com.apple.security.files.downloads.read-write
32 |
33 | NSLocationWhenInUseUsageDescription
34 | Location is used if you choose to auto-attach your current location to your transactions.
35 |
36 |
--------------------------------------------------------------------------------
/macos/Runner/MainFlutterWindow.swift:
--------------------------------------------------------------------------------
1 | import Cocoa
2 | import FlutterMacOS
3 |
4 | class MainFlutterWindow: NSWindow {
5 | override func awakeFromNib() {
6 | let flutterViewController = FlutterViewController()
7 | let windowFrame = self.frame
8 | self.contentViewController = flutterViewController
9 | self.setFrame(windowFrame, display: true)
10 |
11 | RegisterGeneratedPlugins(registry: flutterViewController)
12 |
13 | super.awakeFromNib()
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/macos/Runner/Release.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.files.user-selected.read-only
8 |
9 | com.apple.security.network.client
10 |
11 | com.apple.security.network.server
12 |
13 | com.apple.security.application-groups
14 |
15 | NJH37247C9.flow
16 |
17 | com.apple.security.files.downloads.read-write
18 |
19 |
20 |
--------------------------------------------------------------------------------
/macos/RunnerTests/RunnerTests.swift:
--------------------------------------------------------------------------------
1 | import FlutterMacOS
2 | import Cocoa
3 | import XCTest
4 |
5 | class RunnerTests: XCTestCase {
6 |
7 | func testExample() {
8 | // If you add code to the Runner application, consider adding tests here.
9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest.
10 | }
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/reformat_l10n_files.sh:
--------------------------------------------------------------------------------
1 | dart ./scripts/reformat_l10n_files.dart
--------------------------------------------------------------------------------
/regenerate_code.sh:
--------------------------------------------------------------------------------
1 | dart run build_runner build --delete-conflicting-outputs && dart format lib
2 |
--------------------------------------------------------------------------------
/scripts/reformat_l10n_files.dart:
--------------------------------------------------------------------------------
1 | import "dart:convert";
2 | import "dart:io";
3 |
4 | void reformat(File file) {
5 | final String content = file.readAsStringSync();
6 | final Map jsonMap = jsonDecode(content);
7 | final List keys = jsonMap.keys.toList();
8 | final List sortedKeys = List.from(keys)..sort();
9 | final Map sortedJsonMap = {};
10 | for (String key in sortedKeys) {
11 | sortedJsonMap[key] = jsonMap[key];
12 | }
13 |
14 | file.writeAsStringSync(JsonEncoder.withIndent(" ").convert(sortedJsonMap));
15 | }
16 |
17 | void main() {
18 | final Directory directory = Directory("assets/l10n");
19 |
20 | if (!directory.existsSync()) {
21 | throw Exception("Directory does not exist");
22 | }
23 |
24 | directory
25 | .listSync()
26 | .where((entry) => entry is File && entry.path.endsWith(".json"))
27 | .cast()
28 | .forEach(reformat);
29 | }
30 |
--------------------------------------------------------------------------------
/test/backup/v1_export.dart:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/test/backup/v1_import.dart:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/test/backup/v1_import.dart
--------------------------------------------------------------------------------
/test/import/csv_data_parser_test.dart:
--------------------------------------------------------------------------------
1 | import "dart:io";
2 |
3 | import "package:flow/sync/model/csv/parsed_data.dart";
4 | import "package:flow/sync/model/csv/parsers.dart";
5 | import "package:flutter_test/flutter_test.dart";
6 |
7 | void main() {
8 | test("A valid csv", () async {
9 | final valid = await CSVParsedData.fromFile(
10 | File("test/import/valid-1.csv"),
11 | ).then((v) => v as CSVParsedData?).catchError((e) => null);
12 |
13 | expect(valid, isNotNull);
14 | expect(valid?.accountNames.length, 3);
15 | expect(valid?.categoryNames.nonNulls.length, 24);
16 | expect(valid?.transactions.length, 81);
17 | });
18 | test("An invalid csv", () async {
19 | final invalid = await CSVParsedData.fromFile(
20 | File("test/import/invalid-1.csv"),
21 | ).then((e) => e as dynamic).catchError((e) => e);
22 |
23 | expect(invalid, CSVCellParserError.invalidDate);
24 | });
25 | }
26 |
--------------------------------------------------------------------------------
/test/l10n/json_integrity_test.dart:
--------------------------------------------------------------------------------
1 | import "dart:convert";
2 | import "dart:io";
3 |
4 | import "package:test/test.dart";
5 | import "package:path/path.dart";
6 |
7 | List getKeys(File file) {
8 | final String content = file.readAsStringSync();
9 | final Map jsonMap = jsonDecode(content);
10 | return jsonMap.keys.toList();
11 | }
12 |
13 | void main() {
14 | final Directory directory = Directory("assets/l10n");
15 |
16 | final File baseFile = File("assets/l10n/en.json");
17 |
18 | test("Directory exists", () {
19 | expect(directory.existsSync(), true);
20 | });
21 |
22 | test("Base file exists", () {
23 | expect(baseFile.existsSync(), true);
24 | });
25 |
26 | final List keys = getKeys(baseFile);
27 |
28 | test("No duplicate keys in base file", () {
29 | final Set uniqueKeys = keys.toSet();
30 | expect(uniqueKeys.length, keys.length);
31 | });
32 |
33 | for (final entry in directory.listSync()) {
34 | if (entry is! File) continue;
35 | if (!entry.path.endsWith(".json")) continue;
36 | if (entry.path == baseFile.path) continue;
37 |
38 | test("File ${basename(entry.path)} has all keys in same order", () {
39 | final languageKeys = getKeys(entry);
40 |
41 | for (int i = 0; i < keys.length; i++) {
42 | expect(languageKeys[i], keys[i]);
43 | }
44 | });
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/test/objectbox_erase.dart:
--------------------------------------------------------------------------------
1 | import "dart:io";
2 |
3 | import "package:flow/objectbox.dart";
4 |
5 | Future testCleanupObject({
6 | required ObjectBox instance,
7 | required String directory,
8 | bool cleanUp = true,
9 | }) async {
10 | instance.store.close();
11 |
12 | if (cleanUp) {
13 | await Directory(directory).delete(recursive: true);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/windows/.gitignore:
--------------------------------------------------------------------------------
1 | flutter/ephemeral/
2 |
3 | # Visual Studio user-specific files.
4 | *.suo
5 | *.user
6 | *.userosscache
7 | *.sln.docstates
8 |
9 | # Visual Studio build-related files.
10 | x64/
11 | x86/
12 |
13 | # Visual Studio cache files
14 | # files ending in .cache can be ignored
15 | *.[Cc]ache
16 | # but keep track of directories ending in .cache
17 | !*.[Cc]ache/
18 |
--------------------------------------------------------------------------------
/windows/flutter/generated_plugin_registrant.h:
--------------------------------------------------------------------------------
1 | //
2 | // Generated file. Do not edit.
3 | //
4 |
5 | // clang-format off
6 |
7 | #ifndef GENERATED_PLUGIN_REGISTRANT_
8 | #define GENERATED_PLUGIN_REGISTRANT_
9 |
10 | #include
11 |
12 | // Registers Flutter plugins.
13 | void RegisterPlugins(flutter::PluginRegistry* registry);
14 |
15 | #endif // GENERATED_PLUGIN_REGISTRANT_
16 |
--------------------------------------------------------------------------------
/windows/flutter/generated_plugins.cmake:
--------------------------------------------------------------------------------
1 | #
2 | # Generated file, do not edit.
3 | #
4 |
5 | list(APPEND FLUTTER_PLUGIN_LIST
6 | connectivity_plus
7 | desktop_drop
8 | file_saver
9 | file_selector_windows
10 | flutter_timezone
11 | geolocator_windows
12 | local_auth_windows
13 | objectbox_flutter_libs
14 | screen_retriever_windows
15 | share_plus
16 | url_launcher_windows
17 | window_manager
18 | )
19 |
20 | list(APPEND FLUTTER_FFI_PLUGIN_LIST
21 | flutter_local_notifications_windows
22 | )
23 |
24 | set(PLUGIN_BUNDLED_LIBRARIES)
25 |
26 | foreach(plugin ${FLUTTER_PLUGIN_LIST})
27 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin})
28 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
29 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $)
30 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
31 | endforeach(plugin)
32 |
33 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
34 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin})
35 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
36 | endforeach(ffi_plugin)
37 |
--------------------------------------------------------------------------------
/windows/runner/flutter_window.h:
--------------------------------------------------------------------------------
1 | #ifndef RUNNER_FLUTTER_WINDOW_H_
2 | #define RUNNER_FLUTTER_WINDOW_H_
3 |
4 | #include
5 | #include
6 |
7 | #include
8 |
9 | #include "win32_window.h"
10 |
11 | // A window that does nothing but host a Flutter view.
12 | class FlutterWindow : public Win32Window {
13 | public:
14 | // Creates a new FlutterWindow hosting a Flutter view running |project|.
15 | explicit FlutterWindow(const flutter::DartProject& project);
16 | virtual ~FlutterWindow();
17 |
18 | protected:
19 | // Win32Window:
20 | bool OnCreate() override;
21 | void OnDestroy() override;
22 | LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam,
23 | LPARAM const lparam) noexcept override;
24 |
25 | private:
26 | // The project to run.
27 | flutter::DartProject project_;
28 |
29 | // The Flutter instance hosted by this window.
30 | std::unique_ptr flutter_controller_;
31 | };
32 |
33 | #endif // RUNNER_FLUTTER_WINDOW_H_
34 |
--------------------------------------------------------------------------------
/windows/runner/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include "flutter_window.h"
6 | #include "utils.h"
7 |
8 | int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
9 | _In_ wchar_t *command_line, _In_ int show_command) {
10 | // Attach to console when present (e.g., 'flutter run') or create a
11 | // new console when running with a debugger.
12 | if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) {
13 | CreateAndAttachConsole();
14 | }
15 |
16 | // Initialize COM, so that it is available for use in the library and/or
17 | // plugins.
18 | ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
19 |
20 | flutter::DartProject project(L"data");
21 |
22 | std::vector command_line_arguments =
23 | GetCommandLineArguments();
24 |
25 | project.set_dart_entrypoint_arguments(std::move(command_line_arguments));
26 |
27 | FlutterWindow window(project);
28 | Win32Window::Point origin(10, 10);
29 | Win32Window::Size size(1280, 720);
30 | if (!window.Create(L"Flow", origin, size)) {
31 | return EXIT_FAILURE;
32 | }
33 | window.SetQuitOnClose(true);
34 |
35 | ::MSG msg;
36 | while (::GetMessage(&msg, nullptr, 0, 0)) {
37 | ::TranslateMessage(&msg);
38 | ::DispatchMessage(&msg);
39 | }
40 |
41 | ::CoUninitialize();
42 | return EXIT_SUCCESS;
43 | }
44 |
--------------------------------------------------------------------------------
/windows/runner/resource.h:
--------------------------------------------------------------------------------
1 | //{{NO_DEPENDENCIES}}
2 | // Microsoft Visual C++ generated include file.
3 | // Used by Runner.rc
4 | //
5 | #define IDI_APP_ICON 101
6 |
7 | // Next default values for new objects
8 | //
9 | #ifdef APSTUDIO_INVOKED
10 | #ifndef APSTUDIO_READONLY_SYMBOLS
11 | #define _APS_NEXT_RESOURCE_VALUE 102
12 | #define _APS_NEXT_COMMAND_VALUE 40001
13 | #define _APS_NEXT_CONTROL_VALUE 1001
14 | #define _APS_NEXT_SYMED_VALUE 101
15 | #endif
16 | #endif
17 |
--------------------------------------------------------------------------------
/windows/runner/resources/app_icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flow-mn/flow/632f761cf1ad6d1463b296331b5af2679e900f2f/windows/runner/resources/app_icon.ico
--------------------------------------------------------------------------------
/windows/runner/runner.exe.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PerMonitorV2
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/windows/runner/utils.h:
--------------------------------------------------------------------------------
1 | #ifndef RUNNER_UTILS_H_
2 | #define RUNNER_UTILS_H_
3 |
4 | #include
5 | #include
6 |
7 | // Creates a console for the process, and redirects stdout and stderr to
8 | // it for both the runner and the Flutter library.
9 | void CreateAndAttachConsole();
10 |
11 | // Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string
12 | // encoded in UTF-8. Returns an empty std::string on failure.
13 | std::string Utf8FromUtf16(const wchar_t* utf16_string);
14 |
15 | // Gets the command line arguments passed in as a std::vector,
16 | // encoded in UTF-8. Returns an empty std::vector on failure.
17 | std::vector GetCommandLineArguments();
18 |
19 | #endif // RUNNER_UTILS_H_
20 |
--------------------------------------------------------------------------------