Initial commit
1
.env.development
Normal file
@ -0,0 +1 @@
|
||||
API_URL=https://venbait.in/nhance/dev/employeeRest/
|
||||
1
.env.production
Normal file
@ -0,0 +1 @@
|
||||
API_URL=https://venbait.in/nhance/dev/employeeRest/
|
||||
68
.gitignore
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
# Miscellaneous
|
||||
*.class
|
||||
*.log
|
||||
*.pyc
|
||||
*.swp
|
||||
.DS_Store
|
||||
.atom/
|
||||
.buildlog/
|
||||
.history
|
||||
.svn/
|
||||
.env
|
||||
migrate_working_dir/
|
||||
|
||||
# IntelliJ related
|
||||
*.iml
|
||||
*.lock
|
||||
*.packages
|
||||
*.ipr
|
||||
*.iws
|
||||
.idea/
|
||||
.vscode/
|
||||
|
||||
# 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/
|
||||
|
||||
# Android specific files
|
||||
*.android/
|
||||
*.android.iml
|
||||
*.apk
|
||||
*.ap_
|
||||
|
||||
# iOS specific files
|
||||
*.ios/
|
||||
*.ios.iml
|
||||
*.ipa
|
||||
*.xcworkspace
|
||||
*.xcodeproj/
|
||||
*.xcuserdatad/
|
||||
|
||||
# macOS specific files
|
||||
.idea/workspace.xml
|
||||
|
||||
|
||||
# Dependency lock files
|
||||
.pubspec.lock
|
||||
|
||||
# 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
|
||||
45
.metadata
Normal file
@ -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: "7482962148e8d758338d8a28f589f317e1e42ba4"
|
||||
channel: "stable"
|
||||
|
||||
project_type: app
|
||||
|
||||
# Tracks metadata for the flutter migrate command
|
||||
migration:
|
||||
platforms:
|
||||
- platform: root
|
||||
create_revision: 7482962148e8d758338d8a28f589f317e1e42ba4
|
||||
base_revision: 7482962148e8d758338d8a28f589f317e1e42ba4
|
||||
- platform: android
|
||||
create_revision: 7482962148e8d758338d8a28f589f317e1e42ba4
|
||||
base_revision: 7482962148e8d758338d8a28f589f317e1e42ba4
|
||||
- platform: ios
|
||||
create_revision: 7482962148e8d758338d8a28f589f317e1e42ba4
|
||||
base_revision: 7482962148e8d758338d8a28f589f317e1e42ba4
|
||||
- platform: linux
|
||||
create_revision: 7482962148e8d758338d8a28f589f317e1e42ba4
|
||||
base_revision: 7482962148e8d758338d8a28f589f317e1e42ba4
|
||||
- platform: macos
|
||||
create_revision: 7482962148e8d758338d8a28f589f317e1e42ba4
|
||||
base_revision: 7482962148e8d758338d8a28f589f317e1e42ba4
|
||||
- platform: web
|
||||
create_revision: 7482962148e8d758338d8a28f589f317e1e42ba4
|
||||
base_revision: 7482962148e8d758338d8a28f589f317e1e42ba4
|
||||
- platform: windows
|
||||
create_revision: 7482962148e8d758338d8a28f589f317e1e42ba4
|
||||
base_revision: 7482962148e8d758338d8a28f589f317e1e42ba4
|
||||
|
||||
# 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'
|
||||
16
README.md
Normal file
@ -0,0 +1,16 @@
|
||||
# nhancepolicy
|
||||
|
||||
A new Flutter project.
|
||||
|
||||
## Getting Started
|
||||
|
||||
This project is a starting point for a Flutter application.
|
||||
|
||||
A few resources to get you started if this is your first Flutter project:
|
||||
|
||||
- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
|
||||
- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
|
||||
|
||||
For help getting started with Flutter development, view the
|
||||
[online documentation](https://docs.flutter.dev/), which offers tutorials,
|
||||
samples, guidance on mobile development, and a full API reference.
|
||||
28
analysis_options.yaml
Normal file
@ -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
|
||||
13
android/.gitignore
vendored
Normal file
@ -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/docs/deployment/android#reference-the-keystore-from-the-app
|
||||
key.properties
|
||||
**/*.keystore
|
||||
**/*.jks
|
||||
67
android/app/build.gradle
Normal file
@ -0,0 +1,67 @@
|
||||
plugins {
|
||||
id "com.android.application"
|
||||
id "kotlin-android"
|
||||
id "dev.flutter.flutter-gradle-plugin"
|
||||
}
|
||||
|
||||
def localProperties = new Properties()
|
||||
def localPropertiesFile = rootProject.file('local.properties')
|
||||
if (localPropertiesFile.exists()) {
|
||||
localPropertiesFile.withReader('UTF-8') { reader ->
|
||||
localProperties.load(reader)
|
||||
}
|
||||
}
|
||||
|
||||
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
|
||||
if (flutterVersionCode == null) {
|
||||
flutterVersionCode = '1'
|
||||
}
|
||||
|
||||
def flutterVersionName = localProperties.getProperty('flutter.versionName')
|
||||
if (flutterVersionName == null) {
|
||||
flutterVersionName = '1.0'
|
||||
}
|
||||
|
||||
android {
|
||||
namespace "com.example.nhancepolicy"
|
||||
compileSdk flutter.compileSdkVersion
|
||||
ndkVersion flutter.ndkVersion
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main.java.srcDirs += 'src/main/kotlin'
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||
applicationId "com.example.nhancepolicy"
|
||||
// You can update the following values to match your application needs.
|
||||
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
|
||||
minSdkVersion flutter.minSdkVersion
|
||||
targetSdkVersion flutter.targetSdkVersion
|
||||
versionCode flutterVersionCode.toInteger()
|
||||
versionName flutterVersionName
|
||||
}
|
||||
|
||||
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 '../..'
|
||||
}
|
||||
|
||||
dependencies {}
|
||||
7
android/app/src/debug/AndroidManifest.xml
Normal file
@ -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>
|
||||
44
android/app/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,44 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<application
|
||||
android:label="nhancepolicy"
|
||||
android:name="${applicationName}"
|
||||
android:icon="@mipmap/ic_launcher">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTop"
|
||||
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?hl=en 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.nhancepolicy
|
||||
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
|
||||
class MainActivity: FlutterActivity()
|
||||
12
android/app/src/main/res/drawable-v21/launch_background.xml
Normal file
@ -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>
|
||||
12
android/app/src/main/res/drawable/launch_background.xml
Normal file
@ -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>
|
||||
BIN
android/app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 544 B |
BIN
android/app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 442 B |
BIN
android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 721 B |
BIN
android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
18
android/app/src/main/res/values-night/styles.xml
Normal file
@ -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>
|
||||
18
android/app/src/main/res/values/styles.xml
Normal file
@ -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>
|
||||
7
android/app/src/profile/AndroidManifest.xml
Normal file
@ -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>
|
||||
18
android/build.gradle
Normal file
@ -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
|
||||
}
|
||||
3
android/gradle.properties
Normal file
@ -0,0 +1,3 @@
|
||||
org.gradle.jvmargs=-Xmx4G
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
5
android/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@ -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-7.6.3-all.zip
|
||||
26
android/settings.gradle
Normal file
@ -0,0 +1,26 @@
|
||||
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
|
||||
}
|
||||
settings.ext.flutterSdkPath = flutterSdkPath()
|
||||
|
||||
includeBuild("${settings.ext.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 "7.3.0" apply false
|
||||
id "org.jetbrains.kotlin.android" version "1.7.10" apply false
|
||||
}
|
||||
|
||||
include ":app"
|
||||
BIN
assets/Nhance-Logo-Final 1.png
Normal file
|
After Width: | Height: | Size: 4.0 KiB |
BIN
assets/Nhance-Logo-Final 123.png
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
BIN
assets/Nhance-Logo-Final-mobile.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
assets/img1.png
Normal file
|
After Width: | Height: | Size: 125 KiB |
BIN
assets/login_web.jpg
Normal file
|
After Width: | Height: | Size: 833 KiB |
BIN
assets/navbarLogo.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
assets/policy.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
34
ios/.gitignore
vendored
Normal file
@ -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
|
||||
26
ios/Flutter/AppFrameworkInfo.plist
Normal file
@ -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>
|
||||
1
ios/Flutter/Debug.xcconfig
Normal file
@ -0,0 +1 @@
|
||||
#include "Generated.xcconfig"
|
||||
1
ios/Flutter/Release.xcconfig
Normal file
@ -0,0 +1 @@
|
||||
#include "Generated.xcconfig"
|
||||
13
ios/Runner/AppDelegate.swift
Normal file
@ -0,0 +1,13 @@
|
||||
import UIKit
|
||||
import Flutter
|
||||
|
||||
@UIApplicationMain
|
||||
@objc class AppDelegate: FlutterAppDelegate {
|
||||
override func application(
|
||||
_ application: UIApplication,
|
||||
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
||||
) -> Bool {
|
||||
GeneratedPluginRegistrant.register(with: self)
|
||||
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||
}
|
||||
}
|
||||
122
ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
Normal file
@ -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"
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 295 B |
|
After Width: | Height: | Size: 406 B |
|
After Width: | Height: | Size: 450 B |
|
After Width: | Height: | Size: 282 B |
|
After Width: | Height: | Size: 462 B |
|
After Width: | Height: | Size: 704 B |
|
After Width: | Height: | Size: 406 B |
|
After Width: | Height: | Size: 586 B |
|
After Width: | Height: | Size: 862 B |
|
After Width: | Height: | Size: 862 B |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 762 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
23
ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
vendored
Normal file
@ -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"
|
||||
}
|
||||
}
|
||||
BIN
ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
vendored
Normal file
|
After Width: | Height: | Size: 68 B |
BIN
ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 68 B |
BIN
ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 68 B |
5
ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md
vendored
Normal file
@ -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.
|
||||
37
ios/Runner/Base.lproj/LaunchScreen.storyboard
Normal file
@ -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>
|
||||
26
ios/Runner/Base.lproj/Main.storyboard
Normal file
@ -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>
|
||||
49
ios/Runner/Info.plist
Normal file
@ -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>Nhancepolicy</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>nhancepolicy</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>
|
||||
1
ios/Runner/Runner-Bridging-Header.h
Normal file
@ -0,0 +1 @@
|
||||
#import "GeneratedPluginRegistrant.h"
|
||||
12
ios/RunnerTests/RunnerTests.swift
Normal file
@ -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.
|
||||
}
|
||||
|
||||
}
|
||||
78
lib/customAppBar/customAppBar.dart
Normal file
@ -0,0 +1,78 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:adaptive_navbar/adaptive_navbar.dart';
|
||||
|
||||
class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
|
||||
@override
|
||||
Size get preferredSize => Size.fromHeight(kToolbarHeight);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final sw = MediaQuery.of(context).size.width;
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: Color(0xFF00989E), // Set background color for AppBar
|
||||
appBar: PreferredSize(
|
||||
preferredSize: preferredSize,
|
||||
child: SafeArea(
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: Row(
|
||||
children: [
|
||||
// Logo Column
|
||||
Expanded(
|
||||
flex: 4,
|
||||
child: Container(
|
||||
margin: EdgeInsets.only(top: 10, bottom: 10),
|
||||
width: 150,
|
||||
height: 150,
|
||||
child: Image.asset(
|
||||
'assets/navbarLogo.png',
|
||||
fit: BoxFit.contain, // Adjust the fit as needed
|
||||
),
|
||||
),
|
||||
),
|
||||
// AdaptiveNavBar Column
|
||||
Expanded(
|
||||
flex: 8,
|
||||
child: AdaptiveNavBar(
|
||||
screenWidth: sw,
|
||||
backgroundColor: Color(0xFF00989E),
|
||||
leading:
|
||||
Container(), // Set an empty container as we have the logo separately
|
||||
title: Text(''),
|
||||
navBarItems: [
|
||||
NavBarItem(
|
||||
text: "",
|
||||
onTap: () {
|
||||
Navigator.pushNamed(context, "routeName");
|
||||
},
|
||||
),
|
||||
NavBarItem(
|
||||
text: "",
|
||||
onTap: () {
|
||||
Navigator.pushNamed(context, "routeName");
|
||||
},
|
||||
),
|
||||
NavBarItem(
|
||||
text: "",
|
||||
onTap: () {
|
||||
Navigator.pushNamed(context, "routeName");
|
||||
},
|
||||
),
|
||||
NavBarItem(
|
||||
text: "Logout",
|
||||
onTap: () {
|
||||
Navigator.pushNamed(context, "phone");
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
28
lib/customAppBar/toastHelper.dart
Normal file
@ -0,0 +1,28 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:fluttertoast/fluttertoast.dart';
|
||||
|
||||
class ToastHelper {
|
||||
static void showSuccessToast(BuildContext context, String message) {
|
||||
_showToast(context, message, Colors.green);
|
||||
}
|
||||
|
||||
static void showWarningToast(BuildContext context, String message) {
|
||||
_showToast(context, message, Colors.orange);
|
||||
}
|
||||
|
||||
static void showErrorToast(BuildContext context, String message) {
|
||||
_showToast(context, message, Colors.red);
|
||||
}
|
||||
|
||||
static void _showToast(BuildContext context, String message, Color color) {
|
||||
Fluttertoast.showToast(
|
||||
msg: message,
|
||||
toastLength: Toast.LENGTH_SHORT,
|
||||
gravity: ToastGravity.TOP,
|
||||
timeInSecForIosWeb: 5,
|
||||
backgroundColor: color,
|
||||
textColor: Colors.white,
|
||||
fontSize: 16.0,
|
||||
);
|
||||
}
|
||||
}
|
||||
2122
lib/home.dart
Normal file
712
lib/hrHome.dart
Normal file
@ -0,0 +1,712 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:nhancepolicy/customAppBar/customAppBar.dart';
|
||||
import 'package:nhancepolicy/models/environment.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:jwt_decode/jwt_decode.dart';
|
||||
import 'dart:convert';
|
||||
import 'dart:async';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:nhancepolicy/customAppBar/toastHelper.dart';
|
||||
import 'dart:html' as html;
|
||||
import 'dart:typed_data';
|
||||
import 'dart:io';
|
||||
import 'package:flutter/foundation.dart' show kIsWeb;
|
||||
|
||||
class MyHrHome extends StatefulWidget {
|
||||
const MyHrHome({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<MyHrHome> createState() => _MyHrHomeState();
|
||||
}
|
||||
|
||||
class _MyHrHomeState extends State<MyHrHome> with TickerProviderStateMixin {
|
||||
Uint8List? _fileBytes;
|
||||
late String _token;
|
||||
List<Map<String, dynamic>> getEmpDependenceByClintIdGMC = [];
|
||||
List<Map<String, dynamic>> getEmpDependenceByClintIdGPA = [];
|
||||
dynamic getPolicyNameDetails0;
|
||||
dynamic getPolicyNameDetails1;
|
||||
dynamic getPolicyNo0;
|
||||
dynamic getPolicyNo1;
|
||||
bool _isLoading = false;
|
||||
dynamic clintID;
|
||||
late TabController _tabController;
|
||||
List<dynamic> dataPolicy = [];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_tabController = TabController(length: 3, vsync: this);
|
||||
_loadToken();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_tabController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> _loadToken() async {
|
||||
final SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
final String? token = prefs.getString('token');
|
||||
if (token != null) {
|
||||
setState(() {
|
||||
_token = token;
|
||||
});
|
||||
Map<String, dynamic>? decodedToken = Jwt.parseJwt(token);
|
||||
clintID = decodedToken['client_id'].toString();
|
||||
await getPolicyName(clintID);
|
||||
} else {
|
||||
// Handle the case when token is not available
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> getPolicyName(String clintID) async {
|
||||
setState(() {
|
||||
_isLoading = true;
|
||||
});
|
||||
var url =
|
||||
Uri.parse(Environment.apiUrl + 'getClientPolicy?client_id=' + clintID);
|
||||
try {
|
||||
var response = await http.get(
|
||||
url,
|
||||
headers: {
|
||||
'Authorization': 'Bearer $_token',
|
||||
},
|
||||
);
|
||||
if (response.statusCode == 200) {
|
||||
Map<String, dynamic> data = json.decode(response.body);
|
||||
if (data['status'] == 'success') {
|
||||
print(data);
|
||||
setState(() {
|
||||
dataPolicy = List<Map<String, dynamic>>.from(data['data']);
|
||||
print(dataPolicy);
|
||||
getPolicyNameDetails0 = dataPolicy[0]['policy_name'];
|
||||
print(getPolicyNameDetails0);
|
||||
getPolicyNameDetails1 = dataPolicy[1]['policy_name'];
|
||||
print(getPolicyNameDetails1);
|
||||
getPolicyNo0 = dataPolicy[0]['client_policy_id'];
|
||||
print(getPolicyNameDetails1);
|
||||
getPolicyNo1 = dataPolicy[1]['client_policy_id'];
|
||||
print(getPolicyNameDetails1);
|
||||
});
|
||||
const duration = Duration(seconds: 5);
|
||||
Timer.periodic(duration, (timer) {
|
||||
// Code to execute periodically every 2 seconds
|
||||
getEmployeeAndDependenceGPA(clintID, getPolicyNo0);
|
||||
getEmployeeAndDependenceGMC(clintID, getPolicyNo1);
|
||||
|
||||
// If you want to stop the periodic execution after some time,
|
||||
// you can cancel the timer like this:
|
||||
timer.cancel();
|
||||
});
|
||||
} else {
|
||||
print('API request failed with status: ${data['status']}');
|
||||
}
|
||||
} else {
|
||||
print('Request failed with status: ${response.statusCode}');
|
||||
}
|
||||
} catch (e) {
|
||||
print('Exception occurred: $e');
|
||||
} finally {
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> getEmployeeAndDependenceGPA(clintID, getPolicyNo0) async {
|
||||
setState(() {
|
||||
_isLoading = true;
|
||||
});
|
||||
var url = Uri.parse(Environment.apiUrl +
|
||||
'getEmployeeAndDependenceByClientId?client_id=$clintID&client_policy_id=$getPolicyNo0');
|
||||
try {
|
||||
var response = await http.get(
|
||||
url,
|
||||
headers: {
|
||||
'Authorization': 'Bearer $_token',
|
||||
},
|
||||
);
|
||||
if (response.statusCode == 200) {
|
||||
Map<String, dynamic> data = json.decode(response.body);
|
||||
if (data['status'] == 'success') {
|
||||
setState(() {
|
||||
getEmpDependenceByClintIdGPA =
|
||||
List<Map<String, dynamic>>.from(data['data']);
|
||||
});
|
||||
} else {
|
||||
print('API request failed with status: ${data['status']}');
|
||||
}
|
||||
} else {
|
||||
print('Request failed with status: ${response.statusCode}');
|
||||
}
|
||||
} catch (e) {
|
||||
print('Exception occurred: $e');
|
||||
} finally {
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> getEmployeeAndDependenceGMC(clintID, getPolicyNo1) async {
|
||||
setState(() {
|
||||
_isLoading = true;
|
||||
});
|
||||
var url = Uri.parse(Environment.apiUrl +
|
||||
'getEmployeeAndDependenceByClientId?client_id=$clintID&client_policy_id=$getPolicyNo1');
|
||||
try {
|
||||
var response = await http.get(
|
||||
url,
|
||||
headers: {
|
||||
'Authorization': 'Bearer $_token',
|
||||
},
|
||||
);
|
||||
if (response.statusCode == 200) {
|
||||
Map<String, dynamic> data = json.decode(response.body);
|
||||
if (data['status'] == 'success') {
|
||||
setState(() {
|
||||
getEmpDependenceByClintIdGMC =
|
||||
List<Map<String, dynamic>>.from(data['data']);
|
||||
});
|
||||
} else {
|
||||
print('API request failed with status: ${data['status']}');
|
||||
}
|
||||
} else {
|
||||
print('Request failed with status: ${response.statusCode}');
|
||||
}
|
||||
} catch (e) {
|
||||
print('Exception occurred: $e');
|
||||
} finally {
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// void _GMCImport() async {
|
||||
// FilePickerResult? result = await FilePicker.platform.pickFiles(
|
||||
// type: FileType.custom,
|
||||
// allowedExtensions: ['xlsx', 'xls'], // Allow Excel file extensions
|
||||
// );
|
||||
//
|
||||
// if (result != null) {
|
||||
// List<int> fileBytes = result.files.single.bytes!;
|
||||
// String fileName = result.files.single.name;
|
||||
//
|
||||
// var request = http.MultipartRequest(
|
||||
// 'POST',
|
||||
// Uri.parse(Environment.apiUrl + 'employeeUpload'),
|
||||
// );
|
||||
// // Set authorization token in headers
|
||||
// request.headers['Authorization'] = 'Bearer $_token';
|
||||
// request.files.add(
|
||||
// http.MultipartFile.fromBytes(
|
||||
// 'file',
|
||||
// fileBytes,
|
||||
// filename: fileName,
|
||||
// ),
|
||||
// );
|
||||
// request.fields['client_id'] = clintID;
|
||||
// request.fields['policy_id'] = '3';
|
||||
//
|
||||
// var response = await request.send();
|
||||
//
|
||||
// if (response.statusCode == 200) {
|
||||
// ToastHelper.showSuccessToast(context, 'File uploaded successfully');
|
||||
// print('File uploaded successfully');
|
||||
//
|
||||
// // Call your API here after file upload
|
||||
// await getEmployeeAndDependenceGMC(clintID, getPolicyNo1);
|
||||
// } else {
|
||||
// ToastHelper.showErrorToast(
|
||||
// context, 'Failed to upload file: ${response.reasonPhrase}');
|
||||
// print('Failed to upload file: ${response.reasonPhrase}');
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// void _GPAImport() async {
|
||||
// FilePickerResult? result = await FilePicker.platform.pickFiles(
|
||||
// type: FileType.custom,
|
||||
// allowedExtensions: ['xlsx', 'xls'], // Allow Excel file extensions
|
||||
// );
|
||||
//
|
||||
// if (result != null) {
|
||||
// List<int> fileBytes = result.files.single.bytes!;
|
||||
// String fileName = result.files.single.name;
|
||||
//
|
||||
// var request = http.MultipartRequest(
|
||||
// 'POST',
|
||||
// Uri.parse(Environment.apiUrl + 'employeeUpload'),
|
||||
// );
|
||||
// // Set authorization token in headers
|
||||
// request.headers['Authorization'] = 'Bearer $_token';
|
||||
// request.files.add(
|
||||
// http.MultipartFile.fromBytes(
|
||||
// 'file',
|
||||
// fileBytes,
|
||||
// filename: fileName,
|
||||
// ),
|
||||
// );
|
||||
// request.fields['client_id'] = clintID;
|
||||
// request.fields['policy_id'] = '1';
|
||||
//
|
||||
// var response = await request.send();
|
||||
//
|
||||
// if (response.statusCode == 200) {
|
||||
// print('File uploaded successfully');
|
||||
// ToastHelper.showSuccessToast(context, 'File uploaded successfully');
|
||||
//
|
||||
// // Call your API here after file upload
|
||||
// await getEmployeeAndDependenceGPA(clintID, getPolicyNo0);
|
||||
// } else {
|
||||
// ToastHelper.showErrorToast(
|
||||
// context, 'Failed to upload file: ${response.reasonPhrase}');
|
||||
// print('Failed to upload file: ${response.reasonPhrase}');
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
void _uploadFile(importPolicyName) async {
|
||||
print('openFile1');
|
||||
final input = html.FileUploadInputElement();
|
||||
input.accept = '.xlsx,.xls'; // Specify accepted file types here
|
||||
input.click();
|
||||
print('openFile2');
|
||||
input.onChange.listen((event) {
|
||||
final file = input.files!.first;
|
||||
final reader = html.FileReader();
|
||||
reader.readAsArrayBuffer(file);
|
||||
|
||||
reader.onLoadEnd.listen((event) {
|
||||
setState(() {
|
||||
print('openFile3');
|
||||
_fileBytes = reader.result as Uint8List?;
|
||||
print(_fileBytes);
|
||||
_importFile(importPolicyName);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _importFile(importPolicyName) async {
|
||||
if (_fileBytes == null) {
|
||||
return; // No file selected
|
||||
}
|
||||
|
||||
// URL of the API where you want to send the file
|
||||
final apiUrl = Environment.apiUrl + 'employeeUpload';
|
||||
|
||||
// Create a multipart request
|
||||
final request = http.MultipartRequest('POST', Uri.parse(apiUrl));
|
||||
|
||||
// Attach the file to the request
|
||||
// Set authorization token in headers
|
||||
request.headers['Authorization'] = 'Bearer $_token';
|
||||
request.files.add(http.MultipartFile.fromBytes('file', _fileBytes!,
|
||||
filename: 'excel_file.xls')); // Specify filename here
|
||||
request.fields['client_id'] = clintID;
|
||||
if (importPolicyName == 'GPA') {
|
||||
request.fields['policy_id'] = '1';
|
||||
} else {
|
||||
request.fields['policy_id'] = '3';
|
||||
}
|
||||
|
||||
// Send the request
|
||||
final response = await request.send();
|
||||
|
||||
// Check the status code of the response
|
||||
if (response.statusCode == 200) {
|
||||
ToastHelper.showSuccessToast(context, 'File uploaded successfully');
|
||||
if (importPolicyName == 'GPA') {
|
||||
await getEmployeeAndDependenceGPA(clintID, getPolicyNo0);
|
||||
} else {
|
||||
await getEmployeeAndDependenceGMC(clintID, getPolicyNo1);
|
||||
}
|
||||
print('File uploaded successfully');
|
||||
} else {
|
||||
ToastHelper.showSuccessToast(
|
||||
context, 'Failed to upload file: ${response.reasonPhrase}');
|
||||
print('Failed to upload file: ${response.reasonPhrase}');
|
||||
}
|
||||
}
|
||||
|
||||
// void _GPAImport() async {
|
||||
// print('Enter');
|
||||
//
|
||||
// if (kIsWeb) {
|
||||
// print('WEB');
|
||||
// final input = html.FileUploadInputElement();
|
||||
// input.accept = '.xlsx,.xls'; // Specify accepted file types here
|
||||
// input.click();
|
||||
// print('WEB111');
|
||||
// input.onChange.listen((event) {
|
||||
// final file = input.files!.first;
|
||||
// final reader = html.FileReader();
|
||||
// reader.readAsArrayBuffer(file);
|
||||
//
|
||||
// reader.onLoadEnd.listen((event) {
|
||||
// setState(() {
|
||||
// _fileBytes = reader.result as Uint8List?;
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
// print(_fileBytes);
|
||||
// if (_fileBytes == null) {
|
||||
// return; // No file selected
|
||||
// } else {
|
||||
// var request = http.MultipartRequest(
|
||||
// 'POST',
|
||||
// Uri.parse(Environment.apiUrl + 'employeeUpload'),
|
||||
// );
|
||||
//
|
||||
// // Set authorization token in headers
|
||||
// request.headers['Authorization'] = 'Bearer $_token';
|
||||
// request.files.add(
|
||||
// http.MultipartFile.fromBytes(
|
||||
// 'file',
|
||||
// _fileBytes!,
|
||||
// ),
|
||||
// );
|
||||
// request.fields['client_id'] = clintID;
|
||||
// request.fields['policy_id'] = '1';
|
||||
//
|
||||
// var response = await request.send();
|
||||
//
|
||||
// if (response.statusCode == 200) {
|
||||
// print('File uploaded successfully');
|
||||
// ToastHelper.showSuccessToast(context, 'File uploaded successfully');
|
||||
//
|
||||
// // Call your API here after file upload
|
||||
// await getEmployeeAndDependenceGPA(clintID, getPolicyNo0);
|
||||
// } else {
|
||||
// ToastHelper.showErrorToast(
|
||||
// context, 'Failed to upload file: ${response.reasonPhrase}');
|
||||
// print('Failed to upload file: ${response.reasonPhrase}');
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// print('IOS Android');
|
||||
// // Use file picker for mobile platforms
|
||||
// FilePickerResult? result = await FilePicker.platform.pickFiles(
|
||||
// type: FileType.custom,
|
||||
// allowedExtensions: ['xlsx', 'xls'], // Allow Excel file extensions
|
||||
// );
|
||||
//
|
||||
// // Rest of your code remains the same
|
||||
// // Make sure to handle the result based on the platform
|
||||
// if (result != null) {
|
||||
// List<int> fileBytes = result.files.single.bytes!;
|
||||
// String fileName = result.files.single.name;
|
||||
//
|
||||
// var request = http.MultipartRequest(
|
||||
// 'POST',
|
||||
// Uri.parse(Environment.apiUrl + 'employeeUpload'),
|
||||
// );
|
||||
//
|
||||
// // Set authorization token in headers
|
||||
// request.headers['Authorization'] = 'Bearer $_token';
|
||||
// request.files.add(
|
||||
// http.MultipartFile.fromBytes(
|
||||
// 'file',
|
||||
// fileBytes,
|
||||
// filename: fileName,
|
||||
// ),
|
||||
// );
|
||||
// request.fields['client_id'] = clintID;
|
||||
// request.fields['policy_id'] = '1';
|
||||
//
|
||||
// var response = await request.send();
|
||||
//
|
||||
// if (response.statusCode == 200) {
|
||||
// print('File uploaded successfully');
|
||||
// ToastHelper.showSuccessToast(context, 'File uploaded successfully');
|
||||
//
|
||||
// // Call your API here after file upload
|
||||
// await getEmployeeAndDependenceGPA(clintID, getPolicyNo0);
|
||||
// } else {
|
||||
// ToastHelper.showErrorToast(
|
||||
// context, 'Failed to upload file: ${response.reasonPhrase}');
|
||||
// print('Failed to upload file: ${response.reasonPhrase}');
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// Check if the code is running on web
|
||||
bool get isWeb {
|
||||
try {
|
||||
// Check if the window object is accessible
|
||||
return identical(0, 0.0);
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: CustomAppBar(),
|
||||
body: Container(
|
||||
padding: const EdgeInsets.all(20),
|
||||
color: Color(0xFFEFF3F6),
|
||||
child: Card(
|
||||
elevation: 0,
|
||||
child: Column(
|
||||
children: [
|
||||
TabBar(
|
||||
controller: _tabController,
|
||||
tabs: [
|
||||
Tab(text: 'GPA-' + getPolicyNameDetails0 ?? ''),
|
||||
Tab(text: 'GMC-' + getPolicyNameDetails1 ?? ''),
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: TabBarView(
|
||||
controller: _tabController,
|
||||
children: [
|
||||
Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: _isLoading
|
||||
? Center(child: CircularProgressIndicator())
|
||||
: Column(
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 10,
|
||||
child: Container(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
'',
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Container(
|
||||
alignment: Alignment.centerRight,
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
Expanded(
|
||||
child: ElevatedButton(
|
||||
onPressed: () =>
|
||||
_uploadFile('GPA'),
|
||||
child: Text(
|
||||
'Import',
|
||||
style: TextStyle(
|
||||
color: Colors.white),
|
||||
),
|
||||
style:
|
||||
ElevatedButton.styleFrom(
|
||||
backgroundColor:
|
||||
Color(0xFFE26728),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
child: _buildDataTableGPA(),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: _isLoading
|
||||
? Center(child: CircularProgressIndicator())
|
||||
: Column(
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 10,
|
||||
child: Container(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
'',
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Container(
|
||||
alignment: Alignment.centerRight,
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
Expanded(
|
||||
child: ElevatedButton(
|
||||
onPressed: () =>
|
||||
_uploadFile('GMC'),
|
||||
child: Text(
|
||||
'Import',
|
||||
style: TextStyle(
|
||||
color: Colors.white),
|
||||
),
|
||||
style:
|
||||
ElevatedButton.styleFrom(
|
||||
backgroundColor:
|
||||
Color(0xFFE26728),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
child: _buildDataTableGMC(),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDataTableGPA() {
|
||||
if (getEmpDependenceByClintIdGPA.isEmpty) {
|
||||
SizedBox(height: 25);
|
||||
return Text('No available data');
|
||||
} else {
|
||||
return Card(
|
||||
elevation: 0, // Set elevation to 0 for no shadow
|
||||
child: PaginatedDataTable(
|
||||
rowsPerPage: 5, // Adjust rows per page as needed
|
||||
columns: [
|
||||
DataColumn(label: Text('Employee ID')),
|
||||
DataColumn(label: Text('Name')),
|
||||
DataColumn(label: Text('Relationship')),
|
||||
DataColumn(label: Text('Date of Birth')),
|
||||
DataColumn(label: Text('Gender')),
|
||||
DataColumn(label: Text('Mobile No')),
|
||||
],
|
||||
source: _DependenceDataSource0(getEmpDependenceByClintIdGPA),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildDataTableGMC() {
|
||||
if (getEmpDependenceByClintIdGPA.isEmpty) {
|
||||
SizedBox(height: 25);
|
||||
return Text('No available data');
|
||||
} else {
|
||||
return Card(
|
||||
elevation: 0, // Set elevation to 0 for no shadow
|
||||
child: PaginatedDataTable(
|
||||
rowsPerPage: 5, // Adjust rows per page as needed
|
||||
columns: [
|
||||
DataColumn(label: Text('Employee ID')),
|
||||
DataColumn(label: Text('Name')),
|
||||
DataColumn(label: Text('Relationship')),
|
||||
DataColumn(label: Text('Date of Birth')),
|
||||
DataColumn(label: Text('Gender')),
|
||||
DataColumn(label: Text('Mobile No')),
|
||||
],
|
||||
source: _DependenceDataSource0(getEmpDependenceByClintIdGMC),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class _DependenceDataSource0 extends DataTableSource {
|
||||
final List<Map<String, dynamic>> _data;
|
||||
_DependenceDataSource0(this._data);
|
||||
|
||||
@override
|
||||
DataRow getRow(int index) {
|
||||
final row = _data[index];
|
||||
return DataRow(cells: [
|
||||
DataCell(Text(row['emp_code'].toString())),
|
||||
DataCell(Text(row['name'].toString())),
|
||||
DataCell(Text(row['relationship'].toString())),
|
||||
DataCell(Text(row['dob'] ?? 'N/A')),
|
||||
DataCell(Text(row['gender'] ?? 'N/A')),
|
||||
DataCell(Text(row['mobile'] ?? 'N/A')),
|
||||
]);
|
||||
}
|
||||
|
||||
@override
|
||||
bool get isRowCountApproximate => false;
|
||||
|
||||
@override
|
||||
int get rowCount => _data.length;
|
||||
|
||||
@override
|
||||
int get selectedRowCount => 0;
|
||||
}
|
||||
|
||||
class _DependenceDataSource1 extends DataTableSource {
|
||||
final List<Map<String, dynamic>> _data;
|
||||
_DependenceDataSource1(this._data);
|
||||
|
||||
@override
|
||||
DataRow getRow(int index) {
|
||||
final row = _data[index];
|
||||
return DataRow(cells: [
|
||||
DataCell(Text(row['emp_code'].toString())),
|
||||
DataCell(Text(row['name'].toString())),
|
||||
DataCell(Text(row['relationship'].toString())),
|
||||
DataCell(Text(row['dob'] ?? 'N/A')),
|
||||
DataCell(Text(row['gender'] ?? 'N/A')),
|
||||
DataCell(Text(row['mobile'] ?? 'N/A')),
|
||||
]);
|
||||
}
|
||||
|
||||
@override
|
||||
bool get isRowCountApproximate => false;
|
||||
|
||||
@override
|
||||
int get rowCount => _data.length;
|
||||
|
||||
@override
|
||||
int get selectedRowCount => 0;
|
||||
}
|
||||
458
lib/hrLogin.dart
Normal file
@ -0,0 +1,458 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:nhancepolicy/models/environment.dart';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'package:nhancepolicy/responsive.dart';
|
||||
|
||||
class MyHrLogin extends StatefulWidget {
|
||||
const MyHrLogin({Key? key});
|
||||
|
||||
@override
|
||||
State<MyHrLogin> createState() => _MyPhoneState();
|
||||
}
|
||||
|
||||
class _MyPhoneState extends State<MyHrLogin> {
|
||||
TextEditingController countryController = TextEditingController();
|
||||
TextEditingController mobileController = TextEditingController();
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
countryController.text = "+91";
|
||||
super.initState();
|
||||
}
|
||||
|
||||
void toggleLoginType() {
|
||||
Navigator.pushNamed(context, 'phone'); // Navigate to another page
|
||||
}
|
||||
|
||||
Future<bool> verifyMobileNumber(String mobileNumber) async {
|
||||
try {
|
||||
final response = await http.post(
|
||||
Uri.parse(Environment.apiUrl + 'verifyHrWithMobileNumber'),
|
||||
body: json.encode({'mobile_number': mobileNumber}),
|
||||
headers: {
|
||||
HttpHeaders.contentTypeHeader: 'application/json',
|
||||
},
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
Map<String, dynamic> data = json.decode(response.body);
|
||||
bool userVerification = data['data']['user_verification'];
|
||||
return userVerification;
|
||||
} else {
|
||||
throw Exception('Failed to verify mobile number');
|
||||
}
|
||||
} catch (e) {
|
||||
print('Error: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void handleSubmit() async {
|
||||
if (_formKey.currentState!.validate()) {
|
||||
// var enteredMobileNumber = countryController.text + mobileController.text;
|
||||
var enteredMobileNumber = mobileController.text;
|
||||
|
||||
bool isValid = await verifyMobileNumber(enteredMobileNumber);
|
||||
|
||||
if (isValid) {
|
||||
Navigator.pushNamed(context, 'hrVerify',
|
||||
arguments: enteredMobileNumber);
|
||||
} else {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Invalid mobile number'),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Size _size = MediaQuery.of(context).size;
|
||||
EdgeInsets marginInsets = EdgeInsets.zero;
|
||||
|
||||
if (Responsive.isDesktop(context)) {
|
||||
marginInsets = const EdgeInsets.only(
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
top: 0,
|
||||
);
|
||||
} else if (Responsive.isMobile(context)) {
|
||||
marginInsets = const EdgeInsets.only(
|
||||
left: 25, // Example value for mobile
|
||||
right: 25, // Example value for mobile
|
||||
bottom: 0, // Example value for mobile
|
||||
top: 0, // Example value for mobile
|
||||
);
|
||||
} else if (Responsive.isTablet(context)) {
|
||||
marginInsets = const EdgeInsets.only(
|
||||
left: 25, // Example value for mobile
|
||||
right: 25, // Example value for mobile
|
||||
bottom: 0, // Example value for mobile
|
||||
top: 0, // Example value for mobile
|
||||
);
|
||||
}
|
||||
return Scaffold(
|
||||
body: SingleChildScrollView(
|
||||
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
|
||||
child: Container(
|
||||
height: _size.height,
|
||||
color: Colors.white,
|
||||
child: Stack(
|
||||
children: [
|
||||
Visibility(
|
||||
visible: _size.width <= 1100,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.only(
|
||||
bottomLeft: Radius.circular(30),
|
||||
bottomRight: Radius.circular(30),
|
||||
),
|
||||
child: Container(
|
||||
height: _size.height / 3,
|
||||
width: double.infinity,
|
||||
color: Color(0xFF00989E),
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
margin: marginInsets,
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: SingleChildScrollView(
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: _size.width < 1100 ? 6 : 12,
|
||||
child: Container(
|
||||
margin: _size.width > 1100
|
||||
? EdgeInsets.only(left: 150, right: 150)
|
||||
: null,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
child: InkWell(
|
||||
onTap:
|
||||
toggleLoginType, // Call the toggleLoginType function on tap
|
||||
child: Container(
|
||||
// Add your text here
|
||||
child: Text(
|
||||
'Employee Login',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Color(0xFF00989E)),
|
||||
),
|
||||
alignment: Alignment
|
||||
.centerRight, // Add padding
|
||||
),
|
||||
),
|
||||
),
|
||||
_size.width <= 1100
|
||||
? Image.asset(
|
||||
'assets/Nhance-Logo-Final-mobile.png',
|
||||
width: 150,
|
||||
height: 150,
|
||||
)
|
||||
: _size.width > 1100
|
||||
? Image.asset(
|
||||
'assets/Nhance-Logo-Final 1.png',
|
||||
width: 150,
|
||||
height: 150,
|
||||
)
|
||||
: Image.asset(
|
||||
'assets/Nhance-Logo-Final 1.png',
|
||||
width: 150,
|
||||
height: 150,
|
||||
),
|
||||
SizedBox(
|
||||
height: _size.width <= 1100 ? 50 : 0,
|
||||
),
|
||||
Text(
|
||||
"Welcome to Nhance HR Login",
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
Text(
|
||||
"Have a Health Insurance Policy number, but never signed in? Don't worry, We got you covered",
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Color(0xFF000000)),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
SizedBox(
|
||||
height: 30,
|
||||
),
|
||||
Container(
|
||||
height: 55,
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
width: 1, color: Colors.grey),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
SizedBox(
|
||||
width: 40,
|
||||
child: TextField(
|
||||
controller: countryController,
|
||||
keyboardType:
|
||||
TextInputType.number,
|
||||
decoration: InputDecoration(
|
||||
border: InputBorder.none,
|
||||
),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
"|",
|
||||
style: TextStyle(
|
||||
fontSize: 33,
|
||||
color: Colors.grey),
|
||||
),
|
||||
SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
controller: mobileController,
|
||||
keyboardType: TextInputType.phone,
|
||||
decoration: InputDecoration(
|
||||
border: InputBorder.none,
|
||||
hintText:
|
||||
"Enter your mobile number",
|
||||
),
|
||||
validator: (value) {
|
||||
if (value == null ||
|
||||
value.isEmpty) {
|
||||
return 'Please enter your mobile number';
|
||||
}
|
||||
if (value.length != 10) {
|
||||
return 'Mobile number must be 10 digits';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
inputFormatters: <TextInputFormatter>[
|
||||
FilteringTextInputFormatter
|
||||
.digitsOnly,
|
||||
LengthLimitingTextInputFormatter(
|
||||
10),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
height: 45,
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Color(0xFF00989E),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius:
|
||||
BorderRadius.circular(10),
|
||||
),
|
||||
),
|
||||
onPressed: handleSubmit,
|
||||
child: Text(
|
||||
"Login With OTP",
|
||||
style: TextStyle(
|
||||
color: Color(0xFFFFFFFF)),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: _size.width <= 1100 ? 0 : 0,
|
||||
),
|
||||
_size.width > 1100
|
||||
? Column(
|
||||
children: [
|
||||
SizedBox(height: 30),
|
||||
Text(
|
||||
"Benefits of Login",
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 15),
|
||||
],
|
||||
)
|
||||
: SizedBox(),
|
||||
_size.width > 1100
|
||||
? Container(
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 6,
|
||||
child: Container(
|
||||
padding:
|
||||
EdgeInsets.symmetric(
|
||||
vertical: 8),
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.center,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: EdgeInsets
|
||||
.symmetric(
|
||||
vertical:
|
||||
12),
|
||||
decoration:
|
||||
BoxDecoration(
|
||||
border: Border(
|
||||
right:
|
||||
BorderSide(
|
||||
width: 1,
|
||||
color: Colors
|
||||
.black,
|
||||
),
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Icon(
|
||||
Icons
|
||||
.policy,
|
||||
color: Color(
|
||||
0xFFE26728)),
|
||||
SizedBox(
|
||||
height: 10),
|
||||
Text(
|
||||
"View Policy"),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: EdgeInsets
|
||||
.symmetric(
|
||||
vertical:
|
||||
12),
|
||||
child: Column(
|
||||
children: [
|
||||
Icon(Icons.edit,
|
||||
color: Color(
|
||||
0xFFE26728)),
|
||||
SizedBox(
|
||||
height: 10),
|
||||
Text(
|
||||
"Manage Claims"),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
: SizedBox(
|
||||
height: _size.height * 0.2,
|
||||
),
|
||||
SizedBox(
|
||||
height: _size.height * 0.1,
|
||||
),
|
||||
Container(
|
||||
alignment: Alignment.bottomCenter,
|
||||
padding:
|
||||
EdgeInsets.symmetric(vertical: 8),
|
||||
child: RichText(
|
||||
textAlign: TextAlign.center,
|
||||
text: TextSpan(
|
||||
text:
|
||||
'By continuing, you agree with our ',
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 9,
|
||||
),
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text: 'privacy policy ',
|
||||
style: TextStyle(
|
||||
color: Color(0xFF00989E),
|
||||
fontSize: 9,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: 'and ',
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 9,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: 'terms of use',
|
||||
style: TextStyle(
|
||||
color: Color(0xFF00989E),
|
||||
fontSize: 9,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
if (_size.width > 1100)
|
||||
Expanded(
|
||||
flex: _size.width < 1100 ? 6 : 12,
|
||||
child: LayoutBuilder(
|
||||
builder: (BuildContext context,
|
||||
BoxConstraints constraints) {
|
||||
if (constraints.maxWidth > 600) {
|
||||
return Image.asset(
|
||||
'assets/login_web.jpg',
|
||||
height: _size.height,
|
||||
fit: BoxFit.fill,
|
||||
);
|
||||
} else {
|
||||
return SizedBox();
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
)),
|
||||
));
|
||||
}
|
||||
}
|
||||
540
lib/hrVerify.dart
Normal file
@ -0,0 +1,540 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:nhancepolicy/models/environment.dart';
|
||||
import 'package:pinput/pinput.dart';
|
||||
import 'dart:async';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:nhancepolicy/responsive.dart';
|
||||
import 'package:jwt_decode/jwt_decode.dart';
|
||||
|
||||
class MyHrVerify extends StatefulWidget {
|
||||
const MyHrVerify({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<MyHrVerify> createState() => _MyVerifyState();
|
||||
}
|
||||
|
||||
class _MyVerifyState extends State<MyHrVerify> {
|
||||
TextEditingController _otpController = TextEditingController();
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
late Timer _timer;
|
||||
int _secondsRemaining = 30;
|
||||
bool _isTimerRunning = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
// Start the timer when the widget is initialized
|
||||
startTimer();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_timer.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void startTimer() {
|
||||
_isTimerRunning = true;
|
||||
_timer = Timer.periodic(Duration(seconds: 1), (Timer timer) {
|
||||
setState(() {
|
||||
if (_secondsRemaining > 0) {
|
||||
_secondsRemaining--;
|
||||
} else {
|
||||
_isTimerRunning = false;
|
||||
_timer.cancel();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> resendOTP(String mobileNumber) async {
|
||||
print(mobileNumber);
|
||||
// Update the UI as needed
|
||||
setState(() {
|
||||
_secondsRemaining = 30;
|
||||
_isTimerRunning = true;
|
||||
});
|
||||
startTimer();
|
||||
try {
|
||||
final response = await http.post(
|
||||
Uri.parse(Environment.apiUrl + 'verifyHrWithMobileNumber'),
|
||||
body: json.encode({'mobile_number': mobileNumber}),
|
||||
headers: {
|
||||
HttpHeaders.contentTypeHeader: 'application/json',
|
||||
},
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
// Handle successful response
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('OTP resent successfully.'),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
// Handle other response status codes
|
||||
throw Exception('Failed to resend OTP');
|
||||
}
|
||||
} catch (e) {
|
||||
// Handle API call errors
|
||||
print('Error: $e');
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Failed to resend OTP. Please try again.'),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void verifyOTP(String otp) async {
|
||||
// Retrieve the passed mobile number value
|
||||
final String mobileNumber =
|
||||
ModalRoute.of(context)!.settings.arguments as String;
|
||||
try {
|
||||
final response = await http.post(
|
||||
Uri.parse(Environment.apiUrl + 'getVerifiedHrData'),
|
||||
body: json.encode({'mobile_number': mobileNumber, 'otp': otp}),
|
||||
headers: {
|
||||
HttpHeaders.contentTypeHeader: 'application/json',
|
||||
},
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
Map<String, dynamic> data = json.decode(response.body);
|
||||
print(data);
|
||||
String status = data['status'];
|
||||
print(status);
|
||||
if (status == 'success') {
|
||||
final SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
prefs.setString('token', data['data']);
|
||||
// Store data in local storage (if needed)
|
||||
// SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
// await prefs.setString('userData', json.encode(data['data']));
|
||||
|
||||
// Redirect to another page
|
||||
Navigator.pushNamed(context, 'hrHome');
|
||||
} else {
|
||||
// Show a Snackbar if the OTP is invalid
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Invalid OTP. Please try again.'),
|
||||
),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
throw Exception('Failed to verify OTP');
|
||||
}
|
||||
} catch (e) {
|
||||
print('Error: $e');
|
||||
// Show a Snackbar if there's an error while verifying OTP
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Failed to verify OTP. Please try again.'),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// Retrieve the passed mobile number value
|
||||
final String mobileNumber =
|
||||
ModalRoute.of(context)!.settings.arguments as String;
|
||||
Size _size = MediaQuery.of(context).size;
|
||||
EdgeInsets marginInsets = EdgeInsets.zero;
|
||||
if (Responsive.isDesktop(context)) {
|
||||
marginInsets = const EdgeInsets.only(
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
top: 0,
|
||||
);
|
||||
} else if (Responsive.isMobile(context)) {
|
||||
marginInsets = const EdgeInsets.only(
|
||||
left: 25, // Example value for mobile
|
||||
right: 25, // Example value for mobile
|
||||
bottom: 0, // Example value for mobile
|
||||
top: 0, // Example value for mobile
|
||||
);
|
||||
} else if (Responsive.isTablet(context)) {
|
||||
marginInsets = const EdgeInsets.only(
|
||||
left: 25, // Example value for mobile
|
||||
right: 25, // Example value for mobile
|
||||
bottom: 0, // Example value for mobile
|
||||
top: 0, // Example value for mobile
|
||||
);
|
||||
}
|
||||
final defaultPinTheme = PinTheme(
|
||||
width: 56,
|
||||
height: 56,
|
||||
textStyle: TextStyle(
|
||||
fontSize: 20,
|
||||
color: Color.fromRGBO(30, 60, 87, 1),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Color.fromRGBO(234, 239, 243, 1)),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
);
|
||||
|
||||
final focusedPinTheme = defaultPinTheme.copyDecorationWith(
|
||||
border: Border.all(color: Color.fromRGBO(114, 178, 238, 1)),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
);
|
||||
|
||||
final submittedPinTheme = defaultPinTheme.copyWith(
|
||||
decoration: defaultPinTheme.decoration?.copyWith(
|
||||
color: Color.fromRGBO(234, 239, 243, 1),
|
||||
),
|
||||
);
|
||||
|
||||
return Scaffold(
|
||||
// extendBodyBehindAppBar: true,
|
||||
// appBar: AppBar(
|
||||
// backgroundColor: Colors.transparent,
|
||||
// leading: IconButton(
|
||||
// onPressed: () {
|
||||
// Navigator.pop(context);
|
||||
// },
|
||||
// icon: Icon(
|
||||
// Icons.arrow_back_ios_rounded,
|
||||
// color: Colors.black,
|
||||
// ),
|
||||
// ),
|
||||
// elevation: 0,
|
||||
// ),
|
||||
body: Stack(children: [
|
||||
// First half of the screen with background color
|
||||
Visibility(
|
||||
visible: _size.width <=
|
||||
1100, // Show only for screen width less than or equal to 1100 (mobile view)
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.only(
|
||||
bottomLeft: Radius.circular(30), // Adjust border radius as needed
|
||||
bottomRight:
|
||||
Radius.circular(30), // Adjust border radius as needed
|
||||
),
|
||||
child: Container(
|
||||
height: _size.height / 3, // One-third of the screen height
|
||||
width: double.infinity, // Full width
|
||||
color: Color(0xFF00989E), // Your desired background color
|
||||
),
|
||||
),
|
||||
),
|
||||
// Second half of the screen with the content
|
||||
Container(
|
||||
margin: marginInsets, // Adjust bottom margin
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: SingleChildScrollView(
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: Column(children: [
|
||||
Row(children: [
|
||||
Expanded(
|
||||
flex: _size.width < 1100 ? 6 : 12,
|
||||
child: Container(
|
||||
margin: _size.width > 1100
|
||||
? EdgeInsets.only(left: 150, right: 150)
|
||||
: null,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
_size.width <= 1100
|
||||
? Image.asset(
|
||||
'assets/Nhance-Logo-Final-mobile.png',
|
||||
width: 150,
|
||||
height: 150,
|
||||
)
|
||||
: _size.width <= 1100
|
||||
? Image.asset(
|
||||
'assets/Nhance-Logo-Final 1.png',
|
||||
width: 150,
|
||||
height: 150,
|
||||
)
|
||||
: Image.asset(
|
||||
'assets/Nhance-Logo-Final 1.png',
|
||||
width: 150,
|
||||
height: 150,
|
||||
),
|
||||
SizedBox(
|
||||
height: _size.width <= 1100 ? 50 : 0,
|
||||
),
|
||||
Text(
|
||||
"Welcome to Nhance",
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold),
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
RichText(
|
||||
textAlign: TextAlign.center,
|
||||
text: TextSpan(
|
||||
text:
|
||||
"Please enter the one-time usage code sent to your mobile number $mobileNumber",
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
height: 1.5,
|
||||
color: Color(0xFF000000)),
|
||||
children: [
|
||||
TextSpan(
|
||||
text: " (Change Number)",
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Color(
|
||||
0xFFE26728)), // Change color as desired
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () {
|
||||
// Navigate to the page where the user can change the phone number
|
||||
Navigator.pushNamed(
|
||||
context, 'phone');
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: 30),
|
||||
Pinput(
|
||||
length: 6,
|
||||
// defaultPinTheme: defaultPinTheme,
|
||||
// focusedPinTheme: focusedPinTheme,
|
||||
// submittedPinTheme: submittedPinTheme,
|
||||
showCursor: true,
|
||||
controller: _otpController,
|
||||
),
|
||||
SizedBox(height: 15),
|
||||
SizedBox(height: 0),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment
|
||||
.end, // Align text to the right
|
||||
children: [
|
||||
_isTimerRunning
|
||||
? Text(
|
||||
"Resend OTP in $_secondsRemaining seconds",
|
||||
style: TextStyle(
|
||||
color: Colors.black),
|
||||
)
|
||||
: InkWell(
|
||||
onTap: () {
|
||||
resendOTP(mobileNumber);
|
||||
},
|
||||
child: Text(
|
||||
"Resend OTP",
|
||||
style: TextStyle(
|
||||
color: Colors.blue),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
height: 45,
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Color(0xFF00989E),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius:
|
||||
BorderRadius.circular(10),
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
if (_formKey.currentState!.validate()) {
|
||||
_formKey.currentState!
|
||||
.save(); // Save form fields before calling verifyOTP
|
||||
verifyOTP(_otpController.text);
|
||||
}
|
||||
},
|
||||
child: Text(
|
||||
"Submit",
|
||||
style:
|
||||
TextStyle(color: Color(0xFFFFFFFF)),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Row(
|
||||
// children: [
|
||||
// TextButton(
|
||||
// onPressed: () {
|
||||
// Navigator.pushNamedAndRemoveUntil(
|
||||
// context,
|
||||
// 'phone',
|
||||
// (route) => false,
|
||||
// );
|
||||
// },
|
||||
// child: Text("Edit Phone Number?",
|
||||
// style: TextStyle(
|
||||
// color: Color(0xFFE26728))),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
SizedBox(
|
||||
height: _size.width <= 1100 ? 0 : 0,
|
||||
), // Added SizedBox
|
||||
_size.width > 1100
|
||||
? // Conditionally rendering based on screen width
|
||||
Column(
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 15), // Added SizedBox
|
||||
Text(
|
||||
"Benefits of Login",
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 15),
|
||||
],
|
||||
)
|
||||
: SizedBox(), // Added SizedBox
|
||||
_size.width > 1100
|
||||
? Container(
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 6,
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
vertical: 8),
|
||||
// color: Colors.grey[200],
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.center,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: EdgeInsets
|
||||
.symmetric(
|
||||
vertical: 12),
|
||||
decoration:
|
||||
BoxDecoration(
|
||||
border: Border(
|
||||
right: BorderSide(
|
||||
width: 1,
|
||||
color: Colors
|
||||
.black,
|
||||
),
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Icon(Icons.policy,
|
||||
color: Color(
|
||||
0xFFE26728)),
|
||||
SizedBox(
|
||||
height: 10),
|
||||
Text(
|
||||
"View Policy"),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: EdgeInsets
|
||||
.symmetric(
|
||||
vertical: 12),
|
||||
child: Column(
|
||||
children: [
|
||||
Icon(Icons.edit,
|
||||
color: Color(
|
||||
0xFFE26728)),
|
||||
SizedBox(
|
||||
height: 10),
|
||||
Text(
|
||||
"Manage Claims"),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
: SizedBox(
|
||||
height: _size.height * 0.2,
|
||||
),
|
||||
SizedBox(
|
||||
height: _size.height * 0.1,
|
||||
),
|
||||
Container(
|
||||
alignment: Alignment.bottomCenter,
|
||||
padding: EdgeInsets.symmetric(vertical: 8),
|
||||
child: RichText(
|
||||
textAlign: TextAlign.center,
|
||||
text: TextSpan(
|
||||
text:
|
||||
'By continuing, you agree with our ',
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 9,
|
||||
),
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text: 'privacy policy ',
|
||||
style: TextStyle(
|
||||
color: Color(0xFF00989E),
|
||||
fontSize: 9,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: 'and ',
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 9,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: 'terms of use',
|
||||
style: TextStyle(
|
||||
color: Color(0xFF00989E),
|
||||
fontSize: 9,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)),
|
||||
if (_size.width >
|
||||
1100) // Render Expanded column only if screen width is greater than 600 (tablet or larger)
|
||||
Expanded(
|
||||
flex: _size.width < 1100
|
||||
? 6
|
||||
: 12, // Take 6 parts out of 12
|
||||
child: LayoutBuilder(
|
||||
builder: (BuildContext context,
|
||||
BoxConstraints constraints) {
|
||||
// Only show the image column if screen width is greater than 600 (tablet or larger)
|
||||
if (constraints.maxWidth > 600) {
|
||||
return Image.asset(
|
||||
'assets/login_web.jpg',
|
||||
height: _size.height,
|
||||
fit: BoxFit.fill,
|
||||
);
|
||||
} else {
|
||||
return SizedBox(); // If screen width is smaller, return an empty SizedBox
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
])
|
||||
]))))
|
||||
]),
|
||||
);
|
||||
}
|
||||
}
|
||||
27
lib/main.dart
Normal file
@ -0,0 +1,27 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:nhancepolicy/hrHome.dart';
|
||||
import 'package:nhancepolicy/hrVerify.dart';
|
||||
import 'package:nhancepolicy/models/environment.dart';
|
||||
import 'package:nhancepolicy/phone.dart';
|
||||
import 'package:nhancepolicy/verify.dart';
|
||||
import 'package:nhancepolicy/home.dart';
|
||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||
import 'package:nhancepolicy/hrLogin.dart';
|
||||
|
||||
Future<void> main() async {
|
||||
await dotenv.load(fileName: Environment.fileName);
|
||||
|
||||
runApp(MaterialApp(
|
||||
initialRoute: 'phone',
|
||||
debugShowCheckedModeBanner: false,
|
||||
routes: {
|
||||
'phone': (context) => MyPhone(),
|
||||
'verify': (context) => MyVerify(),
|
||||
'home': (context) => MyApp(),
|
||||
'hrLogin': (context) => MyHrLogin(),
|
||||
'hrVerify': (context) => MyHrVerify(),
|
||||
'hrHome': (context) => MyHrHome()
|
||||
},
|
||||
));
|
||||
}
|
||||
16
lib/models/environment.dart
Normal file
@ -0,0 +1,16 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||
|
||||
class Environment {
|
||||
static String get fileName {
|
||||
if (kReleaseMode) {
|
||||
return '.env.production';
|
||||
}
|
||||
|
||||
return '.env.development';
|
||||
}
|
||||
|
||||
static String get apiUrl {
|
||||
return dotenv.env['API_URL'] ?? 'API_URL not found!';
|
||||
}
|
||||
}
|
||||
454
lib/phone.dart
Normal file
@ -0,0 +1,454 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:nhancepolicy/models/environment.dart';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'package:nhancepolicy/responsive.dart';
|
||||
import 'package:nhancepolicy/customAppBar/toastHelper.dart';
|
||||
|
||||
class MyPhone extends StatefulWidget {
|
||||
const MyPhone({Key? key});
|
||||
|
||||
@override
|
||||
State<MyPhone> createState() => _MyPhoneState();
|
||||
}
|
||||
|
||||
class _MyPhoneState extends State<MyPhone> {
|
||||
TextEditingController countryController = TextEditingController();
|
||||
TextEditingController mobileController = TextEditingController();
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
countryController.text = "+91";
|
||||
super.initState();
|
||||
}
|
||||
|
||||
void toggleLoginType() {
|
||||
Navigator.pushNamed(context, 'hrLogin'); // Navigate to another page
|
||||
}
|
||||
|
||||
Future<bool> verifyMobileNumber(String mobileNumber) async {
|
||||
try {
|
||||
final response = await http.post(
|
||||
Uri.parse(Environment.apiUrl + 'verifyEmployeeNumber'),
|
||||
body: json.encode({'mobile_number': mobileNumber}),
|
||||
headers: {
|
||||
HttpHeaders.contentTypeHeader: 'application/json',
|
||||
},
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
Map<String, dynamic> data = json.decode(response.body);
|
||||
bool userVerification = data['data']['user_verification'];
|
||||
return userVerification;
|
||||
} else {
|
||||
throw Exception('Failed to verify mobile number');
|
||||
}
|
||||
} catch (e) {
|
||||
print('Error: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void handleSubmit() async {
|
||||
if (_formKey.currentState!.validate()) {
|
||||
// var enteredMobileNumber = countryController.text + mobileController.text;
|
||||
var enteredMobileNumber = mobileController.text;
|
||||
|
||||
bool isValid = await verifyMobileNumber(enteredMobileNumber);
|
||||
|
||||
if (isValid) {
|
||||
Navigator.pushNamed(context, 'verify', arguments: enteredMobileNumber);
|
||||
} else {
|
||||
ToastHelper.showErrorToast(context, 'Invalid mobile number');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Size _size = MediaQuery.of(context).size;
|
||||
EdgeInsets marginInsets = EdgeInsets.zero;
|
||||
|
||||
if (Responsive.isDesktop(context)) {
|
||||
marginInsets = const EdgeInsets.only(
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
top: 0,
|
||||
);
|
||||
} else if (Responsive.isMobile(context)) {
|
||||
marginInsets = const EdgeInsets.only(
|
||||
left: 25, // Example value for mobile
|
||||
right: 25, // Example value for mobile
|
||||
bottom: 0, // Example value for mobile
|
||||
top: 0, // Example value for mobile
|
||||
);
|
||||
} else if (Responsive.isTablet(context)) {
|
||||
marginInsets = const EdgeInsets.only(
|
||||
left: 25, //// Example value for mobile
|
||||
right: 25, // Example value for mobile
|
||||
bottom: 0, // Example value for mobile
|
||||
top: 0, // Example value for mobile
|
||||
);
|
||||
}
|
||||
return Scaffold(
|
||||
body: SingleChildScrollView(
|
||||
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
|
||||
child: Container(
|
||||
height: _size.height,
|
||||
color: Colors.white,
|
||||
child: Stack(
|
||||
children: [
|
||||
Visibility(
|
||||
visible: _size.width <= 1100,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.only(
|
||||
bottomLeft: Radius.circular(30),
|
||||
bottomRight: Radius.circular(30),
|
||||
),
|
||||
child: Container(
|
||||
height: _size.height / 3,
|
||||
width: double.infinity,
|
||||
color: Color(0xFF00989E),
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
margin: marginInsets,
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: SingleChildScrollView(
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: _size.width < 1100 ? 6 : 12,
|
||||
child: Container(
|
||||
margin: _size.width > 1100
|
||||
? EdgeInsets.only(left: 150, right: 150)
|
||||
: null,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
child: InkWell(
|
||||
onTap:
|
||||
toggleLoginType, // Call the toggleLoginType function on tap
|
||||
child: Container(
|
||||
// Add your text here
|
||||
child: Text(
|
||||
'HR Login',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Color(0xFF00989E)),
|
||||
),
|
||||
alignment: Alignment
|
||||
.centerRight, // Add padding
|
||||
),
|
||||
),
|
||||
),
|
||||
_size.width <= 1100
|
||||
? Image.asset(
|
||||
'assets/Nhance-Logo-Final-mobile.png',
|
||||
width: 150,
|
||||
height: 150,
|
||||
)
|
||||
: _size.width > 1100
|
||||
? Image.asset(
|
||||
'assets/Nhance-Logo-Final 1.png',
|
||||
width: 150,
|
||||
height: 150,
|
||||
)
|
||||
: Image.asset(
|
||||
'assets/Nhance-Logo-Final 1.png',
|
||||
width: 150,
|
||||
height: 150,
|
||||
),
|
||||
SizedBox(
|
||||
height: _size.width <= 1100 ? 50 : 0,
|
||||
),
|
||||
Text(
|
||||
"Welcome to Nhance Employee Login",
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
Text(
|
||||
"Have a Health Insurance Policy number, but never signed in? Don't worry, We got you covered",
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Color(0xFF000000)),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
SizedBox(
|
||||
height: 30,
|
||||
),
|
||||
Container(
|
||||
height: 55,
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
width: 1, color: Colors.grey),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
SizedBox(
|
||||
width: 40,
|
||||
child: TextField(
|
||||
controller: countryController,
|
||||
keyboardType:
|
||||
TextInputType.number,
|
||||
decoration: InputDecoration(
|
||||
border: InputBorder.none,
|
||||
),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
"|",
|
||||
style: TextStyle(
|
||||
fontSize: 33,
|
||||
color: Colors.grey),
|
||||
),
|
||||
SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
controller: mobileController,
|
||||
keyboardType: TextInputType.phone,
|
||||
decoration: InputDecoration(
|
||||
border: InputBorder.none,
|
||||
hintText:
|
||||
"Enter your mobile number",
|
||||
),
|
||||
validator: (value) {
|
||||
if (value == null ||
|
||||
value.isEmpty) {
|
||||
return 'Please enter your mobile number';
|
||||
}
|
||||
if (value.length != 10) {
|
||||
return 'Mobile number must be 10 digits';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
inputFormatters: <TextInputFormatter>[
|
||||
FilteringTextInputFormatter
|
||||
.digitsOnly,
|
||||
LengthLimitingTextInputFormatter(
|
||||
10),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
height: 45,
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Color(0xFF00989E),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius:
|
||||
BorderRadius.circular(10),
|
||||
),
|
||||
),
|
||||
onPressed: handleSubmit,
|
||||
child: Text(
|
||||
"Login With OTP",
|
||||
style: TextStyle(
|
||||
color: Color(0xFFFFFFFF)),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: _size.width <= 1100 ? 0 : 0,
|
||||
),
|
||||
_size.width > 1100
|
||||
? Column(
|
||||
children: [
|
||||
SizedBox(height: 30),
|
||||
Text(
|
||||
"Benefits of Login",
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 15),
|
||||
],
|
||||
)
|
||||
: SizedBox(),
|
||||
_size.width > 1100
|
||||
? Container(
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 6,
|
||||
child: Container(
|
||||
padding:
|
||||
EdgeInsets.symmetric(
|
||||
vertical: 8),
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.center,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: EdgeInsets
|
||||
.symmetric(
|
||||
vertical:
|
||||
12),
|
||||
decoration:
|
||||
BoxDecoration(
|
||||
border: Border(
|
||||
right:
|
||||
BorderSide(
|
||||
width: 1,
|
||||
color: Colors
|
||||
.black,
|
||||
),
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Icon(
|
||||
Icons
|
||||
.policy,
|
||||
color: Color(
|
||||
0xFFE26728)),
|
||||
SizedBox(
|
||||
height: 10),
|
||||
Text(
|
||||
"View Policy"),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: EdgeInsets
|
||||
.symmetric(
|
||||
vertical:
|
||||
12),
|
||||
child: Column(
|
||||
children: [
|
||||
Icon(Icons.edit,
|
||||
color: Color(
|
||||
0xFFE26728)),
|
||||
SizedBox(
|
||||
height: 10),
|
||||
Text(
|
||||
"Manage Claims"),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
: SizedBox(
|
||||
height: _size.height * 0.2,
|
||||
),
|
||||
SizedBox(
|
||||
height: _size.height * 0.1,
|
||||
),
|
||||
Container(
|
||||
alignment: Alignment.bottomCenter,
|
||||
padding:
|
||||
EdgeInsets.symmetric(vertical: 8),
|
||||
child: RichText(
|
||||
textAlign: TextAlign.center,
|
||||
text: TextSpan(
|
||||
text:
|
||||
'By continuing, you agree with our ',
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 9,
|
||||
),
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text: 'privacy policy ',
|
||||
style: TextStyle(
|
||||
color: Color(0xFF00989E),
|
||||
fontSize: 9,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: 'and ',
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 9,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: 'terms of use',
|
||||
style: TextStyle(
|
||||
color: Color(0xFF00989E),
|
||||
fontSize: 9,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
if (_size.width > 1100)
|
||||
Expanded(
|
||||
flex: _size.width < 1100 ? 6 : 12,
|
||||
child: LayoutBuilder(
|
||||
builder: (BuildContext context,
|
||||
BoxConstraints constraints) {
|
||||
if (constraints.maxWidth > 600) {
|
||||
return Image.asset(
|
||||
'assets/login_web.jpg',
|
||||
height: _size.height,
|
||||
fit: BoxFit.fill,
|
||||
);
|
||||
} else {
|
||||
return SizedBox();
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
)),
|
||||
));
|
||||
}
|
||||
}
|
||||
47
lib/responsive.dart
Normal file
@ -0,0 +1,47 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class Responsive extends StatelessWidget {
|
||||
final Widget mobile;
|
||||
final Widget tablet;
|
||||
final Widget desktop;
|
||||
|
||||
const Responsive({
|
||||
required Key key,
|
||||
required this.mobile,
|
||||
required this.tablet,
|
||||
required this.desktop,
|
||||
}) : super(key: key);
|
||||
|
||||
// This size work fine on my design, maybe you need some customization depends on your design
|
||||
|
||||
// This isMobile, isTablet, isDesktop helep us later
|
||||
static bool isMobile(BuildContext context) =>
|
||||
MediaQuery.of(context).size.width < 650;
|
||||
|
||||
static bool isTablet(BuildContext context) =>
|
||||
MediaQuery.of(context).size.width < 1100 &&
|
||||
MediaQuery.of(context).size.width >= 650;
|
||||
|
||||
static bool isDesktop(BuildContext context) =>
|
||||
MediaQuery.of(context).size.width >= 1100;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return LayoutBuilder(
|
||||
// If our width is more than 1100 then we consider it a desktop
|
||||
builder: (context, constraints) {
|
||||
if (constraints.maxWidth >= 1100) {
|
||||
return desktop;
|
||||
}
|
||||
// If width it less then 1100 and more then 650 we consider it as tablet
|
||||
else if (constraints.maxWidth >= 650) {
|
||||
return tablet;
|
||||
}
|
||||
// Or less then that we called it mobile
|
||||
else {
|
||||
return mobile;
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
527
lib/verify.dart
Normal file
@ -0,0 +1,527 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:nhancepolicy/models/environment.dart';
|
||||
import 'package:pinput/pinput.dart';
|
||||
import 'dart:async';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:nhancepolicy/responsive.dart';
|
||||
import 'package:jwt_decode/jwt_decode.dart';
|
||||
import 'package:nhancepolicy/customAppBar/toastHelper.dart';
|
||||
|
||||
class MyVerify extends StatefulWidget {
|
||||
const MyVerify({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<MyVerify> createState() => _MyVerifyState();
|
||||
}
|
||||
|
||||
class _MyVerifyState extends State<MyVerify> {
|
||||
TextEditingController _otpController = TextEditingController();
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
late Timer _timer;
|
||||
int _secondsRemaining = 30;
|
||||
bool _isTimerRunning = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
// Start the timer when the widget is initialized
|
||||
startTimer();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_timer.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void startTimer() {
|
||||
_isTimerRunning = true;
|
||||
_timer = Timer.periodic(Duration(seconds: 1), (Timer timer) {
|
||||
setState(() {
|
||||
if (_secondsRemaining > 0) {
|
||||
_secondsRemaining--;
|
||||
} else {
|
||||
_isTimerRunning = false;
|
||||
_timer.cancel();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> resendOTP(String mobileNumber) async {
|
||||
print(mobileNumber);
|
||||
// Update the UI as needed
|
||||
setState(() {
|
||||
_secondsRemaining = 30;
|
||||
_isTimerRunning = true;
|
||||
});
|
||||
startTimer();
|
||||
try {
|
||||
final response = await http.post(
|
||||
Uri.parse(Environment.apiUrl + 'verifyEmployeeNumber'),
|
||||
body: json.encode({'mobile_number': mobileNumber}),
|
||||
headers: {
|
||||
HttpHeaders.contentTypeHeader: 'application/json',
|
||||
},
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
// Handle successful response
|
||||
ToastHelper.showSuccessToast(context, 'OTP resent successfully');
|
||||
} else {
|
||||
// Handle other response status codes
|
||||
throw Exception('Failed to resend OTP');
|
||||
}
|
||||
} catch (e) {
|
||||
// Handle API call errors
|
||||
print('Error: $e');
|
||||
ToastHelper.showErrorToast(
|
||||
context, 'Failed to resend OTP. Please try again.');
|
||||
}
|
||||
}
|
||||
|
||||
void verifyOTP(String otp) async {
|
||||
// Retrieve the passed mobile number value
|
||||
final String mobileNumber =
|
||||
ModalRoute.of(context)!.settings.arguments as String;
|
||||
try {
|
||||
final response = await http.post(
|
||||
Uri.parse(Environment.apiUrl + 'getVerifiedUserData'),
|
||||
body: json.encode({'mobile_number': mobileNumber, 'otp': otp}),
|
||||
headers: {
|
||||
HttpHeaders.contentTypeHeader: 'application/json',
|
||||
},
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
Map<String, dynamic> data = json.decode(response.body);
|
||||
print(data);
|
||||
String status = data['status'];
|
||||
print(status);
|
||||
if (status == 'success') {
|
||||
final SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
prefs.setString('token', data['data']);
|
||||
// Store data in local storage (if needed)
|
||||
// SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
// await prefs.setString('userData', json.encode(data['data']));
|
||||
ToastHelper.showSuccessToast(context, 'Successfully Login');
|
||||
// Redirect to another page
|
||||
Navigator.pushNamed(context, 'home');
|
||||
} else {
|
||||
// Show a Snackbar if the OTP is invalid
|
||||
ToastHelper.showErrorToast(context, 'Invalid OTP. Please try again');
|
||||
}
|
||||
} else {
|
||||
throw Exception('Failed to verify OTP');
|
||||
}
|
||||
} catch (e) {
|
||||
print('Error: $e');
|
||||
// Show a Snackbar if there's an error while verifying OTP
|
||||
ToastHelper.showErrorToast(
|
||||
context, 'Failed to verify OTP. Please try again.');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// Retrieve the passed mobile number value
|
||||
final String mobileNumber =
|
||||
ModalRoute.of(context)!.settings.arguments as String;
|
||||
Size _size = MediaQuery.of(context).size;
|
||||
EdgeInsets marginInsets = EdgeInsets.zero;
|
||||
if (Responsive.isDesktop(context)) {
|
||||
marginInsets = const EdgeInsets.only(
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
top: 0,
|
||||
);
|
||||
} else if (Responsive.isMobile(context)) {
|
||||
marginInsets = const EdgeInsets.only(
|
||||
left: 25, // Example value for mobile
|
||||
right: 25, // Example value for mobile
|
||||
bottom: 0, // Example value for mobile
|
||||
top: 0, // Example value for mobile
|
||||
);
|
||||
} else if (Responsive.isTablet(context)) {
|
||||
marginInsets = const EdgeInsets.only(
|
||||
left: 25, // Example value for mobile
|
||||
right: 25, // Example value for mobile
|
||||
bottom: 0, // Example value for mobile
|
||||
top: 0, // Example value for mobile
|
||||
);
|
||||
}
|
||||
final defaultPinTheme = PinTheme(
|
||||
width: 56,
|
||||
height: 56,
|
||||
textStyle: TextStyle(
|
||||
fontSize: 20,
|
||||
color: Color.fromRGBO(30, 60, 87, 1),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Color.fromRGBO(234, 239, 243, 1)),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
);
|
||||
|
||||
final focusedPinTheme = defaultPinTheme.copyDecorationWith(
|
||||
border: Border.all(color: Color.fromRGBO(114, 178, 238, 1)),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
);
|
||||
|
||||
final submittedPinTheme = defaultPinTheme.copyWith(
|
||||
decoration: defaultPinTheme.decoration?.copyWith(
|
||||
color: Color.fromRGBO(234, 239, 243, 1),
|
||||
),
|
||||
);
|
||||
|
||||
return Scaffold(
|
||||
// extendBodyBehindAppBar: true,
|
||||
// appBar: AppBar(
|
||||
// backgroundColor: Colors.transparent,
|
||||
// leading: IconButton(
|
||||
// onPressed: () {
|
||||
// Navigator.pop(context);
|
||||
// },
|
||||
// icon: Icon(
|
||||
// Icons.arrow_back_ios_rounded,
|
||||
// color: Colors.black,
|
||||
// ),
|
||||
// ),
|
||||
// elevation: 0,
|
||||
// ),
|
||||
body: Stack(children: [
|
||||
// First half of the screen with background color
|
||||
Visibility(
|
||||
visible: _size.width <=
|
||||
1100, // Show only for screen width less than or equal to 1100 (mobile view)
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.only(
|
||||
bottomLeft: Radius.circular(30), // Adjust border radius as needed
|
||||
bottomRight:
|
||||
Radius.circular(30), // Adjust border radius as needed
|
||||
),
|
||||
child: Container(
|
||||
height: _size.height / 3, // One-third of the screen height
|
||||
width: double.infinity, // Full width
|
||||
color: Color(0xFF00989E), // Your desired background color
|
||||
),
|
||||
),
|
||||
),
|
||||
// Second half of the screen with the content
|
||||
Container(
|
||||
margin: marginInsets, // Adjust bottom margin
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: SingleChildScrollView(
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: Column(children: [
|
||||
Row(children: [
|
||||
Expanded(
|
||||
flex: _size.width < 1100 ? 6 : 12,
|
||||
child: Container(
|
||||
margin: _size.width > 1100
|
||||
? EdgeInsets.only(left: 150, right: 150)
|
||||
: null,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
_size.width <= 1100
|
||||
? Image.asset(
|
||||
'assets/Nhance-Logo-Final-mobile.png',
|
||||
width: 150,
|
||||
height: 150,
|
||||
)
|
||||
: _size.width <= 1100
|
||||
? Image.asset(
|
||||
'assets/Nhance-Logo-Final 1.png',
|
||||
width: 150,
|
||||
height: 150,
|
||||
)
|
||||
: Image.asset(
|
||||
'assets/Nhance-Logo-Final 1.png',
|
||||
width: 150,
|
||||
height: 150,
|
||||
),
|
||||
SizedBox(
|
||||
height: _size.width <= 1100 ? 50 : 0,
|
||||
),
|
||||
Text(
|
||||
"Welcome to Nhance",
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold),
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
RichText(
|
||||
textAlign: TextAlign.center,
|
||||
text: TextSpan(
|
||||
text:
|
||||
"Please enter the one-time usage code sent to your mobile number $mobileNumber",
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
height: 1.5,
|
||||
color: Color(0xFF000000)),
|
||||
children: [
|
||||
TextSpan(
|
||||
text: " (Change Number)",
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Color(
|
||||
0xFFE26728)), // Change color as desired
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () {
|
||||
// Navigate to the page where the user can change the phone number
|
||||
Navigator.pushNamed(
|
||||
context, 'phone');
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: 30),
|
||||
Pinput(
|
||||
length: 6,
|
||||
// defaultPinTheme: defaultPinTheme,
|
||||
// focusedPinTheme: focusedPinTheme,
|
||||
// submittedPinTheme: submittedPinTheme,
|
||||
showCursor: true,
|
||||
controller: _otpController,
|
||||
),
|
||||
SizedBox(height: 15),
|
||||
SizedBox(height: 0),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment
|
||||
.end, // Align text to the right
|
||||
children: [
|
||||
_isTimerRunning
|
||||
? Text(
|
||||
"Resend OTP in $_secondsRemaining seconds",
|
||||
style: TextStyle(
|
||||
color: Colors.black),
|
||||
)
|
||||
: InkWell(
|
||||
onTap: () {
|
||||
resendOTP(mobileNumber);
|
||||
},
|
||||
child: Text(
|
||||
"Resend OTP",
|
||||
style: TextStyle(
|
||||
color: Colors.blue),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
height: 45,
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Color(0xFF00989E),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius:
|
||||
BorderRadius.circular(10),
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
if (_formKey.currentState!.validate()) {
|
||||
_formKey.currentState!
|
||||
.save(); // Save form fields before calling verifyOTP
|
||||
verifyOTP(_otpController.text);
|
||||
}
|
||||
},
|
||||
child: Text(
|
||||
"Submit",
|
||||
style:
|
||||
TextStyle(color: Color(0xFFFFFFFF)),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Row(
|
||||
// children: [
|
||||
// TextButton(
|
||||
// onPressed: () {
|
||||
// Navigator.pushNamedAndRemoveUntil(
|
||||
// context,
|
||||
// 'phone',
|
||||
// (route) => false,
|
||||
// );
|
||||
// },
|
||||
// child: Text("Edit Phone Number?",
|
||||
// style: TextStyle(
|
||||
// color: Color(0xFFE26728))),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
SizedBox(
|
||||
height: _size.width <= 1100 ? 0 : 0,
|
||||
), // Added SizedBox
|
||||
_size.width > 1100
|
||||
? // Conditionally rendering based on screen width
|
||||
Column(
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 15), // Added SizedBox
|
||||
Text(
|
||||
"Benefits of Login",
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 15),
|
||||
],
|
||||
)
|
||||
: SizedBox(), // Added SizedBox
|
||||
_size.width > 1100
|
||||
? Container(
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 6,
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
vertical: 8),
|
||||
// color: Colors.grey[200],
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.center,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: EdgeInsets
|
||||
.symmetric(
|
||||
vertical: 12),
|
||||
decoration:
|
||||
BoxDecoration(
|
||||
border: Border(
|
||||
right: BorderSide(
|
||||
width: 1,
|
||||
color: Colors
|
||||
.black,
|
||||
),
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Icon(Icons.policy,
|
||||
color: Color(
|
||||
0xFFE26728)),
|
||||
SizedBox(
|
||||
height: 10),
|
||||
Text(
|
||||
"View Policy"),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: EdgeInsets
|
||||
.symmetric(
|
||||
vertical: 12),
|
||||
child: Column(
|
||||
children: [
|
||||
Icon(Icons.edit,
|
||||
color: Color(
|
||||
0xFFE26728)),
|
||||
SizedBox(
|
||||
height: 10),
|
||||
Text(
|
||||
"Manage Claims"),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
: SizedBox(
|
||||
height: _size.height * 0.2,
|
||||
),
|
||||
SizedBox(
|
||||
height: _size.height * 0.1,
|
||||
),
|
||||
Container(
|
||||
alignment: Alignment.bottomCenter,
|
||||
padding: EdgeInsets.symmetric(vertical: 8),
|
||||
child: RichText(
|
||||
textAlign: TextAlign.center,
|
||||
text: TextSpan(
|
||||
text:
|
||||
'By continuing, you agree with our ',
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 9,
|
||||
),
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text: 'privacy policy ',
|
||||
style: TextStyle(
|
||||
color: Color(0xFF00989E),
|
||||
fontSize: 9,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: 'and ',
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 9,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: 'terms of use',
|
||||
style: TextStyle(
|
||||
color: Color(0xFF00989E),
|
||||
fontSize: 9,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)),
|
||||
if (_size.width >
|
||||
1100) // Render Expanded column only if screen width is greater than 600 (tablet or larger)
|
||||
Expanded(
|
||||
flex: _size.width < 1100
|
||||
? 6
|
||||
: 12, // Take 6 parts out of 12
|
||||
child: LayoutBuilder(
|
||||
builder: (BuildContext context,
|
||||
BoxConstraints constraints) {
|
||||
// Only show the image column if screen width is greater than 600 (tablet or larger)
|
||||
if (constraints.maxWidth > 600) {
|
||||
return Image.asset(
|
||||
'assets/login_web.jpg',
|
||||
height: _size.height,
|
||||
fit: BoxFit.fill,
|
||||
);
|
||||
} else {
|
||||
return SizedBox(); // If screen width is smaller, return an empty SizedBox
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
])
|
||||
]))))
|
||||
]),
|
||||
);
|
||||
}
|
||||
}
|
||||
1
linux/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
flutter/ephemeral
|
||||
145
linux/CMakeLists.txt
Normal file
@ -0,0 +1,145 @@
|
||||
# Project-level configuration.
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
project(runner LANGUAGES CXX)
|
||||
|
||||
# The name of the executable created for the application. Change this to change
|
||||
# the on-disk name of your application.
|
||||
set(BINARY_NAME "nhancepolicy")
|
||||
# The unique GTK application identifier for this application. See:
|
||||
# https://wiki.gnome.org/HowDoI/ChooseApplicationID
|
||||
set(APPLICATION_ID "com.example.nhancepolicy")
|
||||
|
||||
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
|
||||
# versions of CMake.
|
||||
cmake_policy(SET CMP0063 NEW)
|
||||
|
||||
# Load bundled libraries from the lib/ directory relative to the binary.
|
||||
set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
|
||||
|
||||
# Root filesystem for cross-building.
|
||||
if(FLUTTER_TARGET_PLATFORM_SYSROOT)
|
||||
set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT})
|
||||
set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
endif()
|
||||
|
||||
# Define build configuration options.
|
||||
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
set(CMAKE_BUILD_TYPE "Debug" CACHE
|
||||
STRING "Flutter build mode" FORCE)
|
||||
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
|
||||
"Debug" "Profile" "Release")
|
||||
endif()
|
||||
|
||||
# Compilation settings that should be applied to most targets.
|
||||
#
|
||||
# Be cautious about adding new options here, as plugins use this function by
|
||||
# default. In most cases, you should add new options to specific targets instead
|
||||
# of modifying this function.
|
||||
function(APPLY_STANDARD_SETTINGS TARGET)
|
||||
target_compile_features(${TARGET} PUBLIC cxx_std_14)
|
||||
target_compile_options(${TARGET} PRIVATE -Wall -Werror)
|
||||
target_compile_options(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O3>")
|
||||
target_compile_definitions(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:NDEBUG>")
|
||||
endfunction()
|
||||
|
||||
# Flutter library and tool build rules.
|
||||
set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
|
||||
add_subdirectory(${FLUTTER_MANAGED_DIR})
|
||||
|
||||
# System-level dependencies.
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
|
||||
|
||||
add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}")
|
||||
|
||||
# Define the application target. To change its name, change BINARY_NAME above,
|
||||
# not the value here, or `flutter run` will no longer work.
|
||||
#
|
||||
# Any new source files that you add to the application should be added here.
|
||||
add_executable(${BINARY_NAME}
|
||||
"main.cc"
|
||||
"my_application.cc"
|
||||
"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
|
||||
)
|
||||
|
||||
# Apply the standard set of build settings. This can be removed for applications
|
||||
# that need different build settings.
|
||||
apply_standard_settings(${BINARY_NAME})
|
||||
|
||||
# Add dependency libraries. Add any application-specific dependencies here.
|
||||
target_link_libraries(${BINARY_NAME} PRIVATE flutter)
|
||||
target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK)
|
||||
|
||||
# Run the Flutter tool portions of the build. This must not be removed.
|
||||
add_dependencies(${BINARY_NAME} flutter_assemble)
|
||||
|
||||
# Only the install-generated bundle's copy of the executable will launch
|
||||
# correctly, since the resources must in the right relative locations. To avoid
|
||||
# people trying to run the unbundled copy, put it in a subdirectory instead of
|
||||
# the default top-level location.
|
||||
set_target_properties(${BINARY_NAME}
|
||||
PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run"
|
||||
)
|
||||
|
||||
|
||||
# Generated plugin build rules, which manage building the plugins and adding
|
||||
# them to the application.
|
||||
include(flutter/generated_plugins.cmake)
|
||||
|
||||
|
||||
# === Installation ===
|
||||
# By default, "installing" just makes a relocatable bundle in the build
|
||||
# directory.
|
||||
set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle")
|
||||
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
|
||||
set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
|
||||
endif()
|
||||
|
||||
# Start with a clean build bundle directory every time.
|
||||
install(CODE "
|
||||
file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\")
|
||||
" COMPONENT Runtime)
|
||||
|
||||
set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
|
||||
set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib")
|
||||
|
||||
install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
|
||||
COMPONENT Runtime)
|
||||
|
||||
install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
|
||||
COMPONENT Runtime)
|
||||
|
||||
install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
||||
COMPONENT Runtime)
|
||||
|
||||
foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES})
|
||||
install(FILES "${bundled_library}"
|
||||
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
||||
COMPONENT Runtime)
|
||||
endforeach(bundled_library)
|
||||
|
||||
# Copy the native assets provided by the build.dart from all packages.
|
||||
set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/")
|
||||
install(DIRECTORY "${NATIVE_ASSETS_DIR}"
|
||||
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
||||
COMPONENT Runtime)
|
||||
|
||||
# Fully re-copy the assets directory on each build to avoid having stale files
|
||||
# from a previous install.
|
||||
set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
|
||||
install(CODE "
|
||||
file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
|
||||
" COMPONENT Runtime)
|
||||
install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
|
||||
DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
|
||||
|
||||
# Install the AOT library on non-Debug builds only.
|
||||
if(NOT CMAKE_BUILD_TYPE MATCHES "Debug")
|
||||
install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
||||
COMPONENT Runtime)
|
||||
endif()
|
||||
88
linux/flutter/CMakeLists.txt
Normal file
@ -0,0 +1,88 @@
|
||||
# This file controls Flutter-level build steps. It should not be edited.
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
|
||||
|
||||
# Configuration provided via flutter tool.
|
||||
include(${EPHEMERAL_DIR}/generated_config.cmake)
|
||||
|
||||
# TODO: Move the rest of this into files in ephemeral. See
|
||||
# https://github.com/flutter/flutter/issues/57146.
|
||||
|
||||
# Serves the same purpose as list(TRANSFORM ... PREPEND ...),
|
||||
# which isn't available in 3.10.
|
||||
function(list_prepend LIST_NAME PREFIX)
|
||||
set(NEW_LIST "")
|
||||
foreach(element ${${LIST_NAME}})
|
||||
list(APPEND NEW_LIST "${PREFIX}${element}")
|
||||
endforeach(element)
|
||||
set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# === Flutter Library ===
|
||||
# System-level dependencies.
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
|
||||
pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0)
|
||||
pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0)
|
||||
|
||||
set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so")
|
||||
|
||||
# Published to parent scope for install step.
|
||||
set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
|
||||
set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
|
||||
set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
|
||||
set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE)
|
||||
|
||||
list(APPEND FLUTTER_LIBRARY_HEADERS
|
||||
"fl_basic_message_channel.h"
|
||||
"fl_binary_codec.h"
|
||||
"fl_binary_messenger.h"
|
||||
"fl_dart_project.h"
|
||||
"fl_engine.h"
|
||||
"fl_json_message_codec.h"
|
||||
"fl_json_method_codec.h"
|
||||
"fl_message_codec.h"
|
||||
"fl_method_call.h"
|
||||
"fl_method_channel.h"
|
||||
"fl_method_codec.h"
|
||||
"fl_method_response.h"
|
||||
"fl_plugin_registrar.h"
|
||||
"fl_plugin_registry.h"
|
||||
"fl_standard_message_codec.h"
|
||||
"fl_standard_method_codec.h"
|
||||
"fl_string_codec.h"
|
||||
"fl_value.h"
|
||||
"fl_view.h"
|
||||
"flutter_linux.h"
|
||||
)
|
||||
list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/")
|
||||
add_library(flutter INTERFACE)
|
||||
target_include_directories(flutter INTERFACE
|
||||
"${EPHEMERAL_DIR}"
|
||||
)
|
||||
target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}")
|
||||
target_link_libraries(flutter INTERFACE
|
||||
PkgConfig::GTK
|
||||
PkgConfig::GLIB
|
||||
PkgConfig::GIO
|
||||
)
|
||||
add_dependencies(flutter flutter_assemble)
|
||||
|
||||
# === Flutter tool backend ===
|
||||
# _phony_ is a non-existent file to force this command to run every time,
|
||||
# since currently there's no way to get a full input/output list from the
|
||||
# flutter tool.
|
||||
add_custom_command(
|
||||
OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
|
||||
${CMAKE_CURRENT_BINARY_DIR}/_phony_
|
||||
COMMAND ${CMAKE_COMMAND} -E env
|
||||
${FLUTTER_TOOL_ENVIRONMENT}
|
||||
"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh"
|
||||
${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE}
|
||||
VERBATIM
|
||||
)
|
||||
add_custom_target(flutter_assemble DEPENDS
|
||||
"${FLUTTER_LIBRARY}"
|
||||
${FLUTTER_LIBRARY_HEADERS}
|
||||
)
|
||||
15
linux/flutter/generated_plugin_registrant.cc
Normal file
@ -0,0 +1,15 @@
|
||||
//
|
||||
// Generated file. Do not edit.
|
||||
//
|
||||
|
||||
// clang-format off
|
||||
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <smart_auth/smart_auth_plugin.h>
|
||||
|
||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
||||
g_autoptr(FlPluginRegistrar) smart_auth_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "SmartAuthPlugin");
|
||||
smart_auth_plugin_register_with_registrar(smart_auth_registrar);
|
||||
}
|
||||
15
linux/flutter/generated_plugin_registrant.h
Normal file
@ -0,0 +1,15 @@
|
||||
//
|
||||
// Generated file. Do not edit.
|
||||
//
|
||||
|
||||
// clang-format off
|
||||
|
||||
#ifndef GENERATED_PLUGIN_REGISTRANT_
|
||||
#define GENERATED_PLUGIN_REGISTRANT_
|
||||
|
||||
#include <flutter_linux/flutter_linux.h>
|
||||
|
||||
// Registers Flutter plugins.
|
||||
void fl_register_plugins(FlPluginRegistry* registry);
|
||||
|
||||
#endif // GENERATED_PLUGIN_REGISTRANT_
|
||||
24
linux/flutter/generated_plugins.cmake
Normal file
@ -0,0 +1,24 @@
|
||||
#
|
||||
# Generated file, do not edit.
|
||||
#
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
smart_auth
|
||||
)
|
||||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||
)
|
||||
|
||||
set(PLUGIN_BUNDLED_LIBRARIES)
|
||||
|
||||
foreach(plugin ${FLUTTER_PLUGIN_LIST})
|
||||
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin})
|
||||
target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
|
||||
list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)
|
||||
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
|
||||
endforeach(plugin)
|
||||
|
||||
foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
|
||||
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin})
|
||||
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
|
||||
endforeach(ffi_plugin)
|
||||
6
linux/main.cc
Normal file
@ -0,0 +1,6 @@
|
||||
#include "my_application.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
g_autoptr(MyApplication) app = my_application_new();
|
||||
return g_application_run(G_APPLICATION(app), argc, argv);
|
||||
}
|
||||
124
linux/my_application.cc
Normal file
@ -0,0 +1,124 @@
|
||||
#include "my_application.h"
|
||||
|
||||
#include <flutter_linux/flutter_linux.h>
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
#include <gdk/gdkx.h>
|
||||
#endif
|
||||
|
||||
#include "flutter/generated_plugin_registrant.h"
|
||||
|
||||
struct _MyApplication {
|
||||
GtkApplication parent_instance;
|
||||
char** dart_entrypoint_arguments;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION)
|
||||
|
||||
// Implements GApplication::activate.
|
||||
static void my_application_activate(GApplication* application) {
|
||||
MyApplication* self = MY_APPLICATION(application);
|
||||
GtkWindow* window =
|
||||
GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));
|
||||
|
||||
// Use a header bar when running in GNOME as this is the common style used
|
||||
// by applications and is the setup most users will be using (e.g. Ubuntu
|
||||
// desktop).
|
||||
// If running on X and not using GNOME then just use a traditional title bar
|
||||
// in case the window manager does more exotic layout, e.g. tiling.
|
||||
// If running on Wayland assume the header bar will work (may need changing
|
||||
// if future cases occur).
|
||||
gboolean use_header_bar = TRUE;
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
GdkScreen* screen = gtk_window_get_screen(window);
|
||||
if (GDK_IS_X11_SCREEN(screen)) {
|
||||
const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen);
|
||||
if (g_strcmp0(wm_name, "GNOME Shell") != 0) {
|
||||
use_header_bar = FALSE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (use_header_bar) {
|
||||
GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new());
|
||||
gtk_widget_show(GTK_WIDGET(header_bar));
|
||||
gtk_header_bar_set_title(header_bar, "nhancepolicy");
|
||||
gtk_header_bar_set_show_close_button(header_bar, TRUE);
|
||||
gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));
|
||||
} else {
|
||||
gtk_window_set_title(window, "nhancepolicy");
|
||||
}
|
||||
|
||||
gtk_window_set_default_size(window, 1280, 720);
|
||||
gtk_widget_show(GTK_WIDGET(window));
|
||||
|
||||
g_autoptr(FlDartProject) project = fl_dart_project_new();
|
||||
fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments);
|
||||
|
||||
FlView* view = fl_view_new(project);
|
||||
gtk_widget_show(GTK_WIDGET(view));
|
||||
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view));
|
||||
|
||||
fl_register_plugins(FL_PLUGIN_REGISTRY(view));
|
||||
|
||||
gtk_widget_grab_focus(GTK_WIDGET(view));
|
||||
}
|
||||
|
||||
// Implements GApplication::local_command_line.
|
||||
static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) {
|
||||
MyApplication* self = MY_APPLICATION(application);
|
||||
// Strip out the first argument as it is the binary name.
|
||||
self->dart_entrypoint_arguments = g_strdupv(*arguments + 1);
|
||||
|
||||
g_autoptr(GError) error = nullptr;
|
||||
if (!g_application_register(application, nullptr, &error)) {
|
||||
g_warning("Failed to register: %s", error->message);
|
||||
*exit_status = 1;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
g_application_activate(application);
|
||||
*exit_status = 0;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Implements GApplication::startup.
|
||||
static void my_application_startup(GApplication* application) {
|
||||
//MyApplication* self = MY_APPLICATION(object);
|
||||
|
||||
// Perform any actions required at application startup.
|
||||
|
||||
G_APPLICATION_CLASS(my_application_parent_class)->startup(application);
|
||||
}
|
||||
|
||||
// Implements GApplication::shutdown.
|
||||
static void my_application_shutdown(GApplication* application) {
|
||||
//MyApplication* self = MY_APPLICATION(object);
|
||||
|
||||
// Perform any actions required at application shutdown.
|
||||
|
||||
G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application);
|
||||
}
|
||||
|
||||
// Implements GObject::dispose.
|
||||
static void my_application_dispose(GObject* object) {
|
||||
MyApplication* self = MY_APPLICATION(object);
|
||||
g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev);
|
||||
G_OBJECT_CLASS(my_application_parent_class)->dispose(object);
|
||||
}
|
||||
|
||||
static void my_application_class_init(MyApplicationClass* klass) {
|
||||
G_APPLICATION_CLASS(klass)->activate = my_application_activate;
|
||||
G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line;
|
||||
G_APPLICATION_CLASS(klass)->startup = my_application_startup;
|
||||
G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown;
|
||||
G_OBJECT_CLASS(klass)->dispose = my_application_dispose;
|
||||
}
|
||||
|
||||
static void my_application_init(MyApplication* self) {}
|
||||
|
||||
MyApplication* my_application_new() {
|
||||
return MY_APPLICATION(g_object_new(my_application_get_type(),
|
||||
"application-id", APPLICATION_ID,
|
||||
"flags", G_APPLICATION_NON_UNIQUE,
|
||||
nullptr));
|
||||
}
|
||||
18
linux/my_application.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef FLUTTER_MY_APPLICATION_H_
|
||||
#define FLUTTER_MY_APPLICATION_H_
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION,
|
||||
GtkApplication)
|
||||
|
||||
/**
|
||||
* my_application_new:
|
||||
*
|
||||
* Creates a new Flutter-based application.
|
||||
*
|
||||
* Returns: a new #MyApplication.
|
||||
*/
|
||||
MyApplication* my_application_new();
|
||||
|
||||
#endif // FLUTTER_MY_APPLICATION_H_
|
||||
7
macos/.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
# Flutter-related
|
||||
**/Flutter/ephemeral/
|
||||
**/Pods/
|
||||
|
||||
# Xcode-related
|
||||
**/dgph
|
||||
**/xcuserdata/
|
||||
1
macos/Flutter/Flutter-Debug.xcconfig
Normal file
@ -0,0 +1 @@
|
||||
#include "ephemeral/Flutter-Generated.xcconfig"
|
||||
1
macos/Flutter/Flutter-Release.xcconfig
Normal file
@ -0,0 +1 @@
|
||||
#include "ephemeral/Flutter-Generated.xcconfig"
|
||||
16
macos/Flutter/GeneratedPluginRegistrant.swift
Normal file
@ -0,0 +1,16 @@
|
||||
//
|
||||
// Generated file. Do not edit.
|
||||
//
|
||||
|
||||
import FlutterMacOS
|
||||
import Foundation
|
||||
|
||||
import path_provider_foundation
|
||||
import shared_preferences_foundation
|
||||
import smart_auth
|
||||
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||
SmartAuthPlugin.register(with: registry.registrar(forPlugin: "SmartAuthPlugin"))
|
||||
}
|
||||
9
macos/Runner/AppDelegate.swift
Normal file
@ -0,0 +1,9 @@
|
||||
import Cocoa
|
||||
import FlutterMacOS
|
||||
|
||||
@NSApplicationMain
|
||||
class AppDelegate: FlutterAppDelegate {
|
||||
override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,68 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"size" : "16x16",
|
||||
"idiom" : "mac",
|
||||
"filename" : "app_icon_16.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "16x16",
|
||||
"idiom" : "mac",
|
||||
"filename" : "app_icon_32.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "32x32",
|
||||
"idiom" : "mac",
|
||||
"filename" : "app_icon_32.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "32x32",
|
||||
"idiom" : "mac",
|
||||
"filename" : "app_icon_64.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "128x128",
|
||||
"idiom" : "mac",
|
||||
"filename" : "app_icon_128.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "128x128",
|
||||
"idiom" : "mac",
|
||||
"filename" : "app_icon_256.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "256x256",
|
||||
"idiom" : "mac",
|
||||
"filename" : "app_icon_256.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "256x256",
|
||||
"idiom" : "mac",
|
||||
"filename" : "app_icon_512.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "512x512",
|
||||
"idiom" : "mac",
|
||||
"filename" : "app_icon_512.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "512x512",
|
||||
"idiom" : "mac",
|
||||
"filename" : "app_icon_1024.png",
|
||||
"scale" : "2x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 101 KiB |
BIN
macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
BIN
macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png
Normal file
|
After Width: | Height: | Size: 520 B |
BIN
macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
343
macos/Runner/Base.lproj/MainMenu.xib
Normal file
@ -0,0 +1,343 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14490.70"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
|
||||
<connections>
|
||||
<outlet property="delegate" destination="Voe-Tx-rLC" id="GzC-gU-4Uq"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="Runner" customModuleProvider="target">
|
||||
<connections>
|
||||
<outlet property="applicationMenu" destination="uQy-DD-JDr" id="XBo-yE-nKs"/>
|
||||
<outlet property="mainFlutterWindow" destination="QvC-M9-y7g" id="gIp-Ho-8D9"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<customObject id="YLy-65-1bz" customClass="NSFontManager"/>
|
||||
<menu title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
|
||||
<items>
|
||||
<menuItem title="APP_NAME" id="1Xt-HY-uBw">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="APP_NAME" systemMenu="apple" id="uQy-DD-JDr">
|
||||
<items>
|
||||
<menuItem title="About APP_NAME" id="5kV-Vb-QxS">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="orderFrontStandardAboutPanel:" target="-1" id="Exp-CZ-Vem"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
|
||||
<menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW"/>
|
||||
<menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/>
|
||||
<menuItem title="Services" id="NMo-om-nkz">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
|
||||
<menuItem title="Hide APP_NAME" keyEquivalent="h" id="Olw-nP-bQN">
|
||||
<connections>
|
||||
<action selector="hide:" target="-1" id="PnN-Uc-m68"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
|
||||
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="hideOtherApplications:" target="-1" id="VT4-aY-XCT"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Show All" id="Kd2-mp-pUS">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="unhideAllApplications:" target="-1" id="Dhg-Le-xox"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
|
||||
<menuItem title="Quit APP_NAME" keyEquivalent="q" id="4sb-4s-VLi">
|
||||
<connections>
|
||||
<action selector="terminate:" target="-1" id="Te7-pn-YzF"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Edit" id="5QF-Oa-p0T">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Edit" id="W48-6f-4Dl">
|
||||
<items>
|
||||
<menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg">
|
||||
<connections>
|
||||
<action selector="undo:" target="-1" id="M6e-cu-g7V"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam">
|
||||
<connections>
|
||||
<action selector="redo:" target="-1" id="oIA-Rs-6OD"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/>
|
||||
<menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG">
|
||||
<connections>
|
||||
<action selector="cut:" target="-1" id="YJe-68-I9s"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU">
|
||||
<connections>
|
||||
<action selector="copy:" target="-1" id="G1f-GL-Joy"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL">
|
||||
<connections>
|
||||
<action selector="paste:" target="-1" id="UvS-8e-Qdg"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Paste and Match Style" keyEquivalent="V" id="WeT-3V-zwk">
|
||||
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="pasteAsPlainText:" target="-1" id="cEh-KX-wJQ"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Delete" id="pa3-QI-u2k">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="delete:" target="-1" id="0Mk-Ml-PaM"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m">
|
||||
<connections>
|
||||
<action selector="selectAll:" target="-1" id="VNm-Mi-diN"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/>
|
||||
<menuItem title="Find" id="4EN-yA-p0u">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Find" id="1b7-l0-nxx">
|
||||
<items>
|
||||
<menuItem title="Find…" tag="1" keyEquivalent="f" id="Xz5-n4-O0W">
|
||||
<connections>
|
||||
<action selector="performFindPanelAction:" target="-1" id="cD7-Qs-BN4"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="YEy-JH-Tfz">
|
||||
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="performFindPanelAction:" target="-1" id="WD3-Gg-5AJ"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Find Next" tag="2" keyEquivalent="g" id="q09-fT-Sye">
|
||||
<connections>
|
||||
<action selector="performFindPanelAction:" target="-1" id="NDo-RZ-v9R"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Find Previous" tag="3" keyEquivalent="G" id="OwM-mh-QMV">
|
||||
<connections>
|
||||
<action selector="performFindPanelAction:" target="-1" id="HOh-sY-3ay"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="buJ-ug-pKt">
|
||||
<connections>
|
||||
<action selector="performFindPanelAction:" target="-1" id="U76-nv-p5D"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Jump to Selection" keyEquivalent="j" id="S0p-oC-mLd">
|
||||
<connections>
|
||||
<action selector="centerSelectionInVisibleArea:" target="-1" id="IOG-6D-g5B"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Spelling and Grammar" id="Dv1-io-Yv7">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Spelling" id="3IN-sU-3Bg">
|
||||
<items>
|
||||
<menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI">
|
||||
<connections>
|
||||
<action selector="showGuessPanel:" target="-1" id="vFj-Ks-hy3"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7">
|
||||
<connections>
|
||||
<action selector="checkSpelling:" target="-1" id="fz7-VC-reM"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="bNw-od-mp5"/>
|
||||
<menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleContinuousSpellChecking:" target="-1" id="7w6-Qz-0kB"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleGrammarChecking:" target="-1" id="muD-Qn-j4w"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Correct Spelling Automatically" id="78Y-hA-62v">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleAutomaticSpellingCorrection:" target="-1" id="2lM-Qi-WAP"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Substitutions" id="9ic-FL-obx">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Substitutions" id="FeM-D8-WVr">
|
||||
<items>
|
||||
<menuItem title="Show Substitutions" id="z6F-FW-3nz">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="orderFrontSubstitutionsPanel:" target="-1" id="oku-mr-iSq"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/>
|
||||
<menuItem title="Smart Copy/Paste" id="9yt-4B-nSM">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleSmartInsertDelete:" target="-1" id="3IJ-Se-DZD"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Smart Quotes" id="hQb-2v-fYv">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleAutomaticQuoteSubstitution:" target="-1" id="ptq-xd-QOA"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Smart Dashes" id="rgM-f4-ycn">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleAutomaticDashSubstitution:" target="-1" id="oCt-pO-9gS"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Smart Links" id="cwL-P1-jid">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleAutomaticLinkDetection:" target="-1" id="Gip-E3-Fov"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Data Detectors" id="tRr-pd-1PS">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleAutomaticDataDetection:" target="-1" id="R1I-Nq-Kbl"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Text Replacement" id="HFQ-gK-NFA">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleAutomaticTextReplacement:" target="-1" id="DvP-Fe-Py6"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Transformations" id="2oI-Rn-ZJC">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Transformations" id="c8a-y6-VQd">
|
||||
<items>
|
||||
<menuItem title="Make Upper Case" id="vmV-6d-7jI">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="uppercaseWord:" target="-1" id="sPh-Tk-edu"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Make Lower Case" id="d9M-CD-aMd">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="lowercaseWord:" target="-1" id="iUZ-b5-hil"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Capitalize" id="UEZ-Bs-lqG">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="capitalizeWord:" target="-1" id="26H-TL-nsh"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Speech" id="xrE-MZ-jX0">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Speech" id="3rS-ZA-NoH">
|
||||
<items>
|
||||
<menuItem title="Start Speaking" id="Ynk-f8-cLZ">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="startSpeaking:" target="-1" id="654-Ng-kyl"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Stop Speaking" id="Oyz-dy-DGm">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="stopSpeaking:" target="-1" id="dX8-6p-jy9"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="View" id="H8h-7b-M4v">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="View" id="HyV-fh-RgO">
|
||||
<items>
|
||||
<menuItem title="Enter Full Screen" keyEquivalent="f" id="4J7-dP-txa">
|
||||
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="toggleFullScreen:" target="-1" id="dU3-MA-1Rq"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Window" id="aUF-d1-5bR">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
|
||||
<items>
|
||||
<menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV">
|
||||
<connections>
|
||||
<action selector="performMiniaturize:" target="-1" id="VwT-WD-YPe"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Zoom" id="R4o-n2-Eq4">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="performZoom:" target="-1" id="DIl-cC-cCs"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
|
||||
<menuItem title="Bring All to Front" id="LE2-aR-0XJ">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="arrangeInFront:" target="-1" id="DRN-fu-gQh"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Help" id="EPT-qC-fAb">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Help" systemMenu="help" id="rJ0-wn-3NY"/>
|
||||
</menuItem>
|
||||
</items>
|
||||
<point key="canvasLocation" x="142" y="-258"/>
|
||||
</menu>
|
||||
<window title="APP_NAME" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g" customClass="MainFlutterWindow" customModule="Runner" customModuleProvider="target">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
|
||||
<rect key="contentRect" x="335" y="390" width="800" height="600"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1577"/>
|
||||
<view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ">
|
||||
<rect key="frame" x="0.0" y="0.0" width="800" height="600"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</view>
|
||||
</window>
|
||||
</objects>
|
||||
</document>
|
||||
14
macos/Runner/Configs/AppInfo.xcconfig
Normal file
@ -0,0 +1,14 @@
|
||||
// Application-level settings for the Runner target.
|
||||
//
|
||||
// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the
|
||||
// future. If not, the values below would default to using the project name when this becomes a
|
||||
// 'flutter create' template.
|
||||
|
||||
// The application's name. By default this is also the title of the Flutter window.
|
||||
PRODUCT_NAME = nhancepolicy
|
||||
|
||||
// The application's bundle identifier
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.example.nhancepolicy
|
||||
|
||||
// The copyright displayed in application information
|
||||
PRODUCT_COPYRIGHT = Copyright © 2024 com.example. All rights reserved.
|
||||
2
macos/Runner/Configs/Debug.xcconfig
Normal file
@ -0,0 +1,2 @@
|
||||
#include "../../Flutter/Flutter-Debug.xcconfig"
|
||||
#include "Warnings.xcconfig"
|
||||
2
macos/Runner/Configs/Release.xcconfig
Normal file
@ -0,0 +1,2 @@
|
||||
#include "../../Flutter/Flutter-Release.xcconfig"
|
||||
#include "Warnings.xcconfig"
|
||||