first commit

This commit is contained in:
brahmihawa2023 2025-06-19 16:44:10 +07:00
commit 3585f4c453
176 changed files with 10921 additions and 0 deletions

45
AdmindukPuger_mobile-master/.gitignore vendored Normal file
View File

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

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 and should not be manually edited.
version:
revision: "35c388afb57ef061d06a39b537336c87e0e3d1b1"
channel: "stable"
project_type: app
# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
base_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
- platform: android
create_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
base_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
- platform: ios
create_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
base_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
- platform: linux
create_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
base_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
- platform: macos
create_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
base_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
- platform: web
create_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
base_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
- platform: windows
create_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
base_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
# 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'

View File

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

View File

@ -0,0 +1,28 @@
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at https://dart.dev/lints.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options

View File

@ -0,0 +1,14 @@
gradle-wrapper.jar
/.gradle
/captures/
/gradlew
/gradlew.bat
/local.properties
GeneratedPluginRegistrant.java
.cxx/
# Remember to never publicly share your keystore.
# See https://flutter.dev/to/reference-keystore
key.properties
**/*.keystore
**/*.jks

View File

@ -0,0 +1,44 @@
plugins {
id("com.android.application")
id("kotlin-android")
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
id("dev.flutter.flutter-gradle-plugin")
}
android {
namespace = "com.example.adminduk_puger"
compileSdk = flutter.compileSdkVersion
ndkVersion = flutter.ndkVersion
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_11.toString()
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId = "com.example.adminduk_puger"
// You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = 21
targetSdk = 33
versionCode = flutter.versionCode
versionName = flutter.versionName
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig = signingConfigs.getByName("debug")
}
}
}
flutter {
source = "../.."
}

View File

@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

View File

@ -0,0 +1,48 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:label="adminduk_puger"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:taskAffinity=""
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
<!-- Required to query activities that can process text, see:
https://developer.android.com/training/package-visibility and
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
<queries>
<intent>
<action android:name="android.intent.action.PROCESS_TEXT"/>
<data android:mimeType="text/plain"/>
</intent>
</queries>
</manifest>

View File

@ -0,0 +1,5 @@
package com.example.adminduk_puger
import io.flutter.embedding.android.FlutterActivity
class MainActivity : FlutterActivity()

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>

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: 544 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 721 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 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,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

View File

@ -0,0 +1,21 @@
allprojects {
repositories {
google()
mavenCentral()
}
}
val newBuildDir: Directory = rootProject.layout.buildDirectory.dir("../../build").get()
rootProject.layout.buildDirectory.value(newBuildDir)
subprojects {
val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)
project.layout.buildDirectory.value(newSubprojectBuildDir)
}
subprojects {
project.evaluationDependsOn(":app")
}
tasks.register<Delete>("clean") {
delete(rootProject.layout.buildDirectory)
}

View File

@ -0,0 +1,3 @@
org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
android.useAndroidX=true
android.enableJetifier=true

View File

@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip

View File

@ -0,0 +1,25 @@
pluginManagement {
val flutterSdkPath = run {
val properties = java.util.Properties()
file("local.properties").inputStream().use { properties.load(it) }
val flutterSdkPath = properties.getProperty("flutter.sdk")
require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" }
flutterSdkPath
}
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
plugins {
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
id("com.android.application") version "8.7.0" apply false
id("org.jetbrains.kotlin.android") version "1.8.22" apply false
}
include(":app")

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

View File

@ -0,0 +1,3 @@
description: This file stores settings for Dart & Flutter DevTools.
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
extensions:

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

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,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1510"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
<TestableReference
skipped = "NO"
parallelizable = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "331C8080294A63A400263BE5"
BuildableName = "RunnerTests.xctest"
BlueprintName = "RunnerTests"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
enableGPUValidationMode = "1"
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 Flutter
import UIKit
@main
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}

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: 295 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 450 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 462 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 704 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 586 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 862 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 862 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 762 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 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>

View File

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Adminduk Puger</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>adminduk_puger</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
</dict>
</plist>

View File

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

View File

@ -0,0 +1,12 @@
import Flutter
import UIKit
import XCTest
class RunnerTests: XCTestCase {
func testExample() {
// If you add code to the Runner application, consider adding tests here.
// See https://developer.apple.com/documentation/xctest for more information about using XCTest.
}
}

View File

@ -0,0 +1,220 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:adminduk_puger/cubit/Auth/Auth_repository.dart';
import 'package:adminduk_puger/cubit/Auth/Auth_state.dart';
import 'package:dio/dio.dart';
import 'dart:convert';
class AuthCubit extends Cubit<AuthState> {
final AuthRepository _authRepository;
AuthCubit(this._authRepository) : super(AuthInitial());
Future<void> login(String email, String password) async {
emit(AuthLoading());
try {
final response = await _authRepository.login(email, password);
print("AuthCubit received response: $response");
if (response.isEmpty) {
emit(AuthFailure("Login gagal: Response kosong"));
return;
}
if (response['success'] == true) {
// Login berhasil, email sudah diverifikasi
final token = response['access_token'] ?? "";
final user = response['user'];
await saveToken(token);
await saveUserId(user['id']);
emit(AuthSuccess(token, user['id']));
} else if (response['email_verified'] == false) {
// Kasus khusus: email belum diverifikasi
final userId = response['user_id'];
await resendVerificationEmail(userId);
emit(AuthEmailNotVerified(userId, email));
} else {
// Login gagal karena alasan lain
emit(AuthFailure(response['message'] ?? "Login gagal"));
}
} catch (e) {
print("AuthCubit login error: $e");
emit(AuthFailure(e.toString()));
}
}
Future<void> resendVerificationEmail(int userId) async {
try {
print("Mengirim ulang email verifikasi untuk user_id: $userId");
await _authRepository.resendVerificationEmail(userId);
} catch (e) {
print("Gagal mengirim ulang email verifikasi: $e");
}
}
Future<void> saveToken(String token) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString('token', token);
}
Future<String?> getToken() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getString('token');
}
Future<void> saveUserId(int userId) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setInt('user_id', userId);
}
Future<int?> getUserId() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getInt('user_id');
}
Future<int?> fetchUserId(String token) async {
try {
Dio dio = Dio();
Response response = await dio.get(
"https://adminduk-kec-puger.my.id/api/user",
options: Options(headers: {"Authorization": "Bearer $token"}),
);
if (response.statusCode == 200) {
return response.data['id'];
}
} catch (e) {
print("Fetch user ID error: $e");
}
return null;
}
Future<void> loaduser() async {
final token = await getToken();
final userId = await getUserId();
if (token != null && userId != null) {
emit(AuthSuccess(token, userId));
}
}
Future<void> logout() async {
final prefs = await SharedPreferences.getInstance();
await prefs.remove('token');
await prefs.remove('user_id');
emit(AuthInitial());
}
Future<Map<String, dynamic>?> getProfile(int userId) async {
try {
final token = await getToken();
if (token != null) {
Dio dio = Dio();
Response response = await dio.get(
"https://adminduk-kec-puger.my.id/api/user",
options: Options(headers: {"Authorization": "Bearer $token"}),
);
if (response.statusCode == 200) {
return response.data;
}
}
} catch (e) {
print("Fetch profile error: $e");
}
return null;
}
Future<void> updateProfile(
int userId,
String name,
String email,
String phone,
String password,
) async {
try {
emit(AuthLoading());
final token = await getToken();
if (token != null) {
Dio dio = Dio();
Response response = await dio.post(
"https://adminduk-kec-puger.my.id/api/updateprofile/$userId",
data: {
'name': name,
'email': email,
'phone': phone,
'password': password,
},
options: Options(headers: {"Authorization": "Bearer $token"}),
);
if (response.statusCode == 200) {
emit(AuthSuccess(token, userId));
} else {
emit(AuthFailure("Gagal mengupdate profil"));
}
} else {
emit(AuthFailure("Token tidak ditemukan"));
}
} catch (e) {
emit(AuthFailure(e.toString()));
}
}
Future<bool> deleteAccount(int userId) async {
try {
final token = await getToken();
if (token != null) {
Dio dio = Dio();
Response response = await dio.delete(
"https://adminduk-kec-puger.my.id/api/deleteaccount/$userId",
options: Options(headers: {"Authorization": "Bearer $token"}),
);
if (response.statusCode == 200) {
await logout();
return true;
}
}
return false;
} catch (e) {
print("Delete account error: $e");
return false;
}
}
Future<void> register(
String name,
String email,
String phone,
String password,
String address,
String nik,
String nokk,
) async {
emit(AuthLoading());
try {
final result = await _authRepository.register(
name,
email,
phone,
password,
address,
nik,
nokk,
);
print("Response dari backend: $result");
if (result['success']) {
final message = result['data']['message'];
emit(AuthRegistrationSuccess(message));
} else {
emit(AuthFailure(result['message'] ?? "Registrasi gagal"));
}
} catch (e) {
emit(AuthFailure(e.toString()));
}
}
}

View File

@ -0,0 +1,89 @@
import 'package:dio/dio.dart';
class AuthRepository {
final Dio _dio = Dio();
Future<Map<String, dynamic>> login(String email, String password) async {
try {
final response = await _dio.post(
'https://adminduk-kec-puger.my.id/api/login',
data: {'email': email, 'password': password},
);
print("Login response: ${response.data}");
return response.data;
} catch (e) {
print("Login error: $e");
if (e is DioException && e.response != null) {
print("Error response: ${e.response!.data}");
// Jika status 403 dan error terkait email belum diverifikasi
if (e.response!.statusCode == 403 &&
e.response!.data['email_verified'] == false) {
return e.response!.data; // Kembalikan response dari server
}
return {
'success': false,
'message': e.response!.data['message'] ?? 'Login gagal',
};
}
return {'success': false, 'message': 'Terjadi kesalahan: $e'};
}
}
Future<void> resendVerificationEmail(int userId) async {
try {
await _dio.post(
"https://adminduk-kec-puger.my.id/api/email/resend-by-id",
data: {"user_id": userId},
);
print("Email verifikasi berhasil dikirim");
} catch (e) {
print("Gagal mengirim ulang email verifikasi: $e");
}
}
Future<Map<String, dynamic>> register(
String name,
String email,
String phone,
String password,
String address,
String nik,
String nokk,
) async {
try {
Dio dio = Dio();
Response response = await dio.post(
"https://adminduk-kec-puger.my.id/api/register",
data: {
'name': name,
'email': email,
'phone': phone,
'password': password,
'address': address,
'nik': nik,
'nokk': nokk,
},
);
if (response.statusCode == 200 || response.statusCode == 201) {
return {'success': true, 'data': response.data};
} else {
return {'success': false, 'message': 'Gagal melakukan registrasi'};
}
} catch (e) {
if (e is DioException && e.response != null) {
// Handle validation errors from the server
if (e.response!.statusCode == 422 &&
e.response!.data['errors'] != null) {
final errors = e.response!.data['errors'];
final errorMsg = errors.entries.first.value[0] ?? 'Validation error';
return {'success': false, 'message': errorMsg};
}
}
return {'success': false, 'message': e.toString()};
}
}
}

View File

@ -0,0 +1,43 @@
import 'package:equatable/equatable.dart';
abstract class AuthState extends Equatable {
const AuthState();
@override
List<Object?> get props => [];
}
class AuthInitial extends AuthState {
const AuthInitial();
}
class AuthLoading extends AuthState {
const AuthLoading();
}
class AuthSuccess extends AuthState {
final String token;
final int userId;
AuthSuccess(this.token, this.userId);
}
class AuthFailure extends AuthState {
final String error;
AuthFailure(this.error);
}
class AuthEmailNotVerified extends AuthState {
final int userId;
final String email;
AuthEmailNotVerified(this.userId, this.email);
}
class AuthVerificationEmailSent extends AuthState {}
class AuthRegistrationSuccess extends AuthState {
final String email;
AuthRegistrationSuccess(this.email);
}

View File

@ -0,0 +1,90 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:path_provider/path_provider.dart';
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
class DocumentCubit extends Cubit<List<DocumentModel>> {
DocumentCubit() : super([]);
Future<void> loadDocuments() async {
final response = await http.get(
Uri.parse('https://adminduk-kec-puger.my.id/api/docs'),
);
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
final List<DocumentModel> documents =
(data['data'] as List).map((e) => DocumentModel.fromJson(e)).toList();
emit(documents);
} else {
emit([]);
}
}
// Buat fungsi download menjadi static
static Future<void> downloadDocument(
String fileName,
String url,
BuildContext context,
) async {
try {
// Minta izin penyimpanan
if (Platform.isAndroid) {
var status = await Permission.storage.request();
if (!status.isGranted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("Izin penyimpanan ditolak")),
);
return;
}
}
// Tentukan lokasi penyimpanan
Directory? directory;
if (Platform.isAndroid) {
directory = Directory('/storage/emulated/0/Download');
} else {
directory = await getApplicationDocumentsDirectory();
}
if (!await directory.exists()) {
directory = await getApplicationDocumentsDirectory();
}
String savePath = '${directory.path}/$fileName.pdf';
// Mulai download
Dio dio = Dio();
await dio.download(url, savePath);
// Tampilkan notifikasi berhasil
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text("Dokumen disimpan di: $savePath")));
} catch (e) {
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text("Gagal download: $e")));
}
}
}
class DocumentModel {
final int id;
final String judul;
final String path;
DocumentModel({required this.id, required this.judul, required this.path});
factory DocumentModel.fromJson(Map<String, dynamic> json) {
return DocumentModel(
id: json['id'],
judul: json['name'],
path: json['location'],
);
}
}

View File

@ -0,0 +1,141 @@
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class SubmissionState {
final Map<String, dynamic> data;
final List<String> submittedTypes;
SubmissionState({required this.data, required this.submittedTypes});
}
class SubmissionCubit extends Cubit<Map<String, List<Map<String, dynamic>>>> {
SubmissionCubit() : super({});
Map<String, List<Map<String, dynamic>>> _originalSubmissions = {};
String formatTanggal(String? tanggalStr) {
if (tanggalStr == null || tanggalStr.isEmpty) return "-";
try {
DateTime tanggal = DateTime.parse(tanggalStr);
List<String> namaBulan = [
"Januari",
"Februari",
"Maret",
"April",
"Mei",
"Juni",
"Juli",
"Agustus",
"September",
"Oktober",
"November",
"Desember",
];
List<String> namaHari = [
"Senin",
"Selasa",
"Rabu",
"Kamis",
"Jumat",
"Sabtu",
"Minggu",
];
String hari = namaHari[tanggal.weekday - 1];
String bulan = namaBulan[tanggal.month - 1];
return "$hari, ${tanggal.day} $bulan ${tanggal.year}";
} catch (e) {
print("Error formatting date: $e");
return tanggalStr ?? "-";
}
}
List<String> get submittedTypes {
return _originalSubmissions.keys.toList();
}
Future<void> fetchSubmissions() async {
final prefs = await SharedPreferences.getInstance();
final token = prefs.getString('token');
if (token == null) {
print("Token tidak ditemukan, tidak dapat mengambil data");
return;
}
final url = Uri.parse('https://adminduk-kec-puger.my.id/api/submission');
try {
final response = await http.get(
url,
headers: {
'Authorization': 'Bearer $token',
'Content-Type': 'application/json',
'Accept': 'application/json',
},
);
print("Response status: ${response.statusCode}");
print("Response body: ${response.body}");
if (response.statusCode == 200) {
final Map<String, dynamic> jsonData = jsonDecode(response.body);
final Map<String, dynamic> data = jsonData['data'] ?? {};
Map<String, List<Map<String, dynamic>>> categorizedSubmissions = {};
for (var category in data.keys) {
List<dynamic> submissions = data[category];
categorizedSubmissions[category] =
submissions.map((item) {
return {
"nama": item["name"] ?? "Tidak diketahui",
"jenis": item["type"] ?? category,
"status": item["status"] ?? "Belum ada status",
"tanggal": formatTanggal(item["created_at"]),
"catatan": item["notes"],
};
}).toList();
}
_originalSubmissions = categorizedSubmissions;
emit(categorizedSubmissions);
} else {
print("Error fetching submissions: ${response.statusCode}");
print("Error message: ${response.body}");
}
} catch (e) {
print("Error detail: $e");
}
}
void filterSubmissions(String query) {
if (query.isEmpty) {
emit(_originalSubmissions);
} else {
Map<String, List<Map<String, dynamic>>> filteredData = {};
_originalSubmissions.forEach((category, submissions) {
final filteredList =
submissions.where((submission) {
final nama = submission['nama'].toLowerCase();
final jenis = submission['jenis'].toLowerCase();
final status = submission['status'].toLowerCase();
final searchQuery = query.toLowerCase();
return nama.contains(searchQuery) ||
jenis.contains(searchQuery) ||
status.contains(searchQuery);
}).toList();
if (filteredList.isNotEmpty) {
filteredData[category] = filteredList;
}
});
emit(filteredData);
}
}
}

View File

@ -0,0 +1,233 @@
import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:dio/dio.dart';
import 'package:adminduk_puger/widget/upload_photo.dart';
import 'package:adminduk_puger/cubit/Auth/Auth_cubit.dart';
import 'package:adminduk_puger/cubit/Auth/Auth_state.dart';
import 'package:form_builder_validators/form_builder_validators.dart';
class Kia5 extends StatefulWidget {
Kia5({Key? key}) : super(key: key);
@override
_KtpFormState createState() => _KtpFormState();
}
class _KtpFormState extends State<Kia5> {
final _formKey = GlobalKey<FormBuilderState>();
bool _isLoading = false;
bool _isSelfSubmission = false;
Future<void> _loadProfileData() async {
final authState = context.read<AuthCubit>().state;
if (authState is AuthSuccess) {
final userId = authState.userId;
final profileData = await context.read<AuthCubit>().getProfile(userId);
if (profileData != null) {
_formKey.currentState?.fields['name']?.didChange(profileData['name']);
_formKey.currentState?.fields['nik']?.didChange(profileData['nik']);
}
}
}
Future<void> _submitForm() async {
if (_formKey.currentState?.saveAndValidate() == true) {
setState(() => _isLoading = true);
final authState = context.read<AuthCubit>().state;
if (authState is! AuthSuccess) {
setState(() => _isLoading = false);
return;
}
final userId = authState.userId;
final token = authState.token;
final formData = FormData.fromMap({
'user_id': userId,
'name': _formKey.currentState!.value['name'],
'nik': _formKey.currentState!.value['nik'],
'kk': await MultipartFile.fromFile(
_formKey.currentState!.value['KK'][0].path,
),
'akta': await MultipartFile.fromFile(
_formKey.currentState!.value['akta'][0].path,
),
'ktp': await MultipartFile.fromFile(
_formKey.currentState!.value['ktp'][0].path,
),
});
try {
Dio dio = Dio();
Response response = await dio.post(
'https://adminduk-kec-puger.my.id/api/kia5',
data: formData,
options: Options(headers: {"Authorization": "Bearer $token"}),
);
if (response.statusCode == 200) {
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('Upload berhasil')));
_formKey.currentState?.reset();
Navigator.pushNamed(context, '/home');
} else {
throw Exception('Upload gagal');
}
} catch (e) {
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('Terjadi kesalahan: $e')));
} finally {
setState(() => _isLoading = false);
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[100],
appBar: AppBar(
title: const Text('KIA Untuk Anak 5 Tahun Keatas'),
centerTitle: true,
backgroundColor: Colors.deepPurple,
),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
elevation: 6,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: FormBuilder(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
'Silahkan lengkapi Dokumen yang diperlukan',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.black87,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 15),
FormBuilderCheckbox(
name: 'self_submission',
title: Text('Pengajuan untuk diri sendiri'),
initialValue: false,
onChanged: (value) async {
setState(() {
_isSelfSubmission = value ?? false;
});
if (value == true) {
await _loadProfileData();
} else {
_formKey.currentState?.fields['name']?.reset();
_formKey.currentState?.fields['nik']?.reset();
}
},
),
const SizedBox(height: 15),
FormBuilderTextField(
name: 'name',
decoration: const InputDecoration(
labelText: 'Nama Pengaju',
border: OutlineInputBorder(),
),
validator: FormBuilderValidators.compose([
FormBuilderValidators.required(),
]),
),
const SizedBox(height: 15),
FormBuilderTextField(
name: 'nik',
decoration: const InputDecoration(
labelText: 'NIK',
border: OutlineInputBorder(),
),
),
const SizedBox(height: 20),
ImagePickerField(
name: 'KK',
labelText: 'Upload Foto Kartu Keluarga',
maxImages: 1,
),
const SizedBox(height: 20),
ImagePickerField(
name: 'akta',
labelText: 'Upload Akta Kelahiran',
maxImages: 1,
),
const SizedBox(height: 20),
ImagePickerField(
name: 'ktp',
labelText:
'Upload Foto KTP Ayah & Ibu (Keduanya Jika ada)',
maxImages: 2,
),
const SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.deepPurple,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 12,
),
),
child:
_isLoading
? CircularProgressIndicator(
color: Colors.white,
)
: const Text(
'Kirim',
style: TextStyle(color: Colors.white),
),
onPressed: _isLoading ? null : _submitForm,
),
OutlinedButton(
style: OutlinedButton.styleFrom(
side: BorderSide(color: Colors.deepPurple),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 12,
),
),
child: const Text(
'Reset',
style: TextStyle(color: Colors.deepPurple),
),
onPressed:
_isLoading
? null
: () {
_formKey.currentState?.reset();
},
),
],
),
],
),
),
),
),
),
),
);
}
}

View File

@ -0,0 +1,47 @@
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
class KiaOption extends StatelessWidget {
const KiaOption({super.key});
@override
Widget build(BuildContext context) {
final List<String> jenisKtp = ['Anak Sudah 5 Tahun', 'Anak Belum 5 Tahun'];
final List<String> routes = ['/5tahun', '/under5'];
return Scaffold(
appBar: AppBar(
title: Text(
'Jenis Pembuatan KIA',
style: GoogleFonts.poppins(fontSize: 20, fontWeight: FontWeight.w600),
),
),
body: ListView.builder(
itemCount: jenisKtp.length,
itemBuilder: (context, index) {
return Card(
margin: const EdgeInsets.symmetric(vertical: 8, horizontal: 10),
color: Colors.white,
child: SizedBox(
height: 80,
width: double.infinity,
child: ListTile(
contentPadding: const EdgeInsets.all(16),
leading: const Icon(Icons.edit_document),
trailing: IconButton(
icon: const Icon(Icons.arrow_circle_right_rounded),
onPressed: () {
Navigator.pushNamed(context, routes[index]);
},
),
title: Text(
jenisKtp[index],
style: GoogleFonts.poppins(fontSize: 16),
),
),
),
);
},
),
);
}
}

View File

@ -0,0 +1,234 @@
import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:dio/dio.dart';
import 'package:adminduk_puger/widget/upload_photo.dart';
import 'package:adminduk_puger/cubit/Auth/Auth_cubit.dart';
import 'package:adminduk_puger/cubit/Auth/Auth_state.dart';
import 'package:form_builder_validators/form_builder_validators.dart';
class KiaUnder5 extends StatefulWidget {
KiaUnder5({Key? key}) : super(key: key);
@override
_KtpFormState createState() => _KtpFormState();
}
class _KtpFormState extends State<KiaUnder5> {
final _formKey = GlobalKey<FormBuilderState>();
bool _isLoading = false;
bool _isSelfSubmission = false;
Future<void> _loadProfileData() async {
final authState = context.read<AuthCubit>().state;
if (authState is AuthSuccess) {
final userId = authState.userId;
final profileData = await context.read<AuthCubit>().getProfile(userId);
if (profileData != null) {
_formKey.currentState?.fields['name']?.didChange(profileData['name']);
_formKey.currentState?.fields['nik']?.didChange(profileData['nik']);
}
}
}
Future<void> _submitForm() async {
if (_formKey.currentState?.saveAndValidate() == true) {
setState(() => _isLoading = true);
final authState = context.read<AuthCubit>().state;
if (authState is! AuthSuccess) {
setState(() => _isLoading = false);
return;
}
final userId = authState.userId;
final token = authState.token;
final formData = FormData.fromMap({
'user_id': userId,
'name': _formKey.currentState!.value['name'],
'nik': _formKey.currentState!.value['nik'],
'kk': await MultipartFile.fromFile(
_formKey.currentState!.value['KK'][0].path,
),
'akta': await MultipartFile.fromFile(
_formKey.currentState!.value['akta'][0].path,
),
'ktp': await MultipartFile.fromFile(
_formKey.currentState!.value['ktp'][0].path,
),
});
try {
Dio dio = Dio();
Response response = await dio.post(
'https://adminduk-kec-puger.my.id/api/kiaunder5',
data: formData,
options: Options(headers: {"Authorization": "Bearer $token"}),
);
if (response.statusCode == 200) {
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('Upload berhasil')));
_formKey.currentState?.reset();
Navigator.pushNamed(context, '/home');
} else {
throw Exception('Upload gagal');
}
} catch (e) {
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('Terjadi kesalahan: $e')));
} finally {
setState(() => _isLoading = false);
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[100],
appBar: AppBar(
title: const Text('KIA Untuk Anak Belum 5 Tahun'),
centerTitle: true,
backgroundColor: Colors.deepPurple,
),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
elevation: 6,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: FormBuilder(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
'Silahkan lengkapi Dokumen yang diperlukan',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.black87,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 15),
FormBuilderCheckbox(
name: 'self_submission',
title: Text('Pengajuan untuk diri sendiri'),
initialValue: false,
onChanged: (value) async {
setState(() {
_isSelfSubmission = value ?? false;
});
if (value == true) {
await _loadProfileData();
} else {
_formKey.currentState?.fields['name']?.reset();
_formKey.currentState?.fields['nik']?.reset();
}
},
),
const SizedBox(height: 15),
FormBuilderTextField(
name: 'name',
decoration: const InputDecoration(
labelText: 'Nama Pengaju',
border: OutlineInputBorder(),
),
validator: FormBuilderValidators.compose([
FormBuilderValidators.required(),
]),
),
const SizedBox(height: 15),
FormBuilderTextField(
name: 'nik',
decoration: const InputDecoration(
labelText: 'NIK',
border: OutlineInputBorder(),
),
),
const SizedBox(height: 20),
ImagePickerField(
name: 'KK',
labelText: 'Upload Foto Kartu Keluarga',
maxImages: 1,
),
const SizedBox(height: 20),
ImagePickerField(
name: 'akta',
labelText: 'Upload Akta Kelahiran',
maxImages: 1,
),
const SizedBox(height: 20),
ImagePickerField(
name: 'ktp',
labelText:
'Upload Foto KTP Ayah & Ibu (Keduanya Jika ada)',
maxImages: 2,
),
const SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.deepPurple,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 12,
),
),
child:
_isLoading
? CircularProgressIndicator(
color: Colors.white,
)
: const Text(
'Kirim',
style: TextStyle(color: Colors.white),
),
onPressed: _isLoading ? null : _submitForm,
),
OutlinedButton(
style: OutlinedButton.styleFrom(
side: BorderSide(color: Colors.deepPurple),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 12,
),
),
child: const Text(
'Reset',
style: TextStyle(color: Colors.deepPurple),
),
onPressed:
_isLoading
? null
: () {
_formKey.currentState?.reset();
},
),
],
),
],
),
),
),
),
),
),
);
}
}

View File

@ -0,0 +1,211 @@
import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:dio/dio.dart';
import 'package:adminduk_puger/widget/upload_photo.dart';
import 'package:adminduk_puger/cubit/Auth/Auth_cubit.dart';
import 'package:adminduk_puger/cubit/Auth/Auth_state.dart';
import 'package:form_builder_validators/form_builder_validators.dart';
class DamagedKtp extends StatefulWidget {
DamagedKtp({Key? key}) : super(key: key);
@override
_KtpFormState createState() => _KtpFormState();
}
class _KtpFormState extends State<DamagedKtp> {
final _formKey = GlobalKey<FormBuilderState>();
bool _isLoading = false;
bool _isSelfSubmission = false;
Future<void> _loadProfileData() async {
final authState = context.read<AuthCubit>().state;
if (authState is AuthSuccess) {
final userId = authState.userId;
final profileData = await context.read<AuthCubit>().getProfile(userId);
if (profileData != null) {
_formKey.currentState?.fields['name']?.didChange(profileData['name']);
_formKey.currentState?.fields['nik']?.didChange(profileData['nik']);
}
}
}
Future<void> _submitForm() async {
if (_formKey.currentState?.saveAndValidate() == true) {
setState(() => _isLoading = true);
final authState = context.read<AuthCubit>().state;
if (authState is! AuthSuccess) {
setState(() => _isLoading = false);
return;
}
final userId = authState.userId;
final token = authState.token;
final formData = FormData.fromMap({
'user_id': userId,
'name': _formKey.currentState!.value['name'],
'nik': _formKey.currentState!.value['nik'],
// 'nokk': _formKey.currentState!.value['nokk'],
'kk': await MultipartFile.fromFile(
_formKey.currentState!.value['KK'][0].path,
),
});
try {
Dio dio = Dio();
Response response = await dio.post(
'https://adminduk-kec-puger.my.id/api/damagedektp',
data: formData,
options: Options(headers: {"Authorization": "Bearer $token"}),
);
if (response.statusCode == 200) {
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('Upload berhasil')));
_formKey.currentState?.reset();
Navigator.pushNamed(context, '/home');
} else {
throw Exception('Upload gagal');
}
} catch (e) {
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('Terjadi kesalahan: $e')));
} finally {
setState(() => _isLoading = false);
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[100],
appBar: AppBar(
title: const Text('KTP Rusak'),
centerTitle: true,
backgroundColor: Colors.deepPurple,
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
elevation: 6,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: FormBuilder(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
'Silahkan lengkapi Dokumen yang diperlukan',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.black87,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 15),
FormBuilderTextField(
name: 'name',
decoration: const InputDecoration(
labelText: 'Nama Pengaju',
border: OutlineInputBorder(),
),
validator: FormBuilderValidators.compose([
FormBuilderValidators.required(),
]),
),
const SizedBox(height: 15),
FormBuilderTextField(
name: 'nik',
decoration: const InputDecoration(
labelText: 'NIK',
border: OutlineInputBorder(),
),
),
const SizedBox(height: 15),
FormBuilderCheckbox(
name: 'self_submission',
title: Text('Pengajuan untuk diri sendiri'),
initialValue: false,
onChanged: (value) async {
setState(() {
_isSelfSubmission = value ?? false;
});
if (value == true) {
await _loadProfileData();
} else {
_formKey.currentState?.fields['name']?.reset();
_formKey.currentState?.fields['nik']?.reset();
}
},
),
const SizedBox(height: 20),
ImagePickerField(
name: 'KK',
labelText: 'Upload Foto Kartu Keluarga',
maxImages: 1,
),
const SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.deepPurple,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 12,
),
),
child:
_isLoading
? CircularProgressIndicator(color: Colors.white)
: const Text(
'Kirim',
style: TextStyle(color: Colors.white),
),
onPressed: _isLoading ? null : _submitForm,
),
OutlinedButton(
style: OutlinedButton.styleFrom(
side: BorderSide(color: Colors.deepPurple),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 12,
),
),
child: const Text(
'Reset',
style: TextStyle(color: Colors.deepPurple),
),
onPressed:
_isLoading
? null
: () {
_formKey.currentState?.reset();
},
),
],
),
],
),
),
),
),
),
);
}
}

View File

@ -0,0 +1,52 @@
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
class KtpOption extends StatelessWidget {
const KtpOption({super.key});
@override
Widget build(BuildContext context) {
final List<String> jenisKtp = ['KTP Baru', 'KTP Hilang', 'KTP Rusak'];
final List<String> routes = [
'/newktp',
'/lostktp',
'/damagedktp',
]; // Sesuaikan dengan route yang kamu definisikan
return Scaffold(
appBar: AppBar(
title: Text(
'Jenis Pembuatan KTP',
style: GoogleFonts.poppins(fontSize: 20, fontWeight: FontWeight.w600),
),
),
body: ListView.builder(
itemCount: jenisKtp.length,
itemBuilder: (context, index) {
return Card(
margin: const EdgeInsets.symmetric(vertical: 8, horizontal: 10),
color: Colors.white,
child: SizedBox(
height: 80,
width: double.infinity,
child: ListTile(
contentPadding: const EdgeInsets.all(16),
leading: const Icon(Icons.edit_document),
trailing: IconButton(
icon: const Icon(Icons.arrow_circle_right_rounded),
onPressed: () {
Navigator.pushNamed(context, routes[index]);
},
),
title: Text(
jenisKtp[index],
style: GoogleFonts.poppins(fontSize: 16),
),
),
),
);
},
),
);
}
}

View File

@ -0,0 +1,233 @@
import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:dio/dio.dart';
import 'package:adminduk_puger/widget/upload_photo.dart';
import 'package:adminduk_puger/cubit/Auth/Auth_cubit.dart';
import 'package:adminduk_puger/cubit/Auth/Auth_state.dart';
import 'package:form_builder_validators/form_builder_validators.dart';
class LostKtp extends StatefulWidget {
LostKtp({Key? key}) : super(key: key);
@override
_KtpFormState createState() => _KtpFormState();
}
class _KtpFormState extends State<LostKtp> {
final _formKey = GlobalKey<FormBuilderState>();
bool _isLoading = false;
bool _isSelfSubmission = false;
Future<void> _loadProfileData() async {
final authState = context.read<AuthCubit>().state;
if (authState is AuthSuccess) {
final userId = authState.userId;
final profileData = await context.read<AuthCubit>().getProfile(userId);
if (profileData != null) {
_formKey.currentState?.fields['name']?.didChange(profileData['name']);
_formKey.currentState?.fields['nik']?.didChange(profileData['nik']);
}
}
}
Future<void> _submitForm() async {
if (_formKey.currentState?.saveAndValidate() == true) {
setState(() => _isLoading = true);
final authState = context.read<AuthCubit>().state;
if (authState is! AuthSuccess) {
setState(() => _isLoading = false);
return;
}
final userId = authState.userId;
final token = authState.token;
final formData = FormData.fromMap({
'user_id': userId,
'name': _formKey.currentState!.value['name'],
'nik': _formKey.currentState!.value['nik'],
// 'nokk': _formKey.currentState!.value['nokk'],
'lostletter': await MultipartFile.fromFile(
_formKey.currentState!.value['lostletter'][0].path,
),
'kk': await MultipartFile.fromFile(
_formKey.currentState!.value['KK'][0].path,
),
});
try {
Dio dio = Dio();
Response response = await dio.post(
'https://adminduk-kec-puger.my.id/api/lostektp',
data: formData,
options: Options(headers: {"Authorization": "Bearer $token"}),
);
if (response.statusCode == 200) {
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('Upload berhasil')));
_formKey.currentState?.reset();
Navigator.pushNamed(context, '/home');
} else {
throw Exception('Upload gagal');
}
} catch (e) {
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('Terjadi kesalahan: $e')));
} finally {
setState(() => _isLoading = false);
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[100],
appBar: AppBar(
title: const Text('KTP Hilang'),
centerTitle: true,
backgroundColor: Colors.deepPurple,
),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
elevation: 6,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: FormBuilder(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
'Silahkan lengkapi Dokumen yang diperlukan',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.black87,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 15),
FormBuilderCheckbox(
name: 'self_submission',
title: Text('Pengajuan untuk diri sendiri'),
initialValue: false,
onChanged: (value) async {
setState(() {
_isSelfSubmission = value ?? false;
});
if (value == true) {
await _loadProfileData();
} else {
_formKey.currentState?.fields['name']?.reset();
_formKey.currentState?.fields['nik']?.reset();
}
},
),
const SizedBox(height: 15),
FormBuilderTextField(
name: 'name',
decoration: const InputDecoration(
labelText: 'Nama Pengaju',
border: OutlineInputBorder(),
),
validator: FormBuilderValidators.compose([
FormBuilderValidators.required(),
]),
),
const SizedBox(height: 20),
FormBuilderTextField(
name: 'nik',
decoration: const InputDecoration(
labelText: 'NIK',
border: OutlineInputBorder(),
),
),
const SizedBox(height: 20),
ImagePickerField(
name: 'lostletter',
labelText: 'Upload Foto Surat Kehilangan dari Polisi',
maxImages: 1,
),
// const SizedBox(height: 20),
// FormBuilderTextField(
// name: 'nokk',
// decoration: const InputDecoration(
// labelText: 'No. KK',
// border: OutlineInputBorder(),
// ),
// ),
const SizedBox(height: 20),
ImagePickerField(
name: 'KK',
labelText: 'Upload Foto Kartu Keluarga',
maxImages: 1,
),
const SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.deepPurple,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 12,
),
),
child:
_isLoading
? CircularProgressIndicator(
color: Colors.white,
)
: const Text(
'Kirim',
style: TextStyle(color: Colors.white),
),
onPressed: _isLoading ? null : _submitForm,
),
OutlinedButton(
style: OutlinedButton.styleFrom(
side: BorderSide(color: Colors.deepPurple),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 12,
),
),
child: const Text(
'Reset',
style: TextStyle(color: Colors.deepPurple),
),
onPressed:
_isLoading
? null
: () {
_formKey.currentState?.reset();
},
),
],
),
],
),
),
),
),
),
),
);
}
}

View File

@ -0,0 +1,214 @@
import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:dio/dio.dart';
import 'package:adminduk_puger/widget/upload_photo.dart';
import 'package:adminduk_puger/cubit/Auth/Auth_cubit.dart';
import 'package:adminduk_puger/cubit/Auth/Auth_state.dart';
import 'package:form_builder_validators/form_builder_validators.dart';
class NewKtp extends StatefulWidget {
NewKtp({Key? key}) : super(key: key);
@override
_KtpFormState createState() => _KtpFormState();
}
class _KtpFormState extends State<NewKtp> {
final _formKey = GlobalKey<FormBuilderState>();
bool _isLoading = false;
bool _isSelfSubmission = false;
Future<void> _loadProfileData() async {
final authState = context.read<AuthCubit>().state;
if (authState is! AuthSuccess) return;
final userId = authState.userId;
final profileData = await context.read<AuthCubit>().getProfile(userId);
if (profileData != null) {
_formKey.currentState?.fields['name']?.didChange(profileData['name']);
_formKey.currentState?.fields['nik']?.didChange(profileData['nik']);
}
}
Future<void> _submitForm() async {
if (_formKey.currentState?.saveAndValidate() == true) {
setState(() => _isLoading = true);
final authState = context.read<AuthCubit>().state;
if (authState is! AuthSuccess) {
setState(() => _isLoading = false);
return;
}
final userId = authState.userId;
final token = authState.token;
final formData = FormData.fromMap({
'user_id': userId,
'name': _formKey.currentState!.value['name'],
'nik': _formKey.currentState!.value['nik'],
'kk': await MultipartFile.fromFile(
_formKey.currentState!.value['KK'][0].path,
),
});
try {
Dio dio = Dio();
Response response = await dio.post(
'https://adminduk-kec-puger.my.id/api/ektp',
data: formData,
options: Options(headers: {"Authorization": "Bearer $token"}),
);
if (response.statusCode == 200) {
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('Upload berhasil')));
_formKey.currentState?.reset();
Navigator.pushNamed(context, '/home');
} else {
throw Exception('Upload gagal');
}
} catch (e) {
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('Terjadi kesalahan: $e')));
} finally {
setState(() => _isLoading = false);
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[100],
appBar: AppBar(
title: const Text('KTP Baru'),
centerTitle: true,
backgroundColor: Colors.deepPurple,
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
elevation: 6,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: FormBuilder(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
'Silahkan lengkapi Dokumen yang diperlukan',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.black87,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 15),
FormBuilderCheckbox(
name: 'self_submission',
title: Text('Pengajuan untuk diri sendiri'),
initialValue: false,
onChanged: (value) async {
setState(() {
_isSelfSubmission = value ?? false;
});
if (value == true) {
await _loadProfileData();
} else {
_formKey.currentState?.fields['name']?.reset();
_formKey.currentState?.fields['nik']?.reset();
}
},
),
const SizedBox(height: 15),
FormBuilderTextField(
name: 'name',
decoration: const InputDecoration(
labelText: 'Nama Pengaju',
border: OutlineInputBorder(),
),
validator: FormBuilderValidators.compose([
FormBuilderValidators.required(),
]),
),
const SizedBox(height: 15),
FormBuilderTextField(
name: 'nik',
decoration: const InputDecoration(
labelText: 'NIK',
border: OutlineInputBorder(),
),
validator: FormBuilderValidators.compose([
FormBuilderValidators.required(),
]),
),
const SizedBox(height: 20),
ImagePickerField(
name: 'KK',
labelText: 'Upload Foto Kartu Keluarga',
maxImages: 1,
),
const SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.deepPurple,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 12,
),
),
child:
_isLoading
? CircularProgressIndicator(color: Colors.white)
: const Text(
'Kirim',
style: TextStyle(color: Colors.white),
),
onPressed: _isLoading ? null : _submitForm,
),
OutlinedButton(
style: OutlinedButton.styleFrom(
side: BorderSide(color: Colors.deepPurple),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 12,
),
),
child: const Text(
'Reset',
style: TextStyle(color: Colors.deepPurple),
),
onPressed:
_isLoading
? null
: () {
_formKey.currentState?.reset();
},
),
],
),
],
),
),
),
),
),
);
}
}

View File

@ -0,0 +1,255 @@
import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:dio/dio.dart';
import 'package:adminduk_puger/widget/upload_photo.dart';
import 'package:adminduk_puger/cubit/Auth/Auth_cubit.dart';
import 'package:adminduk_puger/cubit/Auth/Auth_state.dart';
import 'package:form_builder_validators/form_builder_validators.dart';
class BirthCertif extends StatefulWidget {
BirthCertif({Key? key}) : super(key: key);
@override
_KtpFormState createState() => _KtpFormState();
}
class _KtpFormState extends State<BirthCertif> {
final _formKey = GlobalKey<FormBuilderState>();
bool _isLoading = false;
Future<void> _submitForm() async {
if (_formKey.currentState?.saveAndValidate() == true) {
setState(() => _isLoading = true);
print("Form valid, mulai submit...");
final authState = context.read<AuthCubit>().state;
if (authState is! AuthSuccess) {
print("User tidak login, membatalkan submit");
setState(() => _isLoading = false);
return;
}
final String status = "Diproses";
final userId = authState.userId;
final token = authState.token;
print("User ID: $userId");
final formData = FormData.fromMap({
'user_id': userId,
'name': _formKey.currentState!.value['name'],
'form': await MultipartFile.fromFile(
_formKey.currentState!.value['form'][0].path,
),
'mom_ktp': await MultipartFile.fromFile(
_formKey.currentState!.value['mom_ktp'][0].path,
),
'dad_ktp': await MultipartFile.fromFile(
_formKey.currentState!.value['dad_ktp'][0].path,
),
'maried_certif': await MultipartFile.fromFile(
_formKey.currentState!.value['maried_certif'][0].path,
),
'birth_certificate': await MultipartFile.fromFile(
_formKey.currentState!.value['birth_certificate'][0].path,
),
'new_kk': await MultipartFile.fromFile(
_formKey.currentState!.value['new_kk'][0].path,
),
'witness1_ktp': await MultipartFile.fromFile(
_formKey.currentState!.value['witness1_ktp'][0].path,
),
'witness2_ktp': await MultipartFile.fromFile(
_formKey.currentState!.value['witness2_ktp'][0].path,
),
'status': status,
});
print("Mengirim data ke API...");
try {
Dio dio = Dio();
Response response = await dio.post(
'https://adminduk-kec-puger.my.id/api/birthcertif',
data: formData,
options: Options(headers: {"Authorization": "Bearer $token"}),
);
print("Respons diterima: ${response.data}");
if (response.statusCode == 200) {
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('Upload berhasil')));
_formKey.currentState?.reset();
Navigator.pushNamed(context, '/home');
} else {
throw Exception('Upload gagal');
}
} catch (e) {
print("Terjadi kesalahan: $e");
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('Terjadi kesalahan: $e')));
} finally {
setState(() => _isLoading = false);
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[100],
appBar: AppBar(
title: const Text('Pembuatan Akte Kelahiran'),
centerTitle: true,
backgroundColor: Colors.deepPurple,
),
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
elevation: 6,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: SingleChildScrollView(
child: FormBuilder(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
'Silahkan lengkapi Dokumen yang diperlukan',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.black87,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 15),
FormBuilderTextField(
name: 'name',
decoration: const InputDecoration(
labelText: 'Nama Pengaju',
border: OutlineInputBorder(),
),
validator: FormBuilderValidators.compose([
FormBuilderValidators.required(),
]),
),
const SizedBox(height: 15),
ImagePickerField(
name: 'form',
labelText:
'Upload foto Formulir Perekaman yang sudah diisi',
maxImages: 1,
),
const SizedBox(height: 15),
ImagePickerField(
name: 'mom_ktp',
labelText: 'Upload Foto KTP Ibu',
maxImages: 1,
),
const SizedBox(height: 20),
ImagePickerField(
name: 'dad_ktp',
labelText: 'Upload Foto KTP Ayah',
maxImages: 1,
),
const SizedBox(height: 20),
ImagePickerField(
name: 'maried_certif',
labelText: 'Upload Foto Akte Nikah',
maxImages: 1,
),
const SizedBox(height: 20),
ImagePickerField(
name: 'birth_certificate',
labelText:
'Foto Keterangan Lahir dari Rumah Sakit atau RT',
maxImages: 1,
),
const SizedBox(height: 20),
ImagePickerField(
name: 'new_kk',
labelText: 'Foto Kartu Keluarga Terbaru',
maxImages: 1,
),
const SizedBox(height: 20),
ImagePickerField(
name: 'witness1_ktp',
labelText: 'Foto KTP Saksi 1',
maxImages: 1,
),
const SizedBox(height: 20),
ImagePickerField(
name: 'witness2_ktp',
labelText: 'Foto KTP Saksi 2',
maxImages: 1,
),
const SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.deepPurple,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 12,
),
),
child:
_isLoading
? CircularProgressIndicator(
color: Colors.white,
)
: const Text(
'Kirim',
style: TextStyle(color: Colors.white),
),
onPressed: _isLoading ? null : _submitForm,
),
OutlinedButton(
style: OutlinedButton.styleFrom(
side: BorderSide(color: Colors.deepPurple),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 12,
),
),
child: const Text(
'Reset',
style: TextStyle(color: Colors.deepPurple),
),
onPressed:
_isLoading
? null
: () {
_formKey.currentState?.reset();
},
),
],
),
],
),
),
),
),
),
),
),
);
}
}

View File

@ -0,0 +1,216 @@
import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:dio/dio.dart';
import 'package:adminduk_puger/widget/upload_photo.dart';
import 'package:adminduk_puger/cubit/Auth/Auth_cubit.dart';
import 'package:adminduk_puger/cubit/Auth/Auth_state.dart';
import 'package:form_builder_validators/form_builder_validators.dart';
class DieCertif extends StatefulWidget {
DieCertif({Key? key}) : super(key: key);
@override
_DieFormState createState() => _DieFormState();
}
class _DieFormState extends State<DieCertif> {
final _formKey = GlobalKey<FormBuilderState>();
bool _isLoading = false;
Future<void> _submitForm() async {
if (_formKey.currentState?.saveAndValidate() == true) {
setState(() => _isLoading = true);
final authState = context.read<AuthCubit>().state;
if (authState is! AuthSuccess) {
setState(() => _isLoading = false);
return;
}
final userId = authState.userId;
final token = authState.token;
final formData = FormData.fromMap({
'user_id': userId, // Tambahkan user_id
'name': _formKey.currentState!.value['name'],
'form': await MultipartFile.fromFile(
_formKey.currentState!.value['form'][0].path,
),
'death_certificate': await MultipartFile.fromFile(
_formKey.currentState!.value['death_certificate'][0].path,
),
'maried_certificate': await MultipartFile.fromFile(
_formKey.currentState!.value['maried_certificate'][0].path,
),
'kk': await MultipartFile.fromFile(
_formKey.currentState!.value['kk'][0].path,
),
'ktp': await MultipartFile.fromFile(
_formKey.currentState!.value['ktp'][0].path,
),
});
try {
Dio dio = Dio();
Response response = await dio.post(
'https://adminduk-kec-puger.my.id/api/diecertif',
data: formData,
options: Options(headers: {"Authorization": "Bearer $token"}),
);
if (response.statusCode == 200) {
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('Upload berhasil')));
_formKey.currentState?.reset();
Navigator.pushNamed(context, '/home');
} else {
throw Exception('Upload gagal');
}
} catch (e) {
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('Terjadi kesalahan: $e')));
} finally {
setState(() => _isLoading = false);
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[100],
appBar: AppBar(
title: const Text('Pembuatan Akte Kematian'),
centerTitle: true,
backgroundColor: Colors.deepPurple,
),
body: SafeArea(
child: SingleChildScrollView(
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
elevation: 6,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: FormBuilder(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
'Silahkan lengkapi Dokumen yang diperlukan',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.black87,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 15),
FormBuilderTextField(
name: 'name',
decoration: const InputDecoration(
labelText: 'Nama Pengaju',
border: OutlineInputBorder(),
),
validator: FormBuilderValidators.compose([
FormBuilderValidators.required(),
]),
),
const SizedBox(height: 15),
ImagePickerField(
name: 'form',
labelText:
'Upload foto Formulir Perekaman yang sudah diisi',
maxImages: 1,
),
const SizedBox(height: 20),
ImagePickerField(
name: 'death_certificate',
labelText: 'Surat Keterangan Mati dari RT atau RS',
maxImages: 1,
),
const SizedBox(height: 20),
ImagePickerField(
name: 'maried_certificate',
labelText: 'Surat Nikah apabila sudah menikah',
maxImages: 1,
),
const SizedBox(height: 20),
ImagePickerField(
name: 'kk',
labelText: 'Upload Kartu Keluarga terbaru',
maxImages: 1,
),
const SizedBox(height: 20),
ImagePickerField(
name: 'ktp',
labelText: 'Foto KTP',
maxImages: 1,
),
const SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.deepPurple,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 12,
),
),
child:
_isLoading
? CircularProgressIndicator(
color: Colors.white,
)
: const Text(
'Kirim',
style: TextStyle(color: Colors.white),
),
onPressed: _isLoading ? null : _submitForm,
),
OutlinedButton(
style: OutlinedButton.styleFrom(
side: BorderSide(color: Colors.deepPurple),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 12,
),
),
child: const Text(
'Reset',
style: TextStyle(color: Colors.deepPurple),
),
onPressed:
_isLoading
? null
: () {
_formKey.currentState?.reset();
},
),
],
),
],
),
),
),
),
),
),
);
}
}

View File

@ -0,0 +1,201 @@
import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:dio/dio.dart';
import 'package:adminduk_puger/widget/upload_photo.dart';
import 'package:adminduk_puger/cubit/Auth/Auth_cubit.dart';
import 'package:adminduk_puger/cubit/Auth/Auth_state.dart';
import 'package:form_builder_validators/form_builder_validators.dart';
class KkForm extends StatefulWidget {
KkForm({Key? key}) : super(key: key);
@override
_KKFormState createState() => _KKFormState();
}
class _KKFormState extends State<KkForm> {
final _formKey = GlobalKey<FormBuilderState>();
bool _isLoading = false;
Future<void> _submitForm() async {
if (_formKey.currentState?.saveAndValidate() == true) {
setState(() => _isLoading = true);
final authState = context.read<AuthCubit>().state;
if (authState is! AuthSuccess) {
setState(() => _isLoading = false);
return;
}
final userId = authState.userId;
final token = authState.token;
final formData = FormData.fromMap({
'user_id': userId,
'name': _formKey.currentState!.value['name'],
'form': await MultipartFile.fromFile(
_formKey.currentState!.value['form'][0].path,
),
'ktp': await MultipartFile.fromFile(
_formKey.currentState!.value['ktp'][0].path,
),
'maried_certificated': await MultipartFile.fromFile(
_formKey.currentState!.value['maried_certificated'][0].path,
),
});
try {
Dio dio = Dio();
Response response = await dio.post(
'https://adminduk-kec-puger.my.id/api/kk',
data: formData,
options: Options(
headers: {"Au_KtpFormStatethorization": "Bearer $token"},
),
);
if (response.statusCode == 200) {
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('Upload berhasil')));
_formKey.currentState?.reset();
Navigator.pushNamed(context, '/home');
} else {
throw Exception('Upload gagal');
}
} catch (e) {
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('Terjadi kesalahan: $e')));
} finally {
setState(() => _isLoading = false);
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[100],
appBar: AppBar(
title: const Text('Pembuatan Kartu Keluarga'),
centerTitle: true,
backgroundColor: Colors.deepPurple,
),
body: SafeArea(
child: SingleChildScrollView(
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
elevation: 6,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: FormBuilder(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
'Silahkan lengkapi Dokumen yang diperlukan',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.black87,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 15),
FormBuilderTextField(
name: 'name',
decoration: const InputDecoration(
labelText: 'Nama Pengaju',
border: OutlineInputBorder(),
),
validator: FormBuilderValidators.compose([
FormBuilderValidators.required(),
]),
),
const SizedBox(height: 20),
ImagePickerField(
name: 'form',
labelText:
'Upload foto Formulir Perekaman yang sudah diisi',
maxImages: 1,
),
const SizedBox(height: 15),
ImagePickerField(
name: 'ktp',
labelText: 'Upload Foto KTP',
maxImages: 1,
),
const SizedBox(height: 20),
ImagePickerField(
name: 'maried_certificated',
labelText: 'Akte Nikah jika sudah menikah',
maxImages: 1,
),
const SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.deepPurple,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 12,
),
),
child:
_isLoading
? CircularProgressIndicator(
color: Colors.white,
)
: const Text(
'Kirim',
style: TextStyle(color: Colors.white),
),
onPressed: _isLoading ? null : _submitForm,
),
OutlinedButton(
style: OutlinedButton.styleFrom(
side: BorderSide(color: Colors.deepPurple),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 12,
),
),
child: const Text(
'Reset',
style: TextStyle(color: Colors.deepPurple),
),
onPressed:
_isLoading
? null
: () {
_formKey.currentState?.reset();
},
),
],
),
],
),
),
),
),
),
),
);
}
}

View File

@ -0,0 +1,208 @@
import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:dio/dio.dart';
import 'package:adminduk_puger/widget/upload_photo.dart';
import 'package:adminduk_puger/cubit/Auth/Auth_cubit.dart';
import 'package:form_builder_validators/form_builder_validators.dart';
import 'package:adminduk_puger/cubit/Auth/Auth_state.dart';
class MovingForm extends StatefulWidget {
MovingForm({Key? key}) : super(key: key);
@override
_MovingFormState createState() => _MovingFormState();
}
class _MovingFormState extends State<MovingForm> {
final _formKey = GlobalKey<FormBuilderState>();
bool _isLoading = false;
Future<void> _submitForm() async {
if (_formKey.currentState?.saveAndValidate() == true) {
setState(() => _isLoading = true);
final authState = context.read<AuthCubit>().state;
if (authState is! AuthSuccess) {
setState(() => _isLoading = false);
return;
}
final userId = authState.userId;
final token = authState.token;
final formData = FormData.fromMap({
'user_id': userId,
'name': _formKey.currentState!.value['name'],
'moving_letter': await MultipartFile.fromFile(
_formKey.currentState!.value['moving_letter'][0].path,
),
'kk': await MultipartFile.fromFile(
_formKey.currentState!.value['kk'][0].path,
),
'ktp': await MultipartFile.fromFile(
_formKey.currentState!.value['ktp'][0].path,
),
'maried_certificate': await MultipartFile.fromFile(
_formKey.currentState!.value['maried_certificate'][0].path,
),
'consent_partner': await MultipartFile.fromFile(
_formKey.currentState!.value['consent_partner'][0].path,
),
});
try {
Dio dio = Dio();
Response response = await dio.post(
'https://adminduk-kec-puger.my.id/api/movingletter',
data: formData,
options: Options(headers: {"Authorization": "Bearer $token"}),
);
if (response.statusCode == 200) {
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('Upload berhasil')));
_formKey.currentState?.reset();
Navigator.pushNamed(context, '/home');
} else {
throw Exception('Upload gagal');
}
} catch (e) {
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('Terjadi kesalahan: $e')));
} finally {
setState(() => _isLoading = false);
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[100],
appBar: AppBar(
title: const Text('Pembuatan Surat Pindah'),
centerTitle: true,
backgroundColor: Colors.deepPurple,
),
body: SafeArea(
child: SingleChildScrollView(
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
elevation: 6,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: FormBuilder(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
'Silahkan lengkapi Dokumen yang diperlukan',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.black87,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 15),
FormBuilderTextField(
name: 'name',
decoration: const InputDecoration(
labelText: 'Nama Pengaju',
border: OutlineInputBorder(),
),
validator: FormBuilderValidators.compose([
FormBuilderValidators.required(),
]),
),
const SizedBox(height: 15),
ImagePickerField(
name: 'kk',
labelText: 'Upload Foto Kartu Keluarga',
maxImages: 1,
),
const SizedBox(height: 15),
ImagePickerField(
name: 'ktp',
labelText: 'Upload Foto KTP',
maxImages: 1,
),
const SizedBox(height: 20),
ImagePickerField(
name: 'moving_letter_certificate',
labelText: 'Surat Keterangan Pindah dari RT',
maxImages: 1,
),
const SizedBox(height: 20),
ImagePickerField(
name: 'consent_partner',
labelText:
'Surat Persetujuan Pasangan, Jika tidak ada Boleh Kosong',
maxImages: 1,
),
const SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.deepPurple,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 12,
),
),
child:
_isLoading
? CircularProgressIndicator(
color: Colors.white,
)
: const Text(
'Kirim',
style: TextStyle(color: Colors.white),
),
onPressed: _isLoading ? null : _submitForm,
),
OutlinedButton(
style: OutlinedButton.styleFrom(
side: BorderSide(color: Colors.deepPurple),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 12,
),
),
child: const Text(
'Reset',
style: TextStyle(color: Colors.deepPurple),
),
onPressed:
_isLoading
? null
: () {
_formKey.currentState?.reset();
},
),
],
),
],
),
),
),
),
),
),
);
}
}

View File

@ -0,0 +1,97 @@
import 'package:adminduk_puger/cubit/submission_cubit.dart';
import 'package:adminduk_puger/form/KIA/kia_under_5.dart';
import 'package:adminduk_puger/screen/setting_account.dart';
import 'package:flutter/material.dart';
import 'package:adminduk_puger/screen/Auth/login.dart';
import 'package:adminduk_puger/screen/splash.dart';
import 'package:adminduk_puger/screen/home.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:adminduk_puger/screen/setting.dart';
import 'package:adminduk_puger/screen/submission.dart';
import 'package:adminduk_puger/form/KTP/new_ktp.dart';
import 'package:adminduk_puger/cubit/Auth/Auth_cubit.dart';
import 'package:adminduk_puger/cubit/Auth/Auth_repository.dart';
import 'package:adminduk_puger/form/kk_form.dart';
import 'package:adminduk_puger/form/akte_lahir.dart';
import 'package:adminduk_puger/form/akte_mati.dart';
import 'package:adminduk_puger/form/surat_pindah.dart';
import 'package:adminduk_puger/screen/Auth/register.dart';
import 'package:adminduk_puger/screen/Auth/verificatoin_screen.dart';
import 'package:adminduk_puger/screen/document.dart';
import 'package:adminduk_puger/form/KTP/ktp_option.dart';
import 'package:adminduk_puger/form/KTP/lost_ktp.dart';
import 'package:adminduk_puger/form/KTP/damaged_ktp.dart';
import 'package:adminduk_puger/form/KIA/kia_option.dart';
import 'package:adminduk_puger/form/KIA/kia5.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
final authCubit = AuthCubit(AuthRepository());
runApp(MyApp(authCubit: authCubit));
}
class MyApp extends StatelessWidget {
final AuthCubit authCubit;
const MyApp({super.key, required this.authCubit});
@override
Widget build(BuildContext context) {
return FutureBuilder<String?>(
future: authCubit.getToken(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return MaterialApp(home: SplashScreen());
}
final token = snapshot.data;
return MultiBlocProvider(
providers: [
BlocProvider(create: (_) => authCubit..loaduser()),
BlocProvider(
create: (context) {
return SubmissionCubit();
},
child: HomeScreen(),
),
],
child: MaterialApp(
initialRoute: token == null ? '/splash' : '/home',
routes: {
'/splash': (context) => SplashScreen(),
'/login': (context) => LoginScreen(),
'/home': (context) => HomeScreen(),
'/setting': (context) => SettingsPage(),
'/submission': (context) => SubmissionPage(),
'/kia_option': (context) => KiaOption(),
'/under5': (context) => KiaUnder5(),
'/5tahun': (context) => Kia5(),
'/newktp': (context) => NewKtp(),
'/lostktp': (context) => LostKtp(),
'/damagedktp': (context) => DamagedKtp(),
'/ktp_option': (context) => KtpOption(),
'/kkform': (context) => KkForm(),
'/birthcertif': (context) => BirthCertif(),
'/diecertif': (context) => DieCertif(),
'/moving_letter': (context) => MovingForm(),
'/profile': (context) => SettingAccount(),
'/regist': (context) => RegisterScreen(),
'/document': (context) => DocumentPage(),
'/verify': (context) {
final args =
ModalRoute.of(context)!.settings.arguments
as Map<String, dynamic>;
return VerifyScreen(
userId: args["userId"],
email: args["email"],
);
},
},
),
);
},
);
}
}

View File

@ -0,0 +1,208 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:adminduk_puger/theme.dart';
import 'package:adminduk_puger/cubit/Auth/Auth_cubit.dart';
import 'package:adminduk_puger/cubit/Auth/Auth_state.dart';
import 'package:flutter/gestures.dart';
import 'package:url_launcher/url_launcher.dart';
class LoginScreen extends StatefulWidget {
const LoginScreen({super.key});
@override
_LoginScreenState createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
bool _obscureText = true;
final TextEditingController _emailController = TextEditingController();
final TextEditingController _passwordController = TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: SingleChildScrollView(
padding: const EdgeInsets.all(30.0),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(height: 150),
// Logo & Title
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Adminduk",
style: GoogleFonts.poppins(
fontSize: 30,
fontWeight: FontWeight.bold,
color: Colors.black,
height: 1.0,
),
),
Text(
"PUGER",
style: GoogleFonts.poppins(
fontSize: 35,
fontWeight: FontWeight.bold,
color: dongker,
height: 1.0,
),
),
],
),
const SizedBox(height: 60),
const Text('Silahkan login ke akun anda'),
const SizedBox(height: 20),
// Email Input
TextField(
controller: _emailController,
decoration: InputDecoration(
labelText: 'Masukan Email',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(30),
),
prefixIcon: const Icon(Icons.person),
),
),
const SizedBox(height: 20),
// Password Input
TextField(
controller: _passwordController,
obscureText: _obscureText,
decoration: InputDecoration(
labelText: 'Masukan Password',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(30),
),
prefixIcon: const Icon(Icons.lock),
suffixIcon: IconButton(
icon: Icon(
_obscureText
? Icons.visibility_off_outlined
: Icons.remove_red_eye_outlined,
color: Colors.grey,
),
onPressed: () {
setState(() {
_obscureText = !_obscureText;
});
},
),
),
),
const SizedBox(height: 10),
Align(
alignment: Alignment.centerRight,
child: TextButton(
onPressed: () async {
final url =
'https://adminduk-kec-puger.my.id/forgot-password';
if (await canLaunchUrl(Uri.parse(url))) {
await launchUrl(
Uri.parse(url),
mode: LaunchMode.externalApplication,
);
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Gagal membuka dokumen')),
);
}
},
child: Text(
"Lupa Password?",
style: TextStyle(color: dongker),
),
),
),
const SizedBox(height: 30),
BlocConsumer<AuthCubit, AuthState>(
listener: (context, state) {
if (state is AuthEmailNotVerified) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
'Email belum terverifikasi, silahkan cek email',
),
duration: Duration(seconds: 5),
),
);
} else if (state is AuthFailure) {
// Tampilkan error message
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text(state.error)));
} else if (state is AuthSuccess) {
Navigator.of(context).pushReplacementNamed('/home');
}
},
builder: (context, state) {
return ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: dongker,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
),
minimumSize: const Size(double.infinity, 50),
),
onPressed:
state is AuthLoading
? null
: () {
context.read<AuthCubit>().login(
_emailController.text,
_passwordController.text,
);
},
child:
state is AuthLoading
? const CircularProgressIndicator(
color: Colors.white,
)
: Text(
'Masuk',
style: GoogleFonts.poppins(color: Colors.white),
selectionColor: Colors.white,
),
);
},
),
const SizedBox(height: 20),
RichText(
text: TextSpan(
children: [
const TextSpan(
text: "Belum punya akun? ",
style: TextStyle(color: Colors.black),
),
TextSpan(
text: "Daftar",
style: TextStyle(
color: dongker,
fontWeight: FontWeight.bold,
),
recognizer:
TapGestureRecognizer()
..onTap = () {
Navigator.pushNamed(context, '/regist');
},
),
],
),
),
],
),
),
),
);
}
}

View File

@ -0,0 +1,403 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:adminduk_puger/theme.dart';
import 'package:adminduk_puger/cubit/Auth/Auth_cubit.dart';
import 'package:adminduk_puger/cubit/Auth/Auth_state.dart';
class RegisterScreen extends StatefulWidget {
const RegisterScreen({super.key});
@override
_RegisterScreenState createState() => _RegisterScreenState();
}
class _RegisterScreenState extends State<RegisterScreen> {
bool _obscureText = true;
bool _obscureConfirmText = true;
final _formKey = GlobalKey<FormState>();
final TextEditingController _nameController = TextEditingController();
final TextEditingController _nikController = TextEditingController();
final TextEditingController _noKkController = TextEditingController();
final TextEditingController _emailController = TextEditingController();
final TextEditingController _phoneController = TextEditingController();
final TextEditingController _addressController = TextEditingController();
final TextEditingController _passwordController = TextEditingController();
final TextEditingController _confirmPasswordController =
TextEditingController();
@override
void dispose() {
_nameController.dispose();
_nikController.dispose();
_noKkController.dispose();
_emailController.dispose();
_phoneController.dispose();
_addressController.dispose();
_passwordController.dispose();
_confirmPasswordController.dispose();
super.dispose();
}
String? _validateName(String? value) {
if (value == null || value.isEmpty) {
return 'Nama tidak boleh kosong';
}
return null;
}
String? _validateEmail(String? value) {
if (value == null || value.isEmpty) {
return 'Email tidak boleh kosong';
}
if (!RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$').hasMatch(value)) {
return 'Email tidak valid';
}
return null;
}
String? _validatePhone(String? value) {
if (value == null || value.isEmpty) {
return 'Nomor telepon tidak boleh kosong';
}
if (!RegExp(r'^[0-9]{10,13}$').hasMatch(value)) {
return 'Nomor telepon tidak valid (10-13 digit)';
}
return null;
}
String? _validateAddress(String? value) {
if (value == null || value.isEmpty) {
return 'Alamat tidak boleh kosong';
}
return null;
}
String? _validatePassword(String? value) {
if (value == null || value.isEmpty) {
return 'Password tidak boleh kosong';
}
if (value.length < 8) {
return 'Password minimal 8 karakter';
}
return null;
}
String? _validateConfirmPassword(String? value) {
if (value == null || value.isEmpty) {
return 'Konfirmasi password tidak boleh kosong';
}
if (value != _passwordController.text) {
return 'Password tidak sama';
}
return null;
}
void _submitForm() {
if (_formKey.currentState!.validate()) {
context.read<AuthCubit>().register(
_nameController.text,
_emailController.text,
_phoneController.text,
_passwordController.text,
_addressController.text,
_nikController.text,
_noKkController.text,
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
leading: IconButton(
icon: Icon(Icons.arrow_back, color: Colors.black),
onPressed: () => Navigator.of(context).pop(),
),
),
body: BlocListener<AuthCubit, AuthState>(
listener: (context, state) {
if (state is AuthSuccess) {
Navigator.pushReplacementNamed(context, '/home');
} else if (state is AuthFailure) {
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text(state.error)));
} else if (state is AuthRegistrationSuccess) {
Navigator.pushReplacementNamed(
context,
'/login',
); // Pindah ke login
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(state.email)), // Tampilkan pesan dari API
);
}
},
child: SingleChildScrollView(
padding: const EdgeInsets.all(30.0),
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Header
Center(
child: Text.rich(
TextSpan(
children: [
TextSpan(
text: "Adminduk\n",
style: GoogleFonts.poppins(
fontWeight: FontWeight.bold,
fontSize: 30,
color: Colors.black,
),
),
TextSpan(
text: "PUGER",
style: GoogleFonts.poppins(
fontWeight: FontWeight.bold,
fontSize: 30,
color: dongker,
),
),
],
),
textAlign: TextAlign.center,
),
),
const SizedBox(height: 40),
Center(
child: Text(
'Buat Akun Baru',
style: GoogleFonts.poppins(
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
),
const SizedBox(height: 30),
// Name Input
TextFormField(
controller: _nameController,
validator: _validateName,
decoration: InputDecoration(
labelText: 'Nama Lengkap',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(30),
),
prefixIcon: const Icon(Icons.person),
),
),
const SizedBox(height: 30),
// Name Input
TextFormField(
controller: _nikController,
validator: _validateName,
decoration: InputDecoration(
labelText: 'NIK',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(30),
),
prefixIcon: const Icon(Icons.person),
),
),
const SizedBox(height: 30),
// Name Input
TextFormField(
controller: _noKkController,
validator: _validateName,
decoration: InputDecoration(
labelText: 'No. KK',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(30),
),
prefixIcon: const Icon(Icons.person),
),
),
const SizedBox(height: 20),
// Email Input
TextFormField(
controller: _emailController,
validator: _validateEmail,
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
labelText: 'Email',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(30),
),
prefixIcon: const Icon(Icons.email),
),
),
const SizedBox(height: 20),
// Phone Input
TextFormField(
controller: _phoneController,
validator: _validatePhone,
keyboardType: TextInputType.phone,
decoration: InputDecoration(
labelText: 'Nomor Telepon',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(30),
),
prefixIcon: const Icon(Icons.phone),
),
),
const SizedBox(height: 20),
// Address Input
TextFormField(
controller: _addressController,
validator: _validateAddress,
maxLines: 1,
decoration: InputDecoration(
labelText: 'Alamat',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(30),
),
prefixIcon: const Icon(Icons.home),
alignLabelWithHint: true,
),
),
const SizedBox(height: 20),
TextFormField(
controller: _passwordController,
validator: _validatePassword,
obscureText: _obscureText,
decoration: InputDecoration(
labelText: 'Password',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(30),
),
prefixIcon: const Icon(Icons.lock),
suffixIcon: IconButton(
icon: Icon(
_obscureText
? Icons.visibility_off_outlined
: Icons.remove_red_eye_outlined,
color: Colors.grey,
),
onPressed: () {
setState(() {
_obscureText = !_obscureText;
});
},
),
),
),
const SizedBox(height: 20),
TextFormField(
controller: _confirmPasswordController,
validator: _validateConfirmPassword,
obscureText: _obscureConfirmText,
decoration: InputDecoration(
labelText: 'Konfirmasi Password',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(30),
),
prefixIcon: const Icon(Icons.lock_outline),
suffixIcon: IconButton(
icon: Icon(
_obscureConfirmText
? Icons.visibility_off_outlined
: Icons.remove_red_eye_outlined,
color: Colors.grey,
),
onPressed: () {
setState(() {
_obscureConfirmText = !_obscureConfirmText;
});
},
),
),
),
const SizedBox(height: 40),
// Submit Button
BlocBuilder<AuthCubit, AuthState>(
builder: (context, state) {
return SizedBox(
width: double.infinity,
height: 50,
child: ElevatedButton(
onPressed: state is AuthLoading ? null : _submitForm,
style: ElevatedButton.styleFrom(
backgroundColor: dongker,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
),
),
child:
state is AuthLoading
? CircularProgressIndicator(color: Colors.white)
: Text(
"Daftar",
style: GoogleFonts.poppins(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.white,
),
),
),
);
},
),
const SizedBox(height: 25),
// Login Link
Center(
child: GestureDetector(
onTap: () {
Navigator.pushReplacementNamed(context, '/login');
},
child: RichText(
text: TextSpan(
children: [
TextSpan(
text: "Sudah punya akun? ",
style: GoogleFonts.poppins(
color: Colors.black,
fontSize: 14,
),
),
TextSpan(
text: "Login",
style: GoogleFonts.poppins(
color: dongker,
fontWeight: FontWeight.bold,
fontSize: 14,
),
),
],
),
),
),
),
const SizedBox(height: 20),
],
),
),
),
),
);
}
}

View File

@ -0,0 +1,37 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:adminduk_puger/cubit/Auth/Auth_cubit.dart';
import 'package:adminduk_puger/cubit/Auth/Auth_state.dart';
class VerifyScreen extends StatelessWidget {
final int userId;
final String email;
const VerifyScreen({super.key, required this.userId, required this.email});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("Verifikasi Email")),
body: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
"Email Anda belum diverifikasi",
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
const SizedBox(height: 10),
Text(
"Kami telah mengirim email verifikasi ke $email. Silakan periksa email Anda dan klik link verifikasi.",
textAlign: TextAlign.center,
),
const SizedBox(height: 20),
],
),
),
);
}
}

View File

@ -0,0 +1,73 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:adminduk_puger/cubit/document_cubit.dart';
import 'package:url_launcher/url_launcher.dart';
class DocumentPage extends StatelessWidget {
const DocumentPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'Dokumen',
style: GoogleFonts.poppins(fontSize: 20, fontWeight: FontWeight.w600),
),
),
body: BlocProvider(
create: (context) => DocumentCubit()..loadDocuments(),
child: BlocBuilder<DocumentCubit, List<DocumentModel>>(
builder: (context, documents) {
if (documents.isEmpty) {
return const Center(child: CircularProgressIndicator());
}
return ListView.builder(
itemCount: documents.length,
itemBuilder: (context, index) {
return Card(
margin: const EdgeInsets.symmetric(
vertical: 8,
horizontal: 10,
),
color: Colors.white,
child: SizedBox(
height: 80,
width: double.infinity,
child: ListTile(
contentPadding: const EdgeInsets.all(16),
leading: const Icon(Icons.document_scanner),
trailing: IconButton(
icon: const Icon(Icons.download),
onPressed: () async {
String fileName = documents[index].judul.replaceAll(
' ',
'_',
);
String url =
'https://admindukpuger.punyapadias.my.id/storage/${documents[index].path}';
await DocumentCubit.downloadDocument(
fileName,
url,
context,
);
},
),
title: Text(
documents[index].judul,
style: GoogleFonts.poppins(fontSize: 16),
),
),
),
);
},
);
},
),
),
backgroundColor: Colors.white,
);
}
}

File diff suppressed because one or more lines are too long

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