| @@ -0,0 +1 @@ | |||||
| PATH_add /Users/amin/flutter/latest/bin | |||||
| @@ -0,0 +1,43 @@ | |||||
| # Miscellaneous | |||||
| *.class | |||||
| *.log | |||||
| *.pyc | |||||
| *.swp | |||||
| .DS_Store | |||||
| .atom/ | |||||
| .buildlog/ | |||||
| .history | |||||
| .svn/ | |||||
| migrate_working_dir/ | |||||
| # IntelliJ related | |||||
| *.iml | |||||
| *.ipr | |||||
| *.iws | |||||
| .idea/ | |||||
| # The .vscode folder contains launch configuration and tasks you configure in | |||||
| # VS Code which you may wish to be included in version control, so this line | |||||
| # is commented out by default. | |||||
| #.vscode/ | |||||
| # Flutter/Dart/Pub related | |||||
| **/doc/api/ | |||||
| **/ios/Flutter/.last_build_id | |||||
| .dart_tool/ | |||||
| .flutter-plugins | |||||
| .flutter-plugins-dependencies | |||||
| .pub-cache/ | |||||
| .pub/ | |||||
| /build/ | |||||
| # Symbolication related | |||||
| app.*.symbols | |||||
| # Obfuscation related | |||||
| app.*.map.json | |||||
| # Android Studio will place build artifacts here | |||||
| /android/app/debug | |||||
| /android/app/profile | |||||
| /android/app/release | |||||
| @@ -0,0 +1,45 @@ | |||||
| # This file tracks properties of this Flutter project. | |||||
| # Used by Flutter tool to assess capabilities and perform upgrades etc. | |||||
| # | |||||
| # This file should be version controlled and should not be manually edited. | |||||
| version: | |||||
| revision: "2663184aa79047d0a33a14a3b607954f8fdd8730" | |||||
| channel: "stable" | |||||
| project_type: app | |||||
| # Tracks metadata for the flutter migrate command | |||||
| migration: | |||||
| platforms: | |||||
| - platform: root | |||||
| create_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730 | |||||
| base_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730 | |||||
| - platform: android | |||||
| create_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730 | |||||
| base_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730 | |||||
| - platform: ios | |||||
| create_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730 | |||||
| base_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730 | |||||
| - platform: linux | |||||
| create_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730 | |||||
| base_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730 | |||||
| - platform: macos | |||||
| create_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730 | |||||
| base_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730 | |||||
| - platform: web | |||||
| create_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730 | |||||
| base_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730 | |||||
| - platform: windows | |||||
| create_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730 | |||||
| base_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730 | |||||
| # User provided section | |||||
| # List of Local paths (relative to this file) that should be | |||||
| # ignored by the migrate tool. | |||||
| # | |||||
| # Files that are not part of the templates will be ignored by default. | |||||
| unmanaged_files: | |||||
| - 'lib/main.dart' | |||||
| - 'ios/Runner.xcodeproj/project.pbxproj' | |||||
| @@ -0,0 +1,28 @@ | |||||
| # This file configures the analyzer, which statically analyzes Dart code to | |||||
| # check for errors, warnings, and lints. | |||||
| # | |||||
| # The issues identified by the analyzer are surfaced in the UI of Dart-enabled | |||||
| # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be | |||||
| # invoked from the command line by running `flutter analyze`. | |||||
| # The following line activates a set of recommended lints for Flutter apps, | |||||
| # packages, and plugins designed to encourage good coding practices. | |||||
| include: package:flutter_lints/flutter.yaml | |||||
| linter: | |||||
| # The lint rules applied to this project can be customized in the | |||||
| # section below to disable rules from the `package:flutter_lints/flutter.yaml` | |||||
| # included above or to enable additional rules. A list of all available lints | |||||
| # and their documentation is published at https://dart.dev/lints. | |||||
| # | |||||
| # Instead of disabling a lint rule for the entire project in the | |||||
| # section below, it can also be suppressed for a single line of code | |||||
| # or a specific dart file by using the `// ignore: name_of_lint` and | |||||
| # `// ignore_for_file: name_of_lint` syntax on the line or in the file | |||||
| # producing the lint. | |||||
| rules: | |||||
| # avoid_print: false # Uncomment to disable the `avoid_print` rule | |||||
| # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule | |||||
| # Additional information about this file can be found at | |||||
| # https://dart.dev/guides/language/analysis-options | |||||
| @@ -0,0 +1,13 @@ | |||||
| gradle-wrapper.jar | |||||
| /.gradle | |||||
| /captures/ | |||||
| /gradlew | |||||
| /gradlew.bat | |||||
| /local.properties | |||||
| GeneratedPluginRegistrant.java | |||||
| # Remember to never publicly share your keystore. | |||||
| # See https://flutter.dev/to/reference-keystore | |||||
| key.properties | |||||
| **/*.keystore | |||||
| **/*.jks | |||||
| @@ -0,0 +1,44 @@ | |||||
| plugins { | |||||
| id "com.android.application" | |||||
| id "kotlin-android" | |||||
| // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. | |||||
| id "dev.flutter.flutter-gradle-plugin" | |||||
| } | |||||
| android { | |||||
| namespace = "com.example.qadirneyriz" | |||||
| compileSdk = flutter.compileSdkVersion | |||||
| ndkVersion = flutter.ndkVersion | |||||
| compileOptions { | |||||
| sourceCompatibility = JavaVersion.VERSION_1_8 | |||||
| targetCompatibility = JavaVersion.VERSION_1_8 | |||||
| } | |||||
| kotlinOptions { | |||||
| jvmTarget = JavaVersion.VERSION_1_8 | |||||
| } | |||||
| defaultConfig { | |||||
| // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). | |||||
| applicationId = "com.example.qadirneyriz" | |||||
| // You can update the following values to match your application needs. | |||||
| // For more information, see: https://flutter.dev/to/review-gradle-config. | |||||
| minSdk = flutter.minSdkVersion | |||||
| targetSdk = flutter.targetSdkVersion | |||||
| versionCode = flutter.versionCode | |||||
| versionName = flutter.versionName | |||||
| } | |||||
| buildTypes { | |||||
| release { | |||||
| // TODO: Add your own signing config for the release build. | |||||
| // Signing with the debug keys for now, so `flutter run --release` works. | |||||
| signingConfig = signingConfigs.debug | |||||
| } | |||||
| } | |||||
| } | |||||
| flutter { | |||||
| source = "../.." | |||||
| } | |||||
| @@ -0,0 +1,7 @@ | |||||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android"> | |||||
| <!-- The INTERNET permission is required for development. Specifically, | |||||
| the Flutter tool needs it to communicate with the running application | |||||
| to allow setting breakpoints, to provide hot reload, etc. | |||||
| --> | |||||
| <uses-permission android:name="android.permission.INTERNET"/> | |||||
| </manifest> | |||||
| @@ -0,0 +1,45 @@ | |||||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android"> | |||||
| <application | |||||
| android:label="qadirneyriz" | |||||
| android:name="${applicationName}" | |||||
| android:icon="@mipmap/ic_launcher"> | |||||
| <activity | |||||
| android:name=".MainActivity" | |||||
| android:exported="true" | |||||
| android:launchMode="singleTop" | |||||
| android:taskAffinity="" | |||||
| android:theme="@style/LaunchTheme" | |||||
| android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" | |||||
| android:hardwareAccelerated="true" | |||||
| android:windowSoftInputMode="adjustResize"> | |||||
| <!-- Specifies an Android theme to apply to this Activity as soon as | |||||
| the Android process has started. This theme is visible to the user | |||||
| while the Flutter UI initializes. After that, this theme continues | |||||
| to determine the Window background behind the Flutter UI. --> | |||||
| <meta-data | |||||
| android:name="io.flutter.embedding.android.NormalTheme" | |||||
| android:resource="@style/NormalTheme" | |||||
| /> | |||||
| <intent-filter> | |||||
| <action android:name="android.intent.action.MAIN"/> | |||||
| <category android:name="android.intent.category.LAUNCHER"/> | |||||
| </intent-filter> | |||||
| </activity> | |||||
| <!-- Don't delete the meta-data below. | |||||
| This is used by the Flutter tool to generate GeneratedPluginRegistrant.java --> | |||||
| <meta-data | |||||
| android:name="flutterEmbedding" | |||||
| android:value="2" /> | |||||
| </application> | |||||
| <!-- Required to query activities that can process text, see: | |||||
| https://developer.android.com/training/package-visibility and | |||||
| https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT. | |||||
| In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. --> | |||||
| <queries> | |||||
| <intent> | |||||
| <action android:name="android.intent.action.PROCESS_TEXT"/> | |||||
| <data android:mimeType="text/plain"/> | |||||
| </intent> | |||||
| </queries> | |||||
| </manifest> | |||||
| @@ -0,0 +1,5 @@ | |||||
| package com.example.qadirneyriz | |||||
| import io.flutter.embedding.android.FlutterActivity | |||||
| class MainActivity: FlutterActivity() | |||||
| @@ -0,0 +1,12 @@ | |||||
| <?xml version="1.0" encoding="utf-8"?> | |||||
| <!-- Modify this file to customize your launch splash screen --> | |||||
| <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> | |||||
| <item android:drawable="?android:colorBackground" /> | |||||
| <!-- You can insert your own image assets here --> | |||||
| <!-- <item> | |||||
| <bitmap | |||||
| android:gravity="center" | |||||
| android:src="@mipmap/launch_image" /> | |||||
| </item> --> | |||||
| </layer-list> | |||||
| @@ -0,0 +1,12 @@ | |||||
| <?xml version="1.0" encoding="utf-8"?> | |||||
| <!-- Modify this file to customize your launch splash screen --> | |||||
| <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> | |||||
| <item android:drawable="@android:color/white" /> | |||||
| <!-- You can insert your own image assets here --> | |||||
| <!-- <item> | |||||
| <bitmap | |||||
| android:gravity="center" | |||||
| android:src="@mipmap/launch_image" /> | |||||
| </item> --> | |||||
| </layer-list> | |||||
| @@ -0,0 +1,18 @@ | |||||
| <?xml version="1.0" encoding="utf-8"?> | |||||
| <resources> | |||||
| <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on --> | |||||
| <style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar"> | |||||
| <!-- Show a splash screen on the activity. Automatically removed when | |||||
| the Flutter engine draws its first frame --> | |||||
| <item name="android:windowBackground">@drawable/launch_background</item> | |||||
| </style> | |||||
| <!-- Theme applied to the Android Window as soon as the process has started. | |||||
| This theme determines the color of the Android Window while your | |||||
| Flutter UI initializes, as well as behind your Flutter UI while its | |||||
| running. | |||||
| This Theme is only used starting with V2 of Flutter's Android embedding. --> | |||||
| <style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar"> | |||||
| <item name="android:windowBackground">?android:colorBackground</item> | |||||
| </style> | |||||
| </resources> | |||||
| @@ -0,0 +1,18 @@ | |||||
| <?xml version="1.0" encoding="utf-8"?> | |||||
| <resources> | |||||
| <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off --> | |||||
| <style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar"> | |||||
| <!-- Show a splash screen on the activity. Automatically removed when | |||||
| the Flutter engine draws its first frame --> | |||||
| <item name="android:windowBackground">@drawable/launch_background</item> | |||||
| </style> | |||||
| <!-- Theme applied to the Android Window as soon as the process has started. | |||||
| This theme determines the color of the Android Window while your | |||||
| Flutter UI initializes, as well as behind your Flutter UI while its | |||||
| running. | |||||
| This Theme is only used starting with V2 of Flutter's Android embedding. --> | |||||
| <style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar"> | |||||
| <item name="android:windowBackground">?android:colorBackground</item> | |||||
| </style> | |||||
| </resources> | |||||
| @@ -0,0 +1,7 @@ | |||||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android"> | |||||
| <!-- The INTERNET permission is required for development. Specifically, | |||||
| the Flutter tool needs it to communicate with the running application | |||||
| to allow setting breakpoints, to provide hot reload, etc. | |||||
| --> | |||||
| <uses-permission android:name="android.permission.INTERNET"/> | |||||
| </manifest> | |||||
| @@ -0,0 +1,18 @@ | |||||
| allprojects { | |||||
| repositories { | |||||
| google() | |||||
| mavenCentral() | |||||
| } | |||||
| } | |||||
| rootProject.buildDir = "../build" | |||||
| subprojects { | |||||
| project.buildDir = "${rootProject.buildDir}/${project.name}" | |||||
| } | |||||
| subprojects { | |||||
| project.evaluationDependsOn(":app") | |||||
| } | |||||
| tasks.register("clean", Delete) { | |||||
| delete rootProject.buildDir | |||||
| } | |||||
| @@ -0,0 +1,3 @@ | |||||
| org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError | |||||
| android.useAndroidX=true | |||||
| android.enableJetifier=true | |||||
| @@ -0,0 +1,5 @@ | |||||
| distributionBase=GRADLE_USER_HOME | |||||
| distributionPath=wrapper/dists | |||||
| zipStoreBase=GRADLE_USER_HOME | |||||
| zipStorePath=wrapper/dists | |||||
| distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip | |||||
| @@ -0,0 +1,25 @@ | |||||
| pluginManagement { | |||||
| def flutterSdkPath = { | |||||
| def properties = new Properties() | |||||
| file("local.properties").withInputStream { properties.load(it) } | |||||
| def flutterSdkPath = properties.getProperty("flutter.sdk") | |||||
| assert flutterSdkPath != null, "flutter.sdk not set in local.properties" | |||||
| return flutterSdkPath | |||||
| }() | |||||
| includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") | |||||
| repositories { | |||||
| google() | |||||
| mavenCentral() | |||||
| gradlePluginPortal() | |||||
| } | |||||
| } | |||||
| plugins { | |||||
| id "dev.flutter.flutter-plugin-loader" version "1.0.0" | |||||
| id "com.android.application" version "8.1.0" apply false | |||||
| id "org.jetbrains.kotlin.android" version "1.8.22" apply false | |||||
| } | |||||
| include ":app" | |||||
| @@ -0,0 +1,34 @@ | |||||
| **/dgph | |||||
| *.mode1v3 | |||||
| *.mode2v3 | |||||
| *.moved-aside | |||||
| *.pbxuser | |||||
| *.perspectivev3 | |||||
| **/*sync/ | |||||
| .sconsign.dblite | |||||
| .tags* | |||||
| **/.vagrant/ | |||||
| **/DerivedData/ | |||||
| Icon? | |||||
| **/Pods/ | |||||
| **/.symlinks/ | |||||
| profile | |||||
| xcuserdata | |||||
| **/.generated/ | |||||
| Flutter/App.framework | |||||
| Flutter/Flutter.framework | |||||
| Flutter/Flutter.podspec | |||||
| Flutter/Generated.xcconfig | |||||
| Flutter/ephemeral/ | |||||
| Flutter/app.flx | |||||
| Flutter/app.zip | |||||
| Flutter/flutter_assets/ | |||||
| Flutter/flutter_export_environment.sh | |||||
| ServiceDefinitions.json | |||||
| Runner/GeneratedPluginRegistrant.* | |||||
| # Exceptions to above rules. | |||||
| !default.mode1v3 | |||||
| !default.mode2v3 | |||||
| !default.pbxuser | |||||
| !default.perspectivev3 | |||||
| @@ -0,0 +1,26 @@ | |||||
| <?xml version="1.0" encoding="UTF-8"?> | |||||
| <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |||||
| <plist version="1.0"> | |||||
| <dict> | |||||
| <key>CFBundleDevelopmentRegion</key> | |||||
| <string>en</string> | |||||
| <key>CFBundleExecutable</key> | |||||
| <string>App</string> | |||||
| <key>CFBundleIdentifier</key> | |||||
| <string>io.flutter.flutter.app</string> | |||||
| <key>CFBundleInfoDictionaryVersion</key> | |||||
| <string>6.0</string> | |||||
| <key>CFBundleName</key> | |||||
| <string>App</string> | |||||
| <key>CFBundlePackageType</key> | |||||
| <string>FMWK</string> | |||||
| <key>CFBundleShortVersionString</key> | |||||
| <string>1.0</string> | |||||
| <key>CFBundleSignature</key> | |||||
| <string>????</string> | |||||
| <key>CFBundleVersion</key> | |||||
| <string>1.0</string> | |||||
| <key>MinimumOSVersion</key> | |||||
| <string>12.0</string> | |||||
| </dict> | |||||
| </plist> | |||||
| @@ -0,0 +1 @@ | |||||
| #include "Generated.xcconfig" | |||||
| @@ -0,0 +1 @@ | |||||
| #include "Generated.xcconfig" | |||||
| @@ -0,0 +1,616 @@ | |||||
| // !$*UTF8*$! | |||||
| { | |||||
| archiveVersion = 1; | |||||
| classes = { | |||||
| }; | |||||
| objectVersion = 54; | |||||
| objects = { | |||||
| /* Begin PBXBuildFile section */ | |||||
| 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; | |||||
| 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; | |||||
| 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; | |||||
| 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; | |||||
| 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; | |||||
| 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; | |||||
| 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; | |||||
| /* End PBXBuildFile section */ | |||||
| /* Begin PBXContainerItemProxy section */ | |||||
| 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { | |||||
| isa = PBXContainerItemProxy; | |||||
| containerPortal = 97C146E61CF9000F007C117D /* Project object */; | |||||
| proxyType = 1; | |||||
| remoteGlobalIDString = 97C146ED1CF9000F007C117D; | |||||
| remoteInfo = Runner; | |||||
| }; | |||||
| /* End PBXContainerItemProxy section */ | |||||
| /* Begin PBXCopyFilesBuildPhase section */ | |||||
| 9705A1C41CF9048500538489 /* Embed Frameworks */ = { | |||||
| isa = PBXCopyFilesBuildPhase; | |||||
| buildActionMask = 2147483647; | |||||
| dstPath = ""; | |||||
| dstSubfolderSpec = 10; | |||||
| files = ( | |||||
| ); | |||||
| name = "Embed Frameworks"; | |||||
| runOnlyForDeploymentPostprocessing = 0; | |||||
| }; | |||||
| /* End PBXCopyFilesBuildPhase section */ | |||||
| /* Begin PBXFileReference section */ | |||||
| 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; }; | |||||
| 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; }; | |||||
| 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; }; | |||||
| 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; | |||||
| 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; }; | |||||
| 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; }; | |||||
| 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; | |||||
| 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; }; | |||||
| 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; }; | |||||
| 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; }; | |||||
| 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; | |||||
| 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; }; | |||||
| 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; }; | |||||
| 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; }; | |||||
| 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; | |||||
| /* End PBXFileReference section */ | |||||
| /* Begin PBXFrameworksBuildPhase section */ | |||||
| 97C146EB1CF9000F007C117D /* Frameworks */ = { | |||||
| isa = PBXFrameworksBuildPhase; | |||||
| buildActionMask = 2147483647; | |||||
| files = ( | |||||
| ); | |||||
| runOnlyForDeploymentPostprocessing = 0; | |||||
| }; | |||||
| /* End PBXFrameworksBuildPhase section */ | |||||
| /* Begin PBXGroup section */ | |||||
| 331C8082294A63A400263BE5 /* RunnerTests */ = { | |||||
| isa = PBXGroup; | |||||
| children = ( | |||||
| 331C807B294A618700263BE5 /* RunnerTests.swift */, | |||||
| ); | |||||
| path = RunnerTests; | |||||
| sourceTree = "<group>"; | |||||
| }; | |||||
| 9740EEB11CF90186004384FC /* Flutter */ = { | |||||
| isa = PBXGroup; | |||||
| children = ( | |||||
| 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, | |||||
| 9740EEB21CF90195004384FC /* Debug.xcconfig */, | |||||
| 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, | |||||
| 9740EEB31CF90195004384FC /* Generated.xcconfig */, | |||||
| ); | |||||
| name = Flutter; | |||||
| sourceTree = "<group>"; | |||||
| }; | |||||
| 97C146E51CF9000F007C117D = { | |||||
| isa = PBXGroup; | |||||
| children = ( | |||||
| 9740EEB11CF90186004384FC /* Flutter */, | |||||
| 97C146F01CF9000F007C117D /* Runner */, | |||||
| 97C146EF1CF9000F007C117D /* Products */, | |||||
| 331C8082294A63A400263BE5 /* RunnerTests */, | |||||
| ); | |||||
| sourceTree = "<group>"; | |||||
| }; | |||||
| 97C146EF1CF9000F007C117D /* Products */ = { | |||||
| isa = PBXGroup; | |||||
| children = ( | |||||
| 97C146EE1CF9000F007C117D /* Runner.app */, | |||||
| 331C8081294A63A400263BE5 /* RunnerTests.xctest */, | |||||
| ); | |||||
| name = Products; | |||||
| sourceTree = "<group>"; | |||||
| }; | |||||
| 97C146F01CF9000F007C117D /* Runner */ = { | |||||
| isa = PBXGroup; | |||||
| children = ( | |||||
| 97C146FA1CF9000F007C117D /* Main.storyboard */, | |||||
| 97C146FD1CF9000F007C117D /* Assets.xcassets */, | |||||
| 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, | |||||
| 97C147021CF9000F007C117D /* Info.plist */, | |||||
| 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, | |||||
| 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, | |||||
| 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, | |||||
| 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, | |||||
| ); | |||||
| path = Runner; | |||||
| sourceTree = "<group>"; | |||||
| }; | |||||
| /* End PBXGroup section */ | |||||
| /* Begin PBXNativeTarget section */ | |||||
| 331C8080294A63A400263BE5 /* RunnerTests */ = { | |||||
| isa = PBXNativeTarget; | |||||
| buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; | |||||
| buildPhases = ( | |||||
| 331C807D294A63A400263BE5 /* Sources */, | |||||
| 331C807F294A63A400263BE5 /* Resources */, | |||||
| ); | |||||
| buildRules = ( | |||||
| ); | |||||
| dependencies = ( | |||||
| 331C8086294A63A400263BE5 /* PBXTargetDependency */, | |||||
| ); | |||||
| name = RunnerTests; | |||||
| productName = RunnerTests; | |||||
| productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; | |||||
| productType = "com.apple.product-type.bundle.unit-test"; | |||||
| }; | |||||
| 97C146ED1CF9000F007C117D /* Runner */ = { | |||||
| isa = PBXNativeTarget; | |||||
| buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; | |||||
| buildPhases = ( | |||||
| 9740EEB61CF901F6004384FC /* Run Script */, | |||||
| 97C146EA1CF9000F007C117D /* Sources */, | |||||
| 97C146EB1CF9000F007C117D /* Frameworks */, | |||||
| 97C146EC1CF9000F007C117D /* Resources */, | |||||
| 9705A1C41CF9048500538489 /* Embed Frameworks */, | |||||
| 3B06AD1E1E4923F5004D2608 /* Thin Binary */, | |||||
| ); | |||||
| buildRules = ( | |||||
| ); | |||||
| dependencies = ( | |||||
| ); | |||||
| name = Runner; | |||||
| productName = Runner; | |||||
| productReference = 97C146EE1CF9000F007C117D /* Runner.app */; | |||||
| productType = "com.apple.product-type.application"; | |||||
| }; | |||||
| /* End PBXNativeTarget section */ | |||||
| /* Begin PBXProject section */ | |||||
| 97C146E61CF9000F007C117D /* Project object */ = { | |||||
| isa = PBXProject; | |||||
| attributes = { | |||||
| BuildIndependentTargetsInParallel = YES; | |||||
| LastUpgradeCheck = 1510; | |||||
| ORGANIZATIONNAME = ""; | |||||
| TargetAttributes = { | |||||
| 331C8080294A63A400263BE5 = { | |||||
| CreatedOnToolsVersion = 14.0; | |||||
| TestTargetID = 97C146ED1CF9000F007C117D; | |||||
| }; | |||||
| 97C146ED1CF9000F007C117D = { | |||||
| CreatedOnToolsVersion = 7.3.1; | |||||
| LastSwiftMigration = 1100; | |||||
| }; | |||||
| }; | |||||
| }; | |||||
| buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; | |||||
| compatibilityVersion = "Xcode 9.3"; | |||||
| developmentRegion = en; | |||||
| hasScannedForEncodings = 0; | |||||
| knownRegions = ( | |||||
| en, | |||||
| Base, | |||||
| ); | |||||
| mainGroup = 97C146E51CF9000F007C117D; | |||||
| productRefGroup = 97C146EF1CF9000F007C117D /* Products */; | |||||
| projectDirPath = ""; | |||||
| projectRoot = ""; | |||||
| targets = ( | |||||
| 97C146ED1CF9000F007C117D /* Runner */, | |||||
| 331C8080294A63A400263BE5 /* RunnerTests */, | |||||
| ); | |||||
| }; | |||||
| /* End PBXProject section */ | |||||
| /* Begin PBXResourcesBuildPhase section */ | |||||
| 331C807F294A63A400263BE5 /* Resources */ = { | |||||
| isa = PBXResourcesBuildPhase; | |||||
| buildActionMask = 2147483647; | |||||
| files = ( | |||||
| ); | |||||
| runOnlyForDeploymentPostprocessing = 0; | |||||
| }; | |||||
| 97C146EC1CF9000F007C117D /* Resources */ = { | |||||
| isa = PBXResourcesBuildPhase; | |||||
| buildActionMask = 2147483647; | |||||
| files = ( | |||||
| 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, | |||||
| 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, | |||||
| 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, | |||||
| 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, | |||||
| ); | |||||
| runOnlyForDeploymentPostprocessing = 0; | |||||
| }; | |||||
| /* End PBXResourcesBuildPhase section */ | |||||
| /* Begin PBXShellScriptBuildPhase section */ | |||||
| 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { | |||||
| isa = PBXShellScriptBuildPhase; | |||||
| alwaysOutOfDate = 1; | |||||
| buildActionMask = 2147483647; | |||||
| files = ( | |||||
| ); | |||||
| inputPaths = ( | |||||
| "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", | |||||
| ); | |||||
| name = "Thin Binary"; | |||||
| outputPaths = ( | |||||
| ); | |||||
| runOnlyForDeploymentPostprocessing = 0; | |||||
| shellPath = /bin/sh; | |||||
| shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; | |||||
| }; | |||||
| 9740EEB61CF901F6004384FC /* Run Script */ = { | |||||
| isa = PBXShellScriptBuildPhase; | |||||
| alwaysOutOfDate = 1; | |||||
| buildActionMask = 2147483647; | |||||
| files = ( | |||||
| ); | |||||
| inputPaths = ( | |||||
| ); | |||||
| name = "Run Script"; | |||||
| outputPaths = ( | |||||
| ); | |||||
| runOnlyForDeploymentPostprocessing = 0; | |||||
| shellPath = /bin/sh; | |||||
| shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; | |||||
| }; | |||||
| /* End PBXShellScriptBuildPhase section */ | |||||
| /* Begin PBXSourcesBuildPhase section */ | |||||
| 331C807D294A63A400263BE5 /* Sources */ = { | |||||
| isa = PBXSourcesBuildPhase; | |||||
| buildActionMask = 2147483647; | |||||
| files = ( | |||||
| 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, | |||||
| ); | |||||
| runOnlyForDeploymentPostprocessing = 0; | |||||
| }; | |||||
| 97C146EA1CF9000F007C117D /* Sources */ = { | |||||
| isa = PBXSourcesBuildPhase; | |||||
| buildActionMask = 2147483647; | |||||
| files = ( | |||||
| 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, | |||||
| 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, | |||||
| ); | |||||
| runOnlyForDeploymentPostprocessing = 0; | |||||
| }; | |||||
| /* End PBXSourcesBuildPhase section */ | |||||
| /* Begin PBXTargetDependency section */ | |||||
| 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { | |||||
| isa = PBXTargetDependency; | |||||
| target = 97C146ED1CF9000F007C117D /* Runner */; | |||||
| targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; | |||||
| }; | |||||
| /* End PBXTargetDependency section */ | |||||
| /* Begin PBXVariantGroup section */ | |||||
| 97C146FA1CF9000F007C117D /* Main.storyboard */ = { | |||||
| isa = PBXVariantGroup; | |||||
| children = ( | |||||
| 97C146FB1CF9000F007C117D /* Base */, | |||||
| ); | |||||
| name = Main.storyboard; | |||||
| sourceTree = "<group>"; | |||||
| }; | |||||
| 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { | |||||
| isa = PBXVariantGroup; | |||||
| children = ( | |||||
| 97C147001CF9000F007C117D /* Base */, | |||||
| ); | |||||
| name = LaunchScreen.storyboard; | |||||
| sourceTree = "<group>"; | |||||
| }; | |||||
| /* End PBXVariantGroup section */ | |||||
| /* Begin XCBuildConfiguration section */ | |||||
| 249021D3217E4FDB00AE95B9 /* Profile */ = { | |||||
| isa = XCBuildConfiguration; | |||||
| buildSettings = { | |||||
| ALWAYS_SEARCH_USER_PATHS = NO; | |||||
| ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; | |||||
| CLANG_ANALYZER_NONNULL = YES; | |||||
| CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; | |||||
| CLANG_CXX_LIBRARY = "libc++"; | |||||
| CLANG_ENABLE_MODULES = YES; | |||||
| CLANG_ENABLE_OBJC_ARC = YES; | |||||
| CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; | |||||
| CLANG_WARN_BOOL_CONVERSION = YES; | |||||
| CLANG_WARN_COMMA = YES; | |||||
| CLANG_WARN_CONSTANT_CONVERSION = YES; | |||||
| CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; | |||||
| CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; | |||||
| CLANG_WARN_EMPTY_BODY = YES; | |||||
| CLANG_WARN_ENUM_CONVERSION = YES; | |||||
| CLANG_WARN_INFINITE_RECURSION = YES; | |||||
| CLANG_WARN_INT_CONVERSION = YES; | |||||
| CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; | |||||
| CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; | |||||
| CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; | |||||
| CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; | |||||
| CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; | |||||
| CLANG_WARN_STRICT_PROTOTYPES = YES; | |||||
| CLANG_WARN_SUSPICIOUS_MOVE = YES; | |||||
| CLANG_WARN_UNREACHABLE_CODE = YES; | |||||
| CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; | |||||
| "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; | |||||
| COPY_PHASE_STRIP = NO; | |||||
| DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; | |||||
| ENABLE_NS_ASSERTIONS = NO; | |||||
| ENABLE_STRICT_OBJC_MSGSEND = YES; | |||||
| ENABLE_USER_SCRIPT_SANDBOXING = NO; | |||||
| GCC_C_LANGUAGE_STANDARD = gnu99; | |||||
| GCC_NO_COMMON_BLOCKS = YES; | |||||
| GCC_WARN_64_TO_32_BIT_CONVERSION = YES; | |||||
| GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; | |||||
| GCC_WARN_UNDECLARED_SELECTOR = YES; | |||||
| GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; | |||||
| GCC_WARN_UNUSED_FUNCTION = YES; | |||||
| GCC_WARN_UNUSED_VARIABLE = YES; | |||||
| IPHONEOS_DEPLOYMENT_TARGET = 12.0; | |||||
| MTL_ENABLE_DEBUG_INFO = NO; | |||||
| SDKROOT = iphoneos; | |||||
| SUPPORTED_PLATFORMS = iphoneos; | |||||
| TARGETED_DEVICE_FAMILY = "1,2"; | |||||
| VALIDATE_PRODUCT = YES; | |||||
| }; | |||||
| name = Profile; | |||||
| }; | |||||
| 249021D4217E4FDB00AE95B9 /* Profile */ = { | |||||
| isa = XCBuildConfiguration; | |||||
| baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; | |||||
| buildSettings = { | |||||
| ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; | |||||
| CLANG_ENABLE_MODULES = YES; | |||||
| CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; | |||||
| ENABLE_BITCODE = NO; | |||||
| INFOPLIST_FILE = Runner/Info.plist; | |||||
| LD_RUNPATH_SEARCH_PATHS = ( | |||||
| "$(inherited)", | |||||
| "@executable_path/Frameworks", | |||||
| ); | |||||
| PRODUCT_BUNDLE_IDENTIFIER = com.example.qadirneyriz; | |||||
| PRODUCT_NAME = "$(TARGET_NAME)"; | |||||
| SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; | |||||
| SWIFT_VERSION = 5.0; | |||||
| VERSIONING_SYSTEM = "apple-generic"; | |||||
| }; | |||||
| name = Profile; | |||||
| }; | |||||
| 331C8088294A63A400263BE5 /* Debug */ = { | |||||
| isa = XCBuildConfiguration; | |||||
| buildSettings = { | |||||
| BUNDLE_LOADER = "$(TEST_HOST)"; | |||||
| CODE_SIGN_STYLE = Automatic; | |||||
| CURRENT_PROJECT_VERSION = 1; | |||||
| GENERATE_INFOPLIST_FILE = YES; | |||||
| MARKETING_VERSION = 1.0; | |||||
| PRODUCT_BUNDLE_IDENTIFIER = com.example.qadirneyriz.RunnerTests; | |||||
| PRODUCT_NAME = "$(TARGET_NAME)"; | |||||
| SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; | |||||
| SWIFT_OPTIMIZATION_LEVEL = "-Onone"; | |||||
| SWIFT_VERSION = 5.0; | |||||
| TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; | |||||
| }; | |||||
| name = Debug; | |||||
| }; | |||||
| 331C8089294A63A400263BE5 /* Release */ = { | |||||
| isa = XCBuildConfiguration; | |||||
| buildSettings = { | |||||
| BUNDLE_LOADER = "$(TEST_HOST)"; | |||||
| CODE_SIGN_STYLE = Automatic; | |||||
| CURRENT_PROJECT_VERSION = 1; | |||||
| GENERATE_INFOPLIST_FILE = YES; | |||||
| MARKETING_VERSION = 1.0; | |||||
| PRODUCT_BUNDLE_IDENTIFIER = com.example.qadirneyriz.RunnerTests; | |||||
| PRODUCT_NAME = "$(TARGET_NAME)"; | |||||
| SWIFT_VERSION = 5.0; | |||||
| TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; | |||||
| }; | |||||
| name = Release; | |||||
| }; | |||||
| 331C808A294A63A400263BE5 /* Profile */ = { | |||||
| isa = XCBuildConfiguration; | |||||
| buildSettings = { | |||||
| BUNDLE_LOADER = "$(TEST_HOST)"; | |||||
| CODE_SIGN_STYLE = Automatic; | |||||
| CURRENT_PROJECT_VERSION = 1; | |||||
| GENERATE_INFOPLIST_FILE = YES; | |||||
| MARKETING_VERSION = 1.0; | |||||
| PRODUCT_BUNDLE_IDENTIFIER = com.example.qadirneyriz.RunnerTests; | |||||
| PRODUCT_NAME = "$(TARGET_NAME)"; | |||||
| SWIFT_VERSION = 5.0; | |||||
| TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; | |||||
| }; | |||||
| name = Profile; | |||||
| }; | |||||
| 97C147031CF9000F007C117D /* Debug */ = { | |||||
| isa = XCBuildConfiguration; | |||||
| buildSettings = { | |||||
| ALWAYS_SEARCH_USER_PATHS = NO; | |||||
| ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; | |||||
| CLANG_ANALYZER_NONNULL = YES; | |||||
| CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; | |||||
| CLANG_CXX_LIBRARY = "libc++"; | |||||
| CLANG_ENABLE_MODULES = YES; | |||||
| CLANG_ENABLE_OBJC_ARC = YES; | |||||
| CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; | |||||
| CLANG_WARN_BOOL_CONVERSION = YES; | |||||
| CLANG_WARN_COMMA = YES; | |||||
| CLANG_WARN_CONSTANT_CONVERSION = YES; | |||||
| CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; | |||||
| CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; | |||||
| CLANG_WARN_EMPTY_BODY = YES; | |||||
| CLANG_WARN_ENUM_CONVERSION = YES; | |||||
| CLANG_WARN_INFINITE_RECURSION = YES; | |||||
| CLANG_WARN_INT_CONVERSION = YES; | |||||
| CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; | |||||
| CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; | |||||
| CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; | |||||
| CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; | |||||
| CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; | |||||
| CLANG_WARN_STRICT_PROTOTYPES = YES; | |||||
| CLANG_WARN_SUSPICIOUS_MOVE = YES; | |||||
| CLANG_WARN_UNREACHABLE_CODE = YES; | |||||
| CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; | |||||
| "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; | |||||
| COPY_PHASE_STRIP = NO; | |||||
| DEBUG_INFORMATION_FORMAT = dwarf; | |||||
| ENABLE_STRICT_OBJC_MSGSEND = YES; | |||||
| ENABLE_TESTABILITY = YES; | |||||
| ENABLE_USER_SCRIPT_SANDBOXING = NO; | |||||
| GCC_C_LANGUAGE_STANDARD = gnu99; | |||||
| GCC_DYNAMIC_NO_PIC = NO; | |||||
| GCC_NO_COMMON_BLOCKS = YES; | |||||
| GCC_OPTIMIZATION_LEVEL = 0; | |||||
| GCC_PREPROCESSOR_DEFINITIONS = ( | |||||
| "DEBUG=1", | |||||
| "$(inherited)", | |||||
| ); | |||||
| GCC_WARN_64_TO_32_BIT_CONVERSION = YES; | |||||
| GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; | |||||
| GCC_WARN_UNDECLARED_SELECTOR = YES; | |||||
| GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; | |||||
| GCC_WARN_UNUSED_FUNCTION = YES; | |||||
| GCC_WARN_UNUSED_VARIABLE = YES; | |||||
| IPHONEOS_DEPLOYMENT_TARGET = 12.0; | |||||
| MTL_ENABLE_DEBUG_INFO = YES; | |||||
| ONLY_ACTIVE_ARCH = YES; | |||||
| SDKROOT = iphoneos; | |||||
| TARGETED_DEVICE_FAMILY = "1,2"; | |||||
| }; | |||||
| name = Debug; | |||||
| }; | |||||
| 97C147041CF9000F007C117D /* Release */ = { | |||||
| isa = XCBuildConfiguration; | |||||
| buildSettings = { | |||||
| ALWAYS_SEARCH_USER_PATHS = NO; | |||||
| ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; | |||||
| CLANG_ANALYZER_NONNULL = YES; | |||||
| CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; | |||||
| CLANG_CXX_LIBRARY = "libc++"; | |||||
| CLANG_ENABLE_MODULES = YES; | |||||
| CLANG_ENABLE_OBJC_ARC = YES; | |||||
| CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; | |||||
| CLANG_WARN_BOOL_CONVERSION = YES; | |||||
| CLANG_WARN_COMMA = YES; | |||||
| CLANG_WARN_CONSTANT_CONVERSION = YES; | |||||
| CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; | |||||
| CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; | |||||
| CLANG_WARN_EMPTY_BODY = YES; | |||||
| CLANG_WARN_ENUM_CONVERSION = YES; | |||||
| CLANG_WARN_INFINITE_RECURSION = YES; | |||||
| CLANG_WARN_INT_CONVERSION = YES; | |||||
| CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; | |||||
| CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; | |||||
| CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; | |||||
| CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; | |||||
| CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; | |||||
| CLANG_WARN_STRICT_PROTOTYPES = YES; | |||||
| CLANG_WARN_SUSPICIOUS_MOVE = YES; | |||||
| CLANG_WARN_UNREACHABLE_CODE = YES; | |||||
| CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; | |||||
| "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; | |||||
| COPY_PHASE_STRIP = NO; | |||||
| DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; | |||||
| ENABLE_NS_ASSERTIONS = NO; | |||||
| ENABLE_STRICT_OBJC_MSGSEND = YES; | |||||
| ENABLE_USER_SCRIPT_SANDBOXING = NO; | |||||
| GCC_C_LANGUAGE_STANDARD = gnu99; | |||||
| GCC_NO_COMMON_BLOCKS = YES; | |||||
| GCC_WARN_64_TO_32_BIT_CONVERSION = YES; | |||||
| GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; | |||||
| GCC_WARN_UNDECLARED_SELECTOR = YES; | |||||
| GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; | |||||
| GCC_WARN_UNUSED_FUNCTION = YES; | |||||
| GCC_WARN_UNUSED_VARIABLE = YES; | |||||
| IPHONEOS_DEPLOYMENT_TARGET = 12.0; | |||||
| MTL_ENABLE_DEBUG_INFO = NO; | |||||
| SDKROOT = iphoneos; | |||||
| SUPPORTED_PLATFORMS = iphoneos; | |||||
| SWIFT_COMPILATION_MODE = wholemodule; | |||||
| SWIFT_OPTIMIZATION_LEVEL = "-O"; | |||||
| TARGETED_DEVICE_FAMILY = "1,2"; | |||||
| VALIDATE_PRODUCT = YES; | |||||
| }; | |||||
| name = Release; | |||||
| }; | |||||
| 97C147061CF9000F007C117D /* Debug */ = { | |||||
| isa = XCBuildConfiguration; | |||||
| baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; | |||||
| buildSettings = { | |||||
| ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; | |||||
| CLANG_ENABLE_MODULES = YES; | |||||
| CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; | |||||
| ENABLE_BITCODE = NO; | |||||
| INFOPLIST_FILE = Runner/Info.plist; | |||||
| LD_RUNPATH_SEARCH_PATHS = ( | |||||
| "$(inherited)", | |||||
| "@executable_path/Frameworks", | |||||
| ); | |||||
| PRODUCT_BUNDLE_IDENTIFIER = com.example.qadirneyriz; | |||||
| PRODUCT_NAME = "$(TARGET_NAME)"; | |||||
| SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; | |||||
| SWIFT_OPTIMIZATION_LEVEL = "-Onone"; | |||||
| SWIFT_VERSION = 5.0; | |||||
| VERSIONING_SYSTEM = "apple-generic"; | |||||
| }; | |||||
| name = Debug; | |||||
| }; | |||||
| 97C147071CF9000F007C117D /* Release */ = { | |||||
| isa = XCBuildConfiguration; | |||||
| baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; | |||||
| buildSettings = { | |||||
| ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; | |||||
| CLANG_ENABLE_MODULES = YES; | |||||
| CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; | |||||
| ENABLE_BITCODE = NO; | |||||
| INFOPLIST_FILE = Runner/Info.plist; | |||||
| LD_RUNPATH_SEARCH_PATHS = ( | |||||
| "$(inherited)", | |||||
| "@executable_path/Frameworks", | |||||
| ); | |||||
| PRODUCT_BUNDLE_IDENTIFIER = com.example.qadirneyriz; | |||||
| PRODUCT_NAME = "$(TARGET_NAME)"; | |||||
| SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; | |||||
| SWIFT_VERSION = 5.0; | |||||
| VERSIONING_SYSTEM = "apple-generic"; | |||||
| }; | |||||
| name = Release; | |||||
| }; | |||||
| /* End XCBuildConfiguration section */ | |||||
| /* Begin XCConfigurationList section */ | |||||
| 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { | |||||
| isa = XCConfigurationList; | |||||
| buildConfigurations = ( | |||||
| 331C8088294A63A400263BE5 /* Debug */, | |||||
| 331C8089294A63A400263BE5 /* Release */, | |||||
| 331C808A294A63A400263BE5 /* Profile */, | |||||
| ); | |||||
| defaultConfigurationIsVisible = 0; | |||||
| defaultConfigurationName = Release; | |||||
| }; | |||||
| 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { | |||||
| isa = XCConfigurationList; | |||||
| buildConfigurations = ( | |||||
| 97C147031CF9000F007C117D /* Debug */, | |||||
| 97C147041CF9000F007C117D /* Release */, | |||||
| 249021D3217E4FDB00AE95B9 /* Profile */, | |||||
| ); | |||||
| defaultConfigurationIsVisible = 0; | |||||
| defaultConfigurationName = Release; | |||||
| }; | |||||
| 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { | |||||
| isa = XCConfigurationList; | |||||
| buildConfigurations = ( | |||||
| 97C147061CF9000F007C117D /* Debug */, | |||||
| 97C147071CF9000F007C117D /* Release */, | |||||
| 249021D4217E4FDB00AE95B9 /* Profile */, | |||||
| ); | |||||
| defaultConfigurationIsVisible = 0; | |||||
| defaultConfigurationName = Release; | |||||
| }; | |||||
| /* End XCConfigurationList section */ | |||||
| }; | |||||
| rootObject = 97C146E61CF9000F007C117D /* Project object */; | |||||
| } | |||||
| @@ -0,0 +1,7 @@ | |||||
| <?xml version="1.0" encoding="UTF-8"?> | |||||
| <Workspace | |||||
| version = "1.0"> | |||||
| <FileRef | |||||
| location = "self:"> | |||||
| </FileRef> | |||||
| </Workspace> | |||||
| @@ -0,0 +1,8 @@ | |||||
| <?xml version="1.0" encoding="UTF-8"?> | |||||
| <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |||||
| <plist version="1.0"> | |||||
| <dict> | |||||
| <key>IDEDidComputeMac32BitWarning</key> | |||||
| <true/> | |||||
| </dict> | |||||
| </plist> | |||||
| @@ -0,0 +1,8 @@ | |||||
| <?xml version="1.0" encoding="UTF-8"?> | |||||
| <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |||||
| <plist version="1.0"> | |||||
| <dict> | |||||
| <key>PreviewsEnabled</key> | |||||
| <false/> | |||||
| </dict> | |||||
| </plist> | |||||
| @@ -0,0 +1,98 @@ | |||||
| <?xml version="1.0" encoding="UTF-8"?> | |||||
| <Scheme | |||||
| LastUpgradeVersion = "1510" | |||||
| version = "1.3"> | |||||
| <BuildAction | |||||
| parallelizeBuildables = "YES" | |||||
| buildImplicitDependencies = "YES"> | |||||
| <BuildActionEntries> | |||||
| <BuildActionEntry | |||||
| buildForTesting = "YES" | |||||
| buildForRunning = "YES" | |||||
| buildForProfiling = "YES" | |||||
| buildForArchiving = "YES" | |||||
| buildForAnalyzing = "YES"> | |||||
| <BuildableReference | |||||
| BuildableIdentifier = "primary" | |||||
| BlueprintIdentifier = "97C146ED1CF9000F007C117D" | |||||
| BuildableName = "Runner.app" | |||||
| BlueprintName = "Runner" | |||||
| ReferencedContainer = "container:Runner.xcodeproj"> | |||||
| </BuildableReference> | |||||
| </BuildActionEntry> | |||||
| </BuildActionEntries> | |||||
| </BuildAction> | |||||
| <TestAction | |||||
| buildConfiguration = "Debug" | |||||
| selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" | |||||
| selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" | |||||
| shouldUseLaunchSchemeArgsEnv = "YES"> | |||||
| <MacroExpansion> | |||||
| <BuildableReference | |||||
| BuildableIdentifier = "primary" | |||||
| BlueprintIdentifier = "97C146ED1CF9000F007C117D" | |||||
| BuildableName = "Runner.app" | |||||
| BlueprintName = "Runner" | |||||
| ReferencedContainer = "container:Runner.xcodeproj"> | |||||
| </BuildableReference> | |||||
| </MacroExpansion> | |||||
| <Testables> | |||||
| <TestableReference | |||||
| skipped = "NO" | |||||
| parallelizable = "YES"> | |||||
| <BuildableReference | |||||
| BuildableIdentifier = "primary" | |||||
| BlueprintIdentifier = "331C8080294A63A400263BE5" | |||||
| BuildableName = "RunnerTests.xctest" | |||||
| BlueprintName = "RunnerTests" | |||||
| ReferencedContainer = "container:Runner.xcodeproj"> | |||||
| </BuildableReference> | |||||
| </TestableReference> | |||||
| </Testables> | |||||
| </TestAction> | |||||
| <LaunchAction | |||||
| buildConfiguration = "Debug" | |||||
| selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" | |||||
| selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" | |||||
| launchStyle = "0" | |||||
| useCustomWorkingDirectory = "NO" | |||||
| ignoresPersistentStateOnLaunch = "NO" | |||||
| debugDocumentVersioning = "YES" | |||||
| debugServiceExtension = "internal" | |||||
| allowLocationSimulation = "YES"> | |||||
| <BuildableProductRunnable | |||||
| runnableDebuggingMode = "0"> | |||||
| <BuildableReference | |||||
| BuildableIdentifier = "primary" | |||||
| BlueprintIdentifier = "97C146ED1CF9000F007C117D" | |||||
| BuildableName = "Runner.app" | |||||
| BlueprintName = "Runner" | |||||
| ReferencedContainer = "container:Runner.xcodeproj"> | |||||
| </BuildableReference> | |||||
| </BuildableProductRunnable> | |||||
| </LaunchAction> | |||||
| <ProfileAction | |||||
| buildConfiguration = "Profile" | |||||
| shouldUseLaunchSchemeArgsEnv = "YES" | |||||
| savedToolIdentifier = "" | |||||
| useCustomWorkingDirectory = "NO" | |||||
| debugDocumentVersioning = "YES"> | |||||
| <BuildableProductRunnable | |||||
| runnableDebuggingMode = "0"> | |||||
| <BuildableReference | |||||
| BuildableIdentifier = "primary" | |||||
| BlueprintIdentifier = "97C146ED1CF9000F007C117D" | |||||
| BuildableName = "Runner.app" | |||||
| BlueprintName = "Runner" | |||||
| ReferencedContainer = "container:Runner.xcodeproj"> | |||||
| </BuildableReference> | |||||
| </BuildableProductRunnable> | |||||
| </ProfileAction> | |||||
| <AnalyzeAction | |||||
| buildConfiguration = "Debug"> | |||||
| </AnalyzeAction> | |||||
| <ArchiveAction | |||||
| buildConfiguration = "Release" | |||||
| revealArchiveInOrganizer = "YES"> | |||||
| </ArchiveAction> | |||||
| </Scheme> | |||||
| @@ -0,0 +1,7 @@ | |||||
| <?xml version="1.0" encoding="UTF-8"?> | |||||
| <Workspace | |||||
| version = "1.0"> | |||||
| <FileRef | |||||
| location = "group:Runner.xcodeproj"> | |||||
| </FileRef> | |||||
| </Workspace> | |||||
| @@ -0,0 +1,8 @@ | |||||
| <?xml version="1.0" encoding="UTF-8"?> | |||||
| <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |||||
| <plist version="1.0"> | |||||
| <dict> | |||||
| <key>IDEDidComputeMac32BitWarning</key> | |||||
| <true/> | |||||
| </dict> | |||||
| </plist> | |||||
| @@ -0,0 +1,8 @@ | |||||
| <?xml version="1.0" encoding="UTF-8"?> | |||||
| <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |||||
| <plist version="1.0"> | |||||
| <dict> | |||||
| <key>PreviewsEnabled</key> | |||||
| <false/> | |||||
| </dict> | |||||
| </plist> | |||||
| @@ -0,0 +1,13 @@ | |||||
| import Flutter | |||||
| import UIKit | |||||
| @main | |||||
| @objc class AppDelegate: FlutterAppDelegate { | |||||
| override func application( | |||||
| _ application: UIApplication, | |||||
| didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? | |||||
| ) -> Bool { | |||||
| GeneratedPluginRegistrant.register(with: self) | |||||
| return super.application(application, didFinishLaunchingWithOptions: launchOptions) | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,122 @@ | |||||
| { | |||||
| "images" : [ | |||||
| { | |||||
| "size" : "20x20", | |||||
| "idiom" : "iphone", | |||||
| "filename" : "Icon-App-20x20@2x.png", | |||||
| "scale" : "2x" | |||||
| }, | |||||
| { | |||||
| "size" : "20x20", | |||||
| "idiom" : "iphone", | |||||
| "filename" : "Icon-App-20x20@3x.png", | |||||
| "scale" : "3x" | |||||
| }, | |||||
| { | |||||
| "size" : "29x29", | |||||
| "idiom" : "iphone", | |||||
| "filename" : "Icon-App-29x29@1x.png", | |||||
| "scale" : "1x" | |||||
| }, | |||||
| { | |||||
| "size" : "29x29", | |||||
| "idiom" : "iphone", | |||||
| "filename" : "Icon-App-29x29@2x.png", | |||||
| "scale" : "2x" | |||||
| }, | |||||
| { | |||||
| "size" : "29x29", | |||||
| "idiom" : "iphone", | |||||
| "filename" : "Icon-App-29x29@3x.png", | |||||
| "scale" : "3x" | |||||
| }, | |||||
| { | |||||
| "size" : "40x40", | |||||
| "idiom" : "iphone", | |||||
| "filename" : "Icon-App-40x40@2x.png", | |||||
| "scale" : "2x" | |||||
| }, | |||||
| { | |||||
| "size" : "40x40", | |||||
| "idiom" : "iphone", | |||||
| "filename" : "Icon-App-40x40@3x.png", | |||||
| "scale" : "3x" | |||||
| }, | |||||
| { | |||||
| "size" : "60x60", | |||||
| "idiom" : "iphone", | |||||
| "filename" : "Icon-App-60x60@2x.png", | |||||
| "scale" : "2x" | |||||
| }, | |||||
| { | |||||
| "size" : "60x60", | |||||
| "idiom" : "iphone", | |||||
| "filename" : "Icon-App-60x60@3x.png", | |||||
| "scale" : "3x" | |||||
| }, | |||||
| { | |||||
| "size" : "20x20", | |||||
| "idiom" : "ipad", | |||||
| "filename" : "Icon-App-20x20@1x.png", | |||||
| "scale" : "1x" | |||||
| }, | |||||
| { | |||||
| "size" : "20x20", | |||||
| "idiom" : "ipad", | |||||
| "filename" : "Icon-App-20x20@2x.png", | |||||
| "scale" : "2x" | |||||
| }, | |||||
| { | |||||
| "size" : "29x29", | |||||
| "idiom" : "ipad", | |||||
| "filename" : "Icon-App-29x29@1x.png", | |||||
| "scale" : "1x" | |||||
| }, | |||||
| { | |||||
| "size" : "29x29", | |||||
| "idiom" : "ipad", | |||||
| "filename" : "Icon-App-29x29@2x.png", | |||||
| "scale" : "2x" | |||||
| }, | |||||
| { | |||||
| "size" : "40x40", | |||||
| "idiom" : "ipad", | |||||
| "filename" : "Icon-App-40x40@1x.png", | |||||
| "scale" : "1x" | |||||
| }, | |||||
| { | |||||
| "size" : "40x40", | |||||
| "idiom" : "ipad", | |||||
| "filename" : "Icon-App-40x40@2x.png", | |||||
| "scale" : "2x" | |||||
| }, | |||||
| { | |||||
| "size" : "76x76", | |||||
| "idiom" : "ipad", | |||||
| "filename" : "Icon-App-76x76@1x.png", | |||||
| "scale" : "1x" | |||||
| }, | |||||
| { | |||||
| "size" : "76x76", | |||||
| "idiom" : "ipad", | |||||
| "filename" : "Icon-App-76x76@2x.png", | |||||
| "scale" : "2x" | |||||
| }, | |||||
| { | |||||
| "size" : "83.5x83.5", | |||||
| "idiom" : "ipad", | |||||
| "filename" : "Icon-App-83.5x83.5@2x.png", | |||||
| "scale" : "2x" | |||||
| }, | |||||
| { | |||||
| "size" : "1024x1024", | |||||
| "idiom" : "ios-marketing", | |||||
| "filename" : "Icon-App-1024x1024@1x.png", | |||||
| "scale" : "1x" | |||||
| } | |||||
| ], | |||||
| "info" : { | |||||
| "version" : 1, | |||||
| "author" : "xcode" | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,23 @@ | |||||
| { | |||||
| "images" : [ | |||||
| { | |||||
| "idiom" : "universal", | |||||
| "filename" : "LaunchImage.png", | |||||
| "scale" : "1x" | |||||
| }, | |||||
| { | |||||
| "idiom" : "universal", | |||||
| "filename" : "LaunchImage@2x.png", | |||||
| "scale" : "2x" | |||||
| }, | |||||
| { | |||||
| "idiom" : "universal", | |||||
| "filename" : "LaunchImage@3x.png", | |||||
| "scale" : "3x" | |||||
| } | |||||
| ], | |||||
| "info" : { | |||||
| "version" : 1, | |||||
| "author" : "xcode" | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,5 @@ | |||||
| # Launch Screen Assets | |||||
| You can customize the launch screen with your own desired assets by replacing the image files in this directory. | |||||
| You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. | |||||
| @@ -0,0 +1,37 @@ | |||||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | |||||
| <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM"> | |||||
| <dependencies> | |||||
| <deployment identifier="iOS"/> | |||||
| <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/> | |||||
| </dependencies> | |||||
| <scenes> | |||||
| <!--View Controller--> | |||||
| <scene sceneID="EHf-IW-A2E"> | |||||
| <objects> | |||||
| <viewController id="01J-lp-oVM" sceneMemberID="viewController"> | |||||
| <layoutGuides> | |||||
| <viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/> | |||||
| <viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/> | |||||
| </layoutGuides> | |||||
| <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3"> | |||||
| <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> | |||||
| <subviews> | |||||
| <imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4"> | |||||
| </imageView> | |||||
| </subviews> | |||||
| <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> | |||||
| <constraints> | |||||
| <constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/> | |||||
| <constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/> | |||||
| </constraints> | |||||
| </view> | |||||
| </viewController> | |||||
| <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/> | |||||
| </objects> | |||||
| <point key="canvasLocation" x="53" y="375"/> | |||||
| </scene> | |||||
| </scenes> | |||||
| <resources> | |||||
| <image name="LaunchImage" width="168" height="185"/> | |||||
| </resources> | |||||
| </document> | |||||
| @@ -0,0 +1,26 @@ | |||||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | |||||
| <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r"> | |||||
| <dependencies> | |||||
| <deployment identifier="iOS"/> | |||||
| <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/> | |||||
| </dependencies> | |||||
| <scenes> | |||||
| <!--Flutter View Controller--> | |||||
| <scene sceneID="tne-QT-ifu"> | |||||
| <objects> | |||||
| <viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController"> | |||||
| <layoutGuides> | |||||
| <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/> | |||||
| <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/> | |||||
| </layoutGuides> | |||||
| <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC"> | |||||
| <rect key="frame" x="0.0" y="0.0" width="600" height="600"/> | |||||
| <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> | |||||
| <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/> | |||||
| </view> | |||||
| </viewController> | |||||
| <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/> | |||||
| </objects> | |||||
| </scene> | |||||
| </scenes> | |||||
| </document> | |||||
| @@ -0,0 +1,49 @@ | |||||
| <?xml version="1.0" encoding="UTF-8"?> | |||||
| <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |||||
| <plist version="1.0"> | |||||
| <dict> | |||||
| <key>CFBundleDevelopmentRegion</key> | |||||
| <string>$(DEVELOPMENT_LANGUAGE)</string> | |||||
| <key>CFBundleDisplayName</key> | |||||
| <string>Qadirneyriz</string> | |||||
| <key>CFBundleExecutable</key> | |||||
| <string>$(EXECUTABLE_NAME)</string> | |||||
| <key>CFBundleIdentifier</key> | |||||
| <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> | |||||
| <key>CFBundleInfoDictionaryVersion</key> | |||||
| <string>6.0</string> | |||||
| <key>CFBundleName</key> | |||||
| <string>qadirneyriz</string> | |||||
| <key>CFBundlePackageType</key> | |||||
| <string>APPL</string> | |||||
| <key>CFBundleShortVersionString</key> | |||||
| <string>$(FLUTTER_BUILD_NAME)</string> | |||||
| <key>CFBundleSignature</key> | |||||
| <string>????</string> | |||||
| <key>CFBundleVersion</key> | |||||
| <string>$(FLUTTER_BUILD_NUMBER)</string> | |||||
| <key>LSRequiresIPhoneOS</key> | |||||
| <true/> | |||||
| <key>UILaunchStoryboardName</key> | |||||
| <string>LaunchScreen</string> | |||||
| <key>UIMainStoryboardFile</key> | |||||
| <string>Main</string> | |||||
| <key>UISupportedInterfaceOrientations</key> | |||||
| <array> | |||||
| <string>UIInterfaceOrientationPortrait</string> | |||||
| <string>UIInterfaceOrientationLandscapeLeft</string> | |||||
| <string>UIInterfaceOrientationLandscapeRight</string> | |||||
| </array> | |||||
| <key>UISupportedInterfaceOrientations~ipad</key> | |||||
| <array> | |||||
| <string>UIInterfaceOrientationPortrait</string> | |||||
| <string>UIInterfaceOrientationPortraitUpsideDown</string> | |||||
| <string>UIInterfaceOrientationLandscapeLeft</string> | |||||
| <string>UIInterfaceOrientationLandscapeRight</string> | |||||
| </array> | |||||
| <key>CADisableMinimumFrameDurationOnPhone</key> | |||||
| <true/> | |||||
| <key>UIApplicationSupportsIndirectInputEvents</key> | |||||
| <true/> | |||||
| </dict> | |||||
| </plist> | |||||
| @@ -0,0 +1 @@ | |||||
| #import "GeneratedPluginRegistrant.h" | |||||
| @@ -0,0 +1,12 @@ | |||||
| import Flutter | |||||
| import UIKit | |||||
| import XCTest | |||||
| class RunnerTests: XCTestCase { | |||||
| func testExample() { | |||||
| // If you add code to the Runner application, consider adding tests here. | |||||
| // See https://developer.apple.com/documentation/xctest for more information about using XCTest. | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,3 @@ | |||||
| arb-dir: lib/l10n | |||||
| template-arb-file: app_en.arb | |||||
| output-localization-file: app_localizations.dart | |||||
| @@ -0,0 +1,14 @@ | |||||
| import 'package:qadirneyriz/config/network_config.dart'; | |||||
| import 'package:qadirneyriz/config/ui_config.dart'; | |||||
| class AppConfig { | |||||
| final UIConfig ui; | |||||
| final NetworkConfig network; | |||||
| const AppConfig({ | |||||
| required this.ui, | |||||
| required this.network, | |||||
| }); | |||||
| } | |||||
| @@ -0,0 +1,9 @@ | |||||
| import 'package:qadirneyriz/config/app_config.dart'; | |||||
| import 'package:qadirneyriz/config/network_config.dart'; | |||||
| import 'package:qadirneyriz/config/ui_config.dart'; | |||||
| const config = AppConfig( | |||||
| ui: UIConfig(), | |||||
| network: NetworkConfig(), | |||||
| ); | |||||
| @@ -0,0 +1,4 @@ | |||||
| class NetworkConfig { | |||||
| final baseUrl = 'https://api.nghsco.com/api/'; | |||||
| const NetworkConfig(); | |||||
| } | |||||
| @@ -0,0 +1,9 @@ | |||||
| import 'package:flutter/material.dart'; | |||||
| class UIConfig { | |||||
| final Color mainGreen = const Color(0xff0A8754); | |||||
| final Color buttongreen = const Color(0xff04A54F); | |||||
| final Color secendGreen = const Color.fromARGB(255, 75, 173, 78); | |||||
| final Color mainGray = const Color(0xff333333); | |||||
| const UIConfig(); | |||||
| } | |||||
| @@ -0,0 +1,250 @@ | |||||
| import 'package:flutter/material.dart'; | |||||
| import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | |||||
| import 'package:font_awesome_flutter/font_awesome_flutter.dart'; | |||||
| import 'package:provider/provider.dart'; | |||||
| import 'package:qadirneyriz/config/config.dart'; | |||||
| import 'package:qadirneyriz/screens/auth/state/state.dart'; | |||||
| import 'package:qadirneyriz/screens/home/screen.dart'; | |||||
| import 'package:qadirneyriz/screens/meeting/screen.dart'; | |||||
| import 'package:qadirneyriz/setting/setting.dart'; | |||||
| class CustomDrawerNavigation extends StatefulWidget { | |||||
| final int activeTab; | |||||
| const CustomDrawerNavigation({super.key, required this.activeTab}); | |||||
| @override | |||||
| _CustomDrawerNavigationState createState() => _CustomDrawerNavigationState(); | |||||
| } | |||||
| class _CustomDrawerNavigationState extends State<CustomDrawerNavigation> { | |||||
| late final PageController _pageController; | |||||
| int _selectedIndex = 0; | |||||
| final String language = setting.userLocalDb.getUser().language; | |||||
| String? selectedLanguage; // زبان پیشفرض فارسی | |||||
| late AuthState state; | |||||
| @override | |||||
| void initState() { | |||||
| super.initState(); | |||||
| state = Provider.of(context, listen: false); | |||||
| selectedLanguage = language; | |||||
| _selectedIndex = widget.activeTab; | |||||
| _pageController = PageController(initialPage: _selectedIndex); | |||||
| } | |||||
| final List<Widget> _bottomBarPages = [ | |||||
| const HomeScreen(), | |||||
| const MeetingsScreen() | |||||
| // Add more screens here | |||||
| ]; | |||||
| void _onItemTapped(int index) { | |||||
| setState(() { | |||||
| _selectedIndex = index; | |||||
| }); | |||||
| _pageController.jumpToPage(index); | |||||
| Navigator.pop(context); // Close the drawer | |||||
| } | |||||
| @override | |||||
| Widget build(BuildContext context) { | |||||
| return Scaffold( | |||||
| drawer: Consumer<AuthState>( | |||||
| builder: (context, value, child) { | |||||
| return Drawer( | |||||
| child: Column( | |||||
| crossAxisAlignment: CrossAxisAlignment.start, | |||||
| children: <Widget>[ | |||||
| Padding( | |||||
| padding: const EdgeInsets.only(left: 16.0, top: 40), | |||||
| child: Image.asset( | |||||
| 'assets/images/iconinappbar.png', // مسیر لوگوی شما | |||||
| height: 60, | |||||
| ), | |||||
| ), | |||||
| NewSessionButton(), | |||||
| Expanded( | |||||
| child: ListView( | |||||
| padding: EdgeInsets.zero, | |||||
| children: <Widget>[ | |||||
| _buildDrawerItem( | |||||
| icon: FontAwesomeIcons.house, | |||||
| text: 'خانه', | |||||
| index: 0, | |||||
| ), | |||||
| _buildDrawerItem( | |||||
| icon: FontAwesomeIcons.pencil, | |||||
| text: 'جلسات', | |||||
| index: 1, | |||||
| ), | |||||
| _buildDrawerItem( | |||||
| icon: FontAwesomeIcons.pencil, | |||||
| text: 'ملاقات ها', | |||||
| index: 2, | |||||
| ), | |||||
| _buildDrawerItem( | |||||
| icon: FontAwesomeIcons.pencil, | |||||
| text: 'گزارشات', | |||||
| index: 3, | |||||
| ), | |||||
| Padding( | |||||
| padding: const EdgeInsets.all(8.0), | |||||
| child: Container( | |||||
| decoration: BoxDecoration( | |||||
| color: Colors.grey[300], | |||||
| borderRadius: BorderRadius.circular(10), | |||||
| ), | |||||
| child: Row( | |||||
| mainAxisAlignment: MainAxisAlignment.spaceEvenly, | |||||
| children: [ | |||||
| _buildLanguageButton('fa', 'فارسی', () { | |||||
| value.setLocale('fa'); | |||||
| }), | |||||
| _buildLanguageButton('en', 'English', () { | |||||
| value.setLocale('en'); | |||||
| }), | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| ) | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| const Divider(), | |||||
| ], | |||||
| ), | |||||
| ); | |||||
| }, | |||||
| ), | |||||
| body: PageView( | |||||
| controller: _pageController, | |||||
| physics: const NeverScrollableScrollPhysics(), | |||||
| children: _bottomBarPages, | |||||
| ), | |||||
| ); | |||||
| } | |||||
| Widget _buildDrawerItem( | |||||
| {required IconData icon, required String text, required int index}) { | |||||
| bool isSelected = _selectedIndex == index; | |||||
| return Padding( | |||||
| padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 2), | |||||
| child: Material( | |||||
| color: isSelected | |||||
| ? config.ui.mainGreen.withOpacity(.2) | |||||
| : Colors.transparent, | |||||
| borderRadius: BorderRadius.circular(8), | |||||
| child: InkWell( | |||||
| borderRadius: BorderRadius.circular(8), | |||||
| onTap: () => _onItemTapped(index), | |||||
| child: Container( | |||||
| decoration: BoxDecoration( | |||||
| borderRadius: BorderRadius.circular(8), | |||||
| ), | |||||
| child: ListTile( | |||||
| leading: FaIcon( | |||||
| icon, | |||||
| size: 19, | |||||
| color: isSelected ? config.ui.mainGreen : config.ui.mainGray, | |||||
| ), | |||||
| title: Text( | |||||
| text, | |||||
| style: TextStyle( | |||||
| color: | |||||
| isSelected ? config.ui.mainGreen : config.ui.mainGray, | |||||
| fontWeight: | |||||
| isSelected ? FontWeight.bold : FontWeight.normal, | |||||
| fontSize: 15), | |||||
| ), | |||||
| selected: isSelected, | |||||
| ), | |||||
| ), | |||||
| ), | |||||
| ), | |||||
| ); | |||||
| } | |||||
| Widget _buildLanguageButton( | |||||
| String language, String text, void Function() onPressed) { | |||||
| bool isSelected = selectedLanguage == language; | |||||
| return ElevatedButton( | |||||
| onPressed: () { | |||||
| setState(() { | |||||
| selectedLanguage = language; // بهروز کردن زبان انتخاب شده | |||||
| }); | |||||
| onPressed(); // اجرای متد تغییر زبان | |||||
| }, | |||||
| style: ElevatedButton.styleFrom( | |||||
| backgroundColor: isSelected ? Colors.green : Colors.grey[300], | |||||
| shape: RoundedRectangleBorder( | |||||
| borderRadius: BorderRadius.circular(8.0), | |||||
| ), | |||||
| ), | |||||
| child: Text( | |||||
| text, | |||||
| style: TextStyle( | |||||
| color: isSelected ? Colors.white : Colors.black, | |||||
| ), | |||||
| ), | |||||
| ); | |||||
| } | |||||
| @override | |||||
| void dispose() { | |||||
| _pageController.dispose(); | |||||
| super.dispose(); | |||||
| } | |||||
| } | |||||
| class NewSessionButton extends StatelessWidget { | |||||
| @override | |||||
| Widget build(BuildContext context) { | |||||
| return ElevatedButton( | |||||
| style: ElevatedButton.styleFrom( | |||||
| backgroundColor: Colors.green, // رنگ لبهها | |||||
| shape: RoundedRectangleBorder( | |||||
| borderRadius: BorderRadius.circular(8), // گرد کردن گوشهها | |||||
| ), | |||||
| elevation: 0, // بدون سایه | |||||
| padding: EdgeInsets.symmetric(vertical: 20, horizontal: 16), | |||||
| ), | |||||
| onPressed: () { | |||||
| // کاری که باید انجام شود | |||||
| }, | |||||
| child: Column( | |||||
| mainAxisSize: MainAxisSize.min, | |||||
| children: [ | |||||
| Icon( | |||||
| Icons.person_outline, | |||||
| color: Colors.white, // رنگ آیکون | |||||
| size: 40, | |||||
| ), | |||||
| SizedBox(height: 8), | |||||
| Text( | |||||
| 'جلسه جدید', | |||||
| style: TextStyle( | |||||
| color: Colors.white, // رنگ متن | |||||
| fontSize: 16, | |||||
| fontWeight: FontWeight.bold, | |||||
| ), | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| ); | |||||
| } | |||||
| } | |||||
| class CustomScalfod extends StatefulWidget { | |||||
| const CustomScalfod({super.key}); | |||||
| @override | |||||
| State<CustomScalfod> createState() => _CustomScalfodState(); | |||||
| } | |||||
| class _CustomScalfodState extends State<CustomScalfod> { | |||||
| @override | |||||
| Widget build(BuildContext context) { | |||||
| return Scaffold(); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,341 @@ | |||||
| import 'package:flutter/material.dart'; | |||||
| import 'package:qadirneyriz/models/meetings/meetings_location_model.dart'; | |||||
| import 'package:qadirneyriz/models/meetings/meetings_managers_model.dart'; | |||||
| import 'package:qadirneyriz/models/meetings/meetings_subjects_model.dart'; | |||||
| import 'package:qadirneyriz/models/meetings/meetings_users_model.dart'; | |||||
| import 'package:qadirneyriz/screens/meeting/diolog_meetings_filters.dart'; | |||||
| import 'package:qadirneyriz/setting/setting.dart'; | |||||
| import 'package:qadirneyriz/utils/enums/status.dart'; | |||||
| class GlobalState extends ChangeNotifier { | |||||
| // users meetings | |||||
| Status usersStatus = Status.empty; | |||||
| List<UsersModel>? usersModel; | |||||
| Future<Status> getUsers({bool refresh = false}) async { | |||||
| usersStatus = Status.loading; | |||||
| notifyListeners(); | |||||
| if (refresh) { | |||||
| usersStatus = Status.loading; | |||||
| notifyListeners(); | |||||
| } | |||||
| if (usersModel != null && usersModel!.isNotEmpty) { | |||||
| usersStatus = Status.ready; | |||||
| try { | |||||
| usersModel = await setting.globalServices.getUsers(); | |||||
| if (usersModel != null) { | |||||
| usersStatus = Status.ready; | |||||
| } else { | |||||
| usersStatus = Status.empty; | |||||
| } | |||||
| } catch (e) { | |||||
| usersStatus = Status.error; | |||||
| print('$e error usersModel'); | |||||
| } | |||||
| notifyListeners(); | |||||
| } else { | |||||
| try { | |||||
| usersModel = await setting.globalServices.getUsers(); | |||||
| if (usersModel != null) { | |||||
| usersStatus = Status.ready; | |||||
| } else { | |||||
| usersStatus = Status.empty; | |||||
| } | |||||
| notifyListeners(); | |||||
| } catch (e) { | |||||
| usersStatus = Status.error; | |||||
| print('$e error usersModel'); | |||||
| } | |||||
| } | |||||
| notifyListeners(); | |||||
| print('$usersStatus usersModel'); | |||||
| return usersStatus; | |||||
| } | |||||
| // locations meetings | |||||
| Status locationsStatus = Status.empty; | |||||
| List<LocationsModel>? locationsModel; | |||||
| Future<Status> getLocations({bool refresh = false}) async { | |||||
| locationsStatus = Status.loading; | |||||
| notifyListeners(); | |||||
| if (refresh) { | |||||
| locationsStatus = Status.loading; | |||||
| notifyListeners(); | |||||
| } | |||||
| if (locationsModel != null && locationsModel!.isNotEmpty) { | |||||
| locationsStatus = Status.ready; | |||||
| try { | |||||
| locationsModel = await setting.globalServices.getLocation(); | |||||
| if (locationsModel != null) { | |||||
| locationsStatus = Status.ready; | |||||
| } else { | |||||
| locationsStatus = Status.empty; | |||||
| } | |||||
| } catch (e) { | |||||
| locationsStatus = Status.error; | |||||
| print(e); | |||||
| } | |||||
| notifyListeners(); | |||||
| } else { | |||||
| try { | |||||
| locationsModel = await setting.globalServices.getLocation(); | |||||
| if (locationsModel != null) { | |||||
| locationsStatus = Status.ready; | |||||
| } else { | |||||
| locationsStatus = Status.empty; | |||||
| } | |||||
| notifyListeners(); | |||||
| } catch (e) { | |||||
| locationsStatus = Status.error; | |||||
| print(e); | |||||
| } | |||||
| } | |||||
| notifyListeners(); | |||||
| print(locationsStatus); | |||||
| return locationsStatus; | |||||
| } | |||||
| // subjects meetings | |||||
| Status subjectsStatus = Status.empty; | |||||
| List<SubjectsModel>? subjectsModel; | |||||
| Future<Status> getSubjects({bool refresh = false}) async { | |||||
| subjectsStatus = Status.loading; | |||||
| notifyListeners(); | |||||
| if (refresh) { | |||||
| subjectsStatus = Status.loading; | |||||
| notifyListeners(); | |||||
| } | |||||
| if (subjectsModel != null && subjectsModel!.isNotEmpty) { | |||||
| subjectsStatus = Status.ready; | |||||
| try { | |||||
| subjectsModel = await setting.globalServices.getSubjects(); | |||||
| if (subjectsModel != null) { | |||||
| subjectsStatus = Status.ready; | |||||
| } else { | |||||
| subjectsStatus = Status.empty; | |||||
| } | |||||
| } catch (e) { | |||||
| subjectsStatus = Status.error; | |||||
| print(e); | |||||
| } | |||||
| notifyListeners(); | |||||
| } else { | |||||
| try { | |||||
| subjectsModel = await setting.globalServices.getSubjects(); | |||||
| if (subjectsModel != null) { | |||||
| subjectsStatus = Status.ready; | |||||
| } else { | |||||
| subjectsStatus = Status.empty; | |||||
| } | |||||
| notifyListeners(); | |||||
| } catch (e) { | |||||
| subjectsStatus = Status.error; | |||||
| print(e); | |||||
| } | |||||
| } | |||||
| notifyListeners(); | |||||
| print(subjectsStatus); | |||||
| return subjectsStatus; | |||||
| } | |||||
| // managers meetings | |||||
| Status meetingsManagerStatus = Status.empty; | |||||
| List<MeetingsMangersModel>? meetingsManagerModel; | |||||
| Future<Status> getMeetingsManager({bool refresh = false}) async { | |||||
| meetingsManagerStatus = Status.loading; | |||||
| notifyListeners(); | |||||
| if (refresh) { | |||||
| meetingsManagerStatus = Status.loading; | |||||
| notifyListeners(); | |||||
| } | |||||
| if (meetingsManagerModel != null && meetingsManagerModel!.isNotEmpty) { | |||||
| meetingsManagerStatus = Status.ready; | |||||
| try { | |||||
| meetingsManagerModel = await setting.globalServices.getManagers(); | |||||
| if (meetingsManagerModel != null) { | |||||
| meetingsManagerStatus = Status.ready; | |||||
| } else { | |||||
| meetingsManagerStatus = Status.empty; | |||||
| } | |||||
| } catch (e) { | |||||
| meetingsManagerStatus = Status.error; | |||||
| print(e); | |||||
| } | |||||
| notifyListeners(); | |||||
| } else { | |||||
| try { | |||||
| meetingsManagerModel = await setting.globalServices.getManagers(); | |||||
| if (meetingsManagerModel != null) { | |||||
| meetingsManagerStatus = Status.ready; | |||||
| } else { | |||||
| meetingsManagerStatus = Status.empty; | |||||
| } | |||||
| notifyListeners(); | |||||
| } catch (e) { | |||||
| meetingsManagerStatus = Status.error; | |||||
| print(e); | |||||
| } | |||||
| } | |||||
| notifyListeners(); | |||||
| print(meetingsManagerStatus); | |||||
| return meetingsManagerStatus; | |||||
| } | |||||
| // statuses meetings | |||||
| List<MeetingsStatus> meetingStatuses = [ | |||||
| MeetingsStatus(id: 1, title: 'جلسات برگذار شده'), | |||||
| MeetingsStatus(id: 2, title: 'جلسات موکول شده'), | |||||
| MeetingsStatus(id: 3, title: 'جلسات لغو شده'), | |||||
| MeetingsStatus(id: 4, title: 'جلسات منتظر برگذاری'), | |||||
| ]; | |||||
| // load all items together | |||||
| Status allFiltersStatus = Status.empty; | |||||
| Future<Status> getAllFiltersItems({bool refresh = false}) async { | |||||
| if (_isDataAlreadyLoaded()) { | |||||
| allFiltersStatus = Status.ready; | |||||
| } else { | |||||
| allFiltersStatus = Status.loading; | |||||
| } | |||||
| notifyListeners(); | |||||
| await _fetchAllData(refresh: refresh); | |||||
| _updateAllFiltersStatus(); | |||||
| notifyListeners(); | |||||
| return allFiltersStatus; | |||||
| } | |||||
| bool _isDataAlreadyLoaded() { | |||||
| return locationsModel != null && | |||||
| locationsModel!.isNotEmpty && | |||||
| usersModel != null && | |||||
| usersModel!.isNotEmpty && | |||||
| meetingsManagerModel != null && | |||||
| meetingsManagerModel!.isNotEmpty && | |||||
| subjectsModel != null && | |||||
| subjectsModel!.isNotEmpty; | |||||
| } | |||||
| Future<void> _fetchAllData({required bool refresh}) async { | |||||
| await Future.wait([ | |||||
| getLocations(refresh: refresh), | |||||
| getMeetingsManager(refresh: refresh), | |||||
| getSubjects(refresh: refresh), | |||||
| getUsers(refresh: refresh), | |||||
| ]); | |||||
| } | |||||
| void _updateAllFiltersStatus() { | |||||
| if (locationsStatus == Status.ready && | |||||
| subjectsStatus == Status.ready && | |||||
| usersStatus == Status.ready && | |||||
| meetingsManagerStatus == Status.ready) { | |||||
| allFiltersStatus = Status.ready; | |||||
| } else { | |||||
| allFiltersStatus = Status.error; | |||||
| } | |||||
| } | |||||
| // add new subject | |||||
| Status statusAddNewSubject = Status.empty; | |||||
| String? messageAddNewSubject; | |||||
| Map? errorsAddNewSubject; | |||||
| Future<Status> addNewSubject({required String subject}) async { | |||||
| statusAddNewSubject = Status.loading; | |||||
| notifyListeners(); | |||||
| try { | |||||
| final result = | |||||
| await setting.globalServices.addNewSubject(subject: subject); | |||||
| if (result.isOk) { | |||||
| statusAddNewSubject = Status.ready; | |||||
| messageAddNewSubject = result.message; | |||||
| } else if (result.isOk == false) { | |||||
| errorsAddNewSubject = result.errors; | |||||
| messageAddNewSubject = result.message; | |||||
| statusAddNewSubject = Status.error; | |||||
| } else { | |||||
| statusAddNewSubject = Status.error; | |||||
| } | |||||
| notifyListeners(); | |||||
| } catch (e) { | |||||
| statusAddNewSubject = Status.error; | |||||
| } | |||||
| notifyListeners(); | |||||
| return statusAddNewSubject; | |||||
| } | |||||
| // add new address | |||||
| Status statusAddNewAddress = Status.empty; | |||||
| String? messageAddNewAddress; | |||||
| Map? errorsAddNewAddress; | |||||
| Future<Status> addNewAddress({required String address}) async { | |||||
| statusAddNewAddress = Status.loading; | |||||
| notifyListeners(); | |||||
| try { | |||||
| final result = | |||||
| await setting.globalServices.addNewLocation(address: address); | |||||
| if (result.isOk) { | |||||
| statusAddNewAddress = Status.ready; | |||||
| messageAddNewAddress = result.message; | |||||
| } else if (result.isOk == false) { | |||||
| errorsAddNewAddress = result.errors; | |||||
| messageAddNewAddress = result.message; | |||||
| statusAddNewAddress = Status.error; | |||||
| } else { | |||||
| statusAddNewAddress = Status.error; | |||||
| } | |||||
| notifyListeners(); | |||||
| } catch (e) { | |||||
| statusAddNewAddress = Status.error; | |||||
| } | |||||
| notifyListeners(); | |||||
| return statusAddNewAddress; | |||||
| } | |||||
| // add new user | |||||
| Status statusAddNewUser = Status.empty; | |||||
| String? messageAddNewUser; | |||||
| Map? errorsAddNewUser; | |||||
| Future<Status> addNewUser( | |||||
| {required String name, | |||||
| required String mobile, | |||||
| required String password, | |||||
| required int role}) async { | |||||
| statusAddNewUser = Status.loading; | |||||
| notifyListeners(); | |||||
| try { | |||||
| final result = await setting.globalServices.addNewUser( | |||||
| mobile: mobile, name: name, password: password, role: role); | |||||
| if (result.isOk) { | |||||
| statusAddNewUser = Status.ready; | |||||
| messageAddNewUser = result.message; | |||||
| } else if (result.isOk == false) { | |||||
| errorsAddNewUser = result.errors; | |||||
| messageAddNewUser = result.message; | |||||
| statusAddNewUser = Status.error; | |||||
| } else { | |||||
| statusAddNewUser = Status.error; | |||||
| } | |||||
| notifyListeners(); | |||||
| } catch (e) { | |||||
| statusAddNewUser = Status.error; | |||||
| } | |||||
| notifyListeners(); | |||||
| return statusAddNewUser; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,43 @@ | |||||
| { | |||||
| "helloWorld": "Hello World!", | |||||
| "phonenumber":"PhoneNumber", | |||||
| "hintphonenumber":"Please enter your phonenumber ...", | |||||
| "hintpass":"Please enter your password ...", | |||||
| "password":"Password", | |||||
| "submit":"Submit", | |||||
| "submitwithotp":"Submit with OTP", | |||||
| "submitwithphone":"Submit with phonenumber", | |||||
| "enterotp":"Enter OTP", | |||||
| "an4digitotp":"An 4 digit OTP has been sent to", | |||||
| "loading":"loading ...", | |||||
| "phoneerror":"Please enter your phonenumber!", | |||||
| "passerror":"Please enter your password!", | |||||
| "haserror":"Something went wrong. Please try again", | |||||
| "resend":"Resend code!", | |||||
| "today":"Today", | |||||
| "to":"To", | |||||
| "reports":"Reports", | |||||
| "meetings":"Meetings", | |||||
| "events":"Events", | |||||
| "exit":"Exit", | |||||
| "appname":"Foolad QadirNeyriz", | |||||
| "nomeetingfortoday":"No Meetings for today", | |||||
| "todaymeetings":"Today Meetings", | |||||
| "empty":"The list is empty.", | |||||
| "back":"Back", | |||||
| "searchFor":"جستوجو براساس", | |||||
| "date":"تاریخ", | |||||
| "location":"مکان", | |||||
| "meetingmanager":"مدیر جلسه", | |||||
| "subject":"موضوع", | |||||
| "donemeetings":"جلسات برگذار شده", | |||||
| "adjournedmeetings":"جلسات موکول شده", | |||||
| "canceldmeetings":"جلسات لغو شده", | |||||
| "meetingswaitingtobeheld":"جلسات منتظر برگذاری", | |||||
| "selectdate":"انتخاب تاریخ", | |||||
| "editmeeting":"ویرایش جلسه", | |||||
| "meetingsubject":"موضوع جلسه", | |||||
| "clock":"ساعت", | |||||
| "users":"کاربران", | |||||
| "selectusers":"انتخاب کاربران" | |||||
| } | |||||
| @@ -0,0 +1,43 @@ | |||||
| { | |||||
| "helloWorld": "Hello World!", | |||||
| "phonenumber":"شماره موبایل", | |||||
| "hintphonenumber":"لطفا شماره موبایل خود را وارد کنید ...", | |||||
| "hintpass":"لطفا رمزعبور خود را وارد کنید ...", | |||||
| "password":"رمزعبور", | |||||
| "submit":"ثبت", | |||||
| "submitwithotp":"ورود با رمز یکبارمصرف", | |||||
| "submitwithphone":"ورود با شماره موبایل", | |||||
| "enterotp":"رمز یکبارمصرف", | |||||
| "an4digitotp":"رمز ۴ رقمی ارسال شده به شماره ", | |||||
| "loading":"صبر کنید ...", | |||||
| "phoneerror":"لطفا شماره خود را وارد کنید!", | |||||
| "passerror":"لطفا رمزعبور خود را وارد کنید!", | |||||
| "haserror":"مشکلی رخ داده است! دوباره تلاش کنید!", | |||||
| "resend":"دوباره کد را بفرست!", | |||||
| "today":"امروز", | |||||
| "to":"تا", | |||||
| "reports":"گزارشات", | |||||
| "meetings":"جلسات", | |||||
| "events":"ملاقات ها", | |||||
| "exit":"خروج", | |||||
| "appname":"فولاد غدیر نیریز", | |||||
| "nomeetingfortoday":"برای امروز جلسه ایی تعریف نشده است.", | |||||
| "todaymeetings":"جلسه های امروز", | |||||
| "empty":"داده ایی وجود ندارد.", | |||||
| "back":"بازگشست", | |||||
| "searchFor":"جستوجو براساس", | |||||
| "date":"تاریخ", | |||||
| "location":"مکان", | |||||
| "meetingmanager":"مدیر جلسه", | |||||
| "subject":"موضوع", | |||||
| "donemeetings":"جلسات برگذار شده", | |||||
| "adjournedmeetings":"جلسات موکول شده", | |||||
| "canceldmeetings":"جلسات لغو شده", | |||||
| "meetingswaitingtobeheld":"جلسات منتظر برگذاری", | |||||
| "selectdate":"انتخاب تاریخ", | |||||
| "editmeeting":"ویرایش جلسه", | |||||
| "meetingsubject":"موضوع جلسه", | |||||
| "clock":"ساعت", | |||||
| "users":"کاربران", | |||||
| "selectusers":"انتخاب کاربران" | |||||
| } | |||||
| @@ -0,0 +1,79 @@ | |||||
| import 'package:flutter/material.dart'; | |||||
| import 'package:flutter_localizations/flutter_localizations.dart'; | |||||
| import 'package:hive_flutter/hive_flutter.dart'; | |||||
| import 'package:provider/provider.dart'; | |||||
| import 'package:qadirneyriz/global_state/global_state.dart'; | |||||
| import 'package:qadirneyriz/router/router.dart'; | |||||
| import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | |||||
| import 'package:qadirneyriz/screens/auth/state/state.dart'; | |||||
| import 'package:qadirneyriz/screens/home/state.dart'; | |||||
| import 'package:qadirneyriz/screens/meeting/state.dart'; | |||||
| import 'package:qadirneyriz/setting/setting.dart'; | |||||
| void main() async { | |||||
| await Hive.initFlutter(); | |||||
| await setting.userLocalDb.openBox(); | |||||
| runApp( | |||||
| MultiProvider( | |||||
| providers: [ | |||||
| ChangeNotifierProvider(create: (_) => GlobalState()), | |||||
| ChangeNotifierProvider(create: (_) => AuthState()), | |||||
| ChangeNotifierProvider(create: (_) => HomeState()), | |||||
| ChangeNotifierProvider(create: (_) => MeetingsState()), | |||||
| ], | |||||
| child: const MyApp(), | |||||
| ), | |||||
| ); | |||||
| } | |||||
| class MyApp extends StatefulWidget { | |||||
| const MyApp({super.key}); | |||||
| @override | |||||
| State<MyApp> createState() => _MyAppState(); | |||||
| } | |||||
| class _MyAppState extends State<MyApp> { | |||||
| late AuthState state ; | |||||
| String language = setting.userLocalDb.getUser().language; | |||||
| @override | |||||
| void initState() { | |||||
| Future.delayed(Duration.zero, () async { | |||||
| state = Provider.of(context, listen: false); | |||||
| setState(() { | |||||
| language = state.language; | |||||
| }); | |||||
| }); | |||||
| super.initState(); | |||||
| } | |||||
| // This widget is the root of your application. | |||||
| @override | |||||
| Widget build(BuildContext context) { | |||||
| return Consumer<AuthState>( | |||||
| builder: (context, value, child) { | |||||
| return MaterialApp.router( | |||||
| theme: ThemeData( | |||||
| useMaterial3: true, | |||||
| fontFamily: 'Font', | |||||
| scaffoldBackgroundColor: Colors.white), | |||||
| debugShowCheckedModeBanner: false, | |||||
| routerDelegate: router.routerDelegate, | |||||
| routeInformationParser: router.routeInformationParser, | |||||
| routeInformationProvider: router.routeInformationProvider, | |||||
| localizationsDelegates: const [ | |||||
| AppLocalizations.delegate, // Add this line | |||||
| GlobalMaterialLocalizations.delegate, | |||||
| GlobalWidgetsLocalizations.delegate, | |||||
| GlobalCupertinoLocalizations.delegate, | |||||
| ], | |||||
| locale: Locale(value.language), | |||||
| supportedLocales: const [ | |||||
| Locale('fa'), // Persian | |||||
| Locale('en'), // English | |||||
| ], | |||||
| ); | |||||
| }, | |||||
| ); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,193 @@ | |||||
| import 'dart:convert'; | |||||
| class TodayMeetingModel { | |||||
| List<Meeting>? meetings; | |||||
| String? note; | |||||
| TodayMeetingModel({ | |||||
| this.meetings, | |||||
| this.note, | |||||
| }); | |||||
| factory TodayMeetingModel.fromRawJson(String str) => TodayMeetingModel.fromJson(json.decode(str)); | |||||
| String toRawJson() => json.encode(toJson()); | |||||
| factory TodayMeetingModel.fromJson(Map<String, dynamic> json) => TodayMeetingModel( | |||||
| meetings: json["meetings"] == null ? [] : List<Meeting>.from(json["meetings"]!.map((x) => Meeting.fromJson(x))), | |||||
| note: json["note"], | |||||
| ); | |||||
| Map<String, dynamic> toJson() => { | |||||
| "meetings": meetings == null ? [] : List<dynamic>.from(meetings!.map((x) => x.toJson())), | |||||
| "note": note, | |||||
| }; | |||||
| } | |||||
| class Meeting { | |||||
| int? id; | |||||
| int? locationsId; | |||||
| int? subjectId; | |||||
| int? managerId; | |||||
| int? ownerId; | |||||
| String? azHour; | |||||
| String? taHour; | |||||
| dynamic description; | |||||
| int? status; | |||||
| int? accepted; | |||||
| DateTime? dateMeeting; | |||||
| DateTime? endDate; | |||||
| DateTime? createdAt; | |||||
| DateTime? updatedAt; | |||||
| String? dateJalali; | |||||
| String? statusTxt; | |||||
| String? az; | |||||
| String? ta; | |||||
| Location? location; | |||||
| Subject? subject; | |||||
| Meeting({ | |||||
| this.id, | |||||
| this.locationsId, | |||||
| this.subjectId, | |||||
| this.managerId, | |||||
| this.ownerId, | |||||
| this.azHour, | |||||
| this.taHour, | |||||
| this.description, | |||||
| this.status, | |||||
| this.accepted, | |||||
| this.dateMeeting, | |||||
| this.endDate, | |||||
| this.createdAt, | |||||
| this.updatedAt, | |||||
| this.dateJalali, | |||||
| this.statusTxt, | |||||
| this.az, | |||||
| this.ta, | |||||
| this.location, | |||||
| this.subject, | |||||
| }); | |||||
| factory Meeting.fromRawJson(String str) => Meeting.fromJson(json.decode(str)); | |||||
| String toRawJson() => json.encode(toJson()); | |||||
| factory Meeting.fromJson(Map<String, dynamic> json) => Meeting( | |||||
| id: json["id"], | |||||
| locationsId: json["locations_id"], | |||||
| subjectId: json["subject_id"], | |||||
| managerId: json["manager_id"], | |||||
| ownerId: json["owner_id"], | |||||
| azHour: json["az_hour"], | |||||
| taHour: json["ta_hour"], | |||||
| description: json["description"], | |||||
| status: json["status"], | |||||
| accepted: json["accepted"], | |||||
| dateMeeting: json["date_meeting"] == null ? null : DateTime.parse(json["date_meeting"]), | |||||
| endDate: json["end_date"] == null ? null : DateTime.parse(json["end_date"]), | |||||
| createdAt: json["created_at"] == null ? null : DateTime.parse(json["created_at"]), | |||||
| updatedAt: json["updated_at"] == null ? null : DateTime.parse(json["updated_at"]), | |||||
| dateJalali: json["date_jalali"], | |||||
| statusTxt: json["status_txt"], | |||||
| az: json["az"], | |||||
| ta: json["ta"], | |||||
| location: json["location"] == null ? null : Location.fromJson(json["location"]), | |||||
| subject: json["subject"] == null ? null : Subject.fromJson(json["subject"]), | |||||
| ); | |||||
| Map<String, dynamic> toJson() => { | |||||
| "id": id, | |||||
| "locations_id": locationsId, | |||||
| "subject_id": subjectId, | |||||
| "manager_id": managerId, | |||||
| "owner_id": ownerId, | |||||
| "az_hour": azHour, | |||||
| "ta_hour": taHour, | |||||
| "description": description, | |||||
| "status": status, | |||||
| "accepted": accepted, | |||||
| "date_meeting": dateMeeting?.toIso8601String(), | |||||
| "end_date": endDate?.toIso8601String(), | |||||
| "created_at": createdAt?.toIso8601String(), | |||||
| "updated_at": updatedAt?.toIso8601String(), | |||||
| "date_jalali": dateJalali, | |||||
| "status_txt": statusTxt, | |||||
| "az": az, | |||||
| "ta": ta, | |||||
| "location": location?.toJson(), | |||||
| "subject": subject?.toJson(), | |||||
| }; | |||||
| } | |||||
| class Location { | |||||
| int? id; | |||||
| String? address; | |||||
| String? addressEn; | |||||
| DateTime? createdAt; | |||||
| DateTime? updatedAt; | |||||
| Location({ | |||||
| this.id, | |||||
| this.address, | |||||
| this.addressEn, | |||||
| this.createdAt, | |||||
| this.updatedAt, | |||||
| }); | |||||
| factory Location.fromRawJson(String str) => Location.fromJson(json.decode(str)); | |||||
| String toRawJson() => json.encode(toJson()); | |||||
| factory Location.fromJson(Map<String, dynamic> json) => Location( | |||||
| id: json["id"], | |||||
| address: json["address"], | |||||
| addressEn: json["address_en"], | |||||
| createdAt: json["created_at"] == null ? null : DateTime.parse(json["created_at"]), | |||||
| updatedAt: json["updated_at"] == null ? null : DateTime.parse(json["updated_at"]), | |||||
| ); | |||||
| Map<String, dynamic> toJson() => { | |||||
| "id": id, | |||||
| "address": address, | |||||
| "address_en": addressEn, | |||||
| "created_at": createdAt?.toIso8601String(), | |||||
| "updated_at": updatedAt?.toIso8601String(), | |||||
| }; | |||||
| } | |||||
| class Subject { | |||||
| int? id; | |||||
| dynamic subject; | |||||
| dynamic subjectEn; | |||||
| DateTime? createdAt; | |||||
| DateTime? updatedAt; | |||||
| Subject({ | |||||
| this.id, | |||||
| this.subject, | |||||
| this.subjectEn, | |||||
| this.createdAt, | |||||
| this.updatedAt, | |||||
| }); | |||||
| factory Subject.fromRawJson(String str) => Subject.fromJson(json.decode(str)); | |||||
| String toRawJson() => json.encode(toJson()); | |||||
| factory Subject.fromJson(Map<String, dynamic> json) => Subject( | |||||
| id: json["id"], | |||||
| subject: json["subject"], | |||||
| subjectEn: json["subject_en"], | |||||
| createdAt: json["created_at"] == null ? null : DateTime.parse(json["created_at"]), | |||||
| updatedAt: json["updated_at"] == null ? null : DateTime.parse(json["updated_at"]), | |||||
| ); | |||||
| Map<String, dynamic> toJson() => { | |||||
| "id": id, | |||||
| "subject": subject, | |||||
| "subject_en": subjectEn, | |||||
| "created_at": createdAt?.toIso8601String(), | |||||
| "updated_at": updatedAt?.toIso8601String(), | |||||
| }; | |||||
| } | |||||
| @@ -0,0 +1,30 @@ | |||||
| import 'dart:convert'; | |||||
| class LocationsModel { | |||||
| int? id; | |||||
| String? address; | |||||
| String? addressEn; | |||||
| LocationsModel({ | |||||
| this.id, | |||||
| this.address, | |||||
| this.addressEn, | |||||
| }); | |||||
| factory LocationsModel.fromRawJson(String str) => | |||||
| LocationsModel.fromJson(json.decode(str)); | |||||
| String toRawJson() => json.encode(toJson()); | |||||
| factory LocationsModel.fromJson(Map<String, dynamic> json) => LocationsModel( | |||||
| id: json["id"], | |||||
| address: json["address"], | |||||
| addressEn: json["address_en"], | |||||
| ); | |||||
| Map<String, dynamic> toJson() => { | |||||
| "id": id, | |||||
| "address": address, | |||||
| "address_en": addressEn, | |||||
| }; | |||||
| } | |||||
| @@ -0,0 +1,71 @@ | |||||
| import 'dart:convert'; | |||||
| class MeetingsMangersModel { | |||||
| int? id; | |||||
| String? name; | |||||
| int? role; | |||||
| String? mobile; | |||||
| dynamic otp; | |||||
| String? access; | |||||
| dynamic managerId; | |||||
| dynamic firebaseToken; | |||||
| int? isBlock; | |||||
| int? getSms; | |||||
| DateTime? createdAt; | |||||
| DateTime? updatedAt; | |||||
| MeetingsMangersModel({ | |||||
| this.id, | |||||
| this.name, | |||||
| this.role, | |||||
| this.mobile, | |||||
| this.otp, | |||||
| this.access, | |||||
| this.managerId, | |||||
| this.firebaseToken, | |||||
| this.isBlock, | |||||
| this.getSms, | |||||
| this.createdAt, | |||||
| this.updatedAt, | |||||
| }); | |||||
| factory MeetingsMangersModel.fromRawJson(String str) => | |||||
| MeetingsMangersModel.fromJson(json.decode(str)); | |||||
| String toRawJson() => json.encode(toJson()); | |||||
| factory MeetingsMangersModel.fromJson(Map<String, dynamic> json) => | |||||
| MeetingsMangersModel( | |||||
| id: json["id"], | |||||
| name: json["name"], | |||||
| role: json["role"], | |||||
| mobile: json["mobile"], | |||||
| otp: json["otp"], | |||||
| access: json["access"], | |||||
| managerId: json["manager_id"], | |||||
| firebaseToken: json["firebase_token"], | |||||
| isBlock: json["is_block"], | |||||
| getSms: json["get_sms"], | |||||
| createdAt: json["created_at"] == null | |||||
| ? null | |||||
| : DateTime.parse(json["created_at"]), | |||||
| updatedAt: json["updated_at"] == null | |||||
| ? null | |||||
| : DateTime.parse(json["updated_at"]), | |||||
| ); | |||||
| Map<String, dynamic> toJson() => { | |||||
| "id": id, | |||||
| "name": name, | |||||
| "role": role, | |||||
| "mobile": mobile, | |||||
| "otp": otp, | |||||
| "access": access, | |||||
| "manager_id": managerId, | |||||
| "firebase_token": firebaseToken, | |||||
| "is_block": isBlock, | |||||
| "get_sms": getSms, | |||||
| "created_at": createdAt?.toIso8601String(), | |||||
| "updated_at": updatedAt?.toIso8601String(), | |||||
| }; | |||||
| } | |||||
| @@ -0,0 +1,287 @@ | |||||
| import 'dart:convert'; | |||||
| class MeetingsModel { | |||||
| List<Datum>? data; | |||||
| MeetingsModel({ | |||||
| this.data, | |||||
| }); | |||||
| factory MeetingsModel.fromRawJson(String str) => | |||||
| MeetingsModel.fromJson(json.decode(str)); | |||||
| String toRawJson() => json.encode(toJson()); | |||||
| factory MeetingsModel.fromJson(Map<String, dynamic> json) => MeetingsModel( | |||||
| data: json["data"] == null | |||||
| ? [] | |||||
| : List<Datum>.from(json["data"]!.map((x) => Datum.fromJson(x))), | |||||
| ); | |||||
| Map<String, dynamic> toJson() => { | |||||
| "data": data == null | |||||
| ? [] | |||||
| : List<dynamic>.from(data!.map((x) => x.toJson())), | |||||
| }; | |||||
| hasData() => data!.isNotEmpty; | |||||
| } | |||||
| class Datum { | |||||
| int? id; | |||||
| int? locationsId; | |||||
| int? subjectId; | |||||
| int? managerId; | |||||
| int? ownerId; | |||||
| String? azHour; | |||||
| String? taHour; | |||||
| dynamic description; | |||||
| int? status; | |||||
| int? accepted; | |||||
| DateTime? dateMeeting; | |||||
| DateTime? endDate; | |||||
| DateTime? createdAt; | |||||
| DateTime? updatedAt; | |||||
| String? dateJalali; | |||||
| String? statusTxt; | |||||
| String? az; | |||||
| String? ta; | |||||
| Location? location; | |||||
| Subject? subject; | |||||
| Manager? manager; | |||||
| Datum({ | |||||
| this.id, | |||||
| this.locationsId, | |||||
| this.subjectId, | |||||
| this.managerId, | |||||
| this.ownerId, | |||||
| this.azHour, | |||||
| this.taHour, | |||||
| this.description, | |||||
| this.status, | |||||
| this.accepted, | |||||
| this.dateMeeting, | |||||
| this.endDate, | |||||
| this.createdAt, | |||||
| this.updatedAt, | |||||
| this.dateJalali, | |||||
| this.statusTxt, | |||||
| this.az, | |||||
| this.ta, | |||||
| this.location, | |||||
| this.subject, | |||||
| this.manager, | |||||
| }); | |||||
| factory Datum.fromRawJson(String str) => Datum.fromJson(json.decode(str)); | |||||
| String toRawJson() => json.encode(toJson()); | |||||
| factory Datum.fromJson(Map<String, dynamic> json) => Datum( | |||||
| id: json["id"], | |||||
| locationsId: json["locations_id"], | |||||
| subjectId: json["subject_id"], | |||||
| managerId: json["manager_id"], | |||||
| ownerId: json["owner_id"], | |||||
| azHour: json["az_hour"], | |||||
| taHour: json["ta_hour"], | |||||
| description: json["description"], | |||||
| status: json["status"], | |||||
| accepted: json["accepted"], | |||||
| dateMeeting: json["date_meeting"] == null | |||||
| ? null | |||||
| : DateTime.parse(json["date_meeting"]), | |||||
| endDate: | |||||
| json["end_date"] == null ? null : DateTime.parse(json["end_date"]), | |||||
| createdAt: json["created_at"] == null | |||||
| ? null | |||||
| : DateTime.parse(json["created_at"]), | |||||
| updatedAt: json["updated_at"] == null | |||||
| ? null | |||||
| : DateTime.parse(json["updated_at"]), | |||||
| dateJalali: json["date_jalali"], | |||||
| statusTxt: json["status_txt"], | |||||
| az: json["az"], | |||||
| ta: json["ta"], | |||||
| location: json["location"] == null | |||||
| ? null | |||||
| : Location.fromJson(json["location"]), | |||||
| subject: | |||||
| json["subject"] == null ? null : Subject.fromJson(json["subject"]), | |||||
| manager: | |||||
| json["manager"] == null ? null : Manager.fromJson(json["manager"]), | |||||
| ); | |||||
| Map<String, dynamic> toJson() => { | |||||
| "id": id, | |||||
| "locations_id": locationsId, | |||||
| "subject_id": subjectId, | |||||
| "manager_id": managerId, | |||||
| "owner_id": ownerId, | |||||
| "az_hour": azHour, | |||||
| "ta_hour": taHour, | |||||
| "description": description, | |||||
| "status": status, | |||||
| "accepted": accepted, | |||||
| "date_meeting": dateMeeting?.toIso8601String(), | |||||
| "end_date": endDate?.toIso8601String(), | |||||
| "created_at": createdAt?.toIso8601String(), | |||||
| "updated_at": updatedAt?.toIso8601String(), | |||||
| "date_jalali": dateJalali, | |||||
| "status_txt": statusTxt, | |||||
| "az": az, | |||||
| "ta": ta, | |||||
| "location": location?.toJson(), | |||||
| "subject": subject?.toJson(), | |||||
| "manager": manager?.toJson(), | |||||
| }; | |||||
| } | |||||
| class Location { | |||||
| int? id; | |||||
| String? address; | |||||
| String? addressEn; | |||||
| DateTime? createdAt; | |||||
| DateTime? updatedAt; | |||||
| Location({ | |||||
| this.id, | |||||
| this.address, | |||||
| this.addressEn, | |||||
| this.createdAt, | |||||
| this.updatedAt, | |||||
| }); | |||||
| factory Location.fromRawJson(String str) => | |||||
| Location.fromJson(json.decode(str)); | |||||
| String toRawJson() => json.encode(toJson()); | |||||
| factory Location.fromJson(Map<String, dynamic> json) => Location( | |||||
| id: json["id"], | |||||
| address: json["address"], | |||||
| addressEn: json["address_en"], | |||||
| createdAt: json["created_at"] == null | |||||
| ? null | |||||
| : DateTime.parse(json["created_at"]), | |||||
| updatedAt: json["updated_at"] == null | |||||
| ? null | |||||
| : DateTime.parse(json["updated_at"]), | |||||
| ); | |||||
| Map<String, dynamic> toJson() => { | |||||
| "id": id, | |||||
| "address": address, | |||||
| "address_en": addressEn, | |||||
| "created_at": createdAt?.toIso8601String(), | |||||
| "updated_at": updatedAt?.toIso8601String(), | |||||
| }; | |||||
| } | |||||
| class Manager { | |||||
| int? id; | |||||
| String? name; | |||||
| int? role; | |||||
| String? mobile; | |||||
| String? otp; | |||||
| dynamic access; | |||||
| dynamic managerId; | |||||
| dynamic firebaseToken; | |||||
| int? isBlock; | |||||
| int? getSms; | |||||
| DateTime? createdAt; | |||||
| DateTime? updatedAt; | |||||
| Manager({ | |||||
| this.id, | |||||
| this.name, | |||||
| this.role, | |||||
| this.mobile, | |||||
| this.otp, | |||||
| this.access, | |||||
| this.managerId, | |||||
| this.firebaseToken, | |||||
| this.isBlock, | |||||
| this.getSms, | |||||
| this.createdAt, | |||||
| this.updatedAt, | |||||
| }); | |||||
| factory Manager.fromRawJson(String str) => Manager.fromJson(json.decode(str)); | |||||
| String toRawJson() => json.encode(toJson()); | |||||
| factory Manager.fromJson(Map<String, dynamic> json) => Manager( | |||||
| id: json["id"], | |||||
| name: json["name"], | |||||
| role: json["role"], | |||||
| mobile: json["mobile"], | |||||
| otp: json["otp"], | |||||
| access: json["access"], | |||||
| managerId: json["manager_id"], | |||||
| firebaseToken: json["firebase_token"], | |||||
| isBlock: json["is_block"], | |||||
| getSms: json["get_sms"], | |||||
| createdAt: json["created_at"] == null | |||||
| ? null | |||||
| : DateTime.parse(json["created_at"]), | |||||
| updatedAt: json["updated_at"] == null | |||||
| ? null | |||||
| : DateTime.parse(json["updated_at"]), | |||||
| ); | |||||
| Map<String, dynamic> toJson() => { | |||||
| "id": id, | |||||
| "name": name, | |||||
| "role": role, | |||||
| "mobile": mobile, | |||||
| "otp": otp, | |||||
| "access": access, | |||||
| "manager_id": managerId, | |||||
| "firebase_token": firebaseToken, | |||||
| "is_block": isBlock, | |||||
| "get_sms": getSms, | |||||
| "created_at": createdAt?.toIso8601String(), | |||||
| "updated_at": updatedAt?.toIso8601String(), | |||||
| }; | |||||
| } | |||||
| class Subject { | |||||
| int? id; | |||||
| String? subject; | |||||
| dynamic subjectEn; | |||||
| DateTime? createdAt; | |||||
| DateTime? updatedAt; | |||||
| Subject({ | |||||
| this.id, | |||||
| this.subject, | |||||
| this.subjectEn, | |||||
| this.createdAt, | |||||
| this.updatedAt, | |||||
| }); | |||||
| factory Subject.fromRawJson(String str) => Subject.fromJson(json.decode(str)); | |||||
| String toRawJson() => json.encode(toJson()); | |||||
| factory Subject.fromJson(Map<String, dynamic> json) => Subject( | |||||
| id: json["id"], | |||||
| subject: json["subject"], | |||||
| subjectEn: json["subject_en"], | |||||
| createdAt: json["created_at"] == null | |||||
| ? null | |||||
| : DateTime.parse(json["created_at"]), | |||||
| updatedAt: json["updated_at"] == null | |||||
| ? null | |||||
| : DateTime.parse(json["updated_at"]), | |||||
| ); | |||||
| Map<String, dynamic> toJson() => { | |||||
| "id": id, | |||||
| "subject": subject, | |||||
| "subject_en": subjectEn, | |||||
| "created_at": createdAt?.toIso8601String(), | |||||
| "updated_at": updatedAt?.toIso8601String(), | |||||
| }; | |||||
| } | |||||
| @@ -0,0 +1,30 @@ | |||||
| import 'dart:convert'; | |||||
| class SubjectsModel { | |||||
| int? id; | |||||
| String? subject; | |||||
| dynamic subjectEn; | |||||
| SubjectsModel({ | |||||
| this.id, | |||||
| this.subject, | |||||
| this.subjectEn, | |||||
| }); | |||||
| factory SubjectsModel.fromRawJson(String str) => | |||||
| SubjectsModel.fromJson(json.decode(str)); | |||||
| String toRawJson() => json.encode(toJson()); | |||||
| factory SubjectsModel.fromJson(Map<String, dynamic> json) => SubjectsModel( | |||||
| id: json["id"], | |||||
| subject: json["subject"], | |||||
| subjectEn: json["subject_en"], | |||||
| ); | |||||
| Map<String, dynamic> toJson() => { | |||||
| "id": id, | |||||
| "subject": subject, | |||||
| "subject_en": subjectEn, | |||||
| }; | |||||
| } | |||||
| @@ -0,0 +1,70 @@ | |||||
| import 'dart:convert'; | |||||
| class UsersModel { | |||||
| int? id; | |||||
| String? name; | |||||
| int? role; | |||||
| String? mobile; | |||||
| dynamic otp; | |||||
| dynamic access; | |||||
| dynamic managerId; | |||||
| dynamic firebaseToken; | |||||
| int? isBlock; | |||||
| int? getSms; | |||||
| DateTime? createdAt; | |||||
| DateTime? updatedAt; | |||||
| UsersModel({ | |||||
| this.id, | |||||
| this.name, | |||||
| this.role, | |||||
| this.mobile, | |||||
| this.otp, | |||||
| this.access, | |||||
| this.managerId, | |||||
| this.firebaseToken, | |||||
| this.isBlock, | |||||
| this.getSms, | |||||
| this.createdAt, | |||||
| this.updatedAt, | |||||
| }); | |||||
| factory UsersModel.fromRawJson(String str) => | |||||
| UsersModel.fromJson(json.decode(str)); | |||||
| String toRawJson() => json.encode(toJson()); | |||||
| factory UsersModel.fromJson(Map<String, dynamic> json) => UsersModel( | |||||
| id: json["id"], | |||||
| name: json["name"], | |||||
| role: json["role"], | |||||
| mobile: json["mobile"], | |||||
| otp: json["otp"], | |||||
| access: json["access"], | |||||
| managerId: json["manager_id"], | |||||
| firebaseToken: json["firebase_token"], | |||||
| isBlock: json["is_block"], | |||||
| getSms: json["get_sms"], | |||||
| createdAt: json["created_at"] == null | |||||
| ? null | |||||
| : DateTime.parse(json["created_at"]), | |||||
| updatedAt: json["updated_at"] == null | |||||
| ? null | |||||
| : DateTime.parse(json["updated_at"]), | |||||
| ); | |||||
| Map<String, dynamic> toJson() => { | |||||
| "id": id, | |||||
| "name": name, | |||||
| "role": role, | |||||
| "mobile": mobile, | |||||
| "otp": otp, | |||||
| "access": access, | |||||
| "manager_id": managerId, | |||||
| "firebase_token": firebaseToken, | |||||
| "is_block": isBlock, | |||||
| "get_sms": getSms, | |||||
| "created_at": createdAt?.toIso8601String(), | |||||
| "updated_at": updatedAt?.toIso8601String(), | |||||
| }; | |||||
| } | |||||
| @@ -0,0 +1,272 @@ | |||||
| import 'dart:convert'; | |||||
| class OneMeetingModel { | |||||
| int? id; | |||||
| int? locationsId; | |||||
| int? subjectId; | |||||
| int? managerId; | |||||
| int? ownerId; | |||||
| String? azHour; | |||||
| String? taHour; | |||||
| dynamic description; | |||||
| int? status; | |||||
| int? accepted; | |||||
| DateTime? dateMeeting; | |||||
| DateTime? endDate; | |||||
| DateTime? createdAt; | |||||
| DateTime? updatedAt; | |||||
| List<Manager>? users; | |||||
| String? dateJalali; | |||||
| String? statusTxt; | |||||
| String? az; | |||||
| String? ta; | |||||
| Location? location; | |||||
| Subject? subject; | |||||
| Manager? manager; | |||||
| OneMeetingModel({ | |||||
| this.id, | |||||
| this.locationsId, | |||||
| this.subjectId, | |||||
| this.managerId, | |||||
| this.ownerId, | |||||
| this.azHour, | |||||
| this.taHour, | |||||
| this.description, | |||||
| this.status, | |||||
| this.accepted, | |||||
| this.dateMeeting, | |||||
| this.endDate, | |||||
| this.createdAt, | |||||
| this.updatedAt, | |||||
| this.users, | |||||
| this.dateJalali, | |||||
| this.statusTxt, | |||||
| this.az, | |||||
| this.ta, | |||||
| this.location, | |||||
| this.subject, | |||||
| this.manager, | |||||
| }); | |||||
| factory OneMeetingModel.fromRawJson(String str) => | |||||
| OneMeetingModel.fromJson(json.decode(str)); | |||||
| String toRawJson() => json.encode(toJson()); | |||||
| factory OneMeetingModel.fromJson(Map<String, dynamic> json) => | |||||
| OneMeetingModel( | |||||
| id: json["id"], | |||||
| locationsId: json["locations_id"], | |||||
| subjectId: json["subject_id"], | |||||
| managerId: json["manager_id"], | |||||
| ownerId: json["owner_id"], | |||||
| azHour: json["az_hour"], | |||||
| taHour: json["ta_hour"], | |||||
| description: json["description"], | |||||
| status: json["status"], | |||||
| accepted: json["accepted"], | |||||
| dateMeeting: json["date_meeting"] == null | |||||
| ? null | |||||
| : DateTime.parse(json["date_meeting"]), | |||||
| endDate: | |||||
| json["end_date"] == null ? null : DateTime.parse(json["end_date"]), | |||||
| createdAt: json["created_at"] == null | |||||
| ? null | |||||
| : DateTime.parse(json["created_at"]), | |||||
| updatedAt: json["updated_at"] == null | |||||
| ? null | |||||
| : DateTime.parse(json["updated_at"]), | |||||
| users: json["users"] == null | |||||
| ? [] | |||||
| : List<Manager>.from( | |||||
| json["users"]!.map((x) => Manager.fromJson(x))), | |||||
| dateJalali: json["date_jalali"], | |||||
| statusTxt: json["status_txt"], | |||||
| az: json["az"], | |||||
| ta: json["ta"], | |||||
| location: json["location"] == null | |||||
| ? null | |||||
| : Location.fromJson(json["location"]), | |||||
| subject: | |||||
| json["subject"] == null ? null : Subject.fromJson(json["subject"]), | |||||
| manager: | |||||
| json["manager"] == null ? null : Manager.fromJson(json["manager"]), | |||||
| ); | |||||
| Map<String, dynamic> toJson() => { | |||||
| "id": id, | |||||
| "locations_id": locationsId, | |||||
| "subject_id": subjectId, | |||||
| "manager_id": managerId, | |||||
| "owner_id": ownerId, | |||||
| "az_hour": azHour, | |||||
| "ta_hour": taHour, | |||||
| "description": description, | |||||
| "status": status, | |||||
| "accepted": accepted, | |||||
| "date_meeting": dateMeeting?.toIso8601String(), | |||||
| "end_date": endDate?.toIso8601String(), | |||||
| "created_at": createdAt?.toIso8601String(), | |||||
| "updated_at": updatedAt?.toIso8601String(), | |||||
| "users": users == null | |||||
| ? [] | |||||
| : List<dynamic>.from(users!.map((x) => x.toJson())), | |||||
| "date_jalali": dateJalali, | |||||
| "status_txt": statusTxt, | |||||
| "az": az, | |||||
| "ta": ta, | |||||
| "location": location?.toJson(), | |||||
| "subject": subject?.toJson(), | |||||
| "manager": manager?.toJson(), | |||||
| }; | |||||
| } | |||||
| class Location { | |||||
| int? id; | |||||
| String? address; | |||||
| String? addressEn; | |||||
| DateTime? createdAt; | |||||
| DateTime? updatedAt; | |||||
| Location({ | |||||
| this.id, | |||||
| this.address, | |||||
| this.addressEn, | |||||
| this.createdAt, | |||||
| this.updatedAt, | |||||
| }); | |||||
| factory Location.fromRawJson(String str) => | |||||
| Location.fromJson(json.decode(str)); | |||||
| String toRawJson() => json.encode(toJson()); | |||||
| factory Location.fromJson(Map<String, dynamic> json) => Location( | |||||
| id: json["id"], | |||||
| address: json["address"], | |||||
| addressEn: json["address_en"], | |||||
| createdAt: json["created_at"] == null | |||||
| ? null | |||||
| : DateTime.parse(json["created_at"]), | |||||
| updatedAt: json["updated_at"] == null | |||||
| ? null | |||||
| : DateTime.parse(json["updated_at"]), | |||||
| ); | |||||
| Map<String, dynamic> toJson() => { | |||||
| "id": id, | |||||
| "address": address, | |||||
| "address_en": addressEn, | |||||
| "created_at": createdAt?.toIso8601String(), | |||||
| "updated_at": updatedAt?.toIso8601String(), | |||||
| }; | |||||
| } | |||||
| class Manager { | |||||
| int? id; | |||||
| String? name; | |||||
| int? role; | |||||
| String? mobile; | |||||
| dynamic otp; | |||||
| dynamic access; | |||||
| dynamic managerId; | |||||
| dynamic firebaseToken; | |||||
| int? isBlock; | |||||
| int? getSms; | |||||
| DateTime? createdAt; | |||||
| DateTime? updatedAt; | |||||
| Manager({ | |||||
| this.id, | |||||
| this.name, | |||||
| this.role, | |||||
| this.mobile, | |||||
| this.otp, | |||||
| this.access, | |||||
| this.managerId, | |||||
| this.firebaseToken, | |||||
| this.isBlock, | |||||
| this.getSms, | |||||
| this.createdAt, | |||||
| this.updatedAt, | |||||
| }); | |||||
| factory Manager.fromRawJson(String str) => Manager.fromJson(json.decode(str)); | |||||
| String toRawJson() => json.encode(toJson()); | |||||
| factory Manager.fromJson(Map<String, dynamic> json) => Manager( | |||||
| id: json["id"], | |||||
| name: json["name"], | |||||
| role: json["role"], | |||||
| mobile: json["mobile"], | |||||
| otp: json["otp"], | |||||
| access: json["access"], | |||||
| managerId: json["manager_id"], | |||||
| firebaseToken: json["firebase_token"], | |||||
| isBlock: json["is_block"], | |||||
| getSms: json["get_sms"], | |||||
| createdAt: json["created_at"] == null | |||||
| ? null | |||||
| : DateTime.parse(json["created_at"]), | |||||
| updatedAt: json["updated_at"] == null | |||||
| ? null | |||||
| : DateTime.parse(json["updated_at"]), | |||||
| ); | |||||
| Map<String, dynamic> toJson() => { | |||||
| "id": id, | |||||
| "name": name, | |||||
| "role": role, | |||||
| "mobile": mobile, | |||||
| "otp": otp, | |||||
| "access": access, | |||||
| "manager_id": managerId, | |||||
| "firebase_token": firebaseToken, | |||||
| "is_block": isBlock, | |||||
| "get_sms": getSms, | |||||
| "created_at": createdAt?.toIso8601String(), | |||||
| "updated_at": updatedAt?.toIso8601String(), | |||||
| }; | |||||
| } | |||||
| class Subject { | |||||
| int? id; | |||||
| String? subject; | |||||
| String? subjectEn; | |||||
| DateTime? createdAt; | |||||
| DateTime? updatedAt; | |||||
| Subject({ | |||||
| this.id, | |||||
| this.subject, | |||||
| this.subjectEn, | |||||
| this.createdAt, | |||||
| this.updatedAt, | |||||
| }); | |||||
| factory Subject.fromRawJson(String str) => Subject.fromJson(json.decode(str)); | |||||
| String toRawJson() => json.encode(toJson()); | |||||
| factory Subject.fromJson(Map<String, dynamic> json) => Subject( | |||||
| id: json["id"], | |||||
| subject: json["subject"], | |||||
| subjectEn: json["subject_en"], | |||||
| createdAt: json["created_at"] == null | |||||
| ? null | |||||
| : DateTime.parse(json["created_at"]), | |||||
| updatedAt: json["updated_at"] == null | |||||
| ? null | |||||
| : DateTime.parse(json["updated_at"]), | |||||
| ); | |||||
| Map<String, dynamic> toJson() => { | |||||
| "id": id, | |||||
| "subject": subject, | |||||
| "subject_en": subjectEn, | |||||
| "created_at": createdAt?.toIso8601String(), | |||||
| "updated_at": updatedAt?.toIso8601String(), | |||||
| }; | |||||
| } | |||||
| @@ -0,0 +1,92 @@ | |||||
| import 'package:flutter/material.dart'; | |||||
| import 'package:go_router/go_router.dart'; | |||||
| import 'package:provider/provider.dart'; | |||||
| import 'package:qadirneyriz/drawer_navigation_bar.dart'; | |||||
| import 'package:qadirneyriz/models/meetings/meetings_model.dart'; | |||||
| import 'package:qadirneyriz/screens/auth/login_screen.dart'; | |||||
| import 'package:qadirneyriz/screens/auth/login_with_otp_screen.dart'; | |||||
| import 'package:qadirneyriz/screens/auth/otp_screen.dart'; | |||||
| import 'package:qadirneyriz/screens/home/screen.dart'; | |||||
| import 'package:qadirneyriz/screens/meeting/screen.dart'; | |||||
| import 'package:qadirneyriz/screens/meeting_edit/screen.dart'; | |||||
| import 'package:qadirneyriz/screens/meeting_edit/state.dart'; | |||||
| import 'package:qadirneyriz/screens/meeting_summary/screen.dart'; | |||||
| import 'package:qadirneyriz/screens/meeting_summary/state.dart'; | |||||
| import 'package:qadirneyriz/splash_screen.dart'; | |||||
| final GoRouter router = GoRouter( | |||||
| initialLocation: '/route', | |||||
| routes: <GoRoute>[ | |||||
| GoRoute( | |||||
| path: '/navigate/:tab', | |||||
| name: 'navigate', | |||||
| builder: (context, state) { | |||||
| return CustomDrawerNavigation( | |||||
| activeTab: int.parse(state.pathParameters["tab"]!), | |||||
| ); | |||||
| }, | |||||
| ), | |||||
| GoRoute( | |||||
| path: '/home', | |||||
| name: 'home', | |||||
| builder: (context, state) { | |||||
| return const HomeScreen(); | |||||
| }, | |||||
| ), | |||||
| GoRoute( | |||||
| path: '/route', | |||||
| builder: (BuildContext context, GoRouterState state) { | |||||
| return const SplashScreen(); | |||||
| }, | |||||
| routes: [ | |||||
| GoRoute( | |||||
| path: 'login', | |||||
| name: 'login', | |||||
| builder: (context, state) { | |||||
| return const LoginScreen(); | |||||
| }, | |||||
| ), | |||||
| GoRoute( | |||||
| path: 'loginotp', | |||||
| name: 'loginotp', | |||||
| builder: (context, state) { | |||||
| return const LoginWithOtpScreen(); | |||||
| }, | |||||
| ), | |||||
| GoRoute( | |||||
| path: 'otp/:phonenumber', | |||||
| name: 'otp', | |||||
| builder: (context, state) { | |||||
| return OtpScreen( | |||||
| phoneNumber: state.pathParameters['phonenumber']!, | |||||
| ); | |||||
| }, | |||||
| ), | |||||
| ]), | |||||
| GoRoute( | |||||
| path: '/meetingedit/:id', | |||||
| name: 'meetingedit', | |||||
| builder: (context, state) { | |||||
| return ChangeNotifierProvider( | |||||
| child: MeetingEditScreen( | |||||
| id: int.parse(state.pathParameters['id']!), | |||||
| ), | |||||
| create: (context) => MeetingEditState(), | |||||
| ); | |||||
| }, | |||||
| ), | |||||
| GoRoute( | |||||
| path: '/meetinsammary', | |||||
| name: 'meetinsammary', | |||||
| builder: (context, state) { | |||||
| Datum meetingData = state.extra as Datum; | |||||
| return ChangeNotifierProvider( | |||||
| create: (context) => MeetingSummaryState(), | |||||
| child: MeetingSummaryScreen( | |||||
| meetingItem: meetingData, | |||||
| ), | |||||
| ); | |||||
| }, | |||||
| ), | |||||
| ], | |||||
| ); | |||||
| @@ -0,0 +1,174 @@ | |||||
| import 'package:flutter/material.dart'; | |||||
| import 'package:provider/provider.dart'; | |||||
| import 'package:qadirneyriz/config/config.dart'; | |||||
| import 'package:qadirneyriz/screens/auth/state/state.dart'; | |||||
| import 'package:qadirneyriz/utils/enums/status.dart'; | |||||
| import 'package:qadirneyriz/utils/tools/tools.dart'; | |||||
| import 'package:qadirneyriz/widgets/custom_button.dart'; | |||||
| import 'package:qadirneyriz/widgets/custom_textfield.dart'; | |||||
| import 'package:go_router/go_router.dart'; | |||||
| import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | |||||
| class LoginScreen extends StatefulWidget { | |||||
| const LoginScreen({super.key}); | |||||
| @override | |||||
| State<LoginScreen> createState() => _LoginScreenState(); | |||||
| } | |||||
| class _LoginScreenState extends State<LoginScreen> { | |||||
| TextEditingController phoneController = TextEditingController(); | |||||
| TextEditingController passwordController = TextEditingController(); | |||||
| @override | |||||
| Widget build(BuildContext context) { | |||||
| return Scaffold( | |||||
| body: Consumer<AuthState>( | |||||
| builder: (context, value, child) { | |||||
| return CustomScrollView( | |||||
| slivers: <Widget>[ | |||||
| SliverToBoxAdapter( | |||||
| child: Container( | |||||
| height: 30, | |||||
| color: config.ui.mainGreen, | |||||
| ), | |||||
| ), | |||||
| // Header Image with cut-out shape at the bottom | |||||
| SliverToBoxAdapter( | |||||
| child: ClipPath( | |||||
| child: Image.asset( | |||||
| 'assets/images/template.png', | |||||
| width: double.infinity, | |||||
| fit: BoxFit.cover, | |||||
| ), | |||||
| ), | |||||
| ), | |||||
| // Form section with inputs and buttons | |||||
| SliverPadding( | |||||
| padding: const EdgeInsets.symmetric(horizontal: 20), | |||||
| sliver: SliverToBoxAdapter( | |||||
| child: Column( | |||||
| children: [ | |||||
| Container( | |||||
| padding: const EdgeInsets.all(16), | |||||
| decoration: BoxDecoration( | |||||
| color: Colors.white, | |||||
| borderRadius: BorderRadius.circular(16), | |||||
| boxShadow: [ | |||||
| BoxShadow( | |||||
| color: | |||||
| Colors.black.withOpacity(0.1), // light shadow | |||||
| blurRadius: 10, | |||||
| spreadRadius: 5, | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| child: Column( | |||||
| crossAxisAlignment: CrossAxisAlignment.stretch, | |||||
| children: [ | |||||
| // Username field | |||||
| CustomTextField( | |||||
| label: AppLocalizations.of(context)!.phonenumber, | |||||
| hintText: | |||||
| AppLocalizations.of(context)!.hintphonenumber, | |||||
| textEditingController: phoneController, | |||||
| textInputType: TextInputType.phone, | |||||
| ), | |||||
| const SizedBox(height: 16), | |||||
| // Password field | |||||
| CustomTextField( | |||||
| isPass: true, | |||||
| label: AppLocalizations.of(context)!.password, | |||||
| hintText: AppLocalizations.of(context)!.hintpass, | |||||
| textEditingController: passwordController, | |||||
| textInputType: TextInputType.visiblePassword, | |||||
| ), | |||||
| const SizedBox(height: 40), | |||||
| // Buttons section | |||||
| Row( | |||||
| mainAxisAlignment: MainAxisAlignment.spaceBetween, | |||||
| children: [ | |||||
| // Login button (filled) | |||||
| CustomButton( | |||||
| hieght: 56, | |||||
| fontSize: 13, | |||||
| text: AppLocalizations.of(context)! | |||||
| .submitwithotp, | |||||
| color: Colors.white, | |||||
| textColor: Colors.green, | |||||
| onPressed: | |||||
| value.statusLogin == Status.loading | |||||
| ? null | |||||
| : () { | |||||
| context.pushNamed('loginotp'); | |||||
| }), | |||||
| const SizedBox(width: 16), | |||||
| // Register button (outlined) | |||||
| Expanded( | |||||
| child: submitButton(context, value), | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| const SizedBox(height: 40), | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| ), | |||||
| ], | |||||
| ); | |||||
| }, | |||||
| ), | |||||
| ); | |||||
| } | |||||
| CustomButton submitButton(BuildContext context, AuthState state) { | |||||
| switch (state.statusLogin) { | |||||
| case Status.loading: | |||||
| return CustomButton( | |||||
| hieght: 56, | |||||
| fontSize: 12, | |||||
| text: AppLocalizations.of(context)!.loading, | |||||
| onPressed: null); | |||||
| default: | |||||
| return CustomButton( | |||||
| hieght: 56, | |||||
| fontSize: 16, | |||||
| text: AppLocalizations.of(context)!.submit, | |||||
| onPressed: () async { | |||||
| if (phoneController.text == '') { | |||||
| Tools.showCustomSnackBar( | |||||
| text: AppLocalizations.of(context)!.phoneerror, | |||||
| isError: true, | |||||
| context, | |||||
| ); | |||||
| } else if (passwordController.text == '') { | |||||
| Tools.showCustomSnackBar( | |||||
| text: AppLocalizations.of(context)!.passerror, | |||||
| isError: true, | |||||
| context, | |||||
| ); | |||||
| } else { | |||||
| final status = await state.login( | |||||
| mobile: phoneController.text, | |||||
| password: passwordController.text); | |||||
| if (status == Status.ready) { | |||||
| context.goNamed('navigate', pathParameters: {'tab': '0'}); | |||||
| } else { | |||||
| Tools.showCustomSnackBar( | |||||
| text: state.errorsLogin == null | |||||
| ? state.messageLogin ?? | |||||
| AppLocalizations.of(context)!.haserror | |||||
| : Tools.combineErrorMessages(state.errorsLogin ?? {}), | |||||
| isError: true, | |||||
| context, | |||||
| ); | |||||
| } | |||||
| } | |||||
| }, | |||||
| ); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,157 @@ | |||||
| import 'package:flutter/material.dart'; | |||||
| import 'package:go_router/go_router.dart'; | |||||
| import 'package:provider/provider.dart'; | |||||
| import 'package:qadirneyriz/config/config.dart'; | |||||
| import 'package:qadirneyriz/screens/auth/state/state.dart'; | |||||
| import 'package:qadirneyriz/utils/enums/status.dart'; | |||||
| import 'package:qadirneyriz/utils/tools/tools.dart'; | |||||
| import 'package:qadirneyriz/widgets/custom_button.dart'; | |||||
| import 'package:qadirneyriz/widgets/custom_textfield.dart'; | |||||
| import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | |||||
| class LoginWithOtpScreen extends StatefulWidget { | |||||
| const LoginWithOtpScreen({super.key}); | |||||
| @override | |||||
| State<LoginWithOtpScreen> createState() => _LoginWithOtpScreenState(); | |||||
| } | |||||
| class _LoginWithOtpScreenState extends State<LoginWithOtpScreen> { | |||||
| TextEditingController phoneController = TextEditingController(); | |||||
| @override | |||||
| Widget build(BuildContext context) { | |||||
| return Scaffold( | |||||
| body: Consumer<AuthState>( | |||||
| builder: (context, value, child) { | |||||
| return CustomScrollView( | |||||
| slivers: <Widget>[ | |||||
| SliverToBoxAdapter( | |||||
| child: Container( | |||||
| height: 30, | |||||
| color: config.ui.mainGreen, | |||||
| ), | |||||
| ), | |||||
| // Header Image with cut-out shape at the bottom | |||||
| SliverToBoxAdapter( | |||||
| child: ClipPath( | |||||
| child: Image.asset( | |||||
| 'assets/images/template.png', | |||||
| width: double.infinity, | |||||
| fit: BoxFit.cover, | |||||
| ), | |||||
| ), | |||||
| ), | |||||
| // Form section with inputs and buttons | |||||
| SliverPadding( | |||||
| padding: const EdgeInsets.symmetric(horizontal: 20), | |||||
| sliver: SliverToBoxAdapter( | |||||
| child: Column( | |||||
| children: [ | |||||
| Container( | |||||
| padding: const EdgeInsets.all(16), | |||||
| decoration: BoxDecoration( | |||||
| color: Colors.white, | |||||
| borderRadius: BorderRadius.circular(16), | |||||
| boxShadow: [ | |||||
| BoxShadow( | |||||
| color: | |||||
| Colors.black.withOpacity(0.1), // light shadow | |||||
| blurRadius: 10, | |||||
| spreadRadius: 5, | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| child: Column( | |||||
| crossAxisAlignment: CrossAxisAlignment.stretch, | |||||
| children: [ | |||||
| // Username field | |||||
| CustomTextField( | |||||
| label: AppLocalizations.of(context)!.phonenumber, | |||||
| hintText: | |||||
| AppLocalizations.of(context)!.hintphonenumber, | |||||
| textEditingController: phoneController, | |||||
| textInputType: TextInputType.phone, | |||||
| ), | |||||
| const SizedBox(height: 40), | |||||
| // Buttons section | |||||
| Row( | |||||
| mainAxisAlignment: MainAxisAlignment.spaceBetween, | |||||
| children: [ | |||||
| CustomButton( | |||||
| hieght: 56, | |||||
| fontSize: 13, | |||||
| text: AppLocalizations.of(context)! | |||||
| .submitwithphone, | |||||
| color: Colors.white, | |||||
| textColor: Colors.green, | |||||
| onPressed: | |||||
| value.statusSendotp == Status.loading | |||||
| ? null | |||||
| : () { | |||||
| context.pop(); | |||||
| }, | |||||
| ), | |||||
| const SizedBox(width: 16), | |||||
| Expanded( | |||||
| child: submitButton(context, value), | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| const SizedBox(height: 40), | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| ), | |||||
| ], | |||||
| ); | |||||
| }, | |||||
| ), | |||||
| ); | |||||
| } | |||||
| CustomButton submitButton(BuildContext context, AuthState state) { | |||||
| switch (state.statusSendotp) { | |||||
| case Status.loading: | |||||
| return CustomButton( | |||||
| hieght: 56, | |||||
| fontSize: 12, | |||||
| text: AppLocalizations.of(context)!.loading, | |||||
| onPressed: null); | |||||
| default: | |||||
| return CustomButton( | |||||
| hieght: 56, | |||||
| fontSize: 16, | |||||
| text: AppLocalizations.of(context)!.submit, | |||||
| onPressed: () async { | |||||
| if (phoneController.text == '') { | |||||
| Tools.showCustomSnackBar( | |||||
| text: AppLocalizations.of(context)!.phoneerror, | |||||
| isError: true, | |||||
| context, | |||||
| ); | |||||
| } else { | |||||
| final status = await state.sendOtp(mobile: phoneController.text); | |||||
| if (status == Status.ready) { | |||||
| context.pushNamed('otp', | |||||
| pathParameters: {'phonenumber': phoneController.text}); | |||||
| } else { | |||||
| Tools.showCustomSnackBar( | |||||
| text: state.errorsSendOtp == null | |||||
| ? state.messageSendOtp ?? | |||||
| AppLocalizations.of(context)!.haserror | |||||
| : Tools.combineErrorMessages(state.errorsSendOtp ?? {}), | |||||
| isError: true, | |||||
| context, | |||||
| ); | |||||
| } | |||||
| } | |||||
| }, | |||||
| ); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,211 @@ | |||||
| // ignore_for_file: public_member_api_docs, sort_constructors_first | |||||
| import 'package:flutter/material.dart'; | |||||
| import 'package:go_router/go_router.dart'; | |||||
| import 'package:provider/provider.dart'; | |||||
| import 'package:qadirneyriz/config/config.dart'; | |||||
| import 'package:qadirneyriz/screens/auth/state/state.dart'; | |||||
| import 'package:qadirneyriz/utils/enums/status.dart'; | |||||
| import 'package:qadirneyriz/utils/timer/apt_simple_timer_with_controller.dart'; | |||||
| import 'package:qadirneyriz/utils/tools/tools.dart'; | |||||
| import 'package:qadirneyriz/widgets/otp_textfield.dart'; | |||||
| import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | |||||
| class OtpScreen extends StatefulWidget { | |||||
| final String phoneNumber; | |||||
| const OtpScreen({ | |||||
| super.key, | |||||
| required this.phoneNumber, | |||||
| }); | |||||
| @override | |||||
| State<OtpScreen> createState() => _OtpScreenState(); | |||||
| } | |||||
| class _OtpScreenState extends State<OtpScreen> { | |||||
| bool timerEnd = false; | |||||
| @override | |||||
| Widget build(BuildContext context) { | |||||
| return Scaffold( | |||||
| body: Consumer<AuthState>( | |||||
| builder: (context, value, child) { | |||||
| return CustomScrollView( | |||||
| slivers: <Widget>[ | |||||
| SliverToBoxAdapter( | |||||
| child: Container( | |||||
| height: 30, | |||||
| color: config.ui.mainGreen, | |||||
| ), | |||||
| ), | |||||
| // Header Image with cut-out shape at the bottom | |||||
| SliverToBoxAdapter( | |||||
| child: ClipPath( | |||||
| child: Image.asset( | |||||
| 'assets/images/template.png', | |||||
| width: double.infinity, | |||||
| fit: BoxFit.cover, | |||||
| ), | |||||
| ), | |||||
| ), | |||||
| SliverPadding( | |||||
| padding: const EdgeInsets.symmetric(horizontal: 20), | |||||
| sliver: SliverToBoxAdapter( | |||||
| child: Container( | |||||
| padding: const EdgeInsets.all(16), | |||||
| decoration: BoxDecoration( | |||||
| color: Colors.white, | |||||
| borderRadius: BorderRadius.circular(16), | |||||
| boxShadow: [ | |||||
| BoxShadow( | |||||
| color: | |||||
| Colors.black.withOpacity(0.1), // light shadow | |||||
| blurRadius: 10, | |||||
| spreadRadius: 5, | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| child: Column( | |||||
| children: [ | |||||
| Text( | |||||
| AppLocalizations.of(context)!.enterotp, | |||||
| style: TextStyle( | |||||
| color: config.ui.mainGray, | |||||
| fontSize: 18, | |||||
| fontWeight: FontWeight.bold), | |||||
| ), | |||||
| const SizedBox( | |||||
| height: 5, | |||||
| ), | |||||
| Text( | |||||
| AppLocalizations.of(context)!.an4digitotp, | |||||
| style: TextStyle( | |||||
| color: config.ui.mainGray.withOpacity(.5), | |||||
| fontSize: 14, | |||||
| ), | |||||
| ), | |||||
| const SizedBox( | |||||
| height: 5, | |||||
| ), | |||||
| Row( | |||||
| mainAxisAlignment: MainAxisAlignment.center, | |||||
| children: [ | |||||
| Text( | |||||
| widget.phoneNumber, | |||||
| style: TextStyle( | |||||
| color: config.ui.mainGray.withOpacity(.5), | |||||
| fontSize: 16, | |||||
| fontWeight: FontWeight.bold), | |||||
| ), | |||||
| Icon( | |||||
| Icons.phone_callback_outlined, | |||||
| color: config.ui.mainGreen, | |||||
| ) | |||||
| ], | |||||
| ), | |||||
| const SizedBox( | |||||
| height: 10, | |||||
| ), | |||||
| OTPTextField( | |||||
| length: 4, | |||||
| onSubmitted: (onSubmitted) { | |||||
| otpCheckCode(onSubmitted, value); | |||||
| }), | |||||
| const SizedBox( | |||||
| height: 20, | |||||
| ), | |||||
| Row( | |||||
| mainAxisAlignment: MainAxisAlignment.center, | |||||
| children: [ | |||||
| resendOtpbutton(value), | |||||
| if (!timerEnd) | |||||
| Directionality( | |||||
| textDirection: TextDirection.ltr, | |||||
| child: AptSimpleTimerWithController( | |||||
| seconds: 60, | |||||
| fontSize: 16, | |||||
| timerColor: const Color(0xff8FA5B6) | |||||
| .withOpacity(0.6), | |||||
| onTimerEnd: () { | |||||
| setState(() { | |||||
| timerEnd = true; | |||||
| }); | |||||
| }, | |||||
| ), | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| ], | |||||
| )), | |||||
| ), | |||||
| ), | |||||
| ], | |||||
| ); | |||||
| }, | |||||
| ), | |||||
| ); | |||||
| } | |||||
| Widget resendOtpbutton(AuthState value) { | |||||
| return timerEnd | |||||
| ? GestureDetector( | |||||
| onTap: value.statusSendotp != Status.loading | |||||
| ? () async { | |||||
| final status = await value.sendOtp( | |||||
| mobile: widget.phoneNumber, | |||||
| ); | |||||
| if (status == Status.ready) { | |||||
| setState(() { | |||||
| timerEnd = false; | |||||
| }); | |||||
| } else { | |||||
| Tools.showCustomSnackBar( | |||||
| text: value.errorsSendOtp == null | |||||
| ? value.messageSendOtp ?? 'An error has occurred' | |||||
| : Tools.combineErrorMessages( | |||||
| value.errorsSendOtp ?? {}), | |||||
| isError: true, | |||||
| context, | |||||
| ); | |||||
| } | |||||
| } | |||||
| : null, | |||||
| child: Text( | |||||
| value.statusSendotp == Status.loading | |||||
| ? AppLocalizations.of(context)!.loading | |||||
| : AppLocalizations.of(context)!.resend, | |||||
| style: TextStyle( | |||||
| color: config.ui.secendGreen, | |||||
| fontSize: 16, | |||||
| ), | |||||
| ), | |||||
| ) | |||||
| : Container(); | |||||
| } | |||||
| void otpCheckCode(onSubmitted, AuthState value) async { | |||||
| if (onSubmitted.length == 4) { | |||||
| final status = | |||||
| await value.login(mobile: widget.phoneNumber, otp: onSubmitted); | |||||
| if (status == Status.ready) { | |||||
| context.goNamed('navigate', pathParameters: {'tab': '0'}); | |||||
| } else if (status == Status.error) { | |||||
| Tools.showCustomSnackBar( | |||||
| text: value.errorsLogin == null | |||||
| ? value.messageLogin ?? AppLocalizations.of(context)!.haserror | |||||
| : Tools.combineErrorMessages(value.errorsLogin ?? {}), | |||||
| isError: true, | |||||
| context, | |||||
| ); | |||||
| setState(() {}); | |||||
| } else if (status == Status.empty) { | |||||
| Tools.showCustomSnackBar( | |||||
| text: value.errorsLogin == null | |||||
| ? value.messageLogin ?? AppLocalizations.of(context)!.haserror | |||||
| : Tools.combineErrorMessages(value.errorsLogin ?? {}), | |||||
| isError: true, | |||||
| context, | |||||
| ); | |||||
| onSubmitted = ''; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,93 @@ | |||||
| import 'package:flutter/material.dart'; | |||||
| import 'package:qadirneyriz/services/auth/auth.dart'; | |||||
| import 'package:qadirneyriz/setting/setting.dart'; | |||||
| import 'package:qadirneyriz/utils/enums/status.dart'; | |||||
| class AuthState extends ChangeNotifier { | |||||
| /// set and fetch language | |||||
| String language = setting.userLocalDb.getUser().language; | |||||
| Future<void> setLocale(String newLanguage) async { | |||||
| language = newLanguage; | |||||
| await setting.userLocalDb.saveUserField('language', newLanguage); | |||||
| notifyListeners(); | |||||
| } | |||||
| // auth seviceses class | |||||
| AuthServices authServises = AuthServices(); | |||||
| // login funtinulity | |||||
| Status statusLogin = Status.empty; | |||||
| String? messageLogin; | |||||
| Map? errorsLogin; | |||||
| Future<Status> login( | |||||
| {required String mobile, String? password, String? otp}) async { | |||||
| assert(password != null || otp != null); | |||||
| statusLogin = Status.loading; | |||||
| notifyListeners(); | |||||
| try { | |||||
| final result = await authServises.loginApi( | |||||
| mobile: mobile, password: password, otp: otp); | |||||
| if (result == null) { | |||||
| statusLogin = Status.error; | |||||
| } else { | |||||
| if (result.isOk) { | |||||
| statusLogin = Status.ready; | |||||
| messageLogin = result.message; | |||||
| } else if (result.isOk == false) { | |||||
| errorsLogin = result.errors; | |||||
| messageLogin = result.message; | |||||
| statusLogin = Status.error; | |||||
| } else { | |||||
| statusLogin = Status.error; | |||||
| } | |||||
| notifyListeners(); | |||||
| } | |||||
| notifyListeners(); | |||||
| } catch (e) { | |||||
| statusLogin = Status.error; | |||||
| } | |||||
| notifyListeners(); | |||||
| return statusLogin; | |||||
| } | |||||
| Status statusSendotp = Status.empty; | |||||
| String? messageSendOtp; | |||||
| Map? errorsSendOtp; | |||||
| Future<Status> sendOtp({ | |||||
| required String mobile, | |||||
| }) async { | |||||
| statusSendotp = Status.loading; | |||||
| notifyListeners(); | |||||
| try { | |||||
| final result = await authServises.sendOtpApi(mobile: mobile); | |||||
| if (result == null) { | |||||
| statusSendotp = Status.error; | |||||
| } else { | |||||
| print(result); | |||||
| if (result.isOk) { | |||||
| statusSendotp = Status.ready; | |||||
| messageSendOtp = result.message; | |||||
| } else if (result.isOk == false) { | |||||
| errorsSendOtp = result.errors; | |||||
| messageSendOtp = result.message; | |||||
| statusSendotp = Status.error; | |||||
| } else { | |||||
| statusSendotp = Status.error; | |||||
| } | |||||
| notifyListeners(); | |||||
| } | |||||
| notifyListeners(); | |||||
| } catch (e) { | |||||
| statusSendotp = Status.error; | |||||
| print(e); | |||||
| } | |||||
| notifyListeners(); | |||||
| print(statusSendotp); | |||||
| return statusSendotp; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,253 @@ | |||||
| // ignore_for_file: public_member_api_docs, sort_constructors_first | |||||
| import 'package:flutter/material.dart'; | |||||
| import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; | |||||
| import 'package:go_router/go_router.dart'; | |||||
| import 'package:provider/provider.dart'; | |||||
| import 'package:qadirneyriz/utils/tools/tools.dart'; | |||||
| import 'package:qadirneyriz/widgets/card_meeting.dart'; | |||||
| import 'package:qadirneyriz/widgets/custom_appbar.dart'; | |||||
| import 'package:qadirneyriz/widgets/today_widget.dart'; | |||||
| import 'package:shamsi_date/shamsi_date.dart'; | |||||
| import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | |||||
| import 'package:qadirneyriz/config/config.dart'; | |||||
| import 'package:qadirneyriz/screens/home/state.dart'; | |||||
| import 'package:qadirneyriz/utils/enums/status.dart'; | |||||
| import 'package:qadirneyriz/widgets/loading_widget.dart'; | |||||
| class HomeScreen extends StatefulWidget { | |||||
| const HomeScreen({super.key}); | |||||
| @override | |||||
| State<HomeScreen> createState() => _HomeScreenState(); | |||||
| } | |||||
| class _HomeScreenState extends State<HomeScreen> { | |||||
| @override | |||||
| void initState() { | |||||
| super.initState(); | |||||
| HomeState homeState = Provider.of(context, listen: false); | |||||
| Future.delayed(Duration.zero, () async { | |||||
| await homeState.getTodayMeetings(); | |||||
| }); | |||||
| } | |||||
| @override | |||||
| Widget build(BuildContext context) { | |||||
| final Jalali shamsi = Jalali.now(); // دریافت تاریخ شمسی کنونی | |||||
| String formattedDate = | |||||
| '${shamsi.day} ${Tools.getMonthName(shamsi.month)} ${shamsi.year}'; // فرمت کردن تاریخ | |||||
| return Consumer<HomeState>( | |||||
| builder: (context, value, child) { | |||||
| switch (value.todayMettingsStatus) { | |||||
| case Status.ready: | |||||
| return CustomScrollView( | |||||
| slivers: [ | |||||
| const CustomAppbar(), | |||||
| SliverToBoxAdapter( | |||||
| child: Padding( | |||||
| padding: const EdgeInsets.symmetric( | |||||
| horizontal: 20, vertical: 10), | |||||
| child: Container( | |||||
| decoration: BoxDecoration( | |||||
| color: const Color(0xffF4F9F6), | |||||
| boxShadow: [ | |||||
| BoxShadow( | |||||
| color: config.ui.mainGray.withOpacity(.1), | |||||
| spreadRadius: .1, | |||||
| offset: const Offset(0, 5), | |||||
| blurRadius: 6) | |||||
| ], | |||||
| borderRadius: BorderRadius.circular(25)), | |||||
| width: double.infinity, | |||||
| child: Padding( | |||||
| padding: const EdgeInsets.all(20), | |||||
| child: Row( | |||||
| crossAxisAlignment: CrossAxisAlignment.start, | |||||
| children: [ | |||||
| Icon( | |||||
| Icons.edit_outlined, | |||||
| color: config.ui.mainGreen, | |||||
| ), | |||||
| const SizedBox( | |||||
| width: 10, | |||||
| ), | |||||
| Expanded( | |||||
| child: Text( | |||||
| style: const TextStyle(fontSize: 13), | |||||
| value.todayMeetingsModel!.note ?? ''), | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| ), | |||||
| ), | |||||
| ), | |||||
| SliverToBoxAdapter( | |||||
| child: TodayWidget(formattedDate: formattedDate), | |||||
| ), | |||||
| SliverToBoxAdapter( | |||||
| child: SizedBox( | |||||
| height: 165, | |||||
| child: value.todayMeetingsModel!.meetings!.isNotEmpty | |||||
| ? ListView.builder( | |||||
| scrollDirection: Axis.horizontal, | |||||
| itemCount: | |||||
| value.todayMeetingsModel!.meetings!.length, | |||||
| itemBuilder: (BuildContext context, int index) { | |||||
| final items = | |||||
| value.todayMeetingsModel!.meetings![index]; | |||||
| return CustomCardMeeting( | |||||
| titel: items.subject!.subject ?? '', | |||||
| fromTime: items.azHour ?? '', | |||||
| toTime: items.taHour ?? "", | |||||
| location: items.location!.address ?? '', | |||||
| date: items.dateJalali ?? '', | |||||
| cardId: items.id ?? 0, | |||||
| ); | |||||
| }, | |||||
| ) | |||||
| : Center( | |||||
| child: Column( | |||||
| mainAxisAlignment: MainAxisAlignment.center, | |||||
| children: [ | |||||
| Icon(Icons.error_outline, | |||||
| size: 40, | |||||
| color: config.ui.mainGray.withOpacity(.5)), | |||||
| const SizedBox( | |||||
| height: 20, | |||||
| ), | |||||
| Text( | |||||
| AppLocalizations.of(context)! | |||||
| .nomeetingfortoday, | |||||
| style: TextStyle( | |||||
| color: | |||||
| config.ui.mainGray.withOpacity(.5)), | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| ), | |||||
| ), | |||||
| SliverPadding( | |||||
| padding: | |||||
| const EdgeInsets.symmetric(vertical: 30, horizontal: 10), | |||||
| sliver: SliverToBoxAdapter( | |||||
| child: StaggeredGrid.count( | |||||
| crossAxisCount: 4, | |||||
| mainAxisSpacing: 4, | |||||
| crossAxisSpacing: 4, | |||||
| children: [ | |||||
| StaggeredGridTile.count( | |||||
| crossAxisCellCount: 2, | |||||
| mainAxisCellCount: 1, | |||||
| child: ItemInGrid( | |||||
| icon: Icons.assessment, | |||||
| backColor: const Color(0xff03C85F), | |||||
| text: AppLocalizations.of(context)!.reports, | |||||
| onTap: () {}, | |||||
| ), | |||||
| ), | |||||
| StaggeredGridTile.count( | |||||
| crossAxisCellCount: 2, | |||||
| mainAxisCellCount: 2, | |||||
| child: ItemInGrid( | |||||
| icon: Icons.people, | |||||
| backColor: const Color(0xff04A54F), | |||||
| text: AppLocalizations.of(context)!.meetings, | |||||
| onTap: () { | |||||
| context.pushNamed('navigate', | |||||
| pathParameters: {'tab': '1'}); | |||||
| }, | |||||
| ), | |||||
| ), | |||||
| StaggeredGridTile.count( | |||||
| crossAxisCellCount: 2, | |||||
| mainAxisCellCount: 2, | |||||
| child: ItemInGrid( | |||||
| icon: Icons.calendar_today, | |||||
| backColor: const Color(0xff37A068), | |||||
| text: AppLocalizations.of(context)!.events, | |||||
| onTap: () {}, | |||||
| ), | |||||
| ), | |||||
| StaggeredGridTile.count( | |||||
| crossAxisCellCount: 2, | |||||
| mainAxisCellCount: 1, | |||||
| child: ItemInGrid( | |||||
| icon: Icons.exit_to_app, | |||||
| backColor: const Color(0xff00843D), | |||||
| text: AppLocalizations.of(context)!.exit, | |||||
| onTap: () {}, | |||||
| ), | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| ), | |||||
| ], | |||||
| ); | |||||
| case Status.loading: | |||||
| return const LoadingWidget(); | |||||
| default: | |||||
| return Container(); | |||||
| } | |||||
| }, | |||||
| ); | |||||
| } | |||||
| } | |||||
| class ItemInGrid extends StatelessWidget { | |||||
| final IconData icon; | |||||
| final Color backColor; | |||||
| final String text; | |||||
| final void Function() onTap; | |||||
| const ItemInGrid( | |||||
| {super.key, | |||||
| required this.icon, | |||||
| required this.backColor, | |||||
| required this.text, | |||||
| required this.onTap}); | |||||
| @override | |||||
| Widget build(BuildContext context) { | |||||
| return Padding( | |||||
| padding: const EdgeInsets.all(4.0), | |||||
| child: GestureDetector( | |||||
| onTap: onTap, | |||||
| child: Container( | |||||
| decoration: BoxDecoration( | |||||
| borderRadius: BorderRadius.circular(20), | |||||
| color: backColor, | |||||
| boxShadow: [ | |||||
| BoxShadow( | |||||
| color: config.ui.mainGray.withOpacity(.5), | |||||
| spreadRadius: .1, | |||||
| offset: const Offset(0, 2), | |||||
| blurRadius: 6) | |||||
| ], | |||||
| ), | |||||
| child: Column( | |||||
| mainAxisAlignment: MainAxisAlignment.center, | |||||
| children: [ | |||||
| Icon( | |||||
| icon, | |||||
| size: 40, | |||||
| color: Colors.white, | |||||
| ), | |||||
| const SizedBox( | |||||
| height: 8, | |||||
| ), | |||||
| Text( | |||||
| text, | |||||
| style: const TextStyle( | |||||
| color: Colors.white, | |||||
| ), | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| ), | |||||
| ); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,52 @@ | |||||
| import 'package:flutter/material.dart'; | |||||
| import 'package:qadirneyriz/models/home/home_models.dart'; | |||||
| import 'package:qadirneyriz/services/home/home.dart'; | |||||
| import 'package:qadirneyriz/utils/enums/status.dart'; | |||||
| class HomeState extends ChangeNotifier { | |||||
| HomeApi homeApi = HomeApi(); | |||||
| Status todayMettingsStatus = Status.empty; | |||||
| TodayMeetingModel? todayMeetingsModel; | |||||
| getTodayMeetings({bool refresh = false}) async { | |||||
| todayMettingsStatus = Status.loading; | |||||
| notifyListeners(); | |||||
| if (refresh) { | |||||
| todayMettingsStatus = Status.loading; | |||||
| notifyListeners(); | |||||
| } | |||||
| if (todayMeetingsModel != null) { | |||||
| todayMettingsStatus = Status.ready; | |||||
| try { | |||||
| todayMeetingsModel = await homeApi.getTodayMeetings(); | |||||
| if (todayMeetingsModel != null) { | |||||
| todayMettingsStatus = Status.ready; | |||||
| } else { | |||||
| todayMettingsStatus = Status.empty; | |||||
| } | |||||
| } catch (e) { | |||||
| todayMettingsStatus = Status.error; | |||||
| // print(e); | |||||
| } | |||||
| notifyListeners(); | |||||
| } else { | |||||
| try { | |||||
| todayMeetingsModel = await homeApi.getTodayMeetings(); | |||||
| if (todayMeetingsModel != null) { | |||||
| todayMettingsStatus = Status.ready; | |||||
| } else { | |||||
| todayMettingsStatus = Status.empty; | |||||
| } | |||||
| notifyListeners(); | |||||
| } catch (e) { | |||||
| todayMettingsStatus = Status.error; | |||||
| print(e); | |||||
| } | |||||
| } | |||||
| notifyListeners(); | |||||
| print(todayMettingsStatus); | |||||
| return todayMettingsStatus; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,391 @@ | |||||
| // ignore_for_file: public_member_api_docs, sort_constructors_first | |||||
| import 'package:flutter/material.dart'; | |||||
| import 'package:provider/provider.dart'; | |||||
| import 'package:qadirneyriz/global_state/global_state.dart'; | |||||
| import 'package:qadirneyriz/widgets/ExpansionTileCustom.dart'; | |||||
| import 'package:qadirneyriz/widgets/error_widget.dart'; | |||||
| import 'package:qadirneyriz/config/config.dart'; | |||||
| import 'package:qadirneyriz/screens/meeting/state.dart'; | |||||
| import 'package:qadirneyriz/utils/enums/status.dart'; | |||||
| import 'package:qadirneyriz/utils/tools/tools.dart'; | |||||
| import 'package:qadirneyriz/widgets/picker.dart'; | |||||
| import 'package:qadirneyriz/widgets/loading_widget.dart'; | |||||
| import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | |||||
| class DiologMeetingsFilters extends StatefulWidget { | |||||
| const DiologMeetingsFilters({ | |||||
| super.key, | |||||
| }); | |||||
| @override | |||||
| State<DiologMeetingsFilters> createState() => _DiologMeetingsFiltersState(); | |||||
| } | |||||
| class _DiologMeetingsFiltersState extends State<DiologMeetingsFilters> { | |||||
| MeetingsState? meetingsState; | |||||
| GlobalState? globalState; | |||||
| @override | |||||
| void initState() { | |||||
| meetingsState = Provider.of<MeetingsState>(context, listen: false); | |||||
| globalState = Provider.of<GlobalState>(context, listen: false); | |||||
| Future.delayed(Duration.zero, () async { | |||||
| final status = await globalState!.getAllFiltersItems(); | |||||
| print(status); | |||||
| }); | |||||
| super.initState(); | |||||
| } | |||||
| @override | |||||
| void dispose() { | |||||
| Future.delayed(Duration.zero, () async { | |||||
| await meetingsState!.getMeetings( | |||||
| refresh: true, | |||||
| toDate: meetingsState!.toDate, | |||||
| fromDate: meetingsState!.fromDate, | |||||
| location: meetingsState!.selectedLocationId, | |||||
| subject: meetingsState!.selectedSubjectId, | |||||
| meetingManager: meetingsState!.selectedManagersId, | |||||
| meetingStatus: meetingsState!.selectedStatusId); | |||||
| }); | |||||
| super.dispose(); | |||||
| } | |||||
| @override | |||||
| Widget build(BuildContext context) { | |||||
| return DraggableScrollableSheet( | |||||
| initialChildSize: .7, | |||||
| expand: false, | |||||
| snap: false, | |||||
| builder: (context, scrollController) { | |||||
| return Consumer2<MeetingsState, GlobalState>( | |||||
| builder: (context, meetingsState, globalState, child) { | |||||
| switch (globalState.allFiltersStatus) { | |||||
| case Status.ready: | |||||
| return Column( | |||||
| children: [ | |||||
| LineButtomSheet(), | |||||
| Expanded( | |||||
| child: SingleChildScrollView( | |||||
| controller: scrollController, | |||||
| child: Column( | |||||
| children: [ | |||||
| Column( | |||||
| mainAxisSize: MainAxisSize.max, | |||||
| children: [ | |||||
| Padding( | |||||
| padding: const EdgeInsets.symmetric( | |||||
| vertical: 25, horizontal: 15), | |||||
| child: Row( | |||||
| mainAxisAlignment: | |||||
| MainAxisAlignment.spaceBetween, | |||||
| children: [ | |||||
| Text( | |||||
| AppLocalizations.of(context)! | |||||
| .searchFor, | |||||
| ), | |||||
| GestureDetector( | |||||
| onTap: () { | |||||
| meetingsState.clearFilters(); | |||||
| }, | |||||
| child: | |||||
| meetingsState.hasActiveFilters() | |||||
| ? Icon( | |||||
| Icons.delete_outline, | |||||
| color: Colors.red, | |||||
| ) | |||||
| : Icon( | |||||
| Icons.delete_outline, | |||||
| color: Colors.black | |||||
| .withOpacity(.3), | |||||
| )) | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| Divider(), | |||||
| SizedBox( | |||||
| height: 10, | |||||
| ), | |||||
| ExpansionTileCustom( | |||||
| title: AppLocalizations.of(context)!.date, | |||||
| widgets: <Widget>[ | |||||
| Padding( | |||||
| padding: const EdgeInsets.all(20.0), | |||||
| child: Row( | |||||
| crossAxisAlignment: | |||||
| CrossAxisAlignment.end, | |||||
| mainAxisAlignment: | |||||
| MainAxisAlignment.spaceBetween, | |||||
| children: [ | |||||
| PickerCustom( | |||||
| showDate: meetingsState | |||||
| .fromDate.isNotEmpty | |||||
| ? meetingsState.fromDate | |||||
| : AppLocalizations.of( | |||||
| context)! | |||||
| .selectdate, // Show selected date or prompt | |||||
| onTap: () { | |||||
| showDialog( | |||||
| context: context, | |||||
| builder: (context) { | |||||
| return Dialog( | |||||
| child: Tools | |||||
| .shamsiDateCalendarWidget( | |||||
| context, | |||||
| (newDate) { | |||||
| String | |||||
| fromDateString = | |||||
| '${newDate.year}/${newDate.month}/${newDate.day}'; | |||||
| meetingsState | |||||
| .setFromDates( | |||||
| fromDateString); // Update the selected date | |||||
| }, | |||||
| ), | |||||
| ); | |||||
| }, | |||||
| ); | |||||
| }, | |||||
| ), | |||||
| Text( | |||||
| AppLocalizations.of(context)!.to, | |||||
| ), | |||||
| PickerCustom( | |||||
| showDate: meetingsState | |||||
| .toDate.isNotEmpty | |||||
| ? meetingsState.toDate | |||||
| : AppLocalizations.of( | |||||
| context)! | |||||
| .selectdate, // Show selected date or prompt | |||||
| onTap: () { | |||||
| showDialog( | |||||
| context: context, | |||||
| builder: (context) { | |||||
| return Dialog( | |||||
| child: Tools | |||||
| .shamsiDateCalendarWidget( | |||||
| context, | |||||
| (newDate) { | |||||
| String toDateString = | |||||
| '${newDate.year}/${newDate.month}/${newDate.day}'; | |||||
| meetingsState.setToDates( | |||||
| toDateString); // Update the selected date | |||||
| }, | |||||
| ), | |||||
| ); | |||||
| }, | |||||
| ); | |||||
| }, | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| ) | |||||
| ], | |||||
| ), | |||||
| ExpansionTileCustom( | |||||
| title: | |||||
| AppLocalizations.of(context)!.location, | |||||
| widgets: <Widget>[ | |||||
| ListView.builder( | |||||
| primary: false, | |||||
| physics: NeverScrollableScrollPhysics(), | |||||
| shrinkWrap: true, | |||||
| itemCount: | |||||
| globalState.locationsModel!.length, | |||||
| itemBuilder: | |||||
| (BuildContext context, int index) { | |||||
| final items = globalState | |||||
| .locationsModel![index]; | |||||
| return RadioListTile<int>( | |||||
| toggleable: true, | |||||
| groupValue: meetingsState | |||||
| .selectedLocationId, | |||||
| value: items.id ?? -1, | |||||
| title: Text( | |||||
| items.address ?? '', | |||||
| maxLines: 1, | |||||
| style: TextStyle( | |||||
| fontWeight: FontWeight.w100, | |||||
| fontSize: 14), | |||||
| overflow: TextOverflow.ellipsis, | |||||
| ), | |||||
| activeColor: config.ui.secendGreen, | |||||
| onChanged: (int? newValue) { | |||||
| meetingsState.selectLocation( | |||||
| newValue ?? null); | |||||
| }, | |||||
| ); | |||||
| }, | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| ExpansionTileCustom( | |||||
| title: AppLocalizations.of(context)! | |||||
| .meetingmanager, | |||||
| widgets: <Widget>[ | |||||
| ListView.builder( | |||||
| primary: false, | |||||
| physics: NeverScrollableScrollPhysics(), | |||||
| shrinkWrap: true, | |||||
| itemCount: | |||||
| globalState.meetingsManagerModel!.length, | |||||
| itemBuilder: | |||||
| (BuildContext context, int index) { | |||||
| final items = globalState | |||||
| .meetingsManagerModel![index]; | |||||
| return RadioListTile<int>( | |||||
| toggleable: true, | |||||
| groupValue: meetingsState | |||||
| .selectedManagersId, | |||||
| value: items.id ?? -1, | |||||
| title: Text( | |||||
| items.name ?? '', | |||||
| style: TextStyle( | |||||
| fontWeight: FontWeight.w100, | |||||
| fontSize: 14), | |||||
| maxLines: 1, | |||||
| overflow: TextOverflow.ellipsis, | |||||
| ), | |||||
| activeColor: config.ui.secendGreen, | |||||
| onChanged: (int? newValue) { | |||||
| meetingsState.selectManager( | |||||
| newValue ?? null); | |||||
| }, | |||||
| ); | |||||
| }, | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| ExpansionTileCustom( | |||||
| title: | |||||
| AppLocalizations.of(context)!.subject, | |||||
| widgets: <Widget>[ | |||||
| ListView.builder( | |||||
| primary: false, | |||||
| physics: NeverScrollableScrollPhysics(), | |||||
| shrinkWrap: true, | |||||
| itemCount: | |||||
| globalState.subjectsModel!.length, | |||||
| itemBuilder: | |||||
| (BuildContext context, int index) { | |||||
| final items = | |||||
| globalState.subjectsModel![index]; | |||||
| return RadioListTile<int>( | |||||
| toggleable: true, | |||||
| groupValue: | |||||
| meetingsState.selectedSubjectId, | |||||
| value: items.id ?? -1, | |||||
| title: Text( | |||||
| items.subject ?? '', | |||||
| maxLines: 1, | |||||
| overflow: TextOverflow.ellipsis, | |||||
| style: TextStyle( | |||||
| fontWeight: FontWeight.w100, | |||||
| fontSize: 14), | |||||
| ), | |||||
| activeColor: config.ui.secendGreen, | |||||
| onChanged: (int? newValue) { | |||||
| meetingsState.selectSubject( | |||||
| newValue ?? null); | |||||
| }, | |||||
| ); | |||||
| }, | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| SizedBox( | |||||
| height: 10, | |||||
| ), | |||||
| Divider(), | |||||
| Column( | |||||
| children: [ | |||||
| SizedBox( | |||||
| height: 250, | |||||
| child: ListView.builder( | |||||
| physics: | |||||
| NeverScrollableScrollPhysics(), | |||||
| shrinkWrap: true, | |||||
| primary: false, | |||||
| itemCount: globalState | |||||
| .meetingStatuses.length, | |||||
| itemBuilder: (BuildContext context, | |||||
| int index) { | |||||
| final items = globalState | |||||
| .meetingStatuses[index]; | |||||
| return RadioListTile<int>( | |||||
| toggleable: true, | |||||
| groupValue: meetingsState | |||||
| .selectedStatusId, | |||||
| value: items.id, | |||||
| title: Text( | |||||
| items.title, | |||||
| maxLines: 1, | |||||
| style: TextStyle( | |||||
| fontWeight: FontWeight.w100, | |||||
| fontSize: 14), | |||||
| overflow: TextOverflow.ellipsis, | |||||
| ), | |||||
| activeColor: | |||||
| config.ui.secendGreen, | |||||
| onChanged: (int? newValue) { | |||||
| meetingsState | |||||
| .selectStatusMeeting( | |||||
| newValue ?? null); | |||||
| }, | |||||
| ); | |||||
| }, | |||||
| ), | |||||
| ), | |||||
| ], | |||||
| ) | |||||
| ], | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| ), | |||||
| ], | |||||
| ); | |||||
| case Status.loading: | |||||
| return const LoadingWidget(); | |||||
| case Status.error: | |||||
| return CustomErrorWidget( | |||||
| onPressed: () async { | |||||
| // await meetingsState!.getAllFiltersItems(refresh: true); | |||||
| }, | |||||
| ); | |||||
| default: | |||||
| return Container(); | |||||
| } | |||||
| }, | |||||
| ); | |||||
| }); | |||||
| } | |||||
| } | |||||
| class LineButtomSheet extends StatelessWidget { | |||||
| const LineButtomSheet({ | |||||
| super.key, | |||||
| }); | |||||
| @override | |||||
| Widget build(BuildContext context) { | |||||
| return Container( | |||||
| margin: const EdgeInsets.only(top: 8.0), | |||||
| width: 30.0, | |||||
| height: 3.0, | |||||
| decoration: BoxDecoration( | |||||
| color: Colors.grey.shade400, | |||||
| borderRadius: BorderRadius.circular(24.0), | |||||
| ), | |||||
| ); | |||||
| } | |||||
| } | |||||
| class MeetingsStatus { | |||||
| int id; | |||||
| String title; | |||||
| MeetingsStatus({ | |||||
| required this.id, | |||||
| required this.title, | |||||
| }); | |||||
| } | |||||
| @@ -0,0 +1,296 @@ | |||||
| // ignore_for_file: public_member_api_docs, sort_constructors_first | |||||
| import 'package:flutter/material.dart'; | |||||
| import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | |||||
| import 'package:font_awesome_flutter/font_awesome_flutter.dart'; | |||||
| import 'package:go_router/go_router.dart'; | |||||
| import 'package:provider/provider.dart'; | |||||
| import 'package:qadirneyriz/config/config.dart'; | |||||
| import 'package:qadirneyriz/screens/meeting/diolog_meetings_filters.dart'; | |||||
| import 'package:qadirneyriz/screens/meeting/state.dart'; | |||||
| import 'package:qadirneyriz/utils/enums/status.dart'; | |||||
| import 'package:qadirneyriz/utils/tools/tools.dart'; | |||||
| import 'package:qadirneyriz/widgets/card_meeting.dart'; | |||||
| import 'package:qadirneyriz/widgets/custom_appbar.dart'; | |||||
| import 'package:qadirneyriz/widgets/empty_widget.dart'; | |||||
| import 'package:qadirneyriz/widgets/error_widget.dart'; | |||||
| import 'package:qadirneyriz/widgets/icon_button.dart'; | |||||
| import 'package:qadirneyriz/widgets/loading_widget.dart'; | |||||
| import 'package:qadirneyriz/widgets/today_widget.dart'; | |||||
| import 'package:shamsi_date/shamsi_date.dart'; | |||||
| class MeetingsScreen extends StatefulWidget { | |||||
| const MeetingsScreen({super.key}); | |||||
| @override | |||||
| State<MeetingsScreen> createState() => _MeetingsScreenState(); | |||||
| } | |||||
| class _MeetingsScreenState extends State<MeetingsScreen> { | |||||
| late ScrollController _scrollController; | |||||
| late MeetingsState meetingsState; | |||||
| @override | |||||
| void initState() { | |||||
| _scrollController = ScrollController(); | |||||
| _scrollController.addListener(_scrollListener); | |||||
| meetingsState = Provider.of<MeetingsState>(context, listen: false); | |||||
| Future.delayed(Duration.zero, () async { | |||||
| await meetingsState.getMeetings(); | |||||
| meetingsState.clearFilters(); | |||||
| }); | |||||
| super.initState(); | |||||
| } | |||||
| @override | |||||
| void dispose() { | |||||
| _scrollController.dispose(); | |||||
| super.dispose(); | |||||
| } | |||||
| _scrollListener() async { | |||||
| if (_scrollController.offset >= | |||||
| _scrollController.position.maxScrollExtent && | |||||
| !_scrollController.position.outOfRange) { | |||||
| if (!meetingsState.pageEndedMeetings) { | |||||
| await meetingsState.nextPageMeetings( | |||||
| toDate: meetingsState.toDate, | |||||
| fromDate: meetingsState.fromDate, | |||||
| location: meetingsState.selectedLocationId, | |||||
| subject: meetingsState.selectedSubjectId, | |||||
| meetingManager: meetingsState.selectedManagersId, | |||||
| meetingStatus: meetingsState.selectedStatusId); | |||||
| } | |||||
| } | |||||
| } | |||||
| @override | |||||
| Widget build(BuildContext context) { | |||||
| Jalali nowShamsi = Jalali.now(); | |||||
| String todayDateForShow = | |||||
| '${nowShamsi.day} ${Tools.getMonthName(nowShamsi.month)} ${nowShamsi.year}'; | |||||
| return Consumer<MeetingsState>( | |||||
| builder: (context, value, child) { | |||||
| return CustomScrollView( | |||||
| controller: _scrollController, | |||||
| slivers: <Widget>[ | |||||
| const CustomAppbar(), | |||||
| SliverToBoxAdapter( | |||||
| child: TodayWidget(formattedDate: todayDateForShow), | |||||
| ), | |||||
| SliverToBoxAdapter( | |||||
| child: Padding( | |||||
| padding: | |||||
| const EdgeInsets.symmetric(vertical: 30, horizontal: 15), | |||||
| child: Row( | |||||
| mainAxisAlignment: MainAxisAlignment.spaceBetween, | |||||
| crossAxisAlignment: CrossAxisAlignment.center, | |||||
| children: [ | |||||
| Text( | |||||
| style: const TextStyle(fontSize: 14), | |||||
| AppLocalizations.of(context)!.meetings, | |||||
| ), | |||||
| IconButtonCustom( | |||||
| iconColor: value.hasActiveFilters() | |||||
| ? Colors.white | |||||
| : config.ui.secendGreen, | |||||
| backColor: value.hasActiveFilters() | |||||
| ? config.ui.secendGreen | |||||
| : Colors.white, | |||||
| icon: FontAwesomeIcons.sliders, | |||||
| onTap: () { | |||||
| showModalBottomSheet( | |||||
| isScrollControlled: true, | |||||
| useSafeArea: true, | |||||
| context: context, | |||||
| builder: (context) { | |||||
| return DiologMeetingsFilters(); | |||||
| }, | |||||
| ); | |||||
| }, | |||||
| ) | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| ), | |||||
| meetingsList(value), | |||||
| (value.paginationMeetings == Status.ready || | |||||
| value.paginationMeetings == Status.empty) | |||||
| ? const SliverToBoxAdapter() | |||||
| : const SliverToBoxAdapter( | |||||
| child: Center( | |||||
| child: LoadingWidget( | |||||
| size: 10, | |||||
| ), | |||||
| ), | |||||
| ) | |||||
| ], | |||||
| ); | |||||
| }, | |||||
| ); | |||||
| } | |||||
| Widget meetingsList(MeetingsState state) { | |||||
| switch (state.statusMeetings) { | |||||
| case Status.ready: | |||||
| return SliverList.builder( | |||||
| itemBuilder: (context, index) { | |||||
| final items = state.meetingsModel!.data![index]; | |||||
| return Padding( | |||||
| padding: const EdgeInsets.all(8.0), | |||||
| child: CustomCardMeeting( | |||||
| titel: items.subject!.subject ?? '', | |||||
| fromTime: items.azHour ?? '', | |||||
| toTime: items.taHour ?? "", | |||||
| location: items.location!.address ?? '', | |||||
| date: items.dateJalali ?? '', | |||||
| cardId: items.id ?? 0, | |||||
| onSelectedMoreButton: (value) async { | |||||
| switch (value) { | |||||
| case 'edit': | |||||
| await context.pushNamed('meetingedit', | |||||
| pathParameters: {'id': items.id.toString()}); | |||||
| meetingsState.getMeetings(refresh: true); | |||||
| case 'confirm': | |||||
| acceptMeeting(state, context, items.id ?? -1); | |||||
| case 'cancel': | |||||
| cancelMeeting(state, context, items.id ?? -1); | |||||
| case 'report': | |||||
| await context.pushNamed( | |||||
| 'meetinsammary', | |||||
| extra: items, // `items` should be a Datum instance | |||||
| ); | |||||
| default: | |||||
| } | |||||
| }, | |||||
| itemBuilderMoreButton: (context) => [ | |||||
| PopupMenuItem( | |||||
| value: 'edit', | |||||
| child: Row( | |||||
| children: const [ | |||||
| Icon( | |||||
| Icons.edit, | |||||
| color: Colors.green, | |||||
| size: 17, | |||||
| ), | |||||
| SizedBox(width: 8), | |||||
| Text( | |||||
| 'ویرایش قرار', | |||||
| style: TextStyle(fontSize: 12), | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| PopupMenuItem( | |||||
| enabled: state.statusAcceptMeeting != Status.loading, | |||||
| value: 'confirm', | |||||
| child: Row( | |||||
| children: const [ | |||||
| Icon( | |||||
| Icons.check_circle, | |||||
| color: Colors.green, | |||||
| size: 17, | |||||
| ), | |||||
| SizedBox(width: 8), | |||||
| Text( | |||||
| 'تایید جلسه', | |||||
| style: TextStyle(fontSize: 12), | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| PopupMenuItem( | |||||
| enabled: state.statusCancelMeeting != Status.loading, | |||||
| value: 'cancel', | |||||
| child: Row( | |||||
| children: const [ | |||||
| Icon( | |||||
| Icons.cancel, | |||||
| color: Colors.green, | |||||
| size: 17, | |||||
| ), | |||||
| SizedBox(width: 8), | |||||
| Text( | |||||
| 'لغو قرار', | |||||
| style: TextStyle(fontSize: 12), | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| PopupMenuItem( | |||||
| value: 'report', | |||||
| child: Row( | |||||
| children: const [ | |||||
| Icon( | |||||
| Icons.receipt_long, | |||||
| color: Colors.green, | |||||
| size: 17, | |||||
| ), | |||||
| SizedBox(width: 8), | |||||
| Text( | |||||
| 'صورت جلسه', | |||||
| style: TextStyle(fontSize: 12), | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| ]), | |||||
| ); | |||||
| }, | |||||
| itemCount: state.meetingsModel!.data!.length, | |||||
| ); | |||||
| case Status.loading: | |||||
| return SliverFillRemaining(child: const LoadingWidget()); | |||||
| case Status.error: | |||||
| return SliverFillRemaining( | |||||
| child: CustomErrorWidget( | |||||
| onPressed: () async { | |||||
| await state.getMeetings(refresh: true); | |||||
| }, | |||||
| ), | |||||
| ); | |||||
| case Status.empty: | |||||
| return SliverFillRemaining(child: EmptyStateWidget()); | |||||
| default: | |||||
| return Container(); | |||||
| } | |||||
| } | |||||
| void cancelMeeting( | |||||
| MeetingsState state, BuildContext context, int cardId) async { | |||||
| final status = await state.cancelMeeting(id: cardId); | |||||
| if (status == Status.ready) { | |||||
| Tools.showCustomSnackBar( | |||||
| text: 'جلسه لغو شد!', | |||||
| isError: false, | |||||
| context, | |||||
| ); | |||||
| } else { | |||||
| Tools.showCustomSnackBar( | |||||
| text: 'مشکلی رخ داده است. دوباره تلاش کنید!', | |||||
| isError: true, | |||||
| context, | |||||
| ); | |||||
| } | |||||
| } | |||||
| void acceptMeeting( | |||||
| MeetingsState state, BuildContext context, int cardId) async { | |||||
| final status = await state.acceptMeeting(id: cardId); | |||||
| if (status == Status.ready) { | |||||
| Tools.showCustomSnackBar( | |||||
| text: 'جلسه تایید شد!', | |||||
| isError: false, | |||||
| context, | |||||
| ); | |||||
| } else { | |||||
| Tools.showCustomSnackBar( | |||||
| text: 'مشکلی رخ داده است. دوباره تلاش کنید!', | |||||
| isError: true, | |||||
| context, | |||||
| ); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,265 @@ | |||||
| import 'package:flutter/material.dart'; | |||||
| import 'package:qadirneyriz/models/meetings/meetings_model.dart'; | |||||
| import 'package:qadirneyriz/services/meetings/meetings.dart'; | |||||
| import 'package:qadirneyriz/utils/enums/status.dart'; | |||||
| class MeetingsState extends ChangeNotifier { | |||||
| // api meetings | |||||
| MeetingsApi meetingsApi = MeetingsApi(); | |||||
| // meetings list | |||||
| Status statusMeetings = Status.loading; | |||||
| Status paginationMeetings = Status.ready; | |||||
| MeetingsModel? meetingsModel; | |||||
| int pageMeetings = 1; | |||||
| int limitMeetings = 10; | |||||
| bool pageEndedMeetings = false; | |||||
| Future<Status> getMeetings( | |||||
| {bool refresh = false, | |||||
| String? fromDate, | |||||
| String? toDate, | |||||
| int? location, | |||||
| int? subject, | |||||
| int? meetingManager, | |||||
| int? meetingStatus}) async { | |||||
| if (refresh) { | |||||
| statusMeetings = Status.loading; | |||||
| notifyListeners(); | |||||
| } | |||||
| if (meetingsModel != null && meetingsModel!.data!.isNotEmpty && !refresh) { | |||||
| statusMeetings = Status.ready; | |||||
| notifyListeners(); | |||||
| pageMeetings = 1; | |||||
| pageEndedMeetings = false; | |||||
| paginationMeetings = Status.ready; | |||||
| meetingsModel = await meetingsApi.getMeetings( | |||||
| page: pageMeetings, | |||||
| count: limitMeetings, | |||||
| fromDate: fromDate, | |||||
| toDate: toDate, | |||||
| location: location, | |||||
| subject: subject, | |||||
| meetingManager: meetingManager, | |||||
| status: meetingStatus); | |||||
| } else { | |||||
| pageMeetings = 1; | |||||
| pageEndedMeetings = false; | |||||
| paginationMeetings = Status.ready; | |||||
| try { | |||||
| statusMeetings = Status.loading; | |||||
| notifyListeners(); | |||||
| meetingsModel = await meetingsApi.getMeetings( | |||||
| page: pageMeetings, | |||||
| count: limitMeetings, | |||||
| fromDate: fromDate, | |||||
| toDate: toDate, | |||||
| location: location, | |||||
| subject: subject, | |||||
| meetingManager: meetingManager, | |||||
| status: meetingStatus); | |||||
| if (meetingsModel != null && meetingsModel!.data!.isNotEmpty) { | |||||
| if (meetingsModel!.data!.isNotEmpty) { | |||||
| statusMeetings = Status.ready; | |||||
| } else if (!meetingsModel!.hasData() && meetingsModel == null) { | |||||
| statusMeetings = Status.empty; | |||||
| } else if (meetingsModel!.data!.length < limitMeetings) { | |||||
| pageEndedMeetings = true; | |||||
| statusMeetings = Status.empty; | |||||
| } | |||||
| } else { | |||||
| statusMeetings = Status.empty; | |||||
| } | |||||
| } catch (e) { | |||||
| statusMeetings = Status.error; | |||||
| } | |||||
| notifyListeners(); | |||||
| } | |||||
| notifyListeners(); | |||||
| print(statusMeetings); | |||||
| return statusMeetings; | |||||
| } | |||||
| Future<void> nextPageMeetings( | |||||
| {String? fromDate, | |||||
| String? toDate, | |||||
| int? location, | |||||
| int? subject, | |||||
| int? meetingManager, | |||||
| int? meetingStatus}) async { | |||||
| if (pageEndedMeetings == false && paginationMeetings == Status.ready) { | |||||
| paginationMeetings = Status.loading; | |||||
| notifyListeners(); | |||||
| int p = pageMeetings; | |||||
| pageMeetings = p + 1; | |||||
| try { | |||||
| final adsPaginationModel = await meetingsApi.getMeetings( | |||||
| page: pageMeetings, | |||||
| count: limitMeetings, | |||||
| fromDate: fromDate, | |||||
| toDate: toDate, | |||||
| location: location, | |||||
| subject: subject, | |||||
| meetingManager: meetingManager, | |||||
| status: meetingStatus); | |||||
| if (adsPaginationModel.hasData()) { | |||||
| meetingsModel!.data!.addAll(adsPaginationModel.data!); | |||||
| if (adsPaginationModel.data!.length < limitMeetings) { | |||||
| pageEndedMeetings = true; | |||||
| paginationMeetings = Status.empty; | |||||
| } else { | |||||
| paginationMeetings = Status.ready; | |||||
| } | |||||
| } else if (!adsPaginationModel.hasData()) { | |||||
| pageEndedMeetings = true; | |||||
| paginationMeetings = Status.empty; | |||||
| } | |||||
| } catch (e) { | |||||
| pageEndedMeetings = true; | |||||
| paginationMeetings = Status.empty; | |||||
| } | |||||
| notifyListeners(); | |||||
| } | |||||
| } | |||||
| // set date for filters | |||||
| String fromDate = ''; | |||||
| String toDate = ''; | |||||
| void setFromDates(String? newFromDate) { | |||||
| fromDate = newFromDate ?? ''; | |||||
| notifyListeners(); | |||||
| } | |||||
| void setToDates(String? newToDate) { | |||||
| toDate = newToDate ?? ''; | |||||
| notifyListeners(); | |||||
| } | |||||
| // clear filters | |||||
| void clearFilters() { | |||||
| selectedLocationId = null; | |||||
| selectedManagersId = null; | |||||
| selectedStatusId = null; | |||||
| selectedSubjectId = null; | |||||
| fromDate = ''; | |||||
| toDate = ''; | |||||
| notifyListeners(); | |||||
| } | |||||
| // is filter Not empty | |||||
| bool hasActiveFilters() { | |||||
| return selectedLocationId != null || | |||||
| selectedManagersId != null || | |||||
| selectedStatusId != null || | |||||
| selectedSubjectId != null || | |||||
| fromDate.isNotEmpty || | |||||
| toDate.isNotEmpty; | |||||
| } | |||||
| // get filters location meetings | |||||
| int? selectedLocationId; | |||||
| void selectLocation(int? locationId) { | |||||
| selectedLocationId = locationId; | |||||
| notifyListeners(); | |||||
| } | |||||
| // get filters subjects meetings | |||||
| int? selectedSubjectId; | |||||
| void selectSubject(int? subjectId) { | |||||
| selectedSubjectId = subjectId; | |||||
| notifyListeners(); | |||||
| } | |||||
| // get filters meeting managers | |||||
| int? selectedManagersId; | |||||
| void selectManager(int? managerId) { | |||||
| selectedManagersId = managerId; | |||||
| notifyListeners(); | |||||
| } | |||||
| // all meeting status filters | |||||
| int? selectedStatusId; | |||||
| void selectStatusMeeting(int? statusId) { | |||||
| selectedStatusId = statusId; | |||||
| notifyListeners(); | |||||
| } | |||||
| // cancel meeting | |||||
| Status statusCancelMeeting = Status.empty; | |||||
| String? messageCancelMeeting; | |||||
| Map? errorsCancelMeeting; | |||||
| Future<Status> cancelMeeting({ | |||||
| required int id, | |||||
| }) async { | |||||
| statusCancelMeeting = Status.loading; | |||||
| notifyListeners(); | |||||
| try { | |||||
| final result = await meetingsApi.cancelMeetingApi( | |||||
| id: id, | |||||
| ); | |||||
| if (result.isOk) { | |||||
| statusCancelMeeting = Status.ready; | |||||
| messageCancelMeeting = result.message; | |||||
| } else if (result.isOk == false) { | |||||
| print(result.isOk); | |||||
| errorsCancelMeeting = result.errors; | |||||
| messageCancelMeeting = result.message; | |||||
| statusCancelMeeting = Status.error; | |||||
| } else { | |||||
| statusCancelMeeting = Status.error; | |||||
| } | |||||
| notifyListeners(); | |||||
| } catch (e) { | |||||
| statusCancelMeeting = Status.error; | |||||
| print(e); | |||||
| } | |||||
| notifyListeners(); | |||||
| print(statusCancelMeeting); | |||||
| return statusCancelMeeting; | |||||
| } | |||||
| // accept meeting | |||||
| Status statusAcceptMeeting = Status.empty; | |||||
| String? messageAcceptMeeting; | |||||
| Map? errorsAcceptMeeting; | |||||
| Future<Status> acceptMeeting({ | |||||
| required int id, | |||||
| }) async { | |||||
| statusAcceptMeeting = Status.loading; | |||||
| notifyListeners(); | |||||
| try { | |||||
| final result = await meetingsApi.acceptMeetingApi( | |||||
| id: id, | |||||
| ); | |||||
| if (result.isOk) { | |||||
| statusAcceptMeeting = Status.ready; | |||||
| messageAcceptMeeting = result.message; | |||||
| } else if (result.isOk == false) { | |||||
| print(result.isOk); | |||||
| errorsAcceptMeeting = result.errors; | |||||
| messageAcceptMeeting = result.message; | |||||
| statusAcceptMeeting = Status.error; | |||||
| } else { | |||||
| statusAcceptMeeting = Status.error; | |||||
| } | |||||
| notifyListeners(); | |||||
| } catch (e) { | |||||
| statusAcceptMeeting = Status.error; | |||||
| print(e); | |||||
| } | |||||
| notifyListeners(); | |||||
| print(statusAcceptMeeting); | |||||
| return statusAcceptMeeting; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,106 @@ | |||||
| import 'package:flutter/material.dart'; | |||||
| import 'package:go_router/go_router.dart'; | |||||
| import 'package:provider/provider.dart'; | |||||
| import 'package:qadirneyriz/global_state/global_state.dart'; | |||||
| import 'package:qadirneyriz/utils/enums/status.dart'; | |||||
| import 'package:qadirneyriz/utils/tools/tools.dart'; | |||||
| import 'package:qadirneyriz/widgets/custom_button.dart'; | |||||
| import 'package:qadirneyriz/widgets/custom_textfield.dart'; | |||||
| import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | |||||
| class AddLocationDiolog extends StatelessWidget { | |||||
| AddLocationDiolog({ | |||||
| super.key, | |||||
| }); | |||||
| final TextEditingController addressController = TextEditingController(); | |||||
| @override | |||||
| Widget build(BuildContext context) { | |||||
| return Consumer<GlobalState>( | |||||
| builder: (context, value, child) { | |||||
| return Dialog( | |||||
| child: Padding( | |||||
| padding: const EdgeInsets.all(20.0), | |||||
| child: Column( | |||||
| mainAxisSize: MainAxisSize.min, // برای اندازهگیری درست دیالوگ | |||||
| children: [ | |||||
| Text('آدرس جدید'), | |||||
| CustomTextField( | |||||
| label: 'آدرس', | |||||
| hintText: '', | |||||
| textEditingController: addressController, | |||||
| textInputType: TextInputType.text), | |||||
| SizedBox( | |||||
| height: 20, | |||||
| ), | |||||
| submit(value, context), | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| ); | |||||
| }, | |||||
| ); | |||||
| } | |||||
| CustomButton submit(GlobalState state, BuildContext context) { | |||||
| switch (state.statusAddNewAddress) { | |||||
| case Status.loading: | |||||
| return CustomButton( | |||||
| hieght: 40, | |||||
| width: double.infinity, | |||||
| text: AppLocalizations.of(context)!.loading, | |||||
| fontSize: 13, | |||||
| onPressed: null, | |||||
| topRightRadius: 10, | |||||
| topLeftRadius: 10, | |||||
| bottomLeftRadius: 10, | |||||
| bottomRightRadius: 10, | |||||
| ); | |||||
| default: | |||||
| return CustomButton( | |||||
| hieght: 40, | |||||
| width: double.infinity, | |||||
| text: 'اظافه کردن', | |||||
| fontSize: 13, | |||||
| onPressed: () async { | |||||
| if (addressController.text != '') { | |||||
| // call add new subject | |||||
| final status = | |||||
| await state.addNewAddress(address: addressController.text); | |||||
| if (status == Status.ready) { | |||||
| // call refrresh subjects | |||||
| await state.getLocations(refresh: true); | |||||
| Tools.showCustomSnackBar( | |||||
| text: 'آدرس اظافه شد!', | |||||
| isError: false, | |||||
| context, | |||||
| ); | |||||
| context.pop(); | |||||
| } else { | |||||
| Tools.showCustomSnackBar( | |||||
| text: state.errorsAddNewAddress == null | |||||
| ? state.messageAddNewAddress ?? | |||||
| AppLocalizations.of(context)!.haserror | |||||
| : Tools.combineErrorMessages( | |||||
| state.errorsAddNewAddress ?? {}), | |||||
| isError: true, | |||||
| context, | |||||
| ); | |||||
| } | |||||
| } else { | |||||
| Tools.showCustomSnackBar( | |||||
| text: 'آدرس وارد کنید!', | |||||
| isError: true, | |||||
| context, | |||||
| ); | |||||
| } | |||||
| }, | |||||
| topRightRadius: 10, | |||||
| topLeftRadius: 10, | |||||
| bottomLeftRadius: 10, | |||||
| bottomRightRadius: 10, | |||||
| ); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,106 @@ | |||||
| import 'package:flutter/material.dart'; | |||||
| import 'package:go_router/go_router.dart'; | |||||
| import 'package:provider/provider.dart'; | |||||
| import 'package:qadirneyriz/global_state/global_state.dart'; | |||||
| import 'package:qadirneyriz/utils/enums/status.dart'; | |||||
| import 'package:qadirneyriz/utils/tools/tools.dart'; | |||||
| import 'package:qadirneyriz/widgets/custom_button.dart'; | |||||
| import 'package:qadirneyriz/widgets/custom_textfield.dart'; | |||||
| import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | |||||
| class AddSubjectDiolog extends StatelessWidget { | |||||
| AddSubjectDiolog({ | |||||
| super.key, | |||||
| }); | |||||
| final TextEditingController subjectController = TextEditingController(); | |||||
| @override | |||||
| Widget build(BuildContext context) { | |||||
| return Consumer<GlobalState>( | |||||
| builder: (context, value, child) { | |||||
| return Dialog( | |||||
| child: Padding( | |||||
| padding: const EdgeInsets.all(20.0), | |||||
| child: Column( | |||||
| mainAxisSize: MainAxisSize.min, // برای اندازهگیری درست دیالوگ | |||||
| children: [ | |||||
| Text('موضوع جدید'), | |||||
| CustomTextField( | |||||
| label: 'موضوع', | |||||
| hintText: '', | |||||
| textEditingController: subjectController, | |||||
| textInputType: TextInputType.text), | |||||
| SizedBox( | |||||
| height: 20, | |||||
| ), | |||||
| submit(value, context), | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| ); | |||||
| }, | |||||
| ); | |||||
| } | |||||
| CustomButton submit(GlobalState state, BuildContext context) { | |||||
| switch (state.statusAddNewSubject) { | |||||
| case Status.loading: | |||||
| return CustomButton( | |||||
| hieght: 40, | |||||
| width: double.infinity, | |||||
| text: AppLocalizations.of(context)!.loading, | |||||
| fontSize: 13, | |||||
| onPressed: null, | |||||
| topRightRadius: 10, | |||||
| topLeftRadius: 10, | |||||
| bottomLeftRadius: 10, | |||||
| bottomRightRadius: 10, | |||||
| ); | |||||
| default: | |||||
| return CustomButton( | |||||
| hieght: 40, | |||||
| width: double.infinity, | |||||
| text: 'اظافه کردن', | |||||
| fontSize: 13, | |||||
| onPressed: () async { | |||||
| if (subjectController.text != '') { | |||||
| // call add new subject | |||||
| final status = | |||||
| await state.addNewSubject(subject: subjectController.text); | |||||
| if (status == Status.ready) { | |||||
| // call refrresh subjects | |||||
| await state.getSubjects(refresh: true); | |||||
| Tools.showCustomSnackBar( | |||||
| text: 'موضوع اظافه شد!', | |||||
| isError: false, | |||||
| context, | |||||
| ); | |||||
| context.pop(); | |||||
| } else { | |||||
| Tools.showCustomSnackBar( | |||||
| text: state.errorsAddNewSubject == null | |||||
| ? state.messageAddNewSubject ?? | |||||
| AppLocalizations.of(context)!.haserror | |||||
| : Tools.combineErrorMessages( | |||||
| state.errorsAddNewSubject ?? {}), | |||||
| isError: true, | |||||
| context, | |||||
| ); | |||||
| } | |||||
| } else { | |||||
| Tools.showCustomSnackBar( | |||||
| text: 'موضوع وارد کنید!', | |||||
| isError: true, | |||||
| context, | |||||
| ); | |||||
| } | |||||
| }, | |||||
| topRightRadius: 10, | |||||
| topLeftRadius: 10, | |||||
| bottomLeftRadius: 10, | |||||
| bottomRightRadius: 10, | |||||
| ); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,202 @@ | |||||
| // ignore_for_file: public_member_api_docs, sort_constructors_first | |||||
| import 'package:flutter/material.dart'; | |||||
| import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | |||||
| import 'package:go_router/go_router.dart'; | |||||
| import 'package:provider/provider.dart'; | |||||
| import 'package:qadirneyriz/global_state/global_state.dart'; | |||||
| import 'package:qadirneyriz/screens/meeting_edit/screen.dart'; | |||||
| import 'package:qadirneyriz/utils/enums/status.dart'; | |||||
| import 'package:qadirneyriz/utils/tools/tools.dart'; | |||||
| import 'package:qadirneyriz/widgets/ExpansionTileCustom.dart'; | |||||
| import 'package:qadirneyriz/widgets/custom_button.dart'; | |||||
| import 'package:qadirneyriz/widgets/custom_textfield.dart'; | |||||
| class AddUserDiolog extends StatefulWidget { | |||||
| AddUserDiolog({ | |||||
| super.key, | |||||
| }); | |||||
| @override | |||||
| State<AddUserDiolog> createState() => _AddUserDiologState(); | |||||
| } | |||||
| class _AddUserDiologState extends State<AddUserDiolog> { | |||||
| final TextEditingController nameController = TextEditingController(); | |||||
| final TextEditingController mobileController = TextEditingController(); | |||||
| final TextEditingController passwordController = TextEditingController(); | |||||
| int? selectedRole; | |||||
| final List<MemberRole> roles = [ | |||||
| MemberRole(roleId: 1, roleName: 'کاربر معمولی'), | |||||
| MemberRole(roleId: 2, roleName: 'اپراتور'), | |||||
| ]; | |||||
| @override | |||||
| Widget build(BuildContext context) { | |||||
| return Consumer<GlobalState>( | |||||
| builder: (context, value, child) { | |||||
| return Dialog( | |||||
| child: Padding( | |||||
| padding: const EdgeInsets.all(20.0), | |||||
| child: SingleChildScrollView( | |||||
| child: Column( | |||||
| mainAxisSize: MainAxisSize.min, // برای اندازهگیری درست دیالوگ | |||||
| children: [ | |||||
| Text('عضو جدید'), | |||||
| CustomTextField( | |||||
| label: '', | |||||
| hintText: 'نام و نام خانوادگی', | |||||
| paddingVertical: 0, | |||||
| textEditingController: nameController, | |||||
| textInputType: TextInputType.text), | |||||
| CustomTextField( | |||||
| label: '', | |||||
| paddingVertical: 0, | |||||
| hintText: 'شماره موبایل', | |||||
| textEditingController: mobileController, | |||||
| textInputType: TextInputType.phone), | |||||
| CustomTextField( | |||||
| label: '', | |||||
| paddingVertical: 0, | |||||
| hintText: 'رمز عبور', | |||||
| isPass: true, | |||||
| textEditingController: passwordController, | |||||
| textInputType: TextInputType.visiblePassword), | |||||
| Padding( | |||||
| padding: const EdgeInsets.symmetric(horizontal: 20), | |||||
| child: ExpansionTileCustom( | |||||
| isForm: true, | |||||
| subTitile: '', | |||||
| title: 'نقش کاربر', | |||||
| widgets: <Widget>[ | |||||
| Column( | |||||
| children: roles.map((role) { | |||||
| bool isSelected = selectedRole == role.roleId; | |||||
| return ItemInTile( | |||||
| backColor: | |||||
| isSelected ? Color(0xff06CF64) : Colors.white, | |||||
| textColor: | |||||
| isSelected ? Colors.white : Colors.black, | |||||
| text: role.roleName, | |||||
| hasIcon: false, | |||||
| onTap: () { | |||||
| setState(() { | |||||
| selectedRole = role.roleId; | |||||
| }); | |||||
| }, | |||||
| ); | |||||
| }).toList(), | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| SizedBox( | |||||
| height: 60, | |||||
| ), | |||||
| submit(value, context), | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| ), | |||||
| ); | |||||
| }, | |||||
| ); | |||||
| } | |||||
| CustomButton submit(GlobalState state, BuildContext context) { | |||||
| switch (state.statusAddNewUser) { | |||||
| case Status.loading: | |||||
| return CustomButton( | |||||
| hieght: 40, | |||||
| width: double.infinity, | |||||
| text: AppLocalizations.of(context)!.loading, | |||||
| fontSize: 13, | |||||
| onPressed: null, | |||||
| topRightRadius: 10, | |||||
| topLeftRadius: 10, | |||||
| bottomLeftRadius: 10, | |||||
| bottomRightRadius: 10, | |||||
| ); | |||||
| default: | |||||
| return CustomButton( | |||||
| hieght: 40, | |||||
| width: double.infinity, | |||||
| text: 'اظافه کردن', | |||||
| fontSize: 13, | |||||
| onPressed: () async { | |||||
| if (nameController.text == '') { | |||||
| // call add new subject | |||||
| Tools.showCustomSnackBar( | |||||
| text: 'اسم وارد کنید!', | |||||
| isError: true, | |||||
| context, | |||||
| ); | |||||
| } else if (mobileController.text == '') { | |||||
| Tools.showCustomSnackBar( | |||||
| text: 'موبایل وارد کنید!', | |||||
| isError: true, | |||||
| context, | |||||
| ); | |||||
| } else if (passwordController.text == '') { | |||||
| Tools.showCustomSnackBar( | |||||
| text: 'پسورد وارد کنید!', | |||||
| isError: true, | |||||
| context, | |||||
| ); | |||||
| } else if (selectedRole == null) { | |||||
| Tools.showCustomSnackBar( | |||||
| text: 'نقش کاربر وارد کنید!', | |||||
| isError: true, | |||||
| context, | |||||
| ); | |||||
| } else { | |||||
| final status = await state.addNewUser( | |||||
| name: nameController.text, | |||||
| mobile: mobileController.text, | |||||
| role: selectedRole!, | |||||
| password: passwordController.text); | |||||
| if (status == Status.ready) { | |||||
| // call refrresh users | |||||
| await state.getUsers(refresh: true); | |||||
| Tools.showCustomSnackBar( | |||||
| text: 'کاربر اظافه شد!', | |||||
| isError: false, | |||||
| context, | |||||
| ); | |||||
| context.pop(); | |||||
| } else { | |||||
| Tools.showCustomSnackBar( | |||||
| text: state.errorsAddNewUser == null | |||||
| ? state.messageAddNewUser ?? | |||||
| AppLocalizations.of(context)!.haserror | |||||
| : Tools.combineErrorMessages( | |||||
| state.errorsAddNewUser ?? {}), | |||||
| isError: true, | |||||
| context, | |||||
| ); | |||||
| } | |||||
| } | |||||
| }, | |||||
| topRightRadius: 10, | |||||
| topLeftRadius: 10, | |||||
| bottomLeftRadius: 10, | |||||
| bottomRightRadius: 10, | |||||
| ); | |||||
| } | |||||
| } | |||||
| } | |||||
| class MemberRole { | |||||
| final int roleId; | |||||
| final String roleName; | |||||
| MemberRole({ | |||||
| required this.roleId, | |||||
| required this.roleName, | |||||
| }); | |||||
| } | |||||
| @@ -0,0 +1,518 @@ | |||||
| // ignore_for_file: public_member_api_docs, sort_constructors_first | |||||
| import 'package:flutter/material.dart'; | |||||
| import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | |||||
| import 'package:go_router/go_router.dart'; | |||||
| import 'package:provider/provider.dart'; | |||||
| import 'package:qadirneyriz/global_state/global_state.dart'; | |||||
| import 'package:qadirneyriz/screens/meeting_edit/diolog_add_location.dart'; | |||||
| import 'package:qadirneyriz/screens/meeting_edit/diolog_add_subject.dart'; | |||||
| import 'package:qadirneyriz/screens/meeting_edit/diolog_add_user.dart'; | |||||
| import 'package:qadirneyriz/screens/meeting_edit/state.dart'; | |||||
| import 'package:qadirneyriz/utils/enums/status.dart'; | |||||
| import 'package:qadirneyriz/utils/tools/tools.dart'; | |||||
| import 'package:qadirneyriz/widgets/ExpansionTileCustom.dart'; | |||||
| import 'package:qadirneyriz/widgets/custom_appbar.dart'; | |||||
| import 'package:qadirneyriz/widgets/custom_button.dart'; | |||||
| import 'package:qadirneyriz/widgets/ink_warpper.dart'; | |||||
| import 'package:qadirneyriz/widgets/loading_widget.dart'; | |||||
| import 'package:qadirneyriz/widgets/picker.dart'; | |||||
| class MeetingEditScreen extends StatefulWidget { | |||||
| final int id; | |||||
| const MeetingEditScreen({ | |||||
| Key? key, | |||||
| required this.id, | |||||
| }) : super(key: key); | |||||
| @override | |||||
| State<MeetingEditScreen> createState() => _MeetingEditScreenState(); | |||||
| } | |||||
| class _MeetingEditScreenState extends State<MeetingEditScreen> { | |||||
| final _formKey = GlobalKey<FormState>(); // Key for form validation | |||||
| // all states we have | |||||
| late MeetingEditState meetingEditState; | |||||
| late GlobalState globalState; | |||||
| @override | |||||
| void initState() { | |||||
| super.initState(); | |||||
| //set states | |||||
| meetingEditState = Provider.of<MeetingEditState>(context, listen: false); | |||||
| globalState = Provider.of<GlobalState>(context, listen: false); | |||||
| Future.delayed(Duration.zero, () async { | |||||
| // get items | |||||
| await meetingEditState.getOneMeeting(id: widget.id); | |||||
| await globalState.getAllFiltersItems(); | |||||
| // set variables | |||||
| meetingEditState.setAllVariablesAtStart(id: widget.id); | |||||
| }); | |||||
| } | |||||
| @override | |||||
| Widget build(BuildContext context) { | |||||
| return Scaffold( | |||||
| body: Consumer2<MeetingEditState, GlobalState>( | |||||
| builder: (context, meetingEditState, globalState, child) { | |||||
| return CustomScrollView( | |||||
| slivers: <Widget>[ | |||||
| CustomAppbar(title: AppLocalizations.of(context)!.editmeeting), | |||||
| SliverFillRemaining( | |||||
| child: content(context, meetingEditState, globalState)), | |||||
| ], | |||||
| ); | |||||
| }, | |||||
| ), | |||||
| ); | |||||
| } | |||||
| Widget content(BuildContext context, MeetingEditState meetingEditState, | |||||
| GlobalState globalState) { | |||||
| if (meetingEditState.oneMeetingStatus[widget.id] == Status.ready && | |||||
| globalState.allFiltersStatus == Status.ready) { | |||||
| final itemInOneMeeting = meetingEditState.oneMeetingModel![widget.id]!; | |||||
| return Padding( | |||||
| // This is now wrapped inside SliverToBoxAdapter | |||||
| padding: const EdgeInsets.all(16.0), | |||||
| child: Form( | |||||
| key: _formKey, | |||||
| child: SingleChildScrollView( | |||||
| child: Column( | |||||
| crossAxisAlignment: CrossAxisAlignment.start, | |||||
| children: [ | |||||
| // subject ExpansionTile | |||||
| Padding( | |||||
| padding: const EdgeInsets.symmetric(vertical: 8.0), | |||||
| child: ExpansionTileCustom( | |||||
| isForm: true, | |||||
| subTitile: AppLocalizations.of(context)!.meetingsubject, | |||||
| title: meetingEditState.selectedSubject.id != null | |||||
| ? meetingEditState.selectedSubject.text ?? '' | |||||
| : meetingEditState.oneMeetingModel![widget.id]!.subject! | |||||
| .subject ?? | |||||
| '', | |||||
| widgets: <Widget>[ | |||||
| ItemInTile( | |||||
| text: 'عضو جدید', | |||||
| onTap: () async { | |||||
| await showDialog( | |||||
| context: context, // این باید کانتکست فعلی باشد | |||||
| builder: (BuildContext context) { | |||||
| return AddSubjectDiolog(); | |||||
| }, | |||||
| ); | |||||
| }, | |||||
| hasIcon: true, | |||||
| backColor: Colors.white, | |||||
| textColor: Colors.black.withOpacity(.5), | |||||
| ), | |||||
| Column( | |||||
| children: globalState.subjectsModel!.map((subject) { | |||||
| bool isSelected = | |||||
| meetingEditState.selectedSubject.id == subject.id; | |||||
| return ItemInTile( | |||||
| backColor: | |||||
| isSelected ? Color(0xff06CF64) : Colors.white, | |||||
| textColor: isSelected ? Colors.white : Colors.black, | |||||
| text: subject.subject ?? '', | |||||
| hasIcon: false, | |||||
| onTap: () { | |||||
| setState(() { | |||||
| meetingEditState.selectedSubject = ItemSelected( | |||||
| text: subject.subject ?? '', | |||||
| id: subject.id ?? | |||||
| 0); // Update selected location | |||||
| }); | |||||
| }, | |||||
| ); | |||||
| }).toList(), | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| // Date Picker | |||||
| Padding( | |||||
| padding: const EdgeInsets.symmetric(vertical: 8.0), | |||||
| child: PickerCustom( | |||||
| showDate: meetingEditState.fromDate != null | |||||
| ? meetingEditState.fromDate ?? '' | |||||
| : itemInOneMeeting.dateJalali ?? '', | |||||
| onTap: () { | |||||
| showDialog( | |||||
| context: context, | |||||
| builder: (context) { | |||||
| return Dialog( | |||||
| child: Tools.shamsiDateCalendarWidget( | |||||
| context, | |||||
| (newDate) { | |||||
| String fromDateString = | |||||
| '${newDate.year}/${newDate.month}/${newDate.day}'; | |||||
| meetingEditState.setFromDate( | |||||
| fromDateString); // Update the selected date | |||||
| }, | |||||
| ), | |||||
| ); | |||||
| }, | |||||
| ); | |||||
| }, | |||||
| isForm: true, | |||||
| title: AppLocalizations.of(context)!.date, | |||||
| ), | |||||
| ), | |||||
| // From and To time Range Pickers | |||||
| Padding( | |||||
| padding: const EdgeInsets.symmetric(vertical: 15.0), | |||||
| child: Row( | |||||
| mainAxisAlignment: MainAxisAlignment.spaceBetween, | |||||
| crossAxisAlignment: CrossAxisAlignment.end, | |||||
| children: [ | |||||
| PickerCustom( | |||||
| showDate: meetingEditState.selectedStartTime != null | |||||
| ? Tools.formatTime( | |||||
| meetingEditState.selectedStartTime!.hour, | |||||
| meetingEditState.selectedStartTime!.minute) | |||||
| : itemInOneMeeting.azHour ?? '', | |||||
| onTap: () async { | |||||
| TimeOfDay? picked = await showTimePicker( | |||||
| context: context, | |||||
| initialTime: meetingEditState.selectedStartTime!, | |||||
| ); | |||||
| if (picked != null && | |||||
| picked != meetingEditState.selectedStartTime) | |||||
| setState(() { | |||||
| meetingEditState.selectedStartTime = picked; | |||||
| }); | |||||
| }, | |||||
| isForm: true, | |||||
| icon: Icons.access_time_outlined, | |||||
| title: AppLocalizations.of(context)!.clock, | |||||
| ), | |||||
| Text(AppLocalizations.of(context)!.to), | |||||
| PickerCustom( | |||||
| showDate: meetingEditState.selectedEndTime != null | |||||
| ? Tools.formatTime( | |||||
| meetingEditState.selectedEndTime!.hour, | |||||
| meetingEditState.selectedEndTime!.minute) | |||||
| : itemInOneMeeting.taHour ?? '', | |||||
| isForm: true, | |||||
| icon: Icons.access_time_outlined, | |||||
| onTap: () async { | |||||
| TimeOfDay? picked = await showTimePicker( | |||||
| context: context, | |||||
| initialTime: meetingEditState.selectedEndTime!, | |||||
| ); | |||||
| if (picked != null && | |||||
| picked != meetingEditState.selectedEndTime) | |||||
| setState(() { | |||||
| meetingEditState.selectedEndTime = picked; | |||||
| }); | |||||
| }, | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| // Location ExpansionTile | |||||
| Padding( | |||||
| padding: const EdgeInsets.symmetric(vertical: 8.0), | |||||
| child: ExpansionTileCustom( | |||||
| isForm: true, | |||||
| subTitile: AppLocalizations.of(context)!.location, | |||||
| title: meetingEditState.selectedLocation.id != null | |||||
| ? meetingEditState.selectedLocation.text ?? '' | |||||
| : itemInOneMeeting.location!.address ?? '', | |||||
| widgets: <Widget>[ | |||||
| ItemInTile( | |||||
| text: 'مکان جدید', | |||||
| onTap: () async { | |||||
| await showDialog( | |||||
| context: context, // این باید کانتکست فعلی باشد | |||||
| builder: (BuildContext context) { | |||||
| return AddLocationDiolog(); | |||||
| }, | |||||
| ); | |||||
| }, | |||||
| hasIcon: true, | |||||
| backColor: Colors.white, | |||||
| textColor: Colors.black.withOpacity(.5), | |||||
| ), | |||||
| Column( | |||||
| children: globalState.locationsModel!.map((location) { | |||||
| bool isSelected = | |||||
| meetingEditState.selectedLocation.id == | |||||
| location.id; | |||||
| return ItemInTile( | |||||
| backColor: | |||||
| isSelected ? Color(0xff06CF64) : Colors.white, | |||||
| textColor: isSelected ? Colors.white : Colors.black, | |||||
| text: location.address ?? '', | |||||
| hasIcon: false, | |||||
| onTap: () { | |||||
| setState(() { | |||||
| meetingEditState.selectedLocation = | |||||
| ItemSelected( | |||||
| text: location.address, | |||||
| id: location | |||||
| .id); // Update selected location | |||||
| }); | |||||
| }, | |||||
| ); | |||||
| }).toList(), | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| // Another ExpansionTile for users | |||||
| Padding( | |||||
| padding: const EdgeInsets.symmetric(vertical: 8.0), | |||||
| child: ExpansionTileCustom( | |||||
| isForm: true, | |||||
| subTitile: AppLocalizations.of(context)!.users, | |||||
| title: AppLocalizations.of(context)!.selectusers, | |||||
| widgets: <Widget>[ | |||||
| ItemInTile( | |||||
| text: 'کاربر جدید', | |||||
| onTap: () async { | |||||
| await showDialog( | |||||
| context: context, // این باید کانتکست فعلی باشد | |||||
| builder: (BuildContext context) { | |||||
| return AddUserDiolog(); | |||||
| }, | |||||
| ); | |||||
| }, | |||||
| hasIcon: true, | |||||
| backColor: Colors.white, | |||||
| textColor: Colors.black.withOpacity(.5), | |||||
| ), | |||||
| Column( | |||||
| children: globalState.usersModel != null | |||||
| ? globalState.usersModel!.map((user) { | |||||
| bool isSelected = meetingEditState | |||||
| .selectedUsersItems | |||||
| .contains(user.id); | |||||
| return Container( | |||||
| margin: EdgeInsets.symmetric( | |||||
| vertical: 5.0, horizontal: 10), | |||||
| decoration: BoxDecoration( | |||||
| color: isSelected | |||||
| ? Color(0xff06CF64) | |||||
| : Colors.white, | |||||
| borderRadius: BorderRadius.circular(10), | |||||
| boxShadow: [ | |||||
| BoxShadow( | |||||
| color: Colors.black12, | |||||
| blurRadius: 8, | |||||
| offset: Offset(0, 4), | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| child: InkWrapper( | |||||
| onTap: () { | |||||
| setState(() { | |||||
| if (isSelected) { | |||||
| meetingEditState.selectedUsersItems | |||||
| .remove(user.id); | |||||
| } else { | |||||
| meetingEditState.selectedUsersItems | |||||
| .add(user.id ?? 0); | |||||
| } | |||||
| }); | |||||
| }, | |||||
| child: Padding( | |||||
| padding: const EdgeInsets.all(10.0), | |||||
| child: Row( | |||||
| children: [ | |||||
| Text( | |||||
| maxLines: 1, | |||||
| overflow: TextOverflow.ellipsis, | |||||
| user.name ?? '', | |||||
| style: TextStyle( | |||||
| fontSize: 12, | |||||
| color: isSelected | |||||
| ? Colors.white | |||||
| : Colors.black, | |||||
| ), | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| ), | |||||
| ); | |||||
| }).toList() | |||||
| : [], | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| // Final ExpansionTile if required | |||||
| Padding( | |||||
| padding: const EdgeInsets.symmetric(vertical: 10.0), | |||||
| child: ExpansionTileCustom( | |||||
| isForm: true, | |||||
| subTitile: AppLocalizations.of(context)!.meetingmanager, | |||||
| title: meetingEditState.selectedManager.id != null | |||||
| ? meetingEditState.selectedManager.text ?? '' | |||||
| : itemInOneMeeting.manager!.name ?? '', | |||||
| widgets: <Widget>[ | |||||
| Column( | |||||
| children: | |||||
| globalState.meetingsManagerModel!.map((manager) { | |||||
| bool isSelected = | |||||
| meetingEditState.selectedManager.id == manager.id; | |||||
| return ItemInTile( | |||||
| backColor: | |||||
| isSelected ? Color(0xff06CF64) : Colors.white, | |||||
| textColor: isSelected ? Colors.white : Colors.black, | |||||
| text: manager.name ?? '', | |||||
| hasIcon: false, | |||||
| onTap: () { | |||||
| setState(() { | |||||
| meetingEditState.selectedManager = ItemSelected( | |||||
| id: manager.id, | |||||
| text: manager | |||||
| .name); // Update selected manager | |||||
| }); | |||||
| }, | |||||
| ); | |||||
| }).toList(), | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| // Submit Button | |||||
| SizedBox( | |||||
| height: 60, | |||||
| ), | |||||
| submit(context) | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| ), | |||||
| ); | |||||
| } else if (meetingEditState.oneMeetingStatus[widget.id] == Status.loading || | |||||
| globalState.allFiltersStatus == Status.loading) { | |||||
| return const LoadingWidget(); | |||||
| } else { | |||||
| return Container(); | |||||
| } | |||||
| } | |||||
| CustomButton submit(BuildContext context) { | |||||
| switch (meetingEditState.statusEitMeeting) { | |||||
| case Status.loading: | |||||
| return CustomButton( | |||||
| width: double.infinity, | |||||
| hieght: 50, | |||||
| fontSize: 16, | |||||
| onPressed: null, | |||||
| text: AppLocalizations.of(context)!.loading); | |||||
| default: | |||||
| return CustomButton( | |||||
| width: double.infinity, | |||||
| hieght: 50, | |||||
| fontSize: 16, | |||||
| onPressed: () async { | |||||
| final status = await meetingEditState.editMeeting( | |||||
| id: widget.id, | |||||
| locationId: meetingEditState.selectedLocation.id ?? -1, | |||||
| subjectId: meetingEditState.selectedSubject.id ?? -1, | |||||
| managerId: meetingEditState.selectedManager.id ?? -1, | |||||
| fromHour: Tools.formatTime( | |||||
| meetingEditState.selectedStartTime!.hour, | |||||
| meetingEditState.selectedStartTime!.minute), | |||||
| toHour: Tools.formatTime( | |||||
| meetingEditState.selectedEndTime!.hour, | |||||
| meetingEditState.selectedEndTime!.minute), | |||||
| dateMeeting: meetingEditState.fromDate ?? '', | |||||
| members: meetingEditState.selectedUsersItems); | |||||
| if (status == Status.ready) { | |||||
| context.pop(); | |||||
| } else { | |||||
| Tools.showCustomSnackBar( | |||||
| text: meetingEditState.errorsEditMeeting == null | |||||
| ? meetingEditState.messageEditMeeting ?? | |||||
| AppLocalizations.of(context)!.haserror | |||||
| : Tools.combineErrorMessages( | |||||
| meetingEditState.errorsEditMeeting ?? {}), | |||||
| isError: true, | |||||
| context, | |||||
| ); | |||||
| } | |||||
| }, | |||||
| text: AppLocalizations.of(context)!.submit); | |||||
| } | |||||
| } | |||||
| } | |||||
| class ItemInTile extends StatelessWidget { | |||||
| final void Function()? onTap; | |||||
| final String text; | |||||
| final bool hasIcon; | |||||
| final Color backColor; | |||||
| final Color textColor; | |||||
| const ItemInTile({ | |||||
| Key? key, | |||||
| this.onTap, | |||||
| required this.text, | |||||
| required this.hasIcon, | |||||
| required this.backColor, | |||||
| required this.textColor, | |||||
| }) : super(key: key); | |||||
| @override | |||||
| Widget build(BuildContext context) { | |||||
| return Padding( | |||||
| padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5), | |||||
| child: InkWrapper( | |||||
| borderRadius: 10, | |||||
| onTap: onTap, | |||||
| child: Container( | |||||
| decoration: BoxDecoration(boxShadow: [ | |||||
| BoxShadow( | |||||
| color: Colors.black12, | |||||
| blurRadius: 8, | |||||
| offset: Offset(0, 4), | |||||
| ), | |||||
| ], color: backColor, borderRadius: BorderRadius.circular(10)), | |||||
| child: Padding( | |||||
| padding: const EdgeInsets.all(10.0), | |||||
| child: Row( | |||||
| mainAxisAlignment: MainAxisAlignment.spaceBetween, | |||||
| children: [ | |||||
| Expanded( | |||||
| child: Text( | |||||
| maxLines: 1, | |||||
| overflow: TextOverflow.ellipsis, | |||||
| text, | |||||
| style: TextStyle(color: textColor, fontSize: 12), | |||||
| ), | |||||
| ), | |||||
| if (hasIcon) | |||||
| Icon(Icons.add_circle_outline, | |||||
| color: Colors.black.withOpacity(.3)) | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| ), | |||||
| ), | |||||
| ); | |||||
| } | |||||
| } | |||||
| class ItemSelected { | |||||
| final String? text; | |||||
| final int? id; | |||||
| ItemSelected({ | |||||
| this.text, | |||||
| this.id, | |||||
| }); | |||||
| } | |||||
| @@ -0,0 +1,148 @@ | |||||
| import 'package:flutter/material.dart'; | |||||
| import 'package:qadirneyriz/models/meetings/one_meeting_model.dart'; | |||||
| import 'package:qadirneyriz/screens/meeting_edit/screen.dart'; | |||||
| import 'package:qadirneyriz/services/meetings/meetings.dart'; | |||||
| import 'package:qadirneyriz/utils/enums/status.dart'; | |||||
| class MeetingEditState extends ChangeNotifier { | |||||
| MeetingsApi meetingApi = MeetingsApi(); | |||||
| Map<int, Status> oneMeetingStatus = {}; | |||||
| Map<int, OneMeetingModel>? oneMeetingModel = {}; | |||||
| Future<Status> getOneMeeting({bool refresh = false, required int id}) async { | |||||
| oneMeetingStatus[id] = Status.loading; | |||||
| notifyListeners(); | |||||
| // Ensure the status map is initialized | |||||
| if (oneMeetingStatus[id] == null || refresh) { | |||||
| oneMeetingStatus[id] = Status.loading; | |||||
| notifyListeners(); | |||||
| } | |||||
| // Initialize the model map if it's null | |||||
| oneMeetingModel ??= {}; | |||||
| // If not refreshing and data exists, return the current state | |||||
| if (!refresh && oneMeetingModel![id] != null) { | |||||
| oneMeetingStatus[id] = Status.ready; | |||||
| notifyListeners(); | |||||
| return oneMeetingStatus[id]!; | |||||
| } | |||||
| // Otherwise, fetch new data from API | |||||
| try { | |||||
| oneMeetingModel![id] = await meetingApi.getOneMeeting(id: id); | |||||
| if (oneMeetingModel![id] != null) { | |||||
| oneMeetingStatus[id] = Status.ready; | |||||
| } else { | |||||
| oneMeetingStatus[id] = Status.empty; | |||||
| } | |||||
| } catch (e) { | |||||
| oneMeetingStatus[id] = Status.error; | |||||
| print(e); | |||||
| } | |||||
| notifyListeners(); | |||||
| return oneMeetingStatus[id]!; | |||||
| } | |||||
| // date | |||||
| String? fromDate; | |||||
| void setFromDate(String date) { | |||||
| fromDate = date; | |||||
| notifyListeners(); | |||||
| } | |||||
| // subject | |||||
| ItemSelected selectedSubject = ItemSelected(); | |||||
| // location | |||||
| ItemSelected selectedLocation = ItemSelected(); | |||||
| // manager | |||||
| ItemSelected selectedManager = ItemSelected(); | |||||
| //users | |||||
| List<int> selectedUsersItems = []; | |||||
| // time | |||||
| TimeOfDay? selectedStartTime; | |||||
| TimeOfDay? selectedEndTime; | |||||
| // function at start | |||||
| void setAllVariablesAtStart({required int id}) { | |||||
| if (oneMeetingStatus[id] == Status.ready) { | |||||
| final item = oneMeetingModel![id]!; | |||||
| selectedLocation = ItemSelected( | |||||
| id: item.locationsId ?? -1, text: item.location!.address ?? ''); | |||||
| selectedSubject = ItemSelected( | |||||
| text: item.subject!.subject ?? '', id: item.subject!.id ?? -1); | |||||
| selectedManager = ItemSelected( | |||||
| id: item.managerId ?? -1, text: item.manager!.name ?? ''); | |||||
| fromDate = item.dateJalali; | |||||
| String timeStart = item.azHour ?? ':'; | |||||
| List<String> timeParts = timeStart.split(':'); | |||||
| int hourStart = int.parse(timeParts[0]); | |||||
| int minuteStart = int.parse(timeParts[1]); | |||||
| selectedStartTime = TimeOfDay(hour: hourStart, minute: minuteStart); | |||||
| String timeEnd = item.taHour ?? ':'; | |||||
| List<String> timeEndParts = timeEnd.split(':'); | |||||
| int hourEnd = int.parse(timeEndParts[0]); | |||||
| int minuteEnd = int.parse(timeEndParts[1]); | |||||
| selectedEndTime = TimeOfDay(hour: hourEnd, minute: minuteEnd); | |||||
| // پر کردن لیست کاربران انتخاب شده | |||||
| selectedUsersItems = item.users!.map((user) => user.id ?? -1).toList(); | |||||
| } | |||||
| } | |||||
| // send edit meeting | |||||
| Status statusEitMeeting = Status.empty; | |||||
| String? messageEditMeeting; | |||||
| Map? errorsEditMeeting; | |||||
| Future<Status> editMeeting( | |||||
| {required int id, | |||||
| required int locationId, | |||||
| required int subjectId, | |||||
| required int managerId, | |||||
| required String fromHour, | |||||
| required String toHour, | |||||
| required String dateMeeting, | |||||
| required List<int> members}) async { | |||||
| statusEitMeeting = Status.loading; | |||||
| notifyListeners(); | |||||
| try { | |||||
| final result = await meetingApi.editMeetingApi( | |||||
| id: id, | |||||
| locationId: locationId, | |||||
| subjectId: subjectId, | |||||
| managerId: managerId, | |||||
| fromHour: fromHour, | |||||
| toHour: toHour, | |||||
| dateMeeting: dateMeeting, | |||||
| members: members); | |||||
| if (result.isOk) { | |||||
| statusEitMeeting = Status.ready; | |||||
| messageEditMeeting = result.message; | |||||
| } else if (result.isOk == false) { | |||||
| print(result.isOk); | |||||
| errorsEditMeeting = result.errors; | |||||
| messageEditMeeting = result.message; | |||||
| statusEitMeeting = Status.error; | |||||
| } else { | |||||
| statusEitMeeting = Status.error; | |||||
| } | |||||
| notifyListeners(); | |||||
| } catch (e) { | |||||
| statusEitMeeting = Status.error; | |||||
| print(e); | |||||
| } | |||||
| notifyListeners(); | |||||
| print(statusEitMeeting); | |||||
| return statusEitMeeting; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,329 @@ | |||||
| // ignore_for_file: public_member_api_docs, sort_constructors_first | |||||
| import 'package:file_picker/file_picker.dart'; | |||||
| import 'package:flutter/material.dart'; | |||||
| import 'package:provider/provider.dart'; | |||||
| import 'package:qadirneyriz/config/config.dart'; | |||||
| import 'package:qadirneyriz/models/meetings/meetings_model.dart'; | |||||
| import 'package:qadirneyriz/screens/meeting_summary/state.dart'; | |||||
| import 'package:qadirneyriz/utils/enums/status.dart'; | |||||
| import 'package:qadirneyriz/utils/tools/tools.dart'; | |||||
| import 'package:qadirneyriz/widgets/card_meeting.dart'; | |||||
| import 'package:qadirneyriz/widgets/custom_appbar.dart'; | |||||
| import 'package:qadirneyriz/widgets/custom_button.dart'; | |||||
| class MeetingSummaryScreen extends StatefulWidget { | |||||
| final Datum meetingItem; | |||||
| const MeetingSummaryScreen({ | |||||
| Key? key, | |||||
| required this.meetingItem, | |||||
| }) : super(key: key); | |||||
| @override | |||||
| State<MeetingSummaryScreen> createState() => _MeetingSummaryScreenState(); | |||||
| } | |||||
| class _MeetingSummaryScreenState extends State<MeetingSummaryScreen> { | |||||
| late TextEditingController _textControllerDescription; | |||||
| @override | |||||
| void initState() { | |||||
| super.initState(); | |||||
| _textControllerDescription = TextEditingController(); | |||||
| } | |||||
| @override | |||||
| void dispose() { | |||||
| _textControllerDescription.dispose(); | |||||
| super.dispose(); | |||||
| } | |||||
| @override | |||||
| Widget build(BuildContext context) { | |||||
| return Scaffold( | |||||
| body: Consumer<MeetingSummaryState>( | |||||
| builder: (context, value, child) { | |||||
| return CustomScrollView( | |||||
| slivers: <Widget>[ | |||||
| CustomAppbar( | |||||
| title: 'صورت جلسه', | |||||
| ), | |||||
| SliverPadding( | |||||
| padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 2), | |||||
| sliver: SliverToBoxAdapter( | |||||
| child: CustomCardMeeting( | |||||
| titel: widget.meetingItem.subject!.subject ?? '', | |||||
| date: widget.meetingItem.dateJalali ?? '', | |||||
| location: widget.meetingItem.location!.address ?? '', | |||||
| fromTime: widget.meetingItem.azHour ?? '', | |||||
| toTime: widget.meetingItem.taHour ?? '', | |||||
| cardId: widget.meetingItem.id ?? -1, | |||||
| ), | |||||
| ), | |||||
| ), | |||||
| SliverPadding( | |||||
| padding: | |||||
| const EdgeInsets.symmetric(vertical: 20, horizontal: 10), | |||||
| sliver: SliverToBoxAdapter( | |||||
| child: Container( | |||||
| decoration: BoxDecoration( | |||||
| color: const Color(0xffF4F9F6), | |||||
| boxShadow: [ | |||||
| BoxShadow( | |||||
| color: config.ui.mainGray.withOpacity(.1), | |||||
| spreadRadius: .1, | |||||
| offset: const Offset(0, 2), | |||||
| blurRadius: 6, | |||||
| ), | |||||
| ], | |||||
| borderRadius: const BorderRadius.all(Radius.circular(12)), | |||||
| ), | |||||
| child: CustomTextArea( | |||||
| hintText: 'شرح جلسه', | |||||
| controller: _textControllerDescription, | |||||
| ), | |||||
| ), | |||||
| ), | |||||
| ), | |||||
| SliverToBoxAdapter( | |||||
| child: ReceiptUploadDialog( | |||||
| state: value, | |||||
| ), | |||||
| ), | |||||
| SliverToBoxAdapter( | |||||
| child: Padding( | |||||
| padding: const EdgeInsets.all(30.0), | |||||
| child: submitSammaryButton(context, value), | |||||
| ), | |||||
| ) | |||||
| ], | |||||
| ); | |||||
| }, | |||||
| ), | |||||
| ); | |||||
| } | |||||
| Widget submitSammaryButton(BuildContext context, MeetingSummaryState state) { | |||||
| switch (state.statusMinuteMeeting) { | |||||
| case Status.loading: | |||||
| return CustomButton(hieght: 50, text: 'صبر کنید!'); | |||||
| default: | |||||
| return CustomButton( | |||||
| hieght: 50, | |||||
| text: 'ثبت صورت جلسه', | |||||
| onPressed: () async { | |||||
| if (_textControllerDescription.text == '') { | |||||
| // call add new subject | |||||
| Tools.showCustomSnackBar( | |||||
| text: 'موضوع وارد کنید!', | |||||
| isError: true, | |||||
| context, | |||||
| ); | |||||
| } else if (state.selectedFiles == null) { | |||||
| // call add new subject | |||||
| Tools.showCustomSnackBar( | |||||
| text: 'فایل وارد کنید!', | |||||
| isError: true, | |||||
| context, | |||||
| ); | |||||
| } else { | |||||
| final status = await state.addMinuteMeeting( | |||||
| id: widget.meetingItem.id ?? -1, | |||||
| description: _textControllerDescription.text, | |||||
| meetingFiles: state.selectedFiles ?? []); | |||||
| if (status == Status.ready) { | |||||
| // call refrresh subjects | |||||
| } else { | |||||
| Tools.showCustomSnackBar( | |||||
| text: state.errorsMinuteMeeting == null | |||||
| ? state.messageMinuteMeeting ?? | |||||
| ' AppLocalizations.of(context)!.haserror' | |||||
| : Tools.combineErrorMessages( | |||||
| state.errorsMinuteMeeting ?? {}), | |||||
| isError: true, | |||||
| context, | |||||
| ); | |||||
| } | |||||
| } | |||||
| }, | |||||
| ); | |||||
| } | |||||
| } | |||||
| } | |||||
| class CustomTextArea extends StatelessWidget { | |||||
| final String hintText; | |||||
| final TextEditingController controller; | |||||
| final int maxLines; | |||||
| final int minLines; | |||||
| const CustomTextArea({ | |||||
| Key? key, | |||||
| required this.hintText, | |||||
| required this.controller, | |||||
| this.maxLines = 20, | |||||
| this.minLines = 4, | |||||
| }) : super(key: key); | |||||
| @override | |||||
| Widget build(BuildContext context) { | |||||
| return TextField( | |||||
| controller: controller, | |||||
| maxLines: maxLines, | |||||
| minLines: minLines, | |||||
| decoration: InputDecoration( | |||||
| hintText: hintText, | |||||
| hintStyle: TextStyle(color: Colors.black.withOpacity(.4), fontSize: 13), | |||||
| border: InputBorder.none, | |||||
| contentPadding: const EdgeInsets.all(12.0), | |||||
| ), | |||||
| ); | |||||
| } | |||||
| } | |||||
| class ReceiptUploadDialog extends StatefulWidget { | |||||
| final MeetingSummaryState state; | |||||
| const ReceiptUploadDialog({ | |||||
| Key? key, | |||||
| required this.state, | |||||
| }) : super(key: key); | |||||
| @override | |||||
| _ReceiptUploadDialogState createState() => _ReceiptUploadDialogState(); | |||||
| } | |||||
| class _ReceiptUploadDialogState extends State<ReceiptUploadDialog> { | |||||
| @override | |||||
| Widget build(BuildContext context) { | |||||
| return Padding( | |||||
| padding: const EdgeInsets.symmetric(horizontal: 10), | |||||
| child: Container( | |||||
| decoration: BoxDecoration( | |||||
| color: const Color(0xffF4F9F6), | |||||
| boxShadow: [ | |||||
| BoxShadow( | |||||
| color: config.ui.mainGray.withOpacity(.1), | |||||
| spreadRadius: .1, | |||||
| offset: const Offset(0, 2), | |||||
| blurRadius: 6, | |||||
| ), | |||||
| ], | |||||
| borderRadius: const BorderRadius.all(Radius.circular(12)), | |||||
| ), | |||||
| child: Padding( | |||||
| padding: const EdgeInsets.symmetric(vertical: 25, horizontal: 10), | |||||
| child: Column( | |||||
| mainAxisSize: MainAxisSize.min, | |||||
| crossAxisAlignment: CrossAxisAlignment.start, | |||||
| children: [ | |||||
| Text( | |||||
| 'آپلود فایل', | |||||
| style: TextStyle( | |||||
| fontSize: 16, | |||||
| fontWeight: FontWeight.bold, | |||||
| color: config.ui.mainGreen, | |||||
| ), | |||||
| ), | |||||
| const SizedBox(height: 20), | |||||
| // Upload box | |||||
| FileBorderBox( | |||||
| child: GestureDetector( | |||||
| onTap: widget.state.pickFiles, | |||||
| child: Column( | |||||
| children: [ | |||||
| Icon(Icons.cloud_upload_outlined, | |||||
| size: 30, color: config.ui.mainGreen), | |||||
| Text( | |||||
| 'انتخاب فایل', | |||||
| style: | |||||
| TextStyle(fontSize: 12, color: config.ui.mainGreen), | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| ), | |||||
| // File preview | |||||
| if (widget.state.selectedFiles != null) | |||||
| FilePreview( | |||||
| files: widget.state.selectedFiles!, | |||||
| onDelete: widget.state.removeFile, | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| ), | |||||
| ); | |||||
| } | |||||
| } | |||||
| class FilePreview extends StatelessWidget { | |||||
| final List<PlatformFile> files; | |||||
| final void Function(int) onDelete; | |||||
| const FilePreview({ | |||||
| super.key, | |||||
| required this.files, | |||||
| required this.onDelete, | |||||
| }); | |||||
| @override | |||||
| Widget build(BuildContext context) { | |||||
| return ListView.builder( | |||||
| shrinkWrap: true, | |||||
| itemCount: files.length, | |||||
| physics: const NeverScrollableScrollPhysics(), | |||||
| itemBuilder: (BuildContext context, int index) { | |||||
| return Container( | |||||
| padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5), | |||||
| margin: const EdgeInsets.symmetric(vertical: 5, horizontal: 10), | |||||
| decoration: BoxDecoration( | |||||
| borderRadius: BorderRadius.circular(10), | |||||
| border: Border(bottom: BorderSide(color: config.ui.secendGreen)), | |||||
| ), | |||||
| child: Row( | |||||
| mainAxisAlignment: MainAxisAlignment.start, | |||||
| children: [ | |||||
| const Icon(Icons.file_present_outlined, color: Color(0xffD0D5ED)), | |||||
| const SizedBox(width: 10), | |||||
| Expanded( | |||||
| child: Text( | |||||
| files[index].name, | |||||
| style: const TextStyle(fontSize: 12), | |||||
| ), | |||||
| ), | |||||
| IconButton( | |||||
| icon: Icon(Icons.delete, color: config.ui.secendGreen), | |||||
| onPressed: () => onDelete(index), | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| ); | |||||
| }, | |||||
| ); | |||||
| } | |||||
| } | |||||
| class FileBorderBox extends StatelessWidget { | |||||
| final Widget child; | |||||
| const FileBorderBox({super.key, required this.child}); | |||||
| @override | |||||
| Widget build(BuildContext context) { | |||||
| return Container( | |||||
| padding: const EdgeInsets.all(20), | |||||
| decoration: BoxDecoration( | |||||
| borderRadius: BorderRadius.circular(10), | |||||
| border: Border.all( | |||||
| color: config.ui.mainGreen, | |||||
| style: BorderStyle.solid, | |||||
| width: .5, | |||||
| ), | |||||
| ), | |||||
| child: Center(child: child), | |||||
| ); | |||||
| } | |||||
| } | |||||