├── .env ├── android ├── settings_aar.gradle ├── gradle.properties ├── app │ ├── src │ │ ├── main │ │ │ ├── res │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── values │ │ │ │ │ └── styles.xml │ │ │ │ └── drawable │ │ │ │ │ └── launch_background.xml │ │ │ ├── kotlin │ │ │ │ └── com │ │ │ │ │ └── example │ │ │ │ │ └── pin_cattle │ │ │ │ │ └── MainActivity.kt │ │ │ └── AndroidManifest.xml │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ └── profile │ │ │ └── AndroidManifest.xml │ └── build.gradle ├── .gitignore ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── settings.gradle └── build.gradle ├── ios ├── Flutter │ ├── Debug.xcconfig │ ├── Release.xcconfig │ └── AppFrameworkInfo.plist ├── Runner │ ├── Runner-Bridging-Header.h │ ├── Assets.xcassets │ │ ├── LaunchImage.imageset │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ ├── README.md │ │ │ └── Contents.json │ │ └── AppIcon.appiconset │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ ├── Icon-App-83.5x83.5@2x.png │ │ │ └── Contents.json │ ├── AppDelegate.swift │ ├── Base.lproj │ │ ├── Main.storyboard │ │ └── LaunchScreen.storyboard │ └── Info.plist ├── Runner.xcworkspace │ └── contents.xcworkspacedata ├── Runner.xcodeproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme └── .gitignore ├── ss ├── flutter_01.png ├── flutter_02.png ├── flutter_03.png ├── flutter_04.png ├── flutter_05.png ├── flutter_06.png └── flutter_07.png ├── assets ├── images │ ├── cow.jpeg │ ├── login.png │ ├── splash.png │ ├── state │ │ ├── cow.png │ │ ├── bull.png │ │ ├── calf.png │ │ ├── calved.png │ │ ├── heifer.png │ │ ├── weaned.png │ │ ├── breeding.png │ │ ├── pragnent.png │ │ ├── abortion_ip.png │ │ ├── customside.png │ │ └── onmilking.png │ ├── milk-bottle.svg │ ├── milking.svg │ ├── heart.svg │ ├── total_cow.svg │ ├── milk.svg │ ├── fertilization.svg │ ├── milking_cow.svg │ └── dry_cow.svg └── fonts │ └── Iran_Sans.ttf ├── l10n.yaml ├── lib ├── utils │ ├── PinConfig.dart │ ├── theme.dart │ ├── DateUtil.dart │ ├── api │ │ ├── Response.dart │ │ ├── CustomException.dart │ │ └── ApiProvider.dart │ └── SettingsProvider.dart ├── models │ ├── User.dart │ ├── LoginResponse.dart │ ├── LivestockState.dart │ ├── Dashboard.dart │ ├── livestock.dart │ └── LocaleModel.dart ├── widgets │ ├── PinSnackBar.dart │ ├── fab_bottom_navigation │ │ ├── pin_image.dart │ │ └── fab_bottom_app_bar.dart │ └── confirm_dialog.dart ├── components │ ├── detail │ │ ├── milk_chart.dart │ │ ├── detail_card_actions.dart │ │ └── state_dialog.dart │ ├── settings │ │ ├── language.dart │ │ └── settings.dart │ ├── newAnimal │ │ ├── input.dart │ │ ├── drop_down.dart │ │ └── new-animal.dart │ ├── dashboard │ │ ├── summary_card.dart │ │ ├── main_dashboard_card.dart │ │ └── dashboard.dart │ ├── splash │ │ └── splash_page.dart │ ├── list │ │ ├── filter.dart │ │ └── list.dart │ └── login │ │ ├── otp_page.dart │ │ └── login_page.dart ├── repositories │ ├── SettingRespository.dart │ ├── DashboardRespository.dart │ ├── UserRepository.dart │ ├── AuthRepository.dart │ └── LivstockRespository.dart ├── main.dart ├── home.dart └── l10n │ ├── app_fa.arb │ └── app_en.arb ├── .metadata ├── .vscode └── launch.json ├── .gitignore ├── test └── widget_test.dart ├── README.md ├── pubspec.yaml └── pubspec.lock /.env: -------------------------------------------------------------------------------- 1 | API_URL=http://192.168.43.240/api 2 | -------------------------------------------------------------------------------- /android/settings_aar.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" -------------------------------------------------------------------------------- /ss/flutter_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/ss/flutter_01.png -------------------------------------------------------------------------------- /ss/flutter_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/ss/flutter_02.png -------------------------------------------------------------------------------- /ss/flutter_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/ss/flutter_03.png -------------------------------------------------------------------------------- /ss/flutter_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/ss/flutter_04.png -------------------------------------------------------------------------------- /ss/flutter_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/ss/flutter_05.png -------------------------------------------------------------------------------- /ss/flutter_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/ss/flutter_06.png -------------------------------------------------------------------------------- /ss/flutter_07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/ss/flutter_07.png -------------------------------------------------------------------------------- /assets/images/cow.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/assets/images/cow.jpeg -------------------------------------------------------------------------------- /assets/images/login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/assets/images/login.png -------------------------------------------------------------------------------- /assets/images/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/assets/images/splash.png -------------------------------------------------------------------------------- /assets/fonts/Iran_Sans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/assets/fonts/Iran_Sans.ttf -------------------------------------------------------------------------------- /assets/images/state/cow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/assets/images/state/cow.png -------------------------------------------------------------------------------- /assets/images/state/bull.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/assets/images/state/bull.png -------------------------------------------------------------------------------- /assets/images/state/calf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/assets/images/state/calf.png -------------------------------------------------------------------------------- /assets/images/state/calved.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/assets/images/state/calved.png -------------------------------------------------------------------------------- /assets/images/state/heifer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/assets/images/state/heifer.png -------------------------------------------------------------------------------- /assets/images/state/weaned.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/assets/images/state/weaned.png -------------------------------------------------------------------------------- /assets/images/state/breeding.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/assets/images/state/breeding.png -------------------------------------------------------------------------------- /assets/images/state/pragnent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/assets/images/state/pragnent.png -------------------------------------------------------------------------------- /assets/images/state/abortion_ip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/assets/images/state/abortion_ip.png -------------------------------------------------------------------------------- /assets/images/state/customside.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/assets/images/state/customside.png -------------------------------------------------------------------------------- /assets/images/state/onmilking.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/assets/images/state/onmilking.png -------------------------------------------------------------------------------- /l10n.yaml: -------------------------------------------------------------------------------- 1 | arb-dir: lib/l10n 2 | template-arb-file: app_en.arb 3 | output-localization-file: app_localizations.dart 4 | -------------------------------------------------------------------------------- /lib/utils/PinConfig.dart: -------------------------------------------------------------------------------- 1 | class PinConfig{ 2 | static const int PORT=3000; 3 | static const String IP="192.168.43.240"; 4 | } -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.enableR8=true 3 | android.useAndroidX=true 4 | android.enableJetifier=true 5 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /lib/models/User.dart: -------------------------------------------------------------------------------- 1 | class User{ 2 | String phone; 3 | 4 | User({this.phone}); 5 | 6 | User.fromJSON(Map json) 7 | : phone=json["phone"]; 8 | } -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k2288/cattle/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /lib/models/LoginResponse.dart: -------------------------------------------------------------------------------- 1 | class LoginResponse{ 2 | String token; 3 | 4 | LoginResponse({this.token}); 5 | 6 | LoginResponse.fromJSON(Map json) 7 | : token=json["token"]; 8 | } -------------------------------------------------------------------------------- /lib/utils/theme.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class MyColors { 4 | static const Color primaryColor = Color(0xFF503E9D); 5 | static const Color primaryColorLight = Color(0xFF6252A7); 6 | } -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip 7 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: f139b11009aeb8ed2a3a3aa8b0066e482709dde3 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /lib/utils/DateUtil.dart: -------------------------------------------------------------------------------- 1 | import 'package:cattle/models/LocaleModel.dart'; 2 | import 'package:intl/intl.dart'; 3 | import 'package:persian_date/persian_date.dart'; 4 | 5 | class DateUtil{ 6 | static formatLocaleDate(item,context){ 7 | return Language.isRtl(context)? PersianDate().gregorianToJalali(item,"yyyy/mm/d"): DateFormat("yyyy-MM-dd").format(DateTime.parse(item)); 8 | } 9 | } -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /lib/models/LivestockState.dart: -------------------------------------------------------------------------------- 1 | 2 | class LivestockState{ 3 | String id; 4 | String state; 5 | String date; 6 | String description; 7 | 8 | LivestockState(this.state,this.date,this.description,[this.id]); 9 | 10 | LivestockState.fromJSON(Map json) 11 | : state=json["state"], 12 | id=json["_id"], 13 | date=json["date"]!=null?json["date"]:"", 14 | description=json["description"]; 15 | } -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Flutter", 9 | "request": "launch", 10 | "type": "dart" 11 | } 12 | ] 13 | } -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lib/utils/api/Response.dart: -------------------------------------------------------------------------------- 1 | class Response { 2 | Status status; 3 | T data; 4 | String message; 5 | 6 | Response.loading(this.message) : status = Status.LOADING; 7 | Response.completed(this.data) : status = Status.COMPLETED; 8 | Response.error(this.message) : status = Status.ERROR; 9 | 10 | @override 11 | String toString() { 12 | return "Status : $status \n Message : $message \n Data : $data"; 13 | } 14 | } 15 | 16 | enum Status { LOADING, COMPLETED, ERROR } -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/example/pin_cattle/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.pin_cattle 2 | 3 | import androidx.annotation.NonNull; 4 | import io.flutter.embedding.android.FlutterActivity 5 | import io.flutter.embedding.engine.FlutterEngine 6 | import io.flutter.plugins.GeneratedPluginRegistrant 7 | 8 | class MainActivity: FlutterActivity() { 9 | override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { 10 | GeneratedPluginRegistrant.registerWith(flutterEngine); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lib/widgets/PinSnackBar.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class PinSnackBar { 4 | 5 | final String _text; 6 | final Duration _duration=Duration(seconds: 4); 7 | 8 | PinSnackBar(this._text,[_duration,]); 9 | 10 | SnackBar get(){ 11 | return SnackBar( 12 | duration: _duration, 13 | content: Text(_text,style: TextStyle(color: Colors.white,fontFamily: "Iran_Sans"),), 14 | behavior: SnackBarBehavior.floating, 15 | backgroundColor: Colors.red, 16 | ); 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /lib/components/detail/milk_chart.dart: -------------------------------------------------------------------------------- 1 | /// Example of a simple line chart. 2 | import 'package:charts_flutter/flutter.dart' as charts; 3 | import 'package:flutter/material.dart'; 4 | 5 | class MilkChart extends StatelessWidget { 6 | final List seriesList; 7 | final bool animate; 8 | 9 | MilkChart(this.seriesList, {this.animate}); 10 | 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return new charts.LineChart(seriesList, animate: animate); 15 | } 16 | 17 | 18 | 19 | } 20 | 21 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/repositories/SettingRespository.dart: -------------------------------------------------------------------------------- 1 | import 'package:cattle/utils/SettingsProvider.dart'; 2 | import 'package:cattle/utils/api/ApiProvider.dart'; 3 | import 'package:cattle/utils/api/Response.dart'; 4 | 5 | class SettingRepository{ 6 | ApiProvider _apiProvider=ApiProvider(); 7 | 8 | Future get()async{ 9 | try{ 10 | var response= await _apiProvider.get("/v1/settings"); 11 | return Response.completed(SettingsData.fromJSON(response)); 12 | }catch(e){ 13 | return Response.error(e.toString()); 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() 4 | 5 | def plugins = new Properties() 6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') 7 | if (pluginsFile.exists()) { 8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } 9 | } 10 | 11 | plugins.each { name, path -> 12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() 13 | include ":$name" 14 | project(":$name").projectDir = pluginDirectory 15 | } 16 | -------------------------------------------------------------------------------- /lib/repositories/DashboardRespository.dart: -------------------------------------------------------------------------------- 1 | import 'package:cattle/models/Dashboard.dart'; 2 | import 'package:cattle/utils/api/ApiProvider.dart'; 3 | import 'package:cattle/utils/api/Response.dart'; 4 | 5 | class DashboardRespository{ 6 | ApiProvider _apiProvider=ApiProvider(); 7 | 8 | Future getDashboard()async{ 9 | try{ 10 | final response= await _apiProvider.get("/v1/dashboard"); 11 | return Response.completed(DashboardData.fromJSON(response)); 12 | }catch (e){ 13 | return Response.error(e.toString()); 14 | } 15 | 16 | } 17 | } -------------------------------------------------------------------------------- /lib/models/Dashboard.dart: -------------------------------------------------------------------------------- 1 | class DashboardData{ 2 | int total; 3 | int dry; 4 | int calved; 5 | int insemination; 6 | int milked; 7 | int heifer; 8 | int abortion; 9 | int bull; 10 | int cow; 11 | 12 | DashboardData({this.total}); 13 | 14 | DashboardData.fromJSON(Map json) 15 | : total = json["total"], 16 | dry = json["dry"], 17 | calved = json["calved"], 18 | insemination = json["insemination"], 19 | milked = json["milked"], 20 | heifer = json["heifer"], 21 | abortion = json["abortion"], 22 | bull = json["bull"], 23 | cow = json["cow"] 24 | ; 25 | } -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/app.flx 22 | Flutter/app.zip 23 | Flutter/flutter_assets/ 24 | Flutter/flutter_export_environment.sh 25 | ServiceDefinitions.json 26 | Runner/GeneratedPluginRegistrant.* 27 | 28 | # Exceptions to above rules. 29 | !default.mode1v3 30 | !default.mode2v3 31 | !default.pbxuser 32 | !default.perspectivev3 33 | -------------------------------------------------------------------------------- /lib/repositories/UserRepository.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:cattle/models/User.dart'; 3 | import 'package:cattle/utils/api/ApiProvider.dart'; 4 | import 'package:cattle/utils/api/CustomException.dart'; 5 | import 'package:cattle/utils/api/Response.dart'; 6 | 7 | class UserRepository{ 8 | ApiProvider _provider = ApiProvider(); 9 | 10 | Future getMe()async{ 11 | 12 | try{ 13 | final response =await _provider.get("/v1/users/me"); 14 | return Response.completed(User.fromJSON(response)); 15 | }on FetchDataException catch(e){ 16 | return Response.error(e.toString()); 17 | }catch ( e){ 18 | print(e); 19 | return null; 20 | 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /lib/widgets/fab_bottom_navigation/pin_image.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:cached_network_image/cached_network_image.dart'; 3 | import 'package:cattle/utils/PinConfig.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class PinImage extends StatelessWidget { 7 | 8 | final String url; 9 | 10 | PinImage({this.url}); 11 | @override 12 | Widget build(BuildContext context) { 13 | 14 | return Container( 15 | child: CachedNetworkImage( 16 | placeholder: (context, url) => CircularProgressIndicator(), 17 | imageUrl: 'http://${PinConfig.IP}:${PinConfig.PORT}$url', 18 | errorWidget: (context, url, error) => Icon(Icons.error), 19 | ), 20 | ); 21 | } 22 | } -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.3.50' 3 | repositories { 4 | google() 5 | jcenter() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:3.5.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | jcenter() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | } 25 | subprojects { 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | .dart_tool/ 26 | .flutter-plugins 27 | .flutter-plugins-dependencies 28 | .packages 29 | .pub-cache/ 30 | .pub/ 31 | /build/ 32 | 33 | # Web related 34 | lib/generated_plugin_registrant.dart 35 | 36 | # Exceptions to above rules. 37 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 38 | -------------------------------------------------------------------------------- /lib/models/livestock.dart: -------------------------------------------------------------------------------- 1 | 2 | 3 | import 'package:persian_date/persian_date.dart'; 4 | 5 | class Livestock{ 6 | String id; 7 | String tagNo; 8 | String birthDate; 9 | String lastStateDate; 10 | String gender; 11 | String mother; 12 | String inseminator; 13 | String state; 14 | String userId; 15 | 16 | Livestock({this.tagNo,this.birthDate,this.gender,this.mother,this.inseminator,this.state,this.userId}); 17 | 18 | Livestock.fromJSON(Map json) 19 | : tagNo=json["tagNo"], 20 | id=json["_id"], 21 | birthDate=json["birthDate"]!=null?json["birthDate"]:"", 22 | lastStateDate=json["lastStateDate"]!=null?json["lastStateDate"]:"", 23 | gender=json["gender"], 24 | mother=json["mother"], 25 | inseminator=json["inseminator"], 26 | state=json["state"], 27 | userId=json["user_id"]; 28 | } 29 | -------------------------------------------------------------------------------- /lib/repositories/AuthRepository.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:cattle/models/LoginResponse.dart'; 3 | import 'package:cattle/utils/api/ApiProvider.dart'; 4 | import 'package:cattle/utils/api/Response.dart'; 5 | 6 | class AuthRepository{ 7 | ApiProvider _apiProvider=ApiProvider(); 8 | 9 | Future postUser(body)async{ 10 | try{ 11 | final response = await _apiProvider.post("/v1/auth/phone",body); 12 | return Response.completed( response); 13 | }catch (e){ 14 | return Response.error(e.toString()); 15 | } 16 | } 17 | 18 | Future postCode(body)async{ 19 | try{ 20 | final response = await _apiProvider.post("/v1/auth/code",body); 21 | print(response.runtimeType); 22 | return Response.completed( LoginResponse.fromJSON( response)); 23 | }catch (e){ 24 | return Response.error(e.toString()); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /lib/utils/api/CustomException.dart: -------------------------------------------------------------------------------- 1 | 2 | class CustomException implements Exception { 3 | final _message; 4 | final _prefix; 5 | 6 | CustomException([this._message, this._prefix]); 7 | 8 | String toString() { 9 | return "$_prefix$_message"; 10 | } 11 | } 12 | 13 | class FetchDataException extends CustomException { 14 | FetchDataException([String message]) 15 | : super(message, "Error During Communication: "); 16 | } 17 | 18 | class BadRequestException extends CustomException { 19 | BadRequestException([message]) : super(message, "Invalid Request: "); 20 | } 21 | 22 | class UnauthorisedException extends CustomException { 23 | UnauthorisedException([message]) : super(message, "Unauthorised: "); 24 | } 25 | 26 | class InvalidInputException extends CustomException { 27 | InvalidInputException([String message]) : super(message, "Invalid Input: "); 28 | } 29 | 30 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /lib/models/LocaleModel.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | import 'package:flutter_secure_storage/flutter_secure_storage.dart'; 3 | 4 | class LocaleModel extends ChangeNotifier{ 5 | String _locale="en"; 6 | 7 | void set(String l){ 8 | _locale=l; 9 | 10 | FlutterSecureStorage storage = FlutterSecureStorage(); 11 | storage.write(key: "locale",value: l); 12 | 13 | notifyListeners(); 14 | } 15 | 16 | String get(){ 17 | return _locale; 18 | } 19 | 20 | initLocalFromStorage()async{ 21 | FlutterSecureStorage storage = FlutterSecureStorage(); 22 | String locale=await storage.read(key: "locale"); 23 | if(locale==null){ 24 | set("en"); 25 | }else{ 26 | set(locale); 27 | } 28 | } 29 | } 30 | 31 | class Language{ 32 | String code; 33 | String name; 34 | 35 | Language(this.code,this.name); 36 | 37 | static isRtl(context){ 38 | return Localizations.localeOf(context).languageCode=="fa"; 39 | } 40 | } 41 | 42 | List languageList= [Language("en","English"),Language("fa","فارسی")]; -------------------------------------------------------------------------------- /lib/components/settings/language.dart: -------------------------------------------------------------------------------- 1 | import 'package:cattle/models/LocaleModel.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; 4 | import 'package:settings_ui/settings_ui.dart'; 5 | 6 | class ChangeLanguagePage extends StatelessWidget { 7 | 8 | List _languageList; 9 | Function _chooseLanguage; 10 | 11 | ChangeLanguagePage(this._languageList,this._chooseLanguage); 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return Scaffold( 16 | appBar: AppBar( 17 | title: Text(AppLocalizations.of(context).setting_language), 18 | ), 19 | body: SettingsList( 20 | sections: [ 21 | SettingsSection( 22 | title: '', 23 | tiles: _languageList.map((e) { 24 | return SettingsTile( 25 | title: e.name, 26 | onTap: () { 27 | _chooseLanguage(e); 28 | Navigator.pop(context); 29 | }, 30 | ); 31 | }).toList() 32 | ), 33 | ], 34 | ), 35 | ); 36 | } 37 | } -------------------------------------------------------------------------------- /test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:cattle/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(CattleApp()); 17 | 18 | // Verify that our counter starts at 0. 19 | expect(find.text('0'), findsOneWidget); 20 | expect(find.text('1'), findsNothing); 21 | 22 | // Tap the '+' icon and trigger a frame. 23 | await tester.tap(find.byIcon(Icons.add)); 24 | await tester.pump(); 25 | 26 | // Verify that our counter has incremented. 27 | expect(find.text('0'), findsNothing); 28 | expect(find.text('1'), findsOneWidget); 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /lib/components/newAnimal/input.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class Input extends StatelessWidget { 4 | 5 | final TextEditingController _controller; 6 | final String _label; 7 | final Function _onTab; 8 | final bool _enable; 9 | final _focus; 10 | final Function _changeFieldFocus; 11 | final bool _isLastItem; 12 | Input(this._label,this._controller,this._onTab,this._enable,this._focus,this._changeFieldFocus,this._isLastItem); 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return InkWell( 17 | onTap: _onTab, 18 | child:TextFormField( 19 | textInputAction: _isLastItem?TextInputAction.done:TextInputAction.next, 20 | onFieldSubmitted: _changeFieldFocus, 21 | focusNode: _focus, 22 | enabled: _enable, 23 | onTap: _onTab, 24 | controller: _controller, 25 | decoration: InputDecoration( 26 | border: OutlineInputBorder( 27 | borderRadius: BorderRadius.all(Radius.circular(10)) 28 | ), 29 | labelText: _label, 30 | ), 31 | validator: (value) { 32 | if (value.isEmpty) { 33 | return 'Please enter some text'; 34 | } 35 | return null; 36 | }, 37 | ), 38 | ); 39 | } 40 | } -------------------------------------------------------------------------------- /lib/utils/SettingsProvider.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:flutter/widgets.dart'; 4 | 5 | class SettingsProvider extends ChangeNotifier{ 6 | static final SettingsProvider _instance= SettingsProvider._internal(); 7 | SettingsData _data; 8 | 9 | 10 | SettingsProvider._internal(); 11 | 12 | factory SettingsProvider(){ 13 | return _instance; 14 | } 15 | 16 | setSettings(SettingsData d){ 17 | _data=d; 18 | } 19 | 20 | SettingsData getSettings(){ 21 | return _data; 22 | } 23 | 24 | } 25 | 26 | class SettingsData{ 27 | List livestockState; 28 | List livestockType; 29 | 30 | SettingsData({this.livestockState,this.livestockType}); 31 | 32 | SettingsData.fromJSON(Map json) 33 | : livestockState=json["livestock_state"]!=null?(json["livestock_state"] as List).map((e) => SettingValueTitle.fromJSON(e) ).toList():null, 34 | livestockType=json["livestock_type"]!=null?(json["livestock_type"] as List).map((e) => SettingValueTitle.fromJSON(e)).toList():null; 35 | } 36 | 37 | class SettingValueTitle{ 38 | String value; 39 | String title; 40 | 41 | SettingValueTitle.fromJSON(Map json) 42 | : value=json["name"], 43 | title=jsonEncode(json["title"]); 44 | } 45 | 46 | 47 | -------------------------------------------------------------------------------- /lib/widgets/confirm_dialog.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; 3 | 4 | class ConfirmDialog extends StatelessWidget { 5 | 6 | final Function _confirmDelete; 7 | final String _title; 8 | final String _description; 9 | final dynamic item; 10 | 11 | ConfirmDialog(this._confirmDelete,this._title,this._description,{this.item}); 12 | 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | 17 | Widget cancelButton = FlatButton( 18 | child: Text(AppLocalizations.of(context).confirm_dialog_no,style: TextStyle(color: Colors.black),), 19 | onPressed: () { 20 | Navigator.of(context).pop(); 21 | }, 22 | ); 23 | Widget continueButton = FlatButton( 24 | child: Text(AppLocalizations.of(context).confirm_dialog_yes,style: TextStyle(color: Colors.black),), 25 | onPressed: (){ 26 | if(item!=null){ 27 | print(1); 28 | _confirmDelete(item); 29 | }else{ 30 | print(2); 31 | _confirmDelete(); 32 | } 33 | }, 34 | ); 35 | 36 | // set up the AlertDialog 37 | AlertDialog alert = AlertDialog( 38 | title: Text(_title), 39 | content: Text(_description), 40 | actions: [ 41 | cancelButton, 42 | continueButton, 43 | ], 44 | ); 45 | 46 | return alert; 47 | } 48 | } -------------------------------------------------------------------------------- /lib/components/newAnimal/drop_down.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class DropDown extends StatelessWidget { 4 | final String value; 5 | final String hint; 6 | 7 | final List> items; 8 | final Function onChanged; 9 | 10 | final focus; 11 | final Function changeFieldFocus; 12 | 13 | const DropDown( 14 | {Key key, 15 | this.value, 16 | this.hint, 17 | this.items, 18 | this.onChanged, 19 | this.focus, 20 | this.changeFieldFocus 21 | }) 22 | : super(key: key); 23 | 24 | @override 25 | Widget build(BuildContext context) { 26 | return Column( 27 | crossAxisAlignment: CrossAxisAlignment.start, 28 | children: [ 29 | Container( 30 | decoration: BoxDecoration( 31 | border: Border.all(color: Theme.of(context).primaryColor), 32 | // color: Colors.grey[100], 33 | borderRadius: BorderRadius.circular(10) 34 | ), 35 | child: Padding( 36 | padding: 37 | const EdgeInsets.only(left: 15, right: 15, top: 10, bottom: 5), 38 | child: DropdownButton( 39 | focusNode: focus, 40 | value: value, 41 | hint: Text( 42 | hint, 43 | ), 44 | items:items, 45 | onChanged: (item) { 46 | onChanged(item); 47 | }, 48 | isExpanded: true, 49 | underline: Container(), 50 | icon: Icon(Icons.chevron_right), 51 | ), 52 | ), 53 | ), 54 | 55 | ], 56 | ); 57 | } 58 | } -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | pin_cattle 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 9 | 13 | 20 | 21 | 22 | 23 | 24 | 25 | 27 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /lib/components/detail/detail_card_actions.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_svg/flutter_svg.dart'; 3 | 4 | class DetailCardAction extends StatelessWidget { 5 | 6 | final Color _color; 7 | final Color _imageColor; 8 | final Function _onTab; 9 | final String _image; 10 | final String _title; 11 | 12 | DetailCardAction(this._color,this._onTab,this._title,this._image,this._imageColor); 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return Container( 17 | width: 140, 18 | child:Card( 19 | clipBehavior: Clip.antiAlias, 20 | color: _color, 21 | shape: RoundedRectangleBorder( 22 | borderRadius: BorderRadius.circular(20.0), 23 | ), 24 | child: InkWell( 25 | onTap: _onTab, 26 | child: Padding( 27 | padding: EdgeInsets.all(20), 28 | child: Column( 29 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 30 | crossAxisAlignment: CrossAxisAlignment.start, 31 | children: [ 32 | Flexible( 33 | flex: 2, 34 | child: Container( 35 | height: 60, 36 | width: 60, 37 | // color: Colors.black, 38 | child: SvgPicture.asset(_image ,color: _imageColor,fit: BoxFit.cover,), 39 | ), 40 | ), 41 | Flexible( 42 | flex: 1, 43 | child: Text(_title,style: TextStyle(color: _imageColor,fontSize: 15,fontWeight:FontWeight.bold)), 44 | ) 45 | ], 46 | ), 47 | ) 48 | ), 49 | ) , 50 | ); 51 | } 52 | } -------------------------------------------------------------------------------- /lib/components/settings/settings.dart: -------------------------------------------------------------------------------- 1 | import 'package:cattle/components/login/login_page.dart'; 2 | import 'package:cattle/components/settings/language.dart'; 3 | import 'package:cattle/models/LocaleModel.dart'; 4 | import 'package:cattle/utils/api/ApiProvider.dart'; 5 | import 'package:flutter/material.dart'; 6 | import 'package:provider/provider.dart'; 7 | import 'package:settings_ui/settings_ui.dart'; 8 | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; 9 | 10 | class Settings extends StatefulWidget { 11 | @override 12 | _SettingsState createState() => _SettingsState(); 13 | } 14 | 15 | class _SettingsState extends State { 16 | @override 17 | Widget build(BuildContext context) { 18 | return SettingsList( 19 | sections: [ 20 | SettingsSection( 21 | title: AppLocalizations.of(context).setting_common_section, 22 | tiles: [ 23 | SettingsTile( 24 | title: AppLocalizations.of(context).setting_language, 25 | subtitle: languageList.where((Language element) =>element.code==Localizations.localeOf(context).languageCode).first.name, 26 | leading: Icon(Icons.language), 27 | onTap: () { 28 | Navigator.push(context, MaterialPageRoute(builder: (context)=>ChangeLanguagePage(languageList,(e)=>Provider.of(context, listen: false).set(e.code)))); 29 | }, 30 | ), 31 | SettingsTile( 32 | title:AppLocalizations.of(context).setting_sign_out, 33 | leading: Icon(Icons.exit_to_app), 34 | onTap: () { 35 | ApiProvider().emptyToken(); 36 | Navigator.pushReplacement(context, MaterialPageRoute(builder: (context)=>LoginPage())); 37 | }, 38 | ), 39 | ], 40 | ), 41 | ], 42 | ); 43 | } 44 | } -------------------------------------------------------------------------------- /assets/images/milk-bottle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /assets/images/milking.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/heart.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | android { 29 | compileSdkVersion 28 30 | 31 | sourceSets { 32 | main.java.srcDirs += 'src/main/kotlin' 33 | } 34 | 35 | lintOptions { 36 | disable 'InvalidPackage' 37 | } 38 | 39 | defaultConfig { 40 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 41 | applicationId "com.example.pin_cattle" 42 | minSdkVersion 18 43 | targetSdkVersion 28 44 | versionCode flutterVersionCode.toInteger() 45 | versionName flutterVersionName 46 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 47 | } 48 | 49 | buildTypes { 50 | release { 51 | // TODO: Add your own signing config for the release build. 52 | // Signing with the debug keys for now, so `flutter run --release` works. 53 | signingConfig signingConfigs.debug 54 | } 55 | } 56 | } 57 | 58 | flutter { 59 | source '../..' 60 | } 61 | 62 | dependencies { 63 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 64 | testImplementation 'junit:junit:4.12' 65 | androidTestImplementation 'androidx.test:runner:1.1.1' 66 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' 67 | } 68 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /lib/components/dashboard/summary_card.dart: -------------------------------------------------------------------------------- 1 | import 'package:cattle/models/LocaleModel.dart'; 2 | import "package:flutter/material.dart"; 3 | 4 | class SummaryCard extends StatelessWidget { 5 | 6 | final int _index; 7 | final String _title; 8 | final dynamic _count; 9 | final Function _onTab; 10 | SummaryCard(this._index,this._title,this._count,this._onTab); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | 15 | return Container( 16 | margin: EdgeInsets.all(1), 17 | decoration: BoxDecoration( 18 | color: Colors.white, 19 | borderRadius: BorderRadius.only( 20 | topLeft: Language.isRtl(context)? (_index==2?Radius.circular(10): Radius.circular(0)):(_index==0?Radius.circular(10): Radius.circular(0)), 21 | topRight:Language.isRtl(context)? (_index==0?Radius.circular(10): Radius.circular(0)):(_index==2?Radius.circular(10): Radius.circular(0)), 22 | bottomLeft: Language.isRtl(context)?(_index==5?Radius.circular(10): Radius.circular(0)):(_index==3?Radius.circular(10): Radius.circular(0)), 23 | bottomRight: Language.isRtl(context)?(_index==3?Radius.circular(10): Radius.circular(0)):(_index==5?Radius.circular(10): Radius.circular(0)), 24 | ), 25 | boxShadow: [ 26 | BoxShadow( 27 | color: Colors.grey[200], 28 | blurRadius: 1, 29 | spreadRadius: .5, 30 | offset: Offset( 31 | -2, 32 | 1 33 | ) 34 | ) 35 | ] 36 | ), 37 | child:InkWell( 38 | onTap: _onTab, 39 | child: Column( 40 | mainAxisSize: MainAxisSize.max, 41 | children: [ 42 | Flexible( 43 | child:Container( 44 | padding: EdgeInsets.only( 45 | left: 11, 46 | right: 11, 47 | top: 7, 48 | bottom: 4 49 | ), 50 | margin: EdgeInsets.only( 51 | top:10, 52 | bottom: 5 53 | ), 54 | decoration: BoxDecoration( 55 | color: Color(0xff39445a), 56 | borderRadius: BorderRadius.circular(90) 57 | ), 58 | child: Text(_count=="null"?"":_count,style: TextStyle(color: Colors.white),overflow: TextOverflow.ellipsis,), 59 | ), 60 | flex: 2, 61 | ), 62 | Flexible( 63 | child: Container( 64 | child: Center(child: Text(_title,style: Theme.of(context).textTheme.subtitle2,)) , 65 | ), 66 | flex: 1, 67 | ) 68 | ], 69 | ), 70 | ) 71 | 72 | ); 73 | } 74 | } -------------------------------------------------------------------------------- /lib/widgets/fab_bottom_navigation/fab_bottom_app_bar.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class FABBottomAppBarItem { 4 | FABBottomAppBarItem({this.iconData, this.text}); 5 | IconData iconData; 6 | String text; 7 | } 8 | 9 | 10 | class FabBottomAppBar extends StatefulWidget { 11 | FabBottomAppBar({ 12 | this.items, 13 | this.centerItemText, 14 | this.height: 60.0, 15 | this.iconSize: 24.0, 16 | this.backgroundColor, 17 | this.color, 18 | this.selectedColor, 19 | this.onTabSelected, 20 | }); 21 | final List items; 22 | final String centerItemText; 23 | final double height; 24 | final double iconSize; 25 | final Color backgroundColor; 26 | final Color color; 27 | final Color selectedColor; 28 | final ValueChanged onTabSelected; 29 | @override 30 | _FabBottomAppBarState createState() => _FabBottomAppBarState(); 31 | } 32 | 33 | class _FabBottomAppBarState extends State { 34 | 35 | int _selectedIndex = 0; 36 | 37 | _updateIndex(int index){ 38 | widget.onTabSelected(index); 39 | setState(() { 40 | _selectedIndex = index; 41 | }); 42 | } 43 | 44 | @override 45 | Widget build(BuildContext context) { 46 | 47 | List items = List.generate(widget.items.length, (int index){ 48 | return _buildTabItem( 49 | item:widget.items[index], 50 | index:index, 51 | onPressed:_updateIndex 52 | ); 53 | }); 54 | 55 | return BottomAppBar( 56 | 57 | shape: CircularNotchedRectangle(), 58 | child: Container( 59 | child: Row( 60 | mainAxisSize: MainAxisSize.max, 61 | mainAxisAlignment: MainAxisAlignment.spaceAround, 62 | children: items, 63 | ), 64 | ), 65 | ); 66 | } 67 | 68 | Widget _buildTabItem({ 69 | FABBottomAppBarItem item, 70 | int index, 71 | ValueChanged onPressed, 72 | }) { 73 | Color color = _selectedIndex == index ? widget.selectedColor : widget.color; 74 | return Expanded( 75 | child: SizedBox( 76 | height: widget.height, 77 | child: Material( 78 | type: MaterialType.transparency, 79 | child: InkWell( 80 | onTap: () => onPressed(index), 81 | child: Column( 82 | mainAxisSize: MainAxisSize.min, 83 | mainAxisAlignment: MainAxisAlignment.center, 84 | children: [ 85 | Icon(item.iconData, color: color, size: widget.iconSize), 86 | item.text!=""? 87 | Text( 88 | item.text, 89 | style: TextStyle(color: color), 90 | ):Container() 91 | ], 92 | ), 93 | ), 94 | ), 95 | ), 96 | ); 97 | } 98 | } -------------------------------------------------------------------------------- /lib/components/dashboard/main_dashboard_card.dart: -------------------------------------------------------------------------------- 1 | import 'package:cattle/models/LocaleModel.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_svg/flutter_svg.dart'; 4 | class MainDashboardCard extends StatelessWidget { 5 | 6 | final Color _color; 7 | final String _count; 8 | final String _title; 9 | final String _image; 10 | final Function _onTab; 11 | 12 | MainDashboardCard(this._color,this._count,this._title,this._image,this._onTab); 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return Card( 17 | clipBehavior: Clip.antiAlias, 18 | color: _color, 19 | shape: RoundedRectangleBorder( 20 | borderRadius: BorderRadius.circular(20.0), 21 | ), 22 | child: InkWell( 23 | onTap: _onTab, 24 | child: Column( 25 | crossAxisAlignment: CrossAxisAlignment.start, 26 | children: [ 27 | Container( 28 | padding: EdgeInsets.all(15), 29 | child: Column( 30 | crossAxisAlignment: CrossAxisAlignment.start, 31 | mainAxisAlignment: MainAxisAlignment.start, 32 | children: [ 33 | Text(_count=="null"?"":_count,style: Theme.of(context).textTheme.headline4), 34 | Text(_title.toString(),style: Theme.of(context).textTheme.headline4) 35 | ], 36 | ), 37 | ), 38 | Expanded( 39 | child:Row( 40 | mainAxisSize: MainAxisSize.max, 41 | children: [ 42 | Flexible( 43 | child: Container(), 44 | flex: 2, 45 | ), 46 | Flexible( 47 | flex: 3, 48 | child: Container( 49 | padding: EdgeInsets.fromLTRB( 50 | Language.isRtl(context) ?10:30, 10,Language.isRtl(context)?30: 10, 0 51 | ), 52 | width: double.infinity, 53 | height: double.infinity, 54 | decoration: BoxDecoration( 55 | color: Colors.white, 56 | borderRadius: BorderRadius.only( 57 | topLeft: Language.isRtl(context)?Radius.zero : Radius.circular(100), 58 | topRight: Language.isRtl(context)? Radius.circular(100):Radius.zero, 59 | ) 60 | ), 61 | child: SvgPicture.asset(_image,fit:BoxFit.contain ,color: _color,), 62 | ), 63 | ) 64 | ], 65 | ), 66 | ) 67 | 68 | ], 69 | ), 70 | ) 71 | ); 72 | } 73 | } -------------------------------------------------------------------------------- /lib/components/splash/splash_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:cattle/components/login/login_page.dart'; 2 | import 'package:cattle/home.dart'; 3 | import 'package:cattle/models/LocaleModel.dart'; 4 | import 'package:cattle/repositories/SettingRespository.dart'; 5 | import 'package:cattle/repositories/UserRepository.dart'; 6 | import 'package:cattle/utils/SettingsProvider.dart'; 7 | import 'package:cattle/utils/api/Response.dart'; 8 | import 'package:cattle/widgets/PinSnackBar.dart'; 9 | import 'package:flutter/material.dart'; 10 | import 'package:provider/provider.dart'; 11 | 12 | class SplashPage extends StatefulWidget { 13 | const SplashPage({Key key}) : super(key: key); 14 | @override 15 | _SplashPageState createState() => _SplashPageState(); 16 | } 17 | 18 | class _SplashPageState extends State { 19 | 20 | final GlobalKey _scaffoldKey = GlobalKey(); 21 | UserRepository _userRepository; 22 | SettingRepository _settingRepository; 23 | 24 | _SplashPageState(){ 25 | _userRepository=new UserRepository(); 26 | _settingRepository=new SettingRepository(); 27 | } 28 | 29 | @override 30 | void initState() { 31 | 32 | super.initState(); 33 | checkToken(); 34 | // new Future.delayed(const Duration(milliseconds: 500), checkToken); 35 | 36 | // var response= Http().get("/v1/users/me"); 37 | // if (response.statusCode) 38 | 39 | 40 | // Provider.of(context, listen: false).isAlreadyAuthenticated().then((result) { 41 | // if (result) { 42 | // Navigator.of(context).pushAndRemoveUntil(MaterialPageRoute(builder: (_) => const HomePage()), (Route route) => false); 43 | // } else { 44 | // } 45 | // }); 46 | } 47 | checkToken()async{ 48 | var response=await _userRepository.getMe(); 49 | if(response!=null){ 50 | 51 | Response response=await _settingRepository.get(); 52 | SettingsProvider().setSettings(response.data); 53 | 54 | Provider.of(context,listen: false).initLocalFromStorage(); 55 | 56 | if(response.status==Status.COMPLETED){ 57 | Navigator.pushReplacement( 58 | context, 59 | MaterialPageRoute(builder: (context) => HomePage()), 60 | ); 61 | }else{ 62 | _scaffoldKey.currentState.showSnackBar(PinSnackBar(response.message).get()); 63 | // doStuffCallback(); 64 | } 65 | 66 | }else{ 67 | doStuffCallback(); 68 | } 69 | } 70 | 71 | doStuffCallback(){ 72 | Navigator.of(context).pushAndRemoveUntil(MaterialPageRoute(builder: (_) => const LoginPage()), (Route route) => false); 73 | } 74 | 75 | @override 76 | Widget build(BuildContext context) { 77 | return Scaffold( 78 | key: _scaffoldKey, 79 | backgroundColor: Theme.of(context).primaryColor, 80 | body: Center( 81 | child: Image.asset("assets/images/splash.png",width: MediaQuery.of(context).size.width/3,), 82 | ), 83 | ); 84 | } 85 | } -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:cattle/components/splash/splash_page.dart'; 4 | import 'package:cattle/models/LocaleModel.dart'; 5 | import 'package:cattle/utils/api/ApiProvider.dart'; 6 | import 'package:flutter/material.dart'; 7 | import 'package:provider/provider.dart'; 8 | import 'package:sentry/sentry.dart'; 9 | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; // Add this line. 10 | 11 | // final sentry = SentryClient(dsn: "https://bd54fe34ae6842839c652a7ab201b220@o459244.ingest.sentry.io/5458076"); 12 | 13 | Future main() async{ 14 | 15 | WidgetsFlutterBinding.ensureInitialized(); 16 | 17 | ApiProvider apiProvider=new ApiProvider(); 18 | await apiProvider.init(); 19 | runApp(CattleApp()); 20 | // runZonedGuarded( 21 | // () async{ 22 | 23 | // }, 24 | // (error, stackTrace) async { 25 | // // await sentry.captureException( 26 | // // exception: error, 27 | // // stackTrace: stackTrace, 28 | // // ); 29 | // }, 30 | // ); 31 | 32 | 33 | } 34 | 35 | class CattleApp extends StatelessWidget { 36 | 37 | // This widget is the root of your application. 38 | @override 39 | Widget build(BuildContext context) { 40 | return ChangeNotifierProvider( 41 | create: (context)=>LocaleModel(), 42 | child: Consumer( 43 | builder: (context,locale,child)=>MaterialApp( 44 | localizationsDelegates: AppLocalizations.localizationsDelegates, 45 | supportedLocales: AppLocalizations.supportedLocales, 46 | locale:Locale(locale.get()) , 47 | title: 'Flutter Demo', 48 | theme: ThemeData( 49 | 50 | fontFamily: "Iran_Sans", 51 | // This is the theme of your application. 52 | // 53 | // Try running your application with "flutter run". You'll see the 54 | // application has a blue toolbar. Then, without quitting the app, try 55 | // changing the primarySwatch below to Colors.green and then invoke 56 | // "hot reload" (press "r" in the console where you ran "flutter run", 57 | // or simply save your changes to "hot reload" in a Flutter IDE). 58 | // Notice that the counter didn't reset back to zero; the application 59 | // is not restarted. 60 | primaryColor: Color(0xFF39445a), 61 | accentColor: Color(0xFF369ee5), 62 | scaffoldBackgroundColor: Color(0xFFf8f9fe), 63 | primarySwatch: Colors.blue, 64 | textTheme: TextTheme( 65 | headline4: TextStyle(color: Colors.white,fontWeight: FontWeight.bold,fontSize: 13), 66 | headline3: TextStyle(color: Colors.black,fontWeight: FontWeight.bold,fontSize: 15), 67 | headline2: TextStyle(color: Colors.grey[700],fontWeight: FontWeight.bold,fontSize: 15), 68 | headline1: TextStyle(color: Colors.black,fontSize: 20),//detail 69 | 70 | button:TextStyle(color: Colors.white,fontWeight: FontWeight.bold,fontSize: 20) , 71 | 72 | subtitle2:TextStyle(color: Colors.black,fontSize: 13) 73 | ) 74 | 75 | ), 76 | home: new Scaffold(body:SplashPage(),) 77 | ), 78 | ) 79 | , 80 | ); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Cattle Management App written in Flutter.It uses Nestjs as backend([Link](https://github.com/k2288/cattle-back)) and also a design implementation of [Best Cattle Management App](https://dribbble.com/shots/10497109-Best-Cattle-Management-App) and [Cow milk](https://dribbble.com/shots/13081526-Cow-milk) as app launcher. 2 | 3 | 4 | ## Android Screenshots 5 | 6 | HomePage | Animals List | Filter list 7 | :-------------------------:|:-------------------------:|:-------------------------: 8 | ![](https://github.com/k2288/cattle/blob/master/ss/flutter_01.png?raw=true)|![](https://github.com/k2288/cattle/blob/master/ss/flutter_02.png?raw=true)|![](https://github.com/k2288/cattle/blob/master/ss/flutter_05.png?raw=true) 9 | 10 | Animal Detail | Create | Add State 11 | :-------------------------:|:-------------------------:|:-------------------------: 12 | ![](https://github.com/k2288/cattle/blob/master/ss/flutter_03.png?raw=true)|![](https://github.com/k2288/cattle/blob/master/ss/flutter_06.png?raw=true)|![](https://github.com/k2288/cattle/blob/master/ss/flutter_07.png?raw=true) 13 | 14 | Settings | 15 | :-------------------------:| 16 | ![](https://github.com/k2288/cattle/blob/master/ss/flutter_04.png?raw=true)| 17 | 18 | ## iOS Screenshots 19 | Coming soon 20 | ## Directory Structure 21 | ``` 22 | lib 23 | ├── components 24 | │   ├── dashboard 25 | │   │   ├── dashboard.dart 26 | │   │   ├── main_dashboard_card.dart 27 | │   │   └── summary_card.dart 28 | │   ├── detail 29 | │   │   ├── detail_card_actions.dart 30 | │   │   ├── detail.dart 31 | │   │   ├── milk_chart.dart 32 | │   │   └── state_dialog.dart 33 | │   ├── list 34 | │   │   ├── filter.dart 35 | │   │   └── list.dart 36 | │   ├── login 37 | │   │   ├── login_page.dart 38 | │   │   └── otp_page.dart 39 | │   ├── newAnimal 40 | │   │   ├── drop_down.dart 41 | │   │   ├── input.dart 42 | │   │   └── new-animal.dart 43 | │   ├── settings 44 | │   │   ├── language.dart 45 | │   │   └── settings.dart 46 | │   └── splash 47 | │   └── splash_page.dart 48 | ├── home.dart 49 | ├── l10n 50 | │   ├── app_en.arb 51 | │   └── app_fa.arb 52 | ├── main.dart 53 | ├── models 54 | │   ├── Dashboard.dart 55 | │   ├── livestock.dart 56 | │   ├── LivestockState.dart 57 | │   ├── LocaleModel.dart 58 | │   ├── LoginResponse.dart 59 | │   └── User.dart 60 | ├── repositories 61 | │   ├── AuthRepository.dart 62 | │   ├── DashboardRespository.dart 63 | │   ├── LivstockRespository.dart 64 | │   ├── SettingRespository.dart 65 | │   └── UserRepository.dart 66 | ├── utils 67 | │   ├── api 68 | │   │   ├── ApiProvider.dart 69 | │   │   ├── CustomException.dart 70 | │   │   └── Response.dart 71 | │   ├── DateUtil.dart 72 | │   ├── PinConfig.dart 73 | │   ├── SettingsProvider.dart 74 | │   └── theme.dart 75 | └── widgets 76 | ├── confirm_dialog.dart 77 | ├── fab_bottom_navigation 78 | │   ├── fab_bottom_app_bar.dart 79 | │   └── pin_image.dart 80 | └── PinSnackBar.dart 81 | 82 | ``` 83 | 84 | ## To Do 85 | - [ ] Add chat and medical section 86 | - [ ] Add notification 87 | - [ ] Complete settings 88 | - [ ] Add Scanning Animal Barcode Functionality 89 | 90 | ## Pull Requests 91 | 92 | I welcome and encourage all pull requests. It usually will take me within 24-48 hours to respond to any issue or request. 93 | -------------------------------------------------------------------------------- /lib/home.dart: -------------------------------------------------------------------------------- 1 | import 'package:barcode_scan/platform_wrapper.dart'; 2 | import 'package:cattle/components/dashboard/dashboard.dart'; 3 | import 'package:cattle/components/newAnimal/new-animal.dart'; 4 | import 'package:cattle/components/settings/settings.dart'; 5 | import 'package:cattle/widgets/fab_bottom_navigation/fab_bottom_app_bar.dart'; 6 | import 'package:flutter/material.dart'; 7 | import 'package:font_awesome_flutter/font_awesome_flutter.dart'; 8 | 9 | class HomePage extends StatefulWidget { 10 | HomePage({Key key}) : super(key: key); 11 | 12 | 13 | @override 14 | _HomePageState createState() => _HomePageState(); 15 | } 16 | 17 | class _HomePageState extends State { 18 | // int _selectedIndex = 0; 19 | PageController _pageController = PageController(initialPage: 0); 20 | 21 | void _onItemTapped(int index) { 22 | // _pageController.animateToPage(index,duration: Duration(milliseconds: 400),curve: Curves.easeInOut); 23 | _pageController.jumpToPage(index); 24 | } 25 | 26 | 27 | @override 28 | Widget build(BuildContext context) { 29 | 30 | return Scaffold( 31 | appBar: AppBar( 32 | actions: [ 33 | IconButton(icon: Icon(Icons.notifications_none,color: Colors.white,), onPressed: ()=>{}), 34 | IconButton(icon: Icon(FontAwesomeIcons.qrcode,color: Colors.white,), onPressed: _scaneBarcode), 35 | ], 36 | title: Text(" "), 37 | ), 38 | body: PageView( 39 | controller: _pageController, 40 | children: [ 41 | Center( 42 | child: Container( 43 | child: Dashboard(), 44 | ), 45 | ), 46 | Center( 47 | child: Container( 48 | child: Text('Coming Soon'), 49 | ), 50 | ), 51 | Center( 52 | child: Container( 53 | child: Text(''), 54 | ), 55 | ), 56 | Center( 57 | child: Container( 58 | child: Text('Coming Soon'), 59 | ), 60 | ), 61 | Center( 62 | child: Container( 63 | child: Settings(), 64 | ), 65 | ) 66 | ], 67 | physics: NeverScrollableScrollPhysics(), 68 | ), 69 | floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked, 70 | floatingActionButton: FloatingActionButton( 71 | onPressed: () {Navigator.push(context, MaterialPageRoute(builder: (context) => NewAnimal())); }, 72 | tooltip: '', 73 | child: Icon(Icons.add), 74 | elevation: 2.0, 75 | ), 76 | bottomNavigationBar: FabBottomAppBar( 77 | selectedColor: Theme.of(context).primaryColor, 78 | color: Colors.grey[500], 79 | onTabSelected: _onItemTapped, 80 | items: [ 81 | FABBottomAppBarItem(iconData: Icons.dashboard, text: ''), 82 | FABBottomAppBarItem(iconData: Icons.message, text: ''), 83 | FABBottomAppBarItem(iconData:null, text: ""), 84 | FABBottomAppBarItem(iconData: FontAwesomeIcons.userNurse, text: ''), 85 | FABBottomAppBarItem(iconData: Icons.settings, text: ''), 86 | ], 87 | ), 88 | 89 | ); 90 | } 91 | 92 | _scaneBarcode() async { 93 | var result = await BarcodeScanner.scan(); 94 | print(result.rawContent); 95 | 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /assets/images/total_cow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 18 | 19 | 20 | 21 | 22 | 25 | 26 | 27 | 28 | 29 | 32 | 33 | 34 | 35 | 36 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /assets/images/milk.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/repositories/LivstockRespository.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:cattle/models/LivestockState.dart'; 4 | import 'package:cattle/models/livestock.dart'; 5 | import 'package:cattle/utils/api/ApiProvider.dart'; 6 | import 'package:cattle/utils/api/Response.dart'; 7 | 8 | class LivestockRepository{ 9 | ApiProvider _apiProvider= ApiProvider(); 10 | 11 | Future postLivestock(body)async{ 12 | try{ 13 | final response= await _apiProvider.post("/v1/livestock",body); 14 | return Response.completed(Livestock.fromJSON(response)); 15 | 16 | }catch (e){ 17 | return Response.error(e.toString()); 18 | } 19 | } 20 | 21 | Future putLivestock(id,body)async{ 22 | try{ 23 | await _apiProvider.put("/v1/livestock/$id",body); 24 | var newBody=jsonDecode( body); 25 | newBody["_id"]=id; 26 | 27 | return Response.completed(Livestock.fromJSON(newBody)); 28 | 29 | }catch (e){ 30 | return Response.error(e.toString()); 31 | } 32 | } 33 | 34 | Future getLivestockList(params)async{ 35 | try{ 36 | final response=await _apiProvider.get("/v1/livestock",params); 37 | return Response.completed(LiveStockResponse.fromJSON(response)); 38 | }catch(e){ 39 | return Response.error(e.toString()); 40 | } 41 | } 42 | 43 | Future deleteLivestock(id)async{ 44 | try{ 45 | final response = await _apiProvider.delete("/v1/livestock/$id"); 46 | return Response.completed(Livestock.fromJSON(response)); 47 | }catch(e){ 48 | return Response.error(e.toString()); 49 | } 50 | } 51 | 52 | Future postState(id,body)async{ 53 | try{ 54 | final response = await _apiProvider.post("/v1/livestock/$id/state",jsonEncode(body)); 55 | return Response.completed(LivestockState.fromJSON(response)); 56 | }catch(e){ 57 | return Response.error(e.toString()); 58 | } 59 | } 60 | 61 | Future putState(id,body)async{ 62 | try{ 63 | final response = await _apiProvider.put("/v1/livestock/$id/state/${body['id']}",jsonEncode(body)); 64 | return Response.completed(response); 65 | }catch(e){ 66 | return Response.error(e.toString()); 67 | } 68 | } 69 | 70 | Future getStates(id,params)async{ 71 | try{ 72 | final response = await _apiProvider.get("/v1/livestock/$id/state",params); 73 | return Response.completed( LiveStockStateResponse.fromJSON(response)); 74 | }catch(e){ 75 | return Response.error(e.toString()); 76 | } 77 | } 78 | 79 | Future deleteLivestockState(id,stateId)async{ 80 | try{ 81 | final response = await _apiProvider.delete("/v1/livestock/$id/state/$stateId"); 82 | return Response.completed(Livestock.fromJSON(response)); 83 | }catch(e){ 84 | return Response.error(e.toString()); 85 | } 86 | } 87 | 88 | 89 | 90 | } 91 | 92 | class LiveStockResponse{ 93 | List contents; 94 | int totalElements; 95 | int offset; 96 | int pageSize; 97 | 98 | LiveStockResponse({this.contents}); 99 | 100 | LiveStockResponse.fromJSON(Map json) 101 | : contents=json["contents"]!=null?(json["contents"] as List).map((e) => Livestock.fromJSON(e)).toList():[], 102 | totalElements=json["totalElements"], 103 | offset=json["offset"], 104 | pageSize=json["pageSize"]; 105 | } 106 | 107 | class LiveStockStateResponse{ 108 | List contents; 109 | int totalElements; 110 | int offset; 111 | int pageSize; 112 | 113 | LiveStockStateResponse({this.contents}); 114 | 115 | LiveStockStateResponse.fromJSON(Map json) 116 | : contents=json["contents"]!=null?(json["contents"] as List).map((e) => LivestockState.fromJSON(e)).toList():[], 117 | totalElements=json["totalElements"], 118 | offset=json["offset"], 119 | pageSize=json["pageSize"]; 120 | } -------------------------------------------------------------------------------- /lib/components/list/filter.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:cattle/models/LocaleModel.dart'; 4 | import 'package:cattle/utils/SettingsProvider.dart'; 5 | import 'package:flutter/material.dart'; 6 | import 'package:chips_choice/chips_choice.dart'; 7 | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; 8 | 9 | class Filter extends StatefulWidget { 10 | 11 | final FilterData _data; 12 | 13 | Filter(this._data); 14 | 15 | @override 16 | _FilterState createState() => _FilterState(); 17 | } 18 | 19 | class _FilterState extends State { 20 | 21 | FilterData data=FilterData([],[]); 22 | 23 | @override 24 | void initState() { 25 | data=widget._data; 26 | super.initState(); 27 | } 28 | 29 | @override 30 | Widget build(BuildContext context) { 31 | return SingleChildScrollView( 32 | child: Container( 33 | padding: EdgeInsets.all(20), 34 | child: Column( 35 | children: [ 36 | Align( 37 | alignment: Language.isRtl(context) ? Alignment.centerRight:Alignment.centerLeft, 38 | child: Text(AppLocalizations.of(context).filter_state,style: Theme.of(context).textTheme.headline3), 39 | ), 40 | 41 | Align( 42 | alignment: Alignment.centerRight, 43 | child: ChipsChoice.multiple( 44 | value: data.states , 45 | options: ChipsChoiceOption.listFrom( 46 | source: SettingsProvider().getSettings().livestockState, 47 | value: (i, v) => v.value, 48 | label: (i, v) =>jsonDecode(v.title)[Localizations.localeOf(context).languageCode], 49 | ), 50 | onChanged: (val) => setState(() => data.states = val), 51 | isWrapped: true, 52 | 53 | ), 54 | ), 55 | // SizedBox(height: 10,), 56 | Align( 57 | alignment: Language.isRtl(context) ? Alignment.centerRight:Alignment.centerLeft, 58 | child: Text(AppLocalizations.of(context).filter_gender,style: Theme.of(context).textTheme.headline3), 59 | ), 60 | Align( 61 | alignment: Alignment.centerRight, 62 | child: ChipsChoice.multiple( 63 | value: data.type , 64 | options: ChipsChoiceOption.listFrom( 65 | source: SettingsProvider().getSettings().livestockType, 66 | value: (i, v) => v.value, 67 | label: (i, v) => jsonDecode(v.title)[Localizations.localeOf(context).languageCode], 68 | ), 69 | onChanged: (val) => setState(() => data.type = val), 70 | isWrapped: true, 71 | 72 | ), 73 | ), 74 | ButtonBar( 75 | 76 | buttonPadding: EdgeInsets.all(20), 77 | alignment: MainAxisAlignment.spaceAround, 78 | children: [ 79 | RaisedButton( 80 | color: Theme.of(context).primaryColor, 81 | padding: EdgeInsets.all(10), 82 | 83 | onPressed: (){ 84 | Navigator.of(context).pop(data); 85 | }, 86 | child: Text(AppLocalizations.of(context).filter_confirm,style: TextStyle(fontSize: 15),), 87 | ), 88 | RaisedButton( 89 | color: Theme.of(context).primaryColor, 90 | padding: EdgeInsets.all(10,), 91 | 92 | onPressed: (){ 93 | Navigator.of(context).pop(FilterData([],[])); 94 | }, 95 | child: Text(AppLocalizations.of(context).filter_clear,style: TextStyle(fontSize: 15),), 96 | ) 97 | ], 98 | ) 99 | ], 100 | ) 101 | ), 102 | ); 103 | } 104 | 105 | } 106 | 107 | class FilterData{ 108 | List states=[] ; 109 | List type=[] ; 110 | 111 | FilterData(this.states,this.type); 112 | 113 | } -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: cattle 2 | description: A new Flutter project. 3 | 4 | # The following defines the version and build number for your application. 5 | # A version number is three numbers separated by dots, like 1.2.43 6 | # followed by an optional build number separated by a +. 7 | # Both the version and the builder number may be overridden in flutter 8 | # build by specifying --build-name and --build-number, respectively. 9 | # In Android, build-name is used as versionName while build-number used as versionCode. 10 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 11 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 12 | # Read more about iOS versioning at 13 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 14 | version: 1.0.0+1 15 | 16 | environment: 17 | sdk: ">=2.1.0 <3.0.0" 18 | 19 | dependencies: 20 | flutter_svg: ^0.19.0 21 | font_awesome_flutter: ^8.8.1 22 | barcode_scan: ^3.0.0 23 | faker: ^1.2.1 24 | charts_flutter: ^0.9.0 25 | persian_date: ^0.1.5 26 | http: ^0.12.2 27 | flutter_config: ^1.0.7 28 | flutter_secure_storage: ^3.3.1+1 29 | cached_network_image: ^2.3.2+1 30 | timeago: ^2.0.27 31 | persian_datepicker: ^1.3.1 32 | flutter_icons: ^1.1.0 33 | chips_choice: ^1.2.0 34 | numeric_keyboard: ^1.0.0 35 | sentry: ">=3.0.0 <4.0.0" 36 | 37 | flutter: 38 | sdk: flutter 39 | flutter_localizations: 40 | sdk: flutter 41 | intl: ^0.16.1 # Add this line 42 | 43 | provider: ^3.0.0 44 | settings_ui: ^0.4.0 45 | 46 | 47 | 48 | # The following adds the Cupertino Icons font to your application. 49 | # Use with the CupertinoIcons class for iOS style icons. 50 | cupertino_icons: ^0.1.2 51 | 52 | dev_dependencies: 53 | flutter_test: 54 | sdk: flutter 55 | 56 | # For information on the generic Dart part of this file, see the 57 | # following page: https://dart.dev/tools/pub/pubspec 58 | # The following section is specific to Flutter. 59 | flutter: 60 | generate: true 61 | # The following line ensures that the Material Icons font is 62 | # included with your application, so that you can use the icons in 63 | # the material Icons class. 64 | uses-material-design: true 65 | 66 | # To add assets to your application, add an assets section, like this: 67 | assets: 68 | - assets/images/dry_cow.svg 69 | - assets/images/milk.svg 70 | - assets/images/milking_cow.svg 71 | - assets/images/total_cow.svg 72 | - assets/images/cow.jpeg 73 | - assets/images/milking.svg 74 | - assets/images/fertilization.svg 75 | 76 | - assets/images/state/bull.png 77 | - assets/images/state/calf.png 78 | - assets/images/state/cow.png 79 | - assets/images/state/heifer.png 80 | 81 | - assets/images/state/breeding.png 82 | - assets/images/state/calved.png 83 | - assets/images/state/onmilking.png 84 | - assets/images/state/pragnent.png 85 | - assets/images/state/weaned.png 86 | - assets/images/ 87 | 88 | # An image asset can refer to one or more resolution-specific "variants", see 89 | # https://flutter.dev/assets-and-images/#resolution-aware. 90 | # For details regarding adding assets from package dependencies, see 91 | # https://flutter.dev/assets-and-images/#from-packages 92 | # To add custom fonts to your application, add a fonts section here, 93 | # in this "flutter" section. Each entry in this list should have a 94 | # "family" key with the font family name, and a "fonts" key with a 95 | # list giving the asset and other descriptors for the font. For 96 | # example: 97 | fonts: 98 | - family: Iran_Sans 99 | fonts: 100 | - asset: assets/fonts/Iran_Sans.ttf 101 | # - asset: fonts/Schyler-Italic.ttf 102 | # style: italic 103 | # - family: Trajan Pro 104 | # fonts: 105 | # - asset: fonts/TrajanPro.ttf 106 | # - asset: fonts/TrajanPro_Bold.ttf 107 | # weight: 700 108 | # 109 | # For details regarding fonts from package dependencies, 110 | # see https://flutter.dev/custom-fonts/#from-packages 111 | -------------------------------------------------------------------------------- /assets/images/fertilization.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 32 | 33 | 34 | 35 | 36 | 39 | 40 | 41 | 42 | 43 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /lib/utils/api/ApiProvider.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:cattle/utils/PinConfig.dart'; 4 | import 'package:cattle/utils/api/CustomException.dart'; 5 | import 'package:flutter_secure_storage/flutter_secure_storage.dart'; 6 | import 'package:http/http.dart' as http; 7 | import 'dart:convert'; 8 | 9 | 10 | class ApiProvider{ 11 | static const String API_URL = "${PinConfig.IP}:${PinConfig.PORT}"; 12 | 13 | static final ApiProvider _instance=ApiProvider._internal(); 14 | String token; 15 | 16 | factory ApiProvider(){ 17 | return _instance; 18 | } 19 | 20 | ApiProvider._internal(); 21 | 22 | Future init()async{ 23 | FlutterSecureStorage storage = FlutterSecureStorage(); 24 | String t=await storage.read(key: "token"); 25 | if(t!=null){ 26 | token="Bearer "+t; 27 | }else{ 28 | token=""; 29 | } 30 | 31 | } 32 | 33 | Future setToken(String t)async{ 34 | FlutterSecureStorage storage = FlutterSecureStorage(); 35 | await storage.write(key: "token",value: t); 36 | token="Bearer "+t; 37 | } 38 | 39 | emptyToken() async { 40 | FlutterSecureStorage storage = FlutterSecureStorage(); 41 | await storage.write(key: "token",value: ""); 42 | token=""; 43 | } 44 | 45 | 46 | Future get(dynamic url,[params]) async { 47 | var uri; 48 | if(params!=null){ 49 | uri = Uri( 50 | scheme: 'http', 51 | host: PinConfig.IP, 52 | port: PinConfig.PORT, 53 | path: url, 54 | queryParameters: params, 55 | ); 56 | }else{ 57 | uri=Uri.http(API_URL,url); 58 | } 59 | 60 | 61 | var responseJson; 62 | try { 63 | final response = await http.get(uri, 64 | headers: { 65 | 'Content-Type': 'application/json; charset=UTF-8', 66 | "Authorization":token 67 | }, 68 | ); 69 | responseJson = _response(response); 70 | } on SocketException { 71 | throw FetchDataException('No Internet connection'); 72 | } 73 | return responseJson; 74 | } 75 | 76 | 77 | 78 | Future post(String url,body) async { 79 | var responseJson; 80 | var uri=Uri.http(API_URL,url); 81 | print(uri); 82 | try { 83 | final response = await http.post(uri, 84 | body:body, 85 | headers: { 86 | 'Content-Type': 'application/json; charset=UTF-8', 87 | "Authorization":token 88 | }, 89 | ); 90 | responseJson = _response(response); 91 | } on SocketException { 92 | throw FetchDataException('No Internet connection'); 93 | } 94 | return responseJson; 95 | } 96 | 97 | Future put(String url,body) async { 98 | var responseJson; 99 | var uri=Uri.http(API_URL,url); 100 | try { 101 | final response = await http.put(uri, 102 | body:body, 103 | headers: { 104 | 'Content-Type': 'application/json; charset=UTF-8', 105 | "Authorization":token 106 | }, 107 | ); 108 | responseJson = _response(response); 109 | } on SocketException { 110 | throw FetchDataException('No Internet connection'); 111 | } 112 | return responseJson; 113 | } 114 | 115 | Future delete(String url) async { 116 | var responseJson; 117 | var uri=Uri.http(API_URL,url); 118 | try { 119 | final response = await http.delete(uri, 120 | headers: { 121 | 'Content-Type': 'application/json; charset=UTF-8', 122 | "Authorization":token 123 | }, 124 | ); 125 | responseJson = _response(response); 126 | } on SocketException { 127 | throw FetchDataException('No Internet connection'); 128 | } 129 | return responseJson; 130 | } 131 | 132 | 133 | 134 | dynamic _response(http.Response response) { 135 | switch (response.statusCode) { 136 | case 200: 137 | 138 | var responseJson = json.decode(response.body.toString()); 139 | return responseJson; 140 | case 201: 141 | return json.decode(response.body.toString()); 142 | case 400: 143 | throw BadRequestException(response.body.toString()); 144 | case 401: 145 | 146 | case 403: 147 | throw UnauthorisedException(response.body.toString()); 148 | case 500: 149 | 150 | default: 151 | throw FetchDataException( 152 | 'Error occured while Communication with Server with StatusCode : ${response.statusCode}'); 153 | } 154 | } 155 | 156 | } -------------------------------------------------------------------------------- /lib/components/dashboard/dashboard.dart: -------------------------------------------------------------------------------- 1 | import 'package:cattle/components/dashboard/main_dashboard_card.dart'; 2 | import 'package:cattle/components/dashboard/summary_card.dart'; 3 | import 'package:cattle/components/list/filter.dart'; 4 | import 'package:cattle/components/list/list.dart'; 5 | import 'package:cattle/models/Dashboard.dart'; 6 | import 'package:cattle/repositories/DashboardRespository.dart'; 7 | import 'package:cattle/utils/api/Response.dart'; 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; 10 | 11 | class Dashboard extends StatefulWidget { 12 | @override 13 | _DashboardState createState() => _DashboardState(); 14 | } 15 | 16 | class _DashboardState extends State { 17 | 18 | DashboardRespository _dashboardRespository; 19 | 20 | _DashboardState(){ 21 | _dashboardRespository=DashboardRespository(); 22 | } 23 | 24 | DashboardData _dashboard=DashboardData(); 25 | 26 | EdgeInsetsGeometry _topBottomPadding=EdgeInsets.only( 27 | top:15.0, 28 | bottom:15.0 29 | ); 30 | 31 | 32 | @override 33 | void initState() { 34 | getData(); 35 | super.initState(); 36 | 37 | } 38 | 39 | Future getData()async{ 40 | var response=await _dashboardRespository.getDashboard(); 41 | if(response.status==Status.COMPLETED){ 42 | 43 | setState(() { 44 | _dashboard=response.data; 45 | }); 46 | 47 | }else{ 48 | Scaffold 49 | .of(context) 50 | .showSnackBar(SnackBar( 51 | content: Text(response.message,style: TextStyle(color: Colors.white,fontFamily: "Iran_Sans"),), 52 | behavior: SnackBarBehavior.floating, 53 | backgroundColor: Colors.red, 54 | ) 55 | ); 56 | } 57 | 58 | } 59 | 60 | @override 61 | Widget build(BuildContext context) { 62 | 63 | return RefreshIndicator(child: CustomScrollView( 64 | slivers: [ 65 | SliverPadding( 66 | padding: EdgeInsets.only( 67 | left: 15.0, 68 | right: 15.0 69 | ), 70 | sliver: SliverList( 71 | delegate: SliverChildListDelegate([ 72 | GridView.count( 73 | padding: _topBottomPadding, 74 | physics: NeverScrollableScrollPhysics(), 75 | shrinkWrap: true, 76 | crossAxisCount: 2, 77 | crossAxisSpacing: 10, 78 | mainAxisSpacing: 10, 79 | children: [ 80 | MainDashboardCard(Color(0xfffd6768),_dashboard.total.toString().padLeft(2,"0") ,AppLocalizations.of(context).dashboard_total_animal,"assets/images/total_cow.svg",()=>_onMainCardClick(FilterData([], []))), 81 | MainDashboardCard(Color(0xff109da4),_dashboard.calved.toString().padLeft(2,"0"),AppLocalizations.of(context).dashboard_milking_cow,"assets/images/milking_cow.svg",()=>_onMainCardClick(FilterData(["CALVED"], []))), 82 | MainDashboardCard(Color(0xfff0981a),_dashboard.dry.toString().padLeft(2,"0"),AppLocalizations.of(context).dashboard_dry_cow,"assets/images/dry_cow.svg",()=>_onMainCardClick(FilterData(["DRY"],[]))), 83 | MainDashboardCard(Color(0xff48294b),"00.00",AppLocalizations.of(context).dashboard_avg_milk,"assets/images/milk.svg",null), 84 | ], 85 | ), 86 | Text(AppLocalizations.of(context).dashboard_summary,style: Theme.of(context).textTheme.headline6), 87 | GridView.count( 88 | crossAxisCount: 3, 89 | padding: _topBottomPadding, 90 | // crossAxisSpacing: 2, 91 | // mainAxisSpacing: 2, 92 | childAspectRatio: 4/3, 93 | shrinkWrap: true, 94 | physics: NeverScrollableScrollPhysics(), 95 | children: [ 96 | SummaryCard(0,AppLocalizations.of(context).dashboard_insemination, _dashboard.insemination.toString().padLeft(2,"0"),()=>_onMainCardClick(FilterData(["INSEMINATION"], []))), 97 | SummaryCard(1,AppLocalizations.of(context).dashboard_milked, _dashboard.milked.toString().padLeft(2,"0"),()=>_onMainCardClick(FilterData(["MILKED"], []))), 98 | SummaryCard(2,AppLocalizations.of(context).dashboard_heifer, _dashboard.heifer.toString().padLeft(2,"0"),()=>_onMainCardClick(FilterData(["HEIFER"], []))), 99 | SummaryCard(3,AppLocalizations.of(context).dashboard_abortion, _dashboard.abortion.toString().padLeft(2,"0"),()=>_onMainCardClick(FilterData(["ABORTION"], []))), 100 | SummaryCard(4,AppLocalizations.of(context).dashboard_bull, _dashboard.bull.toString().padLeft(2,"0"),()=>_onMainCardClick(FilterData([], ["BULL"]))), 101 | SummaryCard(5,AppLocalizations.of(context).dashboard_cow, _dashboard.cow.toString().padLeft(2,"0"),()=>_onMainCardClick(FilterData([], ["COW"]))), 102 | ], 103 | ) 104 | ]), 105 | ), 106 | ) 107 | ], 108 | ), onRefresh: getData); 109 | 110 | } 111 | 112 | _onMainCardClick(FilterData filterDate){ 113 | Navigator.push( 114 | context, 115 | MaterialPageRoute(builder: (context) => CattleList(title: AppLocalizations.of(context).list_animals,filterData: filterDate,)), 116 | ); 117 | } 118 | } -------------------------------------------------------------------------------- /assets/images/milking_cow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /lib/l10n/app_fa.arb: -------------------------------------------------------------------------------- 1 | { 2 | "@@locale": "fa", 3 | "login_description_1":"ما", 4 | "@login_description_1":{ 5 | "description":"" 6 | }, 7 | "login_description_2":" رمز یکبار مصرف ", 8 | "@login_description_2":{ 9 | "description":"" 10 | }, 11 | "login_description_3":"را برای همین تلفن ارسال می کنیم", 12 | "@login_description_3":{ 13 | "description":"" 14 | }, 15 | "login_next":"بعدی", 16 | "@login_next":{ 17 | "description":"" 18 | }, 19 | "login_phone_validation_error":"تلفن را درست وارد کنید", 20 | "@login_phone_validation_error":{ 21 | "description":"" 22 | }, 23 | "login_phone_phone_input_placeholder":"...۰۹", 24 | "@login_phone_phone_input_placeholder":{ 25 | "description":"" 26 | }, 27 | 28 | "otp_title":"کد تایید ۶ رقمی ارسال شده را وارد کنید", 29 | "@otp_title":{ 30 | "description":"" 31 | }, 32 | "otp_confirm":"تایید", 33 | "@otp_confirm":{ 34 | "description":"" 35 | }, 36 | 37 | "dashboard_total_animal":"تعداد حیوانات", 38 | "@dashboard_total_animal":{ 39 | "description":"" 40 | }, 41 | 42 | "dashboard_milking_cow":"گاوهای شیری", 43 | "@dashboard_milking_cow":{ 44 | "description":"" 45 | }, 46 | 47 | "dashboard_dry_cow":"گاوهای خشک", 48 | "@dashboard_dry_cow":{ 49 | "description":"" 50 | }, 51 | 52 | "dashboard_avg_milk":" میانگین شیر/گاو (Kg)", 53 | "@dashboard_avg_milk":{ 54 | "description":"" 55 | }, 56 | 57 | "dashboard_insemination":"تلقیح", 58 | "@dashboard_insemination":{ 59 | "description":"" 60 | }, 61 | 62 | "dashboard_milked":"شیرخوار", 63 | "@dashboard_milked":{ 64 | "description":"" 65 | }, 66 | 67 | "dashboard_heifer":"تلیسه", 68 | "@dashboard_heifer":{ 69 | "description":"" 70 | }, 71 | 72 | "dashboard_abortion":"سقط", 73 | "@dashboard_abortion":{ 74 | "description":"" 75 | }, 76 | 77 | "dashboard_bull":"نر", 78 | "@dashboard_bull":{ 79 | "description":"" 80 | }, 81 | 82 | "dashboard_cow":"ماده", 83 | "@dashboard_cow":{ 84 | "description":"" 85 | }, 86 | "dashboard_summary":"خلاصه وضعیت", 87 | "@dashboard_summary":{ 88 | "description":"" 89 | }, 90 | 91 | "filter_state":"وضعیت : ", 92 | "@filter_state":{ 93 | "description":"" 94 | }, 95 | "filter_gender":"جنسیت : ", 96 | "@filter_gender":{ 97 | "description":"" 98 | }, 99 | "filter_confirm":"اعمال فیلتر", 100 | "@filter_confirm":{ 101 | "description":"" 102 | }, 103 | "filter_clear":"پاک کردن فیلتر", 104 | "@filter_clear":{ 105 | "description":"" 106 | }, 107 | 108 | "new_animal_title":"دام جدید", 109 | "@new_animal_title":{ 110 | "description":"" 111 | }, 112 | 113 | "edit_animal_title":"ویرایش دام", 114 | "@edit_animal_title":{ 115 | "description":"" 116 | }, 117 | 118 | "new_animal_tag_no":"شماره تگ", 119 | "@new_animal_tag_no":{ 120 | "description":"" 121 | }, 122 | 123 | "new_animal_mother":"مادر", 124 | "@new_animal_mother":{ 125 | "description":"" 126 | }, 127 | 128 | "new_animal_inserminator":"تلقیح کننده", 129 | "@new_animal_inserminator":{ 130 | "description":"" 131 | }, 132 | 133 | "new_animal_birth":"تاریخ تولد", 134 | "@new_animal_birth":{ 135 | "description":"" 136 | }, 137 | 138 | "new_animal_gender":"جنسیت", 139 | "@new_animal_gender":{ 140 | "description":"" 141 | }, 142 | "new_animal_save":"ذخیره دام", 143 | "@new_animal_save":{ 144 | "description":"" 145 | }, 146 | 147 | "list_not_found":"موردی یافت نشد", 148 | "@list_not_found":{ 149 | "description":"" 150 | }, 151 | 152 | "list_birth_state":"تولد", 153 | "@list_birth_state":{ 154 | "description":"" 155 | }, 156 | 157 | "list_search_tag_no":"جستجوی شماره گوش ...", 158 | "@list_search_tag_no":{ 159 | "description":"" 160 | }, 161 | 162 | "list_animals":"حیوانات", 163 | "@list_animals":{ 164 | "description":"" 165 | }, 166 | 167 | "detail_alert":"هشدار", 168 | "@detail_alert":{ 169 | "description":"" 170 | }, 171 | 172 | "detail_are_you_sure_delete":"آیا از حذف این مورد مطمئن هستید", 173 | "@detail_are_you_sure_delete":{ 174 | "description":"" 175 | }, 176 | 177 | "detail_birth":"تولد", 178 | "@detail_birth":{ 179 | "description":"" 180 | }, 181 | 182 | "detail_gender":"جنسیت", 183 | "@detail_gender":{ 184 | "description":"" 185 | }, 186 | 187 | "detail_mother":"مادر", 188 | "@detail_mother":{ 189 | "description":"" 190 | }, 191 | 192 | "detail_inseminator":"تلقیح کننده", 193 | "@detail_inseminator":{ 194 | "description":"" 195 | }, 196 | 197 | "detail_tag_no":"شماره تگ", 198 | "@detail_tag_no":{ 199 | "description":"" 200 | }, 201 | 202 | "detail_history":"تاریخچه", 203 | "@detail_history":{ 204 | "description":"" 205 | }, 206 | 207 | "state_dialog_type":"نوع", 208 | "@state_dialog_type":{ 209 | "description":"" 210 | }, 211 | 212 | "state_dialog_date":"تاریخ", 213 | "@state_dialog_date":{ 214 | "description":"" 215 | }, 216 | 217 | "state_dialog_description":"توضیحات", 218 | "@state_dialog_description":{ 219 | "description":"" 220 | }, 221 | 222 | "state_dialog_save":"تایید", 223 | "@state_dialog_save":{ 224 | "description":"" 225 | }, 226 | 227 | "state_dialog_cancel":"لغو", 228 | "@state_dialog_cancel":{ 229 | "description":"" 230 | }, 231 | 232 | "confirm_dialog_yes":"بلی", 233 | "@confirm_dialog_yes":{ 234 | "description":"" 235 | }, 236 | 237 | "confirm_dialog_no":"خیر", 238 | "@confirm_dialog_no":{ 239 | "description":"" 240 | }, 241 | 242 | "setting_language":"زبان", 243 | "@setting_language":{ 244 | "description":"" 245 | }, 246 | 247 | "setting_sign_out":"خروج", 248 | "@setting_sign_out":{ 249 | "description":"" 250 | }, 251 | 252 | "setting_language_title":"انتخاب زبان", 253 | "@setting_language_title":{ 254 | "description":"" 255 | }, 256 | 257 | "setting_common_section":"عمومی", 258 | "@setting_common_section":{ 259 | "description":"" 260 | } 261 | } -------------------------------------------------------------------------------- /lib/l10n/app_en.arb: -------------------------------------------------------------------------------- 1 | { 2 | "@@locale": "en", 3 | "login_description_1":"We will send you an ", 4 | "@login_description_1":{ 5 | "description":"" 6 | }, 7 | "login_description_2":"One Time Password", 8 | "@login_description_2":{ 9 | "description":"" 10 | }, 11 | "login_description_3":" on this mobile number", 12 | "@login_description_3":{ 13 | "description":"" 14 | }, 15 | "login_next":"Next", 16 | "@login_next":{ 17 | "description":"" 18 | }, 19 | "login_phone_validation_error":"Please input correct phone number.", 20 | "@login_phone_validation_error":{ 21 | "description":"" 22 | }, 23 | "login_phone_phone_input_placeholder":"+33...", 24 | "@login_phone_phone_input_placeholder":{ 25 | "description":"" 26 | }, 27 | "otp_title":"Enter 6 digits verification code sent to your number", 28 | "@otp_title":{ 29 | "description":"" 30 | }, 31 | "otp_confirm":"Confirm", 32 | "@otp_confirm":{ 33 | "description":"" 34 | }, 35 | 36 | "dashboard_total_animal":"Total Animals", 37 | "@dashboard_total_animal":{ 38 | "description":"" 39 | }, 40 | 41 | "dashboard_milking_cow":"Milking Cows", 42 | "@dashboard_milking_cow":{ 43 | "description":"" 44 | }, 45 | 46 | "dashboard_dry_cow":"Dry Cows", 47 | "@dashboard_dry_cow":{ 48 | "description":"" 49 | }, 50 | 51 | "dashboard_avg_milk":"Kgs Av.Milk/Cow", 52 | "@dashboard_avg_milk":{ 53 | "description":"" 54 | }, 55 | 56 | "dashboard_insemination":"Insemination", 57 | "@dashboard_insemination":{ 58 | "description":"" 59 | }, 60 | 61 | "dashboard_milked":"Milked", 62 | "@dashboard_milked":{ 63 | "description":"" 64 | }, 65 | 66 | "dashboard_heifer":"Heifer", 67 | "@dashboard_heifer":{ 68 | "description":"" 69 | }, 70 | 71 | "dashboard_abortion":"Abortion", 72 | "@dashboard_abortion":{ 73 | "description":"" 74 | }, 75 | 76 | "dashboard_bull":"Bull", 77 | "@dashboard_bull":{ 78 | "description":"" 79 | }, 80 | 81 | "dashboard_cow":"Cow", 82 | "@dashboard_cow":{ 83 | "description":"" 84 | }, 85 | 86 | "dashboard_summary":"Summary", 87 | "@dashboard_summary":{ 88 | "description":"" 89 | }, 90 | 91 | "filter_state":"State : ", 92 | "@filter_state":{ 93 | "description":"" 94 | }, 95 | "filter_gender":"Gender : ", 96 | "@filter_gender":{ 97 | "description":"" 98 | }, 99 | "filter_confirm":"Confirm Filters", 100 | "@filter_confirm":{ 101 | "description":"" 102 | }, 103 | "filter_clear":"Clear Filters", 104 | "@filter_clear":{ 105 | "description":"" 106 | }, 107 | 108 | 109 | "new_animal_title":"New Animal", 110 | "@new_animal_title":{ 111 | "description":"" 112 | }, 113 | 114 | "edit_animal_title":"Edit Animal", 115 | "@edit_animal_title":{ 116 | "description":"" 117 | }, 118 | 119 | "new_animal_tag_no":"Tag No.", 120 | "@new_animal_tag_no":{ 121 | "description":"" 122 | }, 123 | 124 | "new_animal_mother":"Mother", 125 | "@new_animal_mother":{ 126 | "description":"" 127 | }, 128 | 129 | "new_animal_inserminator":"Inseminator", 130 | "@new_animal_inserminator":{ 131 | "description":"" 132 | }, 133 | 134 | "new_animal_birth":"Birth Date", 135 | "@new_animal_birth":{ 136 | "description":"" 137 | }, 138 | 139 | "new_animal_gender":"Gender", 140 | "@new_animal_gender":{ 141 | "description":"" 142 | }, 143 | "new_animal_save":"Save", 144 | "@new_animal_save":{ 145 | "description":"" 146 | }, 147 | 148 | "list_not_found":"No matching animal found", 149 | "@list_not_found":{ 150 | "description":"" 151 | }, 152 | 153 | "list_birth_state":"Birth", 154 | "@list_birth_state":{ 155 | "description":"" 156 | }, 157 | 158 | "list_search_tag_no":"Search tag number...", 159 | "@list_search_tag_no":{ 160 | "description":"" 161 | }, 162 | 163 | "list_animals":"Animals", 164 | "@list_animals":{ 165 | "description":"" 166 | }, 167 | 168 | "detail_alert":"Alert", 169 | "@detail_alert":{ 170 | "description":"" 171 | }, 172 | 173 | "detail_are_you_sure_delete":"Are you sure ?", 174 | "@detail_are_you_sure_delete":{ 175 | "description":"" 176 | }, 177 | 178 | "detail_birth":"Birth", 179 | "@detail_birth":{ 180 | "description":"" 181 | }, 182 | 183 | "detail_gender":"Gender", 184 | "@detail_gender":{ 185 | "description":"" 186 | }, 187 | 188 | "detail_mother":"Mother", 189 | "@detail_mother":{ 190 | "description":"" 191 | }, 192 | 193 | "detail_inseminator":"Inseminator", 194 | "@detail_inseminator":{ 195 | "description":"" 196 | }, 197 | 198 | "detail_tag_no":"Tag No.", 199 | "@detail_tag_no":{ 200 | "description":"" 201 | }, 202 | 203 | "detail_history":"History", 204 | "@detail_history":{ 205 | "description":"" 206 | }, 207 | 208 | "state_dialog_type":"Type ", 209 | "@state_dialog_type":{ 210 | "description":"" 211 | }, 212 | 213 | "state_dialog_date":"Date ", 214 | "@state_dialog_date":{ 215 | "description":"" 216 | }, 217 | 218 | "state_dialog_description":"Description", 219 | "@state_dialog_description":{ 220 | "description":"" 221 | }, 222 | 223 | "state_dialog_save":"Save", 224 | "@state_dialog_save":{ 225 | "description":"" 226 | }, 227 | 228 | "state_dialog_cancel":"Cancel", 229 | "@state_dialog_cancel":{ 230 | "description":"" 231 | }, 232 | 233 | "confirm_dialog_yes":"Yes", 234 | "@confirm_dialog_yes":{ 235 | "description":"" 236 | }, 237 | 238 | "confirm_dialog_no":"No", 239 | "@confirm_dialog_no":{ 240 | "description":"" 241 | }, 242 | "setting_language":"Language", 243 | "@setting_language":{ 244 | "description":"" 245 | }, 246 | 247 | "setting_sign_out":"Sign out", 248 | "@setting_sign_out":{ 249 | "description":"" 250 | }, 251 | "setting_language_title":"Choose Language", 252 | "@setting_language_title":{ 253 | "description":"" 254 | }, 255 | 256 | "setting_common_section":"Common", 257 | "@setting_common_section":{ 258 | "description":"" 259 | } 260 | } -------------------------------------------------------------------------------- /lib/components/detail/state_dialog.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:cattle/components/newAnimal/drop_down.dart'; 4 | import 'package:cattle/components/newAnimal/input.dart'; 5 | import 'package:cattle/models/LivestockState.dart'; 6 | import 'package:cattle/models/LocaleModel.dart'; 7 | import 'package:cattle/utils/DateUtil.dart'; 8 | import 'package:cattle/utils/SettingsProvider.dart'; 9 | import 'package:flutter/material.dart'; 10 | import 'package:intl/intl.dart'; 11 | import 'package:persian_date/persian_date.dart'; 12 | import 'package:persian_datepicker/persian_datepicker.dart'; 13 | import 'package:persian_datepicker/persian_datetime.dart'; 14 | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; 15 | 16 | 17 | class StateDialog extends StatefulWidget { 18 | 19 | final LivestockState _livestockState; 20 | final Function _saveStateHandler; 21 | 22 | StateDialog(this._livestockState,this._saveStateHandler); 23 | 24 | 25 | @override 26 | _StateDialogState createState() => _StateDialogState(); 27 | } 28 | 29 | class _StateDialogState extends State { 30 | 31 | PersianDatePickerWidget persianDatePicker; 32 | final stateDateController = TextEditingController(); 33 | final descriptionController = TextEditingController(); 34 | final stateController = TextEditingController(); 35 | 36 | String stateValue; 37 | 38 | @override 39 | void initState() { 40 | 41 | Future.delayed(Duration.zero,(){ 42 | if(widget._livestockState.date!=null){ 43 | stateDateController.text= DateUtil.formatLocaleDate(widget._livestockState.date, context) ; 44 | }else{ 45 | 46 | stateDateController.text=DateUtil.formatLocaleDate(DateTime.now().toString(), context) ; 47 | } 48 | }); 49 | 50 | 51 | 52 | persianDatePicker = PersianDatePicker( 53 | controller: stateDateController, 54 | ).init(); 55 | 56 | stateValue=widget._livestockState.state; 57 | stateController.text=widget._livestockState.state; 58 | descriptionController.text=widget._livestockState.description; 59 | 60 | super.initState(); 61 | } 62 | 63 | @override 64 | Widget build(BuildContext context) { 65 | return SingleChildScrollView(child: Dialog( 66 | shape: RoundedRectangleBorder( 67 | borderRadius: BorderRadius.circular(16.0), 68 | ), 69 | elevation: 0.0, 70 | backgroundColor: Colors.transparent, 71 | child: dialogContent(context), 72 | )); 73 | } 74 | 75 | dialogContent(BuildContext context) { 76 | // setState(() { 77 | // stateValue=value; 78 | // }); 79 | return Stack( 80 | children: [ 81 | Container( 82 | padding: EdgeInsets.only( 83 | top: Consts.padding, 84 | bottom: Consts.padding, 85 | left: Consts.padding, 86 | right: Consts.padding, 87 | ), 88 | margin: EdgeInsets.only(top: Consts.avatarRadius), 89 | decoration: new BoxDecoration( 90 | color: Colors.white, 91 | shape: BoxShape.rectangle, 92 | borderRadius: BorderRadius.circular(Consts.padding), 93 | boxShadow: [ 94 | BoxShadow( 95 | color: Colors.black26, 96 | blurRadius: 10.0, 97 | offset: const Offset(0.0, 10.0), 98 | ), 99 | ], 100 | ), 101 | child: Column( 102 | mainAxisSize: MainAxisSize.min, // To make the card compact 103 | children: [ 104 | DropDown( 105 | hint: AppLocalizations.of(context).state_dialog_type, 106 | items: SettingsProvider().getSettings().livestockState.map((item){ 107 | return DropdownMenuItem( 108 | child: Text(jsonDecode(item.title)[Localizations.localeOf(context).languageCode]), 109 | value: item.value 110 | ); 111 | }).toList(), 112 | value: stateValue, 113 | onChanged: (newValue){ 114 | print(newValue); 115 | setState((){ 116 | stateValue=newValue; 117 | }); 118 | stateController.text=newValue; 119 | }, 120 | focus: null, 121 | ), 122 | SizedBox(height: 24.0), 123 | Input(AppLocalizations.of(context).state_dialog_date,stateDateController,() async { 124 | if(Language.isRtl(context)){ 125 | FocusScope.of(context).requestFocus(new FocusNode()); // to prevent opening default keyboard 126 | showModalBottomSheet( 127 | context: context, 128 | builder: (BuildContext context) { 129 | return persianDatePicker; 130 | }); 131 | 132 | }else{ 133 | final DateTime picked = await showDatePicker( 134 | context: context, 135 | initialDate: DateTime.parse(stateDateController.text), 136 | firstDate: DateTime(2000), 137 | lastDate: DateTime(2025), 138 | ); 139 | if(picked != null) 140 | stateDateController.text= DateFormat("yyyy-MM-dd").format(picked); 141 | } 142 | },false,null,(str)=>{},false), 143 | SizedBox(height: 24.0), 144 | Input(AppLocalizations.of(context).state_dialog_description,descriptionController,()=>{},true,null,(str)=>{},true), 145 | 146 | SizedBox(height: 24.0), 147 | Row( 148 | children: [ 149 | Align( 150 | alignment: Alignment.bottomRight, 151 | child: FlatButton( 152 | onPressed: () async{ 153 | 154 | var body={ 155 | "state":stateController.text, 156 | "date":Language.isRtl(context) ? PersianDateTime(jalaaliDateTime: stateDateController.text).toGregorian():stateDateController.text , 157 | "description":descriptionController.text, 158 | "id":widget._livestockState.id 159 | }; 160 | widget._saveStateHandler(body); 161 | }, 162 | child: Text(AppLocalizations.of(context).state_dialog_save), 163 | ), 164 | ), 165 | Align( 166 | alignment: Alignment.bottomRight, 167 | child: FlatButton( 168 | onPressed: (){ 169 | Navigator.of(context).pop(); 170 | }, 171 | child: Text(AppLocalizations.of(context).state_dialog_cancel), 172 | ), 173 | ), 174 | ], 175 | ) 176 | 177 | ], 178 | ), 179 | ), 180 | 181 | ], 182 | ); 183 | } 184 | } 185 | 186 | class Consts { 187 | Consts._(); 188 | 189 | static const double padding = 16.0; 190 | static const double avatarRadius = 66.0; 191 | } -------------------------------------------------------------------------------- /assets/images/dry_cow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 59 | 60 | 61 | 62 | 63 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /lib/components/login/otp_page.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:cattle/home.dart'; 4 | import 'package:cattle/models/LocaleModel.dart'; 5 | import 'package:cattle/repositories/AuthRepository.dart'; 6 | import 'package:cattle/repositories/SettingRespository.dart'; 7 | import 'package:cattle/utils/SettingsProvider.dart'; 8 | import 'package:cattle/utils/api/ApiProvider.dart'; 9 | import 'package:cattle/utils/api/Response.dart'; 10 | import 'package:flutter/material.dart'; 11 | import 'package:numeric_keyboard/numeric_keyboard.dart'; 12 | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; 13 | 14 | class OtpPage extends StatefulWidget { 15 | 16 | final String phoneNumber; 17 | 18 | const OtpPage(this.phoneNumber); 19 | @override 20 | _OtpPageState createState() => _OtpPageState(); 21 | } 22 | 23 | class _OtpPageState extends State { 24 | 25 | String text = ''; 26 | AuthRepository _authRepository; 27 | SettingRepository _settingRepository; 28 | 29 | final GlobalKey _scaffoldKey = GlobalKey(); 30 | 31 | 32 | _OtpPageState(){ 33 | _authRepository=new AuthRepository(); 34 | _settingRepository=SettingRepository(); 35 | } 36 | 37 | void _onKeyboardTap(String value) { 38 | setState(() { 39 | text = text + value; 40 | }); 41 | } 42 | 43 | Widget otpNumberWidget(int position) { 44 | try { 45 | return Container( 46 | height: 40, 47 | width: 40, 48 | decoration: BoxDecoration( 49 | border: Border.all(color: Colors.black, width: 0), 50 | borderRadius: const BorderRadius.all(Radius.circular(8)) 51 | ), 52 | child: Center(child: Text(text[position], style: TextStyle(color: Colors.black),)), 53 | ); 54 | } catch (e) { 55 | return Container( 56 | height: 40, 57 | width: 40, 58 | decoration: BoxDecoration( 59 | border: Border.all(color: Colors.black, width: 0), 60 | borderRadius: const BorderRadius.all(Radius.circular(8)) 61 | ), 62 | ); 63 | } 64 | } 65 | 66 | @override 67 | Widget build(BuildContext context) { 68 | return Scaffold( 69 | key: _scaffoldKey, 70 | backgroundColor: Colors.white, 71 | appBar: AppBar( 72 | leading: IconButton( 73 | icon: Container( 74 | padding: const EdgeInsets.all(10), 75 | decoration: BoxDecoration( 76 | borderRadius: const BorderRadius.all(Radius.circular(20)), 77 | // color: Theme.of(context).primaryColor, 78 | ), 79 | child: Icon(Icons.arrow_back_ios, color: Theme.of(context).primaryColor, size: 20,), 80 | ), 81 | onPressed: () => Navigator.of(context).pop(), 82 | ), 83 | elevation: 0, 84 | backgroundColor: Colors.white, 85 | brightness: Brightness.light, 86 | ), 87 | body: SafeArea( 88 | child: Column( 89 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 90 | crossAxisAlignment: CrossAxisAlignment.center, 91 | children: [ 92 | Expanded( 93 | child: Column( 94 | mainAxisSize: MainAxisSize.max, 95 | children: [ 96 | Expanded( 97 | child: Column( 98 | mainAxisAlignment: MainAxisAlignment.spaceEvenly, 99 | children: [ 100 | Container( 101 | margin: const EdgeInsets.symmetric(horizontal: 20), 102 | child: Text(AppLocalizations.of(context).otp_title, style: TextStyle(color: Colors.black, fontSize: 26, fontWeight: FontWeight.w500)) 103 | ), 104 | Container( 105 | constraints: const BoxConstraints( 106 | maxWidth: 500 107 | ), 108 | child: Row( 109 | textDirection: Language.isRtl(context) ? TextDirection.ltr:TextDirection.rtl, 110 | mainAxisAlignment: MainAxisAlignment.spaceEvenly, 111 | crossAxisAlignment: CrossAxisAlignment.center, 112 | children: [ 113 | otpNumberWidget(5), 114 | otpNumberWidget(4), 115 | otpNumberWidget(3), 116 | otpNumberWidget(2), 117 | otpNumberWidget(1), 118 | otpNumberWidget(0), 119 | ], 120 | ), 121 | ), 122 | ], 123 | ), 124 | ), 125 | Container( 126 | margin: const EdgeInsets.symmetric(horizontal: 20, vertical: 10), 127 | constraints: const BoxConstraints( 128 | maxWidth: 500 129 | ), 130 | child: RaisedButton( 131 | onPressed: () async{ 132 | 133 | var response = await _authRepository.postCode(jsonEncode({"code":text,"phone":widget.phoneNumber.toString()})); 134 | if(Status.COMPLETED==response.status){ 135 | 136 | await ApiProvider().setToken(response.data.token.toString()); 137 | 138 | Response settingsResponse=await _settingRepository.get(); 139 | 140 | SettingsProvider().setSettings(settingsResponse.data); 141 | Navigator.pop(context); 142 | Navigator.pushReplacement( 143 | context, 144 | MaterialPageRoute(builder: (context) => HomePage()), 145 | ); 146 | }else{ 147 | _scaffoldKey.currentState 148 | .showSnackBar(SnackBar( 149 | content: Text(response.message,style: TextStyle(color: Colors.white,fontFamily: "Iran_Sans"),), 150 | behavior: SnackBarBehavior.floating, 151 | backgroundColor: Colors.red, 152 | ) 153 | ); 154 | } 155 | 156 | // loginStore.validateOtpAndLogin(context, text); 157 | }, 158 | color: Theme.of(context).primaryColor, 159 | shape: const RoundedRectangleBorder( 160 | borderRadius: BorderRadius.all(Radius.circular(14)) 161 | ), 162 | child: Container( 163 | padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 8), 164 | child: Row( 165 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 166 | children: [ 167 | Text(AppLocalizations.of(context).otp_confirm, style: TextStyle(color: Colors.white),), 168 | Container( 169 | padding: const EdgeInsets.all(8), 170 | decoration: BoxDecoration( 171 | borderRadius: const BorderRadius.all(Radius.circular(20)), 172 | color: Theme.of(context).primaryColor, 173 | ), 174 | child: Icon(Icons.arrow_forward_ios, color: Colors.white, size: 16,), 175 | ) 176 | ], 177 | ), 178 | ), 179 | ), 180 | ), 181 | Directionality( 182 | textDirection: TextDirection.ltr, 183 | child: NumericKeyboard( 184 | onKeyboardTap: _onKeyboardTap, 185 | textColor: Theme.of(context).primaryColor, 186 | rightIcon: Icon( 187 | Icons.backspace, 188 | color: Theme.of(context).primaryColor, 189 | ), 190 | rightButtonFn: () { 191 | setState(() { 192 | text = text.substring(0, text.length - 1); 193 | }); 194 | }, 195 | ), 196 | ), 197 | 198 | ], 199 | ), 200 | ) 201 | ], 202 | ), 203 | ), 204 | ); 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /lib/components/newAnimal/new-animal.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:cattle/components/detail/detail.dart'; 4 | import 'package:cattle/components/newAnimal/drop_down.dart'; 5 | import 'package:cattle/components/newAnimal/input.dart'; 6 | import 'package:cattle/models/LocaleModel.dart'; 7 | import 'package:cattle/models/livestock.dart'; 8 | import 'package:cattle/repositories/LivstockRespository.dart'; 9 | import 'package:cattle/utils/DateUtil.dart'; 10 | import 'package:cattle/utils/SettingsProvider.dart'; 11 | import 'package:cattle/utils/api/Response.dart'; 12 | import 'package:flutter/material.dart'; 13 | import 'package:intl/intl.dart'; 14 | import 'package:persian_datepicker/persian_datepicker.dart'; 15 | import 'package:persian_datepicker/persian_datetime.dart'; 16 | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; 17 | 18 | 19 | 20 | class NewAnimal extends StatefulWidget { 21 | 22 | final Livestock livestock; 23 | NewAnimal({this.livestock}); 24 | 25 | @override 26 | _NewAnimalState createState() => _NewAnimalState(); 27 | } 28 | 29 | class _NewAnimalState extends State { 30 | 31 | LivestockRepository _livestockRepository; 32 | 33 | final tagController = TextEditingController(); 34 | final birthController = TextEditingController(); 35 | final genderController = TextEditingController(); 36 | final stateController = TextEditingController(); 37 | final motherController = TextEditingController(); 38 | final inserminatorController = TextEditingController(); 39 | String _genderValue; 40 | // String _stateValue; 41 | 42 | final FocusNode _tagFocus = FocusNode(); 43 | final FocusNode _birthFocus = FocusNode(); 44 | final FocusNode _genderFocus = FocusNode(); 45 | // final FocusNode _stateFocus = FocusNode(); 46 | final FocusNode _motherFocus = FocusNode(); 47 | final FocusNode _inseminatorFocus = FocusNode(); 48 | 49 | // final FocusScopeNode _node = FocusScopeNode(); 50 | 51 | PersianDatePickerWidget persianDatePicker; 52 | 53 | 54 | FocusNode currentFocus; 55 | bool isInitialized=false; 56 | 57 | 58 | 59 | @override 60 | void initState() { 61 | persianDatePicker = PersianDatePicker( 62 | controller: birthController, 63 | ).init(); 64 | 65 | if(widget.livestock!=null){ 66 | tagController.text=widget.livestock.tagNo; 67 | genderController.text=widget.livestock.gender; 68 | _genderValue=widget.livestock.gender; 69 | motherController.text=widget.livestock.mother; 70 | inserminatorController.text=widget.livestock.inseminator; 71 | } 72 | 73 | // states=SettingsProvider().getSettings().livestockState; 74 | super.initState(); 75 | 76 | 77 | 78 | Future.delayed(Duration.zero,(){ 79 | if(widget.livestock!=null){ 80 | birthController.text= DateUtil.formatLocaleDate(widget.livestock.birthDate, context) ; 81 | } 82 | }); 83 | 84 | 85 | } 86 | 87 | _NewAnimalState(){ 88 | _livestockRepository=LivestockRepository(); 89 | // setState(() { 90 | // currentFocus=_tagFocus; 91 | // }); 92 | // FocusScope.of(context).requestFocus(currentFocus); 93 | } 94 | 95 | @override 96 | Widget build(BuildContext context) { 97 | if (!isInitialized && widget.livestock==null) { 98 | isInitialized = true; 99 | setState(() { 100 | currentFocus=_tagFocus; 101 | }); 102 | FocusScope.of(context).requestFocus(_tagFocus); 103 | } 104 | return Scaffold( 105 | body: Form( 106 | child:CustomScrollView( 107 | slivers: [ 108 | SliverAppBar( 109 | leading: BackButton(), 110 | centerTitle: true, 111 | title:Text(widget.livestock!=null? 112 | AppLocalizations.of(context).edit_animal_title 113 | :AppLocalizations.of(context).new_animal_title 114 | ) 115 | ), 116 | SliverPadding( 117 | padding: EdgeInsets.all(20), 118 | sliver: SliverList( 119 | delegate: SliverChildListDelegate([ 120 | Input(AppLocalizations.of(context).new_animal_tag_no,tagController,()=>{},true,_tagFocus,(str)=>_changeFieldFocus(_motherFocus),false), 121 | 122 | 123 | SizedBox(height: 20), 124 | // DropDown( 125 | // hint: "وضعیت", 126 | // items:states , 127 | // value: _stateValue, 128 | // onChanged: (value){ 129 | // this.setState((){ 130 | // _stateValue=value; 131 | // }); 132 | // stateController.text=value; 133 | // _changeFieldFocus(_motherFocus); 134 | // }, 135 | // focus: _stateFocus, 136 | // ), 137 | SizedBox(height: 20), 138 | Input(AppLocalizations.of(context).new_animal_mother,motherController,()=>{},true,_motherFocus,(str)=>_changeFieldFocus(_inseminatorFocus),false), 139 | SizedBox(height: 20), 140 | Input(AppLocalizations.of(context).new_animal_inserminator,inserminatorController,()=>{},true,_inseminatorFocus,(str)=>{},true), 141 | SizedBox(height: 20), 142 | Input(AppLocalizations.of(context).new_animal_birth,birthController,() async { 143 | if(Language.isRtl(context)){ 144 | FocusScope.of(context).requestFocus(new FocusNode()); // to prevent opening default keyboard 145 | showModalBottomSheet( 146 | context: context, 147 | builder: (BuildContext context) { 148 | return persianDatePicker; 149 | }); 150 | }else{ 151 | 152 | final DateTime picked = await showDatePicker( 153 | context: context, 154 | initialDate: DateTime.parse(birthController.text), 155 | firstDate: DateTime(2000), 156 | lastDate: DateTime(2025), 157 | ); 158 | if(picked != null) 159 | birthController.text= DateFormat("yyyy-MM-dd").format(picked); 160 | } 161 | 162 | },false,_birthFocus,(str)=>{},false), 163 | SizedBox(height: 20,), 164 | DropDown( 165 | hint: AppLocalizations.of(context).new_animal_gender, 166 | items: SettingsProvider().getSettings().livestockType.map((item){ 167 | return DropdownMenuItem( 168 | child: Text(jsonDecode(item.title)[Localizations.localeOf(context).languageCode]), 169 | value: item.value 170 | ); 171 | }).toList(), 172 | value: _genderValue, 173 | onChanged: (value){ 174 | setState((){ 175 | _genderValue=value; 176 | }); 177 | genderController.text=value; 178 | // _changeFieldFocus(_motherFocus); 179 | }, 180 | focus: _genderFocus, 181 | ), 182 | SizedBox(height: 20,), 183 | Builder( 184 | builder: (context){ 185 | return RaisedButton( 186 | color: Theme.of(context).primaryColor, 187 | padding: EdgeInsets.all(15), 188 | shape: RoundedRectangleBorder( 189 | borderRadius: BorderRadius.circular(10) 190 | ), 191 | onPressed: () async { 192 | 193 | 194 | 195 | var body={ 196 | "tagNo":tagController.text, 197 | "birthDate": Language.isRtl(context) ? PersianDateTime(jalaaliDateTime: birthController.text).toGregorian():birthController.text, 198 | "gender":genderController.text, 199 | "mother":motherController.text, 200 | "inseminator":inserminatorController.text, 201 | // "state":stateController.text, 202 | }; 203 | 204 | 205 | 206 | var response; 207 | if(widget.livestock!=null){ 208 | response=await _livestockRepository.putLivestock(widget.livestock.id,jsonEncode(body)); 209 | }else{ 210 | response=await _livestockRepository.postLivestock(jsonEncode(body)); 211 | } 212 | 213 | if(response.status==Status.COMPLETED){ 214 | if(widget.livestock!=null){ 215 | Navigator.pop(context); 216 | Navigator.pop(context); 217 | Navigator.push(context, MaterialPageRoute(builder: (context) => Detail(livestock: response.data,))); 218 | }else{ 219 | Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) => Detail(livestock: response.data,))); 220 | } 221 | 222 | }else{ 223 | Scaffold 224 | .of(context) 225 | .showSnackBar(SnackBar( 226 | content: Text(response.message,style: TextStyle(color: Colors.white,fontFamily: "Iran_Sans"),), 227 | behavior: SnackBarBehavior.floating, 228 | backgroundColor: Colors.red, 229 | ) 230 | ); 231 | } 232 | 233 | // var response = await http.post("${FlutterConfig.get('API_URL')}/v1/livestock", body:body); 234 | // if (_formKey.currentState.validate()) { 235 | // Scaffold 236 | // .of(context) 237 | // .showSnackBar(SnackBar(content: Text('Processing Data'))); 238 | // } 239 | }, 240 | child: Text(AppLocalizations.of(context).new_animal_save,style: Theme.of(context).textTheme.button), 241 | ); 242 | } 243 | ) 244 | 245 | ]), 246 | ) 247 | ) 248 | ], 249 | ), 250 | ) 251 | ); 252 | } 253 | 254 | _changeFieldFocus(FocusNode nextFocus){ 255 | currentFocus.unfocus(); 256 | FocusScope.of(context).requestFocus(nextFocus); 257 | setState(() { 258 | currentFocus=nextFocus; 259 | }); 260 | } 261 | 262 | } -------------------------------------------------------------------------------- /lib/components/login/login_page.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'package:cattle/components/login/otp_page.dart'; 3 | import 'package:cattle/models/LocaleModel.dart'; 4 | import 'package:cattle/repositories/AuthRepository.dart'; 5 | import 'package:cattle/utils/api/Response.dart'; 6 | import 'package:flutter/cupertino.dart'; 7 | import 'package:flutter/material.dart'; 8 | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; 9 | import 'package:flutter_icons/flutter_icons.dart'; 10 | import 'package:provider/provider.dart'; 11 | 12 | 13 | 14 | class LoginPage extends StatefulWidget { 15 | const LoginPage({Key key}) : super(key: key); 16 | @override 17 | _LoginPageState createState() => _LoginPageState(); 18 | } 19 | 20 | class _LoginPageState extends State { 21 | TextEditingController phoneController = TextEditingController(); 22 | AuthRepository _authRepository; 23 | 24 | _LoginPageState(){ 25 | _authRepository=new AuthRepository(); 26 | } 27 | 28 | 29 | @override 30 | Widget build(BuildContext context) { 31 | return Scaffold( 32 | backgroundColor: Colors.white, 33 | body: SafeArea( 34 | child: SingleChildScrollView( 35 | child: Container( 36 | height: MediaQuery.of(context).size.height-30, 37 | child: Column( 38 | children: [ 39 | Expanded( 40 | flex: 2, 41 | child: Column( 42 | children: [ 43 | Container( 44 | padding: EdgeInsets.only(top:20,left: 20,right:20), 45 | child: Align( 46 | alignment: Alignment.bottomRight, 47 | child: DropdownButton( 48 | value: Localizations.localeOf(context).languageCode, 49 | underline: Container( 50 | height: 0, 51 | ), 52 | icon:Icon(MaterialIcons.language), 53 | items: languageList.map>((Language lang) { 54 | return DropdownMenuItem( 55 | value: lang.code, 56 | child: Text(lang.name), 57 | ); 58 | }).toList(), 59 | onChanged: (String newValue) { 60 | Provider.of(context, listen: false).set(newValue); 61 | }, 62 | 63 | ) 64 | ), 65 | ), 66 | Container( 67 | margin: const EdgeInsets.symmetric(horizontal: 20, vertical: 20), 68 | child: Stack( 69 | children: [ 70 | Center( 71 | child: Container( 72 | height: 240, 73 | constraints: const BoxConstraints( 74 | maxWidth: 500 75 | ), 76 | // margin: const EdgeInsets.only(top: 20), 77 | decoration: const BoxDecoration(color: Color(0xFFE1E0F5), borderRadius: BorderRadius.all(Radius.circular(30))), 78 | ), 79 | ), 80 | Center( 81 | child: Container( 82 | constraints: const BoxConstraints(maxHeight: 320), 83 | margin: const EdgeInsets.symmetric(horizontal: 8), 84 | child: Image.asset('assets/images/login.png')), 85 | ), 86 | ], 87 | ), 88 | ), 89 | Container( 90 | margin: const EdgeInsets.symmetric(horizontal: 10), 91 | child: Text('ThePinHerd', 92 | style: TextStyle(color: Theme.of(context).primaryColor, fontSize: 30, fontWeight: FontWeight.w800))) 93 | ], 94 | ), 95 | ), 96 | Expanded( 97 | flex: 1, 98 | child: Column( 99 | children: [ 100 | Container( 101 | constraints: const BoxConstraints( 102 | maxWidth: 500 103 | ), 104 | margin: const EdgeInsets.symmetric(horizontal: 10), 105 | child: RichText( 106 | textAlign: TextAlign.center, 107 | text: TextSpan(children: [ 108 | TextSpan(text: AppLocalizations.of(context).login_description_1, style: TextStyle(color: Theme.of(context).primaryColor,fontFamily: "Iran_Sans")), 109 | TextSpan( 110 | text: AppLocalizations.of(context).login_description_2, style: TextStyle(color: Theme.of(context).primaryColor, fontWeight: FontWeight.bold,fontFamily: "Iran_Sans")), 111 | TextSpan(text: AppLocalizations.of(context).login_description_3, style: TextStyle(color: Theme.of(context).primaryColor,fontFamily: "Iran_Sans")), 112 | ]), 113 | )), 114 | Container( 115 | height: 40, 116 | constraints: const BoxConstraints( 117 | maxWidth: 500 118 | ), 119 | margin: const EdgeInsets.symmetric(horizontal: 20, vertical: 10), 120 | child: CupertinoTextField( 121 | textAlign: TextAlign.left, 122 | padding: const EdgeInsets.symmetric(horizontal: 16), 123 | decoration: BoxDecoration( 124 | color: Colors.white, 125 | borderRadius: const BorderRadius.all(Radius.circular(4)) 126 | ), 127 | controller: phoneController, 128 | clearButtonMode: OverlayVisibilityMode.editing, 129 | keyboardType: TextInputType.phone, 130 | maxLines: 1, 131 | placeholder: AppLocalizations.of(context).login_phone_phone_input_placeholder, 132 | ), 133 | ), 134 | Container( 135 | margin: const EdgeInsets.symmetric(horizontal: 20, vertical: 10), 136 | constraints: const BoxConstraints( 137 | maxWidth: 500 138 | ), 139 | child: Builder( 140 | builder: (context){ 141 | return RaisedButton( 142 | onPressed: () async { 143 | 144 | if (phoneController.text.isNotEmpty) { 145 | var response=await _authRepository.postUser(jsonEncode({"phone":phoneController.text})); 146 | if(Status.COMPLETED==response.status){ 147 | 148 | // ApiProvider().setToken(response.data.token.toString()); 149 | 150 | // Response settingsResponse=await _settingRepository.get(); 151 | 152 | // SettingsProvider().setSettings(settingsResponse.data); 153 | 154 | Navigator.push( 155 | context, 156 | MaterialPageRoute(builder: (context) => OtpPage(phoneController.text,)), 157 | ); 158 | }else{ 159 | Scaffold 160 | .of(context) 161 | .showSnackBar(SnackBar( 162 | content: Text(response.message,style: TextStyle(color: Colors.white,fontFamily: "Iran_Sans"),), 163 | behavior: SnackBarBehavior.floating, 164 | backgroundColor: Colors.red, 165 | ) 166 | ); 167 | } 168 | 169 | 170 | // loginStore.getCodeWithPhoneNumber(context, phoneController.text.toString()); 171 | } else { 172 | Scaffold 173 | .of(context) 174 | .showSnackBar(SnackBar( 175 | content: Text(AppLocalizations.of(context).login_phone_validation_error,style: TextStyle(color: Colors.white,fontFamily: "Iran_Sans"),), 176 | behavior: SnackBarBehavior.floating, 177 | backgroundColor: Colors.red, 178 | ) 179 | ); 180 | } 181 | }, 182 | color: Theme.of(context).primaryColor, 183 | shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(14))), 184 | child: Container( 185 | padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 8), 186 | child: Row( 187 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 188 | children: [ 189 | Text( 190 | AppLocalizations.of(context).login_next, 191 | style: TextStyle(color: Colors.white), 192 | ), 193 | Container( 194 | padding: const EdgeInsets.all(8), 195 | decoration: BoxDecoration( 196 | borderRadius: const BorderRadius.all(Radius.circular(20)), 197 | color: Theme.of(context).primaryColor, 198 | ), 199 | child: Icon( 200 | Icons.arrow_forward_ios, 201 | color: Colors.white, 202 | size: 16, 203 | ), 204 | ) 205 | ], 206 | ), 207 | ), 208 | ); 209 | }, 210 | ) 211 | ) 212 | ], 213 | ), 214 | ) 215 | ], 216 | ), 217 | ), 218 | ), 219 | ), 220 | ); 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /lib/components/list/list.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:cattle/components/detail/detail.dart'; 4 | import 'package:cattle/components/list/filter.dart'; 5 | import 'package:cattle/models/LocaleModel.dart'; 6 | import 'package:cattle/models/livestock.dart'; 7 | import 'package:cattle/repositories/LivstockRespository.dart'; 8 | import 'package:cattle/utils/DateUtil.dart'; 9 | import 'package:cattle/utils/SettingsProvider.dart'; 10 | import 'package:cattle/utils/api/Response.dart'; 11 | import 'package:cattle/widgets/PinSnackBar.dart'; 12 | import 'package:cattle/widgets/fab_bottom_navigation/pin_image.dart'; 13 | import 'package:flutter/material.dart'; 14 | import 'package:flutter_icons/flutter_icons.dart'; 15 | import 'package:intl/intl.dart'; 16 | import 'package:persian_date/persian_date.dart'; 17 | import 'package:timeago/timeago.dart' as timeago; 18 | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; 19 | 20 | class CattleList extends StatefulWidget { 21 | 22 | CattleList({ @required this.title,this.filterData}); 23 | 24 | final String title; 25 | final FilterData filterData; 26 | 27 | @override 28 | _CattleListState createState() => _CattleListState(); 29 | } 30 | 31 | class _CattleListState extends State { 32 | TextEditingController _searchQueryController = TextEditingController(); 33 | bool _isSearching = false; 34 | String searchQuery = ""; 35 | int _pageSize=10,_offset=-10,_totalItems=-1; 36 | bool _loading=true; 37 | 38 | List _livestockList=new List(); 39 | LivestockRepository _livestockRepository; 40 | final GlobalKey _scaffoldKey = GlobalKey(); 41 | Map _livestockType; 42 | Map _livestockState; 43 | 44 | ScrollController scrollController; 45 | 46 | FilterData filterData=FilterData([],[]); 47 | 48 | _CattleListState(){ 49 | _livestockRepository=LivestockRepository(); 50 | } 51 | 52 | @override 53 | void initState() { 54 | filterData=widget.filterData; 55 | loadLivestock(); 56 | _livestockType= Map.fromIterable(SettingsProvider().getSettings().livestockType,key: (v)=>v.value,value: (v)=>v.title); 57 | _livestockState=Map.fromIterable(SettingsProvider().getSettings().livestockState,key: (v)=>v.value,value: (v)=>v.title); 58 | 59 | scrollController= ScrollController()..addListener(_scrollListener); 60 | 61 | 62 | 63 | super.initState(); 64 | } 65 | 66 | void _scrollListener(){ 67 | if (scrollController.position.extentAfter < 300 && _totalItems>_offset+_pageSize && _loading==false ) { 68 | loadLivestock(); 69 | } 70 | } 71 | 72 | Future loadLivestock([bool isRefresh=false])async{ 73 | setState(() { 74 | _loading=true; 75 | }); 76 | if(isRefresh){ 77 | setState(() { 78 | _offset=-10; 79 | _livestockList.clear(); 80 | }); 81 | } 82 | 83 | var params={ 84 | "state":filterData.states.length>0?filterData.states:null, 85 | "type":filterData.type.length>0? filterData.type:null, 86 | "offset":(_offset+_pageSize).toString(), 87 | "pageSize":_pageSize.toString(), 88 | "searchTerm":searchQuery!=""?searchQuery:null 89 | }; 90 | params.removeWhere((key, value) => value==null) ; 91 | var response =await _livestockRepository.getLivestockList(params); 92 | if(response.status==Status.COMPLETED){ 93 | print(response.data.contents); 94 | setState(() { 95 | _livestockList.addAll(response.data.contents) ; 96 | _offset=response.data.offset; 97 | _pageSize=response.data.pageSize; 98 | _totalItems=response.data.totalElements; 99 | _loading=false; 100 | }); 101 | 102 | }else{ 103 | _scaffoldKey.currentState.showSnackBar(PinSnackBar(response.message).get()); 104 | } 105 | 106 | } 107 | 108 | String relativeDate(DateTime dateTime){ 109 | return timeago.format(dateTime,locale: 'fa'); 110 | } 111 | 112 | @override 113 | Widget build(BuildContext context) { 114 | return Scaffold( 115 | key: _scaffoldKey, 116 | appBar: AppBar( 117 | leading: BackButton(), 118 | centerTitle: true, 119 | title: _isSearching?_buildSearchField(): Text(widget.title), 120 | actions: _buildActions(), 121 | ), 122 | body:Container( 123 | color: Theme.of(context).scaffoldBackgroundColor, 124 | child: 125 | RefreshIndicator( 126 | onRefresh:()=>loadLivestock(true), 127 | child: _totalItems>0? SingleChildScrollView( 128 | physics: AlwaysScrollableScrollPhysics(), 129 | controller: scrollController, 130 | child: ListView.builder( 131 | primary: false, 132 | shrinkWrap: true, 133 | itemCount: _livestockList.length, 134 | itemBuilder: (BuildContext buildContext,int index){ 135 | Livestock item=_livestockList[index]; 136 | 137 | return Container( 138 | decoration: BoxDecoration( 139 | color: Colors.white, 140 | // borderRadius: BorderRadius.circular(5), 141 | boxShadow: [ 142 | BoxShadow( 143 | color: Colors.grey[200], 144 | blurRadius: .5, 145 | spreadRadius: .2, 146 | offset: Offset( 147 | 1, 148 | 1 149 | ) 150 | ) 151 | ] 152 | ), 153 | margin: EdgeInsets.only( 154 | // left: 5, 155 | // right: 5, 156 | top:1 157 | ), 158 | child: InkWell( 159 | child: Row( 160 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 161 | children: [ 162 | Flexible(flex: 2, child: Container( 163 | // width: 10, 164 | decoration: BoxDecoration( 165 | shape: BoxShape.circle, 166 | // color: Color(0xff369ee5) 167 | ), 168 | margin: EdgeInsets.only( 169 | bottom: 5 170 | ), 171 | padding: EdgeInsets.all(10), 172 | child: item.gender!=null && _livestockType[item.gender]!=null ? PinImage(url: "/assets/type/${item.gender}.png"):Container() 173 | ) 174 | ), 175 | Flexible(flex: 3, child:Container( 176 | width: double.infinity, 177 | margin: EdgeInsets.all(0), 178 | padding: EdgeInsets.only(top:20,bottom:20), 179 | child: Column( 180 | mainAxisAlignment: MainAxisAlignment.start, 181 | crossAxisAlignment: CrossAxisAlignment.start, 182 | children: [ 183 | Text((jsonDecode(_livestockType[item.gender])[Localizations.localeOf(context).languageCode]) ,style: Theme.of(context).textTheme.headline2,), 184 | Text(item.tagNo,style: Theme.of(context).textTheme.headline3,), 185 | 186 | ], 187 | ) 188 | )), 189 | Flexible(flex: 2, child: Container( 190 | 191 | padding: EdgeInsets.all(15), 192 | child: item.state!=null && _livestockState[item.state]!=null ? PinImage(url: "/assets/states/${item.state}.png"):Container(), 193 | 194 | ) 195 | ), 196 | Flexible(flex: 3, child:Container( 197 | width: double.infinity, 198 | margin: EdgeInsets.all(0), 199 | padding: EdgeInsets.only(top:20,bottom:20,left:5), 200 | child: Column( 201 | mainAxisAlignment: MainAxisAlignment.start, 202 | crossAxisAlignment: CrossAxisAlignment.start, 203 | children: [ 204 | Center(child:Text(item.state!=null?(jsonDecode(_livestockState[item.state])[Localizations.localeOf(context).languageCode]):AppLocalizations.of(context).list_birth_state,style: Theme.of(context).textTheme.headline2)), 205 | Center(child: Text( 206 | item.state!=null?DateUtil.formatLocaleDate(item.lastStateDate, context):DateUtil.formatLocaleDate(item.birthDate, context), 207 | )) 208 | // Icon(FontAwesomeIcons.sort,color: Colors.white,) 209 | ], 210 | ) 211 | )), 212 | ], 213 | ), 214 | onTap:()=> _onListItemClick(item), 215 | ) 216 | ); 217 | } 218 | ) 219 | ):( 220 | _totalItems==0?Center(child:Text(AppLocalizations.of(context).list_not_found)) 221 | :Center( child:CircularProgressIndicator()) 222 | ) 223 | 224 | ) 225 | ) 226 | ); 227 | } 228 | 229 | _onListItemClick(Livestock item)async{ 230 | final deletedItem= await Navigator.push( 231 | context, 232 | MaterialPageRoute(builder: (context) => Detail(livestock: item,)) 233 | ); 234 | 235 | if(deletedItem!=null ){ 236 | setState(() { 237 | _livestockList.removeWhere((element) => element.tagNo==deletedItem.tagNo); 238 | }); 239 | 240 | } 241 | 242 | } 243 | 244 | _buildSearchField(){ 245 | return TextField( 246 | onSubmitted: (query){ 247 | updateSearchQuery(query); 248 | }, 249 | textInputAction: TextInputAction.search, 250 | controller: _searchQueryController, 251 | autofocus: true, 252 | decoration: InputDecoration( 253 | hintText: AppLocalizations.of(context).list_search_tag_no, 254 | border: InputBorder.none, 255 | hintStyle: TextStyle(color: Colors.white30), 256 | ), 257 | style: TextStyle(color: Colors.white, fontSize: 16.0), 258 | onChanged: (query) => {}, 259 | ); 260 | } 261 | List _buildActions() { 262 | if (_isSearching) { 263 | return [ 264 | IconButton( 265 | icon: const Icon(Icons.clear), 266 | onPressed: () { 267 | if (_searchQueryController == null || 268 | _searchQueryController.text.isEmpty) { 269 | Navigator.pop(context); 270 | return; 271 | } 272 | _clearSearchQuery(); 273 | }, 274 | ), 275 | ]; 276 | } 277 | 278 | return [ 279 | IconButton( 280 | icon: const Icon(Icons.search), 281 | onPressed: _startSearch, 282 | ), 283 | IconButton( 284 | icon: const Icon(FontAwesome.sliders), 285 | onPressed: ()=>showFilterHandler(), 286 | ), 287 | ]; 288 | } 289 | 290 | showFilterHandler()async{ 291 | FilterData response=await showModalBottomSheet(context: context, builder: (context){ 292 | return Filter(filterData); 293 | }, 294 | shape: RoundedRectangleBorder( 295 | borderRadius: BorderRadius.vertical(top: Radius.circular(25.0)), 296 | ), 297 | backgroundColor: Colors.white, 298 | ); 299 | if(response!=null){ 300 | setState(() { 301 | filterData=response; 302 | }); 303 | loadLivestock(true); 304 | } 305 | } 306 | 307 | void _startSearch() { 308 | ModalRoute.of(context) 309 | .addLocalHistoryEntry(LocalHistoryEntry(onRemove: _stopSearching)); 310 | 311 | setState(() { 312 | _isSearching = true; 313 | }); 314 | } 315 | 316 | void updateSearchQuery(String newQuery) { 317 | setState(() { 318 | searchQuery = newQuery; 319 | }); 320 | loadLivestock(true); 321 | } 322 | 323 | void _stopSearching() { 324 | _clearSearchQuery(); 325 | 326 | setState(() { 327 | _isSearching = false; 328 | }); 329 | } 330 | 331 | void _clearSearchQuery() { 332 | setState(() { 333 | _searchQueryController.clear(); 334 | updateSearchQuery(""); 335 | }); 336 | } 337 | 338 | 339 | } -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "2.5.0-nullsafety" 11 | barcode_scan: 12 | dependency: "direct main" 13 | description: 14 | name: barcode_scan 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "3.0.1" 18 | boolean_selector: 19 | dependency: transitive 20 | description: 21 | name: boolean_selector 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "2.1.0-nullsafety" 25 | cached_network_image: 26 | dependency: "direct main" 27 | description: 28 | name: cached_network_image 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "2.3.3" 32 | characters: 33 | dependency: transitive 34 | description: 35 | name: characters 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "1.1.0-nullsafety.2" 39 | charcode: 40 | dependency: transitive 41 | description: 42 | name: charcode 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "1.2.0-nullsafety" 46 | charts_common: 47 | dependency: transitive 48 | description: 49 | name: charts_common 50 | url: "https://pub.dartlang.org" 51 | source: hosted 52 | version: "0.9.0" 53 | charts_flutter: 54 | dependency: "direct main" 55 | description: 56 | name: charts_flutter 57 | url: "https://pub.dartlang.org" 58 | source: hosted 59 | version: "0.9.0" 60 | chips_choice: 61 | dependency: "direct main" 62 | description: 63 | name: chips_choice 64 | url: "https://pub.dartlang.org" 65 | source: hosted 66 | version: "1.4.1" 67 | clock: 68 | dependency: transitive 69 | description: 70 | name: clock 71 | url: "https://pub.dartlang.org" 72 | source: hosted 73 | version: "1.1.0-nullsafety" 74 | collection: 75 | dependency: transitive 76 | description: 77 | name: collection 78 | url: "https://pub.dartlang.org" 79 | source: hosted 80 | version: "1.15.0-nullsafety.2" 81 | convert: 82 | dependency: transitive 83 | description: 84 | name: convert 85 | url: "https://pub.dartlang.org" 86 | source: hosted 87 | version: "2.1.1" 88 | crypto: 89 | dependency: transitive 90 | description: 91 | name: crypto 92 | url: "https://pub.dartlang.org" 93 | source: hosted 94 | version: "2.1.5" 95 | cupertino_icons: 96 | dependency: "direct main" 97 | description: 98 | name: cupertino_icons 99 | url: "https://pub.dartlang.org" 100 | source: hosted 101 | version: "0.1.3" 102 | fake_async: 103 | dependency: transitive 104 | description: 105 | name: fake_async 106 | url: "https://pub.dartlang.org" 107 | source: hosted 108 | version: "1.1.0-nullsafety" 109 | faker: 110 | dependency: "direct main" 111 | description: 112 | name: faker 113 | url: "https://pub.dartlang.org" 114 | source: hosted 115 | version: "1.2.1" 116 | ffi: 117 | dependency: transitive 118 | description: 119 | name: ffi 120 | url: "https://pub.dartlang.org" 121 | source: hosted 122 | version: "0.1.3" 123 | file: 124 | dependency: transitive 125 | description: 126 | name: file 127 | url: "https://pub.dartlang.org" 128 | source: hosted 129 | version: "5.2.1" 130 | fixnum: 131 | dependency: transitive 132 | description: 133 | name: fixnum 134 | url: "https://pub.dartlang.org" 135 | source: hosted 136 | version: "0.10.11" 137 | flutter: 138 | dependency: "direct main" 139 | description: flutter 140 | source: sdk 141 | version: "0.0.0" 142 | flutter_blurhash: 143 | dependency: transitive 144 | description: 145 | name: flutter_blurhash 146 | url: "https://pub.dartlang.org" 147 | source: hosted 148 | version: "0.5.0" 149 | flutter_cache_manager: 150 | dependency: transitive 151 | description: 152 | name: flutter_cache_manager 153 | url: "https://pub.dartlang.org" 154 | source: hosted 155 | version: "2.0.0" 156 | flutter_config: 157 | dependency: "direct main" 158 | description: 159 | name: flutter_config 160 | url: "https://pub.dartlang.org" 161 | source: hosted 162 | version: "1.0.7" 163 | flutter_icons: 164 | dependency: "direct main" 165 | description: 166 | name: flutter_icons 167 | url: "https://pub.dartlang.org" 168 | source: hosted 169 | version: "1.1.0" 170 | flutter_localizations: 171 | dependency: "direct main" 172 | description: flutter 173 | source: sdk 174 | version: "0.0.0" 175 | flutter_secure_storage: 176 | dependency: "direct main" 177 | description: 178 | name: flutter_secure_storage 179 | url: "https://pub.dartlang.org" 180 | source: hosted 181 | version: "3.3.5" 182 | flutter_svg: 183 | dependency: "direct main" 184 | description: 185 | name: flutter_svg 186 | url: "https://pub.dartlang.org" 187 | source: hosted 188 | version: "0.19.1" 189 | flutter_test: 190 | dependency: "direct dev" 191 | description: flutter 192 | source: sdk 193 | version: "0.0.0" 194 | font_awesome_flutter: 195 | dependency: "direct main" 196 | description: 197 | name: font_awesome_flutter 198 | url: "https://pub.dartlang.org" 199 | source: hosted 200 | version: "8.10.0" 201 | http: 202 | dependency: "direct main" 203 | description: 204 | name: http 205 | url: "https://pub.dartlang.org" 206 | source: hosted 207 | version: "0.12.2" 208 | http_parser: 209 | dependency: transitive 210 | description: 211 | name: http_parser 212 | url: "https://pub.dartlang.org" 213 | source: hosted 214 | version: "3.1.4" 215 | intl: 216 | dependency: "direct main" 217 | description: 218 | name: intl 219 | url: "https://pub.dartlang.org" 220 | source: hosted 221 | version: "0.16.1" 222 | logging: 223 | dependency: transitive 224 | description: 225 | name: logging 226 | url: "https://pub.dartlang.org" 227 | source: hosted 228 | version: "0.11.4" 229 | matcher: 230 | dependency: transitive 231 | description: 232 | name: matcher 233 | url: "https://pub.dartlang.org" 234 | source: hosted 235 | version: "0.12.10-nullsafety" 236 | meta: 237 | dependency: transitive 238 | description: 239 | name: meta 240 | url: "https://pub.dartlang.org" 241 | source: hosted 242 | version: "1.3.0-nullsafety.2" 243 | numeric_keyboard: 244 | dependency: "direct main" 245 | description: 246 | name: numeric_keyboard 247 | url: "https://pub.dartlang.org" 248 | source: hosted 249 | version: "1.0.0" 250 | octo_image: 251 | dependency: transitive 252 | description: 253 | name: octo_image 254 | url: "https://pub.dartlang.org" 255 | source: hosted 256 | version: "0.3.0" 257 | path: 258 | dependency: transitive 259 | description: 260 | name: path 261 | url: "https://pub.dartlang.org" 262 | source: hosted 263 | version: "1.8.0-nullsafety" 264 | path_drawing: 265 | dependency: transitive 266 | description: 267 | name: path_drawing 268 | url: "https://pub.dartlang.org" 269 | source: hosted 270 | version: "0.4.1+1" 271 | path_parsing: 272 | dependency: transitive 273 | description: 274 | name: path_parsing 275 | url: "https://pub.dartlang.org" 276 | source: hosted 277 | version: "0.1.4" 278 | path_provider: 279 | dependency: transitive 280 | description: 281 | name: path_provider 282 | url: "https://pub.dartlang.org" 283 | source: hosted 284 | version: "1.6.24" 285 | path_provider_linux: 286 | dependency: transitive 287 | description: 288 | name: path_provider_linux 289 | url: "https://pub.dartlang.org" 290 | source: hosted 291 | version: "0.0.1+2" 292 | path_provider_macos: 293 | dependency: transitive 294 | description: 295 | name: path_provider_macos 296 | url: "https://pub.dartlang.org" 297 | source: hosted 298 | version: "0.0.4+6" 299 | path_provider_platform_interface: 300 | dependency: transitive 301 | description: 302 | name: path_provider_platform_interface 303 | url: "https://pub.dartlang.org" 304 | source: hosted 305 | version: "1.0.4" 306 | path_provider_windows: 307 | dependency: transitive 308 | description: 309 | name: path_provider_windows 310 | url: "https://pub.dartlang.org" 311 | source: hosted 312 | version: "0.0.4+3" 313 | pedantic: 314 | dependency: transitive 315 | description: 316 | name: pedantic 317 | url: "https://pub.dartlang.org" 318 | source: hosted 319 | version: "1.9.2" 320 | persian_date: 321 | dependency: "direct main" 322 | description: 323 | name: persian_date 324 | url: "https://pub.dartlang.org" 325 | source: hosted 326 | version: "0.1.5" 327 | persian_datepicker: 328 | dependency: "direct main" 329 | description: 330 | name: persian_datepicker 331 | url: "https://pub.dartlang.org" 332 | source: hosted 333 | version: "1.3.1" 334 | petitparser: 335 | dependency: transitive 336 | description: 337 | name: petitparser 338 | url: "https://pub.dartlang.org" 339 | source: hosted 340 | version: "3.1.0" 341 | platform: 342 | dependency: transitive 343 | description: 344 | name: platform 345 | url: "https://pub.dartlang.org" 346 | source: hosted 347 | version: "2.2.1" 348 | plugin_platform_interface: 349 | dependency: transitive 350 | description: 351 | name: plugin_platform_interface 352 | url: "https://pub.dartlang.org" 353 | source: hosted 354 | version: "1.0.3" 355 | process: 356 | dependency: transitive 357 | description: 358 | name: process 359 | url: "https://pub.dartlang.org" 360 | source: hosted 361 | version: "3.0.13" 362 | protobuf: 363 | dependency: transitive 364 | description: 365 | name: protobuf 366 | url: "https://pub.dartlang.org" 367 | source: hosted 368 | version: "1.1.0" 369 | provider: 370 | dependency: "direct main" 371 | description: 372 | name: provider 373 | url: "https://pub.dartlang.org" 374 | source: hosted 375 | version: "3.2.0" 376 | rxdart: 377 | dependency: transitive 378 | description: 379 | name: rxdart 380 | url: "https://pub.dartlang.org" 381 | source: hosted 382 | version: "0.24.1" 383 | sentry: 384 | dependency: "direct main" 385 | description: 386 | name: sentry 387 | url: "https://pub.dartlang.org" 388 | source: hosted 389 | version: "3.0.1" 390 | settings_ui: 391 | dependency: "direct main" 392 | description: 393 | name: settings_ui 394 | url: "https://pub.dartlang.org" 395 | source: hosted 396 | version: "0.4.0" 397 | sky_engine: 398 | dependency: transitive 399 | description: flutter 400 | source: sdk 401 | version: "0.0.99" 402 | source_span: 403 | dependency: transitive 404 | description: 405 | name: source_span 406 | url: "https://pub.dartlang.org" 407 | source: hosted 408 | version: "1.8.0-nullsafety" 409 | sqflite: 410 | dependency: transitive 411 | description: 412 | name: sqflite 413 | url: "https://pub.dartlang.org" 414 | source: hosted 415 | version: "1.3.1+2" 416 | sqflite_common: 417 | dependency: transitive 418 | description: 419 | name: sqflite_common 420 | url: "https://pub.dartlang.org" 421 | source: hosted 422 | version: "1.0.2+1" 423 | stack_trace: 424 | dependency: transitive 425 | description: 426 | name: stack_trace 427 | url: "https://pub.dartlang.org" 428 | source: hosted 429 | version: "1.10.0-nullsafety" 430 | stream_channel: 431 | dependency: transitive 432 | description: 433 | name: stream_channel 434 | url: "https://pub.dartlang.org" 435 | source: hosted 436 | version: "2.1.0-nullsafety" 437 | string_scanner: 438 | dependency: transitive 439 | description: 440 | name: string_scanner 441 | url: "https://pub.dartlang.org" 442 | source: hosted 443 | version: "1.1.0-nullsafety" 444 | synchronized: 445 | dependency: transitive 446 | description: 447 | name: synchronized 448 | url: "https://pub.dartlang.org" 449 | source: hosted 450 | version: "2.2.0+2" 451 | term_glyph: 452 | dependency: transitive 453 | description: 454 | name: term_glyph 455 | url: "https://pub.dartlang.org" 456 | source: hosted 457 | version: "1.2.0-nullsafety" 458 | test_api: 459 | dependency: transitive 460 | description: 461 | name: test_api 462 | url: "https://pub.dartlang.org" 463 | source: hosted 464 | version: "0.2.19-nullsafety" 465 | timeago: 466 | dependency: "direct main" 467 | description: 468 | name: timeago 469 | url: "https://pub.dartlang.org" 470 | source: hosted 471 | version: "2.0.27" 472 | typed_data: 473 | dependency: transitive 474 | description: 475 | name: typed_data 476 | url: "https://pub.dartlang.org" 477 | source: hosted 478 | version: "1.3.0-nullsafety.2" 479 | usage: 480 | dependency: transitive 481 | description: 482 | name: usage 483 | url: "https://pub.dartlang.org" 484 | source: hosted 485 | version: "3.4.2" 486 | uuid: 487 | dependency: transitive 488 | description: 489 | name: uuid 490 | url: "https://pub.dartlang.org" 491 | source: hosted 492 | version: "2.2.2" 493 | vector_math: 494 | dependency: transitive 495 | description: 496 | name: vector_math 497 | url: "https://pub.dartlang.org" 498 | source: hosted 499 | version: "2.1.0-nullsafety.2" 500 | win32: 501 | dependency: transitive 502 | description: 503 | name: win32 504 | url: "https://pub.dartlang.org" 505 | source: hosted 506 | version: "1.7.4" 507 | xdg_directories: 508 | dependency: transitive 509 | description: 510 | name: xdg_directories 511 | url: "https://pub.dartlang.org" 512 | source: hosted 513 | version: "0.1.2" 514 | xml: 515 | dependency: transitive 516 | description: 517 | name: xml 518 | url: "https://pub.dartlang.org" 519 | source: hosted 520 | version: "4.5.1" 521 | sdks: 522 | dart: ">=2.10.0-0.0.dev <2.10.0" 523 | flutter: ">=1.20.0 <2.0.0" 524 | --------------------------------------------------------------------------------