This commit is contained in:
Kicap Karan
2022-10-20 03:07:33 +08:00
commit 94344db9eb
163 changed files with 8651 additions and 0 deletions

2
.env Normal file
View File

@ -0,0 +1,2 @@
SERVER_URL = http://192.168.189.237/absensi_server/apiuser/
URL=http://192.168.189.237/absensi_server/

1
.fvm/flutter_sdk Normal file
View File

@ -0,0 +1 @@
C:/Users/Kicap_Karan/fvm/versions/3.3.0

4
.fvm/fvm_config.json Normal file
View File

@ -0,0 +1,4 @@
{
"flutterSdkVersion": "3.3.0",
"flavors": {}
}

47
.gitignore vendored Normal file
View File

@ -0,0 +1,47 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
migrate_working_dir/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.packages
.pub-cache/
.pub/
/build/
# Web related
lib/generated_plugin_registrant.dart
# Symbolication related
app.*.symbols
# Obfuscation related
app.*.map.json
# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release

45
.metadata Normal file
View 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.
version:
revision: cd41fdd495f6944ecd3506c21e94c6567b073278
channel: stable
project_type: app
# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: cd41fdd495f6944ecd3506c21e94c6567b073278
base_revision: cd41fdd495f6944ecd3506c21e94c6567b073278
- platform: android
create_revision: cd41fdd495f6944ecd3506c21e94c6567b073278
base_revision: cd41fdd495f6944ecd3506c21e94c6567b073278
- platform: ios
create_revision: cd41fdd495f6944ecd3506c21e94c6567b073278
base_revision: cd41fdd495f6944ecd3506c21e94c6567b073278
- platform: linux
create_revision: cd41fdd495f6944ecd3506c21e94c6567b073278
base_revision: cd41fdd495f6944ecd3506c21e94c6567b073278
- platform: macos
create_revision: cd41fdd495f6944ecd3506c21e94c6567b073278
base_revision: cd41fdd495f6944ecd3506c21e94c6567b073278
- platform: web
create_revision: cd41fdd495f6944ecd3506c21e94c6567b073278
base_revision: cd41fdd495f6944ecd3506c21e94c6567b073278
- platform: windows
create_revision: cd41fdd495f6944ecd3506c21e94c6567b073278
base_revision: cd41fdd495f6944ecd3506c21e94c6567b073278
# 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
View File

@ -0,0 +1,16 @@
# absensi
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.

29
analysis_options.yaml Normal file
View File

@ -0,0 +1,29 @@
# 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-lang.github.io/linter/lints/index.html.
#
# 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
View 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

73
android/app/build.gradle Normal file
View File

@ -0,0 +1,73 @@
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
// compileSdkVersion flutter.compileSdkVersion
compileSdkVersion 33
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.absensi"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration.
// minSdkVersion flutter.minSdkVersion
minSdkVersion 21
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 {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}

View File

@ -0,0 +1,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.absensi">
<!-- 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>

View File

@ -0,0 +1,47 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.absensi">
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<application
android:label="absensi"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<meta-data android:name="com.google.android.geo.API_KEY"
android:value="AIzaSyC0VpcloWxhvVm2IZxsOXOsr-BymvyHcjc"/>
<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 -->
<!-- <service android:name="rekab.app.background_locator.IsolateHolderService"
android:permission="android.permission.FOREGROUND_SERVICE"
android:exported="true"
android:foregroundServiceType = "location"/> -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
</manifest>

View File

@ -0,0 +1,6 @@
package com.example.absensi
import io.flutter.embedding.android.FlutterActivity
class MainActivity: FlutterActivity() {
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View 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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View 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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

View 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>

View 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>

View File

@ -0,0 +1,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.absensi">
<!-- 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>

31
android/build.gradle Normal file
View File

@ -0,0 +1,31 @@
buildscript {
ext.kotlin_version = '1.6.10'
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.1.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(':app')
}
task clean(type: Delete) {
delete rootProject.buildDir
}

View File

@ -0,0 +1,3 @@
org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true
android.enableJetifier=true

View File

@ -0,0 +1,6 @@
#Fri Jun 23 08:50:38 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip

11
android/settings.gradle Normal file
View File

@ -0,0 +1,11 @@
include ':app'
def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
def properties = new Properties()
assert localPropertiesFile.exists()
localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"

BIN
assets/loading.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 KiB

BIN
assets/profile_blank.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

34
ios/.gitignore vendored Normal file
View 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

View 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>9.0</string>
</dict>
</plist>

View File

@ -0,0 +1 @@
#include "Generated.xcconfig"

View File

@ -0,0 +1 @@
#include "Generated.xcconfig"

View File

@ -0,0 +1,481 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objects = {
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */,
);
name = Flutter;
sourceTree = "<group>";
};
97C146E51CF9000F007C117D = {
isa = PBXGroup;
children = (
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
);
sourceTree = "<group>";
};
97C146EF1CF9000F007C117D /* Products */ = {
isa = PBXGroup;
children = (
97C146EE1CF9000F007C117D /* Runner.app */,
);
name = Products;
sourceTree = "<group>";
};
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
97C147021CF9000F007C117D /* Info.plist */,
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
);
path = Runner;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
97C146ED1CF9000F007C117D /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
);
buildRules = (
);
dependencies = (
);
name = Runner;
productName = Runner;
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1300;
ORGANIZATIONNAME = "";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 1100;
};
};
};
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 97C146E51CF9000F007C117D;
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
97C146ED1CF9000F007C117D /* Runner */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
97C146EC1CF9000F007C117D /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Thin Binary";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Script";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
97C146EA1CF9000F007C117D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C146FB1CF9000F007C117D /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C147001CF9000F007C117D /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
249021D3217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Profile;
};
249021D4217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.absensi;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Profile;
};
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
97C147041CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
97C147061CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.absensi;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
};
97C147071CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.absensi;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147031CF9000F007C117D /* Debug */,
97C147041CF9000F007C117D /* Release */,
249021D3217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147061CF9000F007C117D /* Debug */,
97C147071CF9000F007C117D /* Release */,
249021D4217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
}

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>

View File

@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1300"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
</Workspace>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>

View 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)
}
}

View 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"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 564 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View 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"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

View 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.

View 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>

View 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>

59
ios/Runner/Info.plist Normal file
View File

@ -0,0 +1,59 @@
<?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>Absensi</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>absensi</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>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>BGTaskSchedulerPermittedIdentifiers</key>
<array>
<string>dev.flutter.background.refresh</string>
</array>
<key>NSLocationWhenInUseUsageDescription</key>
<key>NSLocationAlwaysUsageDescription</key>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<key>UIBackgroundModes</key>
<string>location</string>
</dict>
</plist>

View File

@ -0,0 +1 @@
#import "GeneratedPluginRegistrant.h"

149
lib/main.dart Normal file
View File

@ -0,0 +1,149 @@
import 'dart:async';
import 'dart:io';
import 'dart:ui';
import 'package:absensi_karyawan/src/services/notification_services.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_background_service/flutter_background_service.dart';
import 'package:flutter_background_service_android/flutter_background_service_android.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:logger/logger.dart';
import 'package:provider/provider.dart';
import 'src/config/routes.dart';
import 'src/config/theme.dart';
import 'src/provider/login_provider.dart';
import 'src/services/storage_service.dart';
import 'package:flutter_native_timezone/flutter_native_timezone.dart';
// import 'package:socket_io_client/socket_io_client.dart';
import 'package:timezone/data/latest_all.dart' as tz;
import 'package:timezone/timezone.dart' as tz;
final dev = Logger();
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
// await GetStorage.init();
await dotenv.load(fileName: ".env");
StorageService storage = StorageService();
await storage.init();
// await initializeService();
await _configureLocalTimeZone();
await NotificationServices.init();
runApp(const MyApp());
}
Future<void> initializeService() async {
final service = FlutterBackgroundService();
await service.configure(
androidConfiguration: AndroidConfiguration(
// this will be executed when app is in foreground or background in separated isolate
onStart: onStart,
// auto start service
autoStart: true,
isForegroundMode: true,
),
iosConfiguration: IosConfiguration(
// auto start service
autoStart: true,
// this will be executed when app is in foreground in separated isolate
onForeground: onStart,
// you have to enable background fetch capability on xcode project
onBackground: onIosBackground,
),
);
service.startService();
}
// to ensure this is executed
// run app from xcode, then from xcode menu, select Simulate Background Fetch
bool onIosBackground(ServiceInstance service) {
WidgetsFlutterBinding.ensureInitialized();
dev.i('FLUTTER BACKGROUND FETCH');
return true;
}
void onStart(ServiceInstance service) async {
// Only available for flutter 3.0.0 and later
DartPluginRegistrant.ensureInitialized();
// For flutter prior to version 3.0.0
// We have to register the plugin manually
if (service is AndroidServiceInstance) {
service.on('setAsForeground').listen((event) {
service.setAsForegroundService();
});
service.on('setAsBackground').listen((event) {
service.setAsBackgroundService();
});
}
service.on('stopService').listen((event) {
service.stopSelf();
});
// bring to foreground
Timer.periodic(const Duration(seconds: 5), (timer) async {
// NotificationServices.showNotification(
// id: 1,
// title: 'Percobaan 2',
// body: "ini message",
// payload: 'Percobaan 2',
// );
});
}
Future<void> _configureLocalTimeZone() async {
if (kIsWeb || Platform.isLinux) {
return;
}
tz.initializeTimeZones();
final String timeZoneName = await FlutterNativeTimezone.getLocalTimezone();
tz.setLocalLocation(tz.getLocation(timeZoneName));
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
SystemChrome.setSystemUIOverlayStyle(
const SystemUiOverlayStyle(
systemNavigationBarColor: ThemeInfo.primary,
statusBarColor: ThemeInfo.primary,
),
);
return MultiProvider(
providers: [
ChangeNotifierProvider<LoginProvider>(
create: (_) => LoginProvider(),
),
],
child: MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Absensi Karyawan',
initialRoute: 'splash',
// initialRoute:'prueba',
theme: ThemeInfo.getTheme(),
routes: RoutesApp.getRoutes(),
builder: EasyLoading.init(),
),
);
}
}

View File

@ -0,0 +1,15 @@
import 'package:flutter/material.dart';
import '../page/karyawan/karyawan_index.dart';
import '../page/login_page.dart';
import '../page/splash_screen_page.dart';
class RoutesApp {
static getRoutes() {
return {
'splash': (BuildContext context) => const SplashScreenPage(),
'login': (BuildContext context) => const LoginPage(),
'karyawan_index': (BuildContext context) => const KaryawanIndexPage(),
};
}
}

24
lib/src/config/theme.dart Normal file
View File

@ -0,0 +1,24 @@
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
class ThemeInfo {
static const Color primary = Color(0xff0A9BAB);
static const Color background = Color(0xffF5F5F5);
static const Color negroTexto = Color(0xff4E4E4E);
static const Color danger = Color.fromARGB(255, 228, 30, 30);
static const Color myGrey = Color.fromARGB(255, 210, 212, 212);
static const Color myGrey2 = Color.fromARGB(255, 174, 175, 175);
static const Color readFile = Color.fromARGB(255, 22, 144, 38);
static ThemeData getTheme() {
return ThemeData(
// brightness: Brightness.dark,
// primarySwatch: generateMaterialColor(Palette.primary),
// primaryColor: Colors.orange[400],
// accentColor: Colors.blue,
backgroundColor: background,
// scaffoldBackgroundColor: const Color(0xff110e15),
fontFamily: GoogleFonts.roboto().fontFamily,
);
}
}

View File

@ -0,0 +1,44 @@
class AbsensiKaryawanModel {
String? no;
String? nik;
String? idDinas;
String? tanggal;
String? jamMasuk;
String? jamIstirehat;
String? jamMasukKembali;
String? jamPulang;
AbsensiKaryawanModel(
{this.no,
this.nik,
this.idDinas,
this.tanggal,
this.jamMasuk,
this.jamIstirehat,
this.jamMasukKembali,
this.jamPulang});
AbsensiKaryawanModel.fromJson(Map<String, dynamic> json) {
no = json['no'];
nik = json['nik'];
idDinas = json['id_dinas'];
tanggal = json['tanggal'];
jamMasuk = json['jam_masuk'];
jamIstirehat = json['jam_istirehat'];
jamMasukKembali = json['jam_masuk_kembali'];
jamPulang = json['jam_pulang'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['no'] = no;
data['nik'] = nik;
data['id_dinas'] = idDinas;
data['tanggal'] = tanggal;
data['jam_masuk'] = jamMasuk;
data['jam_istirehat'] = jamIstirehat;
data['jam_masuk_kembali'] = jamMasukKembali;
data['jam_pulang'] = jamPulang;
return data;
}
}

View File

@ -0,0 +1,34 @@
// To parse this JSON data, do
//
// final baseResponse = baseResponseFromJson(jsonString);
import 'dart:convert';
BaseResponse baseResponseFromJson(String str) =>
BaseResponse.fromJson(json.decode(str));
String baseResponseToJson(BaseResponse data) => json.encode(data.toJson());
class BaseResponse {
BaseResponse(
{required this.status, required this.message, this.data, this.firstTime});
bool status;
String message;
dynamic data;
bool? firstTime;
factory BaseResponse.fromJson(Map<String, dynamic> json) => BaseResponse(
status: json["status"],
message: json["message"],
data: json["data"],
firstTime: json["firstTime"],
);
Map<String, dynamic> toJson() => {
"status": status,
"message": message,
"data": data,
"firstTime": firstTime
};
}

View File

@ -0,0 +1,40 @@
class JadwalDinasModel {
String? no;
String? idDinas;
String? hari;
String? jamMasuk;
String? jamIstirehat;
String? jamMasukKembali;
String? jamPulang;
JadwalDinasModel(
{this.no,
this.idDinas,
this.hari,
this.jamMasuk,
this.jamIstirehat,
this.jamMasukKembali,
this.jamPulang});
JadwalDinasModel.fromJson(Map<String, dynamic> json) {
no = json['no'];
idDinas = json['id_dinas'];
hari = json['hari'];
jamMasuk = json['jam_masuk'];
jamIstirehat = json['jam_istirehat'];
jamMasukKembali = json['jam_masuk_kembali'];
jamPulang = json['jam_pulang'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['no'] = no;
data['id_dinas'] = idDinas;
data['hari'] = hari;
data['jam_masuk'] = jamMasuk;
data['jam_istirehat'] = jamIstirehat;
data['jam_masuk_kembali'] = jamMasukKembali;
data['jam_pulang'] = jamPulang;
return data;
}
}

View File

@ -0,0 +1,65 @@
class LaporanModel {
int? countAll;
int? allPage;
List<LaporanData>? data;
LaporanModel({this.countAll, this.allPage, this.data});
LaporanModel.fromJson(Map<String, dynamic> json) {
countAll = json['count_all'];
allPage = json['all_page'];
if (json['data'] != null) {
data = <LaporanData>[];
json['data'].forEach((v) {
data!.add(LaporanData.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['count_all'] = countAll;
data['all_page'] = allPage;
if (this.data != null) {
data['data'] = this.data!.map((v) => v.toJson()).toList();
}
return data;
}
}
class LaporanData {
String? noLaporan;
String? nik;
String? image;
String? namaLaporan;
String? ketLaporan;
String? createdAt;
LaporanData(
{this.noLaporan,
this.nik,
this.image,
this.namaLaporan,
this.ketLaporan,
this.createdAt});
LaporanData.fromJson(Map<String, dynamic> json) {
noLaporan = json['no_laporan'];
nik = json['nik'];
image = json['image'];
namaLaporan = json['nama_laporan'];
ketLaporan = json['ket_laporan'];
createdAt = json['created_at'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['no_laporan'] = noLaporan;
data['nik'] = nik;
data['image'] = image;
data['nama_laporan'] = namaLaporan;
data['ket_laporan'] = ketLaporan;
data['created_at'] = createdAt;
return data;
}
}

View File

@ -0,0 +1,81 @@
class UserDataModel {
String? nik;
String? nama;
String? noTelpon;
String? jabatan;
String? alamat;
String? idDinas;
String? deviceId;
String? createdAt;
String? updatedAt;
String? dinas;
String? lat;
String? lng;
String? radius;
String? pangkat;
String? status;
String? tanggalLahir;
String? image;
UserDataModel({
this.nik,
this.nama,
this.noTelpon,
this.jabatan,
this.alamat,
this.idDinas,
this.deviceId,
this.createdAt,
this.updatedAt,
this.dinas,
this.lat,
this.lng,
this.radius,
this.pangkat,
this.status,
this.tanggalLahir,
this.image,
});
UserDataModel.fromJson(Map<String, dynamic> json) {
nik = json['nik'];
nama = json['nama'];
noTelpon = json['no_telpon'];
jabatan = json['jabatan'];
alamat = json['alamat'];
idDinas = json['id_dinas'];
deviceId = json['device_id'];
createdAt = json['created_at'];
updatedAt = json['updated_at'];
dinas = json['dinas'];
lat = json['lat'];
lng = json['lng'];
radius = json['radius'];
pangkat = json['pangkat'];
status = json['status'];
tanggalLahir = json['tanggal_lahir'];
image = json['image'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['nik'] = nik;
data['nama'] = nama;
data['no_telpon'] = noTelpon;
data['jabatan'] = jabatan;
data['alamat'] = alamat;
data['id_dinas'] = idDinas;
data['device_id'] = deviceId;
data['created_at'] = createdAt;
data['updated_at'] = updatedAt;
data['dinas'] = dinas;
data['lat'] = lat;
data['lng'] = lng;
data['radius'] = radius;
data['pangkat'] = pangkat;
data['status'] = status;
data['tanggal_lahir'] = tanggalLahir;
data['image'] = image;
return data;
}
}

View File

@ -0,0 +1,754 @@
import 'dart:async';
import 'dart:collection';
import 'package:absensi_karyawan/src/models/base_response.dart';
import 'package:absensi_karyawan/src/services/api_service.dart';
import 'package:animated_snack_bar/animated_snack_bar.dart';
import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:intl/intl.dart';
import 'package:location/location.dart';
import 'package:logger/logger.dart';
import '../../config/theme.dart';
import '../../models/absensi_karyawan_model.dart';
import '../../models/jadwal_dinas_model.dart';
import '../../models/user_data_model.dart';
import '../../services/other_services.dart';
import '../../services/storage_service.dart';
import '../../widget/smart_widget/bounce_scroller.dart';
class AbsensiKaryawan extends StatefulWidget {
const AbsensiKaryawan({
Key? key,
}) : super(key: key);
@override
State<AbsensiKaryawan> createState() => _AbsensiKaryawanState();
}
class _AbsensiKaryawanState extends State<AbsensiKaryawan> {
final dev = Logger();
final _storage = StorageService();
UserDataModel? _userDataModel;
late String formatted;
LatLng? currentLocation;
dynamic _statusnya;
AbsensiKaryawanModel? absensiKaryawanModel;
late JadwalDinasModel _jadwalDinasModel;
bool buttonLoad = false;
String stat = 'jam_masuk';
final statValue = {
"jam_masuk": "Masuk Kerja",
"jam_istirehat": "Istirehat Kerja",
"jam_masuk_kembali": "Kerja Kembali",
"jam_pulang": "Pulang Kerja",
};
@override
void initState() {
super.initState();
getDate();
getUserData();
getUserJadwalHarinIni();
}
void getDate() async {
final DateTime now = DateTime.now();
final DateFormat formatter = DateFormat('yyyy-MM-dd');
formatted = formatter.format(now);
String today = DateFormat('EEEE').format(now);
// dev.i(today);
if (today == "Sunday" || today == "Saturday") {
setState(() {
String day = (today == "Sunday") ? "Minggu" : "Sabtu";
_statusnya = {'stat': "Libur", 'ket': "Libur Hari $day"};
});
} else {
await ApiServices.getTodayLiburAndPerjalanDinas(formatted);
// await Future.delayed(Duration(seconds: 1));
dynamic statusnya = await _storage.read('ada_perjalanan_dinas_libur');
// dev.i(statusnya);
setState(() {
_statusnya = statusnya;
});
}
List jadwalDinasList = await _storage.read('jadwalKerja');
for (var data in jadwalDinasList) {
JadwalDinasModel jadwalDinasModel = JadwalDinasModel.fromJson(data);
String dayName = OtherServices.dayNameChanger(jadwalDinasModel.hari!);
if (dayName == today) {
setState(() {
_jadwalDinasModel = jadwalDinasModel;
});
}
}
dev.i(_jadwalDinasModel.hari);
// dev.i(_jadwalDinasModel.jamMasuk);
// dev.i(_jadwalDinasModel.jamIstirehat);
// dev.i(_jadwalDinasModel.jamMasukKembali);
// dev.i(_jadwalDinasModel.jamPulang);
}
void getUserData() async {
await ApiServices.getUserData();
Map<String, dynamic> userData = await _storage.read('userData');
setState(() {
_userDataModel = UserDataModel.fromJson(userData);
});
}
getUserJadwalHarinIni() async {
BaseResponse? result = await ApiServices.getUserTodayAbsensi(formatted);
if (result == null) {
if (mounted) {
return setState(() {
info(
"Tidak dapat terhubung ke server, Sila cek jaringan anda", false);
});
}
}
if (result!.status == false) {
if (mounted) {
return setState(() {
info(
"Tidak dapat terhubung ke server, Sila cek jaringan anda", false);
});
}
}
// dev.i(result.data);
await _storage.write('runGPS', false);
if (result.data != null) {
// dev.i("sini dia");
await _storage.write('runGPS', true);
setState(() {
absensiKaryawanModel = AbsensiKaryawanModel.fromJson(result.data);
stat = 'jam_istirehat';
if (absensiKaryawanModel!.jamIstirehat != null) {
stat = "jam_masuk_kembali";
}
if (absensiKaryawanModel!.jamMasukKembali != null) {
stat = "jam_pulang";
}
});
if (absensiKaryawanModel!.jamIstirehat != null) {
await _storage.write('runGPS', false);
}
if (absensiKaryawanModel!.jamMasukKembali != null) {
await _storage.write('runGPS', true);
}
if (absensiKaryawanModel!.jamPulang != null) {
await _storage.write('runGPS', false);
}
}
}
info(String? message, bool stat) async {
await AnimatedSnackBar.rectangle(
stat ? 'Info' : 'Error',
message ?? 'Jaringan Bermasalah',
type: stat ? AnimatedSnackBarType.success : AnimatedSnackBarType.error,
brightness: Brightness.dark,
).show(
context,
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: BounceScrollerWidget(
children: [
Container(
alignment: Alignment.center,
height: MediaQuery.of(context).size.height * 0.75,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
_HeaderTitle(dinas: _userDataModel?.dinas),
const _LogoImage(),
_KaryawanDetail(
nik: _userDataModel?.nik, nama: _userDataModel?.nama),
_LaporanAbsensi(
tanggal: formatted,
statusnya: _statusnya,
absensiKaryawanModel: absensiKaryawanModel,
),
],
),
),
],
),
floatingActionButton: FloatingActionButton(
backgroundColor: ThemeInfo.primary,
onPressed: () {
if (absensiKaryawanModel != null) {
if (absensiKaryawanModel!.jamPulang != null) {
info("Anda Sudah Pulang Kerja, Silakan Istirehat", true);
} else {
_dialogAbsensi();
}
} else {
_dialogAbsensi();
}
},
child: const Icon(Icons.work_history_outlined),
),
);
}
Future<void> _dialogAbsensi() async {
if (_statusnya == null) return info("Jaringan Bermasalah", false);
if (_statusnya != 'tiada') {
return info(
"Anda Sedang Dalam ${_statusnya['stat']}\n${_statusnya['ket']}",
true);
}
return showDialog<void>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
content: SizedBox(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text("Form Absensi"),
const SizedBox(
height: 10,
),
_ThisGoogleMaps(
userDataModel: _userDataModel,
),
const SizedBox(
height: 10,
),
Center(
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: ThemeInfo.primary,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
),
),
onPressed: () async {
await EasyLoading.show(
status: "Absensi...",
maskType: EasyLoadingMaskType.black,
);
setState(() {
buttonLoad = false;
});
// await EasyLoading.dismiss();
await Future.delayed(const Duration(seconds: 1));
double? currentLocationStr1 =
await _storage.read("currentLocation1");
double? currentLocationStr2 =
await _storage.read("currentLocation2");
if (currentLocationStr1 == null) {
await EasyLoading.dismiss();
return await info("Sedang Mencari Lokasi Anda", false);
}
LatLng? currentLocationLatLng =
(currentLocationStr2 != null)
? LatLng(currentLocationStr1, currentLocationStr2)
: null;
bool checkMe = OtherServices.checkIfInRadius(
currentLocationLatLng!,
LatLng(double.parse(_userDataModel!.lat!),
double.parse(_userDataModel!.lng!)));
setState(() {
buttonLoad = true;
});
if (!buttonLoad) return info("Still Loading", false);
if (!checkMe) {
return info(
"Anda Berada Di Luar Radius Lokasi Kantor Yang Ditetapkan",
false);
}
// dev.i("jalankan");
await absensiKerja(stat);
await ApiServices.postUserTodayAbsensi(formatted, stat);
},
child: _ThisDialogButton(statValue: statValue, stat: stat),
),
),
],
),
),
);
},
);
}
popDialog() {
Navigator.of(context, rootNavigator: true).pop('dialog');
}
absensiKerja(String? stat) async {
return showDialog<void>(
context: context,
builder: (BuildContext context) {
stopnya() async {
await EasyLoading.dismiss();
}
stopnya();
return AlertDialog(
content: SizedBox(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text("Absensi ${statValue[stat]} ?"),
const SizedBox(
height: 10,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
ElevatedButton(
onPressed: () async {
Navigator.of(context).pop();
await EasyLoading.show(
status: "Sedang Absensi...",
maskType: EasyLoadingMaskType.black,
);
popDialog();
await ApiServices.postUserTodayAbsensi(
formatted, stat!);
await getUserJadwalHarinIni();
await EasyLoading.dismiss();
},
child: const Text("Ya"),
),
ElevatedButton(
onPressed: () {
Navigator.of(context).pop();
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red,
),
child: const Text("Tidak"),
),
],
),
],
),
),
);
},
);
}
}
class _ThisDialogButton extends StatelessWidget {
const _ThisDialogButton({
Key? key,
required this.statValue,
required this.stat,
}) : super(key: key);
final Map<String, String> statValue;
final String? stat;
@override
Widget build(BuildContext context) {
return Text(
"Absensi ${statValue[stat]}",
style: const TextStyle(
color: ThemeInfo.background,
fontSize: 18,
),
);
}
}
class _ThisGoogleMaps extends StatefulWidget {
const _ThisGoogleMaps({
Key? key,
UserDataModel? userDataModel,
}) : _userDataModel = userDataModel,
super(key: key);
final UserDataModel? _userDataModel;
@override
State<_ThisGoogleMaps> createState() => _ThisGoogleMapsState();
}
class _ThisGoogleMapsState extends State<_ThisGoogleMaps> {
final dev = Logger();
final _storage = StorageService();
static const _initialCameraPosition = CameraPosition(
target: LatLng(-2.0702326775846314, 119.28682729516751),
zoom: 15,
);
Location location = Location();
final Set<Marker> _markers = HashSet<Marker>();
final Set<Circle> _circles = HashSet<Circle>();
late GoogleMapController mapController;
// Completer<GoogleMapController> _controller = Completer();
@override
void dispose() {
super.dispose();
mapController.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
height: 250,
width: double.infinity,
// color: Colors.transparent,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
border: Border.all(color: Colors.grey),
),
child: ClipRRect(
borderRadius: const BorderRadius.all(
Radius.circular(20),
),
child: GoogleMap(
initialCameraPosition: _initialCameraPosition,
markers: _markers,
circles: _circles,
onMapCreated: _onMapCreated,
// zoomControlsEnabled: false,
),
),
);
}
void _onMapCreated(GoogleMapController controller) {
mapController = controller;
Timer(const Duration(milliseconds: 1000), () async {
// final GoogleMapController controller = await controller.future;
// -4.007142395641209, 119.6295638910395
// var dinasData = await _storage.read(key);
LocationData locationData;
while (true) {
await _storage.write("currentLocation1", null);
await _storage.write("currentLocation2", null);
locationData = await location.getLocation();
await _storage.write("currentLocation1", locationData.latitude);
await _storage.write("currentLocation2", locationData.longitude);
// dev.i(locationData.latitude);
// dev.i(locationData.longitude);
_markers.clear();
_circles.clear();
if (mounted) {
mapController.animateCamera(
CameraUpdate.newCameraPosition(
CameraPosition(
target: LatLng(locationData.latitude!, locationData.longitude!),
zoom: 17,
),
),
);
setState(() {
_markers.add(Marker(
icon: BitmapDescriptor.defaultMarkerWithHue(
BitmapDescriptor.hueBlue),
markerId: const MarkerId("ini markernya"),
position: LatLng(locationData.latitude!, locationData.longitude!),
infoWindow: const InfoWindow(
title: "Posisi Sekarang",
),
));
_circles.add(
Circle(
circleId: CircleId(widget._userDataModel!.idDinas!),
center: LatLng(double.parse(widget._userDataModel!.lat!),
double.parse(widget._userDataModel!.lng!)),
radius: double.parse(widget._userDataModel!.radius!),
fillColor: Colors.blue.withOpacity(0.2),
strokeWidth: 0,
),
);
});
}
await Future.delayed(const Duration(seconds: 10));
}
});
}
}
class _LaporanAbsensi extends StatelessWidget {
_LaporanAbsensi(
{Key? key,
required this.tanggal,
this.statusnya,
AbsensiKaryawanModel? absensiKaryawanModel})
: _absensiKaryawanModel = absensiKaryawanModel,
super(key: key);
final dev = Logger();
final String tanggal;
final dynamic statusnya;
final AbsensiKaryawanModel? _absensiKaryawanModel;
@override
Widget build(BuildContext context) {
late String jamMasuk, jamPulang, status;
// String? ket;
// dev.i(statusnya);
if (statusnya == null) {
jamMasuk = "-";
jamPulang = "-";
status = "Tiada Jaringan";
} else {
if (statusnya == 'tiada') {
if (_absensiKaryawanModel == null) {
jamMasuk = "-";
jamPulang = "-";
status = "Belum Absen";
} else {
jamMasuk = _absensiKaryawanModel!.jamMasuk ?? "-";
jamPulang = "-";
status = "Sedang Kerja";
if (_absensiKaryawanModel!.jamIstirehat != null) {
status = "Sedang Istirehat";
}
if (_absensiKaryawanModel!.jamMasukKembali != null) {
status = "Sedang Kerja";
}
if (_absensiKaryawanModel!.jamPulang != null) {
jamPulang = _absensiKaryawanModel!.jamPulang ?? '-';
status = "Pulang Kerja";
}
}
} else {
if (statusnya['stat'] == "Perjalanan Dinas") {
jamMasuk = "-";
jamPulang = "-";
status = "Perjalanan Dinas";
// ket = statusnya['ket'];
}
if (statusnya['stat'] == "Libur") {
jamMasuk = "-";
jamPulang = "-";
status = "Libur";
// ket = statusnya['ket'];
}
}
}
return Container(
width: double.infinity,
// height: 180,
decoration: BoxDecoration(
color: ThemeInfo.myGrey,
borderRadius: BorderRadius.circular(10),
boxShadow: const [
BoxShadow(
color: ThemeInfo.myGrey2,
blurRadius: 10,
spreadRadius: 5,
),
],
),
child: Padding(
padding: const EdgeInsets.only(bottom: 15),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_LaporanAbsensiChild(
title: "Tanggal",
value: tanggal,
),
_LaporanAbsensiChild(
title: "Jam Masuk",
value: jamMasuk,
),
_LaporanAbsensiChild(
title: "Jam Keluar",
value: jamPulang,
),
_LaporanAbsensiChild(
title: "Status",
value: status,
),
// if (ket != null)
// _LaporanAbsensiChild(
// title: "Keterangan",
// value: status,
// ),
],
),
),
);
}
}
class _LaporanAbsensiChild extends StatelessWidget {
const _LaporanAbsensiChild({
Key? key,
required this.value,
this.title,
}) : super(key: key);
final String value;
final String? title;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(
left: 20,
right: 20,
top: 20,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Text(
'$title : ',
style: const TextStyle(
fontSize: 20,
// fontWeight: FontWeight.bold,
color: ThemeInfo.negroTexto,
),
),
),
Text(
value,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: ThemeInfo.negroTexto,
),
),
],
),
);
}
}
class _KaryawanDetail extends StatelessWidget {
const _KaryawanDetail({
Key? key,
this.nama,
this.nik,
}) : super(key: key);
final String? nama;
final String? nik;
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.only(
top: 10,
left: 10,
right: 10,
bottom: 20,
),
alignment: Alignment.center,
child: Text(
nama == null ? 'Loading..' : '$nama \n $nik',
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.bold,
),
),
);
}
}
class _LogoImage extends StatelessWidget {
const _LogoImage({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(
left: 20,
right: 20,
),
child: Image.asset(
'assets/logo_mamuju_tengah.png',
height: 150,
width: 150,
),
);
}
}
class _HeaderTitle extends StatelessWidget {
const _HeaderTitle({
Key? key,
this.dinas,
}) : super(key: key);
final String? dinas;
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.only(
top: 10,
bottom: 10,
right: MediaQuery.of(context).size.width * 0.03,
left: MediaQuery.of(context).size.width * 0.03,
),
alignment: Alignment.center,
child: Text(
dinas != null ? dinas!.toUpperCase() : "Loading..",
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.bold,
),
),
);
}
}

View File

@ -0,0 +1,159 @@
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:logger/logger.dart';
import '../../services/api_service.dart';
import '../../services/location_services.dart';
import '../../widget/smart_widget/appbar.dart';
import '../../widget/smart_widget/karyawan_bottombar.dart';
import 'absensi_karyawan.dart';
import 'profil_karyawan.dart';
import 'upload_laporan_page.dart';
class KaryawanIndexPage extends StatefulWidget {
const KaryawanIndexPage({Key? key}) : super(key: key);
@override
State<KaryawanIndexPage> createState() => _KaryawanIndexPageState();
}
class _KaryawanIndexPageState extends State<KaryawanIndexPage> {
final dev = Logger();
int _indexSelected = 1;
// late String formatted;
final List<String> _headerName = [
'Halaman Laporan',
'Halaman Absensi',
'Halaman Profil',
];
@override
void initState() {
super.initState();
SchedulerBinding.instance.addPostFrameCallback((_) async {
var args = ModalRoute.of(context)?.settings.arguments;
if (args == true) {
showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return const ThisFirstDialog();
},
);
}
});
// getLoc().listen((event) async {});
// getLoc().listen((event) async {});
_getLoc();
}
void getDate() {}
_getLoc() async {
// final DateTime now = DateTime.now();
// final DateFormat formatter = DateFormat('yyyy-MM-dd');
// String formatted = formatter.format(now);
// await ApiServices.getUserData();
await ApiServices.getJadwalDinas();
// dev.i(user);
// dev.i(jadwal);
await getLoc();
}
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
final shouldPop = await showDialog<bool>(
context: context,
builder: (context) {
return AlertDialog(
title: const Text('Keluar Dari Aplikasi Absensi?'),
actionsAlignment: MainAxisAlignment.spaceBetween,
actions: [
TextButton(
onPressed: () {
Navigator.pop(context, true);
},
child: const Text('Ya'),
),
TextButton(
onPressed: () {
Navigator.pop(context, false);
},
child: const Text('Tidak'),
),
],
);
},
);
return shouldPop!;
},
child: Scaffold(
appBar: PreferredSize(
preferredSize:
Size.fromHeight(MediaQuery.of(context).size.height * 0.07),
child: AppBarWidget(
header: _headerName[_indexSelected],
autoLeading: false,
),
),
body: tabWidget(context),
bottomNavigationBar: KaryawanBottomBar(
indexSelected: _indexSelected,
onTap: (index) {
setState(() {
_indexSelected = index;
});
},
),
),
);
}
tabWidget(BuildContext context) {
switch (_indexSelected) {
case 0:
return const UploadLaporanKaryawan();
case 1:
return const AbsensiKaryawan();
case 2:
return const ProfilKaryawanPage();
}
}
}
class ThisFirstDialog extends StatelessWidget {
const ThisFirstDialog({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return AlertDialog(
title: const Text('Info'),
content: SingleChildScrollView(
child: ListBody(
children: const <Widget>[
Text(
'Perangkat ini telah terdaftar dalam sistem untuk menjadi perangkat absensi kedisiplinan anda. Untuk menukar perangkar, sila infokan admin bersangkutan',
textAlign: TextAlign.justify,
),
],
),
),
actions: <Widget>[
TextButton(
child: const Text('OK'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
}
}

View File

@ -0,0 +1,216 @@
import 'package:absensi_karyawan/src/models/user_data_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:logger/logger.dart';
import '../../config/theme.dart';
import '../../services/storage_service.dart';
import '../../widget/smart_widget/bounce_scroller.dart';
class ProfilKaryawanPage extends StatefulWidget {
const ProfilKaryawanPage({Key? key}) : super(key: key);
@override
State<ProfilKaryawanPage> createState() => _ProfilKaryawanPageState();
}
class _ProfilKaryawanPageState extends State<ProfilKaryawanPage> {
final dev = Logger();
final _storage = StorageService();
UserDataModel? userDataModel;
static final url = dotenv.env['URL'];
@override
void initState() {
super.initState();
getUserData();
}
void getUserData() async {
var userData = await _storage.read("userData");
// dev.i(userData);
setState(() {
userDataModel = UserDataModel.fromJson(userData);
});
// dev.i("$url${userDataModel.image}");
}
@override
Widget build(BuildContext context) {
return BounceScrollerWidget(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const SizedBox(
height: 20,
),
Container(
padding: const EdgeInsets.all(5),
alignment: Alignment.center,
height: 100,
width: 100,
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: Colors.white,
// borderRadius: BorderRadius.circular(100),
image: DecorationImage(
image: AssetImage('assets/loading.gif'),
fit: BoxFit.fitHeight,
),
boxShadow: [
BoxShadow(
color: ThemeInfo.myGrey2,
blurRadius: 10,
spreadRadius: 5,
),
],
),
// child: Image.network(
// "$url${userDataModel?.image}",
// errorBuilder: (context, error, stackTrace) {
// return Image.asset(
// 'assets/profile_blank.png',
// fit: BoxFit.cover,
// );
// },
// ),
child: Center(
child: CircleAvatar(
radius: 100,
backgroundImage:
NetworkImage("$url${userDataModel?.image}", scale: 100),
onBackgroundImageError: (exception, stackTrace) {
return;
},
),
),
),
Padding(
padding: const EdgeInsets.all(10),
child: Text(
userDataModel == null ? "loading.." : userDataModel!.nama!,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: ThemeInfo.negroTexto,
),
),
),
_DetailParent(userDataModel: userDataModel),
],
),
],
);
}
}
class _DetailParent extends StatelessWidget {
const _DetailParent({
Key? key,
required userDataModel,
}) : _userDataModel = userDataModel,
super(key: key);
final UserDataModel? _userDataModel;
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
_DetailChild(
icon: Icons.person_pin,
title: _userDataModel == null ? "loading.." : _userDataModel!.nik!,
),
_DetailChild(
icon: Icons.home_work_outlined,
title:
_userDataModel == null ? "loading.." : _userDataModel!.jabatan!,
),
_DetailChild(
icon: Icons.work,
title:
_userDataModel == null ? "loading.." : _userDataModel!.pangkat!,
),
_DetailChild(
icon: Icons.work,
title: _userDataModel == null ? "loading.." : _userDataModel!.status!,
),
_DetailChild(
icon: Icons.add_reaction_outlined,
title: _userDataModel == null
? "loading.."
: _userDataModel!.tanggalLahir!,
),
_DetailChild(
icon: Icons.phone_android,
title:
_userDataModel == null ? "loading.." : _userDataModel!.noTelpon!,
),
_DetailChild(
icon: Icons.home_outlined,
title: _userDataModel == null ? "loading.." : _userDataModel!.alamat!,
),
SizedBox(
height: MediaQuery.of(context).size.height * 0.1,
)
],
);
}
}
class _DetailChild extends StatelessWidget {
const _DetailChild({
Key? key,
required this.title,
required this.icon,
}) : super(key: key);
final String title;
final IconData icon;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(bottom: 10),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Icon(
icon,
color: ThemeInfo.myGrey2,
size: 40,
),
const SizedBox(
width: 20,
),
Flexible(
child: Text(
title,
maxLines: 3,
// softWrap: false,
// overflow: TextOverflow.fade,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: ThemeInfo.myGrey2,
),
),
),
],
),
),
],
),
);
}
}

View File

@ -0,0 +1,817 @@
import 'dart:io';
import 'package:animated_snack_bar/animated_snack_bar.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:image_picker/image_picker.dart';
import 'package:logger/logger.dart';
import '../../config/theme.dart';
import '../../models/base_response.dart';
import '../../models/laporan_model.dart';
import '../../services/api_service.dart';
import '../../services/other_services.dart';
import '../../widget/dumb_widget/my_textformfield.dart';
import '../../widget/smart_widget/bounce_scroller.dart';
class UploadLaporanKaryawan extends StatefulWidget {
const UploadLaporanKaryawan({Key? key}) : super(key: key);
@override
State<UploadLaporanKaryawan> createState() => UploadLaporanKaryawanState();
static UploadLaporanKaryawanState? of(BuildContext context) =>
context.findAncestorStateOfType<UploadLaporanKaryawanState>();
}
class UploadLaporanKaryawanState extends State<UploadLaporanKaryawan> {
final dev = Logger();
final String? url = dotenv.env['URL'];
late TextEditingController _namaLaporanController;
late TextEditingController _ketLaporanController;
late FocusNode _namaLaporanFocusNode;
late FocusNode _ketLaporanFocusNode;
// table pagination and search
int _loadLaporan = 0;
List<LaporanData>? _listLaporanData;
int _pageNumber = 1;
int? _pageAll;
int? _countAll;
// String _search = '';
late TextEditingController _searchLaporanController;
@override
void initState() {
super.initState();
_namaLaporanController = TextEditingController();
_ketLaporanController = TextEditingController();
_namaLaporanFocusNode = FocusNode();
_ketLaporanFocusNode = FocusNode();
_searchLaporanController = TextEditingController();
_searchLaporanController.text = '';
getAllLaporan(1, _searchLaporanController.text);
}
void getAllLaporan(int page, String search) async {
setState(() {
_loadLaporan = 0;
});
BaseResponse? response = await ApiServices.getLaporan(page, search);
// dev.i(response?.data);
if (response == null) {
setState(() {
_loadLaporan = 3;
});
return;
}
if (response.status == false) {
setState(() {
_loadLaporan = 2;
});
}
LaporanModel laporanModel = LaporanModel.fromJson(response.data);
// dev.i(laporanModel.data);
setState(() {
_listLaporanData = laporanModel.data;
_loadLaporan = 1;
_pageNumber = page;
_pageAll = laporanModel.allPage;
_countAll = laporanModel.countAll;
});
// await Future.delayed(Duration(seconds: 3));
// if (!mounted) return;
// setState(() {
// _loadLaporan = 1;
// });
}
bool _hasFoto = false; // if has foto
String? _imgPath; // path to foto
final ImagePicker _picker = ImagePicker();
XFile? _imageFile; // file to foto
Uint8List? imagebytes;
Future<void> onImageButtonPressed() async {
try {
final XFile? pickedFile =
await _picker.pickImage(source: ImageSource.camera);
_imageFile = pickedFile;
final file = File(_imageFile!.path);
if (file.existsSync()) {
final Uint8List bytes = await file.readAsBytes();
setState(() {
_imgPath = _imageFile!.path.toString();
imagebytes = bytes;
_hasFoto = true;
});
popDialog();
_showTambahLaporan();
}
} catch (e) {
dev.e(e);
}
}
popDialog() {
Navigator.of(context, rootNavigator: true).pop('dialog');
}
void info(String message, String stat, String title) {
AnimatedSnackBar.rectangle(
title,
message,
type: stat == 'warning'
? AnimatedSnackBarType.warning
: stat == 'success'
? AnimatedSnackBarType.success
: AnimatedSnackBarType.error,
brightness: Brightness.dark,
).show(
context,
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
width: double.infinity,
height: 75,
decoration: const BoxDecoration(
color: Colors.transparent,
),
),
BounceScrollerWidget(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
if (_loadLaporan == 0)
const Center(
child: CircularProgressIndicator(),
)
else if (_loadLaporan == 1)
_LaporanList(
listLaporanData: _listLaporanData,
dev: dev,
pageNumber: _pageNumber,
pageAll: _pageAll,
countAll: _countAll,
serverUrl: url,
)
else if (_loadLaporan == 2)
const Center(
child: Text(
"Gagal Load Laporan\nServer Mungkin Bermasalah",
textAlign: TextAlign.center,
),
)
else if (_loadLaporan == 3)
const Center(
child: Text(
"Gagal Load Laporan\nJaringan Mungkin Bermasalah",
textAlign: TextAlign.center,
),
)
],
),
SizedBox(
height: MediaQuery.of(context).size.height * 0.2,
),
],
),
],
),
),
Positioned(
top: 15,
left: MediaQuery.of(context).size.width * 0.05,
right: MediaQuery.of(context).size.width * 0.05,
child: SizedBox(
width: double.infinity,
height: 50,
child: MyTextFormField(
controller: _searchLaporanController,
onEditingComplete: () {
// dev.i("editing complete");
FocusScope.of(context).unfocus();
setState(() {
_pageNumber = 1;
});
getAllLaporan(1, _searchLaporanController.text);
},
// suffixIcon: Icon(
// Icons.list_alt_outlined,
// color: ThemeInfo.myGrey,
// ),
labelText: "Cari Laporan",
hintText: "Cari Laporan",
prefixIcon: const Icon(
Icons.search,
color: ThemeInfo.myGrey2,
),
),
),
),
],
),
floatingActionButton: FloatingActionButton(
backgroundColor: ThemeInfo.primary,
onPressed: () {
FocusScope.of(context).unfocus();
OtherServices.cekAndDelete();
setState(() {
_hasFoto = false;
_imgPath = null;
});
_showTambahLaporan();
},
child: const Icon(Icons.post_add_outlined),
),
);
}
Future<void> _showTambahLaporan() async {
// create dialog box
_searchLaporanController.text = '';
showDialog<void>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text("Form Laporan"),
content: SizedBox(
// height: MediaQuery.of(context).size.height * 0.5,
width: MediaQuery.of(context).size.width * 0.8,
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.min,
children: [
GestureDetector(
onTap: () => dev.i("sentuh gambar"),
child: Center(
child: Container(
width: 80,
height: 80,
decoration: BoxDecoration(
color: const Color.fromARGB(255, 199, 214, 234),
borderRadius: BorderRadius.circular(100),
boxShadow: const [
BoxShadow(
color: Color.fromARGB(255, 104, 164, 164),
blurRadius: 5,
spreadRadius: 1,
),
],
),
child: Stack(
// put icon on rigth bottom corner
alignment: Alignment.center,
children: [
FotoWidget(
hasFoto: _hasFoto,
imagebytes: imagebytes,
),
Positioned(
bottom: 0,
right: 0,
child: GestureDetector(
onTap: () {
dev.i("sentuh untuk tambah gambar");
onImageButtonPressed();
},
child: Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color:
const Color.fromARGB(255, 4, 103, 103),
borderRadius: BorderRadius.circular(100),
),
child: const Icon(
Icons.add_a_photo_outlined,
color: Colors.black,
size: 30,
),
),
),
),
],
),
),
),
),
const SizedBox(
height: 15,
),
MyTextFormField(
controller: _namaLaporanController,
focusNode: _namaLaporanFocusNode,
labelText: "Nama Laporan",
hintText: "Nama Laporan",
prefixIcon: const Icon(
Icons.title,
color: ThemeInfo.myGrey,
),
),
const SizedBox(
height: 15,
),
MyTextFormField(
controller: _ketLaporanController,
focusNode: _ketLaporanFocusNode,
labelText: "Keterangan",
hintText: "Keterangan",
maxLines: 4,
prefixIcon: const Icon(
Icons.description,
color: ThemeInfo.myGrey,
),
),
],
),
),
),
actions: <Widget>[
TextButton(
child: const Text('Batalkan'),
onPressed: () {
Navigator.of(context).pop();
},
),
TextButton(
child: const Text('Upload Laporan'),
onPressed: () {
// if (_formKey.currentState!.validate()) {
// unfocus all
FocusScope.of(context).unfocus();
if (_namaLaporanController.text == '') {
info('Nama Laporan Harus Terisi', 'warning', 'Info');
_namaLaporanFocusNode.requestFocus();
return;
}
if (_ketLaporanController.text == '') {
info('Keterangan Laporan Harus Terisi', 'warning', 'Info');
_ketLaporanFocusNode.requestFocus();
return;
}
beforeUploadDialog();
},
),
],
);
},
);
}
void beforeUploadDialog() {
showDialog<void>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
content: const Text("Upload Laporan?"),
actions: <Widget>[
TextButton(
child: const Text('Batalkan'),
onPressed: () {
Navigator.of(context).pop();
},
),
TextButton(
child: const Text('Upload Laporan'),
onPressed: () {
popDialog();
uploadLaporan();
},
),
],
);
},
);
}
void uploadLaporan() async {
await EasyLoading.show(
status: "Upload Laporan...",
maskType: EasyLoadingMaskType.black,
);
BaseResponse? response = await ApiServices.uploadLaporan(
_imgPath, _namaLaporanController.text, _ketLaporanController.text);
// await Future.delayed(const Duration(milliseconds: 2000));
await EasyLoading.dismiss();
if (response == null) {
return info('Jaringan Bermasalah', 'error', 'Error');
}
if (response.status == false) {
return info(response.message, 'error', 'Error');
}
_namaLaporanController.text = '';
_ketLaporanController.text = '';
popDialog();
info(response.message, 'success', 'Sukses Upload Laporan');
// load kembali tabel
setState(() {
_pageNumber = 1;
});
getAllLaporan(1, '');
}
void setPageNumber(int newPageNumber) {
setState(() {
_pageNumber = newPageNumber;
});
getAllLaporan(_pageNumber, _searchLaporanController.text);
}
}
class _LaporanList extends StatelessWidget {
const _LaporanList({
Key? key,
required List<LaporanData>? listLaporanData,
required this.dev,
required int pageNumber,
required int? pageAll,
required int? countAll,
String? serverUrl,
}) : _listLaporanData = listLaporanData,
_pageNumber = pageNumber,
_pageAll = pageAll,
_countAll = countAll,
_serverUrl = serverUrl,
super(key: key);
final List<LaporanData>? _listLaporanData;
final Logger dev;
final int _pageNumber;
final int? _pageAll;
final int? _countAll;
final String? _serverUrl;
@override
Widget build(BuildContext context) {
return SizedBox(
child: _countAll! > 0
? Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
for (var data in _listLaporanData!)
Column(
children: [
_LaporanChild(
dev: dev,
data: data,
serverUrl: _serverUrl,
),
],
),
const SizedBox(
height: 5,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: _pageNumber == 1
? ThemeInfo.myGrey
: ThemeInfo.primary,
shape: BoxShape.circle,
boxShadow: const [
BoxShadow(
color: ThemeInfo.myGrey2,
blurRadius: 10,
spreadRadius: 5,
),
],
),
child: IconButton(
onPressed: () {
if (_pageNumber == 1) return;
// dev.i("Page previous");
int newPageNumber = _pageNumber - 1;
UploadLaporanKaryawan.of(context)!
.setPageNumber(newPageNumber);
},
icon: const Icon(Icons.arrow_back_rounded),
),
),
const SizedBox(width: 10),
Container(
width: 40,
height: 40,
alignment: Alignment.center,
decoration: const BoxDecoration(
color: ThemeInfo.primary,
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: ThemeInfo.myGrey2,
blurRadius: 10,
spreadRadius: 5,
),
],
),
child: Text(_pageNumber.toString()),
),
const SizedBox(width: 10),
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: _pageNumber == _pageAll
? ThemeInfo.myGrey
: ThemeInfo.primary,
shape: BoxShape.circle,
boxShadow: const [
BoxShadow(
color: ThemeInfo.myGrey2,
blurRadius: 10,
spreadRadius: 5,
),
],
),
child: IconButton(
onPressed: () {
if (_pageNumber == _pageAll) return;
// dev.i("Page next");
int newPageNumber = _pageNumber + 1;
UploadLaporanKaryawan.of(context)!
.setPageNumber(newPageNumber);
},
icon: const Icon(Icons.arrow_forward_rounded),
),
),
],
),
const SizedBox(
height: 10,
),
Text("$_countAll Laporan")
],
)
: const Text("Tiada Laporan Yang Diupload Oleh Anda"),
);
}
}
class FotoWidget extends StatelessWidget {
const FotoWidget({
Key? key,
required this.hasFoto,
this.imagebytes,
}) : super(key: key);
final bool hasFoto;
final Uint8List? imagebytes;
@override
Widget build(BuildContext context) {
return Center(
child: (hasFoto)
? Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(100),
image: const DecorationImage(
image: AssetImage(
'assets/loading.gif',
),
fit: BoxFit.fill,
),
),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(100),
image: DecorationImage(
image: MemoryImage(
imagebytes!,
),
fit: BoxFit.fill,
),
),
),
)
: const Icon(Icons.add,
color: Color.fromARGB(255, 2, 72, 72), size: 22),
);
}
}
class _LaporanChild extends StatelessWidget {
const _LaporanChild({
Key? key,
required this.data,
required this.dev,
String? serverUrl,
}) : _serverUrl = serverUrl,
super(key: key);
final LaporanData data;
final Logger dev;
final String? _serverUrl;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(10),
child: Container(
padding: const EdgeInsets.all(10),
alignment: Alignment.center,
width: double.infinity,
decoration: BoxDecoration(
color: ThemeInfo.myGrey,
borderRadius: BorderRadius.circular(10),
boxShadow: const [
BoxShadow(
color: ThemeInfo.myGrey2,
blurRadius: 10,
spreadRadius: 5,
),
],
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Expanded(
flex: 4,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
data.createdAt != null
? OtherServices.dateFormater(data.createdAt!, 'date')!
: "",
style: const TextStyle(
color: ThemeInfo.negroTexto,
fontSize: 15,
fontWeight: FontWeight.bold,
),
),
Text(
data.createdAt != null
? OtherServices.dateFormater(data.createdAt!, 'time')!
: "",
style: const TextStyle(
color: ThemeInfo.negroTexto,
fontSize: 15,
fontWeight: FontWeight.bold,
),
),
],
),
),
Expanded(
flex: 5,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
data.namaLaporan ?? '',
style: const TextStyle(
color: ThemeInfo.negroTexto,
fontSize: 15,
fontWeight: FontWeight.bold,
),
),
Text(
// lorem ipsum dolor sit amet consectetur adipisicing elit.
data.ketLaporan ?? '',
overflow: TextOverflow.ellipsis,
maxLines: 2,
style: const TextStyle(
color: ThemeInfo.negroTexto,
fontSize: 10,
fontWeight: FontWeight.bold,
),
),
],
),
),
Expanded(
flex: 3,
child: Container(
width: 40,
height: 40,
decoration: const BoxDecoration(
color: ThemeInfo.readFile,
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: ThemeInfo.myGrey2,
blurRadius: 10,
spreadRadius: 5,
),
],
),
child: IconButton(
onPressed: () {
// dev.i("heheheh");
showLaporan(context);
},
icon: const Icon(Icons.read_more_outlined),
),
),
),
],
),
),
);
}
void showLaporan(BuildContext context) {
// dev.i("sini show laporan");
showDialog<void>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
content: SizedBox(
// height: MediaQuery.of(context).size.height * 0.5,
width: MediaQuery.of(context).size.width * 0.8,
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.min,
children: [
if (data.image != null)
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Image.network(
_serverUrl! + data.image!,
errorBuilder: (context, error, stackTrace) {
return const Icon(Icons.error);
},
loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null) return child;
return Center(
child: CircularProgressIndicator(
value: loadingProgress.expectedTotalBytes !=
null
? loadingProgress.cumulativeBytesLoaded /
loadingProgress.expectedTotalBytes!
: null,
),
);
},
),
const SizedBox(
height: 15,
),
],
),
Text(
data.namaLaporan!,
style: const TextStyle(
fontWeight: FontWeight.bold,
),
),
const SizedBox(
height: 15,
),
Text(
data.ketLaporan!,
textAlign: TextAlign.justify,
),
],
),
),
),
);
},
);
}
}

View File

@ -0,0 +1,289 @@
import 'package:absensi_karyawan/src/models/base_response.dart';
import 'package:absensi_karyawan/src/services/api_service.dart';
import 'package:animated_snack_bar/animated_snack_bar.dart';
import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:logger/logger.dart';
import '../services/storage_service.dart';
import '../widget/dumb_widget/my_button.dart';
import '../widget/dumb_widget/my_textformfield.dart';
import '../widget/smart_widget/appbar.dart';
import '../widget/smart_widget/bounce_scroller.dart';
class LoginPage extends StatefulWidget {
const LoginPage({Key? key}) : super(key: key);
@override
State<LoginPage> createState() => _LoginPageState();
// static _LoginPageState? of(BuildContext context) =>
// context.findAncestorStateOfType<_LoginPageState>();
}
class _LoginPageState extends State<LoginPage> {
final _storage = StorageService();
final dev = Logger();
bool _showPassword = false;
late TextEditingController _nikController;
late TextEditingController _passwordController;
late FocusNode _nikFocusNode;
late FocusNode _passwordFocusNode;
late GlobalKey<FormState> _formKey;
@override
void initState() {
super.initState();
_nikController = TextEditingController();
_passwordController = TextEditingController();
_formKey = GlobalKey<FormState>();
_nikFocusNode = FocusNode();
_passwordFocusNode = FocusNode();
baca();
}
void baca() async {
String? ini = await _storage.read('device_id');
dev.i(ini);
}
Future<void> _dialogLogin() async {
return showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Info'),
content: SingleChildScrollView(
child: ListBody(
children: const <Widget>[
Text(
'Perangkat ini akan menjadi perangkat absensi disiplin anda, anda tidak dapat login ke perangkat lain untuk absensi kedisiplinan kecuali login di perangkat ini.',
textAlign: TextAlign.justify,
),
Text(
"Infokan admin bersangkutan jika ingin menukar perangkat anda.",
textAlign: TextAlign.justify,
),
Text("Anda yakin untuk login ?")
],
),
),
actions: <Widget>[
TextButton(
child: const Text('Batalkan'),
onPressed: () {
Navigator.of(context).pop();
},
),
TextButton(
child: const Text('Login'),
onPressed: () {
Navigator.of(context).pop();
loginUser();
},
),
],
);
},
);
}
void loginUser() async {
String nik = _nikController.text;
String password = _passwordController.text;
await EasyLoading.show(
status: "Login...",
maskType: EasyLoadingMaskType.black,
);
BaseResponse? response = await ApiServices.login(nik, password);
await EasyLoading.dismiss();
if (response == null) {
return info(null, false);
}
if (response.status == false) {
// if (mounted) {
_nikFocusNode.requestFocus();
return info(response.message, false);
// }
}
// dev.i(response.firstTime);
await _storage.write('userData', response.data);
info(response.message, true);
bool firstTime = false;
if (response.firstTime == true) {
firstTime = true;
}
toHomepage(firstTime);
}
void info(String? message, bool stat) {
AnimatedSnackBar.rectangle(
stat ? 'Sukses Login' : 'Error',
message ?? 'Jaringan Bermasalah',
type: stat ? AnimatedSnackBarType.success : AnimatedSnackBarType.error,
brightness: Brightness.dark,
).show(
context,
);
}
void toHomepage(bool firstTime) {
Navigator.pushNamedAndRemoveUntil(
context,
'karyawan_index',
arguments: firstTime,
(route) => false,
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: PreferredSize(
preferredSize:
Size.fromHeight(MediaQuery.of(context).size.height * 0.07),
child: const AppBarWidget(
header: 'HALAMAN LOGIN',
autoLeading: false,
),
),
body: Form(
key: _formKey,
child: BounceScrollerWidget(
children: [
Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).size.height * 0.05,
top: MediaQuery.of(context).size.height * 0.1,
),
child: Image.asset(
'assets/logo_mamuju_tengah.png',
height: 150,
width: 150,
),
),
Padding(
padding: const EdgeInsets.only(
bottom: 20,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Padding(
padding: EdgeInsets.only(left: 10),
child: Text(
'Masukkan NIK',
style: TextStyle(
fontSize: 15,
),
),
),
const SizedBox(
height: 10,
),
MyTextFormField(
controller: _nikController,
focusNode: _nikFocusNode,
labelText: 'NIK',
hintText: 'Masukkan NIK',
validator: (value) {
if (value!.isEmpty) {
// focus to nik
_nikFocusNode.requestFocus();
return 'NIK tidak boleh kosong';
}
return null;
},
),
],
),
),
Padding(
padding: const EdgeInsets.only(
bottom: 20,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Padding(
padding: EdgeInsets.only(left: 10),
child: Text(
'Masukkan Password',
style: TextStyle(
fontSize: 15,
),
),
),
const SizedBox(
height: 10,
),
MyTextFormField(
controller: _passwordController,
focusNode: _passwordFocusNode,
labelText: 'Password',
hintText: 'Masukkan Password',
obscureText: !_showPassword,
validator: (value) {
if (value!.isEmpty) {
// focus to password
_passwordFocusNode.requestFocus();
return 'Password tidak boleh kosong';
}
return null;
},
suffixIcon: IconButton(
icon: Icon(
_showPassword ? Icons.visibility : Icons.visibility_off,
color: Colors.grey,
),
onPressed: () {
setState(() {
_showPassword = !_showPassword;
});
},
),
),
],
),
),
Padding(
padding: EdgeInsets.only(
top: MediaQuery.of(context).size.height * 0.03,
),
child: SizedBox(
width: double.infinity,
height: 45,
child: MyButton(
text: 'Login',
onPressed: () {
// dev.log("sini login");
if (_formKey.currentState!.validate()) {
// unfocus all
FocusScope.of(context).unfocus();
dev.i("sini login");
_dialogLogin();
// Navigator.pushNamedAndRemoveUntil(
// context, 'karyawan_index', (route) => false);
}
},
),
),
),
],
),
),
);
}
}

View File

@ -0,0 +1,125 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:logger/logger.dart';
import 'package:platform_device_id/platform_device_id.dart';
import '../config/theme.dart';
import '../services/storage_service.dart';
class SplashScreenPage extends StatefulWidget {
const SplashScreenPage({Key? key}) : super(key: key);
@override
State<SplashScreenPage> createState() => _SplashScreenPageState();
}
class _SplashScreenPageState extends State<SplashScreenPage> {
final dev = Logger();
// String? _deviceId;
final _storage = StorageService();
@override
void initState() {
super.initState();
initPlatformState();
// future 3 sec
Future.delayed(const Duration(seconds: 4), () async {
// await _storage.remove('userData');
var checkUser = await _storage.read('userData');
// dev.i(checkUser);
if (checkUser == null) {
goToLogin();
} else {
goToHomepage();
}
// Navigator.pushReplacementNamed(context, 'login');
});
}
void goToLogin() {
Navigator.pushReplacementNamed(context, 'login');
}
void goToHomepage() {
Navigator.pushNamedAndRemoveUntil(
context,
'karyawan_index',
arguments: false,
(route) => false,
);
}
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initPlatformState() async {
String? deviceId;
// Platform messages may fail, so we use a try/catch PlatformException.
try {
deviceId = await PlatformDeviceId.getDeviceId;
} on PlatformException {
deviceId = 'Failed to get deviceId.';
}
_storage.write('device_id', deviceId);
// // If the widget was removed from the tree while the asynchronous platform
// // message was in flight, we want to discard the reply rather than calling
// // setState to update our non-existent appearance.
// if (!mounted) return;
// setState(() {
// _deviceId = deviceId;
// dev.i("deviceId->$_deviceId");
// });
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: ThemeInfo.primary,
body: SafeArea(
child: Stack(
children: [
Center(
child: Image.asset(
'assets/logo_mamuju_tengah.png',
width: 200,
height: 200,
),
),
const Positioned(
bottom: 150,
left: 15,
right: 15,
child: Center(
child: Text(
'APLIKASI ABSENSI KARYAWAN',
style: TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.center,
),
),
),
const Positioned(
bottom: 10,
left: 15,
right: 15,
child: Center(
child: Text(
'Dinas Pariwisata Dan Kebudayaan\nKabupaten Mamuju Tengah\n\nAirlangga IT',
style: TextStyle(
color: Colors.white,
fontSize: 10,
fontWeight: FontWeight.w400),
textAlign: TextAlign.center,
),
),
),
],
),
),
);
}
}

View File

@ -0,0 +1,3 @@
import 'package:flutter/cupertino.dart';
class LoginProvider extends ChangeNotifier {}

View File

@ -0,0 +1,263 @@
import 'package:dio/dio.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:logger/logger.dart';
import '../models/base_response.dart';
import '../models/user_data_model.dart';
import 'storage_service.dart';
class ApiServices {
static final dev = Logger();
static final storage = StorageService();
static final url = dotenv.env['SERVER_URL'];
static final options = BaseOptions(
baseUrl: url!,
connectTimeout: 5000,
receiveTimeout: 5000,
);
static Dio dio = Dio(options);
static Future<BaseResponse?> login(String nik, String password) async {
try {
String endpoint = 'login';
String deviceId = await storage.read("device_id");
Map<String, String> data = {
"nik": nik,
"password": password,
"device_id": deviceId,
};
var response = await dio.post(endpoint, data: data);
var responseReturn = response.data;
// dev.i(responseReturn);
return BaseResponse.fromJson(responseReturn);
} on DioError catch (e) {
dev.e(e);
return BaseResponse(
status: false,
message: e.response != null ? e.response!.data['message'] : e.message,
);
} catch (e) {
dev.e(e);
return null;
}
}
static Future<BaseResponse?> uploadLaporan(
String? imgPath, String namaLaporan, String ketLaporan) async {
try {
String endpoint = 'laporan';
String deviceId = await storage.read("device_id");
Map<String, dynamic> userData = await storage.read("userData");
UserDataModel userDataModel = UserDataModel.fromJson(userData);
var formData = FormData.fromMap({
'ada_foto': imgPath != null ? true : false,
'image': imgPath != null ? await MultipartFile.fromFile(imgPath) : null,
'nik': userDataModel.nik,
'device_id': deviceId,
'id_dinas': userDataModel.idDinas,
'nama_laporan': namaLaporan,
'ket_laporan': ketLaporan,
});
var response = await dio.post(endpoint, data: formData);
var data = response.data;
dev.i(data);
return BaseResponse.fromJson(data);
} on DioError catch (e) {
dev.e(e);
return BaseResponse(
status: false,
message: e.response != null ? e.response!.data['message'] : e.message,
);
} catch (e) {
dev.e(e);
return null;
}
}
static Future<BaseResponse?> getLaporan(int page, String search) async {
dev.i(page);
try {
Map<String, dynamic> userData = await storage.read("userData");
UserDataModel userDataModel = UserDataModel.fromJson(userData);
String deviceId = await storage.read("device_id");
String endpoint =
'laporan?nik=${userDataModel.nik}&device_id=$deviceId&page=$page&where=$search';
// dev.i(endpoint);
var response = await dio.get(endpoint);
var responseReturn = response.data;
// dev.i(responseReturn['data']['data']);
// return null;
return BaseResponse.fromJson(responseReturn);
} on DioError catch (e) {
dev.e(e);
return BaseResponse(
status: false,
message: e.response != null ? e.response!.data['message'] : e.message,
);
} catch (e) {
dev.e(e);
return null;
}
}
static Future<BaseResponse?> getJadwalDinas() async {
try {
Map<String, dynamic> userData = await storage.read("userData");
UserDataModel userDataModel = UserDataModel.fromJson(userData);
var response = await dio
.post("jadwal_dinas", data: {"id_dinas": userDataModel.idDinas});
var responseReturn = response.data;
// dev.i(responseReturn['data']);
// return null;
if (response.statusCode == 200) {
storage.write('jadwalKerja', responseReturn['data']);
}
return null;
} on DioError catch (e) {
dev.e(e);
return null;
} catch (e) {
dev.e(e);
return null;
}
}
static Future<BaseResponse?> getUserData() async {
try {
Map<String, dynamic> userData = await storage.read("userData");
UserDataModel userDataModel = UserDataModel.fromJson(userData);
var response = await dio.get("user_data?nik=${userDataModel.nik}");
var responseReturn = response.data;
// dev.i(responseReturn['data']);
if (response.statusCode == 200) {
await storage.write('userData', responseReturn['data']);
}
// return null;
return null;
} on DioError catch (e) {
dev.e(e);
return null;
} catch (e) {
dev.e(e);
return null;
}
}
static Future<BaseResponse?> getUserTodayAbsensi(String date) async {
try {
Map<String, dynamic> userData = await storage.read("userData");
UserDataModel userDataModel = UserDataModel.fromJson(userData);
var response =
await dio.get("today_absensi?nik=${userDataModel.nik}&date=$date");
var responseReturn = response.data;
// dev.i(responseReturn);
// return null;
return BaseResponse.fromJson(responseReturn);
} on DioError catch (e) {
// dev.e(e.response);
// return null;
if (e.response == null) return null;
return BaseResponse(
status: false,
message: e.response != null ? e.response!.data['message'] : e.message,
);
} catch (e) {
dev.e(e);
return null;
}
}
static Future<BaseResponse?> getTodayLiburAndPerjalanDinas(
String date) async {
try {
Map<String, dynamic> userData = await storage.read("userData");
UserDataModel userDataModel = UserDataModel.fromJson(userData);
var response = await dio.get(
"get_perjalanan_dinas_libur?nik=${userDataModel.nik}&date=$date");
var responseReturn = response.data;
BaseResponse baseResponse = BaseResponse.fromJson(responseReturn);
if (baseResponse.data == null) {
await storage.write('ada_perjalanan_dinas_libur', 'tiada');
} else {
await storage.write('ada_perjalanan_dinas_libur', baseResponse.data);
// dev.i(baseResponse.data);
}
return null;
// return BaseResponse.fromJson(responseReturn);
} on DioError catch (e) {
dev.e(e.response);
// return null;
await storage.write('ada_perjalanan_dinas_libur', null);
if (e.response == null) return null;
return BaseResponse(
status: false,
message: e.response != null ? e.response!.data['message'] : e.message,
);
} catch (e) {
await storage.write('ada_perjalanan_dinas_libur', null);
dev.e(e);
return null;
}
}
static Future<BaseResponse?> postUserTodayAbsensi(
String date, String stat) async {
try {
Map<String, dynamic> userData = await storage.read("userData");
UserDataModel userDataModel = UserDataModel.fromJson(userData);
var response = await dio.post("today_absensi",
data: {'nik': userDataModel.nik, "date": date, "stat": stat});
var responseReturn = response.data;
dev.i(responseReturn);
return null;
// return BaseResponse.fromJson(responseReturn);
} on DioError catch (e) {
// dev.e(e.response);
// return null;
if (e.response == null) return null;
return BaseResponse(
status: false,
message: e.response != null ? e.response!.data['message'] : e.message,
);
} catch (e) {
dev.e(e);
return null;
}
}
static Future<void> sendMyLocation(String lat, String lng) async {
try {
Map<String, dynamic> userData = await storage.read("userData");
UserDataModel userDataModel = UserDataModel.fromJson(userData);
dev.i(lat);
dev.i(lng);
var response = await dio.post("my_location",
data: {'nik': userDataModel.nik, "lat": lat, "lng": lng});
var responseReturn = response.data;
dev.i(responseReturn);
} on DioError catch (e) {
dev.e(e);
} catch (e) {
dev.e(e);
}
}
}

View File

@ -0,0 +1,205 @@
import 'dart:async';
import 'package:absensi_karyawan/src/services/api_service.dart';
import 'package:absensi_karyawan/src/services/storage_service.dart';
import 'package:location/location.dart';
import 'package:logger/logger.dart';
Location location = Location();
final dev = Logger();
final storage = StorageService();
// Stream<void> getLoc() async* {
Future<void> getLoc() async {
// bool checkIfRunGps = await storage.read('runGPS');
dev.i("heheh");
bool serviceEnabled;
PermissionStatus permissionGranted;
// ignore: unused_local_variable
LocationData locationData;
// await location.isBackgroundModeEnabled();
// await location.enableBackgroundMode();
serviceEnabled = await location.serviceEnabled();
if (!serviceEnabled) {
serviceEnabled = await location.requestService();
if (!serviceEnabled) {
return;
}
}
permissionGranted = await location.hasPermission();
if (permissionGranted == PermissionStatus.denied) {
permissionGranted = await location.requestPermission();
if (permissionGranted != PermissionStatus.granted) {
return;
}
}
location.changeSettings(
accuracy: LocationAccuracy.high, interval: 10000, distanceFilter: 3);
// locationData = await location.getLocation();
while (true) {
bool checkIfRunGps = await storage.read('runGPS');
dev.i("ini check if gps $checkIfRunGps");
if (checkIfRunGps) {
locationData = await location.getLocation();
// dev.i("ini location sekarang ${locationData.}");
await ApiServices.sendMyLocation(
locationData.latitude.toString(), locationData.longitude.toString());
}
await Future.delayed(const Duration(seconds: 10));
}
// if (checkIfRunGps) {
// dev.i("ini location sekarang $locationData");
// }
// location.onLocationChanged.listen((LocationData currentLocation) async {
// bool checkIfRunGps1 = await storage.read('runGPS');
// if (checkIfRunGps1) {
// dev.i("ini location sekarang $locationData");
// }
// });
// return;
// dev.i("ini location sekarang $locationData");
}
// import 'package:geolocator/geolocator.dart';
// import 'package:logger/logger.dart';
// final dev = Logger();
// Future<Position> determinePosition() async {
// //
// late LocationSettings locationSettings;
// locationSettings = const LocationSettings(
// accuracy: LocationAccuracy.low,
// distanceFilter: 5,
// // timeLimit: Duration(seconds: 10),
// );
// bool serviceEnabled;
// LocationPermission permission;
// locationSettings;
// // Test if location services are enabled.
// serviceEnabled = await Geolocator.isLocationServiceEnabled();
// if (!serviceEnabled) {
// // Location services are not enabled don't continue
// // accessing the position and request users of the
// // App to enable the location services.
// return Future.error('Location services are disabled.');
// }
// permission = await Geolocator.checkPermission();
// if (permission == LocationPermission.denied) {
// permission = await Geolocator.requestPermission();
// if (permission == LocationPermission.denied) {
// // Permissions are denied, next time you could try
// // requesting permissions again (this is also where
// // Android's shouldShowRequestPermissionRationale
// // returned true. According to Android guidelines
// // your App should show an explanatory UI now.
// return Future.error('Location permissions are denied');
// }
// }
// if (permission == LocationPermission.deniedForever) {
// // Permissions are denied forever, handle appropriately.
// return Future.error(
// 'Location permissions are permanently denied, we cannot request permissions.');
// }
// // When we reach here, permissions are granted and we can
// // continue accessing the position of the device.
// var thisLocation = await Geolocator.getCurrentPosition();
// // var position = await determinePosition();
// // String positionString = thisLocation.toString();
// // BaseResponse? result = await ApiServices.percobaan(positionString);
// // result;
// // dev.i(thisLocation);
// String positionString = thisLocation.toString();
// dev.i("this is the position $positionString");
// // await ApiServices.percobaan(positionString);
// return thisLocation;
// }
// final dev = Logger();
// void settingGPS() {
// late LocationSettings locationSettings;
// if (defaultTargetPlatform == TargetPlatform.android) {
// locationSettings = AndroidSettings(
// accuracy: LocationAccuracy.high,
// distanceFilter: 3,
// forceLocationManager: true,
// intervalDuration: const Duration(seconds: 15),
// //(Optional) Set foreground notification config to keep the app alive
// //when going to the background
// foregroundNotificationConfig: const ForegroundNotificationConfig(
// notificationText:
// "Example app will continue to receive your location even when you aren't using it",
// notificationTitle: "Running in Background",
// enableWakeLock: true,
// ));
// } else if (defaultTargetPlatform == TargetPlatform.iOS ||
// defaultTargetPlatform == TargetPlatform.macOS) {
// locationSettings = AppleSettings(
// accuracy: LocationAccuracy.high,
// activityType: ActivityType.fitness,
// distanceFilter: 5,
// pauseLocationUpdatesAutomatically: true,
// // Only set to true if our app will be started up in the background.
// showBackgroundLocationIndicator: false,
// );
// } else {
// locationSettings = const LocationSettings(
// accuracy: LocationAccuracy.high,
// distanceFilter: 5,
// );
// }
// locationSettings;
// StreamSubscription<Position> positionStream =
// Geolocator.getPositionStream(locationSettings: locationSettings)
// .listen((Position? position) async {
// dev.i(position == null
// ? 'Unknown'
// : '${position.latitude.toString()}, ${position.longitude.toString()}');
// String positionString = position.toString();
// await ApiServices.percobaan(positionString);
// });
// positionStream;
// }
// StreamSubscription<Position>? _positionStreamSubscription;
// final GeolocatorPlatform _geolocatorPlatform = GeolocatorPlatform.instance;
// void toggleListening() {
// if (_positionStreamSubscription == null) {
// final positionStream = _geolocatorPlatform.getPositionStream();
// _positionStreamSubscription = positionStream.handleError((error) {
// _positionStreamSubscription?.cancel();
// _positionStreamSubscription = null;
// }).listen((position) {
// dev.i(position);
// });
// }
// }
// import 'package:location/location.dart';
// import 'package:logger/logger.dart';
// import 'api_service.dart';
// final dev = Logger();
// void getTheLocation() async {
// final location = await getLocation();
// dev.i("Location: ${location.latitude}, ${location.longitude}");
// String positionString = location.latitude.toString();
// await ApiServices.percobaan(positionString);
// }

View File

@ -0,0 +1,94 @@
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter_native_timezone/flutter_native_timezone.dart';
import 'package:rxdart/rxdart.dart';
import 'package:timezone/timezone.dart' as tz;
// import 'package:timezone/tzdata.dart' as tz;
// ignore: avoid_classes_with_only_static_members
class NotificationServices {
// Below is the code for initializing the plugin using var _notificationPlugin
static final _notifications = FlutterLocalNotificationsPlugin();
static final onNotifications = BehaviorSubject<String?>();
static Future showNotification({
required int id,
String? title,
String? body,
String? payload,
}) async =>
_notifications.show(
id,
title,
body,
await _notificanDetails(),
payload: payload,
);
// static Future showScheduleNotification() async =>
// _notifications.zonedSchedule(
// 0,
// 'Cek Laporan',
// "Laporan Baru Mungkin Ada, Sila Cek Di Aplikasi",
// // tz.TZDateTime.from(scheduledDate, tz.local),
// _scheduleDaily(const Time(18)),
// await _notificanDetails(),
// payload: "Laporan Baru Mungkin Ada, Sila Cek Di Aplikasi",
// androidAllowWhileIdle: true,
// uiLocalNotificationDateInterpretation:
// UILocalNotificationDateInterpretation.absoluteTime,
// matchDateTimeComponents: DateTimeComponents.time,
// );
static Future _notificanDetails() async {
const AndroidNotificationDetails androidPlatformChannelSpecifics =
AndroidNotificationDetails(
'your channel id',
'your channel name',
channelDescription: 'your channel description',
importance: Importance.max,
// priority: Priority.high,
// ticker: 'ticker',
);
return const NotificationDetails(
android: androidPlatformChannelSpecifics,
iOS: IOSNotificationDetails(),
);
}
static Future init(
{bool initScheduled = false, BuildContext? context}) async {
const android = AndroidInitializationSettings('@mipmap/ic_launcher');
const iOS = IOSInitializationSettings();
const settings = InitializationSettings(android: android, iOS: iOS);
final details = await _notifications.getNotificationAppLaunchDetails();
if (details != null && details.didNotificationLaunchApp) {
onNotifications.add(details.payload);
}
await _notifications.initialize(
settings,
onSelectNotification: (payload) async {
onNotifications.add(payload);
},
);
if (initScheduled) {
final locationName = await FlutterNativeTimezone.getLocalTimezone();
tz.setLocalLocation(tz.getLocation(locationName));
}
}
// static tz.TZDateTime _scheduleDaily(Time time) {
// final tz.TZDateTime now = tz.TZDateTime.now(tz.local);
// final scheduledDate = tz.TZDateTime(tz.local, now.year, now.month, now.day,
// time.hour, time.minute, time.second);
// // if (scheduledDate.isBefore(now)) {
// // scheduledDate = scheduledDate.add(const Duration(days: 1));
// // }
// return scheduledDate.isBefore(now)
// ? scheduledDate.add(const Duration(days: 1))
// : scheduledDate;
// }
}

View File

@ -0,0 +1,73 @@
import 'dart:math';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:logger/logger.dart';
import 'package:path_provider/path_provider.dart';
class OtherServices {
static final dev = Logger();
static Future<void> cekAndDelete() async {
final appStorage = await getTemporaryDirectory();
// // if (appStorage.existsSync()) {
final fileList = appStorage.listSync();
dev.i("${fileList}ini file list");
if (fileList.isNotEmpty) {
dev.i("ada file");
// print(fileList);
for (var i = 0; i < fileList.length; i++) {
final file = fileList[i];
dev.i(file.path);
if (file.toString().contains(".jpg") ||
file.toString().contains(".png") ||
file.toString().contains(".jpeg") ||
file.toString().contains(".JPG") ||
file.toString().contains(".PNG") ||
file.toString().contains(".JPEG")) {
dev.i("delete");
await file.delete(recursive: true);
}
}
} else {
dev.i("tidak ada file");
// print(fileList);
}
}
static String? dateFormater(String date, String stat) {
String? thisReturn;
if (stat == "date") {
thisReturn = date.split(" ")[0];
} else if (stat == "time") {
thisReturn = date.split(" ")[1];
}
return thisReturn;
}
static String dayNameChanger(String day) {
const dayMap = {
"senin": "Monday",
"selasa": "Tuesday",
"rabu": "Wednesday",
"kamis": "Thursday",
"jumat": "Friday",
"sabtu": "Saturday",
"minggu": "Sunday",
};
String dayName = dayMap[day]!;
return dayName;
}
static dynamic checkIfInRadius(
LatLng currentLocation, LatLng centerLocation) {
double ky = 40000 / 360;
const double pi = 3.1415926535897932;
double kx = cos(pi * centerLocation.latitude / 180.0) * ky;
double first = centerLocation.longitude - currentLocation.longitude;
double sec = centerLocation.latitude - currentLocation.latitude;
double dx = first.abs() * kx;
double dy = sec.abs() * ky;
return sqrt(dx * dx + dy * dy) <= 0.1;
}
}

View File

@ -0,0 +1,30 @@
import 'package:get_storage/get_storage.dart';
class StorageService {
static final StorageService _singleton = StorageService.internal();
factory StorageService() {
return _singleton;
}
StorageService.internal();
late GetStorage _storage;
init() async {
await GetStorage.init();
_storage = GetStorage();
}
Future<dynamic> read(String key) async {
return await _storage.read(key);
}
Future<void> write(String key, dynamic val) async {
return await _storage.write(key, val);
}
Future<void> remove(String key) async {
return await _storage.remove(key);
}
}

View File

@ -0,0 +1,34 @@
import 'package:flutter/material.dart';
import '../../config/theme.dart';
class MyButton extends StatelessWidget {
const MyButton({
Key? key,
required this.text,
this.onPressed,
}) : super(key: key);
final String text;
final VoidCallback? onPressed;
@override
Widget build(BuildContext context) {
return ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: ThemeInfo.primary,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
),
),
onPressed: onPressed,
child: Text(
text,
style: const TextStyle(
color: ThemeInfo.background,
fontSize: 18,
),
),
);
}
}

View File

@ -0,0 +1,73 @@
import 'package:flutter/material.dart';
import '../../config/theme.dart';
class MyTextFormField extends StatelessWidget {
const MyTextFormField({
Key? key,
this.labelText,
this.hintText,
this.obscureText,
this.validator,
this.suffixIcon,
this.prefixIcon,
this.focusNode,
this.controller,
this.maxLines = 1,
this.onEditingComplete,
}) : super(key: key);
final String? labelText;
final String? hintText;
final bool? obscureText;
final FormFieldValidator<String>? validator;
final Widget? suffixIcon;
final Widget? prefixIcon;
final FocusNode? focusNode;
final TextEditingController? controller;
final int maxLines;
final VoidCallback? onEditingComplete;
@override
Widget build(BuildContext context) {
return TextFormField(
onEditingComplete: onEditingComplete,
maxLines: maxLines,
controller: controller,
focusNode: focusNode,
obscureText: obscureText ?? false,
decoration: InputDecoration(
prefixIcon: prefixIcon,
suffixIcon: suffixIcon,
enabledBorder: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(25)),
borderSide: BorderSide(
color: ThemeInfo.primary,
),
),
focusedBorder: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(25)),
borderSide: BorderSide(
color: ThemeInfo.primary,
),
),
focusedErrorBorder: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(25)),
borderSide: BorderSide(
color: ThemeInfo.danger,
),
),
errorBorder: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(25)),
borderSide: BorderSide(
color: ThemeInfo.danger,
),
),
labelText: labelText,
hintText: hintText,
labelStyle: const TextStyle(color: ThemeInfo.negroTexto),
),
validator: validator,
);
}
}

View File

@ -0,0 +1,34 @@
import 'package:flutter/material.dart';
import '../../config/theme.dart';
class AppBarWidget extends StatelessWidget {
const AppBarWidget({
Key? key,
required this.header,
required this.autoLeading,
}) : super(key: key);
final String header;
final bool autoLeading;
@override
Widget build(BuildContext context) {
return AppBar(
centerTitle: true,
title: Text(
header,
style: TextStyle(
fontSize: MediaQuery.of(context).size.height * 0.03,
fontWeight: FontWeight.bold,
),
),
automaticallyImplyLeading: autoLeading,
backgroundColor: ThemeInfo.primary,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
bottom: Radius.circular(40),
),
),
);
}
}

View File

@ -0,0 +1,27 @@
import 'package:flutter/material.dart';
class BounceScrollerWidget extends StatelessWidget {
final List<Widget> children;
const BounceScrollerWidget({Key? key, required this.children})
: super(key: key);
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: SizedBox(
height: MediaQuery.of(context).size.height * 0.9,
width: MediaQuery.of(context).size.width,
child: ListView(
padding: EdgeInsets.only(
left: MediaQuery.of(context).size.height * 0.03,
right: MediaQuery.of(context).size.height * 0.03,
),
physics: const BouncingScrollPhysics(
parent: AlwaysScrollableScrollPhysics(),
),
children: children,
),
),
);
}
}

View File

@ -0,0 +1,50 @@
import 'package:convex_bottom_bar/convex_bottom_bar.dart';
import 'package:flutter/material.dart';
import '../../config/theme.dart';
class KaryawanBottomBar extends StatelessWidget {
const KaryawanBottomBar(
{Key? key, required this.indexSelected, required this.onTap})
: super(key: key);
final int indexSelected;
final Function(int) onTap;
@override
Widget build(BuildContext context) {
return ConvexAppBar(
// cornerRadius: 10,
initialActiveIndex: indexSelected,
disableDefaultTabController: true,
backgroundColor: ThemeInfo.primary,
items: [
TabItem(
icon: Icon(
Icons.list_alt_outlined,
color: (indexSelected == 0) ? ThemeInfo.primary : ThemeInfo.myGrey,
),
title: 'Laporan',
),
TabItem(
icon: Icon(
Icons.calendar_month_outlined,
color: (indexSelected == 1) ? ThemeInfo.primary : ThemeInfo.myGrey,
),
title: 'Absensi',
),
TabItem(
icon: Icon(
Icons.person_outline,
color: (indexSelected == 2) ? ThemeInfo.primary : ThemeInfo.myGrey,
),
title: 'Profil',
),
],
elevation: 1,
onTap: (int index) {
onTap(index);
},
);
}
}

1
linux/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
flutter/ephemeral

Some files were not shown because too many files have changed in this diff Show More