Repository: floranguyen0/mmas-money-tracker Branch: main Commit: c886e0fce272 Files: 141 Total size: 408.3 KB Directory structure: gitextract_sxwtmaf3/ ├── .gitignore ├── .metadata ├── LICENSE ├── README.md ├── android/ │ ├── .gitignore │ ├── app/ │ │ ├── build.gradle │ │ └── src/ │ │ ├── debug/ │ │ │ └── AndroidManifest.xml │ │ ├── main/ │ │ │ ├── AndroidManifest.xml │ │ │ ├── kotlin/ │ │ │ │ └── com/ │ │ │ │ └── mmas/ │ │ │ │ └── money_assistant_2608/ │ │ │ │ └── MainActivity.kt │ │ │ └── res/ │ │ │ ├── drawable/ │ │ │ │ └── launch_background.xml │ │ │ ├── drawable-v21/ │ │ │ │ └── launch_background.xml │ │ │ ├── values/ │ │ │ │ └── styles.xml │ │ │ └── values-night/ │ │ │ └── styles.xml │ │ └── profile/ │ │ └── AndroidManifest.xml │ ├── build.gradle │ ├── gradle/ │ │ └── wrapper/ │ │ └── gradle-wrapper.properties │ ├── gradle.properties │ └── settings.gradle ├── flutter ├── ios/ │ ├── .gitignore │ ├── Flutter/ │ │ ├── AppFrameworkInfo.plist │ │ ├── Debug.xcconfig │ │ └── Release.xcconfig │ ├── Podfile │ ├── Runner/ │ │ ├── AppDelegate.swift │ │ ├── Assets.xcassets/ │ │ │ ├── AppIcon.appiconset/ │ │ │ │ └── Contents.json │ │ │ ├── LaunchBackground.imageset/ │ │ │ │ └── Contents.json │ │ │ └── LaunchImage.imageset/ │ │ │ ├── Contents.json │ │ │ └── README.md │ │ ├── Base.lproj/ │ │ │ ├── LaunchScreen.storyboard │ │ │ └── Main.storyboard │ │ ├── GoogleService-Info.plist │ │ ├── Info.plist │ │ ├── Runner-Bridging-Header.h │ │ └── Runner.entitlements │ ├── Runner.xcodeproj/ │ │ ├── project.pbxproj │ │ ├── project.xcworkspace/ │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata/ │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ │ └── xcshareddata/ │ │ └── xcschemes/ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace/ │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata/ │ │ ├── IDEWorkspaceChecks.plist │ │ └── WorkspaceSettings.xcsettings │ └── build/ │ └── Pods.build/ │ └── Release-iphonesimulator/ │ ├── DKImagePickerController-DKImagePickerController.build/ │ │ ├── dgph │ │ └── dgph~ │ ├── DKImagePickerController.build/ │ │ ├── dgph │ │ └── dgph~ │ ├── DKPhotoGallery-DKPhotoGallery.build/ │ │ ├── dgph │ │ └── dgph~ │ ├── DKPhotoGallery.build/ │ │ ├── dgph │ │ └── dgph~ │ ├── FMDB.build/ │ │ ├── dgph │ │ └── dgph~ │ ├── Flutter.build/ │ │ ├── dgph │ │ └── dgph~ │ ├── Pods-Runner.build/ │ │ ├── dgph │ │ └── dgph~ │ ├── SDWebImage.build/ │ │ ├── dgph │ │ └── dgph~ │ ├── SwiftyGif.build/ │ │ ├── dgph │ │ └── dgph~ │ ├── Toast.build/ │ │ └── dgph │ ├── file_picker.build/ │ │ ├── dgph │ │ └── dgph~ │ ├── fluttertoast.build/ │ │ └── dgph │ ├── in_app_review.build/ │ │ ├── dgph │ │ └── dgph~ │ ├── local_auth.build/ │ │ └── dgph │ ├── path_provider.build/ │ │ ├── dgph │ │ └── dgph~ │ ├── rate_my_app.build/ │ │ └── dgph │ ├── share_plus.build/ │ │ ├── dgph │ │ └── dgph~ │ ├── shared_preferences.build/ │ │ ├── dgph │ │ └── dgph~ │ ├── sqflite.build/ │ │ ├── dgph │ │ └── dgph~ │ └── url_launcher.build/ │ ├── dgph │ └── dgph~ ├── lib/ │ ├── main.dart │ └── project/ │ ├── app_pages/ │ │ ├── add_category.dart │ │ ├── analysis.dart │ │ ├── calendar.dart │ │ ├── currency.dart │ │ ├── edit.dart │ │ ├── edit_expense_category.dart │ │ ├── edit_income_category.dart │ │ ├── expense_category.dart │ │ ├── income_category.dart │ │ ├── input.dart │ │ ├── others.dart │ │ ├── parent_category.dart │ │ ├── report.dart │ │ ├── select_date_format.dart │ │ ├── select_icon.dart │ │ └── select_language.dart │ ├── auth_pages/ │ │ ├── loading_page.dart │ │ ├── sign_in.dart │ │ ├── sign_up.dart │ │ ├── user_account.dart │ │ ├── welcome_page.dart │ │ └── wrapper.dart │ ├── auth_services/ │ │ └── firebase_authentication.dart │ ├── classes/ │ │ ├── alert_dialog.dart │ │ ├── app_bar.dart │ │ ├── category_item.dart │ │ ├── chart_pie.dart │ │ ├── constants.dart │ │ ├── custom_toast.dart │ │ ├── dropdown_box.dart │ │ ├── icons.dart │ │ ├── input_model.dart │ │ ├── keyboard.dart │ │ ├── lockscreen.dart │ │ └── saveOrSaveAndDeleteButtons.dart │ ├── database_management/ │ │ ├── database.dart │ │ ├── shared_preferences_services.dart │ │ └── sqflite_services.dart │ ├── draft1.dart │ ├── home.dart │ ├── localization/ │ │ ├── app_localization.dart │ │ ├── lang/ │ │ │ ├── ar.json │ │ │ ├── de.json │ │ │ ├── en.json │ │ │ ├── es.json │ │ │ ├── fr.json │ │ │ ├── hi.json │ │ │ ├── ja.json │ │ │ ├── ko.json │ │ │ ├── ne.json │ │ │ ├── pt.json │ │ │ ├── ru.json │ │ │ ├── tr.json │ │ │ ├── vi.json │ │ │ └── zh.json │ │ ├── language.dart │ │ └── methods.dart │ ├── provider.dart │ └── real_main.dart ├── pubspec.yaml └── test/ └── widget_test.dart ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # Miscellaneous *.class *.log *.pyc *.swp .DS_Store .atom/ .buildlog/ .history .svn/ # IntelliJ related *.iml *.ipr *.iws .idea/ # The .vscode folder contains launch configuration and tasks you configure in # VS Code which you may wish to be included in version control, so this line # is commented out by default. #.vscode/ # Flutter/Dart/Pub related **/doc/api/ **/ios/Flutter/.last_build_id .dart_tool/ .flutter-plugins .flutter-plugins-dependencies .packages .pub-cache/ .pub/ /build/ # Web related lib/generated_plugin_registrant.dart # Symbolication related app.*.symbols # Obfuscation related app.*.map.json # Android Studio will place build artifacts here /android/app/debug /android/app/profile /android/app/release ================================================ FILE: .metadata ================================================ # This file tracks properties of this Flutter project. # Used by Flutter tool to assess capabilities and perform upgrades etc. # # This file should be version controlled and should not be manually edited. version: revision: f4abaa0735eba4dfd8f33f73363911d63931fe03 channel: stable project_type: app ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2021 Hoa Nguyen Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # MMAS: Money Tracker > An optimized application for daily expense tracking and finance management.
![MMAS (820 x 360 px)](https://user-images.githubusercontent.com/72301141/206877824-90492e92-2e2d-4de6-b23c-312f283bdfd6.png) ## Setup Run the following commands from your terminal: 1) `git clone https://github.com/floranguyen0/mmas-money-tracker` to clone this repository 2) `flutter pub get` in the project root directory to install all the required dependencies. ## Download MMAS at: https://apps.apple.com/vn/app/mmas-money-tracker/id1582638369 ## Screenshots
## LICENSE MMAS: Money Tracker is [MIT-licensed](https://github.com/floranguyen0/mmas-money-tracker/blob/main/LICENSE). ================================================ FILE: android/.gitignore ================================================ gradle-wrapper.jar /.gradle /captures/ /gradlew /gradlew.bat /local.properties GeneratedPluginRegistrant.java # Remember to never publicly share your keystore. # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app key.properties app/upload-keystore.jks ================================================ FILE: android/app/build.gradle ================================================ def localProperties = new Properties() def localPropertiesFile = rootProject.file('local.properties') if (localPropertiesFile.exists()) { localPropertiesFile.withReader('UTF-8') { reader -> localProperties.load(reader) } } def flutterRoot = localProperties.getProperty('flutter.sdk') if (flutterRoot == null) { throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") } def flutterVersionCode = localProperties.getProperty('flutter.versionCode') if (flutterVersionCode == null) { flutterVersionCode = '1' } def flutterVersionName = localProperties.getProperty('flutter.versionName') if (flutterVersionName == null) { flutterVersionName = '1.0' } apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" def keystoreProperties = new Properties() def keystorePropertiesFile = rootProject.file('key.properties') if (keystorePropertiesFile.exists()) { keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) } android { compileSdkVersion 30 sourceSets { main.java.srcDirs += 'src/main/kotlin' } defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "com.mmas.money_assistant_2608" minSdkVersion 16 targetSdkVersion 33 versionCode flutterVersionCode.toInteger() versionName flutterVersionName } signingConfigs { release { keyAlias keystoreProperties['keyAlias'] keyPassword keystoreProperties['keyPassword'] storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null storePassword keystoreProperties['storePassword'] } } buildTypes { release { signingConfig signingConfigs.release } } } flutter { source '../..' } dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" } ================================================ FILE: android/app/src/debug/AndroidManifest.xml ================================================ ================================================ FILE: android/app/src/main/AndroidManifest.xml ================================================ ================================================ FILE: android/app/src/main/kotlin/com/mmas/money_assistant_2608/MainActivity.kt ================================================ package com.mmas.money_assistant_2608 import io.flutter.embedding.android.FlutterActivity class MainActivity: FlutterActivity() { } ================================================ FILE: android/app/src/main/res/drawable/launch_background.xml ================================================ ================================================ FILE: android/app/src/main/res/drawable-v21/launch_background.xml ================================================ ================================================ FILE: android/app/src/main/res/values/styles.xml ================================================ ================================================ FILE: android/app/src/main/res/values-night/styles.xml ================================================ ================================================ FILE: android/app/src/profile/AndroidManifest.xml ================================================ ================================================ FILE: android/build.gradle ================================================ buildscript { ext.kotlin_version = '1.8.0' repositories { google() jcenter() } dependencies { classpath 'com.android.tools.build:gradle:4.1.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } allprojects { repositories { google() jcenter() } } rootProject.buildDir = '../build' subprojects { project.buildDir = "${rootProject.buildDir}/${project.name}" project.evaluationDependsOn(':app') } task clean(type: Delete) { delete rootProject.buildDir } ================================================ FILE: android/gradle/wrapper/gradle-wrapper.properties ================================================ #Fri Jun 23 08:50:38 CEST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-bin.zip ================================================ FILE: android/gradle.properties ================================================ #org.gradle.jvmargs=-Xmx1536M android.useAndroidX=true android.enableJetifier=true org.gradle.java.home=C:/Program Files/Java/jdk-19 org.gradle.jvmargs=--add-opens java.base/java.io=ALL-UNNAMED ================================================ FILE: android/settings.gradle ================================================ include ':app' def localPropertiesFile = new File(rootProject.projectDir, "local.properties") def properties = new Properties() assert localPropertiesFile.exists() localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } def flutterSdkPath = properties.getProperty("flutter.sdk") assert flutterSdkPath != null, "flutter.sdk not set in local.properties" apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" ================================================ FILE: flutter ================================================ ================================================ FILE: ios/.gitignore ================================================ *.mode1v3 *.mode2v3 *.moved-aside *.pbxuser *.perspectivev3 **/*sync/ .sconsign.dblite .tags* **/.vagrant/ **/DerivedData/ Icon? **/Pods/ **/.symlinks/ profile xcuserdata **/.generated/ Flutter/App.framework Flutter/Flutter.framework Flutter/Flutter.podspec Flutter/Generated.xcconfig Flutter/ephemeral/ Flutter/app.flx Flutter/app.zip Flutter/flutter_assets/ Flutter/flutter_export_environment.sh ServiceDefinitions.json Runner/GeneratedPluginRegistrant.* # Exceptions to above rules. !default.mode1v3 !default.mode2v3 !default.pbxuser !default.perspectivev3 ================================================ FILE: ios/Flutter/AppFrameworkInfo.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable App CFBundleIdentifier io.flutter.flutter.app CFBundleInfoDictionaryVersion 6.0 CFBundleName App CFBundlePackageType FMWK CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1.0 MinimumOSVersion 9.0 ================================================ FILE: ios/Flutter/Debug.xcconfig ================================================ #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" ================================================ FILE: ios/Flutter/Release.xcconfig ================================================ #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" ================================================ FILE: ios/Podfile ================================================ # Uncomment this line to define a global platform for your project platform :ios, '9.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' project 'Runner', { 'Debug' => :debug, 'Profile' => :release, 'Release' => :release, } def flutter_root generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) unless File.exist?(generated_xcode_build_settings_path) raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" end File.foreach(generated_xcode_build_settings_path) do |line| matches = line.match(/FLUTTER_ROOT\=(.*)/) return matches[1].strip if matches end raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" end require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) flutter_ios_podfile_setup target 'Runner' do use_frameworks! use_modular_headers! flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) end post_install do |installer| installer.pods_project.targets.each do |target| flutter_additional_ios_build_settings(target) end end ================================================ FILE: ios/Runner/AppDelegate.swift ================================================ import UIKit import Flutter @UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } } ================================================ FILE: ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json ================================================ {"images":[{"size":"60x60","expected-size":"180","filename":"180.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"40x40","expected-size":"80","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"40x40","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"60x60","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"57x57","expected-size":"57","filename":"57.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"29x29","expected-size":"29","filename":"29.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"87","filename":"87.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"57x57","expected-size":"114","filename":"114.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"60","filename":"60.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"1024x1024","filename":"1024.png","expected-size":"1024","idiom":"ios-marketing","folder":"Assets.xcassets/AppIcon.appiconset/","scale":"1x"},{"size":"40x40","expected-size":"80","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"72x72","expected-size":"72","filename":"72.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"76x76","expected-size":"152","filename":"152.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"50x50","expected-size":"100","filename":"100.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"76x76","expected-size":"76","filename":"76.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"29x29","expected-size":"29","filename":"29.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"50x50","expected-size":"50","filename":"50.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"72x72","expected-size":"144","filename":"144.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"40x40","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"83.5x83.5","expected-size":"167","filename":"167.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"20x20","expected-size":"20","filename":"20.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"20x20","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"}]} ================================================ FILE: ios/Runner/Assets.xcassets/LaunchBackground.imageset/Contents.json ================================================ { "images" : [ { "filename" : "background.png", "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json ================================================ { "images" : [ { "filename" : "LaunchImage.png", "idiom" : "universal", "scale" : "1x" }, { "filename" : "LaunchImage@2x.png", "idiom" : "universal", "scale" : "2x" }, { "filename" : "LaunchImage@3x.png", "idiom" : "universal", "scale" : "3x" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md ================================================ # Launch Screen Assets You can customize the launch screen with your own desired assets by replacing the image files in this directory. You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. ================================================ FILE: ios/Runner/Base.lproj/LaunchScreen.storyboard ================================================ ================================================ FILE: ios/Runner/Base.lproj/Main.storyboard ================================================ ================================================ FILE: ios/Runner/GoogleService-Info.plist ================================================ CLIENT_ID 189781709351-2fgub7ut4f44e7seqvdgaebid05e8mgd.apps.googleusercontent.com REVERSED_CLIENT_ID com.googleusercontent.apps.189781709351-2fgub7ut4f44e7seqvdgaebid05e8mgd API_KEY AIzaSyC_4qm52Vkak1c_a-WucmgTY1GLhQvIp-g GCM_SENDER_ID 189781709351 PLIST_VERSION 1 BUNDLE_ID com.example.moneyAssistant2608 PROJECT_ID mmas-moneytracker STORAGE_BUCKET mmas-moneytracker.appspot.com IS_ADS_ENABLED IS_ANALYTICS_ENABLED IS_APPINVITE_ENABLED IS_GCM_ENABLED IS_SIGNIN_ENABLED GOOGLE_APP_ID 1:189781709351:ios:53aeb605dc2b087285b402 ================================================ FILE: ios/Runner/Info.plist ================================================ CFBundleDevelopmentRegion en-US CFBundleDisplayName MMAS CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleLocalizations en zh zh_CN fr de ja ko CFBundleName MMAS CFBundlePackageType APPL CFBundleShortVersionString $(FLUTTER_BUILD_NAME) CFBundleSignature ???? CFBundleVersion $(FLUTTER_BUILD_NUMBER) LSRequiresIPhoneOS NSPhotoLibraryUsageDescription We access your photo library to add a photo of your bills to your expense/income records UILaunchStoryboardName LaunchScreen UIMainStoryboardFile Main UIStatusBarHidden UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortraitUpsideDown UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIViewControllerBasedStatusBarAppearance CFBundleURLTypes CFBundleTypeRole Editor CFBundleURLSchemes com.googleusercontent.apps.189781709351-2fgub7ut4f44e7seqvdgaebid05e8mgd ================================================ FILE: ios/Runner/Runner-Bridging-Header.h ================================================ #import "GeneratedPluginRegistrant.h" ================================================ FILE: ios/Runner/Runner.entitlements ================================================ aps-environment development ================================================ FILE: ios/Runner.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 51; objects = { /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 23D73B63272C62B1009E72A7 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 23D73B62272C62B1009E72A7 /* GoogleService-Info.plist */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 61499E5D1D041FF00E95B707 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B99D98016620F7A28ACDC882 /* Pods_Runner.framework */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ 9705A1C41CF9048500538489 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 10; files = ( ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 23D73B62272C62B1009E72A7 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; 23E42C6126E530110040CEF6 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 3CAD1B05AD9D13F3D49A238F /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 6F42B7B7C5C3973C91F87BBA /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; B99D98016620F7A28ACDC882 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; B9A5FB7A6583188949FF87EB /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 97C146EB1CF9000F007C117D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 61499E5D1D041FF00E95B707 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 5A2F1614F901E5E08066321B /* Frameworks */ = { isa = PBXGroup; children = ( B99D98016620F7A28ACDC882 /* Pods_Runner.framework */, ); name = Frameworks; sourceTree = ""; }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 9740EEB31CF90195004384FC /* Generated.xcconfig */, ); name = Flutter; sourceTree = ""; }; 97C146E51CF9000F007C117D = { isa = PBXGroup; children = ( 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, E1BD7345BC0DA67D9B5D118F /* Pods */, 5A2F1614F901E5E08066321B /* Frameworks */, ); sourceTree = ""; }; 97C146EF1CF9000F007C117D /* Products */ = { isa = PBXGroup; children = ( 97C146EE1CF9000F007C117D /* Runner.app */, ); name = Products; sourceTree = ""; }; 97C146F01CF9000F007C117D /* Runner */ = { isa = PBXGroup; children = ( 23D73B62272C62B1009E72A7 /* GoogleService-Info.plist */, 23E42C6126E530110040CEF6 /* Runner.entitlements */, 97C146FA1CF9000F007C117D /* Main.storyboard */, 97C146FD1CF9000F007C117D /* Assets.xcassets */, 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 97C147021CF9000F007C117D /* Info.plist */, 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, ); path = Runner; sourceTree = ""; }; E1BD7345BC0DA67D9B5D118F /* Pods */ = { isa = PBXGroup; children = ( B9A5FB7A6583188949FF87EB /* Pods-Runner.debug.xcconfig */, 3CAD1B05AD9D13F3D49A238F /* Pods-Runner.release.xcconfig */, 6F42B7B7C5C3973C91F87BBA /* Pods-Runner.profile.xcconfig */, ); path = Pods; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 97C146ED1CF9000F007C117D /* Runner */ = { isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( 79D9EC2F681B8FDF039DE67A /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, D1539A2B591CC9A875AC7664 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); dependencies = ( ); name = Runner; productName = Runner; productReference = 97C146EE1CF9000F007C117D /* Runner.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 1020; ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; LastSwiftMigration = 1100; }; }; }; buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; compatibilityVersion = "Xcode 9.3"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = 97C146E51CF9000F007C117D; productRefGroup = 97C146EF1CF9000F007C117D /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 97C146ED1CF9000F007C117D /* Runner */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 97C146EC1CF9000F007C117D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 23D73B63272C62B1009E72A7 /* GoogleService-Info.plist in Resources */, 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = "Thin Binary"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; 79D9EC2F681B8FDF039DE67A /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( ); inputPaths = ( "${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; outputFileListPaths = ( ); outputPaths = ( "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = "Run Script"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; D1539A2B591CC9A875AC7664 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 97C146EA1CF9000F007C117D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ 97C146FA1CF9000F007C117D /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( 97C146FB1CF9000F007C117D /* Base */, ); name = Main.storyboard; sourceTree = ""; }; 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { isa = PBXVariantGroup; children = ( 97C147001CF9000F007C117D /* Base */, ); name = LaunchScreen.storyboard; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 249021D3217E4FDB00AE95B9 /* Profile */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 9.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; name = Profile; }; 249021D4217E4FDB00AE95B9 /* Profile */ = { isa = XCBuildConfiguration; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 2U5AVM796N; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = com.example.moneyAssistant2608; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 1; VERSIONING_SYSTEM = "apple-generic"; }; name = Profile; }; 97C147031CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 9.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; 97C147041CF9000F007C117D /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 9.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; name = Release; }; 97C147061CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 2U5AVM796N; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = com.example.moneyAssistant2608; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 1; VERSIONING_SYSTEM = "apple-generic"; }; name = Debug; }; 97C147071CF9000F007C117D /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 2U5AVM796N; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = com.example.moneyAssistant2608; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 1; VERSIONING_SYSTEM = "apple-generic"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { isa = XCConfigurationList; buildConfigurations = ( 97C147031CF9000F007C117D /* Debug */, 97C147041CF9000F007C117D /* Release */, 249021D3217E4FDB00AE95B9 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { isa = XCConfigurationList; buildConfigurations = ( 97C147061CF9000F007C117D /* Debug */, 97C147071CF9000F007C117D /* Release */, 249021D4217E4FDB00AE95B9 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 97C146E61CF9000F007C117D /* Project object */; } ================================================ FILE: ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ================================================ IDEDidComputeMac32BitWarning ================================================ FILE: ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings ================================================ PreviewsEnabled ================================================ FILE: ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme ================================================ ================================================ FILE: ios/Runner.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ================================================ IDEDidComputeMac32BitWarning ================================================ FILE: ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings ================================================ PreviewsEnabled ================================================ FILE: lib/main.dart ================================================ // @dart=2.9 import 'package:money_assistant_2608/project/real_main.dart'; void main() async { realMain(); } ================================================ FILE: lib/project/app_pages/add_category.dart ================================================ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:money_assistant_2608/project/app_pages/parent_category.dart'; import 'package:money_assistant_2608/project/classes/app_bar.dart'; import 'package:money_assistant_2608/project/classes/category_item.dart'; import 'package:money_assistant_2608/project/classes/constants.dart'; import 'package:money_assistant_2608/project/classes/saveOrSaveAndDeleteButtons.dart'; import 'package:money_assistant_2608/project/database_management/shared_preferences_services.dart'; import 'package:money_assistant_2608/project/localization/methods.dart'; import 'package:money_assistant_2608/project/provider.dart'; import 'package:provider/provider.dart'; import 'select_icon.dart'; class AddCategory extends StatelessWidget { final BuildContext? contextEx, contextExEdit, contextInEdit, contextIn; final String type, appBarTitle; final String? categoryName, description; final IconData? categoryIcon; final CategoryItem? parentItem; static final _formKey4 = GlobalKey(debugLabel: '_formKey4'), _formKey5 = GlobalKey(debugLabel: '_formKey5'); AddCategory( {this.contextExEdit, this.contextEx, this.contextInEdit, this.contextIn, required this.type, required this.appBarTitle, this.categoryName, this.categoryIcon, this.parentItem, this.description}); void unFocusNode(BuildContext context) { FocusScopeNode currentFocus = FocusScope.of(context); if (!currentFocus.hasPrimaryFocus) { currentFocus.unfocus(); } } @override Widget build(BuildContext context) { return GestureDetector( onTap: () { unFocusNode(context); }, child: Scaffold( backgroundColor: blue1, appBar: BasicAppBar(this.appBarTitle), body: Form( key: this.type == 'Income' ? _formKey4 : _formKey5, child: ChangeNotifierProvider( create: (context) => ChangeCategory(), child: ListView( children: [ CategoryName( this.type, this.categoryName == null ? null : getTranslated(context, this.categoryName!) ?? this.categoryName, this.categoryIcon), // Hide ParentCategoryCard when either type is Income or users press on parent category // Fix this? why not (this.categoryName == null && this.parentCategory != null) this.type == 'Income' || (this.categoryName != null && this.parentItem == null) ? SizedBox() : ParentCategoryCard(this.parentItem), SizedBox( height: 20.h, ), Description(this.description), Padding( padding: EdgeInsets.symmetric(vertical: 90.h), child: Save( formKey: this.type == 'Income' ? _formKey4 : _formKey5, contextEx: this.contextEx, contextExEdit: this.contextExEdit, contextIn: this.contextIn, contextInEdit: this.contextInEdit, categoryName: this.categoryName, categoryIcon: this.categoryIcon, parentItem: this.parentItem, description: this.description)) ], ), ), ), )); } } class CategoryName extends StatefulWidget { final String type; final String? categoryName; final IconData? categoryIcon; CategoryName(this.type, this.categoryName, this.categoryIcon); @override _CategoryNameState createState() => _CategoryNameState(); } class _CategoryNameState extends State { // late final FocusNode categoryNameFocusNode; static late TextEditingController categoryNameController; final FocusNode categoryNameFocusNode = FocusNode(); @override void initState() { super.initState(); // categoryNameFocusNode = FocusNode(); categoryNameController = TextEditingController(text: widget.categoryName ?? ''); } // @override // void dispose() { // categoryNameFocusNode.dispose(); // super.dispose(); // } @override Widget build(BuildContext context) { return Card( elevation: 7, child: Padding( padding: EdgeInsets.only(left: 10.w, top: 8.h, bottom: 8.h), child: TextFormField( controller: categoryNameController, focusNode: categoryNameFocusNode, onChanged: (value) => {}, maxLines: null, cursorColor: blue1, textCapitalization: TextCapitalization.sentences, style: TextStyle(fontSize: 22.sp, fontWeight: FontWeight.bold), validator: (categoryNameInput) { categoryNameInput = categoryNameInput!.trim(); if (categoryNameInput.isEmpty) { return getTranslated(context, 'Please fill a category name'); } else { bool isIdenticalCategory() { if (widget.type == 'Income') { for (CategoryItem incomeItem in incomeItems) { if (categoryNameInput == incomeItem.text) { return true; } } } else { List expenseItems = []; sharedPrefs.getAllExpenseItemsLists().forEach( (parentExpenseItem) => parentExpenseItem.forEach( (expenseItem) => expenseItems.add(expenseItem))); for (CategoryItem expenseItem in expenseItems) { if (categoryNameInput == expenseItem.text) { return true; } } } return false; } // Show an error if users want to edit to or add an existing category if ((categoryNameInput != widget.categoryName) && (isIdenticalCategory())) { return getTranslated(context, 'Category already exists'); } } }, decoration: InputDecoration( border: InputBorder.none, hintText: getTranslated(context, 'Category name'), hintStyle: TextStyle( fontSize: 22.sp, color: grey, fontStyle: FontStyle.italic, fontWeight: FontWeight.normal), suffixIcon: categoryNameController.text.length > 0 ? IconButton( icon: Icon(Icons.clear), onPressed: () { categoryNameController.clear(); }) : SizedBox(), icon: Selector( selector: (_, provider) => provider.selectedCategoryIcon, builder: (context, selectedCategoryIcon, child) { return GestureDetector( onTap: () async { IconData? selectedIcon = await Navigator.push( context, MaterialPageRoute( builder: (context) => SelectIcon(widget.type))) ?? selectedCategoryIcon; context .read() .changeCategoryIcon(selectedIcon); }, child: Column( children: [ CircleAvatar( radius: 20.r, backgroundColor: Color.fromRGBO(215, 223, 231, 1), child: Icon( selectedCategoryIcon ?? widget.categoryIcon ?? Icons.category_outlined, size: 25.sp, color: widget.type == 'Income' ? green : red, )), SizedBox( height: 2, ), Text( 'select icon', style: TextStyle(fontSize: 11, color: Colors.blueGrey), ) ], ), ); })), ), ), ); } } class ParentCategoryCard extends StatefulWidget { final CategoryItem? parentItem; const ParentCategoryCard(this.parentItem); @override _ParentCategoryCardState createState() => _ParentCategoryCardState(); } class _ParentCategoryCardState extends State { @override Widget build(BuildContext context) { return Selector( selector: (_, provider) => provider.parentItem, builder: (context, selectedParentItem, child) { selectedParentItem ??= widget.parentItem ?? categoryItem(Icons.category_outlined, getTranslated(context, 'Parent category')!); context.read().parentItem = selectedParentItem; return GestureDetector( onTap: () async { CategoryItem newParentItem = await Navigator.push( context, MaterialPageRoute( builder: (context) => ParentCategoryList())); context.read().changeParentItem(newParentItem); }, child: Card( elevation: 7, child: Padding( padding: EdgeInsets.only(left: 18.w, top: 6.h, bottom: 6.h), child: Row( children: [ CircleAvatar( radius: 20.r, backgroundColor: Color.fromRGBO(215, 223, 231, 1), child: Icon( iconData(selectedParentItem), size: 25.sp, color: red, )), SizedBox( width: 28.w, ), Text( getTranslated(context, selectedParentItem.text) ?? selectedParentItem.text, style: selectedParentItem.text == getTranslated(context, 'Parent category')! ? TextStyle( fontSize: 22.sp, color: grey, fontStyle: FontStyle.italic, ) : TextStyle( fontSize: 22.sp, color: red, fontWeight: FontWeight.bold), ), Spacer(), Icon( Icons.arrow_forward_ios, size: 22.sp, ), SizedBox( width: 10.h, ) ], ), ), )); }); } } class Description extends StatefulWidget { final String? description; Description(this.description); @override _DescriptionState createState() => _DescriptionState(); } class _DescriptionState extends State { final FocusNode descriptionFocusNode = FocusNode(); static late TextEditingController descriptionController; @override void initState() { super.initState(); descriptionController = TextEditingController(text: widget.description ?? ''); } @override Widget build(BuildContext context) { return Card( elevation: 7, child: SizedBox( child: Padding( padding: EdgeInsets.symmetric(horizontal: 15.w, vertical: 6.h), child: TextFormField( controller: descriptionController, focusNode: descriptionFocusNode, maxLines: null, minLines: 1, cursorColor: blue1, textCapitalization: TextCapitalization.sentences, style: TextStyle(fontSize: 22.sp), decoration: InputDecoration( border: InputBorder.none, hintText: getTranslated(context, 'Description') ?? 'Description', hintStyle: GoogleFonts.cousine( fontSize: 21.5.sp, fontStyle: FontStyle.italic, ), suffixIcon: descriptionController.text.length > 0 ? IconButton( icon: Icon(Icons.clear), onPressed: () { descriptionController.clear(); }) : SizedBox(), icon: Padding( padding: EdgeInsets.only(right: 10.w), child: Icon( Icons.description_outlined, size: 35.sp, color: Colors.blueGrey, ), ))), ), ), ); } } class Save extends StatefulWidget { final GlobalKey formKey; final BuildContext? contextEx, contextExEdit, contextIn, contextInEdit; final String? categoryName, description; final IconData? categoryIcon; final CategoryItem? parentItem; const Save( {required this.formKey, this.contextEx, this.contextExEdit, this.contextIn, this.contextInEdit, this.categoryName, this.categoryIcon, this.parentItem, this.description}); @override _SaveState createState() => _SaveState(); } class _SaveState extends State { @override Widget build(BuildContext context) { void saveCategoryFunction() { if (widget.formKey.currentState!.validate()) { String? finalDescription = _DescriptionState.descriptionController.text; String finalCategoryName = _CategoryNameState.categoryNameController.text; IconData? finalCategoryIcon = Provider.of(context, listen: false) .selectedCategoryIcon; // trim to get a real input finalCategoryName = finalCategoryName.trim(); finalDescription = finalDescription.trim(); CategoryItem categoryItem(IconData iconData) => CategoryItem( iconData.codePoint, iconData.fontPackage, iconData.fontFamily, finalCategoryName, finalDescription); void updateCategory() { Provider.of(widget.contextExEdit!, listen: false) .getAllExpenseItems(); Provider.of(widget.contextEx!, listen: false) .getAllExpenseItems(); } if (widget.contextInEdit != null) { print('income'); if (widget.categoryName != null) { print('edit'); if (finalCategoryName != widget.categoryName || widget.categoryIcon != finalCategoryIcon || widget.description != finalDescription) { print('something changed'); incomeItems .removeWhere((item) => item.text == widget.categoryName); } } incomeItems.add(categoryItem(finalCategoryIcon ?? widget.categoryIcon ?? Icons.category_outlined)); sharedPrefs.saveItems('income items', incomeItems); Provider.of(widget.contextInEdit!, listen: false) .getIncomeItems(); if (widget.contextIn != null) { Provider.of(widget.contextIn!, listen: false) .getIncomeItems(); } } else { print('expense'); CategoryItem? finalParent = context.read().parentItem; if ((widget.categoryName == null) && (widget.parentItem == null)) { CategoryItem item = categoryItem(finalCategoryIcon ?? Icons.category_outlined); print('add expense'); if (finalParent!.text == getTranslated(context, 'Parent category')!) { print('add parent'); sharedPrefs.saveItems(finalCategoryName, [item]); var parentExpenseItemNames = sharedPrefs.parentExpenseItemNames; parentExpenseItemNames.add(finalCategoryName); sharedPrefs.parentExpenseItemNames = parentExpenseItemNames; } else { print('add new expense category to an existing parent'); List items = sharedPrefs.getItems(finalParent.text); items.add(item); sharedPrefs.saveItems(finalParent.text, items); } updateCategory(); } else { print('edit'); if (widget.parentItem == null) { print('edit parent only'); if (finalCategoryName != widget.categoryName || widget.categoryIcon != finalCategoryIcon || widget.description != finalDescription) { print('something changed'); List items = sharedPrefs.getItems(widget.categoryName!); items.removeAt(0); items.insert( 0, categoryItem(finalCategoryIcon ?? widget.categoryIcon!)); sharedPrefs.saveItems(finalCategoryName, items); if (finalCategoryName != widget.categoryName) { print('parent name changed'); var parentExpenseItemNames = sharedPrefs.parentExpenseItemNames; parentExpenseItemNames.removeWhere((parentExpenseItemName) => widget.categoryName == parentExpenseItemName); parentExpenseItemNames.insert(0, finalCategoryName); sharedPrefs.parentExpenseItemNames = parentExpenseItemNames; } updateCategory(); } } else { print('edit category'); if (finalParent!.text != widget.parentItem!.text || widget.categoryIcon != finalCategoryIcon || finalCategoryName != widget.categoryName || widget.description != finalDescription) { print('something changed'); void itemsAdd(List items) { items.add( categoryItem(finalCategoryIcon ?? widget.categoryIcon!)); } List items = sharedPrefs.getItems(widget.parentItem!.text); items.removeWhere((item) => item.text == widget.categoryName); if (finalParent.text != widget.parentItem!.text) { print('edit parent of expense category'); List itemsMovedTo = sharedPrefs.getItems(finalParent.text); itemsAdd(itemsMovedTo); sharedPrefs.saveItems(finalParent.text, itemsMovedTo); } else { print('edit other things'); itemsAdd(items); } sharedPrefs.saveItems(widget.parentItem!.text, items); updateCategory(); } } } } Navigator.pop(context); } } if (widget.categoryName == null && widget.parentItem == null) { return SaveButton(false, saveCategoryFunction, null); } else { return SaveAndDeleteButton( saveAndDeleteInput: false, saveCategory: saveCategoryFunction, categoryName: widget.categoryName, parentExpenseItem: widget.parentItem == null ? null : widget.parentItem!.text, contextEx: widget.contextEx, contextExEdit: widget.contextExEdit, contextIn: widget.contextIn, contextInEdit: widget.contextInEdit); } } } ================================================ FILE: lib/project/app_pages/analysis.dart ================================================ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:intl/intl.dart'; import 'package:money_assistant_2608/project/classes/app_bar.dart'; import 'package:money_assistant_2608/project/classes/category_item.dart'; import 'package:money_assistant_2608/project/classes/chart_pie.dart'; import 'package:money_assistant_2608/project/classes/constants.dart'; import 'package:money_assistant_2608/project/classes/dropdown_box.dart'; import 'package:money_assistant_2608/project/classes/input_model.dart'; import 'package:money_assistant_2608/project/database_management/shared_preferences_services.dart'; import 'package:money_assistant_2608/project/database_management/sqflite_services.dart'; import 'package:money_assistant_2608/project/localization/methods.dart'; import 'package:provider/provider.dart'; import '../provider.dart'; import 'report.dart'; final List chartDataNull = [ InputModel( id: null, type: null, amount: 1, category: '', description: null, date: null, time: null, color: const Color.fromRGBO(0, 220, 252, 1)) ]; class Analysis extends StatefulWidget { @override _AnalysisState createState() => _AnalysisState(); } class _AnalysisState extends State { @override Widget build(BuildContext context) { return ChangeNotifierProvider( create: (context) => ChangeSelectedDate(), child: DefaultTabController( initialIndex: 0, length: 2, child: Scaffold( backgroundColor: blue1, appBar: InExAppBar(false), body: Selector( selector: (_, changeSelectedDate) => changeSelectedDate.selectedAnalysisDate, builder: (context, selectedAnalysisDate, child) { selectedAnalysisDate ??= sharedPrefs.selectedDate; ListView listViewChild(String type) => ListView( children: [ ShowDate(true, selectedAnalysisDate!), ShowDetails(type, selectedAnalysisDate), ], ); return TabBarView( children: [ listViewChild('Expense'), listViewChild('Income') ], ); })), ), ); } } class ShowDate extends StatelessWidget { final bool forAnalysis; final String selectedDate; const ShowDate(this.forAnalysis, this.selectedDate); @override Widget build(BuildContext context) { return Padding( padding: EdgeInsets.symmetric( horizontal: 10.w, vertical: 25.h, ), child: Row( children: [ Icon( Icons.calendar_today, size: 27.sp, color: Color.fromRGBO(82, 179, 252, 1), ), SizedBox( width: 10.w, ), DateDisplay(this.selectedDate), Spacer(), DropDownBox(this.forAnalysis, this.selectedDate) ], )); } } class DateDisplay extends StatelessWidget { final String selectedDate; DateDisplay(this.selectedDate); @override Widget build(BuildContext context) { final String today = DateFormat(sharedPrefs.dateFormat).format(todayDT); String since = getTranslated(context, 'Since')!; TextStyle style = GoogleFonts.aBeeZee(fontSize: 20.sp, fontWeight: FontWeight.bold); Map dateMap = { 'Today': Text('$today', style: style), 'This week': Text( '$since ${DateFormat(sharedPrefs.dateFormat).format(startOfThisWeek)}', style: style, ), 'This month': Text( '$since ${DateFormat(sharedPrefs.dateFormat).format(startOfThisMonth)}', style: style), 'This quarter': Text( '$since ${DateFormat(sharedPrefs.dateFormat).format(startOfThisQuarter)}', style: style, ), 'This year': Text( '$since ${DateFormat(sharedPrefs.dateFormat).format(startOfThisYear)}', style: style, ), 'All': Text('${getTranslated(context, 'All')!}', style: style) }; var dateListKey = dateMap.keys.toList(); var dateListValue = dateMap.values.toList(); for (int i = 0; i < dateListKey.length; i++) { if (selectedDate == dateListKey[i]) { return dateListValue[i]; } } return Container(); } } class ShowMoneyFrame extends StatelessWidget { final String type; final double typeValue, balance; const ShowMoneyFrame(this.type, this.typeValue, this.balance); @override Widget build(BuildContext context) { Widget rowFrame(String typeName, double value) { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( getTranslated(context, typeName)!, style: TextStyle(fontSize: 22.sp), ), Expanded( child: Text( format(value) + ' ' + currency, style: GoogleFonts.aBeeZee( fontSize: format(value.toDouble()).length > 22 ? 16.5.sp : format(value.toDouble()).length > 17 ? 19.5.sp : 22.sp), // fix here: Overflow is a temporary parameter, fix whatever it is so that the money value will never overflow overflow: TextOverflow.ellipsis, textAlign: TextAlign.end, ), ), ], ); } return Container( decoration: BoxDecoration( color: Color.fromRGBO(239, 247, 253, 1), borderRadius: BorderRadius.circular(40.r), border: Border.all( color: grey, width: 0.4.w, )), child: Padding( padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 18.5.h), child: Column( children: [ rowFrame(this.type, typeValue), SizedBox( height: 12.5.h, ), rowFrame('Balance', this.balance) ], ), ), ); } } class ShowDetails extends StatefulWidget { final String type, selectedDate; ShowDetails(this.type, this.selectedDate); @override _ShowDetailsState createState() => _ShowDetailsState(); } class _ShowDetailsState extends State { Widget showInExDetails( BuildContext context, List transactionsSorted, ) { List itemList = widget.type == 'Income' ? createItemList( transactions: transactionsSorted, forAnalysisPage: true, isIncomeType: true, forSelectIconPage: false) : createItemList( transactions: transactionsSorted, forAnalysisPage: true, isIncomeType: false, forSelectIconPage: false); return Column( children: List.generate(itemList.length, (int) { return // SwipeActionCell( // backgroundColor: Colors.transparent, // key: ObjectKey(transactionsSorted[int]), // performsFirstActionWithFullSwipe: true, // trailingActions: [ // SwipeAction( // title: "Delete", // onTap: (CompletionHandler handler) async { // Future onDeletion() async { // await handler(true); // transactionsSorted.removeAt(int); // customToast(context, 'Transactions has been deleted'); // setState(() {}); // } // // Platform.isIOS // ? await iosDialog( // context, // 'Deleted data can not be recovered. Are you sure you want to Delete All Transactions In This Category?', // 'Delete', // onDeletion) // : await androidDialog( // context, // 'Deleted data can not be recovered. Are you sure you want to Delete All Transactions In This Category?', // 'Delete', // onDeletion); // }, // color: red), // ], child: GestureDetector( onTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => Report( type: widget.type, category: itemList[int].text, selectedDate: widget.selectedDate, icon: iconData(itemList[int]), ))).then((value) => setState(() {})); }, child: CategoryDetails( widget.type, getTranslated(context, itemList[int].text) ?? itemList[int].text, transactionsSorted[int].amount!, transactionsSorted[int].color, iconData(itemList[int]), false)); })); } @override Widget build(BuildContext context) { late Map chartDataMap; return FutureBuilder>( initialData: [], future: DB.inputModelList(), builder: (BuildContext context, AsyncSnapshot> snapshot) { connectionUI(snapshot); if (snapshot.connectionState == ConnectionState.waiting) { return ShowNullDetail(0, null, this.widget.type, false); } if (snapshot.data == null) { return ShowNullDetail(0, chartDataNull, this.widget.type, true); } else { double income = 0, expense = 0, balance = 0; List allTransactions = filterData(context, snapshot.data!, widget.selectedDate); if (allTransactions.length > 0) { //prepare for MoneyFrame List incomeList = [], expenseList = []; incomeList = allTransactions .map((data) { if (data.type == 'Income') { return data.amount; } }) .where((element) => element != null) .toList(); expenseList = allTransactions .map((data) { if (data.type == 'Expense') { return data.amount; } }) .where((element) => element != null) .toList(); if (incomeList.length > 0) { for (int i = 0; i < incomeList.length; i++) { income = income + incomeList[i]!; } } if (expenseList.length > 0) { for (int i = 0; i < expenseList.length; i++) { expense = expense + expenseList[i]!; } } balance = income - expense; // prepare for InExDetails if (this.widget.type == 'Income') { allTransactions = allTransactions .map((data) { if (data.type == 'Income') { return inputModel(data); } }) .where((element) => element != null) .cast() .toList(); } else { allTransactions = allTransactions .map((data) { if (data.type == 'Expense') { return inputModel(data); } }) .where((element) => element != null) .cast() .toList(); } } if (allTransactions.length == 0) { return ShowNullDetail( balance, chartDataNull, this.widget.type, true); } else { List transactionsSorted = [ InputModel( type: this.widget.type, amount: allTransactions[0].amount, category: allTransactions[0].category, ) ]; int i = 1; //cmt: chartDataListDetailed.length must be greater than 2 to execute while (i < allTransactions.length) { allTransactions .sort((a, b) => a.category!.compareTo(b.category!)); if (i == 1) { chartDataMap = { allTransactions[0].category!: allTransactions[0].amount! }; } if (allTransactions[i].category == allTransactions[i - 1].category) { chartDataMap.update(allTransactions[i].category!, (value) => (value + allTransactions[i].amount!), ifAbsent: () => (allTransactions[i - 1].amount! + allTransactions[i].amount!)); i++; } else { chartDataMap.addAll({ allTransactions[i].category!: allTransactions[i].amount! }); i++; } transactionsSorted = chartDataMap.entries .map((entry) => InputModel( type: this.widget.type, category: entry.key, amount: entry.value, )) .toList(); } void recurringFunc({required int i, n}) { if (n > i) { for (int c = 1; c <= n - i; c++) { transactionsSorted[i + c - 1].color = chartPieColors[c - 1]; recurringFunc(i: i, n: c); } } } for (int n = 1; n <= transactionsSorted.length; n++) { transactionsSorted[n - 1].color = chartPieColors[n - 1]; recurringFunc(i: chartPieColors.length, n: n); } return Column( children: [ ShowMoneyFrame(this.widget.type, this.widget.type == 'Income' ? income : expense, balance), SizedBox(height: 360.h, child: ChartPie(transactionsSorted)), showInExDetails( context, // sum value of transactions having a same category to one transactionsSorted, ) ], ); } } }); } } class ShowNullDetail extends StatelessWidget { final double balanceValue; final List? chartData; final String type; final bool connection; ShowNullDetail(this.balanceValue, this.chartData, this.type, this.connection); @override Widget build(BuildContext context) { return Column( children: [ ShowMoneyFrame(this.type, 0, this.balanceValue), SizedBox( height: 360.h, child: connection == false ? null : ChartPie(this.chartData!)), CategoryDetails( this.type, getTranslated(context, 'Category') ?? 'Category', 0, this.type == 'Income' ? green : red, Icons.category_outlined, true) ], ); } } class CategoryDetails extends StatelessWidget { final String type, category; final double amount; final Color? color; final IconData icon; final bool forNullDetail; CategoryDetails(this.type, this.category, this.amount, this.color, this.icon, this.forNullDetail); @override Widget build(BuildContext context) { return Card( color: white, elevation: 3, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15.r)), child: Padding( padding: EdgeInsets.symmetric(horizontal: 15.w, vertical: 15.h), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Icon( this.icon, color: forNullDetail ? this.type == 'Income' ? green : red : this.color, size: 23.sp, ), Expanded( child: Padding( padding: EdgeInsets.only(left: 15.w, right: 10.w), child: Text( this.category, style: TextStyle(fontSize: 20.sp), overflow: TextOverflow.ellipsis, textAlign: TextAlign.start, ), ), ), // attention: This widget will never overflow Flexible( flex: 0, child: Text( // '${this.color!.red},' + '${this.color!.green},' + '${this.color!.blue},', format(amount) + ' ' + currency, style: GoogleFonts.aBeeZee(fontSize: 20.sp), overflow: TextOverflow.ellipsis, textAlign: TextAlign.end, ), ), SizedBox( width: 10.w, ), forNullDetail ? SizedBox() : Icon( Icons.arrow_forward_ios, size: 18.sp, ), ], ), )); } } ================================================ FILE: lib/project/app_pages/calendar.dart ================================================ import 'dart:collection'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_swipe_action_cell/core/cell.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:intl/intl.dart'; import 'package:money_assistant_2608/project/classes/alert_dialog.dart'; import 'package:money_assistant_2608/project/classes/app_bar.dart'; import 'package:money_assistant_2608/project/classes/category_item.dart'; import 'package:money_assistant_2608/project/classes/constants.dart'; import 'package:money_assistant_2608/project/classes/custom_toast.dart'; import 'package:money_assistant_2608/project/classes/input_model.dart'; import 'package:money_assistant_2608/project/database_management/shared_preferences_services.dart'; import 'package:money_assistant_2608/project/database_management/sqflite_services.dart'; import 'package:money_assistant_2608/project/localization/methods.dart'; import 'package:table_calendar/table_calendar.dart'; import 'dart:io' show Platform; import '../classes/input_model.dart'; import 'edit.dart'; class Calendar extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( backgroundColor: blue1, appBar: BasicAppBar(getTranslated(context, 'Calendar')!), body: CalendarBody()); } } class CalendarBody extends StatefulWidget { @override _CalendarBodyState createState() => _CalendarBodyState(); } class _CalendarBodyState extends State { CalendarFormat _calendarFormat = CalendarFormat.month; RangeSelectionMode _rangeSelectionMode = RangeSelectionMode .toggledOff; // Can be toggled on/off by longpressing a date DateTime _focusedDay = DateTime.now(), today = DateTime( DateTime.now().year, DateTime.now().month, DateTime.now().day); DateTime? _selectedDay, _rangeStart, _rangeEnd; late Map> transactions = {}; late ValueNotifier> _selectedEvents; @override void initState() { super.initState(); _selectedDay = _focusedDay; } @override void dispose() { // _calendarController.dispose(); super.dispose(); } int getHashCode(DateTime key) { return key.day * 1000000 + key.month * 10000 + key.year; } /// Returns a list of [DateTime] objects from [first] to [last], inclusive. List daysInRange(DateTime first, DateTime last) { final dayCount = last.difference(first).inDays + 1; return List.generate( dayCount, (index) => DateTime.utc(first.year, first.month, first.day + index), ); } Widget buildEvents(List? transactions) { Color colorCategory; if (transactions == null) { return Container(); } List itemList = createItemList( transactions: transactions, forAnalysisPage: false, forSelectIconPage: false, isIncomeType: false, ); return ListView.builder( shrinkWrap: true, itemCount: itemList.length, itemBuilder: (context, int) { colorCategory = transactions[int].type == 'Income' ? Colors.lightGreen : red; return GestureDetector( onTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => Edit( inputModel: transactions[int], categoryIcon: iconData(itemList[int]), ))).then((value) => setState(() {})); }, child: SwipeActionCell( key: ObjectKey(transactions[int]), performsFirstActionWithFullSwipe: true, trailingActions: [ SwipeAction( title: getTranslated(context, 'Delete') ?? 'Delete', //setState makes handler experience lagging onTap: (CompletionHandler handler) { Platform.isIOS ? iosDialog( context, 'Are you sure you want to delete this transaction?', 'Delete', () { DB.delete(transactions[int].id!); setState(() {}); customToast( context, 'Transaction has been deleted'); }) : androidDialog( context, 'Are you sure you want to delete this transaction?', 'Delete', () { DB.delete(transactions[int].id!); setState(() {}); customToast( context, 'Transaction has been deleted'); }); }, color: red), SwipeAction( title: getTranslated(context, 'Add') ?? 'Add', onTap: (CompletionHandler handler) { var model = transactions[int]; model.id = null; DB.insert(model); setState(() {}); customToast(context, 'Transaction has been updated'); }, color: Color.fromRGBO(255, 183, 121, 1)), ], child: Column( children: [ Container( color: white, child: Padding( padding: EdgeInsets.symmetric( horizontal: 15.w, vertical: 15.h), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Icon( iconData(itemList[int]), color: colorCategory, ), SizedBox( width: 150.w, child: Padding( padding: EdgeInsets.only(left: 15.w, right: 10.w), child: Text( getTranslated( context, itemList[int].text) ?? itemList[int].text, style: TextStyle( fontSize: 18.sp, ), overflow: TextOverflow.ellipsis), ), ), Expanded( child: Text('(${transactions[int].description})', style: TextStyle( fontSize: 14.sp, fontStyle: FontStyle.italic), overflow: TextOverflow.fade), ), //this widget will never overflow Flexible( flex: 0, child: Padding( padding: EdgeInsets.only(right: 10.w, left: 7.w), child: Text( format(transactions[int].amount!) + ' ' + currency, style: GoogleFonts.aBeeZee( fontSize: format(transactions[int].amount!) .length > 15 ? 16.sp : 17.sp, ), overflow: TextOverflow.ellipsis), ), ), Icon( Icons.arrow_forward_ios, size: 15.5.sp, ), ], ), ), ), Divider( height: 0, thickness: 0.25.h, indent: 20.w, color: grey, // color: Color.fromRGBO(213, 215, 217, 1), ), ], ), )); }); } @override Widget build(BuildContext context) { return FutureBuilder>( initialData: [], future: DB.inputModelList(), builder: (context, snapshot) { connectionUI(snapshot); Map> map = {}; if (snapshot.data != null) { for (int i = 0; i < snapshot.data!.length; i++) { String description = snapshot.data![i].description!; InputModel map1 = InputModel( id: snapshot.data![i].id, type: snapshot.data![i].type, amount: snapshot.data![i].amount, category: snapshot.data![i].category, description: description, date: snapshot.data![i].date, time: snapshot.data![i].time); void updateMapValue(Map> map, K key, V value) => map.update(key, (list) => list..add(value), ifAbsent: () => [value]); updateMapValue( map, '${snapshot.data![i].date}', map1, ); } transactions = map.map((key, value) => MapEntry(DateFormat('dd/MM/yyyy').parse(key), value)); } late LinkedHashMap linkedHashedMapTransactions = LinkedHashMap>( equals: isSameDay, hashCode: getHashCode, )..addAll(transactions); List transactionsForDay(DateTime? day) => linkedHashedMapTransactions[day] ?? []; if (_selectedDay != null) { _selectedEvents = ValueNotifier(transactionsForDay(_selectedDay)); } List _getEventsForRange(DateTime start, DateTime end) { final days = daysInRange(start, end); return [ for (final d in days) ...transactionsForDay(d), ]; } void _onDaySelected(DateTime selectedDay, DateTime focusedDay) { if (!isSameDay(_selectedDay, selectedDay)) { setState(() { _selectedDay = selectedDay; _focusedDay = focusedDay; _rangeStart = null; // Important to clean those _rangeEnd = null; _rangeSelectionMode = RangeSelectionMode.toggledOff; }); _selectedEvents.value = transactionsForDay(selectedDay); } } void _onRangeSelected( DateTime? start, DateTime? end, DateTime focusedDay) { setState(() { _selectedDay = null; _focusedDay = focusedDay; _rangeStart = start; _rangeEnd = end; _rangeSelectionMode = RangeSelectionMode.toggledOn; if (start != null && end != null) { _selectedEvents = ValueNotifier(_getEventsForRange(start, end)); } else if (start != null) { _selectedEvents = ValueNotifier(transactionsForDay(start)); } else if (end != null) { _selectedEvents = ValueNotifier(transactionsForDay(end)); } }); } return Column(children: [ TableCalendar( availableCalendarFormats: { CalendarFormat.month: getTranslated(context, 'Month')!, CalendarFormat.twoWeeks: getTranslated(context, '2 weeks')!, CalendarFormat.week: getTranslated(context, 'Week')! }, locale: Localizations.localeOf(context).languageCode, // sixWeekMonthsEnforced: true, // shouldFillViewport: true, rowHeight: 52.h, daysOfWeekHeight: 22.h, firstDay: DateTime.utc(2000, 01, 01), lastDay: DateTime.utc(2050, 01, 01), focusedDay: _focusedDay, calendarFormat: _calendarFormat, selectedDayPredicate: (day) => isSameDay(_selectedDay, day), rangeStartDay: _rangeStart, rangeEndDay: _rangeEnd, rangeSelectionMode: _rangeSelectionMode, eventLoader: transactionsForDay, startingDayOfWeek: StartingDayOfWeek.monday, calendarStyle: CalendarStyle( // weekendTextStyle: // TextStyle().copyWith(color: Colors.blue[800]), ), headerStyle: HeaderStyle( formatButtonTextStyle: TextStyle(fontSize: 18.sp), formatButtonDecoration: BoxDecoration( boxShadow: [BoxShadow()], color: blue2, borderRadius: BorderRadius.circular(25.r)), ), calendarBuilders: CalendarBuilders( selectedBuilder: (context, date, _) { return Container( //see difference between margin and padding below: Margin: Out (for itself), padding: In (for its child) // margin: EdgeInsets.all(4.0.w), padding: EdgeInsets.only(top: 6.0.h, left: 6.0.w), color: Color.fromRGBO(255, 168, 68, 1), width: 46.w, height: 46.h, child: Text( '${date.day}', style: TextStyle().copyWith(fontSize: 17.0.sp), ), ); }, todayBuilder: (context, date, _) { return Container( padding: EdgeInsets.only(top: 6.0.w, left: 6.0.w), color: blue2, width: 46.w, height: 46.h, child: Text( '${date.day}', style: TextStyle().copyWith(fontSize: 17.0.sp), ), ); }, markerBuilder: (context, date, events) { if (events.isNotEmpty) { return Positioned( right: 1.w, bottom: 1.h, child: _buildEventsMarker(date, events), ); } }, ), onDaySelected: _onDaySelected, onRangeSelected: _onRangeSelected, onFormatChanged: (format) { if (_calendarFormat != format) { setState(() { _calendarFormat = format; }); } }, onPageChanged: (focusedDay) { _focusedDay = focusedDay; }, pageJumpingEnabled: true, ), SizedBox(height: 8.0.h), Expanded( child: ValueListenableBuilder>( valueListenable: _selectedEvents, builder: (context, value, _) { return Column(children: [ Balance(value), Expanded(child: buildEvents(value)) ]); }, ), ) ]); }); } } Widget _buildEventsMarker(DateTime date, List events) { double width = events.length < 100 ? 18.w : 28.w; return AnimatedContainer( duration: const Duration(milliseconds: 300), decoration: BoxDecoration( shape: BoxShape.rectangle, color: Color.fromRGBO(67, 125, 229, 1), ), width: width, height: 18.0.h, child: Center( child: Text( '${events.length}', style: TextStyle().copyWith( color: white, fontSize: 13.0.sp, ), ), ), ); } class Balance extends StatefulWidget { final List? events; Balance(this.events); @override _BalanceState createState() => _BalanceState(); } class _BalanceState extends State { @override Widget build(BuildContext context) { double income = 0, expense = 0, balance = 0; if (widget.events != null) { for (int i = 0; i < widget.events!.length; i++) { if (widget.events![i].type == 'Income') { income = income + widget.events![i].amount; } else { expense = expense + widget.events![i].amount; } balance = income - expense; } } Widget summaryFrame(String type, double amount, color) => Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, children: [ // this widget will never overflow Text( getTranslated(context, type)!, style: TextStyle( color: color, fontSize: 15.sp, fontStyle: FontStyle.italic, fontWeight: FontWeight.bold), ), Text(format(amount.toDouble()) + ' ' + currency, style: GoogleFonts.aBeeZee( color: color, fontSize: (format(amount.toDouble()).length > 19) ? 11.5.sp : format(amount.toDouble()).length > 14 ? 14.sp : 18.sp, fontStyle: FontStyle.italic, fontWeight: FontWeight.bold), overflow: TextOverflow.ellipsis) ], ); return Container( color: Colors.white54, height: 69.h, child: Padding( padding: EdgeInsets.symmetric(horizontal: 15.w, vertical: 10.h), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ summaryFrame( 'INCOME', income, Colors.lightGreen, ), Padding( padding: EdgeInsets.symmetric(horizontal: 5.w), child: summaryFrame('EXPENSE', expense, red)), Flexible( child: summaryFrame('TOTAL BALANCE', balance, Colors.black)), ], ), ), ); } } ================================================ FILE: lib/project/app_pages/currency.dart ================================================ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:money_assistant_2608/project/classes/constants.dart'; import 'package:money_assistant_2608/project/localization/language.dart'; import 'package:money_assistant_2608/project/localization/methods.dart'; import 'package:provider/provider.dart'; import '../provider.dart'; class Currency extends StatelessWidget { @override Widget build(BuildContext context) { List languageList = Language.languageList; return Scaffold( appBar: AppBar( backgroundColor: blue3, title: Text( getTranslated(context, 'Select a currency') ?? 'Select a currency', style: TextStyle(fontSize: 21.sp)), actions: [ Padding( padding: EdgeInsets.only(right: 5.w), child: TextButton( child: Text( getTranslated(context, 'Save') ?? 'Save', style: TextStyle(fontSize: 18.5.sp, color: white), ), onPressed: () => Navigator.pop(context)), ) ]), body: ChangeNotifierProvider( create: (context) => OnCurrencySelected(), builder: (context, widget) => ListView.builder( itemCount: languageList.length, itemBuilder: (context, int) { return GestureDetector( behavior: HitTestBehavior.translucent, onTap: () { context.read().onCurrencySelected( '${languageList[int].languageCode}_${languageList[int].countryCode}'); }, child: Column( children: [ Padding( padding: EdgeInsets.symmetric( horizontal: 15.w, vertical: 10.h), child: Row( children: [ Text( Language.languageList[int].flag, style: TextStyle(fontSize: 45.sp), ), SizedBox(width: 30.w), Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(Language.languageList[int].currencyName, style: TextStyle(fontSize: 20.sp)), SizedBox(height: 2.5.h), Text(Language.languageList[int].currencyCode, style: TextStyle(fontSize: 15.sp)) ], ), Spacer(), context.watch().appCurrency == '${languageList[int].languageCode}_${languageList[int].countryCode}' ? Icon(Icons.check_circle, size: 25.sp, color: blue3) : SizedBox(), SizedBox(width: 25.w), Text( Language.languageList[int].currencySymbol, style: TextStyle(fontSize: 23.sp), ), SizedBox(width: 15.w) ], ), ), Divider( indent: 75.w, height: 0, thickness: 0.25.h, color: grey, ), ], ), ); })), ); } } ================================================ FILE: lib/project/app_pages/edit.dart ================================================ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:money_assistant_2608/project/classes/app_bar.dart'; import 'package:money_assistant_2608/project/classes/constants.dart'; import 'package:money_assistant_2608/project/classes/input_model.dart'; import 'package:money_assistant_2608/project/localization/methods.dart'; import 'input.dart'; class Edit extends StatelessWidget { static final _formKey3 = GlobalKey(debugLabel: '_formKey3'); final InputModel? inputModel; final IconData categoryIcon; const Edit({ this.inputModel, required this.categoryIcon, }); @override Widget build(BuildContext context) { return Scaffold( backgroundColor: blue1, appBar: BasicAppBar(getTranslated(context, 'Edit')!), body: GestureDetector( onTap: () { FocusScopeNode currentFocus = FocusScope.of(context); if (!currentFocus.hasPrimaryFocus) { currentFocus.unfocus(); } }, child: PanelForKeyboard(AddEditInput( formKey: _formKey3, inputModel: this.inputModel, categoryIcon: this.categoryIcon, ),) ), ); } } ================================================ FILE: lib/project/app_pages/edit_expense_category.dart ================================================ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:money_assistant_2608/project/classes/app_bar.dart'; import 'package:money_assistant_2608/project/classes/constants.dart'; import 'package:money_assistant_2608/project/localization/methods.dart'; import 'package:provider/provider.dart'; import '../provider.dart'; import 'add_category.dart'; import 'expense_category.dart'; class EditExpenseCategory extends StatefulWidget { final BuildContext buildContext; EditExpenseCategory(this.buildContext); @override _EditExpenseCategoryState createState() => _EditExpenseCategoryState(); } class _EditExpenseCategoryState extends State { @override Widget build(BuildContext context) { return ChangeNotifierProvider( create: (context) => ChangeExpenseItemEdit(), child: Builder( builder: (contextEdit) => Scaffold( backgroundColor: blue1, appBar: EditCategoryAppBar( AddCategory( contextEx: widget.buildContext, contextExEdit: contextEdit, type: 'Expense', appBarTitle: getTranslated(context, 'Add Expense Category')!, description: ''), ), body: ExpenseCategoryBody( contextExEdit: contextEdit, contextEx: widget.buildContext, )))); } } ================================================ FILE: lib/project/app_pages/edit_income_category.dart ================================================ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:money_assistant_2608' '/project/classes/app_bar.dart'; import 'package:money_assistant_2608' '/project/classes/constants.dart'; import 'package:money_assistant_2608' '/project/localization/methods.dart'; import 'package:provider/provider.dart'; import '../provider.dart'; import 'add_category.dart'; import 'income_category.dart'; class EditIncomeCategory extends StatelessWidget { final BuildContext? buildContext; EditIncomeCategory(this.buildContext); @override Widget build(BuildContext context) { return ChangeNotifierProvider( create: (context) => ChangeIncomeItemEdit(), child: Builder( builder: (contextEdit) => Scaffold( backgroundColor: blue1, appBar: EditCategoryAppBar( AddCategory( contextIn: this.buildContext, contextInEdit: contextEdit , type: 'Income', appBarTitle: getTranslated(context, 'Add Income Category')!, description: ''), ), body: IncomeCategoryBody( context: this.buildContext, contextEdit: contextEdit,editIncomeCategory: true)))); } } ================================================ FILE: lib/project/app_pages/expense_category.dart ================================================ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:money_assistant_2608/project/classes/app_bar.dart'; import 'package:money_assistant_2608/project/classes/category_item.dart'; import 'package:money_assistant_2608/project/classes/constants.dart'; import 'package:money_assistant_2608/project/localization/methods.dart'; import 'package:money_assistant_2608/project/provider.dart'; import 'package:provider/provider.dart'; import 'add_category.dart'; import 'edit_expense_category.dart'; class ExpenseCategory extends StatefulWidget { @override _ExpenseCategoryState createState() => _ExpenseCategoryState(); } class _ExpenseCategoryState extends State { @override Widget build(BuildContext context) { return ChangeNotifierProvider( create: (context) => ChangeExpenseItem(), child: Builder( builder: (buildContext) => Scaffold( backgroundColor: blue1, appBar: CategoryAppBar(EditExpenseCategory(buildContext)), body: ExpenseCategoryBody( contextEx: buildContext, )), )); } } class ExpenseCategoryBody extends StatefulWidget { final BuildContext? contextExEdit,contextEx; ExpenseCategoryBody( {this.contextExEdit, this.contextEx}); @override _ExpenseCategoryBodyState createState() => _ExpenseCategoryBodyState(); } class _ExpenseCategoryBodyState extends State { @override Widget build(BuildContext context) { var exItemsLists = widget.contextExEdit == null ? Provider.of(widget.contextEx!).exItemsLists : Provider.of(widget.contextExEdit!).exItemsLists; return SingleChildScrollView( child: Padding( padding: EdgeInsets.only(left: 10.w, right: 10.w, bottom: 20.h), child: Column( children: [ ListView.builder( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), itemCount: exItemsLists.length, itemBuilder: (context, int) { return Padding( padding: EdgeInsets.only(top: 20.h), child: CategoryContainer( contextEx: widget.contextEx , contextExEdit: widget.contextExEdit, itemsList: exItemsLists[int]), ); }), ], ), )); } } // The named parameter 'body' is required, but there's no corresponding argument. Try adding the required argument. // Widget searchBar() { // return FloatingSearchAppBar( // title: const Text('Enter Category Name'), // transitionDuration: const Duration(milliseconds: 800), // color: Colors.orangeAccent.shade100, // colorOnScroll: Colors.greenAccent.shade200, // height: 55, // ); // } class CategoryContainer extends StatefulWidget { final BuildContext? contextEx,contextExEdit; final List itemsList; const CategoryContainer( { this.contextEx, this.contextExEdit, required this.itemsList}); @override _CategoryContainerState createState() => _CategoryContainerState(); } class _CategoryContainerState extends State { @override Widget build(BuildContext context) { if (widget.itemsList.length < 2) { return ParentCategory( contextEx: widget.contextEx, contextExEdit: widget.contextExEdit, noChildren: true, parentCategory: widget.itemsList[0], ); } return Container( decoration: BoxDecoration( color: white, borderRadius: BorderRadius.circular(40.r), ), child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ ParentCategory( contextEx: widget.contextEx, contextExEdit: widget.contextExEdit, noChildren: false, parentCategory: widget.itemsList[0], ), CategoryItems(contextEx: widget.contextEx, contextExEdit: widget.contextExEdit, categoryItemChildren: widget.itemsList.sublist(1),parentItem: widget.itemsList[0]), ]), ); } } class CategoryItems extends StatefulWidget { final BuildContext? contextEx,contextExEdit; final List categoryItemChildren; final CategoryItem parentItem; const CategoryItems({this.contextEx, this.contextExEdit, required this.categoryItemChildren, required this.parentItem}); @override _CategoryItemsState createState() => _CategoryItemsState(); } class _CategoryItemsState extends State { @override Widget build(BuildContext context) { return Padding( padding: EdgeInsets.only(bottom: 25.h, top: 10.h), child: Wrap( children: List.generate(widget.categoryItemChildren.length, (index) { final cellWidth = (1.sw - 20.w) / 4; return SizedBox( width: cellWidth, child: Column( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.start, children: [ GestureDetector( onLongPress:(){ if (widget.contextExEdit != null) { Navigator.push( context, MaterialPageRoute( builder: (context) => AddCategory( contextEx: widget.contextEx, contextExEdit: widget.contextExEdit, type: 'Expense', appBarTitle: 'Add Expense Category', categoryName: widget.categoryItemChildren[index].text, categoryIcon: iconData( widget.categoryItemChildren[index]), parentItem: widget.parentItem, description: widget .categoryItemChildren[index] .description!))); } }, onTap: () { if (widget.contextExEdit != null) { Navigator.push( context, MaterialPageRoute( builder: (context) => AddCategory( contextEx: widget.contextEx, contextExEdit: widget.contextExEdit, type: 'Expense', appBarTitle: 'Add Expense Category', categoryName: widget.categoryItemChildren[index].text, categoryIcon: iconData( widget.categoryItemChildren[index]), parentItem: widget.parentItem, description: widget .categoryItemChildren[index] .description!))); } else { Navigator.pop( context, widget.categoryItemChildren[index]); } }, child: Padding( padding: EdgeInsets.symmetric(vertical: 15.h), child: CircleAvatar( radius: 24.r, backgroundColor: Color.fromRGBO(215, 223, 231, 1), child: Icon( iconData(widget.categoryItemChildren[index]), color: red, size: 30.sp, )), ), ), Text( getTranslated( context, widget.categoryItemChildren[index].text) ?? widget.categoryItemChildren[index].text, style: TextStyle( fontSize: 16.sp, ), textAlign: TextAlign.center, ), ], ), ); }), ), ); } } class ParentCategory extends StatefulWidget { final BuildContext? contextEx, contextExEdit; final bool noChildren; final CategoryItem parentCategory; ParentCategory( { this.contextEx, this.contextExEdit, required this.noChildren, required this.parentCategory,} ); @override _ParentCategoryState createState() => _ParentCategoryState(); } class _ParentCategoryState extends State { @override Widget build(BuildContext context) { return GestureDetector( behavior: HitTestBehavior.translucent, onLongPress:(){ if (widget.contextExEdit != null) { Navigator.push( context, MaterialPageRoute( builder: (context) => AddCategory( contextEx: widget.contextEx, contextExEdit: widget.contextExEdit, type: 'Expense', appBarTitle: 'Add Expense Category', categoryName: widget.parentCategory.text, categoryIcon: iconData(widget.parentCategory), description: widget.parentCategory.description))); } }, onTap: () { if (widget.contextExEdit != null) { Navigator.push( context, MaterialPageRoute( builder: (context) => AddCategory( contextEx: widget.contextEx, contextExEdit: widget.contextExEdit, type: 'Expense', appBarTitle: 'Add Expense Category', categoryName: widget.parentCategory.text, categoryIcon: iconData(widget.parentCategory), description: widget.parentCategory.description))); } // consider category as parent category for simplicity, need to change later else { Navigator.pop(context, widget.parentCategory); } }, child: Container( decoration: BoxDecoration( color: Color.fromRGBO(222, 174, 112, 1), borderRadius: widget.noChildren ? BorderRadius.circular(40.r) : BorderRadius.vertical( top: Radius.circular(40.r), bottom: Radius.zero), ), child: Padding( padding: EdgeInsets.symmetric(vertical: 18.h, horizontal: 15.w), child: Row( children: [ CircleAvatar( backgroundColor: Color.fromRGBO(215, 223, 231, 1), radius: 26.r, child: Icon( iconData(widget.parentCategory), size: 33.sp, color: red, )), SizedBox( width: 23.5.w, ), Expanded( child: Text( getTranslated(context, widget.parentCategory.text) ?? widget.parentCategory.text, style: TextStyle(fontSize: 22.sp, fontWeight: FontWeight.bold), overflow: TextOverflow.ellipsis, ), ) ], ), ), ), ); } } ================================================ FILE: lib/project/app_pages/income_category.dart ================================================ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:money_assistant_2608/project/classes/app_bar.dart'; import 'package:money_assistant_2608/project/classes/constants.dart'; import 'package:money_assistant_2608/project/localization/methods.dart'; import 'package:money_assistant_2608/project/provider.dart'; import 'package:provider/provider.dart'; import 'add_category.dart'; import 'edit_income_category.dart'; class IncomeCategory extends StatefulWidget { @override _IncomeCategoryState createState() => _IncomeCategoryState(); } class _IncomeCategoryState extends State { @override Widget build(BuildContext context) { return ChangeNotifierProvider( create: (context) => ChangeIncomeItem(), child: Builder( builder: (buildContext) => Scaffold( backgroundColor: blue1, appBar: CategoryAppBar(EditIncomeCategory(buildContext)), body: IncomeCategoryBody( context: buildContext, editIncomeCategory: false)))); } } class IncomeCategoryBody extends StatefulWidget { final BuildContext? context, contextEdit; final bool editIncomeCategory; IncomeCategoryBody( {this.context, this.contextEdit, required this.editIncomeCategory}); @override _IncomeCategoryBodyState createState() => _IncomeCategoryBodyState(); } class _IncomeCategoryBodyState extends State { @override Widget build(BuildContext context) { var incomeList = widget.contextEdit == null ? Provider.of(widget.context!).incomeItems : Provider.of(widget.contextEdit!).incomeItems; return Padding( padding: EdgeInsets.only(top: 30.h), child: ListView.builder( itemCount: incomeList.length, itemBuilder: (context, int) { return Padding( padding: EdgeInsets.only(top: 3.h, left: 10.w, right: 10.w), child: GestureDetector( onLongPress: () { if (this.widget.editIncomeCategory) { Navigator.push( context, MaterialPageRoute( builder: (context) => AddCategory( contextIn: widget.context, contextInEdit: widget.contextEdit, type: 'Income', appBarTitle: 'Add Income Category', categoryName: incomeList[int].text, categoryIcon: iconData(incomeList[int]), description: incomeList[int].description!))); } }, onTap: () { if (this.widget.editIncomeCategory) { Navigator.push( context, MaterialPageRoute( builder: (context) => AddCategory( contextIn: widget.context, contextInEdit: widget.contextEdit, type: 'Income', appBarTitle: 'Add Income Category', categoryName: incomeList[int].text, categoryIcon: iconData(incomeList[int]), description: incomeList[int].description!))); } else { Navigator.pop(context, incomeList[int]); } }, child: Card( elevation: 5, color: white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(35.r), ), child: Padding( padding: EdgeInsets.symmetric(vertical: 15.h), child: Row( children: [ SizedBox( width: 40.h, ), CircleAvatar( backgroundColor: Color.fromRGBO(215, 223, 231, 1), radius: 25.r, child: Icon( iconData(incomeList[int]), size: 33.sp, color: green, ), ), SizedBox( width: 25.w, ), Text( getTranslated(context, incomeList[int].text) ?? incomeList[int].text, style: TextStyle( fontSize: 20.sp, fontWeight: FontWeight.bold), ) ], ), ), ), ), ); }, ), ); } } ================================================ FILE: lib/project/app_pages/input.dart ================================================ import 'dart:core'; import 'dart:io' show Platform; import 'package:day_night_time_picker/day_night_time_picker.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_material_pickers/flutter_material_pickers.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:intl/intl.dart'; import 'package:keyboard_actions/keyboard_actions.dart'; import 'package:money_assistant_2608/project/classes/alert_dialog.dart'; import 'package:money_assistant_2608/project/classes/app_bar.dart'; import 'package:money_assistant_2608/project/classes/category_item.dart'; import 'package:money_assistant_2608/project/classes/constants.dart'; import 'package:money_assistant_2608/project/classes/custom_toast.dart'; import 'package:money_assistant_2608/project/classes/input_model.dart'; import 'package:money_assistant_2608/project/classes/keyboard.dart'; import 'package:money_assistant_2608/project/classes/saveOrSaveAndDeleteButtons.dart'; import 'package:money_assistant_2608/project/database_management/shared_preferences_services.dart'; import 'package:money_assistant_2608/project/database_management/sqflite_services.dart'; import 'package:money_assistant_2608/project/localization/methods.dart'; import 'package:provider/provider.dart'; import 'package:sliding_up_panel/sliding_up_panel.dart'; import '../provider.dart'; import 'expense_category.dart'; import 'income_category.dart'; late CategoryItem defaultCategory; var selectedTime = TimeOfDay.now(); var selectedDate = DateTime.now(); InputModel model = InputModel(); PanelController _pc = PanelController(); late TextEditingController _amountController; FocusNode? amountFocusNode, descriptionFocusNode; class AddInput extends StatefulWidget { @override _AddInputState createState() => _AddInputState(); } class _AddInputState extends State { static final _formKey1 = GlobalKey(debugLabel: '_formKey1'), _formKey2 = GlobalKey(debugLabel: '_formKey2'); @override Widget build(BuildContext context) { return GestureDetector( onTap: () { FocusScopeNode currentFocus = FocusScope.of(context); if (!currentFocus.hasFocus || !currentFocus.hasPrimaryFocus) { currentFocus.unfocus(); if (_pc.isPanelOpen) { _pc.close(); } } }, child: DefaultTabController( initialIndex: 0, length: 2, child: Scaffold( backgroundColor: blue1, appBar: InExAppBar(true), body: // ChangeNotifierProvider( // create: (context) => ChangeModelType(), // child: PanelForKeyboard( TabBarView( children: [ AddEditInput( type: 'Expense', formKey: _formKey2, ), AddEditInput( type: 'Income', formKey: _formKey1, ) ], ), ))), ) // ) ; } } class PanelForKeyboard extends StatelessWidget { const PanelForKeyboard( this.body, ); final Widget body; void _insertText(String myText) { final text = _amountController.text; TextSelection textSelection = _amountController.selection; String newText = text.replaceRange( textSelection.start, textSelection.end, myText, ); if (newText.length > 13) { newText = newText.substring(0, 13); } // if input starts to have '.' => Don't need to reformat if (newText.contains('.')) { String fractionalNumber = newText.split('.').last; // input can not have more than 2 numbers after a decimal point if (fractionalNumber.length > 2) { String wholeNumber = newText.split('.').first; newText = wholeNumber + '.' + fractionalNumber.substring(0, 2); } if (newText.substring(newText.length - 1) == '.') { // input can not have more than 1 dot if ('.'.allMatches(newText).length == 2) { newText = newText.substring(0, newText.length - 1); } } _amountController.text = newText; } else { _amountController.text = format(double.parse(newText.replaceAll(',', ''))); } //define text input and cursor position textSelection = TextSelection.fromPosition( TextPosition(offset: _amountController.text.length)); _amountController.selection = textSelection; } void _backspace() { final text = _amountController.text; TextSelection textSelection = _amountController.selection; // The cursor is at the beginning. if (textSelection.start == 0) { return; } final selectionLength = textSelection.end - textSelection.start; // There is a selection. if (selectionLength > 0) { final newText = text.replaceRange( textSelection.start, textSelection.end, '', ); // if users delete all input or if input has '.' // => Don't need to reformat when deleting if (newText == '' || newText.contains('.')) { _amountController.text = newText; } else { _amountController.text = format(double.parse(newText.replaceAll(',', ''))); } textSelection = TextSelection.fromPosition( TextPosition(offset: _amountController.text.length)); _amountController.selection = textSelection; return; } // Delete the previous character final previousCodeUnit = text.codeUnitAt(textSelection.start - 1); final offset = _isUtf16Surrogate(previousCodeUnit) ? 2 : 1; final newStart = textSelection.start - offset; final newEnd = textSelection.start; final newText = text.replaceRange( newStart, newEnd, '', ); if (newText == '' || newText.contains('.')) { _amountController.text = newText; } else { _amountController.text = format(double.parse(newText.replaceAll(',', ''))); } textSelection = TextSelection.fromPosition( TextPosition(offset: _amountController.text.length)); _amountController.selection = textSelection; } bool _isUtf16Surrogate(int value) { return value & 0xF800 == 0xD800; } @override Widget build(BuildContext context) { return SlidingUpPanel( controller: _pc, minHeight: 0, maxHeight: 300.h, parallaxEnabled: true, isDraggable: false, panelSnapping: true, panel: CustomKeyboard( panelController: _pc, mainFocus: amountFocusNode, nextFocus: descriptionFocusNode, onTextInput: (myText) { _insertText(myText); }, onBackspace: () { _backspace(); }, page: model.type == 'Income' // Provider.of(context).modelType == 'Income' ? IncomeCategory() : ExpenseCategory(), ), body: this.body); } } class AddEditInput extends StatelessWidget { final GlobalKey formKey; final InputModel? inputModel; final String? type; final IconData? categoryIcon; const AddEditInput({ required this.formKey, this.inputModel, this.type, this.categoryIcon, }); @override Widget build(BuildContext context) { if (this.inputModel != null) { model = this.inputModel!; defaultCategory = categoryItem(this.categoryIcon!, model.category!); // Provider.of(context, listen: false) // .changeModelType(this.inputModel!.type!); } else { model = InputModel( type: this.type, ); defaultCategory = categoryItem(Icons.category_outlined, 'Category'); // Provider.of(context, listen: false) // .changeModelType(this.type!); } return ChangeNotifierProvider( create: (context) => ChangeCategoryA(), child: ListView(children: [ AmountCard(), SizedBox( height: 30.h, ), Container( decoration: BoxDecoration( color: white, border: Border.all( color: grey, width: 0.6.w, )), child: Column( children: [ CategoryCard(), DescriptionCard(), DateCard(), ], ), ), Padding( padding: EdgeInsets.symmetric(vertical: 70.h), child: this.inputModel != null ? SaveAndDeleteButton( saveAndDeleteInput: true, formKey: this.formKey, ) : SaveButton(true, null, true), ) ])); } } class AmountCard extends StatefulWidget { @override _AmountCardState createState() => _AmountCardState(); } class _AmountCardState extends State { @override void initState() { super.initState(); amountFocusNode = FocusNode(); _amountController = TextEditingController( text: model.id == null ? '' : format(model.amount!), ); } // @override // void dispose(){ // amountFocusNode!.dispose(); // super.dispose(); // } @override Widget build(BuildContext context) { Color colorMain = model.type == 'Income' ? green : red; return Container( decoration: BoxDecoration( color: white, border: Border( bottom: BorderSide( color: grey, width: 0.6.h, ))), child: Padding( padding: EdgeInsets.only(top: 15.h, bottom: 30.h, right: 20.w, left: 20.w), child: Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ Text( '${getTranslated(context, 'Amount')}', style: TextStyle( fontSize: 22.sp, ), ), TextFormField( controller: _amountController, readOnly: true, showCursor: true, maxLines: null, minLines: 1, // maxLength: , // inputFormatters: [ // FilteringTextInputFormatter.allow( // RegExp(r'^\d*(.?|,?)\d{0,2}')), // ], onTap: () => _pc.open(), cursorColor: colorMain, style: GoogleFonts.aBeeZee( color: colorMain, fontSize: 35.sp, fontWeight: FontWeight.bold), focusNode: amountFocusNode, decoration: InputDecoration( hintText: '0', hintStyle: GoogleFonts.aBeeZee( color: colorMain, fontSize: 35.sp, fontWeight: FontWeight.bold), icon: Padding( padding: EdgeInsets.only(right: 5.w), child: Icon( Icons.monetization_on, size: 45.sp, color: colorMain, ), ), suffixIcon: _amountController.text.length > 0 ? IconButton( icon: Icon( Icons.clear, size: 24.sp, ), onPressed: () { _amountController.clear(); }) : SizedBox(), ), ), ], ), ), ); } } class CategoryCard extends StatefulWidget { @override _CategoryCardState createState() => _CategoryCardState(); } class _CategoryCardState extends State { @override Widget build(BuildContext context) { return Consumer(builder: (_, changeCategoryA, __) { changeCategoryA.categoryItemA ??= defaultCategory; var categoryItem = changeCategoryA.categoryItemA; model.category = categoryItem!.text; return GestureDetector( onTap: () async { if (_pc.isPanelOpen) { _pc.close(); } CategoryItem newCategoryItem = await Navigator.push( context, MaterialPageRoute( builder: (context) => model.type == 'Income' ? IncomeCategory() : ExpenseCategory()), ); changeCategoryA.changeCategory(newCategoryItem); }, child: Column(children: [ Padding( padding: EdgeInsets.only( left: 20.w, right: 20.w, top: 20.h, bottom: 21.h), child: Row( children: [ Icon( iconData(categoryItem), size: 40.sp, color: model.type == 'Income' ? green : red, ), Expanded( child: Padding( padding: EdgeInsets.only(left: 31.w), child: Text( getTranslated(context, categoryItem.text) ?? categoryItem.text, style: TextStyle( fontSize: 24.sp, fontWeight: FontWeight.bold, ), overflow: TextOverflow.ellipsis, ), ), ), // Spacer(), Icon( Icons.arrow_forward_ios_outlined, size: 20.sp, ), ], ), ), Divider( height: 0, thickness: 0.25.w, color: grey, indent: 85.w, ), ])); }); } } class DescriptionCard extends StatefulWidget { @override _DescriptionCardState createState() => _DescriptionCardState(); } class _DescriptionCardState extends State { static late TextEditingController descriptionController; @override void initState() { super.initState(); descriptionFocusNode = FocusNode(); descriptionController = TextEditingController(text: model.description ?? ''); } // @override // void dispose(){ // descriptionFocusNode!.dispose(); // super.dispose(); // } KeyboardActionsConfig _buildConfig(BuildContext context) { return KeyboardActionsConfig( nextFocus: false, keyboardActionsPlatform: KeyboardActionsPlatform.ALL, keyboardBarColor: Colors.grey[200], actions: [ KeyboardActionsItem( focusNode: descriptionFocusNode!, toolbarButtons: [ (node) { return SizedBox( width: 1.sw, child: Padding( padding: EdgeInsets.only(left: 5.w, right: 16.w), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ GestureDetector( onTap: () { FocusScope.of(context) .requestFocus(amountFocusNode); _pc.open(); }, child: SizedBox( height: 35.h, width: 60.w, child: Icon(Icons.keyboard_arrow_up, size: 25.sp, color: Colors.blueGrey), ), ), // GestureDetector( // onTap: () { // node.unfocus(); // Navigator.push( // context, // MaterialPageRoute( // builder: (context) => model.type == 'Income' // ? IncomeCategory() // : ExpenseCategory())); // }, // child: Text( // getTranslated(context, 'Choose Category')!, // style: TextStyle( // fontSize: 16.sp, // fontWeight: FontWeight.bold, // color: Colors.blueGrey), // ), // ), GestureDetector( onTap: () => node.unfocus(), child: Text( getTranslated(context, "Done")!, style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.bold, color: Colors.blue), )) ], )), ); }, ]) ]); } @override Widget build(BuildContext context) { return KeyboardActions( overscroll: 0, disableScroll: true, tapOutsideBehavior: TapOutsideBehavior.translucentDismiss, autoScroll: false, config: _buildConfig(context), child: Column(children: [ Padding( padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 8.5.h), child: TextFormField( controller: descriptionController, maxLines: null, minLines: 1, keyboardType: TextInputType.multiline, keyboardAppearance: Brightness.light, // maxLength: , onTap: () { if (_pc.isPanelOpen) { _pc.close(); } }, cursorColor: blue1, textCapitalization: TextCapitalization.sentences, style: TextStyle(fontSize: 20.sp), focusNode: descriptionFocusNode, textInputAction: TextInputAction.newline, decoration: InputDecoration( border: InputBorder.none, hintText: getTranslated(context, 'Description'), hintStyle: GoogleFonts.cousine( fontSize: 22.sp, fontStyle: FontStyle.italic, ), suffixIcon: descriptionController.text.length > 0 ? IconButton( icon: Icon( Icons.clear, size: 20.sp, ), onPressed: () { descriptionController.clear(); }) : SizedBox(), icon: Padding( padding: EdgeInsets.only(right: 15.w), child: Icon( Icons.description_outlined, size: 40.sp, color: Colors.blueGrey, ), )), ), ), Divider( height: 0, thickness: 0.25.w, color: grey, indent: 85.w, ) ]), ); } } class DateCard extends StatefulWidget { const DateCard(); @override _DateCardState createState() => _DateCardState(); } class _DateCardState extends State { @override Widget build(BuildContext context) { if (model.date == null) { model.date = DateFormat('dd/MM/yyyy').format(selectedDate); model.time = selectedTime.format(context); } return Padding( padding: EdgeInsets.only(left: 20.w, right: 20.w, top: 17.5.h, bottom: 19.h), child: Row( children: [ GestureDetector( onTap: () { if (_pc.isPanelOpen) { _pc.close(); } showMaterialDatePicker( headerColor: blue3, headerTextColor: Colors.black, backgroundColor: white, buttonTextColor: Color.fromRGBO(80, 157, 253, 1), cancelText: getTranslated(context, 'CANCEL'), confirmText: getTranslated(context, 'OK') ?? 'OK', maxLongSide: 450.w, maxShortSide: 300.w, title: getTranslated(context, 'Select a date'), context: context, firstDate: DateTime(1990, 1, 1), lastDate: DateTime(2050, 12, 31), selectedDate: DateFormat('dd/MM/yyyy').parse(model.date!), onChanged: (value) => setState(() { selectedDate = value; model.date = DateFormat('dd/MM/yyyy').format(value); }), ); }, child: Row( mainAxisSize: MainAxisSize.min, children: [ Padding( padding: EdgeInsets.only(right: 30.w), child: Icon( Icons.event, size: 40.sp, color: Colors.blue, ), ), Text( DateFormat(sharedPrefs.dateFormat).format( DateFormat('dd/MM/yyyy').parse( model.date!)), style: GoogleFonts.aBeeZee( fontSize: 21.5.sp, ), ), ], ), ), Spacer(), GestureDetector( behavior: HitTestBehavior.translucent, onTap: () { if (_pc.isPanelOpen) { _pc.close(); } Navigator.of(context).push( showPicker( cancelText: getTranslated(context, 'Cancel') ?? 'Cancel', okText: getTranslated(context, 'Ok') ?? 'Ok', unselectedColor: grey, dialogInsetPadding: EdgeInsets.symmetric( horizontal: 50.w, vertical: 30.0.h), elevation: 12, context: context, value: selectedTime, is24HrFormat: true, onChange: (value) => setState(() { selectedTime = value; model.time = value.format(context); })), ); }, child: Text( model.time!, style: GoogleFonts.aBeeZee( fontSize: 21.5.sp, ), ), ) ], ), ); } } void saveInputFunc(BuildContext context, bool saveFunction) { model.amount = _amountController.text.isEmpty ? 0 : double.parse(_amountController.text.replaceAll(',', '')); model.description = _DescriptionCardState.descriptionController.text; if (saveFunction) { DB.insert(model); _amountController.clear(); if (_DescriptionCardState.descriptionController.text.length > 0) { _DescriptionCardState.descriptionController.clear(); } customToast(context, 'Data has been saved'); } else { DB.update(model); Navigator.pop(context); customToast(context, getTranslated(context, 'Transaction has been updated') ?? 'Transaction has been updated'); } } Future deleteInputFunction( BuildContext context, ) async { void onDeletion() { DB.delete(model.id!); Navigator.pop(context); customToast(context, 'Transaction has been deleted'); } Platform.isIOS ? await iosDialog( context, 'Are you sure you want to delete this transaction?', 'Delete', onDeletion) : await androidDialog( context, 'Are you sure you want to delete this transaction?', 'Delete', onDeletion); } ================================================ FILE: lib/project/app_pages/others.dart ================================================ import 'dart:core'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:in_app_review/in_app_review.dart'; import 'package:intl/intl.dart'; import 'package:money_assistant_2608/project/app_pages/select_date_format.dart'; import 'package:money_assistant_2608/project/app_pages/select_language.dart'; import 'package:money_assistant_2608/project/auth_pages/user_account.dart'; import 'package:money_assistant_2608/project/classes/alert_dialog.dart'; import 'package:money_assistant_2608/project/classes/constants.dart'; import 'package:money_assistant_2608/project/classes/custom_toast.dart'; import 'package:money_assistant_2608/project/database_management/shared_preferences_services.dart'; import 'package:money_assistant_2608/project/database_management/sqflite_services.dart'; import 'package:money_assistant_2608/project/localization/methods.dart'; import 'package:provider/provider.dart'; import 'package:share_plus/share_plus.dart'; import 'dart:io' show Platform; import '../provider.dart'; import 'currency.dart'; class Other extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( primary: true, appBar: PreferredSize( preferredSize: Size.fromHeight( 150.h, ), child: Container( color: blue3, padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 0), height: 200.h, child: Padding( padding: EdgeInsets.only(top: 30.w), child: Row( children: [ CircleAvatar( child: CircleAvatar( child: Icon( FontAwesomeIcons.smileBeam, color: Colors.black, size: 71.sp, ), radius: 35.r, backgroundColor: blue1), radius: 40.r, backgroundColor: Colors.orangeAccent, ), SizedBox( width: 20.w, ), Text( '${getTranslated(context, 'Hi you')!}!', style: TextStyle(fontSize: 30.sp), ), // Spacer(), // Icon( // Icons.notifications_rounded, // size: 25.sp, // ) ], ), ), ), ), body: ChangeNotifierProvider( create: (context) => OnSwitch(), builder: (context, widget) => Settings(providerContext: context))); } } class Settings extends StatefulWidget { final BuildContext providerContext; const Settings({required this.providerContext}); @override State createState() => _SettingsState(); } class _SettingsState extends State { @override Widget build(BuildContext context) { List pageRoute = [ UserAccount(), SelectLanguage(), Currency(), ]; List settingsIcons = [ Icon( Icons.account_circle, size: 35, color: Colors.lightBlue, ), // Icon( // Icons.settings, // size: 32, // color: Colors.blueGrey[800], // ), // Icon( // Icons.feedback, // size: 35.sp, // color: Colors.black54, // ), Icon( Icons.language, size: 32.sp, color: Colors.lightBlue, ), Icon( Icons.monetization_on, size: 32.sp, color: Colors.orangeAccent, ), Icon(Icons.format_align_center, size: 32.sp, color: Colors.lightBlue), Icon(Icons.refresh, size: 32.sp, color: Colors.lightBlue), Icon(Icons.delete_forever, size: 32.sp, color: red), // Icon(Icons.lock, size: 32.sp, color: Colors.blueGrey), Icon( Icons.share, size: 28.sp, color: Colors.lightBlue, ), Icon( Icons.star, size: 32.sp, color: Colors.amber, ), ]; List settingsList = [ getTranslated(context, 'My Account')!, // getTranslated(context, 'General Settings')!, // getTranslated(context, 'Feedback')!, getTranslated(context, 'Language') ?? 'Language', getTranslated(context, 'Currency') ?? 'Currency', (getTranslated(context, 'Date format') ?? 'Date format') + ' (${DateFormat(sharedPrefs.dateFormat).format(now)})', getTranslated(context, 'Reset All Categories') ?? 'Reset All Categories', getTranslated(context, 'Delete All Data') ?? 'Delete All Data', // getTranslated(context, 'Enable Passcode') ?? 'Enable Passcode', getTranslated(context, 'Share Friends') ?? 'Share Friends', getTranslated(context, 'Rate App') ?? 'Rate App', ]; return ListView.builder( itemCount: settingsList.length, itemBuilder: (context, int) { // void onPasscodeSwitched() { // context.read().onSwitch(); // if (context.read().isPasscodeOn) { // showDialog( // context: context, // builder: (providerContext) => // OtherLockScreen(providerContext: this.providerContext)); // } else { // customToast(context, 'Passcode has been disabled'); // } // } return GestureDetector( onTap: () async { if ((int == 0) || (int == 1) || (int == 2)) { Navigator.push(context, MaterialPageRoute(builder: (context) => pageRoute[int])); } else if (int == 3) { Navigator.push(context, MaterialPageRoute(builder: (context) => FormatDate())) .then((value) => setState(() {})); } else if (int == 4) { // Navigator.push( // context, // MaterialPageRoute( // builder: (context) => EditIncomeCategory(null))); void onReset() { sharedPrefs.setItems(setCategoriesToDefault: true); customToast(context, 'Categories have been reset'); } Platform.isIOS ? await iosDialog( context, 'This action cannot be undone. Are you sure you want to reset all categories?', 'Reset', onReset) : await androidDialog( context, 'This action cannot be undone. Are you sure you want to reset all categories?', 'reset', onReset); } else if (int == 5) { Future onDeletion() async { await DB.deleteAll(); customToast(context, 'All data has been deleted'); } Platform.isIOS ? await iosDialog( context, 'Deleted data can not be recovered. Are you sure you want to delete all data?', 'Delete', onDeletion) : await androidDialog( context, 'Deleted data can not be recovered. Are you sure you want to delete all data?', 'Delete', onDeletion); } // else if (int == 4) { // onPasscodeSwitched(); // } else if (int == 6) { Share.share( 'https://apps.apple.com/us/app/mmas-money-tracker-bookkeeper/id1582638369'); } else { final InAppReview inAppReview = InAppReview.instance; await inAppReview.openStoreListing( appStoreId: Platform.isIOS ? '1582638369' : 'com.mmas.money_assistant_2608', ); } }, child: Column( children: [ Padding( padding: EdgeInsets.symmetric(vertical: 7.h), child: SizedBox( child: Center( child: ListTile( title: Padding( padding: EdgeInsets.symmetric(horizontal: 8.w), child: Text( '${settingsList[int]}', style: TextStyle(fontSize: 18.5.sp), ), ), leading: CircleAvatar( radius: 24.r, backgroundColor: Color.fromRGBO(229, 231, 234, 1), child: settingsIcons[int]), trailing: // int == 4 // ? Switch( // value: context.watch().isPasscodeOn, // onChanged: (value) { // onPasscodeSwitched(); // }, // activeTrackColor: blue1, // activeColor: Color.fromRGBO(71, 131, 192, 1), // ) : Icon( Icons.arrow_forward_ios, size: 20.sp, color: Colors.blueGrey, ), )), ), ), Divider( indent: 78.w, height: 0.1.h, thickness: 0.4.h, color: grey, ), ], ), ); }); } } // class Upgrade extends StatelessWidget { // @override // Widget build(BuildContext context) { // return Stack( // alignment: Alignment.center, // children: [ // Container( // height: 165.h, // color: Color.fromRGBO(234, 234, 234, 1), // ), // Container( // alignment: Alignment.center, // height: 115.h, // decoration: BoxDecoration( // image: DecorationImage( // fit: BoxFit.fill, image: AssetImage('images/image13.jpg'))), // ), // Container( // alignment: Alignment.center, // decoration: BoxDecoration( // color: Color.fromRGBO(255, 255, 255, 1), // borderRadius: BorderRadius.circular(40), // border: Border.all( // color: Colors.grey, // width: 0.5.w, // )), // height: 55.h, // width: 260.w, // child: Text( // getTranslated(context, 'VIEW UPGRADE OPTIONS')!, // style: TextStyle(fontSize: 4.206, fontWeight: FontWeight.bold), // ), // ), // ], // ); // } // } ================================================ FILE: lib/project/app_pages/parent_category.dart ================================================ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:money_assistant_2608/project/classes/app_bar.dart'; import 'package:money_assistant_2608/project/classes/category_item.dart'; import 'package:money_assistant_2608/project/classes/constants.dart'; import 'package:money_assistant_2608/project/database_management/shared_preferences_services.dart'; import 'package:money_assistant_2608/project/localization/methods.dart'; class ParentCategoryList extends StatelessWidget { @override Widget build(BuildContext context) { List parentCategories = sharedPrefs.getAllExpenseItemsLists() .map((item) => CategoryItem( item[0].iconCodePoint, item[0].iconFontPackage, item[0].iconFontFamily, item[0].text, item[0].description)) .toList(); return Scaffold( appBar: BasicAppBar(getTranslated(context, 'Parent category')!), body: ListView.builder( itemCount: parentCategories.length, itemBuilder: (context, int) { return GestureDetector( behavior: HitTestBehavior.translucent, onTap: () { Navigator.pop( context, parentCategories[int]); }, child: Column( children: [ Padding( padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 5.h), child: Row( children: [ CircleAvatar( backgroundColor: Color.fromRGBO(215, 223, 231, 1), radius: 20.r, child: Icon( iconData(parentCategories[int]), size: 25.sp, color: red, )), SizedBox( width: 28.w, ), Expanded( child: Text( getTranslated(context, parentCategories[int].text) ?? parentCategories[int].text, style: TextStyle(fontSize: 22.sp), overflow: TextOverflow.ellipsis, ), ) ], ), ), Divider( thickness: 0.25.h, indent: 67.w, color: grey, ) ], )); }, ), ); } } ================================================ FILE: lib/project/app_pages/report.dart ================================================ /// Package import import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_swipe_action_cell/core/cell.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:intl/intl.dart'; import 'package:money_assistant_2608/project/classes/alert_dialog.dart'; import 'package:money_assistant_2608/project/classes/app_bar.dart'; import 'package:money_assistant_2608/project/classes/constants.dart'; import 'package:money_assistant_2608/project/classes/custom_toast.dart'; import 'package:money_assistant_2608/project/classes/input_model.dart'; import 'package:money_assistant_2608/project/classes/dropdown_box.dart'; import 'package:money_assistant_2608/project/database_management/shared_preferences_services.dart'; import 'package:money_assistant_2608/project/database_management/sqflite_services.dart'; import 'package:money_assistant_2608/project/localization/methods.dart'; import 'package:money_assistant_2608/project/provider.dart'; import 'package:provider/provider.dart'; import 'dart:io' show Platform; /// Chart import import 'package:syncfusion_flutter_charts/charts.dart'; import 'edit.dart'; var year = todayDT.year; class Report extends StatefulWidget { final String type; final String category; final String selectedDate; final IconData icon; const Report({ required this.type, required this.category, required this.selectedDate, required this.icon, }); @override _ReportState createState() => _ReportState(); } class _ReportState extends State { @override Widget build(BuildContext context) { Color color = widget.type == getTranslated(context, 'Income') ? green : red; return Scaffold( backgroundColor: blue1, appBar: BasicAppBar(getTranslated(context, 'Report')!), body: Column( children: [ Padding( padding: EdgeInsets.only( top: 17.h, bottom: 15.h, left: 7.w, right: 7.w, ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Padding( padding: EdgeInsets.only(right: 15.w), child: Icon(this.widget.icon, size: 30.sp, color: color), ), Flexible( child: Text( '${getTranslated(context, widget.category) ?? widget.category} ($year)', style: TextStyle( fontSize: 24.sp, fontWeight: FontWeight.bold, color: color), overflow: TextOverflow.ellipsis, ), ) ], ), ), Expanded( child: ReportBody(widget.type, widget.category, widget.selectedDate, color, widget.icon), ) ], ), ); } } class ReportBody extends StatefulWidget { final String type; final String category; final String selectedDate; final Color color; final IconData icon; ReportBody( this.type, this.category, this.selectedDate, this.color, this.icon); @override _ReportBodyState createState() => _ReportBodyState(); } class _ReportBodyState extends State { @override Widget build(BuildContext context) { return ChangeNotifierProvider( create: (context) => InputModelList(), builder: (context, child) { return FutureBuilder>( initialData: [], future: Provider.of(context).inputModelList, builder: (BuildContext context, AsyncSnapshot> snapshot) { connectionUI(snapshot); if (snapshot.data == null || snapshot.connectionState == ConnectionState.waiting) { return SizedBox(); } else { double yearAmount = 0; DateTime date(int duration) => startOfThisYear.add(Duration(days: duration)); bool isLeapYear(int year) { return (year % 4 == 0) && (year % 100 != 0) || (year % 400 == 0); } // widget.transactions.sort((a, b) => a.date!.compareTo(b.date!)); List sortByCategory( List data, String type) { return data .map((data) { if (data.type == type && data.category == widget.category) { return inputModel(data); } }) .where((element) => element != null) .toList() .cast(); } List transactions = widget.type == 'Income' ? sortByCategory(snapshot.data!, 'Income') : sortByCategory(snapshot.data!, 'Expense'); List transactionsYearly = (transactions .map((data) { DateTime dateSelectedDT = DateFormat('dd/MM/yyyy').parse(data.date!); if (dateSelectedDT.isAfter(startOfThisYear .subtract(Duration(days: 1))) && dateSelectedDT .isBefore(DateTime(todayDT.year, 12, 31))) { return inputModel(data); } }) .where((element) => element != null) .toList()) .cast(); if (transactionsYearly.length > 0) { for (InputModel? transaction in transactionsYearly) { yearAmount = yearAmount + transaction!.amount!; } } MonthAmount monthBasedTransaction( String month, DateTime date, int days) { double monthAmount = 0; for (InputModel transaction in transactionsYearly) { DateTime dateSelectedDT = DateFormat('dd/MM/yyyy').parse(transaction.date!); if (dateSelectedDT.isAfter(date) && dateSelectedDT.isBefore( startOfThisYear.add(Duration(days: days)))) { transaction.amount ??= 0; monthAmount = monthAmount + transaction.amount!; } } return MonthAmount(month, monthAmount); } List? monthBasedTransactionList = isLeapYear(year) ? [] : [ monthBasedTransaction( 'Jan', startOfThisYear.subtract(Duration(days: 1)), 30), monthBasedTransaction('Feb', date(30), 58), monthBasedTransaction('Mar', date(58), 89), monthBasedTransaction('Apr', date(89), 119), monthBasedTransaction('May', date(119), 150), monthBasedTransaction('Jun', date(150), 180), monthBasedTransaction('Jul', date(180), 211), monthBasedTransaction('Aug', date(211), 242), monthBasedTransaction('Sep', date(242), 272), monthBasedTransaction('Oct', date(272), 302), monthBasedTransaction('Nov', date(302), 333), monthBasedTransaction('Dec', date(333), 364), ]; double maximumMonthAmount = monthBasedTransactionList[0].amount; for (int i = 0; i < monthBasedTransactionList.length; i++) { if (monthBasedTransactionList[i].amount > maximumMonthAmount) { maximumMonthAmount = monthBasedTransactionList[i].amount; } } return Column( children: [ Padding( padding: EdgeInsets.only(right: 8.0.w), child: SizedBox( height: 280.h, child: SfCartesianChart( primaryXAxis: CategoryAxis( // placeLabelsNearAxisLine: true, // edgeLabelPlacement: EdgeLabelPlacement.none, // majorTickLines: MajorTickLines(size: 5, width: 1), axisLine: AxisLine( width: 3.h, ), labelPlacement: LabelPlacement.onTicks, isVisible: true, labelRotation: -45, rangePadding: ChartRangePadding.none, majorGridLines: MajorGridLines(width: 0)), // tooltipBehavior: _tooltipBehavior, primaryYAxis: NumericAxis( majorGridLines: MajorGridLines(width: 0), minimum: 0, maximum: maximumMonthAmount, labelFormat: '{value}', axisLine: AxisLine( width: 4.h, ), majorTickLines: MajorTickLines(size: 5.sp)), series: _getGradientAreaSeries( this.widget.type, monthBasedTransactionList), onMarkerRender: (MarkerRenderArgs args) { if (this.widget.type == 'Income') { if (args.pointIndex == 0) { args.color = const Color.fromRGBO(9, 110, 16, 1); } else if (args.pointIndex == 1) { args.color = const Color.fromRGBO(19, 134, 13, 1); } else if (args.pointIndex == 2) { args.color = const Color.fromRGBO(55, 171, 49, 1); } else if (args.pointIndex == 3) { args.color = const Color.fromRGBO(77, 213, 70, 1); } else if (args.pointIndex == 4) { args.color = const Color.fromRGBO(134, 213, 70, 1); } else if (args.pointIndex == 5) { args.color = const Color.fromRGBO(156, 222, 103, 1); } else if (args.pointIndex == 6) { args.color = const Color.fromRGBO(153, 249, 172, 1); } else if (args.pointIndex == 7) { args.color = const Color.fromRGBO(189, 235, 120, 1); } else if (args.pointIndex == 8) { args.color = const Color.fromRGBO(177, 249, 191, 1); } else if (args.pointIndex == 9) { args.color = const Color.fromRGBO(217, 241, 179, 1); } else if (args.pointIndex == 10) { args.color = const Color.fromRGBO(235, 246, 199, 1); } else if (args.pointIndex == 11) { args.color = Colors.white; } } else { if (args.pointIndex == 0) { args.color = const Color.fromRGBO(159, 16, 32, 1); } else if (args.pointIndex == 1) { args.color = const Color.fromRGBO(197, 71, 84, 1); } else if (args.pointIndex == 2) { args.color = const Color.fromRGBO(207, 124, 168, 1); } else if (args.pointIndex == 3) { args.color = const Color.fromRGBO(219, 128, 161, 1); } else if (args.pointIndex == 4) { args.color = const Color.fromRGBO(213, 143, 151, 1); } else if (args.pointIndex == 5) { args.color = const Color.fromRGBO(226, 157, 126, 1); } else if (args.pointIndex == 6) { args.color = const Color.fromRGBO(230, 168, 138, 1); } else if (args.pointIndex == 7) { args.color = const Color.fromRGBO(221, 176, 108, 1); } else if (args.pointIndex == 8) { args.color = const Color.fromRGBO(222, 187, 97, 1); } else if (args.pointIndex == 9) { args.color = const Color.fromRGBO(250, 204, 160, 1); } else if (args.pointIndex == 10) { args.color = const Color.fromRGBO(248, 219, 191, 1); } else if (args.pointIndex == 11) { args.color = Colors.white; } } }, ), ), ), Text( '${getTranslated(context, 'This year')}: ${format(yearAmount.toDouble())} $currency', textAlign: TextAlign.center, style: TextStyle( fontSize: 17.5.sp, fontWeight: FontWeight.bold), ), ChangeNotifierProvider( create: (context) => ChangeSelectedDate(), child: Selector( selector: (_, changeSelectedDate) => changeSelectedDate.selectedReportDate, builder: (context, selectedAnalysisDate, child) { selectedAnalysisDate ??= widget.selectedDate; //selectedTransactions is data sorted by category and selectedDate List selectedTransactions = filterData(context, transactions, selectedAnalysisDate); double totalAmount = 0; if (selectedTransactions.length > 0) { for (InputModel? transaction in selectedTransactions) { totalAmount = totalAmount + transaction!.amount!; } } return Expanded( child: Column( children: [ // selectedTransactions = selectedTransactions.reversed.toList(); Padding( padding: EdgeInsets.only( left: totalAmount.toString().length < 16 ? 10.w : 6.w, right: totalAmount.toString().length < 15 ? 20.h : 10.h, top: 25.h), child: Row( children: [ DropDownBox( false, selectedAnalysisDate), Spacer(), Text( '${format(totalAmount.toDouble())} $currency', style: GoogleFonts.aBeeZee( fontSize: format(totalAmount .toDouble()) .toString() .length > 18 ? 14.sp : format(totalAmount .toDouble()) .toString() .length > 14 ? 17.sp : 20.sp, fontStyle: FontStyle.italic, fontWeight: FontWeight.bold, color: widget.color), ) ], ), ), Divider( thickness: 0.5.h, height: 25.h, color: grey, ), Expanded( child: ListView.builder( shrinkWrap: true, itemCount: selectedTransactions.length, itemBuilder: (context, int) { return GestureDetector( behavior: HitTestBehavior.translucent, onTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => Edit( inputModel: selectedTransactions[ int], categoryIcon: widget.icon, ))).then( (value) => Provider.of< InputModelList>( context, listen: false) .changeInputModelList()); }, child: SwipeActionCell( backgroundColor: Colors.transparent, key: ObjectKey( selectedTransactions[ int]), performsFirstActionWithFullSwipe: true, trailingActions: < SwipeAction>[ SwipeAction( title: getTranslated(context, 'Delete') ?? 'Delete', onTap: (CompletionHandler handler) async { Platform.isIOS ? iosDialog( context, 'Are you sure you want to delete this transaction?', 'Delete', () async { DB.delete( selectedTransactions[ int] .id!); await handler( true); Provider.of( context, listen: false) .changeInputModelList(); customToast( context, 'Transaction has been deleted'); }) : androidDialog( context, 'Are you sure you want to delete this transaction?', 'Delete', () async { DB.delete( selectedTransactions[ int] .id!); await handler( true); Provider.of( context, listen: false) .changeInputModelList(); customToast( context, 'Transaction has been deleted'); }); }, color: red), SwipeAction( title: getTranslated(context, 'Add') ?? 'Add', onTap: (CompletionHandler handler) { var model = selectedTransactions[ int]; model.id = null; DB.insert(model); Provider.of( context, listen: false) .changeInputModelList(); customToast(context, 'Transaction has been updated'); }, color: Color.fromRGBO( 255, 183, 121, 1)), ], child: Padding( padding: EdgeInsets.only( left: 15.w, right: 15.w, top: 7.h), child: Row( children: [ Text( DateFormat(sharedPrefs .dateFormat) .format(DateFormat( 'dd/MM/yyyy') .parse(selectedTransactions[ int] .date!)), style: GoogleFonts .aBeeZee( fontSize: 17.sp)), Spacer(), Text( '${format(selectedTransactions[int].amount!)} $currency', style: GoogleFonts .aBeeZee( fontSize: 18.5.sp)), SizedBox( width: 15.w, ), Icon( Icons .arrow_forward_ios, size: 17.sp, ) ], ), ), ), ); }), ) ], ), ); })) ], ); } }); }); } } /// Returns the list of spline area series with horizontal gradient. List> _getGradientAreaSeries( String type, List monthAmountList) { // final List color = []; // color.add(Colors.blue[200]!); // color.add(Colors.orange[200]!); // final List stops = []; // stops.add(0.2); // stops.add(0.7); return >[ SplineAreaSeries( /// To set the gradient colors for border here. borderGradient: type == 'Income' ? const LinearGradient(colors: [ Color.fromRGBO(56, 135, 5, 1), Color.fromRGBO(159, 196, 135, 1) ], stops: [ 0.2, 0.9 ]) : const LinearGradient(colors: [ Color.fromRGBO(212, 126, 166, 1), Color.fromRGBO(222, 187, 104, 1) ], stops: [ 0.2, 0.9 ]), /// To set the gradient colors for series. gradient: type == 'Income' ? const LinearGradient(colors: [ Color.fromRGBO(101, 181, 60, 1), Color.fromRGBO(139, 194, 72, 1), Color.fromRGBO(203, 241, 119, 0.9) ], stops: [ 0.2, 0.5, 0.9 ]) : const LinearGradient(colors: [ Color.fromRGBO(224, 139, 207, 0.9), Color.fromRGBO(255, 232, 149, 0.9) ], stops: [ 0.2, 0.9 ]), borderWidth: 2.5.w, markerSettings: MarkerSettings( isVisible: true, height: 8.h, width: 8.h, borderColor: type == 'Income' ? Color.fromRGBO(161, 171, 35, 1) : Colors.white, borderWidth: 2.w, ), borderDrawMode: BorderDrawMode.all, dataSource: monthAmountList, xValueMapper: (MonthAmount monthAmount, _) => monthAmount.month, yValueMapper: (MonthAmount monthAmount, _) => monthAmount.amount, ) ]; } class MonthAmount { final String month; final double amount; const MonthAmount(this.month, this.amount); } ================================================ FILE: lib/project/app_pages/select_date_format.dart ================================================ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'package:money_assistant_2608/project/classes/constants.dart'; import 'package:money_assistant_2608/project/localization/methods.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:provider/provider.dart'; import '../provider.dart'; class FormatDate extends StatelessWidget { const FormatDate({Key? key}) : super(key: key); @override Widget build(BuildContext context) { List dateFormats = [ 'dd/MM/yyyy', 'MM/dd/yyyy', 'yyyy/MM/dd', 'yMMMd', 'MMMEd', 'MEd', 'MMMMd', 'MMMd', ]; return Scaffold( appBar: AppBar( backgroundColor: blue3, title: Text( getTranslated(context, 'Select a date format') ?? 'Select a date format', style: TextStyle(fontSize: 21.sp)), actions: [ Padding( padding: EdgeInsets.only(right: 5.w), child: TextButton( child: Text( getTranslated(context, 'Save') ?? 'Save', style: TextStyle(fontSize: 18.5.sp, color: white), ), onPressed: () => Navigator.pop(context)), ) ]), body: ChangeNotifierProvider( create: (context) => OnDateFormatSelected(), builder: (context, widget) => ListView.builder( itemCount: dateFormats.length, itemBuilder: (context, int) => GestureDetector( behavior: HitTestBehavior.translucent, onTap: () { context .read() .onDateFormatSelected(dateFormats[int]); }, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: EdgeInsets.all( 27.h), child: Row( children: [ Text( '${DateFormat(dateFormats[int]).format(now)}', style: TextStyle( fontSize: 19.sp, ), ), Spacer(), context .watch() .dateFormat == dateFormats[int] ? Icon(Icons.check_circle, size: 25.sp, color: blue3) : SizedBox() ], ), ), Divider(height: 0, thickness: 0.25, color: grey) ]), )), )); } } ================================================ FILE: lib/project/app_pages/select_icon.dart ================================================ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:money_assistant_2608/project/classes/app_bar.dart'; import 'package:money_assistant_2608/project/classes/category_item.dart'; import 'package:money_assistant_2608/project/classes/constants.dart'; import 'package:money_assistant_2608/project/localization/methods.dart'; class SelectIcon extends StatelessWidget { final String type; SelectIcon(this.type); @override Widget build(BuildContext context) { final List icons = createItemList( forAnalysisPage: false, isIncomeType: false, forSelectIconPage: true); return Scaffold( appBar: BasicAppBar(getTranslated(context, 'Icons')!), body: GridView.count( crossAxisCount: 4, childAspectRatio: 0.82, shrinkWrap: true, children: List.generate(icons.length, (index) { return Padding( padding: const EdgeInsets.symmetric(vertical: 15), child: Column( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.start, children: [ IconButton( onPressed: () { Navigator.pop(context, iconData(icons[index]) ); }, iconSize: 60.sp, icon: CircleAvatar( backgroundColor: Color.fromRGBO(215, 223, 231, 1), radius: 24.r, child: Icon( iconData(icons[index]), size: 30.sp, color: this.type == 'Income' ? green : red, )), ), ], ), ); }), ), ); } } ================================================ FILE: lib/project/app_pages/select_language.dart ================================================ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:money_assistant_2608/project/classes/constants.dart'; import 'package:money_assistant_2608/project/database_management/shared_preferences_services.dart'; import 'package:money_assistant_2608/project/localization/language.dart'; import 'package:money_assistant_2608/project/localization/methods.dart'; import 'package:provider/provider.dart'; import '../provider.dart'; import '../real_main.dart'; class SelectLanguage extends StatefulWidget { @override _SelectLanguageState createState() => _SelectLanguageState(); } class _SelectLanguageState extends State { @override Widget build(BuildContext context) { List languageList = Language.languageList; return Scaffold( appBar: AppBar( backgroundColor: blue3, title: Text(getTranslated(context, 'Select a language')!, style: TextStyle(fontSize: 21.sp)), actions: [ Padding( padding: EdgeInsets.only(right: 5.w), child: TextButton( child: Text( getTranslated(context, 'Save') ?? 'Save', style: TextStyle(fontSize: 18.5.sp, color: white), ), onPressed: () => Navigator.pop(context), ), ) ] ), body: ChangeNotifierProvider( create: (context) => OnLanguageSelected(), builder: (context, widget) => ListView.builder( itemCount: languageList.length, itemBuilder: (context, int) { return GestureDetector( behavior: HitTestBehavior.translucent, onTap: () { Locale _locale = sharedPrefs.setLocale(languageList[int].languageCode); MyApp.setLocale(context, _locale); context .read() .onSelect(languageList[int].languageCode); }, child: Column( children: [ Padding( padding: EdgeInsets.symmetric( vertical: 5.h, horizontal: 23.w), child: Row( children: [ Text( languageList[int].flag, style: TextStyle(fontSize: 45.sp), ), SizedBox( width: 35.w, ), Text(languageList[int].name, style: TextStyle( fontSize: 20.sp, )), Spacer(), context.watch().languageCode == languageList[int].languageCode ? Icon(Icons.check_circle, size: 25.sp, color: blue3) : SizedBox(), SizedBox(width: 15.w) ], ), ), Divider( indent: 90.w, height: 0, thickness: 0.25.h, color: grey, ), ], ), ); }), )); } } ================================================ FILE: lib/project/auth_pages/loading_page.dart ================================================ // import 'package:flutter/material.dart'; // import 'package:flutter_spinkit/flutter_spinkit.dart'; // // class Loading extends StatelessWidget { // @override // Widget build(BuildContext context) { // return Container( // color: Colors.brown[100], // child: Center( // child: SpinKitChasingDots( // color: Colors.brown, // size: 50.0, // ), // ), // ); // } // } ================================================ FILE: lib/project/auth_pages/sign_in.dart ================================================ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_login/flutter_login.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import '../home.dart'; class SignIn extends StatelessWidget { Future? _authenticateUsers(LoginData data) { print('authenticate users'); return Future.delayed(Duration(seconds: 1)).then((_) => null); } Future? _onRecoverPassword(String name) { print('onRecoverPassword'); return Future.delayed(Duration(seconds: 1)).then((_) => null); } @override Widget build(BuildContext context) { final inputBorder = BorderRadius.vertical( bottom: Radius.circular(10.0), top: Radius.circular(20.0), ); return FlutterLogin( title: 'MMAS', logo: 'Hi!', onSignup: _authenticateUsers, onLogin: _authenticateUsers, onRecoverPassword: _onRecoverPassword, onSubmitAnimationCompleted: () { Navigator.pushReplacement( context, MaterialPageRoute(builder: (context) => Home())); }, messages: LoginMessages( userHint: 'User', passwordHint: 'Pass', confirmPasswordHint: 'Confirm', loginButton: 'LOG IN', signupButton: 'REGISTER', forgotPasswordButton: 'Forgot huh?', recoverPasswordButton: 'HELP ME', goBackButton: 'GO BACK', confirmPasswordError: 'Not match!', recoverPasswordDescription: 'recoverPasswordDescription', recoverPasswordSuccess: 'Password rescued successfully', ), loginProviders: [ LoginProvider( icon: FontAwesomeIcons.google, label: 'Google', callback: () async { print('start google sign in'); await Future.delayed(Duration(seconds: 1)); print('stop google sign in'); return null; }, ), LoginProvider( icon: FontAwesomeIcons.facebookF, label: 'Facebook', callback: () async { print('start facebook sign in'); await Future.delayed(Duration(seconds: 1)); print('stop facebook sign in'); return null; }, ), LoginProvider( icon: FontAwesomeIcons.linkedinIn, callback: () async { print('start linkdin sign in'); await Future.delayed(Duration(seconds: 1)); print('stop linkdin sign in'); return null; }, ), LoginProvider( icon: FontAwesomeIcons.githubAlt, callback: () async { print('start github sign in'); await Future.delayed(Duration(seconds: 1)); print('stop github sign in'); return null; }, ), ], theme: LoginTheme( primaryColor: Colors.teal, accentColor: Colors.yellow, errorColor: Colors.deepOrange, titleStyle: TextStyle( color: Colors.greenAccent, fontFamily: 'Quicksand', letterSpacing: 4, ), bodyStyle: TextStyle( fontStyle: FontStyle.italic, decoration: TextDecoration.underline, ), textFieldStyle: TextStyle( color: Colors.orange, shadows: [Shadow(color: Colors.yellow, blurRadius: 2)], ), buttonStyle: TextStyle( fontWeight: FontWeight.w800, color: Colors.yellow, ), cardTheme: CardTheme( color: Colors.yellow.shade100, elevation: 5, margin: EdgeInsets.only(top: 15), shape: ContinuousRectangleBorder( borderRadius: BorderRadius.circular(100.0)), ), inputTheme: InputDecorationTheme( filled: true, fillColor: Colors.purple.withOpacity(.1), contentPadding: EdgeInsets.zero, errorStyle: TextStyle( backgroundColor: Colors.orange, color: Colors.white, ), labelStyle: TextStyle(fontSize: 12), enabledBorder: UnderlineInputBorder( borderSide: BorderSide(color: Colors.blue.shade700, width: 4), borderRadius: inputBorder, ), focusedBorder: UnderlineInputBorder( borderSide: BorderSide(color: Colors.blue.shade400, width: 5), borderRadius: inputBorder, ), errorBorder: UnderlineInputBorder( borderSide: BorderSide(color: Colors.red.shade700, width: 7), borderRadius: inputBorder, ), focusedErrorBorder: UnderlineInputBorder( borderSide: BorderSide(color: Colors.red.shade400, width: 8), borderRadius: inputBorder, ), disabledBorder: UnderlineInputBorder( borderSide: BorderSide(color: Colors.grey, width: 5), borderRadius: inputBorder, ), ), buttonTheme: LoginButtonTheme( splashColor: Colors.purple, backgroundColor: Colors.pinkAccent, highlightColor: Colors.lightGreen, elevation: 9.0, highlightElevation: 6.0, shape: BeveledRectangleBorder( borderRadius: BorderRadius.circular(10), ), // shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)), // shape: CircleBorder(side: BorderSide(color: Colors.green)), // shape: ContinuousRectangleBorder(borderRadius: BorderRadius.circular(55.0)), ), ), ); } } // import 'package:flutter/cupertino.dart'; // import 'package:flutter/material.dart'; // // import '../../classes/textinput_decoration.dart'; // import 'loading_page.dart'; // // class SignIn extends StatefulWidget { // @override // _SignInState createState() => _SignInState(); // } // // class _SignInState extends State { // final AuthService _auth = AuthService(); // final _formKey = GlobalKey(); // String error = ''; // bool loading = false; // // // text field state // String email = ''; // String password = ''; // // @override // Widget build(BuildContext context) { // return loading // ? Loading() // : Scaffold( // backgroundColor: Colors.brown[100], // appBar: AppBar( // backgroundColor: Colors.brown[400], // elevation: 0.0, // title: Text('Sign in to Brew Crew'), // actions: [ // FlatButton.icon( // icon: Icon(Icons.person), // label: Text('Register'), // onPressed: () {}, // ), // ], // ), // body: Container( // padding: EdgeInsets.symmetric(vertical: 20.0, horizontal: 50.0), // child: Form( // key: _formKey, // child: Column( // children: [ // SizedBox(height: 20.0), // TextFormField( // decoration: // textInputDecoration.copyWith(hintText: 'email'), // validator: (val) => val.isEmpty ? 'Enter an email' : null, // onChanged: (val) { // setState(() => email = val); // }, // ), // SizedBox(height: 20.0), // TextFormField( // obscureText: true, // decoration: // textInputDecoration.copyWith(hintText: 'password'), // validator: (val) => val.length < 6 // ? 'Enter a password 6+ chars long' // : null, // onChanged: (val) { // setState(() => password = val); // }, // ), // SizedBox(height: 20.0), // RaisedButton( // color: Colors.pink[400], // child: Text( // 'Sign In', // style: TextStyle(color: Colors.white), // ), // onPressed: () async { // if (_formKey.currentState.validate()) { // setState(() => loading = true); // dynamic result = await _auth // .signInWithEmailAndPassword(email, password); // if (result == null) { // setState(() { // loading = false; // error = // 'Could not sign in with those credentials'; // }); // } else { // Navigator.pop(context); // } // } // }), // SizedBox(height: 12.0), // Text( // error, // style: TextStyle(color: Colors.red, fontSize: 14.0), // ), // ], // ), // ), // ), // ); // } // } ================================================ FILE: lib/project/auth_pages/sign_up.dart ================================================ // import 'package:flutter/cupertino.dart'; // import 'package:flutter/material.dart'; // // import '../../classes/textinput_decoration.dart'; // import 'loading_page.dart'; // // class SignUp extends StatefulWidget { // @override // _SignUpState createState() => _SignUpState(); // } // // class _SignUpState extends State { // final AuthService _auth = AuthService(); // final _formKey = GlobalKey(); // String error = ''; // bool loading = false; // // // text field state // String email = ''; // String password = ''; // // @override // Widget build(BuildContext context) { // return loading // ? Loading() // : Scaffold( // backgroundColor: Colors.brown[100], // appBar: AppBar( // backgroundColor: Colors.brown[400], // elevation: 0.0, // title: Text('Sign up to Brew Crew'), // actions: [ // FlatButton.icon( // icon: Icon(Icons.person), // label: Text('Sign In'), // onPressed: () {}, // ), // ], // ), // body: Container( // padding: EdgeInsets.symmetric(vertical: 20.0, horizontal: 50.0), // child: Form( // key: _formKey, // child: Column( // children: [ // SizedBox(height: 20.0), // TextFormField( // decoration: // textInputDecoration.copyWith(hintText: 'email'), // validator: (val) => val.isEmpty ? 'Enter an email' : null, // onChanged: (val) { // setState(() => email = val); // }, // ), // SizedBox(height: 20.0), // TextFormField( // decoration: // textInputDecoration.copyWith(hintText: 'password'), // obscureText: true, // validator: (val) => val.length < 6 // ? 'Enter a password 6+ chars long' // : null, // onChanged: (val) { // setState(() => password = val); // }, // ), // SizedBox(height: 20.0), // RaisedButton( // color: Colors.pink[400], // child: Text( // 'Register', // style: TextStyle(color: Colors.white), // ), // onPressed: () async { // if (_formKey.currentState.validate()) { // setState(() => loading = true); // dynamic result = await _auth // .registerWithEmailAndPassword(email, password); // // if (result == null) { // setState(() { // loading = false; // error = 'Please supply a valid email'; // }); // } else { // Navigator.pop(context); // } // } // }), // SizedBox(height: 12.0), // Text( // error, // style: TextStyle(color: Colors.red, fontSize: 14.0), // ) // ], // ), // ), // ), // ); // } // } ================================================ FILE: lib/project/auth_pages/user_account.dart ================================================ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:money_assistant_2608/project/classes/constants.dart'; // final AuthService _auth = AuthService(); class UserAccount extends StatefulWidget { @override _UserAccountState createState() => _UserAccountState(); } class _UserAccountState extends State { List textList = [ "Personal information", "Account link", "Change password", "sign out" ]; List iconList = [ Icons.person, Icons.link_sharp, Icons.admin_panel_settings_sharp, Icons.logout ]; @override Widget build(BuildContext context) { return Scaffold( appBar: PreferredSize( preferredSize: Size.fromHeight(270.h), child: Container( height: 270, child: Padding( padding: EdgeInsets.only(top: 40.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: EdgeInsets.only(left: 20.w), child: IconButton( icon: Icon(Icons.arrow_back_ios), onPressed: () { Navigator.pop(context); }), ), Center( child: CircleAvatar( child: CircleAvatar( radius: 30.r, backgroundColor: Color.fromRGBO(210, 234, 251, 1)), radius: 35.r, backgroundColor: Colors.grey, ), ), SizedBox( height: 10.h, ), Center( child: Text( "User name", style: TextStyle(fontSize: 25.sp, fontWeight: FontWeight.bold), )), SizedBox( height: 15.h, ), Center( child: Container( width: 100.w, height: 30.h, decoration: BoxDecoration( borderRadius: BorderRadius.circular(40), border: Border.all(color: Colors.blueGrey, width: 0.5)), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.crop_free), SizedBox( width: 3.w, ), Text( "Free", style: TextStyle(fontSize: 20.sp), ) ], ), ), ), SizedBox( height: 20.h, ), ], ), ), )), body: Column( children: [ // Divider( // height: 0, // thickness: 0.8, // color: Colors.grey, // ), // Container( // height: 13, // color: Color.fromRGBO(210, 234, 251, 1), // ), Divider( height: 0, thickness: 0.8.w, color: grey, ), Padding( padding: EdgeInsets.symmetric(horizontal: 10.w), child: SizedBox( height: 60.h, child: Row( children: [ IconButton( icon: Icon( Icons.sports_golf, size: 30.sp, ), onPressed: () {}, ), SizedBox( width: 10.w, ), Text( 'Explore Premium', style: TextStyle(fontSize: 25.sp), ) ], ), ), ), Divider( height: 0.h, thickness: 0.8.w, color: grey, ), Container( height: 60.h, color: Color.fromRGBO(237, 240, 243, 1), ), Divider( height: 1.h, thickness: 0.8.w, color: grey, ), Expanded( child: ListView.builder( itemCount: iconList.length, itemBuilder: (context, int) { return SizedBox( height: 60.h, child: Column(children: [ Padding( padding: EdgeInsets.symmetric(horizontal: 10.w), child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ IconButton( icon: Icon( iconList[int], size: 30.sp, ), onPressed: () async { // await _auth.signOut(); // Navigator.pop(context); }, ), SizedBox( width: 10.w, ), Text( textList[int], style: TextStyle(fontSize: 25.sp), ), Spacer(), Icon( Icons.arrow_forward_ios, size: 20.sp, ), ], ), ), Divider( height: 0, thickness: 0.8.w, color: grey, ), ]), ); }), ) ], ), ); } } ================================================ FILE: lib/project/auth_pages/welcome_page.dart ================================================ // import 'package:flutter/cupertino.dart'; // import 'package:flutter/material.dart'; // // import 'sign_in.dart'; // import 'sign_up.dart'; // // class WelcomePage extends StatefulWidget { // @override // _WelcomePageState createState() => _WelcomePageState(); // } // // class _WelcomePageState extends State { // @override // Widget build(BuildContext context) { // print('Welcome Page'); // return Scaffold( // backgroundColor: Color.fromRGBO(139, 205, 254, 1), // appBar: AppBar( // backgroundColor: Colors.orange, // title: Text( // 'Welcome Page', // style: TextStyle(fontSize: 20), // ), // ), // body: Center( // child: Column( // children: [ // Row( // children: [ // IconButton( // icon: Icon( // Icons.login, // ), // onPressed: () => Navigator.push(context, // MaterialPageRoute(builder: (context) => SignIn())), // ), // Text( // 'Sign in', // style: TextStyle(fontSize: 20), // ) // ], // ), // Row( // children: [ // IconButton( // icon: Icon( // Icons.app_registration, // ), // onPressed: () => Navigator.push(context, // MaterialPageRoute(builder: (context) => SignUp())), // ), // Text( // 'Sign up', // style: TextStyle(fontSize: 20), // ) // ], // ) // ], // ), // ), // ); // } // } ================================================ FILE: lib/project/auth_pages/wrapper.dart ================================================ // import 'package:flutter/cupertino.dart'; // // import '../app_pages/home.dart'; // import 'welcome_page.dart'; // // class Wrapper extends StatelessWidget { // final UserUid userUid; // const Wrapper(this.userUid); // @override // Widget build(BuildContext context) { // print('${userUid.uid}'); // if (userUid.uid == '') { // return WelcomePage(); // } else { // return Home(); // } // } // } ================================================ FILE: lib/project/auth_services/firebase_authentication.dart ================================================ import 'dart:async'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:google_sign_in/google_sign_in.dart'; import 'package:money_assistant_2608/project/classes/custom_toast.dart'; class FirebaseAuthentication { static Future initializeFireBase() async { FirebaseApp firebaseApp = await Firebase.initializeApp(); return firebaseApp; } static Future googleSignIn({required BuildContext context}) async{ User? user; FirebaseAuth auth = FirebaseAuth.instance; final GoogleSignIn googleSignIn = GoogleSignIn(); final GoogleSignInAccount? googleSignInAccount = await googleSignIn.signIn(); if(googleSignInAccount != null){ final GoogleSignInAuthentication googleSignInAuthentication = await googleSignInAccount.authentication; final AuthCredential credential = GoogleAuthProvider.credential(accessToken: googleSignInAuthentication.accessToken, idToken: googleSignInAuthentication.idToken); try { final UserCredential userCredential = await auth.signInWithCredential(credential); user = userCredential.user; } on FirebaseException catch (e) { if (e.code == 'account-exists-with-different-credentia') { customToast(context,'The account already exists with a different credential.'); } else if (e.code == 'invalid-credential') { customToast(context,'Error occurred while accessing credentials. Try again.'); } }catch(e){ customToast(context,'Error occurred using Google Sign-In. Try again.'); } } return user; } static Future signOut({required BuildContext context})async{ final GoogleSignIn googleSignIn = GoogleSignIn(); try{ await googleSignIn.signOut(); } catch (e){ customToast(context, 'Error signing out. Try again.'); } } } // final FirebaseAuth _auth = FirebaseAuth.instance; // // UserUid _userUid(User user) { // return user != null ? UserUid(uid: user.uid) : null; // } // // // what is get? // Stream get user { // return _auth.authStateChanges().map((User user) => _userUid(user)); // // .map(_userUid); // } // // // sign in anon // Future signInAnon() async { // try { // UserCredential result = await _auth.signInAnonymously(); // User user = result.user; // return _userUid(user); // } catch (e) { // print(e.toString()); // return null; // } // } // // // sign in with email and password // Future signInWithEmailAndPassword(String email, String password) async { // try { // UserCredential result = await _auth.signInWithEmailAndPassword( // email: email, password: password); // User user = result.user; // return user; // } catch (error) { // print(error.toString()); // return null; // } // } // // // register with email and password // Future registerWithEmailAndPassword(String email, String password) async { // try { // UserCredential result = await _auth.createUserWithEmailAndPassword( // email: email, password: password); // User user = result.user; // return _userUid(user); // } catch (error) { // print(error.toString()); // return null; // } // } // // // sign out // Future signOut() async { // try { // return await _auth.signOut(); // } catch (error) { // print(error.toString()); // return null; // } // } // } // class UserUid { // final String uid; // // UserUid({this.uid}); // } ================================================ FILE: lib/project/classes/alert_dialog.dart ================================================ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:money_assistant_2608/project/localization/methods.dart'; Future iosDialog(BuildContext context, String content, String action, Function onAction) => showCupertinoDialog( context: context, builder: (BuildContext context) { return CupertinoAlertDialog( title: Padding( padding: EdgeInsets.only( bottom: 8.h, ), child: Text( getTranslated(context, 'Please Confirm') ?? 'Please Confirm', style: TextStyle(fontSize: 21.sp), ), ), content: Text(getTranslated(context, content) ?? content, style: TextStyle(fontSize: 15.5.sp)), actions: [ CupertinoDialogAction( onPressed: () { Navigator.pop(context); }, child: Padding( padding: EdgeInsets.symmetric(vertical: 6.h, horizontal: 3.w), child: Text(getTranslated(context, 'Cancel') ?? 'Cancel', style: TextStyle( fontSize: 19.5.sp, fontWeight: FontWeight.w600)), ), isDefaultAction: false, isDestructiveAction: false, ), CupertinoDialogAction( onPressed: () { onAction(); Navigator.pop(context); }, child: Padding( padding: EdgeInsets.symmetric(vertical: 6.h, horizontal: 3.w), child: Text(getTranslated(context, action) ?? action, style: TextStyle( fontSize: 19.5.sp, fontWeight: FontWeight.w600)), ), isDefaultAction: true, isDestructiveAction: true, ) ], ); }); Future androidDialog(BuildContext context, String content, String action, Function onAction) => showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: Text(getTranslated(context, 'Please Confirm')!), content: Text( getTranslated(context, content) ?? content), actions: [ TextButton( onPressed: () { onAction(); Navigator.pop(context); }, child: Text(getTranslated(context, 'Cancel') ?? 'Cancel')), TextButton( onPressed: () { Navigator.pop(context); }, child: Text(getTranslated(context, action) ?? action)) ], ); }); ================================================ FILE: lib/project/classes/app_bar.dart ================================================ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:money_assistant_2608/project/localization/methods.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:money_assistant_2608/project/app_pages/input.dart'; import 'constants.dart'; class BasicAppBar extends StatelessWidget with PreferredSizeWidget { final String title; const BasicAppBar(this.title); @override Size get preferredSize => Size.fromHeight(kToolbarHeight); @override Widget build(BuildContext context) { return AppBar( backgroundColor: blue3, title: Text(title, style: TextStyle(fontSize: 21.sp)), ); } } class InExAppBar extends StatelessWidget implements PreferredSizeWidget { final bool isInputPage; const InExAppBar(this.isInputPage); @override Size get preferredSize => Size.fromHeight(kToolbarHeight); @override Widget build(BuildContext context) { Tab appBarTab(String title) => Tab( child: Container( width: double.maxFinite, height: double.maxFinite, decoration: BoxDecoration(), child: Align( child: Text( getTranslated(context, title)!, style: TextStyle(fontSize: 19.sp), )), ), ); return AppBar( backgroundColor: blue2, title: TabBar( unselectedLabelColor: white, indicatorSize: TabBarIndicatorSize.tab, indicator: BoxDecoration( borderRadius: BorderRadius.circular(50.r), color: Color.fromRGBO(82, 179, 252, 1), ), tabs: [ appBarTab('EXPENSE'), appBarTab('INCOME') ], ), actions: isInputPage ? [ IconButton( icon: Icon(Icons.check), iconSize: 28, onPressed: () { saveInputFunc(context,true); }, ) ] : null, ); } } class CategoryAppBar extends StatelessWidget implements PreferredSizeWidget { final Widget editCategory; const CategoryAppBar(this.editCategory); @override Size get preferredSize => Size.fromHeight(kToolbarHeight); @override Widget build(BuildContext context) { return AppBar( backgroundColor: blue3, actions: [ Padding( padding: EdgeInsets.only( right: 20.w, ), child: GestureDetector( behavior: HitTestBehavior.translucent, onTap: () { Navigator.push(context, MaterialPageRoute(builder: (context) => editCategory)); }, child: Row(children: [ Icon( Icons.edit, size: 19.sp, ), SizedBox(width: 3.w), Text( getTranslated(context, 'Edit')!, style: TextStyle(fontSize: 19.sp), ), ]), ), // child: Icon(Icons.edit), ), ], title: Text(getTranslated(context, 'Category')!, style: TextStyle(fontSize: 21.sp)), ); } } class EditCategoryAppBar extends StatelessWidget implements PreferredSizeWidget { final Widget addCategory; const EditCategoryAppBar(this.addCategory); @override Size get preferredSize => Size.fromHeight(kToolbarHeight); @override Widget build(BuildContext context) { return AppBar( backgroundColor: blue3, actions: [ Padding( padding: EdgeInsets.only(right: 5.w), child: TextButton( onPressed: () => Navigator.push(context, MaterialPageRoute(builder: (context) => addCategory)), child: Text( getTranslated(context, 'Add')!, style: TextStyle(fontSize: 18.5.sp, color: white), ), ), // child: Icon(Icons.edit), ), ], title: Text(getTranslated(context, 'Edit Category')!, style: TextStyle(fontSize: 21.sp)), ); } } ================================================ FILE: lib/project/classes/category_item.dart ================================================ class CategoryItem { int iconCodePoint; String? iconFontPackage; String? iconFontFamily; String text; String? description; CategoryItem(this.iconCodePoint, this.iconFontPackage, this.iconFontFamily, this.text, this.description); factory CategoryItem.fromJson(Map json) { return new CategoryItem(json['iconCodePoint'], json['iconFontPackage'], json['iconFontFamily'], json['text'], json['description']); } Map toJson() { return { 'iconCodePoint': this.iconCodePoint, 'iconFontPackage': this.iconFontPackage, 'iconFontFamily': this.iconFontFamily, 'text': this.text, 'description': this.description }; } } ================================================ FILE: lib/project/classes/chart_pie.dart ================================================ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:money_assistant_2608/project/localization/methods.dart'; import 'package:syncfusion_flutter_charts/charts.dart'; import 'input_model.dart'; class ChartPie extends StatelessWidget { const ChartPie(this.transactionsSorted); final List transactionsSorted; @override Widget build(BuildContext context) { bool haveRecords; String width; String height; double animationDuration; if (this.transactionsSorted[0].category == '') { haveRecords = false; width = '67%'; height = '67%'; animationDuration = 0; } else { haveRecords = true; width = '67%'; height = '67%'; animationDuration = 270; } return SfCircularChart( tooltipBehavior: TooltipBehavior(enable: haveRecords), annotations: [ CircularChartAnnotation( width: width, height: height, widget: Annotations(haveRecords)) ], series: >[ DoughnutSeries( startAngle: 90, endAngle: 90, animationDuration: animationDuration, // enableSmartLabels: haveRecords, sortingOrder: SortingOrder.descending, sortFieldValueMapper: (InputModel data, _) => data.category, enableTooltip: haveRecords, dataSource: this.transactionsSorted, pointColorMapper: (InputModel data, _) => data.color, xValueMapper: (InputModel data, _) => getTranslated(context, data.category!) ?? data.category, yValueMapper: (InputModel data, _) => data.amount, dataLabelSettings: DataLabelSettings( showZeroValue: true, useSeriesColor: true, labelPosition: ChartDataLabelPosition.outside, isVisible: haveRecords, ), innerRadius: '50%', radius: '67%'), ], ); } } class Annotations extends StatelessWidget { final bool haveRecords; const Annotations(this.haveRecords); @override Widget build(BuildContext context) { return PhysicalModel( child: Container( child: haveRecords == false ? Center( child: Text(getTranslated(context, 'There is no data')!, textAlign: TextAlign.center, style: TextStyle( color: Color.fromRGBO(0, 0, 0, 0.5), fontSize: 23.5.sp, fontStyle: FontStyle.italic)), ) : null, ), shape: BoxShape.circle, elevation: 10, shadowColor: Colors.black, color: const Color.fromRGBO(230, 230, 230, 1)); } } ================================================ FILE: lib/project/classes/constants.dart ================================================ import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'package:money_assistant_2608/project/database_management/shared_preferences_services.dart'; import 'category_item.dart'; import 'input_model.dart'; Color green = Color.fromRGBO(57, 157, 3, 1), red = Color.fromRGBO(217, 89, 89, 1), white = Color.fromRGBO(255, 255, 255, 1), blue1 = Color.fromRGBO(210, 234, 251, 1), blue2 = Color.fromRGBO(139, 205, 254, 1), blue3 = Color.fromRGBO(89, 176, 222, 1), grey = Colors.grey; List chartPieColors = [ //19 Color.fromRGBO(100, 202, 254, 1), Color.fromRGBO(80, 157, 253, 1), Color.fromRGBO(7, 156, 193, 1), Color.fromRGBO(89, 129, 163, 1), Color.fromRGBO(79, 94, 120, 1), Color.fromRGBO(196, 199, 216, 1), Color.fromRGBO(255, 206, 161, 1), Color.fromRGBO(255, 183, 121, 1), Color.fromRGBO(237, 156, 128, 1), Color.fromRGBO(126, 180, 166, 1), Color.fromRGBO(212, 216, 140, 1), Color.fromRGBO(144, 192, 106, 1), Color.fromRGBO(128, 186, 76, 1), Color.fromRGBO(224, 217, 255, 1), Color.fromRGBO(202, 164, 255, 1), Color.fromRGBO(197, 156, 240, 1), Color.fromRGBO(241, 197, 211, 1), Color.fromRGBO(244, 151, 178, 1), Color.fromRGBO(218, 145, 176, 1), //20 Color.fromRGBO(141, 190, 255, 1), Color.fromRGBO(160, 217, 254, 1), Color.fromRGBO(117, 216, 228, 1), Color.fromRGBO(120, 217, 192, 1), Color.fromRGBO(172, 198, 152, 1), Color.fromRGBO(162, 193, 115, 1), Color.fromRGBO(112, 164, 112, 1), Color.fromRGBO(65, 174, 223, 1), Color.fromRGBO(71, 131, 192, 1), Color.fromRGBO(32, 225, 188, 1), Color.fromRGBO(53, 136, 143, 1), Color.fromRGBO(139, 178, 193, 1), Color.fromRGBO(125, 150, 191, 1), Color.fromRGBO(119, 131, 148, 1), Color.fromRGBO(243, 210, 122, 1), Color.fromRGBO(254, 203, 94, 1), Color.fromRGBO(244, 186, 106, 1), Color.fromRGBO(217, 165, 105, 1), Color.fromRGBO(214, 142, 96, 1), Color.fromRGBO(190, 119, 112, 1), Color.fromRGBO(194, 94, 78, 1), Color.fromRGBO(192, 72, 42, 1), Color.fromRGBO(176, 29, 51, 1), //18 Color.fromRGBO(198, 180, 251, 1), Color.fromRGBO(155, 128, 217, 1), Color.fromRGBO(112, 130, 212, 1), Color.fromRGBO(78, 123, 216, 1), Color.fromRGBO(139, 205, 254, 1), Color.fromRGBO(89, 176, 222, 1), Color.fromRGBO(81, 155, 194, 1), Color.fromRGBO(4, 135, 192, 1), Color.fromRGBO(50, 128, 171, 1), Color.fromRGBO(44, 110, 119, 1), Color.fromRGBO(41, 147, 134, 1), Color.fromRGBO(95, 155, 71, 1), Color.fromRGBO(179, 217, 37, 1), Color.fromRGBO(237, 178, 135, 1), Color.fromRGBO(198, 157, 100, 1), Color.fromRGBO(194, 140, 112, 1), Color.fromRGBO(214, 138, 88, 1), Color.fromRGBO(225, 123, 66, 1), ]; String format(double number) => NumberFormat("#,###,###,###,###,###.##", "en_US").format(number); IconData iconData(CategoryItem item) => IconData(item.iconCodePoint, fontPackage: item.iconFontPackage, fontFamily: item.iconFontFamily); //should description be '' or null? CategoryItem categoryItem(IconData icon, String name) => CategoryItem(icon.codePoint, icon.fontPackage, icon.fontFamily, name, ''); Widget? connectionUI(AsyncSnapshot> snapshot) { if (snapshot.connectionState == ConnectionState.none) { return Center( child: CircularProgressIndicator(), ); } if (snapshot.hasError) { print('${snapshot.error}'); return Center( child: CircularProgressIndicator(), ); } } List createItemList({ List? transactions, required bool forAnalysisPage, isIncomeType, forSelectIconPage, }) { List itemList = [], items = [], expenseItems = []; sharedPrefs.getAllExpenseItemsLists().forEach((parentExpenseItem) => parentExpenseItem .forEach((expenseItem) => expenseItems.add(expenseItem))); if (forAnalysisPage) { items = isIncomeType ? incomeItems : expenseItems; } else { items = [...incomeItems, ...expenseItems]; } if (forSelectIconPage) { return items; } else { for (InputModel transaction in transactions!) { for (int i = 0; i < items.length; i++) { if (transaction.category == items[i].text) { itemList.add(items[i]); break; } if (i == items.length - 1) { CategoryItem itemElse = CategoryItem( Icons.category_outlined.codePoint, Icons.category_outlined.fontPackage, Icons.category_outlined.fontFamily, transaction.category!, transaction.description); itemList.add(itemElse); } } } return itemList; } } //for analysis, report final DateTime now = DateTime.now(), todayDT = DateTime(now.year, now.month, now.day), startOfThisWeek = todayDT.subtract(Duration(days: todayDT.weekday - 1)), startOfThisMonth = DateTime(todayDT.year, todayDT.month, 1), startOfThisYear = DateTime(todayDT.year, 1, 1), startOfThisQuarter = DateTime(todayDT.year, quarterStartMonth, 1); final int thisQuarter = (todayDT.month + 2) ~/ 3, quarterStartMonth = 3 * thisQuarter - 2; final List timeline = [ 'Today', 'This week', 'This month', 'This quarter', 'This year', 'All' ]; InputModel inputModel(data) => InputModel( id: data.id, type: data.type, amount: data.amount!, category: data.category!, description: data.description!, date: data.date, time: data.time); List filterData( BuildContext context, List data, String selectedDate) { // filter data based on user's selected day return (data .map((data) { DateTime dateSelectedDT = DateFormat('dd/MM/yyyy').parse(data.date!); if (selectedDate == 'Today') { if (dateSelectedDT.isAfter(todayDT.subtract(Duration(days: 1))) && dateSelectedDT.isBefore(todayDT.add(Duration(days: 1)))) { return inputModel(data); } } else if (selectedDate == 'This week') { if (dateSelectedDT .isAfter(startOfThisWeek.subtract(Duration(days: 1))) && dateSelectedDT .isBefore(startOfThisWeek.add(Duration(days: 7)))) { return inputModel(data); } } else if (selectedDate == 'This month') { if (dateSelectedDT .isAfter(startOfThisMonth.subtract(Duration(days: 1))) && dateSelectedDT .isBefore(DateTime(todayDT.year, todayDT.month + 1, 1))) { return inputModel(data); } } else if (selectedDate == 'This quarter') { if (dateSelectedDT.isAfter( startOfThisQuarter.subtract(Duration(days: 1))) && dateSelectedDT.isBefore(DateTime(startOfThisQuarter.year, startOfThisQuarter.month + 3, 1))) { return inputModel(data); } } else if (selectedDate == 'This year') { if (dateSelectedDT .isAfter(startOfThisYear.subtract(Duration(days: 1))) && dateSelectedDT.isBefore(DateTime(todayDT.year + 1, 1, 1))) { return inputModel(data); } } else { return inputModel(data); } }) .where((element) => element != null) .toList()) .cast(); } // //3 // Color.fromRGBO(97, 162, 195, 1), // Color.fromRGBO(107, 203, 253, 1), // //2 // Color.fromRGBO(241, 187, 140, 1), // Color.fromRGBO(242, 193, 145, 1), // Color.fromRGBO(241, 197, 161, 1), // Color.fromRGBO(227, 191, 145, 1), // Color.fromRGBO(241, 207, 170, 1), // Color.fromRGBO(151, 209, 255, 1), // Color.fromRGBO(238, 161, 130, 1), // Color.fromRGBO(253, 152, 67, 1), // Color.fromRGBO(11, 153, 178, 1), // Color.fromRGBO(5, 168, 192, 1), // // // Color.fromRGBO( 35, 115, 217, 1), // Color.fromRGBO(6, 104, 189, 1), // Color.fromRGBO( 45, 99, 186, 1), // Color.fromRGBO( 61, 122, 135, 1), // Color.fromRGBO( 42, 65, 88, 1), // Color.fromRGBO(36, 85, 120, 1), // Color.fromRGBO(57, 63, 71, 1), // Color.fromRGBO(20, 44, 90, 1), // Color.fromRGBO(27, 114, 181, 1), // Color.fromRGBO(72, 102, 164, 1), // Color.fromRGBO( 24, 47, 66, 1), // Color.fromRGBO(56, 78, 116, 1), // Color.fromRGBO(101, 70, 163, 1), // Color.fromRGBO(78, 45, 127, 1), // Color.fromRGBO(116, 13, 64, 1), // Color.fromRGBO(83, 92, 112, 1), // Color.fromRGBO(79, 168, 169, 1), // Color.fromRGBO(60, 186, 177, 1), // Color.fromRGBO( 47, 178, 196, 1), // Color.fromRGBO( 68, 165, 193, 1), // Color.fromRGBO(50, 101, 114, 1), // Color.fromRGBO(2, 67, 107, 1), // Color.fromRGBO(57, 68, 99, 1), // Color.fromRGBO(65, 96, 142, 1), // Color.fromRGBO(78, 123, 165, 1), // Color.fromRGBO(95, 114, 138, 1), // Color.fromRGBO(218, 60, 81, 1), // Color.fromRGBO(52, 92, 67, 1), // Color.fromRGBO(69, 91, 50, 1), // Color.fromRGBO(71, 90, 44, 1), // Color.fromRGBO(252, 182, 35, 1), // Color.fromRGBO(255, 201, 0, 1), // Color.fromRGBO(254, 190, 48, 1), // Color.fromRGBO(241, 87, 33, 1), // Color.fromRGBO(255, 122, 0, 1), // Color.fromRGBO(215, 122, 2, 1), // Color.fromRGBO(176, 99, 52, 1), // Color.fromRGBO(190, 100, 42, 1), // Color.fromRGBO(166, 120, 73, 1), // Color.fromRGBO(165, 116, 81, 1), // Color.fromRGBO(161, 85, 244, 1), // Color.fromRGBO(162, 74, 125, 1), // Color.fromRGBO(156, 41, 134, 1), // Color.fromRGBO(153, 51, 178, 1), // Color.fromRGBO(233, 114, 228, 1), // Color.fromRGBO(158, 20, 24, 1), // Color.fromRGBO(203, 71, 242, 1), // Color.fromRGBO(218, 91, 160, 1), // Color.fromRGBO(181, 89, 171, 1), // Color.fromRGBO(208, 80, 135, 1), // Color.fromRGBO(2, 157, 193, 1), // Color.fromRGBO(34, 146, 212, 1), // Color.fromRGBO(2, 205, 209, 1), // Color.fromRGBO(85, 16, 9, 1), // Color.fromRGBO(196, 238, 236, 1), // Color.fromRGBO(192, 243, 247, 1), // Color.fromRGBO(164, 255, 242, 1), // Color.fromRGBO(248, 233, 193, 1), // Color.fromRGBO(244, 231, 203, 1), // Color.fromRGBO(212, 228, 244, 1), // Color.fromRGBO(188, 235, 239, 1), // Color.fromRGBO(246, 192, 142, 1), // Color.fromRGBO(233, 242, 235, 1), // Color.fromRGBO(227, 191, 145, 1), // Color.fromRGBO(189, 79, 0, 1), // Color.fromRGBO(214, 89, 43, 1), // Color.fromRGBO(240, 105, 85, 1), // Color.fromRGBO(231, 116, 46, 1), // Color.fromRGBO(156, 89, 98, 1), // Color.fromRGBO(208, 151, 99, 1), // Color.fromRGBO(189, 124, 66, 1), // Color.fromRGBO(181, 116, 67, 1), // Color.fromRGBO(242, 135, 36, 1), // Color.fromRGBO(243, 129, 61, 1), // Color.fromRGBO(240, 131, 36, 1), // Color.fromRGBO(245, 139, 46, 1), // Color.fromRGBO(254, 160, 51, 1), // Color.fromRGBO(239, 156, 71, 1), // Color.fromRGBO(245, 166, 76, 1), // Color.fromRGBO(245, 164, 52, 1), // Color.fromRGBO(243, 170, 48, 1), // Color.fromRGBO(164, 148, 126, 1), // Color.fromRGBO(190, 157, 116, 1), // Color.fromRGBO(191, 164, 131, 1), // Color.fromRGBO(192, 176, 160, 1), // Color.fromRGBO(193, 177, 164, 1), // Color.fromRGBO(214, 193, 165, 1), // Color.fromRGBO(255, 221, 206, 1), // Color.fromRGBO(242, 217, 203, 1), // Color.fromRGBO(245, 236, 224, 1), // Color.fromRGBO(255, 232, 204, 1), // Color.fromRGBO(255, 246, 216, 1), // Color.fromRGBO(157, 245, 255, 1), // Color.fromRGBO(235, 128, 209, 1), // Color.fromRGBO(194, 212, 241, 1), // Color.fromRGBO(196, 222, 235, 1), // Color.fromRGBO(160, 224, 239, 1), // Color.fromRGBO(157, 231, 244, 1), // Color.fromRGBO(127, 191, 239, 1), // Color.fromRGBO(214, 213, 155, 1), // Color.fromRGBO(229, 217, 147, 1), // Color.fromRGBO(208, 185, 240, 1), // Color.fromRGBO(204, 217, 224, 1), // Color.fromRGBO(168, 196, 187, 1), // Color.fromRGBO(198, 219, 207, 1), // Color.fromRGBO(203, 214, 189, 1), // Color.fromRGBO(213, 245, 206, 1), // Color.fromRGBO(186, 183, 168, 1), // Color.fromRGBO(218, 214, 211, 1), // Color.fromRGBO(218, 200, 182, 1), // Color.fromRGBO(182, 168, 165, 1), // Color.fromRGBO(214, 193, 165, 1), // Color.fromRGBO(183, 205, 164, 1), // Color.fromRGBO(159, 198, 127, 1), // Color.fromRGBO(143, 165, 124, 1), // Color.fromRGBO(126, 165, 147, 1), // Color.fromRGBO(124, 188, 49, 1), // Color.fromRGBO(148, 245, 183, 1), // Color.fromRGBO(110, 145, 80, 1), // Color.fromRGBO(115, 137, 78, 1), // Color.fromRGBO(122, 138, 3, 1), // Color.fromRGBO(209, 182, 73, 1), // Color.fromRGBO(90, 138, 11, 1), // Color.fromRGBO(54, 167, 92, 1), // Color.fromRGBO(137, 224, 208, 1), // Color.fromRGBO(150, 166, 191, 1), // Color.fromRGBO(153, 168, 177, 1), // Color.fromRGBO(160, 174, 179, 1), // Color.fromRGBO(25, 200, 255, 1), // Color.fromRGBO(0, 234, 245, 1), // Color.fromRGBO(141, 7, 0, 1), // Color.fromRGBO(104, 15, 28, 1), // Color.fromRGBO(237, 254, 243, 1), // Color.fromRGBO(22, 207, 152, 1), ================================================ FILE: lib/project/classes/custom_toast.dart ================================================ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:money_assistant_2608/project/classes/constants.dart'; import 'package:money_assistant_2608/project/localization/methods.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; class CustomToast extends StatelessWidget { final String message; CustomToast(this.message); @override Widget build(BuildContext context) { return Container( padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 12.h), decoration: BoxDecoration( boxShadow: [BoxShadow()], borderRadius: BorderRadius.circular(25.r), color: Color.fromRGBO(239, 247, 253, 1), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.check, color: blue3,), SizedBox( width: 12.w, ), Text(getTranslated(context, message) ?? message, style: TextStyle(fontWeight: FontWeight.w500), ), ], ), ); } } void customToast(BuildContext context, String message){ var fToast = FToast(); fToast.init(context); fToast.showToast( child: CustomToast(message), gravity: ToastGravity.TOP, toastDuration: Duration(seconds: 2), ); } ================================================ FILE: lib/project/classes/dropdown_box.dart ================================================ import 'dart:ui'; import 'package:provider/provider.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:money_assistant_2608/project/database_management/shared_preferences_services.dart'; import 'package:money_assistant_2608/project/localization/methods.dart'; import 'package:money_assistant_2608/project/provider.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'constants.dart'; class DropDownBox extends StatelessWidget { final bool forAnalysis; final String selectedDate; const DropDownBox(this.forAnalysis, this.selectedDate); @override Widget build(BuildContext context) { return DecoratedBox( decoration: ShapeDecoration( shadows: [BoxShadow()], color: blue2, shape: RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(15.r))), ), child: SizedBox( height: 35.h, child: Padding( padding: EdgeInsets.symmetric(horizontal: 10.w), child: DropdownButtonHideUnderline( child: DropdownButton( dropdownColor: blue2, value: selectedDate, elevation: 10, icon: Icon( Icons.arrow_drop_down_outlined, size: 28.sp, ), onChanged: (value) { if (this.forAnalysis) { context .read() .changeSelectedAnalysisDate( newSelectedDate: value.toString()); sharedPrefs.selectedDate = value.toString(); } else { context .read() .changeSelectedReportDate( newSelectedDate: value.toString()); } }, items: timeline .map((time) => DropdownMenuItem( value: time, child: Text( getTranslated(context, time)!, style: TextStyle( fontSize: 18.5.sp), textAlign: TextAlign.center, ), )) .toList(), ), ), ), ), ); } } ================================================ FILE: lib/project/classes/icons.dart ================================================ // //for select_icon // import 'package:eva_icons_flutter/eva_icons_flutter.dart'; // import 'package:flutter/material.dart'; // import 'package:flutter_boxicons/flutter_boxicons.dart'; // import 'package:font_awesome_flutter/font_awesome_flutter.dart'; // import 'package:icofont_flutter/icofont_flutter.dart'; // import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; // import 'package:outline_material_icons/outline_material_icons.dart'; // // import 'category_item.dart'; // import 'constants.dart'; // // // // [ // // categoryItem(Icons.business_center_rounded, ''), // // categoryItem(IcoFontIcons.moneyBag, ''), // // categoryItem(IcoFontIcons.searchJob, ''), // // categoryItem(IcoFontIcons.gift, ''), // // categoryItem(MdiIcons.cashPlus, ''), // // categoryItem(MdiIcons.food, ''), // // categoryItem(MdiIcons.foodDrumstick, ''), // // categoryItem(Icons.local_bar, ''), // // categoryItem(Icons.add_shopping_cart, ''), // // categoryItem(OMIcons.commute, ''), // // categoryItem(Icons.local_gas_station, ''), // // categoryItem(Icons.local_parking, ''), // // categoryItem(IcoFontIcons.toolsBag, ''), // // categoryItem(Icons.local_taxi_outlined, ''), // // categoryItem(IcoFontIcons.businessman, ''), // // categoryItem(IcoFontIcons.education, ''), // // categoryItem(Icons.business, ''), // // categoryItem(IcoFontIcons.bagAlt, ''), // // categoryItem(IcoFontIcons.shoppingCart, ''), // // categoryItem(Boxicons.bxs_t_shirt, ''), // // categoryItem(Boxicons.bxs_binoculars, ''), // // categoryItem(Boxicons.bxs_devices, ''), // // categoryItem(Icons.add_photo_alternate_outlined, ''), // // categoryItem(Icons.movie_filter, ''), // // categoryItem(IcoFontIcons.gameController, ''), // // categoryItem(Icons.library_music, ''), // // categoryItem(Icons.airplanemode_active, ''), // // categoryItem(MdiIcons.homeHeart, ''), // // categoryItem(MdiIcons.homeCurrencyUsd, ''), // // categoryItem(MdiIcons.tableChair, ''), // // categoryItem(MdiIcons.autoFix, ''), // // categoryItem(MdiIcons.dogService, ''), // // categoryItem(Icons.emoji_transportation, ''), // // categoryItem(IcoFontIcons.lightBulb, ''), // // categoryItem(IcoFontIcons.globe, ''), // // categoryItem(IcoFontIcons.stockMobile, ''), // // categoryItem(IcoFontIcons.waterDrop, ''), // // categoryItem(FontAwesomeIcons.handHoldingMedical, ''), // // categoryItem(MdiIcons.soccer, ''), // // categoryItem(MdiIcons.fileDocumentMultipleOutline, ''), // // categoryItem(MdiIcons.doctor, ''), // // categoryItem(MdiIcons.medicalBag, ''), // // categoryItem(Boxicons.bxs_donate_heart, ''), // // categoryItem(IcoFontIcons.gift, ''), // // categoryItem(IcoFontIcons.love, ''), // // categoryItem(IcoFontIcons.worried, ''), // // categoryItem(IcoFontIcons.usersSocial, ''), // // categoryItem(Icons.child_care, ''), // // categoryItem(MdiIcons.cashCheck, ''), // // categoryItem(MdiIcons.babyBottle, ''), // // categoryItem(MdiIcons.humanBabyChangingTable, ''), // // categoryItem(MdiIcons.bookCheck, ''), // // categoryItem(EvaIcons.options, ''), // // ]; ================================================ FILE: lib/project/classes/input_model.dart ================================================ import 'dart:ui'; class InputModel { int? id; String? type; double? amount; String? category; String? description; String? date; String? time; Color? color; InputModel( {this.id, this.type, this.amount, this.category, this.description, this.date, this.time, this.color}); Map toMap() { Map map = { 'id': id, 'type': type, 'amount': amount, 'category': category, 'description': description, 'date': date, 'time': time }; // use for updating - not necessary? if (id != null) { map['id'] = id; } return map; } static InputModel fromMap(Map map) { return InputModel( id: map['id'], type: map['type'], amount: map['amount'], category: map['category'], description: map['description'], date: map['date'], time: map['time'], ); } } ================================================ FILE: lib/project/classes/keyboard.dart ================================================ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:money_assistant_2608/project/classes/constants.dart'; import 'package:money_assistant_2608/project/localization/methods.dart'; import 'package:sliding_up_panel/sliding_up_panel.dart'; class CustomKeyboard extends StatelessWidget { CustomKeyboard( {required this.panelController, this.mainFocus, this.nextFocus, required this.onTextInput, required this.onBackspace, required this.page}); final PanelController panelController; final FocusNode? mainFocus; final FocusNode? nextFocus; final VoidCallback onBackspace; final ValueSetter onTextInput; final Widget page; List generatedKeys() { List keys = []; for (String i in [ '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '0', '' ]) { keys.add( TextKey( text: i, onTextInput: this.onTextInput, onBackspace: this.onBackspace, ), ); } return keys; } @override Widget build(BuildContext context) { return Container( color: white, child: Padding( padding: EdgeInsets.only(bottom: 25.h), child: Column(children: [ SizedBox( height: 52.h, child: Padding( padding: EdgeInsets.only(left: 5.w, right: 20.w), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ GestureDetector( onTap: () { panelController.close(); FocusScope.of(context).requestFocus(nextFocus); }, child: SizedBox( height: 35.h, width:60.w, child: Icon(Icons.keyboard_arrow_down, size: 25.sp, color: Colors.blueGrey), ), ), // GestureDetector( // onTap: () { // panelController.close(); // Navigator.push( // context, // MaterialPageRoute( // builder: (context) => this.page, // )); // }, // child: Text( // 'Choose Category', // style: TextStyle( // fontSize: 16.sp, // fontWeight: FontWeight.bold, // color: Colors.blueGrey), // ), // ), GestureDetector( onTap: () { panelController.close(); this.mainFocus!.unfocus(); }, child: Text( getTranslated(context, "Done")!, style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.bold, color: Colors.blue), ), ) ], ), ), ), Wrap( children: generatedKeys(), ), ])), ); } } class TextKey extends StatelessWidget { const TextKey({ required this.text, this.onBackspace, this.onTextInput, }); final VoidCallback? onBackspace; final String text; final ValueSetter? onTextInput; @override Widget build(BuildContext context) { return Container( color: white, width: 1.sw / 3, height: 55.h, child: Material( child: InkWell( onTap: () { this.text.isEmpty ? this.onBackspace?.call() : this.onTextInput?.call(this.text); }, child: Center( child: this.text.isEmpty ? Icon( Icons.backspace_outlined, color: red, ) : Text( this.text, style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), )), ), ), ); } } ================================================ FILE: lib/project/classes/lockscreen.dart ================================================ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_app_lock/flutter_app_lock.dart'; import 'package:flutter_screen_lock/configurations/input_button_config.dart'; import 'package:flutter_screen_lock/configurations/screen_lock_config.dart'; import 'package:flutter_screen_lock/configurations/secret_config.dart'; import 'package:flutter_screen_lock/configurations/secrets_config.dart'; import 'package:flutter_screen_lock/input_controller.dart'; import 'package:flutter_screen_lock/screen_lock.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:money_assistant_2608/project/database_management/shared_preferences_services.dart'; import 'package:money_assistant_2608/project/localization/methods.dart'; import 'package:provider/provider.dart'; import '../provider.dart'; import 'custom_toast.dart'; class MainLockScreen extends StatelessWidget { const MainLockScreen({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return ScreenLock( correctString: sharedPrefs.passcodeScreenLock, canCancel: false, didUnlocked: () => AppLock.of(context)!.didUnlock(), deleteButton: const Icon(Icons.close, color: Color.fromRGBO(89, 129, 163, 1)), title: Padding( padding: const EdgeInsets.only(bottom: 10), child: Text( getTranslated( context, 'Please Enter Passcode', ) ?? 'Please Enter Passcode', style: TextStyle( color: Color.fromRGBO(71, 131, 192, 1), fontWeight: FontWeight.w500, fontSize: 20), ), ), screenLockConfig: const ScreenLockConfig( backgroundColor: Color.fromRGBO(210, 234, 251, 1), ), secretsConfig: SecretsConfig( secretConfig: SecretConfig( borderColor: Color.fromRGBO(79, 94, 120, 1), enabledColor: Color.fromRGBO(89, 129, 163, 1), )), inputButtonConfig: InputButtonConfig( buttonStyle: OutlinedButton.styleFrom( backgroundColor: Color.fromRGBO(71, 131, 192, 1), // Color.fromRGBO(89, 129, 163, 1) ), ), ); } } class OtherLockScreen extends StatelessWidget { final BuildContext providerContext; const OtherLockScreen({required this.providerContext}); @override Widget build(BuildContext context) { final inputController = InputController(); print(getTranslated( context, 'Please Enter Passcode', )); return ScreenLock( correctString: '', title: Padding( padding: EdgeInsets.only(bottom: 10.h), child: Text( getTranslated( context, 'Please Enter Passcode', ) ?? 'Please Enter Passcode', style: TextStyle( color: Color.fromRGBO(71, 131, 192, 1), fontWeight: FontWeight.w500, fontSize: 20.sp), ), ), confirmTitle: Text( getTranslated( context, 'Please Re-enter Passcode', ) ?? 'Please Re-enter Passcode', style: TextStyle( color: Color.fromRGBO(71, 131, 192, 1), fontWeight: FontWeight.w500, fontSize: 20.sp), ), confirmation: true, inputController: inputController, deleteButton: const Icon(Icons.close, color: Color.fromRGBO(71, 131, 192, 1)), screenLockConfig: const ScreenLockConfig( backgroundColor: Color.fromRGBO(210, 234, 251, 1), ), secretsConfig: SecretsConfig( secretConfig: SecretConfig( borderColor: Color.fromRGBO(79, 94, 120, 1), enabledColor: Color.fromRGBO(89, 129, 163, 1), )), inputButtonConfig: InputButtonConfig( buttonStyle: OutlinedButton.styleFrom( backgroundColor: Color.fromRGBO(71, 131, 192, 1), // Color.fromRGBO(89, 129, 163, 1) ), ), didConfirmed: (passCode) { sharedPrefs.passcodeScreenLock = passCode; Navigator.pop(context); customToast(context,'Passcode has been enabled'); }, cancelButton: TextButton( onPressed: () { this.providerContext.read().onSwitch(); Navigator.pop(context); }, child: Text(getTranslated(context, 'Cancel') ?? 'Cancel', style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.w500, color: Color.fromRGBO(71, 131, 192, 1)))), // footer: TextButton( // onPressed: () => inputController.unsetConfirmed(), // child: Padding( // padding: EdgeInsets.only(top: 20.h), // child: Text( // getTranslated( // context, // 'Return', // ) ?? // 'Return', // style: TextStyle( // color: Color.fromRGBO(71, 131, 192, 1), // fontWeight: FontWeight.w500, // fontSize: 20.sp)), // ), // ), ); } } ================================================ FILE: lib/project/classes/saveOrSaveAndDeleteButtons.dart ================================================ import 'dart:io' show Platform; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:money_assistant_2608/project/classes/alert_dialog.dart'; import 'package:money_assistant_2608/project/database_management/shared_preferences_services.dart'; import 'package:money_assistant_2608/project/localization/methods.dart'; import 'package:money_assistant_2608/project/app_pages/input.dart'; import 'package:money_assistant_2608/project/provider.dart'; import 'package:provider/provider.dart'; import 'category_item.dart'; import 'constants.dart'; import 'custom_toast.dart'; class SaveButton extends StatefulWidget { final bool saveInput; final Function? saveCategoryFunc; final bool? saveFunction; const SaveButton(this.saveInput, this.saveCategoryFunc, this.saveFunction); @override _SaveButtonState createState() => _SaveButtonState(); } class _SaveButtonState extends State { @override Widget build(BuildContext context) { return Center( child: ElevatedButton.icon( onPressed: () { if (widget.saveInput) { saveInputFunc(context, widget.saveFunction!); } else { widget.saveCategoryFunc!(); } }, style: ElevatedButton.styleFrom( padding: EdgeInsets.symmetric(vertical: 10.h, horizontal: 20.w), primary: Color.fromRGBO(236, 158, 66, 1), onPrimary: white, onSurface: grey, elevation: 10, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(18.0.r), ), ), label: Text( getTranslated(context, 'Save')!, style: TextStyle(fontSize: 25.sp), ), icon: Icon( Icons.save, size: 25.sp, ), ), ); } } class SaveAndDeleteButton extends StatelessWidget { final bool saveAndDeleteInput; final Function? saveCategory; final String? parentExpenseItem, categoryName; final BuildContext? contextEx, contextExEdit, contextIn, contextInEdit; final GlobalKey? formKey; const SaveAndDeleteButton({ required this.saveAndDeleteInput, this.saveCategory, this.categoryName, this.parentExpenseItem, this.contextEx, this.contextExEdit, this.contextIn, this.contextInEdit, this.formKey, }); @override Widget build(BuildContext context) { return Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ ElevatedButton.icon( onPressed: () { if (this.saveAndDeleteInput) { deleteInputFunction( context, ); } else { deleteCategoryFunction( context: context, categoryName: this.categoryName!, parentExpenseItem: this.parentExpenseItem, contextEx: this.contextEx, contextExEdit: this.contextExEdit, contextIn: this.contextIn, contextInEdit: this.contextInEdit, ); } }, style: ElevatedButton.styleFrom( padding: EdgeInsets.symmetric(vertical: 10.h, horizontal: 20.w), primary: white, onPrimary: red, onSurface: grey, side: BorderSide( color: red, width: 2.h, ), elevation: 10, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(18.0.r), )), icon: Icon( Icons.delete, size: 25.sp, ), label: Text( getTranslated(context, 'Delete')!, style: TextStyle(fontSize: 25.sp), )), SaveButton(saveAndDeleteInput, this.saveCategory, false), ], ); } } Future deleteCategoryFunction( {required BuildContext context, required String categoryName, String? parentExpenseItem, BuildContext? contextEx, contextExEdit, contextIn, contextInEdit}) async { void onDeletion() { if (contextInEdit != null) { List incomeItems = sharedPrefs.getItems('income items'); incomeItems.removeWhere((item) => item.text == categoryName); sharedPrefs.saveItems('income items', incomeItems); Provider.of(contextInEdit, listen: false) .getIncomeItems(); if (contextIn != null) { Provider.of(contextIn, listen: false) .getIncomeItems(); } } else { if (parentExpenseItem == null) { sharedPrefs.removeItem(categoryName); var parentExpenseItemNames = sharedPrefs.parentExpenseItemNames; parentExpenseItemNames.removeWhere( (parentExpenseItemName) => categoryName == parentExpenseItemName); sharedPrefs.parentExpenseItemNames = parentExpenseItemNames; } else { List expenseItems = sharedPrefs.getItems(parentExpenseItem); expenseItems.removeWhere((item) => item.text == categoryName); sharedPrefs.saveItems(parentExpenseItem, expenseItems); } Provider.of(contextEx!, listen: false) .getAllExpenseItems(); Provider.of(contextExEdit!, listen: false) .getAllExpenseItems(); } Navigator.pop(context); customToast(context,'Category has been deleted'); } Platform.isIOS ? await iosDialog( context, 'Are you sure you want to delete this category?', 'Delete', onDeletion) : await androidDialog(context, 'Are you sure you want to delete this category?', 'Delete',onDeletion); } ================================================ FILE: lib/project/database_management/database.dart ================================================ // import 'package:cloud_firestore/cloud_firestore.dart'; // import 'package:firebase_auth/firebase_auth.dart'; // // class DatabaseService { // static final usersCollection = FirebaseFirestore.instance.collection("users"); // static final firebaseUser = FirebaseAuth.instance.currentUser; // // static final Future> userData = FirebaseFirestore // .instance // .collection("users") // .doc(FirebaseAuth.instance.currentUser.uid) // .get() // .then((data) => data.data()); // // Future setUserData( // String type, // double amount, // String category, // String description, // String actualDateTime, // String dateSelected, // String timeSelected, { // bool premiumAccount, // String name = 'null', // }) async { // print('save'); // return await usersCollection.doc(firebaseUser.uid).set({ // "name": name, // "premiumAccount": premiumAccount, // "transactionInfo": FieldValue.arrayUnion([ // { "type": type, // "amount": amount, // "category": category, // "description": description, // "dateSelected": dateSelected, // "timeSelected": timeSelected, // "actualDateTime": actualDateTime // } // ]) // }, SetOptions(merge: true)); // } // // Future updateUserData(String name, String type, int amount, // String category, String description, String date, String time) async { // return await usersCollection.doc(firebaseUser.uid).update({ // "type": type, // "name": name, // "amount": amount, // "category": category, // "description": description, // "date": date, // "time": time // }); // } // // Future deleteUserData() async { // return await usersCollection.doc(firebaseUser.uid).delete(); // } // } ================================================ FILE: lib/project/database_management/shared_preferences_services.dart ================================================ import 'dart:convert'; import 'dart:io'; import 'dart:ui'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_boxicons/flutter_boxicons.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; // ignore: import_of_legacy_library_into_null_safe import 'package:icofont_flutter/icofont_flutter.dart'; import 'package:intl/intl.dart'; // ignore: import_of_legacy_library_into_null_safe import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; import 'package:money_assistant_2608/project/classes/category_item.dart'; import 'package:money_assistant_2608/project/classes/constants.dart'; import 'package:money_assistant_2608/project/localization/methods.dart'; // ignore: import_of_legacy_library_into_null_safe import 'package:outline_material_icons/outline_material_icons.dart'; import 'package:shared_preferences/shared_preferences.dart'; final sharedPrefs = SharedPrefs(); // constants/strings.dart // const String appCurrency = 'app_currency'; late String currency; var incomeItems = sharedPrefs.getItems('income items'); class SharedPrefs { static SharedPreferences? _sharedPrefs; sharePrefsInit() async { if (_sharedPrefs == null) { _sharedPrefs = await SharedPreferences.getInstance(); } } String get selectedDate => _sharedPrefs!.getString('selectedDate')!; set selectedDate(String value) { _sharedPrefs!.setString('selectedDate', value); } String get appCurrency => _sharedPrefs!.getString('appCurrency') ?? Platform.localeName; set appCurrency(String appCurrency) => _sharedPrefs!.setString('appCurrency', appCurrency); String get dateFormat => _sharedPrefs!.getString('dateFormat') ?? 'dd/MM/yyyy'; set dateFormat(String dateFormat) => _sharedPrefs!.setString('dateFormat', dateFormat); bool get isPasscodeOn => _sharedPrefs!.getBool('isPasscodeOn') ?? false; set isPasscodeOn(bool value) => _sharedPrefs!.setBool('isPasscodeOn', value); String get passcodeScreenLock => _sharedPrefs!.getString('passcodeScreenLock')!; set passcodeScreenLock(String value) => _sharedPrefs!.setString('passcodeScreenLock', value); List get parentExpenseItemNames => _sharedPrefs!.getStringList('parent expense item names')!; // not yet use this set method set parentExpenseItemNames(List parentExpenseItemNames) => _sharedPrefs! .setStringList('parent expense item names', parentExpenseItemNames); Locale setLocale(String languageCode) { _sharedPrefs!.setString('languageCode', languageCode); return locale(languageCode); } Locale getLocale() { String languageCode = _sharedPrefs!.getString('languageCode') ?? "en"; return locale(languageCode); } void getCurrency() { if (_sharedPrefs!.containsKey('appCurrency')) { var format = NumberFormat.simpleCurrency(locale: sharedPrefs.appCurrency); currency = format.currencySymbol; } else { var format = NumberFormat.simpleCurrency(locale: Platform.localeName); currency = format.currencySymbol; } } //jsonEncode turns a Map into a json string, //jsonDecode turns a json string into a Map List getItems(String parentItemName) { List itemsEncoded = _sharedPrefs!.getStringList(parentItemName)!; List items = itemsEncoded .map((item) => CategoryItem.fromJson(jsonDecode(item))) .toList(); return items; } void saveItems(String parentItemName, List items) { List itemsEncoded = items.map((item) => jsonEncode(item.toJson())).toList(); _sharedPrefs!.setStringList(parentItemName, itemsEncoded); } List> getAllExpenseItemsLists() { List> expenseItemsLists = []; for (int i = 0; i < this.parentExpenseItemNames.length; i++) { var parentExpenseItem = sharedPrefs.getItems(this.parentExpenseItemNames[i]); expenseItemsLists.add(parentExpenseItem); } return expenseItemsLists; } void removeItem(String itemName) { _sharedPrefs!.remove(itemName); } void setItems({required bool setCategoriesToDefault}) { // _sharedPrefs!.clear(); if (!_sharedPrefs!.containsKey('parent expense item names') || setCategoriesToDefault) { _sharedPrefs!.setStringList('parent expense item names', [ 'Food & Beverages', 'Transport', 'Personal Development', 'Shopping', 'Entertainment', 'Home', 'Utility Bills', 'Health', 'Gifts & Donations', 'Kids', 'OtherExpense' ]); saveItems('income items', [ categoryItem(MdiIcons.accountCash, 'Salary'), categoryItem(Icons.business_center_rounded, 'InvestmentIncome'), categoryItem(IcoFontIcons.moneyBag, 'Bonus'), categoryItem(IcoFontIcons.searchJob, 'Side job'), categoryItem(IcoFontIcons.gift, 'GiftsIncome'), categoryItem(MdiIcons.cashPlus, 'OtherIncome'), ]); saveItems('Food & Beverages', [ categoryItem(MdiIcons.food, 'Food & Beverages'), categoryItem(MdiIcons.foodDrumstick, 'Food'), categoryItem(Icons.local_bar, 'Beverages'), categoryItem(Icons.add_shopping_cart, 'Daily Necessities'), ]); saveItems('Transport', [ categoryItem(OMIcons.commute, 'Transport'), categoryItem(Icons.local_gas_station, 'Fuel'), categoryItem(Icons.local_parking, 'Parking'), categoryItem(IcoFontIcons.toolsBag, 'Services & Maintenance'), categoryItem(Icons.local_taxi_outlined, 'Taxi'), ]); saveItems('Personal Development', [ categoryItem(IcoFontIcons.businessman, 'Personal Development'), categoryItem(Icons.business, 'Business'), categoryItem(IcoFontIcons.education, 'Education'), categoryItem(IcoFontIcons.bagAlt, 'InvestmentExpense'), ]); saveItems('Shopping', [ categoryItem(IcoFontIcons.shoppingCart, 'Shopping'), categoryItem(Boxicons.bxs_t_shirt, 'Clothes'), categoryItem(Boxicons.bxs_binoculars, 'Accessories'), categoryItem(Boxicons.bxs_devices, 'Electronic Devices'), ]); saveItems('Entertainment', [ categoryItem(Icons.add_photo_alternate_outlined, 'Entertainment'), categoryItem(Icons.movie_filter, 'Movies'), categoryItem(IcoFontIcons.gameController, 'Games'), categoryItem(Icons.library_music, 'Music'), categoryItem(Icons.airplanemode_active, 'Travel'), ]); saveItems('Home', [ categoryItem(MdiIcons.homeHeart, 'Home'), categoryItem(MdiIcons.dogService, 'Pets'), categoryItem(MdiIcons.tableChair, 'Furnishings'), categoryItem(MdiIcons.autoFix, 'Home Services'), categoryItem(MdiIcons.homeCurrencyUsd, 'Mortgage & Rent'), ]); saveItems('Utility Bills', [ categoryItem(FontAwesomeIcons.fileInvoiceDollar, 'Utility Bills'), categoryItem(IcoFontIcons.lightBulb, 'Electricity'), categoryItem(IcoFontIcons.globe, 'Internet'), categoryItem(IcoFontIcons.stockMobile, 'Mobile Phone'), categoryItem(IcoFontIcons.waterDrop, 'Water'), ]); saveItems('Health', [ categoryItem(FontAwesomeIcons.handHoldingMedical, 'Health'), categoryItem(MdiIcons.soccer, 'Sports'), categoryItem(MdiIcons.fileDocumentMultipleOutline, 'Health Insurance'), categoryItem(MdiIcons.doctor, 'Doctor'), categoryItem(MdiIcons.medicalBag, 'Medicine'), ]); saveItems('Gifts & Donations', [ categoryItem(Boxicons.bxs_donate_heart, 'Gifts & Donations'), categoryItem(IcoFontIcons.gift, 'GiftsExpense'), categoryItem(IcoFontIcons.love, 'Wedding'), categoryItem(IcoFontIcons.worried, 'Funeral'), categoryItem(IcoFontIcons.usersSocial, 'Charity'), ]); saveItems('Kids', [ categoryItem(Icons.child_care, 'Kids'), categoryItem(MdiIcons.cashCheck, 'Pocket Money'), categoryItem(MdiIcons.babyBottle, 'Baby Products'), categoryItem(MdiIcons.humanBabyChangingTable, 'Babysitter & Daycare'), categoryItem(MdiIcons.bookCheck, 'Tuition'), ]); saveItems('OtherExpense', [ categoryItem(MdiIcons.cashPlus, 'OtherExpense'), ]); if (!setCategoriesToDefault) { _sharedPrefs!.setString('selectedDate', 'Today'); _sharedPrefs!.setBool('isPasscodeOn', false); _sharedPrefs!.setString('passcodeScreenLock', ''); _sharedPrefs!.setString('dateFormat', 'dd/MM/yyyy'); } } if (_sharedPrefs!.containsKey('parent expense item names') == false) { print('didnt save successfully'); } } } ================================================ FILE: lib/project/database_management/sqflite_services.dart ================================================ import 'dart:async'; import 'package:path/path.dart' as p; import 'package:sqflite/sqflite.dart'; import '../classes/input_model.dart'; abstract class DB { static Database? _db; static int get _version => 1; static Future init() async { if (_db != null) { return; } try { var databasesPath = await getDatabasesPath(); String _path = p.join(databasesPath, 'money_crud.db'); _db = await openDatabase(_path, version: _version, onCreate: onCreate); } catch (ex) { print(ex); } } static onCreate(Database db, int version) { return db.execute( 'CREATE TABLE input (id INTEGER PRIMARY KEY AUTOINCREMENT, type TEXT, amount REAL, category TEXT, description TEXT, date TEXT, time TEXT)'); } //why in Git uses Future? // static Future>> query() async => // await _db.query('input'); static Future> inputModelList() async { List> inputList = await _db!.query('input'); return inputList.map((item) => InputModel.fromMap(item)).toList(); } static Future insert(InputModel model) async => await _db!.insert( 'input', model.toMap(), conflictAlgorithm: ConflictAlgorithm.replace, ); static Future update(InputModel model) async => await _db!.update( 'input', model.toMap(), where: 'id = ?', whereArgs: [model.id], ); static Future delete(int id) async => await _db!.delete('input', where: 'id = ?', whereArgs: [id]); static Future deleteAll () async => await _db!.delete('input'); } ================================================ FILE: lib/project/draft1.dart ================================================ // import 'dart:collection'; // // import 'package:flutter/cupertino.dart'; // import 'package:flutter/material.dart'; // import 'package:flutter_screenutil/flutter_screenutil.dart'; // import 'package:google_fonts/google_fonts.dart'; // import 'package:intl/intl.dart'; // import 'package:money_assistant_2608/project/classes/app_bar.dart'; // import 'package:money_assistant_2608/project/classes/category_item.dart'; // import 'package:money_assistant_2608/project/classes/constants.dart'; // import 'package:money_assistant_2608/project/classes/input_model.dart'; // import 'package:money_assistant_2608/project/database_management/shared_preferences_services.dart'; // import 'package:money_assistant_2608/project/database_management/sqflite_services.dart'; // import 'package:money_assistant_2608/project/localization/methods.dart'; // import 'package:table_calendar/table_calendar.dart'; // // import '../classes/input_model.dart'; // import 'edit.dart'; // // class Calendar extends StatelessWidget { // @override // Widget build(BuildContext context) { // return Scaffold( // backgroundColor: blue1, // appBar: BasicAppBar(getTranslated(context, 'Calendar')!), // body: CalendarBody()); // } // } // // class CalendarBody extends StatefulWidget { // @override // _CalendarBodyState createState() => _CalendarBodyState(); // } // // class _CalendarBodyState extends State { // CalendarFormat _calendarFormat = CalendarFormat.month; // RangeSelectionMode _rangeSelectionMode = RangeSelectionMode // .toggledOff; // Can be toggled on/off by longpressing a date // DateTime _focusedDay = DateTime.now(), // today = DateTime( // DateTime.now().year, DateTime.now().month, DateTime.now().day); // DateTime? _selectedDay, _rangeStart, _rangeEnd; // late Map> transactions = {}; // late ValueNotifier> _selectedEvents; // // @override // void initState() { // super.initState(); // _selectedDay = _focusedDay; // } // // @override // void dispose() { // // _calendarController.dispose(); // super.dispose(); // } // // int getHashCode(DateTime key) { // return key.day * 1000000 + key.month * 10000 + key.year; // } // // /// Returns a list of [DateTime] objects from [first] to [last], inclusive. // List daysInRange(DateTime first, DateTime last) { // final dayCount = last.difference(first).inDays + 1; // return List.generate( // dayCount, // (index) => DateTime.utc(first.year, first.month, first.day + index), // ); // } // // Widget buildEvents(List? transactions) { // Color colorCategory; // if (transactions == null) { // return Container(); // } // List itemList = createItemList( // transactions: transactions, // forAnalysisPage: false, // forSelectIconPage: false, // isIncomeType: false, // ); // return ListView.builder( // shrinkWrap: true, // itemCount: itemList.length, // itemBuilder: (context, int) { // colorCategory = // transactions[int].type == 'Income' ? Colors.lightGreen : red; // return GestureDetector( // onTap: () { // Navigator.push( // context, // MaterialPageRoute( // builder: (context) => Edit( // inputModel: transactions[int], // categoryIcon: iconData(itemList[int]), // ))).then((value) => setState(() {})); // }, // child: Column( // children: [ // Container( // color: white, // child: Padding( // padding: EdgeInsets.symmetric( // horizontal: 15.w, vertical: 15.h), // child: Row( // mainAxisAlignment: MainAxisAlignment.spaceBetween, // children: [ // Icon( // iconData(itemList[int]), // color: colorCategory, // ), // SizedBox( // width: 150.w, // child: Padding( // padding: EdgeInsets.only(left: 15.w, right: 10.w), // child: Text( // getTranslated(context, itemList[int].text) ?? // itemList[int].text, // style: TextStyle( // fontSize: 18.sp, // ), // overflow: TextOverflow.ellipsis), // ), // ), // Expanded( // child: Text('(${transactions[int].description})', // style: TextStyle( // fontSize: 14.sp, // fontStyle: FontStyle.italic), // overflow: TextOverflow.fade), // ), // //this widget will never overflow // Flexible( // flex: 0, // child: Padding( // padding: EdgeInsets.only(right: 10.w, left: 7.w), // child: Text( // format(transactions[int].amount!) + // ' ' + // currency, // style: GoogleFonts.aBeeZee( // fontSize: format(transactions[int].amount!) // .length > // 15 // ? 16.sp // : 17.sp, // ), // overflow: TextOverflow.ellipsis), // ), // ), // Icon( // Icons.arrow_forward_ios, // size: 15.5.sp, // ), // ], // ), // ), // ), // Divider( // height: 0, // thickness: 0.25.h, // indent: 20.w, // color: grey, // // color: Color.fromRGBO(213, 215, 217, 1), // ), // ], // )); // }); // } // // @override // Widget build(BuildContext context) { // return FutureBuilder>( // initialData: [], // future: DB.inputModelList(), // builder: (context, snapshot) { // connectionUI(snapshot); // Map> map = {}; // if (snapshot.data != null) { // for (int i = 0; i < snapshot.data!.length; i++) { // String description = snapshot.data![i].description!; // InputModel map1 = InputModel( // id: snapshot.data![i].id, // type: snapshot.data![i].type, // amount: snapshot.data![i].amount, // category: snapshot.data![i].category, // description: description, // date: snapshot.data![i].date, // time: snapshot.data![i].time); // // void updateMapValue(Map> map, K key, V value) => // map.update(key, (list) => list..add(value), // ifAbsent: () => [value]); // // updateMapValue( // map, // '${snapshot.data![i].date}', // map1, // ); // } // transactions = map.map((key, value) => // MapEntry(DateFormat('dd/MM/yyyy').parse(key), value)); // } // // late LinkedHashMap linkedHashedMapTransactions = // LinkedHashMap>( // equals: isSameDay, // hashCode: getHashCode, // )..addAll(transactions); // // List transactionsForDay(DateTime? day) => // linkedHashedMapTransactions[day] ?? []; // // if (_selectedDay != null) { // _selectedEvents = ValueNotifier(transactionsForDay(_selectedDay)); // } // // List _getEventsForRange(DateTime start, DateTime end) { // final days = daysInRange(start, end); // // return [ // for (final d in days) ...transactionsForDay(d), // ]; // } // // void _onDaySelected(DateTime selectedDay, DateTime focusedDay) { // if (!isSameDay(_selectedDay, selectedDay)) { // setState(() { // _selectedDay = selectedDay; // _focusedDay = focusedDay; // _rangeStart = null; // Important to clean those // _rangeEnd = null; // _rangeSelectionMode = RangeSelectionMode.toggledOff; // }); // _selectedEvents.value = transactionsForDay(selectedDay); // } // } // // void _onRangeSelected( // DateTime? start, DateTime? end, DateTime focusedDay) { // setState(() { // _selectedDay = null; // _focusedDay = focusedDay; // _rangeStart = start; // _rangeEnd = end; // _rangeSelectionMode = RangeSelectionMode.toggledOn; // if (start != null && end != null) { // _selectedEvents = ValueNotifier(_getEventsForRange(start, end)); // } else if (start != null) { // _selectedEvents = ValueNotifier(transactionsForDay(start)); // } else if (end != null) { // _selectedEvents = ValueNotifier(transactionsForDay(end)); // } // }); // } // // return Column(children: [ // TableCalendar( // availableCalendarFormats: { // CalendarFormat.month: getTranslated(context, 'Month')!, // CalendarFormat.twoWeeks: getTranslated(context, '2 weeks')!, // CalendarFormat.week: getTranslated(context, 'Week')! // }, // locale: Localizations.localeOf(context).languageCode, // // sixWeekMonthsEnforced: true, // // shouldFillViewport: true, // rowHeight: 52.h, // daysOfWeekHeight: 22.h, // firstDay: DateTime.utc(2000, 01, 01), // lastDay: DateTime.utc(2050, 01, 01), // focusedDay: _focusedDay, // calendarFormat: _calendarFormat, // selectedDayPredicate: (day) => isSameDay(_selectedDay, day), // rangeStartDay: _rangeStart, // rangeEndDay: _rangeEnd, // rangeSelectionMode: _rangeSelectionMode, // eventLoader: transactionsForDay, // startingDayOfWeek: StartingDayOfWeek.monday, // calendarStyle: CalendarStyle( // // weekendTextStyle: // // TextStyle().copyWith(color: Colors.blue[800]), // ), // // headerStyle: HeaderStyle( // formatButtonTextStyle: TextStyle(fontSize: 18.sp), // formatButtonDecoration: BoxDecoration( // boxShadow: [BoxShadow()], // color: blue2, // borderRadius: BorderRadius.circular(25.r)), // ), // calendarBuilders: CalendarBuilders( // selectedBuilder: (context, date, _) { // return Container( // //see difference between margin and padding below: Margin: Out (for itself), padding: In (for its child) // // margin: EdgeInsets.all(4.0.w), // padding: EdgeInsets.only(top: 6.0.h, left: 6.0.w), // color: Color.fromRGBO(255, 168, 68, 1), // width: 46.w, // height: 46.h, // child: Text( // '${date.day}', // style: TextStyle().copyWith(fontSize: 17.0.sp), // ), // ); // }, // todayBuilder: (context, date, _) { // return Container( // padding: EdgeInsets.only(top: 6.0.w, left: 6.0.w), // color: blue2, // width: 46.w, // height: 46.h, // child: Text( // '${date.day}', // style: TextStyle().copyWith(fontSize: 17.0.sp), // ), // ); // }, // markerBuilder: (context, date, events) { // if (events.isNotEmpty) { // return Positioned( // right: 1.w, // bottom: 1.h, // child: _buildEventsMarker(date, events), // ); // } // }, // ), // // onDaySelected: _onDaySelected, // onRangeSelected: _onRangeSelected, // onFormatChanged: (format) { // if (_calendarFormat != format) { // setState(() { // _calendarFormat = format; // }); // } // }, // onPageChanged: (focusedDay) { // _focusedDay = focusedDay; // }, // pageJumpingEnabled: true, // ), // SizedBox(height: 8.0.h), // Expanded( // child: ValueListenableBuilder>( // valueListenable: _selectedEvents, // builder: (context, value, _) { // return Column(children: [ // Balance(value), // Expanded(child: buildEvents(value)) // ]); // }, // ), // ) // ]); // }); // } // } // // Widget _buildEventsMarker(DateTime date, List events) { // double width = events.length < 100 ? 18.w : 28.w; // return AnimatedContainer( // duration: const Duration(milliseconds: 300), // decoration: BoxDecoration( // shape: BoxShape.rectangle, // color: Color.fromRGBO(67, 125, 229, 1), // ), // width: width, // height: 18.0.h, // child: Center( // child: Text( // '${events.length}', // style: TextStyle().copyWith( // color: white, // fontSize: 13.0.sp, // ), // ), // ), // ); // } // // class Balance extends StatefulWidget { // final List? events; // Balance(this.events); // @override // _BalanceState createState() => _BalanceState(); // } // // class _BalanceState extends State { // @override // Widget build(BuildContext context) { // double income = 0, expense = 0, balance = 0; // if (widget.events != null) { // for (int i = 0; i < widget.events!.length; i++) { // if (widget.events![i].type == 'Income') { // income = income + widget.events![i].amount; // } else { // expense = expense + widget.events![i].amount; // } // balance = income - expense; // } // } // Widget summaryFrame(String type, double amount, color) => Column( // mainAxisAlignment: MainAxisAlignment.spaceBetween, // crossAxisAlignment: CrossAxisAlignment.center, // children: [ // // this widget will never overflow // Text( // getTranslated(context, type)!, // style: TextStyle( // color: color, // fontSize: 15.sp, // fontStyle: FontStyle.italic, // fontWeight: FontWeight.bold), // ), // Text(format(amount.toDouble()) + ' ' + currency, // style: GoogleFonts.aBeeZee( // color: color, // fontSize: (format(amount.toDouble()).length > 19) // ? 11.5.sp // : format(amount.toDouble()).length > 14 // ? 14.sp // : 18.sp, // fontStyle: FontStyle.italic, // fontWeight: FontWeight.bold), // overflow: TextOverflow.ellipsis) // ], // ); // return Container( // color: Colors.white54, // height: 69.h, // child: Padding( // padding: EdgeInsets.symmetric(horizontal: 15.w, vertical: 10.h), // child: Row( // mainAxisAlignment: MainAxisAlignment.spaceBetween, // children: [ // summaryFrame( // 'INCOME', // income, // Colors.lightGreen, // ), // Padding( // padding: EdgeInsets.symmetric(horizontal: 5.w), // child: summaryFrame('EXPENSE', expense, red)), // Flexible( // child: summaryFrame('TOTAL BALANCE', balance, Colors.black)), // ], // ), // ), // ); // } // } ================================================ FILE: lib/project/home.dart ================================================ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/painting.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:money_assistant_2608/project/classes/constants.dart'; import 'package:money_assistant_2608/project/database_management/sqflite_services.dart'; import 'package:rate_my_app/rate_my_app.dart'; import 'dart:io' show Platform; import 'app_pages/analysis.dart'; import 'app_pages/input.dart'; import 'localization/methods.dart'; import 'app_pages/calendar.dart'; import 'app_pages/others.dart'; class Home extends StatefulWidget { @override _HomeState createState() => _HomeState(); } class _HomeState extends State { int _selectedIndex = 0; List myBody = [ AddInput(), Analysis(), Calendar(), Other(), ]; BottomNavigationBarItem bottomNavigationBarItem( IconData iconData, String label) => BottomNavigationBarItem( icon: Padding( padding: EdgeInsets.only(bottom: 0.h), child: Icon( iconData, ), ), label: getTranslated(context, label), ); @override void initState() { super.initState(); DB.init(); var rateMyApp = RateMyApp( minDays: 0, // Will pop up the first time users launch the app minLaunches: 1, remindDays: 4, remindLaunches: 15, googlePlayIdentifier: 'com.mmas.money_assistant_2608', appStoreIdentifier: '1582638369', ); WidgetsBinding.instance?.addPostFrameCallback((_) async { await rateMyApp.init(); rateMyApp.conditions.forEach((condition) { if (condition is DebuggableCondition) { print(condition.valuesAsString); // condition.reset(); } }); if (mounted && rateMyApp.shouldOpenDialog) { rateMyApp.showRateDialog( context, // title: 'Rate this app', // The dialog title. // message: // 'If you like this app, please take a little bit of your time to review it!\nYour support means the world to us ^^', // The dialog message. // rateButton: 'RATE', // The dialog "rate" button text. // noButton: 'NO THANKS', // The dialog "no" button text. // laterButton: 'MAYBE LATER', // The dialog "later" button text. // listener: (button) { // // The button click listener (useful if you want to cancel the click event). // switch (button) { // case RateMyAppDialogButton.rate: // print('Clicked on "Rate".'); // break; // case RateMyAppDialogButton.later: // print('Clicked on "Later".'); // break; // case RateMyAppDialogButton.no: // print('Clicked on "No".'); // break; // } // return true; // Return false if you want to cancel the click event. // }, ignoreNativeDialog: Platform .isAndroid, // Set to false if you want to show the Apple's native app rating dialog on iOS or Google's native app rating dialog (depends on the current Platform). onDismissed: () => rateMyApp.callEvent(RateMyAppEventType .laterButtonPressed), // Called when the user dismissed the dialog (either by taping outside or by pressing the "back" button). // contentBuilder: (context, defaultContent) => Text('ok'), // This one allows you to change the default dialog content. // actionsBuilder: (context) => [], // This one allows you to use your own buttons. ); } }); } @override Widget build(BuildContext context) { List bottomItems = [ bottomNavigationBarItem(Icons.add, 'Input'), bottomNavigationBarItem(Icons.analytics_outlined, 'Analysis'), bottomNavigationBarItem(Icons.calendar_today, 'Calendar'), bottomNavigationBarItem(Icons.account_circle, 'Other'), ]; return Scaffold( bottomNavigationBar: Container( decoration: BoxDecoration( boxShadow: [ BoxShadow( color: grey, ), ], ), child: BottomNavigationBar( iconSize: 27.sp, selectedFontSize: 16.sp, unselectedFontSize: 14.sp, backgroundColor: white, selectedItemColor: Colors.amber[800], unselectedItemColor: Colors.black87, type: BottomNavigationBarType.fixed, items: bottomItems, currentIndex: _selectedIndex, onTap: (int index) { setState(() { _selectedIndex = index; }); }, ), ), body: myBody[_selectedIndex]); } } ================================================ FILE: lib/project/localization/app_localization.dart ================================================ import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; class AppLocalization { final Locale locale; AppLocalization(this.locale); late Map _localizedMap; static AppLocalization? of(BuildContext context) { return Localizations.of(context, AppLocalization); } Future load() async { String jsonStringValues = await rootBundle.loadString( 'lib/project/localization/lang/${locale.languageCode}.json'); Map mappedJson = json.decode(jsonStringValues); _localizedMap = mappedJson.map((key, value) => MapEntry(key, value.toString())); } String? translate(String key) { return _localizedMap[key]; } Map localizedMap() => _localizedMap; // static member to have simple access to the delegate from Material App static const LocalizationsDelegate delegate = _DemoLocalizationsDelegate(); } class _DemoLocalizationsDelegate extends LocalizationsDelegate { const _DemoLocalizationsDelegate(); @override bool isSupported(Locale locale) { return [ 'en', // 'ar', 'de', 'es', 'fr', 'hi', 'ja', 'ko', 'pt', 'ru', 'tr', 'vi', 'zh', 'ne' ].contains(locale.languageCode); } @override Future load(Locale locale) async { AppLocalization localization = new AppLocalization(locale); await localization.load(); return localization; } @override bool shouldReload(LocalizationsDelegate old) => false; } ================================================ FILE: lib/project/localization/lang/ar.json ================================================ { "Input": "", "Analysis": "", "Calendar": "", "Other": "", "OtherIncome": "", "OtherExpense": "", "INCOME": "", "EXPENSE": "", "Amount": "", "Description": "", "Save": "", "Edit Category": "", "Enter Category Name": "", "Transport": "", "Fuel": "", "Parking": "", "Services & Maintenance": "", "Taxi": "", "Shopping": "", "Accessories": "", "Electronic Devices": "", "Clothes": "", "Footwear": "", "Entertainment": "", "Movies": "", "Games": "", "Music": "", "Travel": "", "Food & Beverages": "", "Beverages": "", "Food": "", "Daily Necessities": "", "Groceries": "", "Restaurant": "", "Gifts & Donations": "", "Charity": "", "GiftsExpense": "", "Funeral": "", "Wedding": "", "Health": "", "Doctor": "", "Health Insurance": "", "Medicine": "", "Sports": "", "Home": "", "Furnishings": "", "Home Services": "", "Pets": "", "Mortgage & Rent": "", "Kids": "", "Pocket Money": "", "Baby Products": "", "Babysitter & Daycare": "", "Tuition": "", "Personal Development": "", "Education": "", "Business": "", "InvestmentExpense": "", "Utility Bills": "", "Electricity": "", "Internet": "", "Mobile Phone": "", "Water": "", "Salary": "", "Bonus": "", "Side job": "", "GiftsIncome": "", "InvestmentIncome": "", "Income": "", "Expense": "", "Balance": "", "Today": "", "This week": "", "This month": "", "This year": "", "This quarter": "", "Category": "", "TOTAL BALANCE": "", "Nguyen Hoa": "Nguyen Hoa", "VIEW UPGRADE OPTIONS":"", "My Account": "", "General Settings": "", "Language": "", "Currency": "", "Share Friends": "", "Rate App": "", "Feedback": "", "Add Expense Category": "", "Add Income Category": "", "Category name": "", "Parent category": "", "Add": "", "Game": "", "Edit": "", "Select a date": "", "CANCEL": "", "OK": "", "There is no data": "", "Select a language": "", "Please fill a category name": "", "Delete": "", "Total Year Amount": "", "Report": "", "Hi you": "", "All": "", "Category already exists": "", "Month": "", "2 weeks": "", "Week": "", "Since": "", "Data has been saved": "", "Choose Category": "", "Done": "", "Icons": "", "Please Confirm": "", "Yes": "", "No": "", "Cancel": "", "This action cannot be undone. Are you sure you want to reset all categories?": "", "Reset": "", "Reset All Categories": "", "Categories have been reset": "", "Enable Passcode": "", "Please Enter Passcode": "", "Please Re-enter Passcode": "", "Passcode has been disabled": "", "Passcode has been enabled": "", "Category has been deleted": "", "Are you sure you want to delete this category?": "", "Delete All Data": "", "All data has been deleted": "", "Deleted data can not be recovered. Are you sure you want to delete all data?": "", "Select a currency": "", "Category has been updated": "", "Are you sure you want to delete this transaction?": "", "Transaction has been deleted": "", "Transaction has been updated": "", "Select a date format": "", "Date format": "", "Date format has been updated": "" } ================================================ FILE: lib/project/localization/lang/de.json ================================================ { "Input": "Eingang", "Analysis": "Analyse", "Calendar": "Kalender", "Other": "Andere", "OtherIncome": "Andere", "OtherExpense": "Andere", "INCOME": "EINKOMMEN", "EXPENSE": "AUSGABEN", "Amount": "Betrag", "Description": "Beschreibung", "Save": "Sparen", "Edit Category": "Kategorie bearbeiten", "Enter Category Name": "Geben Sie den Kategoriennamen ein", "Transport": "Transport", "Fuel": "Treibstoff", "Parking": "Parken", "Services & Maintenance": "Service & Wartung", "Taxi": "Taxi", "Shopping": "Einkaufen", "Accessories": "Zubehör", "Electronic Devices": "Elektronik", "Clothes": "Kleider", "Footwear": "Schuhwerk", "Entertainment": "Unterhaltung", "Movies": "Filme", "Games": "Spiele", "Music": "Musik", "Travel": "Reise", "Food & Beverages": "Essen & Trinken", "Beverages": "Getränke", "Food": "Essen", "Daily Necessities": "Täglicher Bedarf", "Groceries": "Täglicher Bedarf", "Restaurant": "Restaurant", "Gifts & Donations": "Geschenke & Spenden", "Charity": "Nächstenliebe", "GiftsExpense": "Geschenke", "Funeral": "Beerdigung", "Wedding": "Hochzeit", "Health": "Gesundheit", "Doctor": "Arzt", "Health Insurance": "Krankenkasse", "Medicine": "Medizin", "Sports": "Sport", "Home": "Zuhause", "Furnishings": "Einrichtung", "Home Services": "Heimdienste", "Pets": "Haustiere", "Mortgage & Rent": "Hypothek & Miete", "Kids": "Kinder", "Pocket Money": "Taschengeld", "Baby Products": "Baby-Produkte", "Babysitter & Daycare": "Babysitter", "Tuition": "Schulgeld", "Personal Development": "Personalentwicklung", "Education": "Bildung", "Business": "Geschäft", "InvestmentExpense": "Investition", "Utility Bills": "Rechnungen", "Electricity": "Elektrizität", "Internet": "Internet", "Mobile Phone": "Mobiltelefon", "Water": "Wasser", "Salary": "Gehalt", "Bonus": "Bonus", "Side job": "Nebenjob", "GiftsIncome": "Geschenke", "InvestmentIncome": "Investition", "Income": "Einkommen", "Expense": "Ausgaben", "Balance": "Gesamtsaldo", "Today": "Heute", "This week": "Diese Woche", "This month": "Diesen Monat", "This year": "Dieses Jahr", "This quarter": "Dieses Quartal", "Category": "Kategorie", "TOTAL BALANCE": "GESAMTSALDO", "Nguyen Hoa": "Nguyen Hoa", "VIEW UPGRADE OPTIONS": "UPGRADE-OPTIONEN ANZEIGEN", "My Account": "Mein Konto", "General Settings": "Allgemeine Einstellungen", "Language": "Sprache", "Currency": "Währung", "Share Friends": "Teilen Sie Freunde", "Rate App": "Bewertungs App", "Feedback": "Feedback", "Add Expense Category": "Ausgabenkategorie hinzufügen", "Add Income Category": "Einkommenskategorie hinzufügen", "Category name": "Kategorie-Name", "Parent category": "Übergeordnete Kategorie", "Add": "Hinzufügen", "Game": "Spiel", "Edit": "Bearbeiten", "Select a date": "Wählen Sie ein Datum", "CANCEL": "ABBRECHEN", "OK": "OK", "There is no data": "Es sind keine Daten vorhanden", "Select a language": "Wählen Sie eine Sprache", "Please fill a category name": "Bitte geben Sie einen Kategorienamen ein", "Delete": "Löschen", "Total Year Amount": "Gesamtjahresbetrag", "Report": "Bericht", "Hi you": "Hallo Du", "All": "Alle", "Category already exists": "Kategorie existiert bereits", "Month": "Monat", "2 weeks": "2 Wochen", "Week": "Woche", "Since": "Seit", "Data has been saved": "Die Daten wurden gespeichert", "Choose Category": "Kategorie wählen", "Done": "Erledigt", "Icons": "Icons", "Please Confirm": "Bestätigen Sie", "Yes": "Ja", "No": "Nein", "Cancel": "Abbrechen", "This action cannot be undone. Are you sure you want to reset all categories?": "Diese Aktion kann nicht rückgängig gemacht werden. Sind Sie sicher, dass Sie alle Kategorien zurücksetzen wollen?", "Reset": "Zurücksetzen", "Reset All Categories": "Alle Kategorien zurücksetzen", "Categories have been reset": "Die Kategorien wurden zurückgesetzt", "Enable Passcode": "Aktivieren Sie den Passcode", "Please Enter Passcode": "Bitte Passcode eingeben", "Please Re-enter Passcode": "Bitte geben Sie den Passcode erneut ein", "Passcode has been disabled": "Der Passcode wurde deaktiviert", "Passcode has been enabled": "Der Passcode wurde aktiviert", "Category has been deleted": "Kategorie wurde gelöscht", "Are you sure you want to delete this category?": "Sind Sie sicher, dass Sie diese Kategorie löschen möchten?", "Delete All Data": "Alle Daten löschen", "All data has been deleted": "Alle Daten wurden gelöscht", "Deleted data can not be recovered. Are you sure you want to delete all data?": "Gelöschte Daten können nicht wiederhergestellt werden. Sind Sie sicher, dass Sie alle Daten löschen möchten?", "Select a currency": "Wählen Sie eine Währung", "Category has been updated": "Die Kategorie wurde aktualisiert", "Are you sure you want to delete this transaction?": "Sind Sie sicher, dass Sie diese Transaktion löschen möchten?", "Transaction has been deleted": "Die Transaktion wurde gelöscht", "Transaction has been updated": "Die Transaktion wurde aktualisiert", "Select a date format": "Wählen Sie ein Datumsformat", "Date format": "Datumsformat", "Date format has been updated": "Datumsformat wurde aktualisiert" } ================================================ FILE: lib/project/localization/lang/en.json ================================================ { "Input": "Add", "Analysis": "Analysis", "Calendar": "Calendar", "Other": "Other", "OtherIncome": "Other", "OtherExpense": "Other", "INCOME": "INCOME", "EXPENSE": "EXPENSE", "Amount": "Amount", "Description": "Description", "Save": "Save", "Edit Category": "Edit Categories", "Enter Category Name": "Enter A Category Name", "Transport": "Transport", "Fuel": "Fuel", "Parking":"Parking", "Services & Maintenance": "Services & Maintenance", "Taxi": "Taxi", "Shopping": "Shopping", "Accessories": "Accessories", "Electronic Devices": "Electronic Devices", "Clothes": "Clothes", "Footwear": "Footwear", "Entertainment": "Entertainment", "Movies": "Movies", "Games": "Games", "Music": "Music", "Travel": "Travel", "Food & Beverages": "Food & Beverages", "Beverages": "Beverages", "Food": "Food", "Daily Necessities": "Groceries", "Groceries": "Groceries", "Restaurant": "Restaurant", "Gifts & Donations": "Gifts & Donations", "Charity": "Charity", "GiftsExpense": "Gifts", "Funeral": "Funeral", "Wedding": "Wedding", "Health": "Health", "Doctor": "Doctor", "Health Insurance": "Health Insurance", "Medicine": "Medicine", "Sports": "Sports", "Home": "Home", "Furnishings": "Furnishings", "Home Services": "Home Services", "Pets": "Pets", "Mortgage & Rent": "Mortgage & Rent", "Kids": "Kids", "Pocket Money": "Pocket Money", "Baby Products": "Baby Products", "Babysitter & Daycare": "Babysitter & Daycare", "Tuition":"Tuition", "Personal Development": "Personal Development", "Education": "Education", "Business": "Business", "InvestmentExpense": "Investment", "Utility Bills": "Utility Bills", "Electricity": "Electricity", "Internet": "Internet", "Mobile Phone": "Mobile Phone", "Water": "Water", "Salary": "Salary", "Bonus": "Bonus", "Side job": "Side job", "GiftsIncome": "Gifts", "InvestmentIncome": "Investment", "Income": "Income", "Expense": "Expense", "Balance": "Balance", "Today": "Today", "This week": "This week", "This month": "This month", "This year": "This year", "This quarter": "This quarter", "Category": "Category", "TOTAL BALANCE": "BALANCE", "Nguyen Hoa": "Nguyen Hoa", "VIEW UPGRADE OPTIONS": "VIEW UPGRADE OPTIONS", "My Account": "My Account", "General Settings": "Settings", "Language": "Language", "Currency": "Currency", "Share Friends": "Share Friends", "Rate App": "Rate App", "Feedback": "Feedback", "Add Expense Category": "Add An Expense Category", "Category name": "Category name", "Parent category": "Parent category", "Add": "Add", "Game": "Game", "Edit": "Edit", "Select a date": "Select a date", "CANCEL": "CANCEL", "OK": "OK", "There is no data": "There is no data", "Select a language": "Select a language", "Please fill a category name": "Please fill a category name", "Delete": "Delete", "Total Year Amount": "Total Year Amount", "Report": "Report", "Add Income Category": "Add Income Category", "Hi you": "Hi you", "All": "All", "Category already exists": "Category already exists", "Month": "Month", "2 weeks": "2 weeks", "Week": "Week", "Since": "Since", "Data has been saved": "Data has been saved", "Choose Category": "Choose Category", "Done": "Done", "Icons": "Icons", "Please Confirm": "Please Confirm", "Yes": "Yes", "No": "No", "Cancel": "Cancel", "This action cannot be undone. Are you sure you want to reset all categories?": "This action cannot be undone. Are you sure you want to reset all categories?", "Reset": "Reset", "Reset All Categories": "Reset All Categories", "Categories have been reset": "Categories have been reset", "Enable Passcode": "Enable Passcode", "Please Enter Passcode": "Please Enter Passcode", "Please Re-enter Passcode": "Please Re-enter passcode", "Passcode has been disabled": "Passcode has been disabled", "Passcode has been enabled": "Passcode has been enabled", "Category has been deleted": "Category has been deleted", "Are you sure you want to delete this category?": "Are you sure you want to delete this category?", "Delete All Data": "Delete All Data", "All data has been deleted": "All data has been deleted", "Deleted data can not be recovered. Are you sure you want to delete all data?": "Deleted data can not be recovered. Are you sure you want to delete all data?", "Select a currency": "Select a currency", "Category has been updated": "Category has been updated", "Are you sure you want to delete this transaction?": "Are you sure you want to delete this transaction?", "Transaction has been deleted": "Transaction has been deleted", "Transaction has been updated": "Transaction has been updated", "Select a date format": "Select a date format", "Date format": "Date format", "Date format has been updated": "Date format has been updated" } ================================================ FILE: lib/project/localization/lang/es.json ================================================ { "Input": "Aporte", "Analysis": "Análisis", "Calendar": "Calendario", "Other": "Otro", "OtherIncome": "Otro", "OtherExpense": "Otro", "INCOME": "INGRESO", "EXPENSE": "GASTOS", "Amount": "Cantidad", "Description": "Descripción", "Save": "Salvar", "Edit Category": "Editar categoria", "Enter Category Name": "Ingrese el nombre de la categoría", "Transport": "transporte", "Fuel": "Combustible", "Parking": "Parking", "Services & Maintenance": "Servicios", "Taxi": "Taxi", "Shopping": "Compras", "Accessories": "Accesorios", "Electronic Devices": "Dispositivos electrónicos", "Clothes": "Ropa", "Footwear": "Calzado", "Entertainment": "Entretenimiento", "Movies": "Películas", "Games": "Juegos", "Music": "Música", "Travel": "Viajar", "Food & Beverages": "Alimentos y bebidas", "Beverages": "bebidas", "Food": "Comida", "Daily Necessities": "Comestibles", "Groceries": "Épicerie", "Restaurant": "Restaurante", "Gifts & Donations": "Regalos y Donaciones", "Charity": "Caridad", "GiftsExpense": "Regalos", "Funeral": "Funeral", "Wedding": "Boda", "Health": "Salud", "Doctor": "Doctor", "Health Insurance": "Seguro de salud", "Medicine": "Medicina", "Sports": "Deportes", "Home": "Hogar", "Furnishings": "Mobiliario", "Home Services": "Servicios a domicilio", "Pets": "Mascotas", "Mortgage & Rent": "Hipoteca y alquiler", "Kids": "Niños", "Pocket Money": "dinero de bolsillo", "Baby Products": "productos para bebés", "Babysitter & Daycare": "Niñera y guardería", "Tuition": "Matrícula", "Personal Development": "Desarrollo personal", "Education": "Educación", "Business": "Negocios", "InvestmentExpense": "Inversión", "Utility Bills": "Facturas de servicios", "Electricity": "Electricidad", "Internet": "Internet", "Mobile Phone": "Teléfono móvil", "Water": "Agua", "Salary": "Salario", "Bonus": "Bonificación", "Side job": "Trabajo secundario", "GiftsIncome": "Regalos", "InvestmentIncome": "Inversión", "Income": "Ingreso", "Expense": "Gastos", "Balance": "Saldo", "Today": "Hoy dia", "This week": "Esta semana", "This month": "Este mes", "This year": "Este año", "This quarter": "Este trimestre", "Category": "Categoría", "TOTAL BALANCE": "SALDO TOTAL", "Nguyen Hoa": "Nguyen Hoa", "VIEW UPGRADE OPTIONS": "VER OPCIONES DE ACTUALIZACIÓN", "My Account": "Mi cuenta", "General Settings": "Configuración general", "Language": "Idioma", "Currency": "Moneda", "Share Friends": "Comparte amigos", "Rate App": "Tarifa de la aplicación", "Feedback": "Realimentación", "Add Expense Category": "Añadir categoría de gastos", "Add Income Category": "Añadir categoría de ingresos", "Category name": "Nombre de la categoría", "Parent category": "Categoría padre", "Add": "Añadir", "Game": "Juego", "Edit": "Editar", "Select a date": "Seleccionar una fecha", "CANCEL": "CANCELAR", "OK": "OK", "There is no data": "No hay datos", "Select a language": "Seleccione un idioma", "Please fill a category name": "Por favor complete un nombre de categoría", "Delete": "Borrar", "Total Year Amount": "Importe total del año", "Report": "Informe", "Hi you": "Hola", "All": "Todo", "Category already exists": "La categoría ya existe", "Month": "Mes", "2 weeks": "2 semanas", "Week": "Semana", "Since": "Desde", "Data has been saved": "Los datos se han guardado", "Choose Category": "Elija la categoría", "Done": "Hecho", "Icons": "Iconos", "Please Confirm": "Confirmar", "Yes": "Sí", "No": "No", "Cancel": "Cancelar", "This action cannot be undone. Are you sure you want to reset all categories?": "Esta acción no se puede deshacer. ¿Está seguro de que quiere restablecer todas las categorías?", "Reset": "Restablecer", "Reset All Categories": "Restablecer todas las categorías", "Categories have been reset": "Las categorías se han restablecido", "Enable Passcode": "Habilitar código de acceso", "Please Enter Passcode": "Por favor, introduzca el código de acceso", "Please Re-enter Passcode": "Por favor, vuelva a introducir el código de acceso", "Passcode has been disabled": "El código de acceso ha sido desactivado", "Passcode has been enabled": "Se ha habilitado el código de acceso", "Category has been deleted": "Se ha eliminado la categoría", "Are you sure you want to delete this category?": "¿Está seguro de que desea eliminar esta categoría?", "Delete All Data": "Borrar todos los datos", "All data has been deleted": "Se han borrado todos los datos", "Deleted data can not be recovered. Are you sure you want to delete all data?": "Los datos borrados no se pueden recuperar. ¿Está seguro de que quiere borrar todos los datos?", "Select a currency": "Seleccione una moneda", "Category has been updated": "La categoría ha sido actualizada", "Are you sure you want to delete this transaction?": "¿Está seguro de que quiere borrar esta transacción?", "Transaction has been deleted": "La transacción ha sido eliminada", "Transaction has been updated": "La transacción ha sido actualizada", "Select a date format": "Seleccione un formato de fecha", "Date format": "Formato de fecha", "Date format has been updated": "Se ha actualizado el formato de fecha" } ================================================ FILE: lib/project/localization/lang/fr.json ================================================ { "Input": "Intrant", "Analysis": "Analyse", "Calendar": "Calendrier", "Other": "Autre", "OtherIncome": "Autre", "OtherExpense": "Autre", "INCOME": "REVENU", "EXPENSE": "DÉPENSES", "Amount": "Quantité", "Description": "Description", "Save": "Sauvez", "Edit Category": "Éditer la catégorie", "Enter Category Name": "Entrez le nom de la catégorie", "Transport": "transport", "Fuel": "Le carburant", "Parking": "Parking", "Services & Maintenance": "Services et maintenance", "Taxi": "Taxi", "Shopping": "Shopping", "Accessories": "Accessoires", "Electronic Devices": "Dispositifs", "Clothes": "Vêtements", "Footwear": "Chaussures", "Entertainment": "Divertissement", "Movies": "Films", "Games": "Jeux", "Music": "Musique", "Travel": "Voyage", "Food & Beverages": "Aliments et boissons", "Beverages": "breuvages", "Food": "Aliments", "Daily Necessities": "Épicerie", "Groceries": "Épicerie", "Restaurant": "Le restaurant", "Gifts & Donations": "Cadeaux et dons", "Charity": "Charité", "GiftsExpense": "Cadeaux", "Funeral": "Funéraire", "Wedding": "Mariage", "Health": "Santé", "Doctor": "Médecin", "Health Insurance": "Assurance santé", "Medicine": "Médicament", "Sports": "Des sports", "Home": "Maison", "Furnishings": "Mobilier", "Home Services": "Services à domicile", "Pets": "Animal domestique", "Mortgage & Rent": "Hypothèque et loyer", "Kids": "Enfants", "Pocket Money": "Argent de poche", "Baby Products": "Produits pour bébés", "Babysitter & Daycare": "Baby-sitter et garderie", "Tuition": "Frais de scolarité", "Personal Development": "Développement", "Education": "Éducation", "Business": "Entreprise", "InvestmentExpense": "Investissement", "Utility Bills": "Factures", "Electricity": "Électricité", "Internet": "L'Internet", "Mobile Phone": "Téléphone mobile", "Water": "L'eau", "Salary": "Un salaire", "Bonus": "Bonus", "Side job": "Travail d'appoint", "GiftsIncome": "Cadeaux", "InvestmentIncome": "Investissement", "Income": "Revenu", "Expense": "Dépenses", "Balance": "Solde", "Today": "Aujourd'hui", "This week": "Cette semaine", "This month": "Ce mois-ci", "This year": "Cette année", "This quarter": "Ce trimestre", "Category": "Catégorie", "TOTAL BALANCE": "SOLDE TOTAL", "Nguyen Hoa": "Nguyen Hoa", "VIEW UPGRADE OPTIONS": "VOIR LES OPTIONS DE MISE À NIVEAU", "My Account": "Mon compte", "General Settings": "Réglages généraux", "Language": "Langue", "Currency": "Devise", "Share Friends": "Partager des amis", "Rate App": "Application de taux", "Feedback": "Retour d'information", "Add Expense Category": "Ajouter une catégorie de dépenses", "Add Income Category": "Ajouter une catégorie de revenu", "Category name": "Nom de la catégorie", "Parent category": "Catégorie mère", "Add": "Ajouter", "Game": "Jeu", "Edit": "Editer", "Select a date": "Sélectionner une date", "CANCEL": "ANNULER", "OK": "D'ACCORD", "There is no data": "Il n'y a pas de données", "Select a language": "Sélectionnez une langue", "Please fill a category name": "Veuillez remplir un nom de catégorie", "Delete": "Supprimer", "Total Year Amount": "Montant total de l'année", "Report": "Rapport", "Hi you": "Salut toi", "All": "Tout", "Category already exists": "La catégorie existe déjà", "Month": "Mois", "2 weeks": "2 semaines", "Week": "Semaine", "Since": "Depuis", "Data has been saved": "Les données ont été sauvegardées", "Choose Category": "Choisissez la catégorie", "Done": "Terminé", "Icons": "Icônes", "Please Confirm": "Confirmez", "Yes": "Oui", "No": "Non", "Cancel": "Annuler", "This action cannot be undone. Are you sure you want to reset all categories?": "Cette action ne peut pas être annulée. Êtes-vous sûr de vouloir réinitialiser toutes les catégories ?", "Reset": "Réinitialiser", "Reset All Categories": "Réinitialiser toutes les catégories", "Categories have been reset": "Les catégories ont été réinitialisées", "Enable Passcode": "Activer le code d'accès", "Please Enter Passcode": "Veuillez entrer le code d'accès", "Please Re-enter Passcode": "Veuillez saisir à nouveau le code d'accès", "Passcode has been disabled": "Le code d'accès a été désactivé", "Passcode has been enabled": "Le code d'accès a été activé", "Category has been deleted": "La catégorie a été supprimée", "Are you sure you want to delete this category?": "Êtes-vous sûr de vouloir supprimer cette catégorie ?", "Delete All Data": "Supprimer toutes les données", "All data has been deleted": "Toutes les données ont été supprimées", "Deleted data can not be recovered. Are you sure you want to delete all data?": "Les données supprimées ne peuvent pas être récupérées. Êtes-vous sûr de vouloir supprimer toutes les données ?", "Select a currency": "Sélectionnez une devise", "Category has been updated": "La catégorie a été mise à jour", "Are you sure you want to delete this transaction?": "Êtes-vous sûr de vouloir supprimer cette transaction ?", "Transaction has been deleted": "La transaction a été supprimée", "Transaction has been updated": "La transaction a été mise à jour", "Select a date format": "Sélectionnez un format de date", "Date format": "Format de date", "Date format has been updated": "Le format de date a été mis à jour" } ================================================ FILE: lib/project/localization/lang/hi.json ================================================ { "Input": "इनपुट", "Analysis": "विश्लेषण", "Calendar": "कैलेंडर", "Other": "अन्य", "OtherIncome": "अन्य", "OtherExpense": "अन्य", "INCOME": "आय", "EXPENSE": "व्यय", "Amount": "पैसे की राशि", "Description": "विवरण", "Save": "सहेजें", "Edit Category": "श्रेणी संपादित करें", "Enter Category Name": "श्रेणी नाम दर्ज करें", "Transport": "परिवहन", "Fuel": "ईंधन", "Parking": "पार्किंग", "Services & Maintenance": "भरण पोषण", "Taxi": "टैक्सी", "Shopping": "खरीदारी", "Accessories": "सामान", "Electronic Devices": "उपकरण", "Clothes": "वस्त्र", "Footwear": "जूते", "Entertainment": "मनोरंजन", "Movies": "चलचित्र", "Games": "खेल", "Music": "संगीत", "Travel": "यात्रा", "Food & Beverages": "खाद्य और पेय पदार्थ", "Beverages": "पेय", "Food": "खाना", "Daily Necessities": "परचून", "Groceries": "परचून", "Restaurant": "खाने की दुकान", "Gifts & Donations": "उपहार और दान", "Charity": "दान पुण्य", "GiftsExpense": "उपहार", "Funeral": "अंतिम संस्कार", "Wedding": "शादी", "Health": "स्वास्थ्य", "Doctor": "चिकित्सक", "Health Insurance": "स्वास्थ्य बीमा", "Medicine": "दवा", "Sports": "खेल", "Home": "घर", "Furnishings": "असबाब", "Home Services": "होम सर्विसेज", "Pets": "पालतू पशु", "Mortgage & Rent": "किराया", "Kids": "बच्चे", "Pocket Money": "जेब खर्च", "Baby Products": "छोटे उत्पाद", "Babysitter & Daycare": "दाई और डे केयर", "Tuition": "ट्यूशन", "Personal Development": "व्यक्तिगत विकास", "Education": "शिक्षा", "Business": "व्यापार", "InvestmentExpense": "निवेश", "Utility Bills": "उपयोगिता बिल", "Electricity": "बिजली", "Internet": "इंटरनेट", "Mobile Phone": "चल दूरभाष", "Water": "पानी", "Salary": "वेतन", "Bonus": "बोनस", "Side job": "अन्य नौकरी", "GiftsIncome": "उपहार", "InvestmentIncome": "निवेश", "Income": "आय", "Expense": "व्यय", "Balance": "शेष", "Today": "आज", "This week": "इस सप्ताह", "This month": "इस महीने", "This year": "इस साल", "This quarter": "इस तिमाही", "Category": "वर्ग", "TOTAL BALANCE": "कुल शेष", "Nguyen Hoa": "Nguyen Hoa", "VIEW UPGRADE OPTIONS": "उन्नयन के विकल्प देखें", "My Account": "मेरा खाता", "General Settings": "सामान्य सेटिंग्स", "Language": "भाषा", "Currency": "मुद्रा", "Share Friends": "मित्र साझा करें", "Rate App": "एप्प का मूल्यांकन", "Feedback": "प्रतिपुष्टि", "Add Expense Category": "व्यय श्रेणी जोड़ें", "Add Income Category": "आय श्रेणी जोड़ें", "Category name": "श्रेणी नाम", "Parent category": "अभिभावक श्रेणी", "Add": "जोड़ें", "Game": "खेल", "Edit": "संपादित करें", "Select a date": "एक तारीख चुनें", "CANCEL": "रद्द करना", "OK": "ठीक है", "There is no data": "कोई डेटा नहीं है", "Select a language": "भाषा चुनें", "Please fill a category name": "कृपया एक श्रेणी का नाम भरें", "Delete": "हटाएं", "Total Year Amount": "कुल वर्ष राशि", "Report": "रिपोर्ट", "Hi you": "हाय आप", "All": "सब", "Category already exists": "श्रेणी पहले से मौजूद है", "Month": "महीना", "2 weeks": "2 सप्ताह", "Week": "सप्ताह", "Since": "जबसे", "Data has been saved": "डेटा सहेजा गया है", "Choose Category": "श्रेणी का चयन करें", "Done": "किया हुआ", "Icons": "माउस", "Please Confirm": "पुष्टि करना", "Yes": "हां", "No": "नहीं", "Cancel": "रद्द करें", "This action cannot be undone. Are you sure you want to reset all categories?": "इस क्रिया को पूर्ववत नहीं किया जा सकता है। क्या आप वाकई सभी श्रेणियों को रीसेट करना चाहते हैं?", "Reset": "रीसेट", "Reset All Categories": "सभी श्रेणियों को रीसेट करें", "Categories have been reset": "श्रेणियाँ रीसेट कर दी गई हैं", "Enable Passcode": "पासकोड सक्षम करें", "Please Enter Passcode": "कृपया पासकोड दर्ज करें", "Please Re-enter Passcode": "कृपया पासकोड पुनः दर्ज करें", "Passcode has been disabled": "पासकोड अक्षम कर दिया गया है", "Passcode has been enabled": "पासकोड सक्षम किया गया है", "Category has been deleted": "श्रेणी हटा दी गई है", "Are you sure you want to delete this category?": "क्या आप वाकई इस श्रेणी को हटाना चाहते हैं?", "Delete All Data": "सभी डेटा हटाएँ", "All data has been deleted": "सभी डेटा हटा दिया गया है", "Deleted data can not be recovered. Are you sure you want to delete all data?": "हटाए गए डेटा को पुनर्प्राप्त नहीं किया जा सकता है। क्या आप वाकई सभी डेटा हटाना चाहते हैं?", "Select a currency": "एक मुद्रा चुनें", "Category has been updated": "श्रेणी अपडेट कर दी गई है", "Are you sure you want to delete this transaction?": "क्या आप वाकई इस लेन-देन को हटाना चाहते हैं?", "Transaction has been deleted": "लेन-देन हटा दिया गया है", "Transaction has been updated": "लेन-देन अद्यतन किया गया है", "Select a date format": "दिनांक प्रारूप का चयन करें", "Date format": "डेटा प्रारूप", "Date format has been updated": "दिनांक प्रारूप अपडेट किया गया है" } ================================================ FILE: lib/project/localization/lang/ja.json ================================================ { "Input": "入力", "Analysis": "分析", "Calendar": "カレンダー", "Other": "その他", "OtherIncome": "その他", "OtherExpense": "その他", "INCOME": "所得", "EXPENSE": "エクスペンス", "Amount": "量", "Description": "説明", "Save": "セーブ", "Edit Category": "カテゴリの編集", "Enter Category Name": "カテゴリー名の入力", "Transport": "交通手段", "Fuel": "燃料", "Parking": "パーキング", "Services & Maintenance": "メンテナンス", "Taxi": "タクシー", "Shopping": " ショッピング", "Accessories": "アクセサリー", "Electronic Devices": "デバイス", "Clothes": "服", "Footwear": "履物", "Entertainment": "エンターテインメント", "Movies": "映画", "Games": "ゲーム", "Music": "音楽", "Travel": "トラベル", "Food & Beverages": "フード&ビバレッジ", "Beverages": "飲料", "Food": "食物", "Daily Necessities": "日用品", "Groceries": "日用品", "Restaurant": "レストラン", "Gifts & Donations": " ギフトと寄付", "Charity": "チャリティー", "GiftsExpense": "ギフト", "Funeral": "葬儀", "Wedding": "結婚式", "Health": "健康", "Doctor": "医師", "Health Insurance": "健康保険", "Medicine": "薬", "Sports": "スポーツ", "Home": "ホーム", "Furnishings": "什器備品", "Home Services": "サービス", "Pets": "ペット", "Mortgage & Rent": "レンタル", "Kids": "キッズ", "Pocket Money": "引当金", "Baby Products": "ベビー製品", "Babysitter & Daycare": "デイケア", "Tuition": "授業料", "Personal Development": "個人的な開発", "Education": "教育", "Business": "ビジネス", "InvestmentExpense": "投資", "Utility Bills": "水道光熱費", "Electricity": "電気", "Internet": "ネット", "Mobile Phone": "携帯電話", "Water": "水", "Salary": "給料", "Bonus": "ボーナス", "Side job": "サイドジョブ", "GiftsIncome": "ギフト", "InvestmentIncome": "投資", "Income": "所得", "Expense": "エクスペンス", "Balance": "残高", "Today": "今日", "This week": "今週", "This month": "今月", "This year": "今年", "This quarter": "この四半期", "Category": "カテゴリー", "TOTAL BALANCE": "合計残高", "Nguyen Hoa": "Nguyen Hoa", "VIEW UPGRADE OPTIONS": "アップグレードオプションを見る", "My Account": "マイアカウント", "General Settings": "設定", "Language": "言語", "Currency": "通貨", "Share Friends": "友達を共有し", "Rate App": "アプリの評価", "Feedback": "フィードバック", "Add Expense Category": "経費カテゴリを追加し", "Add Income Category": "収入カテゴリーの追加", "Category name": "種別名", "Parent category": "親カテゴリ", "Add": "追加", "Game": "ゲーム", "Edit": "編集", "Select a date": "日付を選択し", "CANCEL": "キャンセル", "OK": "OK", "There is no data": "データが存在しません", "Select a language": "言語を選択し", "Please fill a category name": "カテゴリー名を入力してください", "Delete": "削除", "Total Year Amount": "合計年額", "Report": "報告書", "Hi you": "こんにちは", "All": "すべて", "Category already exists": "カテゴリーはすでに存在しています", "Month": "月の話", "2 weeks": "2週間", "Week": "週", "Since": "以来", "Data has been saved": "データが保存されている", "Choose Category": "カテゴリを選択し", "Done": "終わり", "Icons": "アイコン", "Please Confirm": "確認", "Yes": "はい", "No": "番号", "Cancel": "キャンセル", "This action cannot be undone. Are you sure you want to reset all categories?": "このアクションは元に戻せません。 すべてのカテゴリをリセットしてもよろしいですか?", "Reset": "リセット", "Reset All Categories": "すべてのカテゴリをリセット", "Categories have been reset": "カテゴリがリセットされました", "Enable Passcode": "パスコードを有効にし", "Please Enter Passcode": "パスコードを入力してください", "Please Re-enter Passcode": "パスコードを再入力してください", "Passcode has been disabled": "パスコードが無効になっています", "Passcode has been enabled": "パスコードが有効になっています", "Category has been deleted": "カテゴリが削除されました", "Are you sure you want to delete this category?": "このカテゴリを削除してもよろしいですか?", "Delete All Data": "すべてのデータを削除し", "All data has been deleted": "すべてのデータが削除されました", "Deleted data can not be recovered. Are you sure you want to delete all data?": "削除したデータは復元できません。 すべてのデータを削除してもよろしいですか?", "Select a currency": "通貨を選択してください", "Category has been updated": "カテゴリーが更新されました", "Are you sure you want to delete this transaction?": "このトランザクションを削除してよろしいですか?", "Transaction has been deleted": "トランザクションが削除されました", "Transaction has been updated": "トランザクションが更新されました", "Select a date format": "日付形式を選択します", "Date format": "日付形式を選択します", "Date format has been updated": "日付形式が更新されました" } ================================================ FILE: lib/project/localization/lang/ko.json ================================================ { "Input": "입력", "Analysis": "분석", "Calendar": "달력", "Other": "다른", "OtherIncome": "다른", "OtherExpense": "다른", "INCOME": "수입", "EXPENSE": "비용", "Amount": "양", "Description": "노트", "Save": "저장", "Edit Category": "카테고리 편집", "Enter Category Name": " 카테고리 이름 입력", "Transport": "수송", "Fuel": "연료", "Parking": "주차", "Services & Maintenance": "서비스 및 유지 관리", "Taxi": "택시", "Shopping": "쇼핑", "Accessories": "부속품", "Electronic Devices": "전자 장치", "Clothes": "천", "Footwear": "신발류", "Entertainment": "환대", "Movies": "영화 산업", "Games": "경기", "Music": "음악", "Travel": "여행", "Food & Beverages": "식음료", "Beverages": "음료수", "Food": "음식", "Daily Necessities": "일 용품", "Groceries": "일 용품", "Restaurant": "레스토랑", "Gifts & Donations": " 선물 및 기부", "Charity": "자선 단체", "GiftsExpense": "선물", "Funeral": "장례", "Wedding": "혼례", "Health": "건강", "Doctor": "박사님", "Health Insurance": "건강 보험", "Medicine": "약", "Sports": "스포츠", "Home": "집", "Furnishings": "가구", "Home Services": "홈 서비스", "Pets": "애완 동물", "Mortgage & Rent": "모기지 및 렌탈", "Kids": "키즈", "Pocket Money": "포켓 돈", "Baby Products": "아기 제품", "Babysitter & Daycare": "베이비 시터 및 보육", "Tuition": "수업료", "Personal Development": " 개인 개발", "Education": "교육", "Business": "사업", "InvestmentExpense": "투자", "Utility Bills": "공공 요금", "Electricity": "전기", "Internet": "인터넷", "Mobile Phone": "휴대폰", "Water": "물", "Salary": "봉급", "Bonus": "보너스", "Side job": "부업", "GiftsIncome": "선물", "InvestmentIncome": "투자", "Income": "수입", "Expense": "비용", "Balance": "균형", "Today": "오늘", "This week": "이번 주", "This month": "이번 달", "This year": "올해", "This quarter": "이번 분기에", "Category": "범주", "TOTAL BALANCE": "전체 균형", "Nguyen Hoa": "Nguyen Hoa", "VIEW UPGRADE OPTIONS": "업그레이드 옵션보기", "My Account": "내 계정", "General Settings": "설정", "Language": "언어", "Currency": "통화", "Share Friends": "친구 공유", "Rate App": "앱 평가", "Feedback": "피드백", "Add Expense Category": "비용 범주 추가", "Add Income Category": "소득 범주 추가", "Category name": "카테고리 이름", "Parent category": "상위 카테고리", "Add": "더하다", "Game": "경기", "Edit": "편집하다", "Select a date": "날짜를 선택하고", "CANCEL": "취소", "OK": "확인", "There is no data": "데이터가 없습니다", "Select a language": "언어를 선택하고", "Please fill a category name": "카테고리 이름을 입력하세요", "Delete": "지우다", "Total Year Amount": "총 연도 금액", "Report": "신고", "Hi you": "안녕하세요", "All": "모두", "Category already exists": "카테고리가 이미 존재합니다", "Month": "달", "2 weeks": "이주", "Week": "주", "Since": "이후", "Data has been saved": "데이터가 저장되었습니다", "Choose Category": "카테고리를 선택하고", "Done": "완료", "Icons": "아이콘", "Please Confirm": "확인하다", "Yes": "예", "No": "아니요", "Cancel": "취소", "This action cannot be undone. Are you sure you want to reset all categories?": "이 작업은 취소할 수 없습니다. 모든 카테고리를 재설정하시겠습니까?", "Reset": "초기화", "Reset All Categories": "모든 카테고리 재설정", "Categories have been reset": "카테고리가 재설정되었습니다", "Enable Passcode": "암호 활성화", "Please Enter Passcode": "비밀번호를 입력하세요", "Please Re-enter Passcode": "비밀번호를 다시 입력하세요", "Passcode has been disabled": "비밀번호가 비활성화되었습니다", "Passcode has been enabled": "암호가 활성화되었습니다", "Category has been deleted": "카테고리가 삭제되었습니다", "Are you sure you want to delete this category?": "이 카테고리를 삭제하시겠습니까?", "Delete All Data": "모든 데이터 삭제", "All data has been deleted": "모든 데이터가 삭제되었으며", "Deleted data can not be recovered. Are you sure you want to delete all data?": "삭제된 데이터는 복구할 수 없습니다. 모든 데이터를 삭제하시겠습니까?", "Select a currency": "통화 선택", "Category has been updated": "카테고리가 업데이트되었습니다", "Are you sure you want to delete this transaction?": "이 거래를 삭제하시겠습니까?", "Transaction has been deleted": "거래가 삭제되었습니다", "Transaction has been updated": "거래가 업데이트되었습니다", "Select a date format": "날짜 형식을 선택하고", "Date format": "날짜 형식", "Date format has been updated": "날짜 형식이 업데이트되었습니다" } ================================================ FILE: lib/project/localization/lang/ne.json ================================================ { "Input": "थप्नुहोस्", "Analysis": "विश्लेषण", "Calendar": "पात्रो", "Other": "अन्य", "OtherIncome": "अन्य", "OtherExpense": "अन्य", "INCOME": "आम्दान", "EXPENSE": "खर्च", "Amount": "रकम", "Description": "विवरण", "Save": "सुरक्षित गर्नुहोस्", "Edit Category": "कोटीहरू सम्पादन गर्नुहोस्", "Enter Category Name": "कोटीको नाम प्रविष्ट गर्नुहोस्", "Transport": "यातायात", "Fuel": "ईंधन", "Parking": "पार्किङ", "Services & Maintenance": "सेवा र रखरखाव", "Taxi": "ट्याक्सी", "Shopping": "खरीददारी", "Accessories": "सामानहरू", "Electronic Devices": "इलेक्ट्रोनिक यन्त्रहरू", "Clothes": "कपडा", "Footwear": "पर्खा", "Entertainment": "मनोरञ्जन", "Movies": "चलचित्र", "Games": "खेलहरू", "Music": "सङ्गीत", "Travel": "यात्रा", "Food & Beverages": "खाद्य र पेयपन", "Beverages": "पेयपनहरू", "Food": "खाद्य", "Daily Necessities": "दैनिक आवश्यकता", "Groceries": "किराना", "Restaurant": "भोजनगृह", "Gifts & Donations": "उपहार र दान", "Charity": "चारिटी", "GiftsExpense": "उपहार", "Funeral": "अन्त्येष्टि", "Wedding": "बिवाह", "Health": "स्वास्थ्य", "Doctor": "डाक्टर", "Health Insurance": "स्वास्थ्य बीमा", "Medicine": "औषधि", "Sports": "खेलकुद", "Home": "घर", "Furnishings": "फर्निचर", "Home Services": "घर सेवा", "Pets": "पाल्टु", "Mortgage & Rent": "मोर्ट्गेज र ठेगाना", "Kids": "बच्चाहरू", "Pocket Money": "किस्ता", "Baby Products": "बच्चाका सामानहरू", "Babysitter & Daycare": "बेबीसिटर र डेकेयर", "Tuition": "पढाइ", "Personal Development": "व्यक्तिगत विकास", "Education": "शिक्षा", "Business": "व्यापार", "InvestmentExpense": "बिनिवेस्टमेन्ट", "Utility Bills": "यूटिलिटी बिल", "Electricity": "बिजुली", "Internet": "इन्टरनेट", "Mobile Phone": "मोबाइल फोन", "Water": "पानी", "Salary": "तलब", "Bonus": "बोनस", "Side job": "पर्खाउ काम", "GiftsIncome": "उपहार", "InvestmentIncome": "बिनिवेस्टमेन्ट", "Income": "आम्दान", "Expense": "खर्च", "Balance": "तलब", "Today": "आज", "This week": "यो हप्ता", "This month": "यो महिना", "This year": "यो वर्ष", "This quarter": "यो तिमाही", "Category": "कोटी", "TOTAL BALANCE": "कुल तलब", "Nguyen Hoa": "न्गुयेन होआ", "VIEW UPGRADE OPTIONS": "अपग्रेड विकल्पहरू हेर्नुहोस्", "My Account": "मेरो खाता", "General Settings": "सामान्य सेटिङ", "Language": "भाषा", "Currency": "मुद्रा", "Share Friends": "साथीहरूसँग साझा गर्नुहोस्", "Rate App": "एप्लिकेशन मूल्यांकन गर्नुहोस्", "Feedback": "प्रतिक्रिया", "Add Expense Category": "खर्च कोटी थप्नुहोस्", "Category name": "कोटीको नाम", "Parent category": "मुख्य कोटी", "Add": "थप्नुहोस्", "Game": "खेल", "Edit": "सम्पादन गर्नुहोस्", "Select a date": "मिति चयन गर्नुहोस्", "CANCEL": "रद्द गर्नुहोस्", "OK": "ठिक छ", "There is no data": "डेटा छैन", "Select a language": "भाषा चयन गर्नुहोस्", "Please fill a category name": "कृपया कोटीको नाम भर्नुहोस्", "Delete": "मेटाउनुहोस्", "Total Year Amount": "कुल वर्ष रकम", "Report": "प्रतिवेदन", "Add Income Category": "आम्दान कोटी थप्नुहोस्", "Hi you": "नमस्ते तपाईं", "All": "सबै", "Category already exists": "कोटी पहिले नै अवस्थित छ", "Month": "महिना", "2 weeks": "2 हप्ता", "Week": "हप्ता", "Since": "बाट", "Data has been saved": "डेटा सुरक्षित गरिएको छ", "Choose Category": "कोटी छनौट गर्नुहोस्", "Done": "गरिएको", "Icons": "प्रतिष्ठानहरू", "Please Confirm": "कृपया पुष्टि गर्नुहोस्", "Yes": "हो", "No": "होइन", "Cancel": "रद्द गर्नुहोस्", "This action cannot be undone. Are you sure you want to reset all categories?": "यस क्रियालाई पूर्वनिर्धारण गर्न सकिन्छैन। के तपाईं सबै कोटीहरू रिसेट गर्न चाहनुहुन्छ?", "Reset": "रिसेट गर्नुहोस्", "Reset All Categories": "सबै कोटीहरू रिसेट गर्नुहोस्", "Categories have been reset": "कोटीहरू रिसेट भएका छन्", "Enable Passcode": "पासकोड सक्षम गर्नुहोस्", "Please Enter Passcode": "कृपया पासकोड प्रविष्ट गर्नुहोस्", "Please Re-enter Passcode": "कृपया पासकोड पुन: प्रविष्ट गर्नुहोस्", "Passcode has been disabled": "पासकोड अक्षम भएको छ", "Passcode has been enabled": "पासकोड सक्षम भएको छ", "Category has been deleted": "कोटी मेटाईएको छ", "Are you sure you want to delete this category?": "के तपाईं यो कोटी मेटाउन चाहनुहुन्छ?", "Delete All Data": "सबै डेटा मेटाउनुहोस्", "All data has been deleted": "सबै डेटा मेटाईएको छ", "Deleted data can not be recovered. Are you sure you want to delete all data?": "मेटिएको डेटा पुनःप्राप्त गर्न सकिन्छैन। के तपाईं सबै डेटा मेटाउन चाहनुहुन्छ?", "Select a currency": "मुद्रा चयन गर्नुहोस्", "Category has been updated": "कोटी अद्यावधिक गरिएको छ", "Are you sure you want to delete this transaction?": "के तपाईं यो लेनदेन मेटाउन चाहनुहुन्छ?", "Transaction has been deleted": "लेनदेन मेटाईएको छ", "Transaction has been updated": "लेनदेन अद्यावधिक गरिएको छ", "Select a date format": "मिति ढाँचा चयन गर्नुहोस्", "Date format": "मिति ढाँचा", "Date format has been updated": "मिति ढाँचा अद्यावधिक गरिएको छ" } ================================================ FILE: lib/project/localization/lang/pt.json ================================================ { "Input": "Entrada", "Analysis": "Análise", "Calendar": "Calendário", "Other": "Outro", "OtherIncome": "Outro", "OtherExpense": "Outro", "INCOME": "RENDA", "EXPENSE": "DESPESA", "Amount": "Quantia", "Description": "Descrição", "Save": "Salve", "Edit Category": "Editar categoria", "Enter Category Name": "Digite o nome da categoria", "Transport": "transporte", "Fuel": "Combustível", "Parking": "Estacionamento", "Services & Maintenance": "Serviços e manutenção", "Taxi": "Táxi", "Shopping": "Compras", "Accessories": "Acessórios", "Electronic Devices": "Dispositivos eletrônicos", "Clothes": "Roupas", "Footwear": "Calçados", "Entertainment": "Entretenimento", "Movies": "Filmes", "Games": "Jogos", "Music": "Música", "Travel": "Viagem", "Food & Beverages": "Alimentos e bebidas", "Beverages": "bebidas", "Food": "Comida", "Daily Necessities": "Necessividades diárias", "Groceries": "Necessividades diárias", "Restaurant": "Restaurante", "Gifts & Donations": "Presentes e doações", "Charity": "Caridade", "GiftsExpense": "Presentes", "Funeral": "Funeral", "Wedding": "Casamento", "Health": "Saúde", "Doctor": "Doutora", "Health Insurance": "Seguros de saúde", "Medicine": "medicina", "Sports": "Esportes", "Home": "Casa", "Furnishings": "Mobiliário", "Home Services": "Serviços ao domicílio", "Pets": "Animais de estimação", "Mortgage & Rent": "Hipoteca e aluguel", "Kids": "Crianças", "Pocket Money": "Mesada", "Baby Products": "Produtos para bebés", "Babysitter & Daycare": "Babá e creche", "Tuition": "Aulas", "Personal Development": "crescimento pessoal", "Education": "Educação", "Business": "Negócios", "InvestmentExpense": "Investimento", "Utility Bills": "Facturas de utilidade", "Electricity": "Eletricidade", "Internet": "Internet", "Mobile Phone": "Celular", "Water": "Água", "Salary": "Salário", "Bonus": "Bônus", "Side job": "Trabalho lateral", "GiftsIncome": "Presentes", "InvestmentIncome": "Investimento", "Income": "Renda", "Expense": "Despesa", "Balance": "Balanço", "Today": "Hoje", "This week": "Essa semana", "This month": "Este mês", "This year": "Este ano", "This quarter": "Este trimestre", "Category": "Categoria", "TOTAL BALANCE": "BALANÇO TOTAL", "Nguyen Hoa": "Nguyen Hoa", "VIEW UPGRADE OPTIONS": "VER OPÇÕES DE UPGRADE", "My Account": "Minha conta", "General Settings": "Configurações Gerais", "Language": "Idioma", "Currency": "Moeda", "Share Friends": "Compartilhar amigos", "Rate App": "Aplicativo de taxa", "Feedback": "Feedback", "Add Expense Category": "Adicionar categoria de despesas", "Add Income Category": "Adicionar categoria de rendimentos", "Category name": "Nome da categoria", "Parent category": "Categoria dos pais", "Add": "Acrescentar", "Game": "Jogo", "Edit": "Editar", "Select a date": "Seleccione uma data", "CANCEL": "CANCELAM", "OK": "OK", "There is no data": "Não há dados", "Select a language": "Seleccione uma língu", "Please fill a category name": "Por favor, preencha um nome de categoria", "Delete": "Eliminar", "Total Year Amount": "Montante Total do Ano", "Report": "Relatório", "Hi you": "Oi vc", "All": "Tudo", "Category already exists": "A categoria já existe", "Month": "Mês", "2 weeks": "2 semanas", "Week": "Semana", "Since": "Desde", "Data has been saved": "Os dados foram guardados", "Choose Category": "Escolha a Categoria", "Done": "Feito", "Icons": "Ícones", "Please Confirm": "Confirmar", "Yes": "Sim", "No": "Não", "Cancel": "Cancelar", "This action cannot be undone. Are you sure you want to reset all categories?": "Esta acção não pode ser desfeita. Tem a certeza de que quer redefinir todas as categorias?", "Reset": "Reinicializar", "Reset All Categories": "Repor todas as categorias", "Categories have been reset": "As categorias foram repostas", "Enable Passcode": "Habilite a senha", "Please Enter Passcode": "Por favor, introduza o código de acesso", "Please Re-enter Passcode": "Por favor, introduza novamente o código de acesso", "Passcode has been disabled": "O código de acesso foi desactivado", "Passcode has been enabled": "O código de acesso foi activado", "Category has been deleted": "A categoria foi eliminada", "Are you sure you want to delete this category?": "Tem a certeza de que quer eliminar esta categoria?", "Delete All Data": "Apagar todos os dados", "All data has been deleted": "Todos os dados foram apagados", "Deleted data can not be recovered. Are you sure you want to delete all data?": "Os dados apagados não podem ser recuperados. Tem a certeza de que quer apagar todos os dados?", "Select a currency": "Seleccione uma moeda", "Category has been updated": "A categoria foi actualizada", "Are you sure you want to delete this transaction?": "Tem a certeza de querer apagar esta transacção?", "Transaction has been deleted": "A transacção foi eliminada", "Transaction has been updated": "A transacção foi actualizada", "Select a date format": "Seleccionar um formato de data", "Date format": "Formato da data", "Date format has been updated": "O formato da data foi actualizado" } ================================================ FILE: lib/project/localization/lang/ru.json ================================================ { "Input": "Вход", "Analysis": "Анализ", "Calendar": "Календарь", "Other": "Другой", "OtherIncome": "Другой", "OtherExpense": "Другой", "INCOME": "ДОХОД", "EXPENSE": "РАСХОДЫ", "Amount": "Количество", "Description": "Описание", "Save": "Сохранить", "Edit Category": "Категория редактирования", "Enter Category Name": "Введите название категории", "Transport": "Транспорт", "Fuel": "Топливо", "Parking": "Стоянка", "Services & Maintenance": "Обслуживание", "Taxi": "Такси", "Shopping": "Покупка товаров", "Accessories": "Аксессуары", "Electronic Devices": " Устройства", "Clothes": "Одежда", "Footwear": "Обувь", "Entertainment": "Развлечение", "Movies": "Фильмы", "Games": "Игры", "Music": "Музыка", "Travel": "Путешествовать", "Food & Beverages": "Еда и напитки", "Beverages": "напитки", "Food": "Еда", "Daily Necessities": "Ежедневные нужды", "Groceries": "Ежедневные нужды", "Restaurant": "Ресторан", "Gifts & Donations": "События", "Charity": "Благотворительность", "GiftsExpense": "Подарки", "Funeral": "Похороны", "Wedding": "Свадьба", "Health": "Здоровье", "Doctor": "Врач", "Health Insurance": "страхование здоровья", "Medicine": "Лекарство", "Sports": "Спортивный", "Home": "Дома", "Furnishings": "Мебель", "Home Services": "Домашние услуги", "Pets": "Домашние питомцы", "Mortgage & Rent": "Ипотека и аренда", "Kids": "Дети", "Pocket Money": "Карманные деньги", "Baby Products": "Детские товары", "Babysitter & Daycare": "Няня и детский сад", "Tuition": "Плата за обучение", "Personal Development": "Личное развитие", "Education": "Образование", "Business": "Бизнес", "InvestmentExpense": "Инвестиции", "Utility Bills": "Счета", "Electricity": "Электричество", "Internet": "Интернет", "Mobile Phone": "Мобильный телефон", "Water": "Вода", "Salary": "Зарплата", "Bonus": "Бонус", "Side job": "Боковая работа", "GiftsIncome": "Подарки", "InvestmentIncome": "Инвестиции", "Income": "Доход", "Expense": "Расходы", "Balance": "баланс", "Today": "Сегодня", "This week": "На этой неделе", "This month": "Этот месяц", "This year": "Этот год", "This quarter": "Этот квартал", "Category": "Категория", "TOTAL BALANCE": "ИТОГОВЫЙ БАЛАНС", "Nguyen Hoa": "Nguyen Hoa", "VIEW UPGRADE OPTIONS": "Просмотр вариантов обновления", "My Account": "Мой счет", "General Settings": "Общие настройки", "Language": "Язык", "Currency": "Валюта", "Share Friends": "Поделиться друзьями", "Rate App": "Оценить приложение", "Feedback": "Обратная связь", "Add Expense Category": "Добавить категорию расходов", "Add Income Category": "Добавить категорию дохода", "Category name": "Название категории", "Parent category": "Родительская категория", "Add": "Добавить", "Game": "Игра", "Edit": "Изменить", "Select a date": "Выбрать дату", "CANCEL": "ОТМЕНИТЬ", "OK": "OK", "There is no data": "Нет данных", "Select a language": "Выберите язык", "Please fill a category name": "Пожалуйста, введите название категории", "Delete": "Удалить", "Total Year Amount": "Общая сумма за год", "Report": "Отчет", "Hi you": "Привет", "All": "Все", "Category already exists": "Категория уже существует", "Month": "Месяц", "2 weeks": "2 недели", "Week": "Неделя", "Since": "С", "Data has been saved": "Данные сохранены", "Choose Category": "Выберите категорию", "Done": "Готово", "Icons": "Иконки", "Please Confirm": "Подтвердите", "Yes": "Да", "No": "Нет", "Cancel": "Отменить", "This action cannot be undone. Are you sure you want to reset all categories?": "Это действие нельзя отменить. Вы уверены, что хотите сбросить все категории?", "Reset": "Сброс", "Reset All Categories": "Сбросить все категории", "Categories have been reset": "Категории были сброшены", "Enable Passcode": "Включить пароль", "Please Enter Passcode": "Пожалуйста, введите пароль", "Please Re-enter Passcode": "Пожалуйста, введите пароль заново", "Passcode has been disabled": "Пасскод был отключен", "Passcode has been enabled": "Пасскод был включен", "Category has been deleted": "Категория была удалена", "Are you sure you want to delete this category?": "Вы уверены, что хотите удалить эту категорию?", "Delete All Data": "Удалить все данные", "All data has been deleted": "Все данные были удалены", "Deleted data can not be recovered. Are you sure you want to delete all data?": "Удаленные данные не могут быть восстановлены. Вы уверены, что хотите удалить все данные?", "Select a currency": "Выберите валюту", "Category has been updated": "Категория была обновлена", "Are you sure you want to delete this transaction?": "Вы уверены, что хотите удалить эту транзакцию?", "Transaction has been deleted": "Транзакция была удалена", "Transaction has been updated": "Транзакция была обновлена", "Select a date format": "Выберите формат даты", "Date format": "Формат даты", "Date format has been updated": "Формат даты был обновлен" } ================================================ FILE: lib/project/localization/lang/tr.json ================================================ { "Input": "Giriş", "Analysis": "Analiz", "Calendar": "Takvim", "Other": "Diğer", "OtherIncome": "Diğer", "OtherExpense": "Diğer", "INCOME": "GELİR", "EXPENSE": "GİDER", "Amount": "Miktar", "Description": "Tanım", "Save": "kurtarmak", "Edit Category": "Kategoriyi düzenle", "Enter Category Name": "Kategori adını girin", "Transport": "Ulaşım", "Fuel": "Yakıt", "Parking": "Otopark", "Services & Maintenance": "Hizmetler ve Bakım", "Taxi": "Taksi", "Shopping": "Alışveriş yapmak", "Accessories": "Aksesuarlar", "Electronic Devices": "Elektronik aletler", "Clothes": "Giysi", "Footwear": "Ayakkabı", "Entertainment": "Eğlence", "Movies": "Filmler", "Games": "Oyunlar", "Music": "Müzik", "Travel": "Seyahat", "Food & Beverages": "Yiyecek ve İçecekler", "Beverages": "içecekler", "Food": "Gıda", "Daily Necessities": "Günlük ihtiyaçlar", "Groceries": "Günlük ihtiyaçlar", "Restaurant": "Restoran", "Gifts & Donations": "Hediyeler ve Bağışlar", "Charity": "Hayırseverlik", "GiftsExpense": "Hediyeler", "Funeral": "Cenaze", "Wedding": "Düğün", "Health": "Sağlık", "Doctor": "Doktor", "Health Insurance": "Sağlık Sigortası", "Medicine": "İlaç", "Sports": "Spor Dalları", "Home": "Ev", "Furnishings": "Mobilyalar", "Home Services": "Ev Hizmetleri", "Pets": "Evcil Hayvanlar", "Mortgage & Rent": "İpotek ve Kira", "Kids": "Çocuklar", "Pocket Money": "Harçlık", "Baby Products": "Bebek ürünleri", "Babysitter & Daycare": "Çocuk bakıcısı", "Tuition": "Öğrenim", "Personal Development": "Kişisel Gelişim", "Education": "Eğitim", "Business": "İş", "InvestmentExpense": "Yatırım", "Utility Bills": "Hizmet Faturaları", "Electricity": "Elektrik", "Internet": "İnternet", "Mobile Phone": "Cep telefonu", "Water": "Su", "Salary": "Maaş", "Bonus": "Bonus", "Side job": "Ek iş", "GiftsIncome": "Hediyeler", "InvestmentIncome": "Yatırım", "Income": "Gelir", "Expense": "Gider", "Balance": "Bakiye", "Today": "Bugün", "This week": "Bu hafta", "This month": "Bu ay", "This year": "Bu yıl", "This quarter": "Bu çeyrek", "Category": "Kategori", "TOTAL BALANCE": "TOPLAM BAKIYE", "Nguyen Hoa": "Nguyen Hoa", "VIEW UPGRADE OPTIONS": "Yükseltme seçeneklerini görüntüleyin", "My Account": "Hesabım", "General Settings": "Genel Ayarlar", "Language": "Dil", "Currency": "Para birimi", "Share Friends": "Arkadaşları paylaş", "Rate App": "Uygulamayı Değerlendir", "Feedback": "Geri bildirim", "Add Expense Category": "Gider Kategorisi Ekle", "Add Income Category": "Akommes Kategorie derbäi", "Category name": "Kategori adı", "Parent category": "Aile kategorisi", "Add": "Ekle", "Game": "oyun", "Edit": "Düzenle", "Select a date": "Bir tarih seçin", "CANCEL": "İPTAL ETMEK", "OK": "TAMAM MI", "There is no data": "Veri yok", "Select a language": "Bir dil seç", "Please fill a category name": "Lütfen bir kategori adı girin", "Delete": "Sil", "Total Year Amount": "Toplam Yıl Tutarı", "Report": "Bildiri", "Hi you": "merhaba sen", "All": "Herşey", "Category already exists": "Kategori zaten var", "Month": "Ay", "2 weeks": "2 hafta", "Week": "Hafta", "Since": "Beri", "Data has been saved": "Veri kaydedildi", "Choose Category": "Kategori Seçin", "Done": "Tamamlandı", "Icons": "Simgeler", "Please Confirm": "Onaylamak", "Yes": "Evet", "No": "Numara", "Cancel": "İptal", "This action cannot be undone. Are you sure you want to reset all categories?": "Bu işlem geri alınamaz. Tüm kategorileri sıfırlamak istediğinizden emin misiniz?", "Reset": "Sıfırla", "Reset All Categories": "Tüm Kategorileri Sıfırla", "Categories have been reset": "Kategoriler sıfırlandı", "Enable Passcode": "Şifreyi Etkinleştir", "Please Enter Passcode": "Lütfen Şifreyi Girin", "Please Re-enter Passcode": "Lütfen şifreyi tekrar girin", "Passcode has been disabled": "Parola devre dışı bırakıldı", "Passcode has been enabled": "Şifre kodu etkinleştirildi", "Category has been deleted": "Kategori silindi", "Are you sure you want to delete this category?": "Bu kategoriyi silmek istediğinizden emin misiniz?", "Delete All Data": "Tüm Verileri Sil", "All data has been deleted": "Tüm veriler silindi", "Deleted data can not be recovered. Are you sure you want to delete all data?": "Silinen veriler kurtarılamaz. Tüm verileri silmek istediğinizden emin misiniz?", "Select a currency": "Bir para birimi seçin", "Category has been updated": "Kategori güncellendi", "Are you sure you want to delete this transaction?": "Bu işlemi silmek istediğinizden emin misiniz?", "Transaction has been deleted": "İşlem silindi", "Transaction has been updated": "İşlem güncellendi", "Select a date format": "Bir tarih formatı seçin", "Date format": "Tarih formatı", "Date format has been updated": "Tarih formatı güncellend" } ================================================ FILE: lib/project/localization/lang/vi.json ================================================ { "Input": "Nhập liệu ", "Analysis": "Phân tích", "Calendar": "Lịch ", "Other": "Khác", "OtherIncome": "Khác", "OtherExpense": "Khác", "INCOME": "THU NHẬP", "EXPENSE": "CHI TIÊU", "Amount": "Số tiền", "Description": "Ghi chú", "Save": "Lưu", "Edit Category": "Chỉnh sửa danh mục", "Enter Category Name": "Nhập danh mục", "Transport": "Đi lại", "Fuel": "Xăng xe", "Parking": "Gửi xe", "Services & Maintenance": "Dịch vụ & Bảo dưỡng", "Taxi": "Thuê xe", "Shopping": "Mua sắm", "Accessories": "Phụ kiện", "Electronic Devices": "Thiết bị điện tử", "Clothes": "Quần áo", "Footwear": "Giày dép", "Entertainment": "Giải trí", "Movies": "Phim ảnh", "Games": "Game", "Music": "Nhạc", "Travel": "Du lịch", "Food & Beverages": "Ăn uống", "Beverages": "Đồ uống", "Food": "Thức ăn", "Daily Necessities": "Tạp phẩm", "Groceries": "Tạp phẩm", "Restaurant": "Nhà hàng", "Gifts & Donations": "Hiếu hỉ & Từ thiện", "Charity": "Từ thiện", "GiftsExpense": "Quà", "Funeral": "Tang lễ", "Wedding": "Cưới hỏi", "Health": "Chăm sóc sức khỏe", "Doctor": "Khám chữa bệnh", "Health Insurance": "Bảo hiểm y tế", "Medicine": "Thuốc men", "Sports": "Thể thao", "Home": "Nhà cửa", "Furnishings": "Đồ đạc & Nội thất", "Home Services": "Sửa chữa nhà cửa", "Pets": "Vật nuôi", "Mortgage & Rent": "Thế chấp & thuê nhà", "Kids": "Con cái", "Pocket Money": "Tiền tiêu vặt", "Baby Products": "Đồ dùng trẻ em", "Babysitter & Daycare": "Giữ trẻ", "Tuition": "Học phí", "Personal Development": "Phát triển bản thân", "Education": "Học hành", "Business": "Kinh doanh", "InvestmentExpense": "Đầu tư", "Utility Bills": "Hóa đơn & Tiện ích", "Electricity": "Điện", "Internet": "Internet", "Mobile Phone": "Điện thoại di động", "Water": "Nước", "Salary": "Lương", "Bonus": "Thưởng", "Side job": "Công việc thêm", "GiftsIncome": "Quà", "InvestmentIncome": "Đầu tư", "Income": "Thu nhập", "Expense": "Chi tiêu", "Balance": "Số dư", "Today": "Hôm nay", "This week": "Tuần này", "This month": "Tháng này", "This year": "Năm nay", "This quarter": "Quý này", "Category": "Danh mục", "TOTAL BALANCE": "SỐ DƯ", "Nguyen Hoa": "Nguyen Hoa", "VIEW UPGRADE OPTIONS": "NÂNG CẤP PREMIUM", "My Account": "Quản lí tài khoản", "General Settings": "Cài đặt chung", "Language": "Ngôn ngữ", "Currency": "Tiền tệ", "Share Friends": "Chia sẻ ứng dụng", "Rate App": "Đánh giá ứng dụng", "Feedback": "Góp ý", "Add Expense Category": "Thêm danh mục chi tiêu", "Add Income Category": "Thêm danh mục thu nhập", "Category name": "Tên danh mục", "Parent category": "Danh mục chính", "Add": "Thêm", "Game": "Trò chơi", "Edit": "Sửa", "Select a date": "Chọn ngày", "CANCEL": "HUỶ BỎ", "OK": "ĐỒNG Ý", "There is no data": "Không có dữ liệu", "Select a language": "Chọn ngôn ngữ", "Please fill a category name": "Vui lòng điền tên danh mục", "Delete": "Xóa", "Total Year Amount": "Tổng số tiền trong năm", "Report": "Báo cáo", "Hi you": "Chào bạn", "All": "Tất cả", "Category already exists": "Danh mục này đã tồn tại", "Month": "Tháng", "2 weeks": "2 tuần", "Week": "Tuần", "Since": "Từ", "Data has been saved": "Dữ liệu đã được lưu", "Choose Category": "Chọn danh mục", "Done": "Xong", "Icons": "Biểu tượng", "Please Confirm": "Xác nhận", "Yes": "Có", "No": "Không", "Cancel": "Hủy bỏ", "This action cannot be undone. Are you sure you want to reset all categories?": "Hành động này không thể được hoàn tác. Bạn có chắc chắn muốn đặt lại tất cả danh mục không?", "Reset": "Đặt lại", "Reset All Categories": "Đặt lại tất cả danh mục", "Categories have been reset": "Danh mục đã được đặt lại", "Enable Passcode": "Bật mật mã", "Please Enter Passcode": "Vui lòng nhập mật mã", "Please Re-enter Passcode": "Vui lòng nhập lại mật mã", "Passcode has been disabled": "Mật mã đã được vô hiệu hóa", "Passcode has been enabled": "Mật mã đã được kích hoạt", "Category has been deleted": "Danh mục đã được xóa", "Are you sure you want to delete this category?": "Bạn có chắc chắn muốn xóa danh mục này không?", "Delete All Data": "Xóa tất cả dữ liệu", "All data has been deleted": "Tất cả dữ liệu đã được xóa", "Deleted data can not be recovered. Are you sure you want to delete all data?": "Không thể khôi phục dữ liệu đã xóa. Bạn có chắc chắn muốn xóa tất cả dữ liệu không?", "Select a currency": "Chọn đơn vị tiền tệ", "Category has been updated": "Danh mục đã được cập nhật", "Are you sure you want to delete this transaction?": "Bạn có chắc chắn muốn xóa giao dịch này không ?", "Transaction has been deleted": "Giao dịch đã được xóa", "Transaction has been updated": "Giao dịch đã được cập nhật", "Select a date format": "Chọn một định dạng ngày", "Date format": "Định dạng ngày tháng", "Date format has been updated": "Định dạng ngày đã được cập nhật" } ================================================ FILE: lib/project/localization/lang/zh.json ================================================ { "Input": "输入", "Analysis": "报告", "Calendar": "日历 ", "Other": "其他", "OtherIncome": "其他", "OtherExpense": "其他", "INCOME": "支出", "EXPENSE": "收入", "Amount": "金额 ", "Description": "记录", "Save": "保存", "Edit Category": "编辑类别", "Enter Category Name": "选择类别", "Transport": "运送", "Fuel": "汽油", "Parking": "停车费", "Services & Maintenance": "服务与维护", "Taxi": "出租车", "Shopping": "购物", "Accessories": "配件", "Electronic Devices": "电子设备", "Clothes": "服装", "Footwear": "鞋类", "Entertainment": "娱乐", "Movies": "电影", "Games": "游戏", "Music": "音乐", "Travel": "旅游", "Food & Beverages": "餐饮", "Beverages": "咖啡厅", "Food": "食物", "Daily Necessities": "日用品", "Groceries": "日用品", "Restaurant": "餐馆", "Gifts & Donations": "礼物和捐赠", "Charity": "慈善", "GiftsExpense": "礼物", "Funeral": "丧事", "Wedding": "婚礼", "Health": "医药", "Doctor": "医生", "Health Insurance": "健康保险", "Medicine": "药房", "Sports": "运动", "Home": "居家", "Pets": "宠物", "Furnishings": "家具", "Home Services": "家装", "Mortgage & Rent": "租金", "Kids": "孩子们", "Pocket Money": "零花钱", "Baby Products": "嬰兒用品", "Babysitter & Daycare": "保姆和日托", "Tuition": "学费", "Personal Development": "个人发展", "Education": "教育", "Business": "商务", "InvestmentExpense": "投资", "Utility Bills": "水电费", "Electricity": "电", "Internet": "互联网", "Mobile Phone": "移动电话", "Water": "水", "Salary": "工资", "Bonus": "奖金", "Side job": "副业", "GiftsIncome": "礼物", "InvestmentIncome": "投资", "Income": "支出", "Expense": "收入", "Balance": "余额合计", "Today": "今天", "This week": "本星期", "This month": "这个月", "This year": "今年", "This quarter": "这个季度", "Category": "分类", "TOTAL BALANCE": "余额合计", "Nguyen Hoa": "Nguyen Hoa", "VIEW UPGRADE OPTIONS": "探索高级", "My Account": "账户管理", "General Settings": "常规设置", "Language": "语言", "Currency": "货币", "Share Friends": "分享朋友", "Rate App": "评价应用", "Feedback": "反馈", "Add Expense Category": "添加支出类别", "Add Income Category": "添加收入类别", "Category name": "类别名称", "Parent category": "父类别", "Add": "添加", "Game": "游戏", "Edit": "编辑", "Select a date": "选择一个日期", "CANCEL": "取消", "OK": "确定", "There is no data": "没有数据", "Select a language": "选择一种语言", "Please fill a category name": "请填写一个类别名称", "Delete": "删除", "Total Year Amount": "年度总金额", "Report": "报告", "Hi you": "你好", "All": "全部", "Category already exists": "类别已经存在", "Month": "月", "2 weeks": "2周", "Week": "周", "Since": "自从", "Data has been saved": "数据已被保存", "Choose Category": "选择类别", "Done": "完成", "Icons": "图标", "Please Confirm": "确认", "Yes": "是的", "No": "不", "Cancel": "取消", "This action cannot be undone. Are you sure you want to reset all categories?": "这个动作不能撤消。你确定要重置所有类别吗?", "Reset": "重置", "Reset All Categories": "重置所有类别", "Categories have been reset": "类别已被重置", "Enable Passcode": "启用密码", "Please Enter Passcode": "请输入密码", "Please Re-enter Passcode": "请重新输入密码", "Passcode has been disabled": "密码已被禁用", "Passcode has been enabled": "密码已启用", "Category has been deleted": "类别已被删除", "Are you sure you want to delete this category?": "你确定你要删除这个类别吗?", "Delete All Data": "删除所有数据", "All data has been deleted": "所有数据已被删除", "Deleted data can not be recovered. Are you sure you want to delete all data?": "已删除的数据无法恢复。你确定要删除所有数据吗?", "Select a currency": "选择一种货币", "Category has been updated": "类别已被更新", "Are you sure you want to delete this transaction?": "你确定你要删除这个交易吗?", "Transaction has been deleted": "交易已被删除", "Transaction has been updated": "交易已被更新", "Select a date format": "选择一个日期格式", "Date format": "日期格式", "Date format has been updated": "日期格式已被更新" } ================================================ FILE: lib/project/localization/language.dart ================================================ class Language { final int id; final String flag; final String name; final String languageCode; final String countryCode; final String currencySymbol; final String currencyCode; final String currencyName; const Language( this.id, this.flag, this.name, this.languageCode, this.countryCode, this.currencySymbol, this.currencyCode, this.currencyName); static List languageList = [ Language( 1, "🇺🇸", "English", "en", 'US', '\$', 'USD', 'United States Dollar'), // Language(2, "🇸🇦", "العربية", "ar", 'SA', 'R'), Language(3, "🇩🇪", "Deutsch", "de", 'DE', '€', 'EUR', 'Euro'), Language(4, "🇪🇸", "Español", "es", 'ES', '€', 'EUR', 'Euro'), Language(5, "🇫🇷", "Français", "fr", 'FR', '€', 'EUR', 'Euro'), Language(6, "🇮🇳", "हिन्दी", "hi", 'IN', '₹', 'INR', 'Indian Rupee'), Language(7, "🇯🇵", "日本語", "ja", 'JP', '¥', 'JPY', 'Japanese Yen'), Language(8, "🇰🇷", "한국어", "ko", 'KR', '₩', 'KRW', 'South Korean Won'), Language(9, "🇵🇹", "Português", "pt", 'PT', '€', 'EUR', 'Euro'), Language( 10, "🇷🇺", "Русский язык", "ru", 'RU', 'руб', 'RUB', 'Russian Ruble'), Language(11, "🇹🇷", "Türkçe", "tr", 'TR', 'TL', 'TRY', 'Turkish Lira'), Language( 12, "🇻🇳", "Tiếng Việt", "vi", 'VN', '₫', 'VND', 'Vietnamese Dong'), Language(13, "🇨🇳", "中文", "zh", 'CN', '¥', 'CNY', 'Chinese Yuan'), Language(14, "🇳🇵", "नेपाली", "ne", 'NP', 'रु', 'NPR', 'Nepali Rupee'), ]; } ================================================ FILE: lib/project/localization/methods.dart ================================================ import 'package:flutter/material.dart'; import 'app_localization.dart'; Locale locale(String languageCode) { switch (languageCode) { case 'en': return Locale('en', 'US'); // case 'ar': // return Locale('ar', "SA"); case 'de': return Locale('de', "DE"); case 'es': return Locale('es', 'ES'); case 'fr': return Locale('fr', "FR"); case 'hi': return Locale('hi', "IN"); case 'ja': return Locale('ja', "JP"); case 'ko': return Locale('ko', 'KR'); case 'pt': return Locale('pt', "PT"); case 'ru': return Locale('ru', "RU"); case 'tr': return Locale('tr', "TR"); case 'vi': return Locale('vi', "VN"); case 'zh': return Locale('zh', "CN"); case 'ne': return Locale('ne', "NP"); default: return Locale('en', 'US'); } } String? getTranslated(BuildContext context, String key) { return AppLocalization.of(context)?.translate(key); } Map? localizedMap(BuildContext context) => AppLocalization.of(context)?.localizedMap(); ================================================ FILE: lib/project/provider.dart ================================================ import 'package:flutter/cupertino.dart'; import 'package:money_assistant_2608/project/classes/category_item.dart'; import 'package:money_assistant_2608/project/database_management/shared_preferences_services.dart'; import 'classes/input_model.dart'; import 'database_management/sqflite_services.dart'; // input class ChangeCategoryA with ChangeNotifier { CategoryItem? categoryItemA; void changeCategory(CategoryItem? newItem) { categoryItemA = newItem ?? categoryItemA; notifyListeners(); } } class ChangeModelType with ChangeNotifier { String? modelType; void changeModelType(String newType) { this.modelType = newType; notifyListeners(); } } // analysis, report class ChangeSelectedDate with ChangeNotifier { String? selectedAnalysisDate; String? selectedReportDate; void changeSelectedAnalysisDate({String? newSelectedDate}) { selectedAnalysisDate = newSelectedDate; notifyListeners(); } void changeSelectedReportDate({String? newSelectedDate}) { selectedReportDate = newSelectedDate; notifyListeners(); } } //report class InputModelList with ChangeNotifier { Future> inputModelList = DB.inputModelList(); void changeInputModelList() { inputModelList = DB.inputModelList(); notifyListeners(); } } //expense_category class ChangeExpenseItem with ChangeNotifier { var exItemsLists = sharedPrefs.getAllExpenseItemsLists(); void getAllExpenseItems() { exItemsLists = sharedPrefs.getAllExpenseItemsLists(); notifyListeners(); } } class ChangeExpenseItemEdit with ChangeNotifier { var exItemsLists = sharedPrefs.getAllExpenseItemsLists(); void getAllExpenseItems() { exItemsLists = sharedPrefs.getAllExpenseItemsLists(); notifyListeners(); } } //income_category class ChangeIncomeItem with ChangeNotifier { var incomeItems = sharedPrefs.getItems('income items'); void getIncomeItems() { incomeItems = sharedPrefs.getItems('income items'); notifyListeners(); } } class ChangeIncomeItemEdit with ChangeNotifier { var incomeItems = sharedPrefs.getItems('income items'); void getIncomeItems() { incomeItems = sharedPrefs.getItems('income items'); notifyListeners(); } } //add_category class ChangeCategory with ChangeNotifier { IconData? selectedCategoryIcon; CategoryItem? parentItem; void changeCategoryIcon(IconData? selectedIcon) { this.selectedCategoryIcon = selectedIcon; notifyListeners(); } void changeParentItem(CategoryItem? newParentItem) { parentItem = newParentItem ?? parentItem; notifyListeners(); } } //other class OnSwitch with ChangeNotifier { bool isPasscodeOn = sharedPrefs.isPasscodeOn; void onSwitch() { sharedPrefs.isPasscodeOn = !sharedPrefs.isPasscodeOn; isPasscodeOn = sharedPrefs.isPasscodeOn; notifyListeners(); } } //select_language class OnLanguageSelected with ChangeNotifier { String languageCode = sharedPrefs.getLocale().languageCode; void onSelect(String newLanguageCode) { languageCode = newLanguageCode; notifyListeners(); } } //select_currency class OnCurrencySelected with ChangeNotifier { String appCurrency = sharedPrefs.appCurrency; void onCurrencySelected(String newCurrency) { appCurrency = newCurrency; sharedPrefs.appCurrency = newCurrency; sharedPrefs.getCurrency(); notifyListeners(); } } //select_date_format class OnDateFormatSelected with ChangeNotifier { String dateFormat = sharedPrefs.dateFormat; void onDateFormatSelected(String newDateFormat) { dateFormat = newDateFormat; sharedPrefs.dateFormat = newDateFormat; notifyListeners(); } } ================================================ FILE: lib/project/real_main.dart ================================================ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:money_assistant_2608/project/auth_pages/sign_in.dart'; import 'database_management/shared_preferences_services.dart'; import 'localization/app_localization.dart'; import 'home.dart'; void realMain() async { WidgetsFlutterBinding.ensureInitialized(); await sharedPrefs.sharePrefsInit(); sharedPrefs.setItems(setCategoriesToDefault: false); sharedPrefs.getCurrency(); sharedPrefs.getAllExpenseItemsLists(); runApp(MyApp() // AppLock( // builder: (args) => MyApp(), // lockScreen: MainLockScreen(), // enabled: sharedPrefs.isPasscodeOn ? true : false) ); } class MyApp extends StatefulWidget { static void setLocale(BuildContext context, Locale newLocale) { _MyAppState state = context.findAncestorStateOfType<_MyAppState>()!; state.setLocale(newLocale); } @override _MyAppState createState() => _MyAppState(); } class _MyAppState extends State { late Locale? _locale; setLocale(Locale locale) { setState(() { _locale = locale; }); } @override void didChangeDependencies() { Locale appLocale = sharedPrefs.getLocale(); setState(() { this._locale = appLocale; }); super.didChangeDependencies(); } @override Widget build(BuildContext context) { if (this._locale == null) { return Container( child: Center( child: CircularProgressIndicator( valueColor: AlwaysStoppedAnimation(Colors.blue[800]!)), ), ); } else { return ScreenUtilInit( designSize: Size(428.0, 926.0), builder: (_, child) => MaterialApp( title: 'MMAS', debugShowCheckedModeBanner: false, theme: ThemeData( textTheme: TextTheme( headline3: TextStyle( fontFamily: 'OpenSans', fontSize: 45.0, color: Colors.deepOrangeAccent, ), button: TextStyle( fontFamily: 'OpenSans', ), subtitle1: TextStyle(fontFamily: 'NotoSans'), bodyText2: TextStyle(fontFamily: 'NotoSans'), ), colorScheme: ColorScheme.fromSwatch(primarySwatch: Colors.indigo) .copyWith(secondary: Colors.orange), textSelectionTheme: TextSelectionThemeData(cursorColor: Colors.amberAccent), ), builder: (context, widget) => MediaQuery( data: MediaQuery.of(context).copyWith(textScaleFactor: 1), child: widget!, ), home: SignIn(), // Home(), locale: _locale, localizationsDelegates: [ AppLocalization.delegate, GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate, ], localeResolutionCallback: (locale, supportedLocales) { for (var supportedLocale in supportedLocales) { if (supportedLocale.languageCode == locale!.languageCode && supportedLocale.countryCode == locale.countryCode) { return supportedLocale; } } return supportedLocales.first; }, supportedLocales: [ Locale("en", "US"), Locale("de", "DE"), Locale("es", "ES"), Locale("fr", "FR"), Locale("hi", "IN"), Locale("ja", "JP"), Locale("ko", "KR"), Locale("pt", "PT"), Locale("ru", "RU"), Locale("tr", "TR"), Locale("vi", "VN"), Locale("zh", "CN"), Locale("ne", "NP"), ], ), ); } } } ================================================ FILE: pubspec.yaml ================================================ name: money_assistant_2608 description: A new Flutter project. # The following line prevents the package from being accidentally published to # pub.dev using `pub publish`. This is preferred for private packages. publish_to: 'none' # Remove this line if you wish to publish to pub.dev # The following defines the version and build number for your application. # A version number is three numbers separated by dots, like 1.2.43 # followed by an optional build number separated by a +. # Both the version and the builder number may be overridden in flutter # build by specifying --build-name and --build-number, respectively. # In Android, build-name is used as versionName while build-number used as versionCode. # Read more about Android versioning at https://developer.android.com/studio/publish/versioning # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html version: 1.0.8 environment: sdk: ">=2.12.0 <3.0.0" dependencies: flutter: sdk: flutter flutter_localizations: sdk: flutter # material_floating_search_bar: ^0.3.3 # cloud_firestore: ^0.16.0+1 # syncfusion_flutter_datepicker: ^19.2.62 # flutter_spinkit: ^5.1.0 google_sign_in: ^5.2.0 firebase_auth: ^3.1.4 firebase_core: ^1.8.0 shared_preferences: ^2.0.8 sqflite: ^2.0.0+4 intl: ^0.17.0 provider: ^5.0.0 flutter_screenutil: ^5.0.0+2 flutter_login: ^2.2.1 flutter_screen_lock: ^4.0.4+2 flutter_app_lock: ^2.0.0 google_fonts: ^2.1.0 table_calendar: ^3.0.2 syncfusion_flutter_charts: ^20.4.54 day_night_time_picker: ^1.0.3+1 flutter_material_pickers: ^3.1.0 sliding_up_panel: ^2.0.0+1 keyboard_actions: ^3.4.4 fluttertoast: ^8.2.1 flutter_swipe_action_cell: ^3.1.0 share_plus: ^2.1.4 in_app_review: ^2.0.3 rate_my_app: ^1.1.1 # local_auth: ^1.1.8 # icons material_design_icons_flutter: ^4.0.5955 font_awesome_flutter: ^9.1.0 outline_material_icons: ^0.1.1 flutter_boxicons: ^3.0.0 icofont_flutter: ^1.4.0 cupertino_icons: ^1.0.3 dependency_overrides: flutter_colorpicker: ^0.6.0 dev_dependencies: flutter_test: sdk: flutter flutter_native_splash: ^1.2.3 flutter_native_splash: color: "#ffffff" # color_dark: "#ffffff" # image_dark: images/splash_screen.png image: images/splash_screen.png android: true ios: true # android12: true # This package generates native code to customize Flutter's default white native splash screen # with background color and splash image. # Customize the parameters below, and run the following command in the terminal: # flutter pub run flutter_native_splash:create # To restore Flutter's default white splash screen, run the following command in the terminal: # flutter pub run flutter_native_splash:remove # color or background_image is the only required parameter. Use color to set the background # of your splash screen to a solid color. Use background_image to set the background of your # splash screen to a png image. This is useful for gradients. The image will be stretch to the # size of the app. Only one parameter can be used, color and background_image cannot both be set. #background_image: "assets/background.png" # Optional parameters are listed below. To enable a parameter, uncomment the line by removing # the leading # character. # The image parameter allows you to specify an image used in the splash screen. It must be a # png file. #image: assets/splash.png # The color_dark, background_image_dark, and image_dark are parameters that set the background # and image when the device is in dark mode. If they are not specified, the app will use the # parameters from above. If the image_dark parameter is specified, color_dark or # background_image_dark must be specified. color_dark and background_image_dark cannot both be # set. #color_dark: "#042a49" #background_image_dark: "assets/dark-background.png" #image_dark: assets/splash-invert.png # The android, ios and web parameters can be used to disable generating a splash screen on a given # platform. #android: false #ios: false #web: false # The position of the splash image can be set with android_gravity, ios_content_mode, and # web_image_mode parameters. All default to center. # # android_gravity can be one of the following Android Gravity (see # https://developer.android.com/reference/android/view/Gravity): bottom, center, # center_horizontal, center_vertical, clip_horizontal, clip_vertical, end, fill, fill_horizontal, # fill_vertical, left, right, start, or top. #android_gravity: center # # ios_content_mode can be one of the following iOS UIView.ContentMode (see # https://developer.apple.com/documentation/uikit/uiview/contentmode): scaleToFill, # scaleAspectFit, scaleAspectFill, center, top, bottom, left, right, topLeft, topRight, # bottomLeft, or bottomRight. #ios_content_mode: center # # web_image_mode can be one of the following modes: center, contain, stretch, and cover. #web_image_mode: center # To hide the notification bar, use the fullscreen parameter. Has no affect in web since web # has no notification bar. Defaults to false. # NOTE: Unlike Android, iOS will not automatically show the notification bar when the app loads. # To show the notification bar, add the following code to your Flutter app: # WidgetsFlutterBinding.ensureInitialized(); # SystemChrome.setEnabledSystemUIOverlays([SystemUiOverlay.bottom, SystemUiOverlay.top]); #fullscreen: true # If you have changed the name(s) of your info.plist file(s), you can specify the filename(s) # with the info_plist_files parameter. Remove only the # characters in the three lines below, # do not remove any spaces: #info_plist_files: # - 'ios/Runner/Info-Debug.plist' # - 'ios/Runner/Info-Release.plist' #command: flutter clean && flutter pub get && flutter pub run flutter_native_splash:create # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec # The following section is specific to Flutter. flutter: generate: true # Add this line # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. uses-material-design: true # To add assets to your application, add an assets section, like this: # assets: # - images/a_dot_burr.jpeg # - images/a_dot_ham.jpeg assets: # - /Users/hoanguyen/AndroidStudioProjects/moneyassistant/lib/project/localization/lang/ # - /Users/hoanguyen/AndroidStudioProjects/moneyassistant/images/ - lib/project/localization/lang/ - images/ # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware. # For details regarding adding assets from package dependencies, see # https://flutter.dev/assets-and-images/#from-packages # To add custom fonts to your application, add a fonts section here, # in this "flutter" section. Each entry in this list should have a # "family" key with the font family name, and a "fonts" key with a # list giving the asset and other descriptors for the font. For # mmas: # fonts: # - family: Schyler # fonts: # - asset: fonts/Schyler-Regular.ttf # - asset: fonts/Schyler-Italic.ttf # style: italic # - family: Trajan Pro # fonts: # - asset: fonts/TrajanPro.ttf # - asset: fonts/TrajanPro_Bold.ttf # weight: 700 # # For details regarding fonts from package dependencies, # see https://flutter.dev/custom-fonts/#from-packages ================================================ FILE: test/widget_test.dart ================================================ // This is a basic Flutter widget test. // // To perform an interaction with a widget in your test, use the WidgetTester // utility that Flutter provides. For mmas, you can send tap and scroll // gestures. You can also use WidgetTester to find child widgets in the widget // tree, read text, and verify that the values of widget properties are correct. import 'package:flutter/material.dart'; import 'package:flutter_material_pickers/main.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { testWidgets('Counter increments smoke test', (WidgetTester tester) async { // Build our app and trigger a frame. await tester.pumpWidget(MyApp()); // Verify that our counter starts at 0. expect(find.text('0'), findsOneWidget); expect(find.text('1'), findsNothing); // Tap the '+' icon and trigger a frame. await tester.tap(find.byIcon(Icons.add)); await tester.pump(); // Verify that our counter has incremented. expect(find.text('0'), findsNothing); expect(find.text('1'), findsOneWidget); }); }