step 25 : upload ktp, qrcode string, edit data,
check token expired 10 menit dari expired_date
This commit is contained in:
@@ -32,7 +32,8 @@ Future<bool> isTokenExpired() async {
|
||||
|
||||
try {
|
||||
DateTime expiredDate = DateTime.parse(expireDateStr);
|
||||
DateTime batasExpired = expiredDate.subtract(Duration(minutes: 3));
|
||||
// DateTime batasExpired = expiredDate.subtract(Duration(minutes: 3));
|
||||
DateTime batasExpired = expiredDate.subtract(Duration(minutes: 10));
|
||||
DateTime now = DateTime.now();
|
||||
|
||||
final bool expired = now.isAfter(batasExpired);
|
||||
|
||||
@@ -4,6 +4,11 @@ class Constant {
|
||||
// static double designHeight = 1024;
|
||||
// static double designWidth = 1440;
|
||||
|
||||
// prosesAksi
|
||||
static String getRiwayat = "getRiwayat";
|
||||
static String postUploadFoto = "postUploadFoto";
|
||||
static String postEditScan = "postEditScan";
|
||||
|
||||
// base url
|
||||
static String baseURL = "http://devone.aplikasi.web.id/";
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:scanktpflutter/screen/no-login-scan/no_login_scan_screen.dart';
|
||||
import '../screen/no-login-home/no_login_home_screen.dart';
|
||||
import '../screen/no-login-scan/no_login_edit_scan_screen.dart';
|
||||
import '../screen/no-login-splash/no_login_splash_screen.dart';
|
||||
import '../screen/no-login/no_login_screen.dart';
|
||||
|
||||
@@ -119,6 +120,16 @@ class AppRoute {
|
||||
});
|
||||
}
|
||||
|
||||
if (settings.name == noLoginEditScanRoute) {
|
||||
return MaterialPageRoute(builder: (context) {
|
||||
return MediaQuery(
|
||||
data: MediaQuery.of(context).copyWith(
|
||||
textScaler: TextScaler.linear(1.0), padding: EdgeInsets.all(0)),
|
||||
child: NoLoginEditScanScreen(),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
return MaterialPageRoute(builder: (context) {
|
||||
return MediaQuery(
|
||||
data: MediaQuery.of(context).copyWith(
|
||||
|
||||
49
lib/model/no-login/no_login_edit_person_ktp_model.dart
Normal file
49
lib/model/no-login/no_login_edit_person_ktp_model.dart
Normal file
@@ -0,0 +1,49 @@
|
||||
class NoLoginEditPersonKtpModel {
|
||||
final String personID;
|
||||
final String personNIK;
|
||||
final String personName;
|
||||
final String personDob;
|
||||
final String personSex;
|
||||
final String personUrl;
|
||||
final String personQrCode;
|
||||
final String m_sexname;
|
||||
|
||||
NoLoginEditPersonKtpModel({
|
||||
required this.personID,
|
||||
required this.personNIK,
|
||||
required this.personName,
|
||||
required this.personDob,
|
||||
required this.personSex,
|
||||
required this.personUrl,
|
||||
required this.personQrCode,
|
||||
required this.m_sexname,
|
||||
});
|
||||
|
||||
// Convert JSON to Model
|
||||
factory NoLoginEditPersonKtpModel.fromJson(Map<String, dynamic> json) {
|
||||
return NoLoginEditPersonKtpModel(
|
||||
personID: json['Person_ID'] ?? "",
|
||||
personNIK: json['Person_NIK'] ?? "",
|
||||
personName: json['Person_Name'] ?? "",
|
||||
personDob: json['Person_Dob'] ?? DateTime.now(),
|
||||
personSex: json['Person_Sex'] ?? "",
|
||||
personUrl: json['Person_Url'] ?? "",
|
||||
personQrCode: json['Person_QrCode'] ?? "",
|
||||
m_sexname: json['m_sexname'] ?? "",
|
||||
);
|
||||
}
|
||||
|
||||
// Convert Model to JSON
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'Person_ID':personID,
|
||||
'Person_NIK': personNIK,
|
||||
'Person_Name': personName,
|
||||
'Person_Dob': personDob,
|
||||
'Person_Sex': personSex,
|
||||
'Person_Url': personUrl,
|
||||
'Person_QrCode': personQrCode,
|
||||
'm_sexname':m_sexname,
|
||||
};
|
||||
}
|
||||
}
|
||||
49
lib/model/no-login/no_login_person_ktp_model.dart
Normal file
49
lib/model/no-login/no_login_person_ktp_model.dart
Normal file
@@ -0,0 +1,49 @@
|
||||
class NoLoginPersonKtpModel {
|
||||
final String personID;
|
||||
final String personNIK;
|
||||
final String personName;
|
||||
final String personDob;
|
||||
final String personSex;
|
||||
final String personUrl;
|
||||
final String personQrCode;
|
||||
final String m_sexname;
|
||||
|
||||
NoLoginPersonKtpModel({
|
||||
required this.personID,
|
||||
required this.personNIK,
|
||||
required this.personName,
|
||||
required this.personDob,
|
||||
required this.personSex,
|
||||
required this.personUrl,
|
||||
required this.personQrCode,
|
||||
required this.m_sexname,
|
||||
});
|
||||
|
||||
// Convert JSON to Model
|
||||
factory NoLoginPersonKtpModel.fromJson(Map<String, dynamic> json) {
|
||||
return NoLoginPersonKtpModel(
|
||||
personID: json['Person_ID'] ?? "",
|
||||
personNIK: json['Person_NIK'] ?? "",
|
||||
personName: json['Person_Name'] ?? "",
|
||||
personDob: json['Person_Dob'] ?? DateTime.now(),
|
||||
personSex: json['Person_Sex'] ?? "",
|
||||
personUrl: json['Person_Url'] ?? "",
|
||||
personQrCode: json['Person_QrCode'] ?? "",
|
||||
m_sexname: json['m_sexname'] ?? "",
|
||||
);
|
||||
}
|
||||
|
||||
// Convert Model to JSON
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'Person_ID':personID,
|
||||
'Person_NIK': personNIK,
|
||||
'Person_Name': personName,
|
||||
'Person_Dob': personDob,
|
||||
'Person_Sex': personSex,
|
||||
'Person_Url': personUrl,
|
||||
'Person_QrCode': personQrCode,
|
||||
'm_sexname':m_sexname,
|
||||
};
|
||||
}
|
||||
}
|
||||
31
lib/model/no-login/no_login_sex_model.dart
Normal file
31
lib/model/no-login/no_login_sex_model.dart
Normal file
@@ -0,0 +1,31 @@
|
||||
class NoLoginSexModel {
|
||||
final String M_SexID;
|
||||
final String M_SexCode;
|
||||
final String m_sexname;
|
||||
final String M_SexNameLang;
|
||||
|
||||
NoLoginSexModel({
|
||||
required this.M_SexID,
|
||||
required this.M_SexCode,
|
||||
required this.m_sexname,
|
||||
required this.M_SexNameLang,
|
||||
});
|
||||
|
||||
factory NoLoginSexModel.fromJson(Map<String, dynamic> json) {
|
||||
return NoLoginSexModel(
|
||||
M_SexID: json['M_SexID'],
|
||||
M_SexCode: json['M_SexCode'],
|
||||
m_sexname: json['m_sexname'],
|
||||
M_SexNameLang: json['M_SexNameLang'],
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'M_SexID': M_SexID,
|
||||
'M_SexCode': M_SexCode,
|
||||
'm_sexname': m_sexname,
|
||||
'M_SexNameLang': M_SexNameLang,
|
||||
};
|
||||
}
|
||||
}
|
||||
49
lib/model/no-login/no_login_sukses_person_model.dart
Normal file
49
lib/model/no-login/no_login_sukses_person_model.dart
Normal file
@@ -0,0 +1,49 @@
|
||||
class NoLoginSuksesPersonKtpModel {
|
||||
final String personID;
|
||||
final String personNIK;
|
||||
final String personName;
|
||||
final String personDob;
|
||||
final String personSex;
|
||||
final String personUrl;
|
||||
final String personQrCode;
|
||||
final String m_sexname;
|
||||
|
||||
NoLoginSuksesPersonKtpModel({
|
||||
required this.personID,
|
||||
required this.personNIK,
|
||||
required this.personName,
|
||||
required this.personDob,
|
||||
required this.personSex,
|
||||
required this.personUrl,
|
||||
required this.personQrCode,
|
||||
required this.m_sexname,
|
||||
});
|
||||
|
||||
// Convert JSON to Model
|
||||
factory NoLoginSuksesPersonKtpModel.fromJson(Map<String, dynamic> json) {
|
||||
return NoLoginSuksesPersonKtpModel(
|
||||
personID: json['Person_ID'] ?? "",
|
||||
personNIK: json['Person_NIK'] ?? "",
|
||||
personName: json['Person_Name'] ?? "",
|
||||
personDob: json['Person_Dob'] ?? DateTime.now(),
|
||||
personSex: json['Person_Sex'] ?? "",
|
||||
personUrl: json['Person_Url'] ?? "",
|
||||
personQrCode: json['Person_QrCode'] ?? "",
|
||||
m_sexname: json['m_sexname'] ?? "",
|
||||
);
|
||||
}
|
||||
|
||||
// Convert Model to JSON
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'Person_ID':personID,
|
||||
'Person_NIK': personNIK,
|
||||
'Person_Name': personName,
|
||||
'Person_Dob': personDob,
|
||||
'Person_Sex': personSex,
|
||||
'Person_Url': personUrl,
|
||||
'Person_QrCode': personQrCode,
|
||||
'm_sexname':m_sexname,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,32 +1,39 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:mobile_scanner/mobile_scanner.dart';
|
||||
import 'package:scanktpflutter/model/sex_model.dart';
|
||||
import 'package:scanktpflutter/model/no-login/no_login_edit_person_ktp_model.dart';
|
||||
import 'package:scanktpflutter/model/no-login/no_login_person_ktp_model.dart';
|
||||
import 'package:scanktpflutter/model/no-login/no_login_sex_model.dart';
|
||||
|
||||
import '../../app/constant.dart';
|
||||
import '../../model/edit_person_model.dart';
|
||||
import '../../model/person_ktp_model.dart';
|
||||
|
||||
// list scan
|
||||
final listScanRwt = StateProvider<List<PersonKtp>>(
|
||||
final listScanRwt = StateProvider<List<NoLoginPersonKtpModel>>(
|
||||
(ref) => List.empty(
|
||||
growable: true,
|
||||
),
|
||||
);
|
||||
|
||||
final selectedPersonIdx = StateProvider<String>((ref) => "0");
|
||||
final selectedEdit = StateProvider<EditPersonModel>(
|
||||
(ref) => EditPersonModel(
|
||||
final selectedEdit = StateProvider<NoLoginEditPersonKtpModel>(
|
||||
(ref) => NoLoginEditPersonKtpModel(
|
||||
personID: "",
|
||||
personNIK: "",
|
||||
personName: "",
|
||||
personDob: "",
|
||||
personSex: "",
|
||||
personUrl: "",
|
||||
personQrCode: "",
|
||||
m_sexname: "",
|
||||
),
|
||||
);
|
||||
|
||||
// inputan edit
|
||||
final eQrCode = StateProvider<TextEditingController>(
|
||||
(ref) => TextEditingController(text: ""),
|
||||
);
|
||||
|
||||
final eNikCtr = StateProvider<TextEditingController>(
|
||||
(ref) => TextEditingController(text: ""),
|
||||
);
|
||||
@@ -47,8 +54,8 @@ final eSexCtr = StateProvider<TextEditingController>(
|
||||
(ref) => TextEditingController(text: ""),
|
||||
);
|
||||
|
||||
final eSexSelected = StateProvider<SexModel>(
|
||||
(ref) => SexModel(
|
||||
final eSexSelected = StateProvider<NoLoginSexModel>(
|
||||
(ref) => NoLoginSexModel(
|
||||
M_SexID: "",
|
||||
M_SexCode: "",
|
||||
m_sexname: "",
|
||||
@@ -58,4 +65,6 @@ final eSexSelected = StateProvider<SexModel>(
|
||||
|
||||
final barcodeX = StateProvider<Barcode>(
|
||||
(ref) => Barcode(),
|
||||
);
|
||||
);
|
||||
|
||||
final noLoginprosesAksi = StateProvider<String>((ref) => Constant.getRiwayat);
|
||||
@@ -1,50 +1,56 @@
|
||||
import '../../model/person_ktp_model.dart';
|
||||
import '../../model/sex_model.dart';
|
||||
|
||||
import '../../model/sukses_person_model.dart';
|
||||
import '../../model/no-login/no_login_person_ktp_model.dart';
|
||||
import '../../model/no-login/no_login_sex_model.dart';
|
||||
import '../../model/no-login/no_login_sukses_person_model.dart';
|
||||
import '../base_repository.dart';
|
||||
|
||||
class NoLoginScanRepository extends BaseRepository {
|
||||
NoLoginScanRepository({required super.dio});
|
||||
|
||||
Future<List<PersonKtp>> listRiwayatScanRepo({
|
||||
Future<List<NoLoginPersonKtpModel>> listRiwayatScanRepo({
|
||||
required String host,
|
||||
required String userId,
|
||||
required String client_id,
|
||||
required String token,
|
||||
}) async {
|
||||
// final service = "${Constant.baseUrl}xauth/login";
|
||||
final service =
|
||||
"http://${host}/one-api/scan-ktpv2-no-login/Scanktpv2/listRiwayatScan";
|
||||
final resp = await post(
|
||||
param: {"userId": userId},
|
||||
param: {"client_id": client_id},
|
||||
service: service,
|
||||
token: token,
|
||||
);
|
||||
|
||||
final result = List<PersonKtp>.empty(growable: true);
|
||||
final result = List<NoLoginPersonKtpModel>.empty(growable: true);
|
||||
resp['data'].forEach((e) {
|
||||
final model = PersonKtp.fromJson(e);
|
||||
final model = NoLoginPersonKtpModel.fromJson(e);
|
||||
result.add(model);
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Future<List<SuksesPersonModel>> prosesScan({
|
||||
Future<List<NoLoginSuksesPersonKtpModel>> prosesScan({
|
||||
required String host,
|
||||
required String base64File,
|
||||
required String userId,
|
||||
required String client_id,
|
||||
required String qr_code,
|
||||
required String token,
|
||||
}) async {
|
||||
final service =
|
||||
"http://${host}/one-api/scan-ktpv2-no-login/Scanktpv2/proses_scan";
|
||||
final resp = await post(param: {
|
||||
"base64File": base64File,
|
||||
"userId": userId,
|
||||
}, service: service);
|
||||
final resp = await post(
|
||||
param: {
|
||||
"base64File": base64File,
|
||||
"client_id": client_id,
|
||||
"qr_code": qr_code,
|
||||
},
|
||||
service: service,
|
||||
token: token,
|
||||
);
|
||||
|
||||
final result = List<SuksesPersonModel>.empty(growable: true);
|
||||
final result = List<NoLoginSuksesPersonKtpModel>.empty(growable: true);
|
||||
resp['data'].forEach((e) {
|
||||
final model = SuksesPersonModel.fromJson(e);
|
||||
final model = NoLoginSuksesPersonKtpModel.fromJson(e);
|
||||
result.add(model);
|
||||
});
|
||||
|
||||
@@ -52,16 +58,23 @@ class NoLoginScanRepository extends BaseRepository {
|
||||
}
|
||||
|
||||
// sex
|
||||
Future<List<SexModel>> sexRepo({
|
||||
Future<List<NoLoginSexModel>> sexRepo({
|
||||
required String host,
|
||||
required String client_id,
|
||||
required String token,
|
||||
}) async {
|
||||
// final service = "${Constant.baseUrl}xauth/login";
|
||||
final service = "http://${host}/one-api/scan-ktpv2-no-login/Scanktpv2/getSex";
|
||||
final resp = await post(param: {}, service: service);
|
||||
final service =
|
||||
"http://${host}/one-api/scan-ktpv2-no-login/Scanktpv2/getSex";
|
||||
final resp = await post(
|
||||
param: {"client_id": client_id},
|
||||
service: service,
|
||||
token: token,
|
||||
);
|
||||
|
||||
final result = List<SexModel>.empty(growable: true);
|
||||
final result = List<NoLoginSexModel>.empty(growable: true);
|
||||
resp['data'].forEach((e) {
|
||||
final model = SexModel.fromJson(e);
|
||||
final model = NoLoginSexModel.fromJson(e);
|
||||
result.add(model);
|
||||
});
|
||||
|
||||
@@ -70,8 +83,9 @@ class NoLoginScanRepository extends BaseRepository {
|
||||
|
||||
// edit
|
||||
Future<String> prosesEdit({
|
||||
required String token,
|
||||
required String host,
|
||||
required String userId,
|
||||
required String client_id,
|
||||
required String Person_ID,
|
||||
required String Person_NIK,
|
||||
required String Person_Name,
|
||||
@@ -87,9 +101,10 @@ class NoLoginScanRepository extends BaseRepository {
|
||||
"Person_Name": Person_Name,
|
||||
"Person_Dob": Person_Dob,
|
||||
"Person_Sex": Person_Sex,
|
||||
"userId": userId,
|
||||
"client_id": client_id,
|
||||
},
|
||||
service: service,
|
||||
token: token,
|
||||
);
|
||||
|
||||
if (resp['status'] == "OK") {
|
||||
|
||||
@@ -8,7 +8,7 @@ import '../../app/route.dart';
|
||||
import '../../app/constant.dart';
|
||||
import '../../model/edit_person_model.dart';
|
||||
import '../../model/person_ktp_model.dart';
|
||||
import '../../provider/no-login-scan/no_login_scan_provider.dart';
|
||||
import '../../provider/scan_provider.dart';
|
||||
|
||||
class CardRiwayatScan extends HookConsumerWidget {
|
||||
final PersonKtp data;
|
||||
|
||||
@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import '../../provider/no-login-scan/no_login_scan_provider.dart';
|
||||
import 'package:scanktpflutter/provider/scan_provider.dart';
|
||||
import '../../screen/home/card_riwayat_scan.dart';
|
||||
import '../../screen/home/list_riwayat_scan_provider.dart';
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import '../../provider/no-login-scan/no_login_scan_provider.dart';
|
||||
import '../../provider/scan_provider.dart';
|
||||
import '../../repository/scan_repository.dart';
|
||||
|
||||
import '../../model/person_ktp_model.dart';
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:scanktpflutter/model/sex_model.dart';
|
||||
import '../../model/no-login/no_login_edit_person_ktp_model.dart';
|
||||
import '../../model/no-login/no_login_person_ktp_model.dart';
|
||||
import '../../model/no-login/no_login_sex_model.dart';
|
||||
import '../../app/app_extension.dart';
|
||||
import '../../app/route.dart';
|
||||
|
||||
import '../../app/constant.dart';
|
||||
import '../../model/edit_person_model.dart';
|
||||
import '../../model/person_ktp_model.dart';
|
||||
import '../../provider/no-login-scan/no_login_scan_provider.dart';
|
||||
|
||||
class NoLoginCardRiwayatScan extends HookConsumerWidget {
|
||||
final PersonKtp data;
|
||||
final NoLoginPersonKtpModel data;
|
||||
const NoLoginCardRiwayatScan({
|
||||
super.key,
|
||||
required this.data,
|
||||
@@ -52,14 +52,14 @@ class NoLoginCardRiwayatScan extends HookConsumerWidget {
|
||||
data.personID;
|
||||
|
||||
// set SEX
|
||||
ref.read(eSexSelected.notifier).state = SexModel(
|
||||
ref.read(eSexSelected.notifier).state = NoLoginSexModel(
|
||||
M_SexID: data.personSex,
|
||||
M_SexCode: "",
|
||||
m_sexname: data.m_sexname,
|
||||
M_SexNameLang: ""
|
||||
);
|
||||
|
||||
ref.read(selectedEdit.notifier).state = EditPersonModel(
|
||||
ref.read(selectedEdit.notifier).state = NoLoginEditPersonKtpModel(
|
||||
personID: data.personID,
|
||||
personNIK: data.personNIK,
|
||||
personName: data.personName,
|
||||
@@ -67,9 +67,10 @@ class NoLoginCardRiwayatScan extends HookConsumerWidget {
|
||||
personDob: data.personDob,
|
||||
personSex: data.personSex,
|
||||
personUrl: data.personUrl,
|
||||
personQrCode: data.personQrCode,
|
||||
);
|
||||
Navigator.of(context).pushNamed(
|
||||
editScanRoute,
|
||||
noLoginEditScanRoute,
|
||||
);
|
||||
},
|
||||
child: Icon(
|
||||
|
||||
@@ -28,25 +28,29 @@ class NoLoginHomeScreen extends HookConsumerWidget {
|
||||
final host = currentUser?.host ?? "";
|
||||
final isLoading = useState<bool>(false);
|
||||
final listScanArr = ref.watch(listScanRwt);
|
||||
final userId = currentUser?.client_id ?? "";
|
||||
final client_id = currentUser?.client_id ?? "";
|
||||
final token = currentUser?.token ?? "";
|
||||
final expire_date = currentUser?.expire_date ?? "";
|
||||
final readProsesAksi = ref.watch(noLoginprosesAksi);
|
||||
|
||||
useEffect(() {
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
|
||||
final userID = currentUser?.client_id ?? "0";
|
||||
// final prefs = await SharedPreferences.getInstance();
|
||||
final token = currentUser?.token ?? "";
|
||||
|
||||
if (userID == "0") {
|
||||
// not logged in
|
||||
if (client_id == "0" || token == "") {
|
||||
// not logged in and doesn't have token
|
||||
Navigator.of(context)
|
||||
.pushNamedAndRemoveUntil(noLoginRoute, (route) => false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (token == "") {
|
||||
Navigator.of(context)
|
||||
.pushNamedAndRemoveUntil(noLoginRoute, (route) => false);
|
||||
return;
|
||||
if (token != "") {
|
||||
if (await isTokenExpired() == true) {
|
||||
print("Token expired, refreshing...");
|
||||
ref.read(noLoginRefreshTokenProvider.notifier).refreshToken(
|
||||
client_id: client_id,
|
||||
host: host,
|
||||
expire_date: expire_date,
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
return () {};
|
||||
@@ -56,14 +60,42 @@ class NoLoginHomeScreen extends HookConsumerWidget {
|
||||
WidgetsBinding.instance.addPostFrameCallback((timestap) async {
|
||||
ref.read(noLoginRiwayatScanProvider.notifier).noLoginRiwayatScan(
|
||||
host: host,
|
||||
userId: userId,
|
||||
token: currentUser?.token ?? "",
|
||||
expire_date: currentUser?.expire_date ?? "",
|
||||
client_id: client_id,
|
||||
token: token,
|
||||
expire_date: expire_date,
|
||||
);
|
||||
});
|
||||
return () {};
|
||||
}, []);
|
||||
|
||||
// refreshToken Provider
|
||||
ref.listen(noLoginRefreshTokenProvider, (prev, next) async {
|
||||
if (next is NoLoginRefreshTokenStateLoading) {
|
||||
isLoading.value = true;
|
||||
} else if (next is NoLoginRefreshTokenStateError) {
|
||||
isLoading.value = false;
|
||||
// errorMessage.value = next.message;
|
||||
snackbarWidget(
|
||||
context,
|
||||
next.message,
|
||||
snackbarType.error,
|
||||
Duration(seconds: 3),
|
||||
);
|
||||
} else if (next is NoLoginRefreshTokenStateDone) {
|
||||
isLoading.value = false;
|
||||
|
||||
// check proses aksi yg berlangsung
|
||||
if (readProsesAksi == Constant.getRiwayat) {
|
||||
ref.read(noLoginRiwayatScanProvider.notifier).noLoginRiwayatScan(
|
||||
host: host,
|
||||
client_id: client_id,
|
||||
token: token,
|
||||
expire_date: expire_date,
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// listRiwayProvider
|
||||
ref.listen(noLoginRiwayatScanProvider, (prev, next) async {
|
||||
if (next is NoLoginRiwayatScanStateLoading) {
|
||||
@@ -83,33 +115,20 @@ class NoLoginHomeScreen extends HookConsumerWidget {
|
||||
});
|
||||
|
||||
void getRiwayat() async {
|
||||
final currentUser = ref.read(noLoginCurrentUserProvider);
|
||||
final host = currentUser?.host ?? "";
|
||||
final userId = currentUser?.client_id ?? "";
|
||||
final expireDate = currentUser?.expire_date ?? "";
|
||||
|
||||
if (await isTokenExpired() == true) {
|
||||
ref.read(noLoginprosesAksi.notifier).state = Constant.getRiwayat;
|
||||
print("Token expired, refreshing...");
|
||||
ref.read(noLoginRefreshTokenProvider.notifier).refreshToken(
|
||||
client_id: userId,
|
||||
client_id: client_id,
|
||||
host: host,
|
||||
expire_date: expireDate,
|
||||
);
|
||||
|
||||
ref.read(noLoginRiwayatScanProvider.notifier).noLoginRiwayatScan(
|
||||
host: host,
|
||||
userId: userId,
|
||||
token: ref.read(noLoginCurrentUserProvider)?.token ?? "",
|
||||
expire_date:
|
||||
ref.read(noLoginCurrentUserProvider)?.expire_date ?? "",
|
||||
expire_date: expire_date,
|
||||
);
|
||||
} else {
|
||||
ref.read(noLoginRiwayatScanProvider.notifier).noLoginRiwayatScan(
|
||||
host: host,
|
||||
userId: userId,
|
||||
token: ref.read(noLoginCurrentUserProvider)?.token ?? "",
|
||||
expire_date:
|
||||
ref.read(noLoginCurrentUserProvider)?.expire_date ?? "",
|
||||
client_id: client_id,
|
||||
token: token,
|
||||
expire_date: expire_date,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:scanktpflutter/screen/no-login/no_login_refresh_token_provider.dart';
|
||||
import '../../app/app_extension.dart';
|
||||
import 'package:scanktpflutter/model/no-login/no_login_person_ktp_model.dart';
|
||||
import '../../repository/no-login-scan/no_login_scan_repository.dart';
|
||||
import '../../provider/no-login-scan/no_login_scan_provider.dart';
|
||||
|
||||
import '../../model/person_ktp_model.dart';
|
||||
import '../../provider/dio_provider.dart';
|
||||
import '../../repository/base_repository.dart';
|
||||
|
||||
@@ -22,7 +20,7 @@ class NoLoginRiwayatScanNotifier
|
||||
: super(NoLoginRiwayatScanStateInit());
|
||||
void noLoginRiwayatScan({
|
||||
required String host,
|
||||
required String userId,
|
||||
required String client_id,
|
||||
required String token,
|
||||
required String expire_date,
|
||||
}) async {
|
||||
@@ -32,7 +30,7 @@ class NoLoginRiwayatScanNotifier
|
||||
dio: ref.read(dioProvider),
|
||||
).listRiwayatScanRepo(
|
||||
host: host,
|
||||
userId: userId,
|
||||
client_id: client_id,
|
||||
token: token,
|
||||
);
|
||||
|
||||
@@ -83,7 +81,7 @@ class NoLoginRiwayatScanStateError extends NoLoginRiwayatScanState {
|
||||
}
|
||||
|
||||
class NoLoginRiwayatScanStateDone extends NoLoginRiwayatScanState {
|
||||
final List<PersonKtp> model;
|
||||
final List<NoLoginPersonKtpModel> model;
|
||||
NoLoginRiwayatScanStateDone({
|
||||
required this.model,
|
||||
}) : super(DateTime.now());
|
||||
|
||||
81
lib/screen/no-login-scan/no_login_edit_scan_provider.dart
Normal file
81
lib/screen/no-login-scan/no_login_edit_scan_provider.dart
Normal file
@@ -0,0 +1,81 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:scanktpflutter/repository/no-login-scan/no_login_scan_repository.dart';
|
||||
|
||||
import '../../provider/dio_provider.dart';
|
||||
import '../../repository/base_repository.dart';
|
||||
|
||||
// 3. state provider
|
||||
final noLoginEditScanProvider = StateNotifierProvider<NoLoginEditScanNotifier, NoLoginEditScanState>(
|
||||
(ref) => NoLoginEditScanNotifier(ref: ref));
|
||||
|
||||
// 2. notifier
|
||||
class NoLoginEditScanNotifier extends StateNotifier<NoLoginEditScanState> {
|
||||
final Ref ref;
|
||||
NoLoginEditScanNotifier({required this.ref}) : super(NoLoginEditScanStateInit());
|
||||
void editScan({
|
||||
required String token,
|
||||
required String host,
|
||||
required String client_id,
|
||||
required String Person_ID,
|
||||
required String Person_NIK,
|
||||
required String Person_Name,
|
||||
required String Person_Dob,
|
||||
required String Person_Sex,
|
||||
}) async {
|
||||
try {
|
||||
state = NoLoginEditScanStateLoading();
|
||||
final resp = await NoLoginScanRepository(
|
||||
dio: ref.read(dioProvider),
|
||||
).prosesEdit(
|
||||
token: token,
|
||||
host: host,
|
||||
Person_ID: Person_ID,
|
||||
Person_NIK: Person_NIK,
|
||||
Person_Name: Person_Name,
|
||||
Person_Dob: Person_Dob,
|
||||
Person_Sex: Person_Sex,
|
||||
client_id: client_id,
|
||||
);
|
||||
|
||||
// print(resp);
|
||||
state = NoLoginEditScanStateDone(pesan: resp);
|
||||
} catch (e) {
|
||||
if (e is BaseRepositoryException) {
|
||||
state = NoLoginEditScanStateError(message: e.message);
|
||||
} else {
|
||||
state = NoLoginEditScanStateError(message: e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 1. state
|
||||
abstract class NoLoginEditScanState extends Equatable {
|
||||
final DateTime date;
|
||||
const NoLoginEditScanState(this.date);
|
||||
@override
|
||||
List<Object?> get props => [date];
|
||||
}
|
||||
|
||||
class NoLoginEditScanStateInit extends NoLoginEditScanState {
|
||||
NoLoginEditScanStateInit() : super(DateTime.now());
|
||||
}
|
||||
|
||||
class NoLoginEditScanStateLoading extends NoLoginEditScanState {
|
||||
NoLoginEditScanStateLoading() : super(DateTime.now());
|
||||
}
|
||||
|
||||
class NoLoginEditScanStateError extends NoLoginEditScanState {
|
||||
final String message;
|
||||
NoLoginEditScanStateError({
|
||||
required this.message,
|
||||
}) : super(DateTime.now());
|
||||
}
|
||||
|
||||
class NoLoginEditScanStateDone extends NoLoginEditScanState {
|
||||
final String pesan;
|
||||
NoLoginEditScanStateDone({
|
||||
required this.pesan,
|
||||
}) : super(DateTime.now());
|
||||
}
|
||||
715
lib/screen/no-login-scan/no_login_edit_scan_screen.dart
Normal file
715
lib/screen/no-login-scan/no_login_edit_scan_screen.dart
Normal file
@@ -0,0 +1,715 @@
|
||||
import 'package:dropdown_button2/dropdown_button2.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:scanktpflutter/model/no-login/no_login_sex_model.dart';
|
||||
import 'package:scanktpflutter/provider/no-login-scan/no_login_scan_provider.dart';
|
||||
import 'package:scanktpflutter/screen/no-login-scan/no_login_edit_scan_provider.dart';
|
||||
import 'package:scanktpflutter/screen/scan/edit_scan_provider.dart';
|
||||
import '../../model/sex_model.dart';
|
||||
import '../../provider/no-login/no_login_current_user_provider.dart';
|
||||
import '../../widget/customsnackbarwidget.dart';
|
||||
|
||||
import '../../app/app_extension.dart';
|
||||
import '../../app/constant.dart';
|
||||
import '../../app/route.dart';
|
||||
import '../../provider/current_user_provider.dart';
|
||||
import '../home/list_riwayat_scan_provider.dart';
|
||||
import '../no-login-home/no_login_riwayat_scan_provider.dart';
|
||||
import '../no-login/no_login_refresh_token_provider.dart';
|
||||
import 'no_login_sex_provider.dart';
|
||||
|
||||
class NoLoginEditScanScreen extends HookConsumerWidget {
|
||||
const NoLoginEditScanScreen({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: [
|
||||
SystemUiOverlay.bottom,
|
||||
]);
|
||||
|
||||
final currentUser = ref.watch(noLoginCurrentUserProvider);
|
||||
// final username = currentUser?.model.username ?? "-";
|
||||
final host = currentUser?.host ?? "";
|
||||
final isLoading = useState<bool>(false);
|
||||
final client_id = currentUser?.client_id ?? "";
|
||||
final token = currentUser?.token ?? "";
|
||||
final expire_date = currentUser?.expire_date ?? "";
|
||||
final readProsesAksi = ref.watch(noLoginprosesAksi);
|
||||
final baseUrl = "https://$host/";
|
||||
|
||||
final selectedPersonId = ref.watch(selectedPersonIdx);
|
||||
|
||||
final listDataEdit = ref.watch(selectedEdit);
|
||||
|
||||
final listSex = useState<List<NoLoginSexModel>>(
|
||||
List.empty(growable: true),
|
||||
);
|
||||
|
||||
useEffect(() {
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
|
||||
if (client_id == "0" || token == "") {
|
||||
// not logged in and doesn't have token
|
||||
Navigator.of(context)
|
||||
.pushNamedAndRemoveUntil(noLoginRoute, (route) => false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (token != "") {
|
||||
if (await isTokenExpired() == true) {
|
||||
print("Token expired, refreshing...");
|
||||
ref.read(noLoginRefreshTokenProvider.notifier).refreshToken(
|
||||
client_id: client_id,
|
||||
host: host,
|
||||
expire_date: expire_date,
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
return () {};
|
||||
}, [currentUser]);
|
||||
|
||||
// sex
|
||||
ref.listen(noLoginSexProvider, (prev, next) {
|
||||
if (next is NoLoginSexStateLoading) {
|
||||
isLoading.value = true;
|
||||
} else if (next is NoLoginSexStateError) {
|
||||
isLoading.value = false;
|
||||
// errorMessage.value = next.message;
|
||||
snackbarWidget(
|
||||
context,
|
||||
next.message,
|
||||
snackbarType.error,
|
||||
Duration(seconds: 3),
|
||||
);
|
||||
} else if (next is NoLoginSexStateDone) {
|
||||
isLoading.value = false;
|
||||
listSex.value = next.model;
|
||||
// ref.read(eSexCtr.notifier).state =
|
||||
// TextEditingController(text: next.model[0].m_sexname);
|
||||
|
||||
final sexSel = ref.read(selectedEdit.notifier).state;
|
||||
if (next.model.isNotEmpty) {
|
||||
final matchedItems = next.model
|
||||
.where((item) => item.M_SexID == sexSel.personSex)
|
||||
.toList();
|
||||
|
||||
if (matchedItems.length == 1) {
|
||||
ref.read(eSexCtr.notifier).state = TextEditingController(
|
||||
text: matchedItems[0].m_sexname,
|
||||
);
|
||||
} else {
|
||||
// Jika lebih dari satu atau tidak ada yang cocok
|
||||
print('Error: Multiple or no matching items found.');
|
||||
// Bisa juga mengatur default value jika tidak ditemukan
|
||||
ref.read(eSexCtr.notifier).state =
|
||||
TextEditingController(text: ''); // atau nilai default lain
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// isLoading
|
||||
useEffect(() {
|
||||
WidgetsBinding.instance.addPostFrameCallback((timestamp) async {
|
||||
if (isLoading.value == true) {
|
||||
snackbarWidget(
|
||||
context,
|
||||
"Sedang Memuat Data",
|
||||
snackbarType.warning,
|
||||
Duration(days: 1),
|
||||
);
|
||||
}
|
||||
});
|
||||
return () {};
|
||||
}, [isLoading]);
|
||||
|
||||
// check person id
|
||||
useEffect(() {
|
||||
WidgetsBinding.instance.addPostFrameCallback((timestamp) async {
|
||||
final personIDx = selectedPersonId;
|
||||
if (personIDx == "0") {
|
||||
snackbarWidget(
|
||||
context,
|
||||
'Gagal mendapatkan data',
|
||||
snackbarType.error,
|
||||
Duration(seconds: 3),
|
||||
);
|
||||
Navigator.of(context)
|
||||
.pushNamedAndRemoveUntil(homeRoute, (route) => false);
|
||||
return;
|
||||
} else {
|
||||
// listDataEdit
|
||||
// set ke inputan
|
||||
ref.read(eQrCode.notifier).state =
|
||||
TextEditingController(text: listDataEdit.personQrCode);
|
||||
|
||||
ref.read(eNikCtr.notifier).state =
|
||||
TextEditingController(text: listDataEdit.personNIK);
|
||||
|
||||
ref.read(eNamaCtr.notifier).state =
|
||||
TextEditingController(text: listDataEdit.personName);
|
||||
|
||||
ref.read(eDobCtr.notifier).state = TextEditingController(
|
||||
text: formatDateJiffy(listDataEdit.personDob));
|
||||
|
||||
ref.read(eDobDt.notifier).state =
|
||||
DateTime.parse(listDataEdit.personDob);
|
||||
|
||||
final parsedDate = DateTime.parse(listDataEdit.personDob);
|
||||
// print("Parsed Date: $parsedDate");
|
||||
|
||||
ref.read(eDobDt.notifier).state = parsedDate;
|
||||
|
||||
// sex
|
||||
ref.read(noLoginSexProvider.notifier).sex(
|
||||
host: host,
|
||||
client_id: client_id,
|
||||
token: token,
|
||||
);
|
||||
}
|
||||
});
|
||||
return () {};
|
||||
}, [selectedPersonId]);
|
||||
|
||||
// date picker
|
||||
Future<void> _selectDate(BuildContext context, WidgetRef ref) async {
|
||||
DateTime? newSelectedDate = await showDatePicker(
|
||||
initialEntryMode: DatePickerEntryMode.calendarOnly,
|
||||
context: context,
|
||||
initialDate: (listDataEdit.personDob != "0000-00-00")
|
||||
? DateTime.parse(listDataEdit.personDob)
|
||||
: DateTime.now(),
|
||||
firstDate: DateTime(1900),
|
||||
lastDate: DateTime(2100),
|
||||
);
|
||||
|
||||
if (newSelectedDate != null) {
|
||||
ref.read(eDobDt.notifier).state = newSelectedDate;
|
||||
ref.read(eDobCtr.notifier).state.text =
|
||||
formatDateJiffy(newSelectedDate.toLocal().toString());
|
||||
}
|
||||
}
|
||||
|
||||
// refreshToken Provider
|
||||
ref.listen(noLoginRefreshTokenProvider, (prev, next) async {
|
||||
if (next is NoLoginRefreshTokenStateLoading) {
|
||||
isLoading.value = true;
|
||||
} else if (next is NoLoginRefreshTokenStateError) {
|
||||
isLoading.value = false;
|
||||
// errorMessage.value = next.message;
|
||||
snackbarWidget(
|
||||
context,
|
||||
next.message,
|
||||
snackbarType.error,
|
||||
Duration(seconds: 3),
|
||||
);
|
||||
} else if (next is NoLoginRefreshTokenStateDone) {
|
||||
isLoading.value = false;
|
||||
|
||||
// check proses aksi yg berlangsung
|
||||
if (readProsesAksi == Constant.getRiwayat) {
|
||||
ref.read(noLoginRiwayatScanProvider.notifier).noLoginRiwayatScan(
|
||||
host: host,
|
||||
client_id: client_id,
|
||||
token: token,
|
||||
expire_date: expire_date,
|
||||
);
|
||||
} else if (readProsesAksi == Constant.postEditScan) {
|
||||
ref.read(noLoginEditScanProvider.notifier).editScan(
|
||||
token: token,
|
||||
host: host,
|
||||
client_id: client_id,
|
||||
Person_ID: selectedPersonId,
|
||||
Person_NIK: ref.read(eNikCtr).text,
|
||||
Person_Name: ref.read(eNamaCtr).text,
|
||||
Person_Dob: ref.read(eDobCtr).text,
|
||||
Person_Sex: ref.read(eSexSelected).M_SexID,
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// void getRiwayat
|
||||
void getRiwayat() async {
|
||||
if (await isTokenExpired() == true) {
|
||||
ref.read(noLoginprosesAksi.notifier).state = Constant.getRiwayat;
|
||||
print("Token expired, refreshing...");
|
||||
ref.read(noLoginRefreshTokenProvider.notifier).refreshToken(
|
||||
client_id: client_id,
|
||||
host: host,
|
||||
expire_date: expire_date,
|
||||
);
|
||||
} else {
|
||||
ref.read(noLoginRiwayatScanProvider.notifier).noLoginRiwayatScan(
|
||||
host: host,
|
||||
client_id: client_id,
|
||||
token: token,
|
||||
expire_date: expire_date,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// listRiwayProvider
|
||||
ref.listen(noLoginRiwayatScanProvider, (prev, next) async {
|
||||
if (next is NoLoginRiwayatScanStateLoading) {
|
||||
isLoading.value = true;
|
||||
} else if (next is NoLoginRiwayatScanStateError) {
|
||||
isLoading.value = false;
|
||||
// errorMessage.value = next.message;
|
||||
snackbarWidget(
|
||||
context,
|
||||
next.message,
|
||||
snackbarType.error,
|
||||
Duration(seconds: 3),
|
||||
);
|
||||
} else if (next is NoLoginRiwayatScanStateDone) {
|
||||
// isLoading.value = false;
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).pushNamedAndRemoveUntil(
|
||||
noLoginHomeRoute,
|
||||
(route) => false,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// proses edit
|
||||
ref.listen(noLoginEditScanProvider, (prev, next) {
|
||||
if (next is NoLoginEditScanStateLoading) {
|
||||
isLoading.value = true;
|
||||
} else if (next is NoLoginEditScanStateError) {
|
||||
isLoading.value = false;
|
||||
// errorMessage.value = next.message;
|
||||
snackbarWidget(
|
||||
context,
|
||||
next.message,
|
||||
snackbarType.error,
|
||||
Duration(seconds: 3),
|
||||
);
|
||||
} else if (next is NoLoginEditScanStateDone) {
|
||||
isLoading.value = false;
|
||||
getRiwayat();
|
||||
}
|
||||
});
|
||||
|
||||
void postEdit() async {
|
||||
if (await isTokenExpired() == true) {
|
||||
ref.read(noLoginprosesAksi.notifier).state = Constant.postEditScan;
|
||||
print("Token expired, refreshing...");
|
||||
ref.read(noLoginRefreshTokenProvider.notifier).refreshToken(
|
||||
client_id: client_id,
|
||||
host: host,
|
||||
expire_date: expire_date,
|
||||
);
|
||||
} else {
|
||||
ref.read(noLoginEditScanProvider.notifier).editScan(
|
||||
token: token,
|
||||
host: host,
|
||||
client_id: client_id,
|
||||
Person_ID: selectedPersonId,
|
||||
Person_NIK: ref.read(eNikCtr).text,
|
||||
Person_Name: ref.read(eNamaCtr).text,
|
||||
Person_Dob: ref.read(eDobCtr).text,
|
||||
Person_Sex: ref.read(eSexSelected).M_SexID,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
FocusManager.instance.primaryFocus!.unfocus();
|
||||
},
|
||||
child: Scaffold(
|
||||
resizeToAvoidBottomInset: true,
|
||||
backgroundColor: Constant.bgGrey,
|
||||
body: ListView(
|
||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// atas
|
||||
Image.asset(
|
||||
'images/vektoratas.png',
|
||||
width: double.infinity,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
SizedBox(
|
||||
height: Constant.getActualYPhone(
|
||||
context: context,
|
||||
y: 34,
|
||||
),
|
||||
),
|
||||
// image ktp
|
||||
Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: Constant.getActualYPhone(context: context, y: 12),
|
||||
right: Constant.getActualYPhone(context: context, y: 12),
|
||||
),
|
||||
child: Image.network(
|
||||
baseUrl + listDataEdit.personUrl,
|
||||
fit: BoxFit.fitWidth,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: Constant.getActualYPhone(
|
||||
context: context,
|
||||
y: 32,
|
||||
),
|
||||
),
|
||||
// inputan qrcode
|
||||
Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: Constant.getActualYPhone(context: context, y: 12),
|
||||
right: Constant.getActualYPhone(context: context, y: 12),
|
||||
),
|
||||
child: Text(
|
||||
'QR Code',
|
||||
style: Constant.title_400(context: context).copyWith(
|
||||
color: Constant.inputanGrey,
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: Constant.getActualYPhone(
|
||||
context: context,
|
||||
y: 16,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: Constant.getActualYPhone(context: context, y: 12),
|
||||
right: Constant.getActualYPhone(context: context, y: 12),
|
||||
),
|
||||
child: TextField(
|
||||
readOnly: true,
|
||||
maxLines: 2,
|
||||
controller: ref.read(eQrCode),
|
||||
decoration: InputDecoration(
|
||||
// hintText: "NIK",
|
||||
enabledBorder: const OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Colors.grey,
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
focusedBorder: const OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Colors.blue,
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: Constant.getActualYPhone(
|
||||
context: context,
|
||||
y: 16,
|
||||
),
|
||||
),
|
||||
// inputan nik
|
||||
Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: Constant.getActualYPhone(context: context, y: 12),
|
||||
right: Constant.getActualYPhone(context: context, y: 12),
|
||||
),
|
||||
child: Text(
|
||||
'NIK',
|
||||
style: Constant.title_400(context: context).copyWith(
|
||||
color: Constant.inputanGrey,
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: Constant.getActualYPhone(
|
||||
context: context,
|
||||
y: 16,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: Constant.getActualYPhone(context: context, y: 12),
|
||||
right: Constant.getActualYPhone(context: context, y: 12),
|
||||
),
|
||||
child: TextField(
|
||||
controller: ref.read(eNikCtr),
|
||||
keyboardType: TextInputType.number,
|
||||
decoration: InputDecoration(
|
||||
// hintText: "NIK",
|
||||
enabledBorder: const OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Colors.grey,
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
focusedBorder: const OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Colors.blue,
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: Constant.getActualYPhone(
|
||||
context: context,
|
||||
y: 16,
|
||||
),
|
||||
),
|
||||
|
||||
// inputan nama
|
||||
Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: Constant.getActualYPhone(context: context, y: 12),
|
||||
right: Constant.getActualYPhone(context: context, y: 12),
|
||||
),
|
||||
child: Text(
|
||||
'Nama',
|
||||
style: Constant.title_400(context: context).copyWith(
|
||||
color: Constant.inputanGrey,
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: Constant.getActualYPhone(
|
||||
context: context,
|
||||
y: 16,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: Constant.getActualYPhone(context: context, y: 12),
|
||||
right: Constant.getActualYPhone(context: context, y: 12),
|
||||
),
|
||||
child: TextField(
|
||||
controller: ref.read(eNamaCtr),
|
||||
decoration: InputDecoration(
|
||||
// hintText: "NIK",
|
||||
enabledBorder: const OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Colors.grey,
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
focusedBorder: const OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Colors.blue,
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: Constant.getActualYPhone(
|
||||
context: context,
|
||||
y: 16,
|
||||
),
|
||||
),
|
||||
// inputan dob
|
||||
Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: Constant.getActualYPhone(context: context, y: 12),
|
||||
right: Constant.getActualYPhone(context: context, y: 12),
|
||||
),
|
||||
child: Text(
|
||||
'DOB',
|
||||
style: Constant.title_400(context: context).copyWith(
|
||||
color: Constant.inputanGrey,
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: Constant.getActualYPhone(
|
||||
context: context,
|
||||
y: 16,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: Constant.getActualYPhone(context: context, y: 12),
|
||||
right: Constant.getActualYPhone(context: context, y: 12),
|
||||
),
|
||||
child: TextField(
|
||||
readOnly: true,
|
||||
controller: ref.read(eDobCtr),
|
||||
onTap: () {
|
||||
_selectDate(context, ref);
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
// hintText: "NIK",
|
||||
suffixIcon: IconButton(
|
||||
icon: Icon(Icons.calendar_today,
|
||||
color: Constant.textCardGrey),
|
||||
onPressed: () {
|
||||
_selectDate(context, ref);
|
||||
},
|
||||
),
|
||||
enabledBorder: const OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Colors.grey,
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
focusedBorder: const OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Colors.blue,
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: Constant.getActualYPhone(
|
||||
context: context,
|
||||
y: 16,
|
||||
),
|
||||
),
|
||||
// inputan jenis kelamin
|
||||
Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: Constant.getActualYPhone(context: context, y: 12),
|
||||
right: Constant.getActualYPhone(context: context, y: 12),
|
||||
),
|
||||
child: Text(
|
||||
'Jenis Kelamin',
|
||||
style: Constant.title_400(context: context).copyWith(
|
||||
color: Constant.inputanGrey,
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: Constant.getActualYPhone(
|
||||
context: context,
|
||||
y: 16,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: Constant.getActualYPhone(context: context, y: 12),
|
||||
right: Constant.getActualYPhone(context: context, y: 12),
|
||||
),
|
||||
child: DropdownButtonHideUnderline(
|
||||
child: DropdownButton2<NoLoginSexModel>(
|
||||
isExpanded: true,
|
||||
value: (listSex.value.isNotEmpty)
|
||||
? listSex.value.firstWhere(
|
||||
(sex) =>
|
||||
sex.M_SexID ==
|
||||
ref.read(eSexSelected.notifier).state.M_SexID,
|
||||
orElse: () => listSex.value[0],
|
||||
)
|
||||
: null,
|
||||
items: listSex.value.map((NoLoginSexModel g) {
|
||||
return DropdownMenuItem<NoLoginSexModel>(
|
||||
value: g,
|
||||
child: Text(
|
||||
g.m_sexname,
|
||||
style: Constant.title_400(context: context).copyWith(
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.normal,
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
onChanged: (NoLoginSexModel? value) {
|
||||
if (value != null) {
|
||||
ref.read(eSexSelected.notifier).state = value;
|
||||
ref.read(eSexCtr.notifier).state = TextEditingController(
|
||||
text: value.m_sexname,
|
||||
);
|
||||
FocusScope.of(context).unfocus();
|
||||
}
|
||||
},
|
||||
buttonStyleData: ButtonStyleData(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
border: Border.all(color: Colors.grey),
|
||||
),
|
||||
padding: EdgeInsets.symmetric(horizontal: 12),
|
||||
width: double.infinity,
|
||||
),
|
||||
dropdownStyleData: DropdownStyleData(
|
||||
maxHeight: 100,
|
||||
width: MediaQuery.of(context).size.width - 20,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
color: Colors.white,
|
||||
),
|
||||
offset: Offset(0, 2),
|
||||
),
|
||||
menuItemStyleData: MenuItemStyleData(
|
||||
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||
),
|
||||
onMenuStateChange: (isOpen) {
|
||||
if (!isOpen) {
|
||||
ref.read(eSexCtr).clear();
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: Constant.getActualYPhone(
|
||||
context: context,
|
||||
y: 44,
|
||||
),
|
||||
),
|
||||
// button save
|
||||
Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: Constant.getActualXPhone(
|
||||
context: context,
|
||||
x: 16,
|
||||
),
|
||||
right: Constant.getActualXPhone(
|
||||
context: context,
|
||||
x: 16,
|
||||
),
|
||||
),
|
||||
child: SizedBox(
|
||||
width: double.infinity,
|
||||
height: Constant.getActualYPhone(
|
||||
context: context,
|
||||
y: 48,
|
||||
),
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
postEdit();
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Constant.bgButton,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
elevation: 8,
|
||||
shadowColor: Constant.bgButton.withOpacity(0.24),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
'SAVE',
|
||||
style:
|
||||
Constant.titleButton500(context: context).copyWith(
|
||||
color: Constant.textWhite,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: Constant.getActualYPhone(
|
||||
context: context,
|
||||
y: 70,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -7,15 +7,17 @@ import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:image/image.dart' as img;
|
||||
import 'package:mobile_scanner/mobile_scanner.dart';
|
||||
import 'package:scanktpflutter/model/no-login/no_login_edit_person_ktp_model.dart';
|
||||
import 'package:scanktpflutter/model/no-login/no_login_sex_model.dart';
|
||||
import '../../app/app_extension.dart';
|
||||
import '../../app/route.dart';
|
||||
|
||||
import '../../app/constant.dart';
|
||||
import '../../model/edit_person_model.dart';
|
||||
import '../../model/sex_model.dart';
|
||||
import '../../provider/current_user_provider.dart';
|
||||
import '../../provider/no-login-scan/no_login_scan_provider.dart';
|
||||
import '../../provider/no-login/no_login_current_user_provider.dart';
|
||||
import '../../widget/customsnackbarwidget.dart';
|
||||
import '../home/list_riwayat_scan_provider.dart';
|
||||
import '../no-login-home/no_login_riwayat_scan_provider.dart';
|
||||
import '../no-login/no_login_refresh_token_provider.dart';
|
||||
import 'no_login_upload_scan_provider.dart';
|
||||
|
||||
class NoLoginScanScreen extends HookConsumerWidget {
|
||||
@@ -43,11 +45,40 @@ class NoLoginScanScreen extends HookConsumerWidget {
|
||||
final croppedImage = useState<File?>(null);
|
||||
final isLoading = useState<bool>(false);
|
||||
final isLoadingUpload = useState<bool>(false);
|
||||
final currentUser = ref.watch(currentUserProvider);
|
||||
|
||||
// auth
|
||||
final currentUser = ref.watch(noLoginCurrentUserProvider);
|
||||
final host = currentUser?.host ?? "";
|
||||
final userId = currentUser?.model.userId ?? "";
|
||||
final client_id = currentUser?.client_id ?? "";
|
||||
final expire_date = currentUser?.expire_date ?? "";
|
||||
final token = currentUser?.token ?? "";
|
||||
final selectedResolution =
|
||||
useState<ResolutionPreset>(ResolutionPreset.medium);
|
||||
final readProsesAksi = ref.watch(noLoginprosesAksi);
|
||||
final base64Post = useState("");
|
||||
|
||||
useEffect(() {
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
|
||||
if (client_id == "0" || token == "") {
|
||||
// not logged in and doesn't have token
|
||||
Navigator.of(context)
|
||||
.pushNamedAndRemoveUntil(noLoginRoute, (route) => false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (token != "") {
|
||||
if (await isTokenExpired() == true) {
|
||||
print("Token expired, refreshing...");
|
||||
ref.read(noLoginRefreshTokenProvider.notifier).refreshToken(
|
||||
client_id: client_id,
|
||||
host: host,
|
||||
expire_date: expire_date,
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
return () {};
|
||||
}, [currentUser]);
|
||||
|
||||
Future<void> initializeCamera() async {
|
||||
try {
|
||||
@@ -85,13 +116,13 @@ class NoLoginScanScreen extends HookConsumerWidget {
|
||||
if (loadingScreen.value) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: (cameraOn.value == false)
|
||||
title: (judulTombol.value == "SCAN")
|
||||
? Text(
|
||||
judulAppBar.value,
|
||||
judulPosisiHp.value,
|
||||
style: Constant.titlePosisiHP(context: context),
|
||||
)
|
||||
: Text(
|
||||
judulPosisiHp.value,
|
||||
judulAppBar.value,
|
||||
style: Constant.titlePosisiHP(context: context),
|
||||
),
|
||||
automaticallyImplyLeading: false,
|
||||
@@ -204,6 +235,54 @@ class NoLoginScanScreen extends HookConsumerWidget {
|
||||
return () {};
|
||||
}, []);
|
||||
|
||||
// void getRiwayat
|
||||
void getRiwayat() async {
|
||||
if (await isTokenExpired() == true) {
|
||||
ref.read(noLoginprosesAksi.notifier).state = Constant.getRiwayat;
|
||||
print("Token expired, refreshing...");
|
||||
ref.read(noLoginRefreshTokenProvider.notifier).refreshToken(
|
||||
client_id: client_id,
|
||||
host: host,
|
||||
expire_date: expire_date,
|
||||
);
|
||||
} else {
|
||||
ref.read(noLoginRiwayatScanProvider.notifier).noLoginRiwayatScan(
|
||||
host: host,
|
||||
client_id: client_id,
|
||||
token: token,
|
||||
expire_date: expire_date,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// void prosesUpload
|
||||
void prosesUpload() async {
|
||||
print("Token expired, refreshing...");
|
||||
print("client_id : $client_id");
|
||||
print("host : $host");
|
||||
print("expire_date : $expire_date");
|
||||
print("token : $token");
|
||||
print("qrCodeStr.value : ${qrCodeStr.value}");
|
||||
|
||||
if (await isTokenExpired() == true) {
|
||||
ref.read(noLoginprosesAksi.notifier).state = Constant.postUploadFoto;
|
||||
print("Token expired, refreshing...");
|
||||
ref.read(noLoginRefreshTokenProvider.notifier).refreshToken(
|
||||
client_id: client_id,
|
||||
host: host,
|
||||
expire_date: expire_date,
|
||||
);
|
||||
} else {
|
||||
ref.read(noLoginUploadScanProvider.notifier).uploadScan(
|
||||
host: host,
|
||||
base64File: base64Post.value,
|
||||
client_id: client_id,
|
||||
qr_code: qrCodeStr.value,
|
||||
token: token,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> initializeCameraAfterChangeResolution() async {
|
||||
final cameras = await availableCameras();
|
||||
cameraController.value = CameraController(
|
||||
@@ -290,11 +369,8 @@ class NoLoginScanScreen extends HookConsumerWidget {
|
||||
// post ke BE
|
||||
Uint8List finalBytes = await croppedImage.value!.readAsBytes();
|
||||
String base64String = base64Encode(finalBytes);
|
||||
ref.read(noLoginUploadScanProvider.notifier).uploadScan(
|
||||
host: host,
|
||||
base64File: base64String,
|
||||
userId: userId,
|
||||
);
|
||||
base64Post.value = base64String;
|
||||
prosesUpload();
|
||||
} catch (e) {
|
||||
print("Error capturing image: $e");
|
||||
} finally {
|
||||
@@ -302,12 +378,12 @@ class NoLoginScanScreen extends HookConsumerWidget {
|
||||
}
|
||||
}
|
||||
|
||||
// listRiwayProvider
|
||||
ref.listen(listRiwayatScanProvider, (prev, next) {
|
||||
if (next is ListRiwayatScanStateLoading) {
|
||||
// isLoading.value = true;
|
||||
} else if (next is ListRiwayatScanStateError) {
|
||||
// isLoading.value = false;
|
||||
// refreshToken Provider
|
||||
ref.listen(noLoginRefreshTokenProvider, (prev, next) async {
|
||||
if (next is NoLoginRefreshTokenStateLoading) {
|
||||
isLoading.value = true;
|
||||
} else if (next is NoLoginRefreshTokenStateError) {
|
||||
isLoading.value = false;
|
||||
// errorMessage.value = next.message;
|
||||
snackbarWidget(
|
||||
context,
|
||||
@@ -315,12 +391,47 @@ class NoLoginScanScreen extends HookConsumerWidget {
|
||||
snackbarType.error,
|
||||
Duration(seconds: 3),
|
||||
);
|
||||
} else if (next is ListRiwayatScanStateDone) {
|
||||
// isLoading.value = false;
|
||||
} else if (next is NoLoginRefreshTokenStateDone) {
|
||||
isLoading.value = false;
|
||||
|
||||
// check proses aksi yg berlangsung
|
||||
if (readProsesAksi == Constant.getRiwayat) {
|
||||
ref.read(noLoginRiwayatScanProvider.notifier).noLoginRiwayatScan(
|
||||
host: host,
|
||||
client_id: client_id,
|
||||
token: token,
|
||||
expire_date: expire_date,
|
||||
);
|
||||
} else if (readProsesAksi == Constant.postUploadFoto) {
|
||||
ref.read(noLoginUploadScanProvider.notifier).uploadScan(
|
||||
host: host,
|
||||
base64File: base64Post.value,
|
||||
client_id: client_id,
|
||||
qr_code: qrCodeStr.value,
|
||||
token: token,
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// listRiwayProvider
|
||||
ref.listen(noLoginRiwayatScanProvider, (prev, next) async {
|
||||
if (next is NoLoginRiwayatScanStateLoading) {
|
||||
isLoading.value = true;
|
||||
} else if (next is NoLoginRiwayatScanStateError) {
|
||||
isLoading.value = false;
|
||||
// errorMessage.value = next.message;
|
||||
snackbarWidget(
|
||||
context,
|
||||
next.message,
|
||||
snackbarType.error,
|
||||
Duration(seconds: 3),
|
||||
);
|
||||
} else if (next is NoLoginRiwayatScanStateDone) {
|
||||
// isLoading.value = false;
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).pushNamed(
|
||||
editScanRoute,
|
||||
noLoginEditScanRoute,
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -344,13 +455,13 @@ class NoLoginScanScreen extends HookConsumerWidget {
|
||||
ref.read(selectedPersonIdx.notifier).state = next.model[0].personID;
|
||||
|
||||
// set SEX
|
||||
ref.read(eSexSelected.notifier).state = SexModel(
|
||||
ref.read(eSexSelected.notifier).state = NoLoginSexModel(
|
||||
M_SexID: next.model[0].personSex,
|
||||
M_SexCode: "",
|
||||
m_sexname: next.model[0].m_sexname,
|
||||
M_SexNameLang: "");
|
||||
|
||||
ref.read(selectedEdit.notifier).state = EditPersonModel(
|
||||
ref.read(selectedEdit.notifier).state = NoLoginEditPersonKtpModel(
|
||||
personID: next.model[0].personID,
|
||||
personNIK: next.model[0].personNIK,
|
||||
personName: next.model[0].personName,
|
||||
@@ -358,12 +469,9 @@ class NoLoginScanScreen extends HookConsumerWidget {
|
||||
personDob: next.model[0].personDob,
|
||||
personSex: next.model[0].personSex,
|
||||
personUrl: next.model[0].personUrl,
|
||||
personQrCode: next.model[0].personQrCode,
|
||||
);
|
||||
|
||||
ref.read(listRiwayatScanProvider.notifier).listRiwayatScan(
|
||||
host: host,
|
||||
userId: userId,
|
||||
);
|
||||
getRiwayat();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -384,7 +492,7 @@ class NoLoginScanScreen extends HookConsumerWidget {
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: (cameraOn.value == false)
|
||||
title: (cameraOrScanner.value == "SCAN")
|
||||
? Text(
|
||||
judulAppBar.value,
|
||||
style: Constant.titlePosisiHP(context: context),
|
||||
|
||||
@@ -1,487 +0,0 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'package:camera/camera.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:image/image.dart' as img;
|
||||
import 'package:mobile_scanner/mobile_scanner.dart';
|
||||
import '../../app/route.dart';
|
||||
|
||||
import '../../app/constant.dart';
|
||||
import '../../model/edit_person_model.dart';
|
||||
import '../../model/sex_model.dart';
|
||||
import '../../provider/current_user_provider.dart';
|
||||
import '../../provider/no-login-scan/no_login_scan_provider.dart';
|
||||
import '../../widget/customsnackbarwidget.dart';
|
||||
import '../home/list_riwayat_scan_provider.dart';
|
||||
import 'no_login_upload_scan_provider.dart';
|
||||
|
||||
class NoLoginScanScreen extends HookConsumerWidget {
|
||||
const NoLoginScanScreen({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: [
|
||||
SystemUiOverlay.bottom,
|
||||
]);
|
||||
|
||||
final judulAppBar = useState<String>("Scan QRCode & Scan KTP");
|
||||
final qrCodeExists = useState<bool>(false);
|
||||
final cameraOn = useState<bool>(false);
|
||||
final qrCodeStr = useState<String>("Scan QRCode untuk dapat merekam");
|
||||
final judulTombol = useState<String>("SCAN QR CODE");
|
||||
final awalan = useState("Info :");
|
||||
final judulPosisiHp = useState<String>("Posisi HP Landscape");
|
||||
|
||||
final cameraController = useState<CameraController?>(null);
|
||||
final initializeControllerFuture = useState<Future<void>?>(null);
|
||||
final capturedImage = useState<XFile?>(null);
|
||||
final croppedImage = useState<File?>(null);
|
||||
final isLoading = useState<bool>(false);
|
||||
final isLoadingUpload = useState<bool>(false);
|
||||
final currentUser = ref.watch(currentUserProvider);
|
||||
final host = currentUser?.host ?? "";
|
||||
final userId = currentUser?.model.userId ?? "";
|
||||
final selectedResolution =
|
||||
useState<ResolutionPreset>(ResolutionPreset.medium);
|
||||
|
||||
void handleBarcode(BarcodeCapture barcodes) {
|
||||
if (barcodes.barcodes.isNotEmpty) {
|
||||
final scannedBarcode =
|
||||
barcodes.barcodes.firstOrNull?.displayValue ?? "";
|
||||
if (scannedBarcode.isNotEmpty) {
|
||||
ref.read(barcodeX.notifier).state = barcodes.barcodes.first;
|
||||
qrCodeStr.value = scannedBarcode;
|
||||
awalan.value = "QrCode : ";
|
||||
qrCodeExists.value = true;
|
||||
cameraOn.value = true;
|
||||
judulTombol.value = "FOTO";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() {
|
||||
Future<void> initializeCamera() async {
|
||||
final cameras = await availableCameras();
|
||||
cameraController.value = CameraController(
|
||||
cameras[0],
|
||||
// ResolutionPreset.max,
|
||||
// ResolutionPreset.medium,
|
||||
selectedResolution.value);
|
||||
initializeControllerFuture.value = cameraController.value!.initialize();
|
||||
await initializeControllerFuture.value;
|
||||
await cameraController.value!.setFlashMode(FlashMode.off);
|
||||
}
|
||||
|
||||
initializeCamera();
|
||||
return null;
|
||||
}, []);
|
||||
|
||||
Future<void> initializeCameraAfterChangeResolution() async {
|
||||
final cameras = await availableCameras();
|
||||
cameraController.value = CameraController(
|
||||
cameras[0],
|
||||
// ResolutionPreset.max,
|
||||
// ResolutionPreset.medium,
|
||||
selectedResolution.value);
|
||||
initializeControllerFuture.value = cameraController.value!.initialize();
|
||||
await initializeControllerFuture.value;
|
||||
await cameraController.value!.setFlashMode(FlashMode.off);
|
||||
}
|
||||
|
||||
Future<File> rotateAndCropImage(File imageFile) async {
|
||||
Uint8List imageBytes = await imageFile.readAsBytes();
|
||||
img.Image? original = img.decodeImage(imageBytes);
|
||||
if (original == null) return imageFile;
|
||||
|
||||
img.Image rotated = img.bakeOrientation(original);
|
||||
|
||||
int width = rotated.width;
|
||||
int height = rotated.height;
|
||||
bool isPortrait = height > width;
|
||||
|
||||
int cropWidth, cropHeight;
|
||||
|
||||
if (isPortrait) {
|
||||
cropHeight = (height * 0.7).toInt();
|
||||
cropWidth = (cropHeight ~/ 1.59).toInt();
|
||||
} else {
|
||||
cropWidth = (width * 0.7).toInt();
|
||||
cropHeight = (cropWidth ~/ 1.59).toInt();
|
||||
}
|
||||
|
||||
int left = ((width - cropWidth) ~/ 2).toInt();
|
||||
int top = ((height - cropHeight) ~/ 2).toInt();
|
||||
|
||||
img.Image cropped = img.copyCrop(rotated,
|
||||
x: left, y: top, width: cropWidth, height: cropHeight);
|
||||
|
||||
File croppedFile = File('${imageFile.path}_cropped.jpg');
|
||||
await croppedFile.writeAsBytes(img.encodeJpg(cropped));
|
||||
|
||||
return croppedFile;
|
||||
}
|
||||
|
||||
Future<File> rotateImage(File imageFile) async {
|
||||
Uint8List bytes = await imageFile.readAsBytes();
|
||||
img.Image? image = img.decodeImage(bytes);
|
||||
|
||||
if (image == null) return imageFile;
|
||||
|
||||
img.Image rotated = img.copyRotate(image, angle: -90);
|
||||
|
||||
File rotatedFile = File('${imageFile.path}_rotated.jpg');
|
||||
await rotatedFile.writeAsBytes(img.encodeJpg(rotated));
|
||||
|
||||
return rotatedFile;
|
||||
}
|
||||
|
||||
Future<void> captureAndCropImage() async {
|
||||
try {
|
||||
isLoading.value = true;
|
||||
await initializeControllerFuture.value;
|
||||
|
||||
// Ambil gambar dari kamera
|
||||
final image = await cameraController.value!.takePicture();
|
||||
File cropped = await rotateAndCropImage(File(image.path));
|
||||
|
||||
// Rotate gambar setelah cropping
|
||||
File rotatedImage = await rotateImage(cropped);
|
||||
|
||||
// Convert to grayscale
|
||||
Uint8List bytes = await rotatedImage.readAsBytes();
|
||||
img.Image? coloredImage = img.decodeImage(bytes);
|
||||
if (coloredImage != null) {
|
||||
img.Image grayscaleImage = img.grayscale(coloredImage);
|
||||
rotatedImage.writeAsBytesSync(img.encodeJpg(grayscaleImage));
|
||||
}
|
||||
|
||||
// Simpan hasil yang sudah di-crop dan di-rotate
|
||||
capturedImage.value = image;
|
||||
croppedImage.value = rotatedImage;
|
||||
|
||||
// post ke BE
|
||||
Uint8List finalBytes = await croppedImage.value!.readAsBytes();
|
||||
String base64String = base64Encode(finalBytes);
|
||||
ref.read(noLoginUploadScanProvider.notifier).uploadScan(
|
||||
host: host,
|
||||
base64File: base64String,
|
||||
userId: userId,
|
||||
);
|
||||
} catch (e) {
|
||||
print("Error capturing image: $e");
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// listRiwayProvider
|
||||
ref.listen(listRiwayatScanProvider, (prev, next) {
|
||||
if (next is ListRiwayatScanStateLoading) {
|
||||
// isLoading.value = true;
|
||||
} else if (next is ListRiwayatScanStateError) {
|
||||
// isLoading.value = false;
|
||||
// errorMessage.value = next.message;
|
||||
snackbarWidget(
|
||||
context,
|
||||
next.message,
|
||||
snackbarType.error,
|
||||
Duration(seconds: 3),
|
||||
);
|
||||
} else if (next is ListRiwayatScanStateDone) {
|
||||
// isLoading.value = false;
|
||||
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).pushNamed(
|
||||
editScanRoute,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// proses upload
|
||||
ref.listen(noLoginUploadScanProvider, (prev, next) {
|
||||
if (next is NoLoginUploadScanStateLoading) {
|
||||
isLoadingUpload.value = true;
|
||||
} else if (next is NoLoginUploadScanStateError) {
|
||||
isLoadingUpload.value = false;
|
||||
// errorMessage.value = next.message;
|
||||
print("Err : ${next.message}");
|
||||
snackbarWidget(
|
||||
context,
|
||||
next.message,
|
||||
snackbarType.error,
|
||||
Duration(seconds: 3),
|
||||
);
|
||||
} else if (next is NoLoginUploadScanStateDone) {
|
||||
isLoadingUpload.value = false;
|
||||
ref.read(selectedPersonIdx.notifier).state = next.model[0].personID;
|
||||
|
||||
// set SEX
|
||||
ref.read(eSexSelected.notifier).state = SexModel(
|
||||
M_SexID: next.model[0].personSex,
|
||||
M_SexCode: "",
|
||||
m_sexname: next.model[0].m_sexname,
|
||||
M_SexNameLang: "");
|
||||
|
||||
ref.read(selectedEdit.notifier).state = EditPersonModel(
|
||||
personID: next.model[0].personID,
|
||||
personNIK: next.model[0].personNIK,
|
||||
personName: next.model[0].personName,
|
||||
m_sexname: next.model[0].m_sexname,
|
||||
personDob: next.model[0].personDob,
|
||||
personSex: next.model[0].personSex,
|
||||
personUrl: next.model[0].personUrl,
|
||||
);
|
||||
|
||||
ref.read(listRiwayatScanProvider.notifier).listRiwayatScan(
|
||||
host: host,
|
||||
userId: userId,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// loading proses upload useEffect
|
||||
useEffect(() {
|
||||
WidgetsBinding.instance.addPostFrameCallback((timestamp) {
|
||||
if (isLoadingUpload.value == true) {
|
||||
snackbarWidget(
|
||||
context,
|
||||
'Sedang Upload Foto...',
|
||||
snackbarType.warning,
|
||||
Duration(seconds: 3),
|
||||
);
|
||||
}
|
||||
});
|
||||
return () {};
|
||||
}, [isLoadingUpload.value]);
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(
|
||||
judulAppBar.value,
|
||||
style: Constant.titlePosisiHP(context: context),
|
||||
),
|
||||
automaticallyImplyLeading: false,
|
||||
actions: [
|
||||
if (cameraOn.value == true)
|
||||
DropdownButton<ResolutionPreset>(
|
||||
value: selectedResolution.value,
|
||||
onChanged: (ResolutionPreset? newValue) {
|
||||
if (newValue != null) {
|
||||
selectedResolution.value = newValue;
|
||||
initializeCameraAfterChangeResolution();
|
||||
}
|
||||
},
|
||||
items: ResolutionPreset.values.map((ResolutionPreset value) {
|
||||
return DropdownMenuItem<ResolutionPreset>(
|
||||
value: value,
|
||||
child: Text(value.toString().split('.').last),
|
||||
);
|
||||
}).toList(),
|
||||
underline: SizedBox.shrink(),
|
||||
),
|
||||
],
|
||||
),
|
||||
backgroundColor: Colors.black.withOpacity(0.5),
|
||||
body: Stack(
|
||||
children: [
|
||||
if (awalan.value == "Info :")
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
height: Constant.getActualYPhone(
|
||||
context: context,
|
||||
y: 450,
|
||||
),
|
||||
child: MobileScanner(
|
||||
onDetect: handleBarcode,
|
||||
),
|
||||
),
|
||||
// Show Qr code Str
|
||||
// Container(
|
||||
// alignment: Alignment.center,
|
||||
// padding: EdgeInsets.symmetric(vertical: 10),
|
||||
// color: Constant.inputanGrey,
|
||||
// child: Text(
|
||||
// "${awalan.value} ${qrCodeStr.value}",
|
||||
// style: TextStyle(color: Colors.white),
|
||||
// ),
|
||||
// ),
|
||||
// jika camera scan ktp true show
|
||||
if (cameraOn.value == true) ...[
|
||||
SizedBox(
|
||||
height: Constant.getActualYPhone(
|
||||
context: context,
|
||||
y: 20,
|
||||
),
|
||||
),
|
||||
// show notif posisi HP
|
||||
Container(
|
||||
alignment: Alignment.center,
|
||||
padding: EdgeInsets.symmetric(vertical: 10),
|
||||
color: Constant.textRed,
|
||||
child: Text(
|
||||
judulPosisiHp.value,
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: Constant.getActualYPhone(
|
||||
context: context,
|
||||
y: 20,
|
||||
),
|
||||
),
|
||||
if (cameraController.value != null && croppedImage.value == null)
|
||||
FutureBuilder<void>(
|
||||
future: initializeControllerFuture.value,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done) {
|
||||
return CameraPreview(cameraController.value!);
|
||||
} else {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
|
||||
// jika sudah ada foto
|
||||
if (croppedImage.value != null) ...[
|
||||
Container(
|
||||
width: double.infinity,
|
||||
height: 300,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: Image.file(
|
||||
croppedImage.value!,
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
),
|
||||
),
|
||||
] else ...[
|
||||
// bingkai foto
|
||||
Positioned.fill(
|
||||
child: CustomPaint(
|
||||
painter: OverlayPainter(),
|
||||
),
|
||||
),
|
||||
],
|
||||
// loading
|
||||
if (isLoading.value)
|
||||
Positioned.fill(
|
||||
child: Container(
|
||||
color: Colors.black.withOpacity(0.5),
|
||||
child: const Center(
|
||||
child: CircularProgressIndicator(
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
bottomNavigationBar: BottomAppBar(
|
||||
height: Constant.getActualYPhone(
|
||||
context: context,
|
||||
y: 100,
|
||||
),
|
||||
shape: const CircularNotchedRectangle(),
|
||||
child: Row(
|
||||
children: [
|
||||
ElevatedButton.icon(
|
||||
onPressed: () {
|
||||
capturedImage.value = null;
|
||||
croppedImage.value = null;
|
||||
|
||||
ref.read(barcodeX.notifier).state = Barcode();
|
||||
qrCodeExists.value = false;
|
||||
judulTombol.value = "SCAN QR CODE";
|
||||
qrCodeStr.value = "Scan QRCode untuk dapat merekam";
|
||||
cameraOn.value = false;
|
||||
awalan.value = "Info :";
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.arrow_back,
|
||||
size: 17,
|
||||
color: Constant.textWhite,
|
||||
),
|
||||
label: Text(
|
||||
'Kembali',
|
||||
style: Constant.cardText(context: context).copyWith(
|
||||
color: Constant.textWhite,
|
||||
),
|
||||
),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Constant.textCardGrey,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
elevation: 8,
|
||||
shadowColor: Constant.bgButton.withOpacity(0.24),
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
// scan
|
||||
ElevatedButton.icon(
|
||||
onPressed: captureAndCropImage,
|
||||
icon: Icon(
|
||||
Icons.camera,
|
||||
size: 17,
|
||||
color: Constant.textWhite,
|
||||
),
|
||||
label: Text(
|
||||
judulTombol.value,
|
||||
style: Constant.cardText(context: context).copyWith(
|
||||
color: Constant.textWhite,
|
||||
),
|
||||
),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Constant.bgButton,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
elevation: 8,
|
||||
shadowColor: Constant.bgButton.withOpacity(0.24),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class OverlayPainter extends CustomPainter {
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
final paint = Paint()
|
||||
..color = Colors.black.withOpacity(0.6)
|
||||
..style = PaintingStyle.fill;
|
||||
|
||||
final borderPaint = Paint()
|
||||
..color = Colors.yellow
|
||||
..strokeWidth = 4
|
||||
..style = PaintingStyle.stroke;
|
||||
|
||||
double boxHeight = size.height * 0.7;
|
||||
double boxWidth = boxHeight / 1.59;
|
||||
|
||||
double left = (size.width - boxWidth) / 2;
|
||||
double top = (size.height - boxHeight) / 2;
|
||||
|
||||
Path path = Path()
|
||||
..addRect(Rect.fromLTWH(0, 0, size.width, size.height))
|
||||
..addRect(Rect.fromLTWH(left, top, boxWidth, boxHeight))
|
||||
..fillType = PathFillType.evenOdd;
|
||||
|
||||
canvas.drawPath(path, paint);
|
||||
canvas.drawRect(Rect.fromLTWH(left, top, boxWidth, boxHeight), borderPaint);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(CustomPainter oldDelegate) => false;
|
||||
}
|
||||
73
lib/screen/no-login-scan/no_login_sex_provider.dart
Normal file
73
lib/screen/no-login-scan/no_login_sex_provider.dart
Normal file
@@ -0,0 +1,73 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:scanktpflutter/model/no-login/no_login_sex_model.dart';
|
||||
import 'package:scanktpflutter/repository/no-login-scan/no_login_scan_repository.dart';
|
||||
|
||||
import '../../provider/dio_provider.dart';
|
||||
import '../../repository/base_repository.dart';
|
||||
|
||||
// 3. state provider
|
||||
final noLoginSexProvider =
|
||||
StateNotifierProvider<NoLoginSexNotifier, NoLoginSexState>(
|
||||
(ref) => NoLoginSexNotifier(ref: ref));
|
||||
|
||||
// 2. notifier
|
||||
class NoLoginSexNotifier extends StateNotifier<NoLoginSexState> {
|
||||
final Ref ref;
|
||||
NoLoginSexNotifier({required this.ref}) : super(NoLoginSexStateInit());
|
||||
void sex({
|
||||
required String host,
|
||||
required String client_id,
|
||||
required String token,
|
||||
}) async {
|
||||
try {
|
||||
state = NoLoginSexStateLoading();
|
||||
final resp = await NoLoginScanRepository(
|
||||
dio: ref.read(dioProvider),
|
||||
).sexRepo(
|
||||
host: host,
|
||||
client_id: client_id,
|
||||
token: token,
|
||||
);
|
||||
|
||||
// print(resp);
|
||||
state = NoLoginSexStateDone(model: resp);
|
||||
} catch (e) {
|
||||
if (e is BaseRepositoryException) {
|
||||
state = NoLoginSexStateError(message: e.message);
|
||||
} else {
|
||||
state = NoLoginSexStateError(message: e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 1. state
|
||||
abstract class NoLoginSexState extends Equatable {
|
||||
final DateTime date;
|
||||
const NoLoginSexState(this.date);
|
||||
@override
|
||||
List<Object?> get props => [date];
|
||||
}
|
||||
|
||||
class NoLoginSexStateInit extends NoLoginSexState {
|
||||
NoLoginSexStateInit() : super(DateTime.now());
|
||||
}
|
||||
|
||||
class NoLoginSexStateLoading extends NoLoginSexState {
|
||||
NoLoginSexStateLoading() : super(DateTime.now());
|
||||
}
|
||||
|
||||
class NoLoginSexStateError extends NoLoginSexState {
|
||||
final String message;
|
||||
NoLoginSexStateError({
|
||||
required this.message,
|
||||
}) : super(DateTime.now());
|
||||
}
|
||||
|
||||
class NoLoginSexStateDone extends NoLoginSexState {
|
||||
final List<NoLoginSexModel> model;
|
||||
NoLoginSexStateDone({
|
||||
required this.model,
|
||||
}) : super(DateTime.now());
|
||||
}
|
||||
@@ -1,23 +1,27 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import '../../model/no-login/no_login_sukses_person_model.dart';
|
||||
import '../../repository/no-login-scan/no_login_scan_repository.dart';
|
||||
import '../../model/sukses_person_model.dart';
|
||||
|
||||
import '../../provider/dio_provider.dart';
|
||||
import '../../repository/base_repository.dart';
|
||||
|
||||
// 3. state provider
|
||||
final noLoginUploadScanProvider = StateNotifierProvider<NoLoginUploadScanNotifier, NoLoginUploadScanState>(
|
||||
(ref) => NoLoginUploadScanNotifier(ref: ref));
|
||||
final noLoginUploadScanProvider =
|
||||
StateNotifierProvider<NoLoginUploadScanNotifier, NoLoginUploadScanState>(
|
||||
(ref) => NoLoginUploadScanNotifier(ref: ref));
|
||||
|
||||
// 2. notifier
|
||||
class NoLoginUploadScanNotifier extends StateNotifier<NoLoginUploadScanState> {
|
||||
final Ref ref;
|
||||
NoLoginUploadScanNotifier({required this.ref}) : super(NoLoginUploadScanStateInit());
|
||||
NoLoginUploadScanNotifier({required this.ref})
|
||||
: super(NoLoginUploadScanStateInit());
|
||||
void uploadScan({
|
||||
required String host,
|
||||
required String userId,
|
||||
required String client_id,
|
||||
required String base64File,
|
||||
required String qr_code,
|
||||
required String token,
|
||||
}) async {
|
||||
try {
|
||||
state = NoLoginUploadScanStateLoading();
|
||||
@@ -26,7 +30,9 @@ class NoLoginUploadScanNotifier extends StateNotifier<NoLoginUploadScanState> {
|
||||
).prosesScan(
|
||||
host: host,
|
||||
base64File: base64File,
|
||||
userId: userId,
|
||||
client_id: client_id,
|
||||
qr_code: qr_code,
|
||||
token: token,
|
||||
);
|
||||
|
||||
// print(resp);
|
||||
@@ -65,7 +71,7 @@ class NoLoginUploadScanStateError extends NoLoginUploadScanState {
|
||||
}
|
||||
|
||||
class NoLoginUploadScanStateDone extends NoLoginUploadScanState {
|
||||
final List<SuksesPersonModel> model;
|
||||
final List<NoLoginSuksesPersonKtpModel> model;
|
||||
NoLoginUploadScanStateDone({
|
||||
required this.model,
|
||||
}) : super(DateTime.now());
|
||||
|
||||
@@ -5,8 +5,8 @@ import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:scanktpflutter/screen/scan/edit_scan_provider.dart';
|
||||
import '../../model/sex_model.dart';
|
||||
import '../../provider/scan_provider.dart';
|
||||
import '../../screen/scan/sex_provider.dart';
|
||||
import '../../provider/no-login-scan/no_login_scan_provider.dart';
|
||||
import '../../widget/customsnackbarwidget.dart';
|
||||
|
||||
import '../../app/app_extension.dart';
|
||||
|
||||
@@ -12,7 +12,7 @@ import '../../app/constant.dart';
|
||||
import '../../model/edit_person_model.dart';
|
||||
import '../../model/sex_model.dart';
|
||||
import '../../provider/current_user_provider.dart';
|
||||
import '../../provider/no-login-scan/no_login_scan_provider.dart';
|
||||
import '../../provider/scan_provider.dart';
|
||||
import '../../widget/customsnackbarwidget.dart';
|
||||
import '../home/list_riwayat_scan_provider.dart';
|
||||
import 'upload_scan_provider.dart';
|
||||
|
||||
Reference in New Issue
Block a user