Compare commits
5 Commits
f4df67fe7f
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7d1e528546 | ||
|
|
eb7236671e | ||
|
|
3790e9e11a | ||
|
|
c23e68de36 | ||
|
|
d35ca7ab8b |
BIN
images/btn_approval.png
Normal file
BIN
images/btn_approval.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.4 KiB |
@@ -171,4 +171,47 @@ class Constant {
|
|||||||
fontFamily: 'Quicksand',
|
fontFamily: 'Quicksand',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static TextStyle title_screen({required BuildContext context}) {
|
||||||
|
return TextStyle(
|
||||||
|
fontSize: Constant.getActualYPhone(context: context, y: 24),
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
fontFamily: 'Public Sans',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static TextStyle body_16({required BuildContext context}) {
|
||||||
|
return TextStyle(
|
||||||
|
fontSize: Constant.getActualYPhone(context: context, y: 16),
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
fontFamily: 'Public Sans',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static TextStyle body_14({required BuildContext context}) {
|
||||||
|
return TextStyle(
|
||||||
|
fontSize: Constant.getActualYPhone(context: context, y: 14),
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
fontFamily: 'Public Sans',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static TextStyle body_12({required BuildContext context}) {
|
||||||
|
return TextStyle(
|
||||||
|
fontSize: Constant.getActualYPhone(context: context, y: 12),
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
fontFamily: 'Public Sans',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Color primaryBlue = const Color(0xff0C53B7);
|
||||||
|
static Color bgBlue = const Color(0xff1890FF).withOpacity(0.16);
|
||||||
|
static Color primaryOrange = const Color(0xffF15A29);
|
||||||
|
static Color bgOrange = const Color(0xffF15A29).withOpacity(0.16);
|
||||||
|
static Color secondaryBlue = const Color(0xff43ADA5);
|
||||||
|
static Color bgSecondaryBlue = const Color(0xff43ADA5).withOpacity(0.16);
|
||||||
|
static Color primaryGreen = const Color(0xff229A16);
|
||||||
|
static Color bgGreen = const Color(0xff54D62C).withOpacity(0.08);
|
||||||
|
static Color primaryRed = const Color(0xffB72136);
|
||||||
|
static Color bgRed = const Color(0xffFF4842).withOpacity(0.08);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import 'package:absensi_sas/screen/approval/approval_screen.dart';
|
||||||
|
import 'package:absensi_sas/screen/approval_detail/approval_detail_screen.dart';
|
||||||
import 'package:absensi_sas/screen/home/home_screen_v1.dart';
|
import 'package:absensi_sas/screen/home/home_screen_v1.dart';
|
||||||
import 'package:absensi_sas/screen/presensi/presensi_screen.dart';
|
import 'package:absensi_sas/screen/presensi/presensi_screen.dart';
|
||||||
import 'package:absensi_sas/screen/presensi/presensi_selfie_screen.dart';
|
import 'package:absensi_sas/screen/presensi/presensi_selfie_screen.dart';
|
||||||
@@ -13,6 +15,8 @@ const testFlutterMapRoute = "/testFlutterMapRoute";
|
|||||||
const homeRoute = "/homeRoute";
|
const homeRoute = "/homeRoute";
|
||||||
const presensiRoute = "/presensiRoute";
|
const presensiRoute = "/presensiRoute";
|
||||||
const presensiSelfieRoute = "/presensiSelfieRoute";
|
const presensiSelfieRoute = "/presensiSelfieRoute";
|
||||||
|
const approvalRoute = "/approvalRoute";
|
||||||
|
const approvalDetailRoute = "/approvalDetailRoute";
|
||||||
|
|
||||||
class AppRoute {
|
class AppRoute {
|
||||||
static Route<dynamic> generateRoute(RouteSettings settings) {
|
static Route<dynamic> generateRoute(RouteSettings settings) {
|
||||||
@@ -81,6 +85,26 @@ class AppRoute {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// approval
|
||||||
|
if (settings.name == approvalRoute) {
|
||||||
|
return MaterialPageRoute(builder: (context) {
|
||||||
|
return MediaQuery(
|
||||||
|
data: MediaQuery.of(context)
|
||||||
|
.copyWith(textScaleFactor: 1.0, padding: EdgeInsets.all(0)),
|
||||||
|
child: ApprovalScreen(),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// approvalDetail
|
||||||
|
if (settings.name == approvalDetailRoute) {
|
||||||
|
return MaterialPageRoute(builder: (context) {
|
||||||
|
return MediaQuery(
|
||||||
|
data: MediaQuery.of(context)
|
||||||
|
.copyWith(textScaleFactor: 1.0, padding: EdgeInsets.all(0)),
|
||||||
|
child: ApprovalDetailScreen(),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return MaterialPageRoute(builder: (context) {
|
return MaterialPageRoute(builder: (context) {
|
||||||
return MediaQuery(
|
return MediaQuery(
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import 'package:absensi_sas/app/constant.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
@@ -43,7 +44,23 @@ class MyApp extends StatelessWidget {
|
|||||||
// ),
|
// ),
|
||||||
theme: ThemeData(
|
theme: ThemeData(
|
||||||
primarySwatch: Colors.orange,
|
primarySwatch: Colors.orange,
|
||||||
|
primaryColor: Constant.textOrange,
|
||||||
|
primaryColorDark: Constant.textOrange,
|
||||||
|
primaryColorLight: Constant.textOrange,
|
||||||
|
colorScheme: Theme.of(context).colorScheme.copyWith(
|
||||||
|
primary: Constant.textOrange,
|
||||||
|
background: Colors.white,
|
||||||
|
surface: Colors.white),
|
||||||
|
// datePickerTheme: DatePickerThemeData(
|
||||||
|
// // backgroundColor: Colors.white,
|
||||||
|
// // headerHeadlineStyle:
|
||||||
|
// // Constant.h3_400(context: context).copyWith(color: Colors.white),
|
||||||
|
// headerBackgroundColor: Constant.textOrange,
|
||||||
|
// headerForegroundColor: Colors.white,
|
||||||
|
// surfaceTintColor: Colors.white,
|
||||||
|
// backgroundColor: Colors.white),
|
||||||
),
|
),
|
||||||
|
|
||||||
// home: TestMap(),
|
// home: TestMap(),
|
||||||
initialRoute: loginRoute,
|
initialRoute: loginRoute,
|
||||||
// initialRoute: presensiSelfieRoute,
|
// initialRoute: presensiSelfieRoute,
|
||||||
|
|||||||
56
lib/model/approval_detail_model.dart
Normal file
56
lib/model/approval_detail_model.dart
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
class ApprovalDetailModel {
|
||||||
|
String? id;
|
||||||
|
String? name;
|
||||||
|
String? nip;
|
||||||
|
String? date;
|
||||||
|
String? time;
|
||||||
|
String? address;
|
||||||
|
double? lat;
|
||||||
|
double? long;
|
||||||
|
String? imagePath;
|
||||||
|
String? statusID;
|
||||||
|
String? statusName;
|
||||||
|
|
||||||
|
ApprovalDetailModel(
|
||||||
|
{this.id,
|
||||||
|
this.name,
|
||||||
|
this.nip,
|
||||||
|
this.date,
|
||||||
|
this.time,
|
||||||
|
this.address,
|
||||||
|
this.lat,
|
||||||
|
this.long,
|
||||||
|
this.imagePath,
|
||||||
|
this.statusID,
|
||||||
|
this.statusName});
|
||||||
|
|
||||||
|
ApprovalDetailModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
id = json['id'];
|
||||||
|
name = json['Name'];
|
||||||
|
nip = json['nip'];
|
||||||
|
date = json['date'];
|
||||||
|
time = json['time'];
|
||||||
|
address = json['address'];
|
||||||
|
lat = json['lat'];
|
||||||
|
long = json['long'];
|
||||||
|
imagePath = json['imagePath'];
|
||||||
|
statusID = json['statusID'];
|
||||||
|
statusName = json['statusName'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||||
|
data['id'] = this.id;
|
||||||
|
data['Name'] = this.name;
|
||||||
|
data['nip'] = this.nip;
|
||||||
|
data['date'] = this.date;
|
||||||
|
data['time'] = this.time;
|
||||||
|
data['address'] = this.address;
|
||||||
|
data['lat'] = this.lat;
|
||||||
|
data['long'] = this.long;
|
||||||
|
data['imagePath'] = this.imagePath;
|
||||||
|
data['statusID'] = this.statusID;
|
||||||
|
data['statusName'] = this.statusName;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
68
lib/model/approval_model.dart
Normal file
68
lib/model/approval_model.dart
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
class ApprovalModel {
|
||||||
|
String? id;
|
||||||
|
String? name;
|
||||||
|
String? date;
|
||||||
|
String? time;
|
||||||
|
String? typename;
|
||||||
|
String? typeID;
|
||||||
|
String? presensiTypeName;
|
||||||
|
String? presensitypeID;
|
||||||
|
String? address;
|
||||||
|
String? reasonType;
|
||||||
|
String? reasontypeID;
|
||||||
|
String? reasonDescription;
|
||||||
|
String? statusID;
|
||||||
|
String? statusName;
|
||||||
|
|
||||||
|
ApprovalModel(
|
||||||
|
{this.id,
|
||||||
|
this.name,
|
||||||
|
this.date,
|
||||||
|
this.time,
|
||||||
|
this.typename,
|
||||||
|
this.typeID,
|
||||||
|
this.presensiTypeName,
|
||||||
|
this.presensitypeID,
|
||||||
|
this.address,
|
||||||
|
this.reasonType,
|
||||||
|
this.reasontypeID,
|
||||||
|
this.reasonDescription,
|
||||||
|
this.statusID,
|
||||||
|
this.statusName});
|
||||||
|
|
||||||
|
ApprovalModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
id = json['id'];
|
||||||
|
name = json['name'];
|
||||||
|
date = json['date'];
|
||||||
|
time = json['time'];
|
||||||
|
typename = json['typename'];
|
||||||
|
typeID = json['typeID'];
|
||||||
|
presensiTypeName = json['presensiTypeName'];
|
||||||
|
presensitypeID = json['presensitypeID'];
|
||||||
|
address = json['address'];
|
||||||
|
reasonType = json['reasonType'];
|
||||||
|
reasontypeID = json['reasontypeID'];
|
||||||
|
reasonDescription = json['reasonDescription'];
|
||||||
|
statusID = json['statusID'];
|
||||||
|
statusName = json['statusName'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||||
|
data['id'] = this.id;
|
||||||
|
data['name'] = this.name;
|
||||||
|
data['date'] = this.date;
|
||||||
|
data['time'] = this.time;
|
||||||
|
data['typename'] = this.typename;
|
||||||
|
data['typeID'] = this.typeID;
|
||||||
|
data['presensiTypeName'] = this.presensiTypeName;
|
||||||
|
data['presensitypeID'] = this.presensitypeID;
|
||||||
|
data['address'] = this.address;
|
||||||
|
data['reasonType'] = this.reasonType;
|
||||||
|
data['reasontypeID'] = this.reasontypeID;
|
||||||
|
data['reasonDescription'] = this.reasonDescription;
|
||||||
|
data['statusID'] = this.statusID;
|
||||||
|
data['statusName'] = this.statusName;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
24
lib/model/approval_type_model.dart
Normal file
24
lib/model/approval_type_model.dart
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
class ApprovalTypeModel {
|
||||||
|
String? id;
|
||||||
|
String? value;
|
||||||
|
String? name;
|
||||||
|
bool? isActive;
|
||||||
|
|
||||||
|
ApprovalTypeModel({this.id, this.value, this.name, this.isActive});
|
||||||
|
|
||||||
|
ApprovalTypeModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
id = json['id'];
|
||||||
|
value = json['value'];
|
||||||
|
name = json['name'];
|
||||||
|
isActive = json['isActive'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||||
|
data['id'] = this.id;
|
||||||
|
data['value'] = this.value;
|
||||||
|
data['name'] = this.name;
|
||||||
|
data['isActive'] = this.isActive;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
28
lib/provider/approval_filter_provider.dart
Normal file
28
lib/provider/approval_filter_provider.dart
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import 'package:absensi_sas/model/approval_type_model.dart';
|
||||||
|
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
|
||||||
|
class ApprovalFilterProvider {
|
||||||
|
DateTime startDate = DateTime.now();
|
||||||
|
DateTime endDate = DateTime.now();
|
||||||
|
String keyword = "";
|
||||||
|
List<String> selectedApprovalType = [];
|
||||||
|
final approvalTypeList = [
|
||||||
|
ApprovalTypeModel(id: "1", name: "Presensi", isActive: false, value: "p"),
|
||||||
|
ApprovalTypeModel(id: "2", name: "Cuti", isActive: true, value: "c"),
|
||||||
|
ApprovalTypeModel(id: "3", name: "Lembur", isActive: false, value: "l"),
|
||||||
|
];
|
||||||
|
ApprovalFilterProvider(
|
||||||
|
{required this.endDate,
|
||||||
|
required this.keyword,
|
||||||
|
required this.selectedApprovalType,
|
||||||
|
required this.startDate});
|
||||||
|
}
|
||||||
|
|
||||||
|
final approvalFilterProvider = StateProvider<ApprovalFilterProvider>((ref) {
|
||||||
|
return ApprovalFilterProvider(
|
||||||
|
selectedApprovalType: [],
|
||||||
|
endDate: DateTime.now(),
|
||||||
|
keyword: "",
|
||||||
|
startDate: DateTime.now());
|
||||||
|
});
|
||||||
158
lib/screen/approval/approval_mockup.dart
Normal file
158
lib/screen/approval/approval_mockup.dart
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
import 'package:absensi_sas/model/approval_detail_model.dart';
|
||||||
|
import 'package:absensi_sas/model/approval_model.dart';
|
||||||
|
|
||||||
|
List<ApprovalModel> approvalCardList = [
|
||||||
|
ApprovalModel(
|
||||||
|
id: "1",
|
||||||
|
name: "Alfianto Andy P",
|
||||||
|
date: "21 Feb 2024",
|
||||||
|
time: "08:03",
|
||||||
|
typeID: "1",
|
||||||
|
typename: "Presensi",
|
||||||
|
presensitypeID: "1",
|
||||||
|
presensiTypeName: "Clock In",
|
||||||
|
address:
|
||||||
|
"Jl. Kwini No.1, RT.5/RW.1, Senen, Kec. Senen, Kota Jakarta Pusat, Daerah Khusus Ibukota Jakarta 10410",
|
||||||
|
statusID: "",
|
||||||
|
statusName: ""),
|
||||||
|
ApprovalModel(
|
||||||
|
id: "1",
|
||||||
|
name: "Alfianto Andy P",
|
||||||
|
date: "21 Feb 2024",
|
||||||
|
time: "08:03",
|
||||||
|
typeID: "1",
|
||||||
|
typename: "Presensi",
|
||||||
|
presensitypeID: "1",
|
||||||
|
presensiTypeName: "Clock In",
|
||||||
|
address:
|
||||||
|
"Jl. Kwini No.1, RT.5/RW.1, Senen, Kec. Senen, Kota Jakarta Pusat, Daerah Khusus Ibukota Jakarta 10410",
|
||||||
|
statusID: "1",
|
||||||
|
statusName: "Approve"),
|
||||||
|
ApprovalModel(
|
||||||
|
id: "2",
|
||||||
|
name: "Alfianto Andy P",
|
||||||
|
date: "21 Feb 2024",
|
||||||
|
time: "17:03",
|
||||||
|
typeID: "1",
|
||||||
|
typename: "Presensi",
|
||||||
|
presensitypeID: "2",
|
||||||
|
presensiTypeName: "Clock Out",
|
||||||
|
address:
|
||||||
|
"Jl. Kwini No.1, RT.5/RW.1, Senen, Kec. Senen, Kota Jakarta Pusat, Daerah Khusus Ibukota Jakarta 10410",
|
||||||
|
statusID: "2",
|
||||||
|
statusName: "Reject"),
|
||||||
|
ApprovalModel(
|
||||||
|
id: "3",
|
||||||
|
name: "Hanan Askarim",
|
||||||
|
date: "06 Jan 2024 - 06 Jan 2024",
|
||||||
|
time: "0",
|
||||||
|
typeID: "2",
|
||||||
|
typename: "Cuti",
|
||||||
|
statusID: "0",
|
||||||
|
reasonType: "Cuti Tahunan",
|
||||||
|
reasonDescription: "Kondangan",
|
||||||
|
reasontypeID: "1",
|
||||||
|
statusName: "0"),
|
||||||
|
ApprovalModel(
|
||||||
|
id: "4",
|
||||||
|
name: "Hanan Askarim",
|
||||||
|
date: "06 Jan 2024 - 06 Jan 2024",
|
||||||
|
time: "0",
|
||||||
|
typeID: "2",
|
||||||
|
typename: "Cuti",
|
||||||
|
statusID: "1",
|
||||||
|
reasonType: "Cuti Tahunan",
|
||||||
|
reasonDescription: "Tidur",
|
||||||
|
reasontypeID: "1",
|
||||||
|
statusName: "Approve"),
|
||||||
|
ApprovalModel(
|
||||||
|
id: "4",
|
||||||
|
name: "Hanan Askarim",
|
||||||
|
date: "06 Jan 2024 - 06 Jan 2024",
|
||||||
|
time: "0",
|
||||||
|
typeID: "2",
|
||||||
|
typename: "Cuti",
|
||||||
|
statusID: "2",
|
||||||
|
reasonType: "Cuti Tahunan",
|
||||||
|
reasonDescription: "Tidur",
|
||||||
|
reasontypeID: "1",
|
||||||
|
statusName: "Reject"),
|
||||||
|
ApprovalModel(
|
||||||
|
id: "5",
|
||||||
|
name: "Stephen Kusumo",
|
||||||
|
date: "06 Jan 2024",
|
||||||
|
time: "17:00 - 19:00",
|
||||||
|
typeID: "3",
|
||||||
|
typename: "Lembur",
|
||||||
|
statusID: "0",
|
||||||
|
reasonType: "0",
|
||||||
|
reasonDescription: "Menyelesaikan project Petty Cash",
|
||||||
|
reasontypeID: "0",
|
||||||
|
statusName: ""),
|
||||||
|
ApprovalModel(
|
||||||
|
id: "5",
|
||||||
|
name: "Stephen Kusumo",
|
||||||
|
date: "06 Jan 2024",
|
||||||
|
time: "17:00 - 19:00",
|
||||||
|
typeID: "3",
|
||||||
|
typename: "Lembur",
|
||||||
|
statusID: "1",
|
||||||
|
reasonType: "0",
|
||||||
|
reasonDescription: "Menyelesaikan project Petty Cash",
|
||||||
|
reasontypeID: "0",
|
||||||
|
statusName: "Approve"),
|
||||||
|
ApprovalModel(
|
||||||
|
id: "5",
|
||||||
|
name: "Stephen Kusumo",
|
||||||
|
date: "06 Jan 2024",
|
||||||
|
time: "17:00 - 19:00",
|
||||||
|
typeID: "3",
|
||||||
|
typename: "Lembur",
|
||||||
|
statusID: "2",
|
||||||
|
reasonType: "0",
|
||||||
|
reasonDescription: "Menyelesaikan project Petty Cash",
|
||||||
|
reasontypeID: "0",
|
||||||
|
statusName: "Reject"),
|
||||||
|
];
|
||||||
|
|
||||||
|
List<ApprovalDetailModel> approvalDetailMockup = [
|
||||||
|
ApprovalDetailModel(
|
||||||
|
id: "1",
|
||||||
|
name: "Alfianto Andy P",
|
||||||
|
address:
|
||||||
|
"Jl. Kwini No.1, RT.5/RW.1, Senen, Kec. Senen, Kota Jakarta Pusat, Daerah Khusus Ibukota Jakarta 10410",
|
||||||
|
date: "06 Feb 2024",
|
||||||
|
time: "08:08",
|
||||||
|
nip: "SS202308",
|
||||||
|
lat: -7.539538,
|
||||||
|
long: 110.798357,
|
||||||
|
imagePath: "https://images4.alphacoders.com/262/262196.jpg",
|
||||||
|
statusID: "1",
|
||||||
|
statusName: "Approve"),
|
||||||
|
ApprovalDetailModel(
|
||||||
|
id: "2",
|
||||||
|
name: "Alfianto Andy P",
|
||||||
|
address:
|
||||||
|
"Jl. Kwini No.1, RT.5/RW.1, Senen, Kec. Senen, Kota Jakarta Pusat, Daerah Khusus Ibukota Jakarta 10410",
|
||||||
|
date: "06 Feb 2024",
|
||||||
|
time: "08:08",
|
||||||
|
nip: "SS202308",
|
||||||
|
lat: -7.539538,
|
||||||
|
long: 110.798357,
|
||||||
|
imagePath: "https://images3.alphacoders.com/147/147465.jpg",
|
||||||
|
statusID: "2",
|
||||||
|
statusName: "Reject"),
|
||||||
|
ApprovalDetailModel(
|
||||||
|
id: "3",
|
||||||
|
name: "Alfianto Andy P",
|
||||||
|
address:
|
||||||
|
"Jl. Kwini No.1, RT.5/RW.1, Senen, Kec. Senen, Kota Jakarta Pusat, Daerah Khusus Ibukota Jakarta 10410",
|
||||||
|
date: "06 Feb 2024",
|
||||||
|
time: "08:08",
|
||||||
|
nip: "SS202308",
|
||||||
|
lat: -7.539538,
|
||||||
|
long: 110.798357,
|
||||||
|
imagePath: "https://images4.alphacoders.com/146/146466.jpg",
|
||||||
|
statusID: "0",
|
||||||
|
statusName: ""),
|
||||||
|
];
|
||||||
159
lib/screen/approval/approval_screen.dart
Normal file
159
lib/screen/approval/approval_screen.dart
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
import 'package:absensi_sas/app/constant.dart';
|
||||||
|
import 'package:absensi_sas/app/route.dart';
|
||||||
|
import 'package:absensi_sas/model/approval_model.dart';
|
||||||
|
|
||||||
|
import 'package:absensi_sas/provider/approval_filter_provider.dart';
|
||||||
|
import 'package:absensi_sas/screen/approval/approval_mockup.dart';
|
||||||
|
import 'package:absensi_sas/screen/approval/widget/approval_card_cuti.dart';
|
||||||
|
import 'package:absensi_sas/screen/approval/widget/approval_card_lembur.dart';
|
||||||
|
import 'package:absensi_sas/screen/approval/widget/approval_card_presensi.dart';
|
||||||
|
import 'package:absensi_sas/screen/approval/widget/approval_filter_chip_widget.dart';
|
||||||
|
import 'package:absensi_sas/screen/approval/widget/approval_filter_widget.dart';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/rendering.dart';
|
||||||
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
|
||||||
|
class ApprovalScreen extends HookConsumerWidget {
|
||||||
|
const ApprovalScreen({super.key});
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final approvalFilterTempProvider = ref.watch(approvalFilterProvider);
|
||||||
|
final approvalTypeList = approvalFilterTempProvider.approvalTypeList;
|
||||||
|
final scrollCtr = useScrollController();
|
||||||
|
|
||||||
|
final List<ApprovalModel> dataMockup = approvalCardList;
|
||||||
|
|
||||||
|
onTap(String tipeID) {
|
||||||
|
if (tipeID == "1") {
|
||||||
|
print("Tipe Id 1");
|
||||||
|
Navigator.pushNamed(context, approvalDetailRoute);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SafeArea(
|
||||||
|
minimum: EdgeInsets.only(
|
||||||
|
top: Constant.getActualYPhone(context: context, y: 30)),
|
||||||
|
child: Scaffold(
|
||||||
|
backgroundColor: Constant.textWhite,
|
||||||
|
appBar: AppBar(
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
shadowColor: Colors.white,
|
||||||
|
surfaceTintColor: Colors.white,
|
||||||
|
scrolledUnderElevation: 0,
|
||||||
|
elevation: 0,
|
||||||
|
leading: Container(
|
||||||
|
child: IconButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
icon: Icon(Icons.arrow_back_ios_new_rounded)),
|
||||||
|
),
|
||||||
|
centerTitle: true,
|
||||||
|
title: Text(
|
||||||
|
"Approval",
|
||||||
|
style: Constant.title_screen(context: context),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
body: Padding(
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: Constant.getActualXPhone(context: context, x: 20)),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
color: Colors.white,
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
ApprovalFilterWidget(),
|
||||||
|
Expanded(
|
||||||
|
child: LayoutBuilder(
|
||||||
|
builder: (context, constraints) {
|
||||||
|
return Container(
|
||||||
|
width: constraints.maxWidth,
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
scrollDirection: Axis.horizontal,
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
...approvalTypeList.map(
|
||||||
|
(e) => ApprovalFilterChipWidget(data: e))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: Constant.getActualYPhone(context: context, y: 27),
|
||||||
|
),
|
||||||
|
Expanded(child: Container(
|
||||||
|
// color: Colors.red,
|
||||||
|
child: LayoutBuilder(builder: (context, Constraints) {
|
||||||
|
return Container(
|
||||||
|
height: Constraints.maxWidth,
|
||||||
|
child: RefreshIndicator(
|
||||||
|
onRefresh: () async {
|
||||||
|
print("Refresh");
|
||||||
|
},
|
||||||
|
child: ListView(
|
||||||
|
controller: scrollCtr,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
margin: EdgeInsets.only(bottom: 28),
|
||||||
|
width: MediaQuery.of(context).size.width,
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
child: Text(
|
||||||
|
"Februari 2024",
|
||||||
|
style: Constant.body_16(context: context)
|
||||||
|
.copyWith(fontWeight: FontWeight.w600),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Container(
|
||||||
|
margin: EdgeInsets.only(left: 10),
|
||||||
|
child: Divider(
|
||||||
|
height: 10,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
...dataMockup.map((e) {
|
||||||
|
switch (e.typeID) {
|
||||||
|
case "1":
|
||||||
|
return ApprovalCardPresensi(
|
||||||
|
data: e,
|
||||||
|
onTap: onTap,
|
||||||
|
);
|
||||||
|
case "2":
|
||||||
|
return ApprovalCardCuti(
|
||||||
|
data: e,
|
||||||
|
);
|
||||||
|
case "3":
|
||||||
|
return ApprovalCardLembur(
|
||||||
|
data: e,
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
}).toList()
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
200
lib/screen/approval/widget/approval_card_cuti.dart
Normal file
200
lib/screen/approval/widget/approval_card_cuti.dart
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
import 'package:absensi_sas/app/constant.dart';
|
||||||
|
import 'package:absensi_sas/model/approval_model.dart';
|
||||||
|
import 'package:absensi_sas/screen/approval/widget/approval_card_status_widget.dart';
|
||||||
|
import 'package:absensi_sas/screen/approval/widget/approval_dialog_confirmation.dart';
|
||||||
|
import 'package:absensi_sas/widget/custom_button_approval.dart';
|
||||||
|
import 'package:eva_icons_flutter/eva_icons_flutter.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:iconify_flutter/iconify_flutter.dart';
|
||||||
|
import 'package:iconify_flutter/icons/heroicons.dart';
|
||||||
|
|
||||||
|
class ApprovalCardCuti extends StatelessWidget {
|
||||||
|
const ApprovalCardCuti({super.key, required this.data});
|
||||||
|
final ApprovalModel data;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
margin: EdgeInsets.only(
|
||||||
|
bottom: Constant.getActualYPhone(context: context, y: 20)),
|
||||||
|
child: InkWell(
|
||||||
|
customBorder: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
),
|
||||||
|
splashColor: Constant.bgOrange,
|
||||||
|
overlayColor: MaterialStatePropertyAll(Constant.bgOrange),
|
||||||
|
onTap: () {
|
||||||
|
print("tapped");
|
||||||
|
},
|
||||||
|
child: Ink(
|
||||||
|
decoration: BoxDecoration(boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.grey.withOpacity(0.12),
|
||||||
|
offset: Offset(0.0, 10), //(x,y)
|
||||||
|
blurRadius: 4.0,
|
||||||
|
),
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.grey.withOpacity(0.2),
|
||||||
|
offset: Offset(0.0, 0), //(x,y)
|
||||||
|
blurRadius: 2.0,
|
||||||
|
),
|
||||||
|
], color: Colors.white, borderRadius: BorderRadius.circular(16)),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal:
|
||||||
|
Constant.getActualXPhone(context: context, x: 20),
|
||||||
|
vertical:
|
||||||
|
Constant.getActualYPhone(context: context, y: 16)),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
data.name ?? "",
|
||||||
|
style: Constant.body_16(context: context),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
color: Constant.primaryOrange.withOpacity(0.2)),
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: Constant.getActualXPhone(
|
||||||
|
context: context, x: 8),
|
||||||
|
vertical: Constant.getActualYPhone(
|
||||||
|
context: context, y: 1)),
|
||||||
|
child: Text(
|
||||||
|
data.typename ?? "",
|
||||||
|
style: Constant.body_12(context: context)
|
||||||
|
.copyWith(color: Constant.primaryOrange),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height:
|
||||||
|
Constant.getActualYPhone(context: context, y: 8),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
EvaIcons.calendar,
|
||||||
|
color: Constant.primaryOrange,
|
||||||
|
size: 14,
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: Constant.getActualXPhone(
|
||||||
|
context: context, x: 8),
|
||||||
|
),
|
||||||
|
Flexible(
|
||||||
|
child: Text(
|
||||||
|
data.date ?? "",
|
||||||
|
style: Constant.titleH2_400_14(context: context)
|
||||||
|
.copyWith(color: Constant.textDarkGrey),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height:
|
||||||
|
Constant.getActualYPhone(context: context, y: 8),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// Icon(
|
||||||
|
// ,
|
||||||
|
// color: Constant.primaryOrange,
|
||||||
|
// size: 14,
|
||||||
|
// ),
|
||||||
|
Iconify(
|
||||||
|
Heroicons.chat_bubble_bottom_center_text_solid,
|
||||||
|
color: Constant.primaryOrange,
|
||||||
|
size: 14,
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: Constant.getActualXPhone(
|
||||||
|
context: context, x: 8),
|
||||||
|
),
|
||||||
|
|
||||||
|
Flexible(
|
||||||
|
child: Text(
|
||||||
|
"${data.reasonType} ▪️ ${data.reasonDescription}",
|
||||||
|
style: Constant.titleH2_400_14(context: context)
|
||||||
|
.copyWith(color: Constant.textDarkGrey),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height:
|
||||||
|
Constant.getActualYPhone(context: context, y: 20),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: List.generate(
|
||||||
|
1000 ~/ 10,
|
||||||
|
(index) => Expanded(
|
||||||
|
child: Container(
|
||||||
|
color: index % 2 == 0
|
||||||
|
? Colors.transparent
|
||||||
|
: Constant.textLightGrey
|
||||||
|
.withOpacity(0.24),
|
||||||
|
height: 1,
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
if (data.statusID != "1" && data.statusID != "2")
|
||||||
|
SizedBox(
|
||||||
|
height:
|
||||||
|
Constant.getActualYPhone(context: context, y: 20),
|
||||||
|
),
|
||||||
|
if (data.statusID != "1" && data.statusID != "2")
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: CustomButtonWhite(
|
||||||
|
btnText: "Reject",
|
||||||
|
onPressed: () {
|
||||||
|
ApprovalDialogConfirmation(
|
||||||
|
context: context,
|
||||||
|
confirmFunc: () {},
|
||||||
|
textInformation: "Menolak ",
|
||||||
|
staffName: data.name ?? "",
|
||||||
|
typename: data.typename ?? "");
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: Constant.getActualXPhone(
|
||||||
|
context: context, x: 24),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: CustomButtonOrange(
|
||||||
|
btnText: "Approve",
|
||||||
|
onPressed: () {
|
||||||
|
ApprovalDialogConfirmation(
|
||||||
|
context: context,
|
||||||
|
confirmFunc: () {},
|
||||||
|
textInformation: "Menyetujui ",
|
||||||
|
staffName: data.name ?? "",
|
||||||
|
typename: data.typename ?? "");
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
AprrovalCardStatusWidget(
|
||||||
|
statusID: data.statusID ?? "",
|
||||||
|
statusName: data.statusName ?? '',
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
200
lib/screen/approval/widget/approval_card_lembur.dart
Normal file
200
lib/screen/approval/widget/approval_card_lembur.dart
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
import 'package:absensi_sas/app/constant.dart';
|
||||||
|
import 'package:absensi_sas/model/approval_model.dart';
|
||||||
|
import 'package:absensi_sas/screen/approval/widget/approval_card_status_widget.dart';
|
||||||
|
import 'package:absensi_sas/screen/approval/widget/approval_dialog_confirmation.dart';
|
||||||
|
import 'package:absensi_sas/widget/custom_button_approval.dart';
|
||||||
|
import 'package:eva_icons_flutter/eva_icons_flutter.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:iconify_flutter/iconify_flutter.dart';
|
||||||
|
import 'package:iconify_flutter/icons/heroicons.dart';
|
||||||
|
|
||||||
|
class ApprovalCardLembur extends StatelessWidget {
|
||||||
|
const ApprovalCardLembur({super.key, required this.data});
|
||||||
|
final ApprovalModel data;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
margin: EdgeInsets.only(
|
||||||
|
bottom: Constant.getActualYPhone(context: context, y: 20)),
|
||||||
|
child: InkWell(
|
||||||
|
customBorder: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
),
|
||||||
|
splashColor: Constant.bgOrange,
|
||||||
|
overlayColor: MaterialStatePropertyAll(Constant.bgOrange),
|
||||||
|
onTap: () {
|
||||||
|
print("tapped");
|
||||||
|
},
|
||||||
|
child: Ink(
|
||||||
|
decoration: BoxDecoration(boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.grey.withOpacity(0.12),
|
||||||
|
offset: Offset(0.0, 10), //(x,y)
|
||||||
|
blurRadius: 4.0,
|
||||||
|
),
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.grey.withOpacity(0.2),
|
||||||
|
offset: Offset(0.0, 0), //(x,y)
|
||||||
|
blurRadius: 2.0,
|
||||||
|
),
|
||||||
|
], color: Colors.white, borderRadius: BorderRadius.circular(16)),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal:
|
||||||
|
Constant.getActualXPhone(context: context, x: 20),
|
||||||
|
vertical:
|
||||||
|
Constant.getActualYPhone(context: context, y: 16)),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
data.name ?? "",
|
||||||
|
style: Constant.body_16(context: context),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
color: Constant.bgSecondaryBlue),
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: Constant.getActualXPhone(
|
||||||
|
context: context, x: 8),
|
||||||
|
vertical: Constant.getActualYPhone(
|
||||||
|
context: context, y: 1)),
|
||||||
|
child: Text(
|
||||||
|
data.typename ?? "",
|
||||||
|
style: Constant.body_12(context: context)
|
||||||
|
.copyWith(color: Constant.secondaryBlue),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height:
|
||||||
|
Constant.getActualYPhone(context: context, y: 8),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
EvaIcons.calendar,
|
||||||
|
color: Constant.textOrange,
|
||||||
|
size: 14,
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: Constant.getActualXPhone(
|
||||||
|
context: context, x: 8),
|
||||||
|
),
|
||||||
|
Flexible(
|
||||||
|
child: Text(
|
||||||
|
data.date ?? "",
|
||||||
|
style: Constant.titleH2_400_14(context: context)
|
||||||
|
.copyWith(color: Constant.textDarkGrey),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height:
|
||||||
|
Constant.getActualYPhone(context: context, y: 8),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// Icon(
|
||||||
|
// ,
|
||||||
|
// color: Constant.textOrange,
|
||||||
|
// size: 14,
|
||||||
|
// ),
|
||||||
|
Iconify(
|
||||||
|
Heroicons.chat_bubble_bottom_center_text_solid,
|
||||||
|
color: Constant.textOrange,
|
||||||
|
size: 14,
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: Constant.getActualXPhone(
|
||||||
|
context: context, x: 8),
|
||||||
|
),
|
||||||
|
|
||||||
|
Flexible(
|
||||||
|
child: Text(
|
||||||
|
data.reasonDescription ?? '',
|
||||||
|
style: Constant.titleH2_400_14(context: context)
|
||||||
|
.copyWith(color: Constant.textDarkGrey),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height:
|
||||||
|
Constant.getActualYPhone(context: context, y: 20),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: List.generate(
|
||||||
|
1000 ~/ 10,
|
||||||
|
(index) => Expanded(
|
||||||
|
child: Container(
|
||||||
|
color: index % 2 == 0
|
||||||
|
? Colors.transparent
|
||||||
|
: Constant.textLightGrey
|
||||||
|
.withOpacity(0.24),
|
||||||
|
height: 1,
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
if (data.statusID != "1" && data.statusID != "2")
|
||||||
|
SizedBox(
|
||||||
|
height:
|
||||||
|
Constant.getActualYPhone(context: context, y: 20),
|
||||||
|
),
|
||||||
|
if (data.statusID != "1" && data.statusID != "2")
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: CustomButtonWhite(
|
||||||
|
btnText: "Reject",
|
||||||
|
onPressed: () {
|
||||||
|
ApprovalDialogConfirmation(
|
||||||
|
context: context,
|
||||||
|
confirmFunc: () {},
|
||||||
|
textInformation: "Menolak ",
|
||||||
|
staffName: data.name ?? "",
|
||||||
|
typename: data.typename ?? "");
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: Constant.getActualXPhone(
|
||||||
|
context: context, x: 24),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: CustomButtonOrange(
|
||||||
|
btnText: "Approve",
|
||||||
|
onPressed: () {
|
||||||
|
ApprovalDialogConfirmation(
|
||||||
|
context: context,
|
||||||
|
confirmFunc: () {},
|
||||||
|
textInformation: "Menyetujui ",
|
||||||
|
staffName: data.name ?? "",
|
||||||
|
typename: data.typename ?? "");
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
AprrovalCardStatusWidget(
|
||||||
|
statusID: data.statusID ?? "",
|
||||||
|
statusName: data.statusName ?? '',
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
203
lib/screen/approval/widget/approval_card_presensi.dart
Normal file
203
lib/screen/approval/widget/approval_card_presensi.dart
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
import 'package:absensi_sas/app/constant.dart';
|
||||||
|
import 'package:absensi_sas/model/approval_model.dart';
|
||||||
|
import 'package:absensi_sas/screen/approval/widget/approval_card_status_widget.dart';
|
||||||
|
import 'package:eva_icons_flutter/eva_icons_flutter.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class ApprovalCardPresensi extends StatelessWidget {
|
||||||
|
const ApprovalCardPresensi(
|
||||||
|
{super.key, required this.data, required this.onTap});
|
||||||
|
final ApprovalModel data;
|
||||||
|
final Function onTap;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
margin: EdgeInsets.only(
|
||||||
|
bottom: Constant.getActualYPhone(context: context, y: 20)),
|
||||||
|
child: InkWell(
|
||||||
|
customBorder: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
),
|
||||||
|
splashColor: Constant.bgOrange,
|
||||||
|
// hoverColor: Colors.red,
|
||||||
|
overlayColor: MaterialStatePropertyAll(Constant.bgOrange),
|
||||||
|
|
||||||
|
onTap: () {
|
||||||
|
onTap(data.typeID);
|
||||||
|
},
|
||||||
|
child: Ink(
|
||||||
|
decoration: BoxDecoration(boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.grey.withOpacity(0.12),
|
||||||
|
offset: Offset(0.0, 10), //(x,y)
|
||||||
|
blurRadius: 4.0,
|
||||||
|
),
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.grey.withOpacity(0.2),
|
||||||
|
offset: Offset(0.0, 0), //(x,y)
|
||||||
|
blurRadius: 2.0,
|
||||||
|
),
|
||||||
|
], color: Colors.white, borderRadius: BorderRadius.circular(16)),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal:
|
||||||
|
Constant.getActualXPhone(context: context, x: 20),
|
||||||
|
vertical:
|
||||||
|
Constant.getActualYPhone(context: context, y: 16)),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
data.name ?? "",
|
||||||
|
style: Constant.body_16(context: context),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
color: Constant.bgBlue),
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: Constant.getActualXPhone(
|
||||||
|
context: context, x: 8),
|
||||||
|
vertical: Constant.getActualYPhone(
|
||||||
|
context: context, y: 1)),
|
||||||
|
child: Text(
|
||||||
|
data.typename ?? "",
|
||||||
|
style: Constant.body_12(context: context)
|
||||||
|
.copyWith(color: Constant.primaryBlue),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height:
|
||||||
|
Constant.getActualYPhone(context: context, y: 8),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
EvaIcons.calendar,
|
||||||
|
color: Constant.primaryOrange,
|
||||||
|
size: 14,
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: Constant.getActualXPhone(
|
||||||
|
context: context, x: 8),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
data.date ?? "",
|
||||||
|
style: Constant.titleH2_400_14(context: context)
|
||||||
|
.copyWith(color: Constant.textDarkGrey),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: Constant.getActualXPhone(
|
||||||
|
context: context, x: 20),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
EvaIcons.clock,
|
||||||
|
color: Constant.primaryOrange,
|
||||||
|
size: 14,
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: Constant.getActualXPhone(
|
||||||
|
context: context, x: 8),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
data.time ?? "",
|
||||||
|
style: Constant.titleH2_400_14(context: context)
|
||||||
|
.copyWith(color: Constant.textDarkGrey),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: Constant.getActualXPhone(
|
||||||
|
context: context, x: 20),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Image.asset(
|
||||||
|
'images/finger_tap_orange_botnav.png',
|
||||||
|
width: Constant.getActualXPhone(
|
||||||
|
context: context, x: 14),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: Constant.getActualXPhone(
|
||||||
|
context: context, x: 8),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
data.presensiTypeName ?? "",
|
||||||
|
style: Constant.titleH2_400_14(context: context)
|
||||||
|
.copyWith(color: Constant.textDarkGrey),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height:
|
||||||
|
Constant.getActualYPhone(context: context, y: 8),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
EvaIcons.pin,
|
||||||
|
color: Constant.primaryOrange,
|
||||||
|
size: 14,
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: Constant.getActualXPhone(
|
||||||
|
context: context, x: 8),
|
||||||
|
),
|
||||||
|
Flexible(
|
||||||
|
child: Text(
|
||||||
|
data.address ?? "",
|
||||||
|
style: Constant.titleH2_400_14(context: context)
|
||||||
|
.copyWith(color: Constant.textDarkGrey),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
if (data.statusID == "1" || data.statusID == "2")
|
||||||
|
SizedBox(
|
||||||
|
height:
|
||||||
|
Constant.getActualYPhone(context: context, y: 20),
|
||||||
|
),
|
||||||
|
if (data.statusID == "1" || data.statusID == "2")
|
||||||
|
Row(
|
||||||
|
children: List.generate(
|
||||||
|
1000 ~/ 10,
|
||||||
|
(index) => Expanded(
|
||||||
|
child: Container(
|
||||||
|
color: index % 2 == 0
|
||||||
|
? Colors.transparent
|
||||||
|
: Constant.textLightGrey
|
||||||
|
.withOpacity(0.24),
|
||||||
|
height: 1,
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
AprrovalCardStatusWidget(
|
||||||
|
statusID: data.statusID ?? "",
|
||||||
|
statusName: data.statusName ?? "",
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
52
lib/screen/approval/widget/approval_card_status_widget.dart
Normal file
52
lib/screen/approval/widget/approval_card_status_widget.dart
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
import 'package:absensi_sas/app/constant.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class AprrovalCardStatusWidget extends StatelessWidget {
|
||||||
|
const AprrovalCardStatusWidget(
|
||||||
|
{super.key, required this.statusID, required this.statusName});
|
||||||
|
final String statusID;
|
||||||
|
final String statusName;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
switch (statusID) {
|
||||||
|
case "1":
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Constant.bgGreen,
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
bottomLeft: Radius.circular(16),
|
||||||
|
bottomRight: Radius.circular(16))),
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: Constant.getActualXPhone(context: context, x: 20),
|
||||||
|
vertical: Constant.getActualYPhone(context: context, y: 16)),
|
||||||
|
width: MediaQuery.of(context).size.width,
|
||||||
|
child: Text(
|
||||||
|
statusName,
|
||||||
|
style: Constant.body_12(context: context)
|
||||||
|
.copyWith(color: Constant.primaryGreen),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
case "2":
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Constant.bgRed,
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
bottomLeft: Radius.circular(16),
|
||||||
|
bottomRight: Radius.circular(16))),
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: Constant.getActualXPhone(context: context, x: 20),
|
||||||
|
vertical: Constant.getActualYPhone(context: context, y: 16)),
|
||||||
|
width: MediaQuery.of(context).size.width,
|
||||||
|
child: Text(
|
||||||
|
statusName,
|
||||||
|
style: Constant.body_12(context: context)
|
||||||
|
.copyWith(color: Constant.primaryRed),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
75
lib/screen/approval/widget/approval_dialog_confirmation.dart
Normal file
75
lib/screen/approval/widget/approval_dialog_confirmation.dart
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
import 'package:absensi_sas/app/constant.dart';
|
||||||
|
import 'package:absensi_sas/widget/custom_button_approval.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
Future ApprovalDialogConfirmation(
|
||||||
|
{required BuildContext context,
|
||||||
|
required String typename,
|
||||||
|
required String textInformation,
|
||||||
|
required String staffName,
|
||||||
|
required Function() confirmFunc}) {
|
||||||
|
return showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) => Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
gradient: LinearGradient(
|
||||||
|
begin: Alignment.centerRight,
|
||||||
|
end: Alignment.centerLeft,
|
||||||
|
colors: [
|
||||||
|
Color(0xff161C24).withOpacity(0.91),
|
||||||
|
Color(0xff161C24).withOpacity(0.3)
|
||||||
|
])),
|
||||||
|
child: AlertDialog(
|
||||||
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
surfaceTintColor: Colors.white,
|
||||||
|
shadowColor: Colors.white,
|
||||||
|
title: Text(
|
||||||
|
'Konfirmasi',
|
||||||
|
style: Constant.titleH1_700_18(context: context),
|
||||||
|
),
|
||||||
|
content: Text.rich(TextSpan(
|
||||||
|
text: "Apakah anda yakin untuk ",
|
||||||
|
style: Constant.body_16(context: context)
|
||||||
|
.copyWith(fontWeight: FontWeight.w400),
|
||||||
|
children: [
|
||||||
|
TextSpan(
|
||||||
|
text: textInformation,
|
||||||
|
style: Constant.body_16(context: context)),
|
||||||
|
TextSpan(
|
||||||
|
text: "${typename} ",
|
||||||
|
style: Constant.body_16(context: context)
|
||||||
|
.copyWith(fontWeight: FontWeight.w400)),
|
||||||
|
TextSpan(
|
||||||
|
text: "${staffName} ?",
|
||||||
|
style: Constant.body_16(context: context))
|
||||||
|
])),
|
||||||
|
actions: <Widget>[
|
||||||
|
Column(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: MediaQuery.of(context).size.width,
|
||||||
|
child: CustomButtonOrange(
|
||||||
|
btnText: "Yakin",
|
||||||
|
onPressed: confirmFunc,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 3,
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
width: MediaQuery.of(context).size.width,
|
||||||
|
child: CustomButtonWhite(
|
||||||
|
btnText: "Batal",
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
71
lib/screen/approval/widget/approval_filter_chip_widget.dart
Normal file
71
lib/screen/approval/widget/approval_filter_chip_widget.dart
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
import 'package:absensi_sas/app/constant.dart';
|
||||||
|
import 'package:absensi_sas/model/approval_type_model.dart';
|
||||||
|
import 'package:absensi_sas/provider/approval_filter_provider.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
|
||||||
|
class ApprovalFilterChipWidget extends HookConsumerWidget {
|
||||||
|
const ApprovalFilterChipWidget({
|
||||||
|
super.key,
|
||||||
|
required this.data,
|
||||||
|
});
|
||||||
|
final ApprovalTypeModel data;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final currentApprovalFilter = ref.watch(approvalFilterProvider);
|
||||||
|
handleOnTap(String value) {
|
||||||
|
var tmp = currentApprovalFilter.selectedApprovalType.toList();
|
||||||
|
var cek = tmp.contains(value);
|
||||||
|
if (cek) {
|
||||||
|
tmp.remove(value);
|
||||||
|
} else {
|
||||||
|
tmp.add(value);
|
||||||
|
}
|
||||||
|
ref.read(approvalFilterProvider.notifier).state = ApprovalFilterProvider(
|
||||||
|
endDate: currentApprovalFilter.endDate,
|
||||||
|
keyword: currentApprovalFilter.keyword,
|
||||||
|
selectedApprovalType: tmp,
|
||||||
|
startDate: currentApprovalFilter.startDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Container(
|
||||||
|
margin: EdgeInsets.only(
|
||||||
|
right: Constant.getActualXPhone(context: context, x: 16)),
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
handleOnTap(data.value!);
|
||||||
|
},
|
||||||
|
style: ButtonStyle(
|
||||||
|
elevation: MaterialStatePropertyAll(0),
|
||||||
|
shape: MaterialStatePropertyAll(RoundedRectangleBorder(
|
||||||
|
side: BorderSide(
|
||||||
|
color: currentApprovalFilter.selectedApprovalType
|
||||||
|
.contains(data.value)
|
||||||
|
? Constant.textOrange
|
||||||
|
: Colors.grey.shade300,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(16))),
|
||||||
|
backgroundColor: MaterialStateProperty.resolveWith((states) {
|
||||||
|
if (currentApprovalFilter.selectedApprovalType
|
||||||
|
.contains(data.value) ==
|
||||||
|
true) {
|
||||||
|
return Constant.textOrange.withOpacity(0.1);
|
||||||
|
}
|
||||||
|
return Colors.white;
|
||||||
|
}),
|
||||||
|
overlayColor:
|
||||||
|
MaterialStatePropertyAll(Constant.textOrange.withOpacity(0.48)),
|
||||||
|
foregroundColor: MaterialStatePropertyAll(Colors.white),
|
||||||
|
shadowColor: MaterialStatePropertyAll(Colors.white),
|
||||||
|
surfaceTintColor: MaterialStatePropertyAll(Colors.white)),
|
||||||
|
child: Text(data.name ?? "",
|
||||||
|
style: Constant.subtitle_600_14(context: context).copyWith(
|
||||||
|
color: currentApprovalFilter.selectedApprovalType
|
||||||
|
.contains(data.value)
|
||||||
|
? Constant.textOrange
|
||||||
|
: Colors.black)),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
69
lib/screen/approval/widget/approval_filter_widget.dart
Normal file
69
lib/screen/approval/widget/approval_filter_widget.dart
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
import 'package:absensi_sas/app/constant.dart';
|
||||||
|
|
||||||
|
import 'package:absensi_sas/screen/approval/widget/filter_bottom_sheet.dart';
|
||||||
|
import 'package:fluentui_system_icons/fluentui_system_icons.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
|
||||||
|
class ApprovalFilterWidget extends HookConsumerWidget {
|
||||||
|
const ApprovalFilterWidget({super.key});
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
return Container(
|
||||||
|
margin: EdgeInsets.only(
|
||||||
|
right: Constant.getActualXPhone(context: context, x: 16)),
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
showModalBottomSheet(
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
topLeft: Radius.circular(32),
|
||||||
|
topRight: Radius.circular(32))),
|
||||||
|
context: context,
|
||||||
|
isScrollControlled: true,
|
||||||
|
enableDrag: true,
|
||||||
|
useSafeArea: true,
|
||||||
|
// useRootNavigator: true,
|
||||||
|
builder: (context) {
|
||||||
|
return FilterBottomSheet();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
style: ButtonStyle(
|
||||||
|
elevation: MaterialStatePropertyAll(0),
|
||||||
|
shape: MaterialStatePropertyAll(RoundedRectangleBorder(
|
||||||
|
side: BorderSide(
|
||||||
|
color: Colors.grey.shade300,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(16))),
|
||||||
|
backgroundColor: MaterialStateProperty.resolveWith((states) {
|
||||||
|
return Colors.white;
|
||||||
|
}),
|
||||||
|
overlayColor:
|
||||||
|
MaterialStatePropertyAll(Constant.textOrange.withOpacity(0.48)),
|
||||||
|
foregroundColor: MaterialStatePropertyAll(Colors.white),
|
||||||
|
shadowColor: MaterialStatePropertyAll(Colors.white),
|
||||||
|
surfaceTintColor: MaterialStatePropertyAll(Colors.white)),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
FluentIcons.options_24_filled,
|
||||||
|
size: 20,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: 8,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"Filter",
|
||||||
|
style: Constant.subtitle_600_14(context: context)
|
||||||
|
.copyWith(color: Colors.black),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
534
lib/screen/approval/widget/filter_bottom_sheet.dart
Normal file
534
lib/screen/approval/widget/filter_bottom_sheet.dart
Normal file
@@ -0,0 +1,534 @@
|
|||||||
|
import 'package:absensi_sas/app/constant.dart';
|
||||||
|
import 'package:absensi_sas/model/approval_type_model.dart';
|
||||||
|
import 'package:absensi_sas/provider/approval_filter_provider.dart';
|
||||||
|
import 'package:absensi_sas/widget/custom_button_approval.dart';
|
||||||
|
import 'package:eva_icons_flutter/eva_icons_flutter.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
|
class FilterBottomSheet extends HookConsumerWidget {
|
||||||
|
const FilterBottomSheet({
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final currApprovalTypeState = ref.read(approvalFilterProvider);
|
||||||
|
final approvalTypeList = [
|
||||||
|
ApprovalTypeModel(id: "1", name: "Presensi", isActive: false, value: "p"),
|
||||||
|
ApprovalTypeModel(id: "2", name: "Cuti", isActive: true, value: "c"),
|
||||||
|
ApprovalTypeModel(id: "3", name: "Lembur", isActive: false, value: "l"),
|
||||||
|
];
|
||||||
|
final staffFocuseNode = useFocusNode();
|
||||||
|
final startDateFocusNode = useFocusNode();
|
||||||
|
final endDateFocusNode = useFocusNode();
|
||||||
|
final staffCtr =
|
||||||
|
useTextEditingController(text: currApprovalTypeState.keyword);
|
||||||
|
final startDateCtr = useTextEditingController(
|
||||||
|
text: DateFormat('dd-MM-yyyy').format(currApprovalTypeState.startDate));
|
||||||
|
final startDateState = useState(currApprovalTypeState.startDate);
|
||||||
|
final endDateCtr = useTextEditingController(
|
||||||
|
text: DateFormat('dd-MM-yyyy').format(currApprovalTypeState.endDate));
|
||||||
|
final endDateState = useState(currApprovalTypeState.endDate);
|
||||||
|
final dateKey = useState(0);
|
||||||
|
|
||||||
|
final selectedApprovalTypeState = useState<List<String>>(
|
||||||
|
currApprovalTypeState.selectedApprovalType.toList());
|
||||||
|
final checkboxKey = useState(1000);
|
||||||
|
|
||||||
|
selectApprovalTypeFunction(String value) {
|
||||||
|
var tmp = selectedApprovalTypeState.value;
|
||||||
|
var cek = tmp.contains(value);
|
||||||
|
if (cek) {
|
||||||
|
tmp.remove(value);
|
||||||
|
} else {
|
||||||
|
tmp.add(value);
|
||||||
|
}
|
||||||
|
selectedApprovalTypeState.value = tmp;
|
||||||
|
checkboxKey.value = checkboxKey.value + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Container(
|
||||||
|
padding: EdgeInsets.only(
|
||||||
|
bottom: MediaQuery.of(context).viewInsets.bottom * 0.75),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
topLeft: Radius.circular(32), topRight: Radius.circular(32))),
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Container(
|
||||||
|
margin: EdgeInsets.symmetric(
|
||||||
|
horizontal: Constant.getActualXPhone(context: context, x: 24)),
|
||||||
|
height: MediaQuery.of(context).size.height * 0.75,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
height: MediaQuery.of(context).size.height * 0.1,
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"Filter",
|
||||||
|
style: Constant.titleH1_700(context: context),
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
icon: Icon(Icons.close))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: MediaQuery.of(context).size.height * 0.55,
|
||||||
|
// color: Colors.green,
|
||||||
|
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"Staff",
|
||||||
|
style: Constant.titleH1_700_18(context: context)
|
||||||
|
.copyWith(fontWeight: FontWeight.w700),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height:
|
||||||
|
Constant.getActualYPhone(context: context, y: 16),
|
||||||
|
),
|
||||||
|
TextFormField(
|
||||||
|
controller: staffCtr,
|
||||||
|
focusNode: staffFocuseNode,
|
||||||
|
style: Constant.titleH1_500_18(context: context),
|
||||||
|
decoration: InputDecoration(
|
||||||
|
focusColor: Constant.textOrange,
|
||||||
|
// hoverColor: Constant.textOrange,
|
||||||
|
suffixIcon: Icon(
|
||||||
|
EvaIcons.searchOutline,
|
||||||
|
color: staffFocuseNode.hasFocus
|
||||||
|
? Constant.textOrange
|
||||||
|
: Color(0xff212B36),
|
||||||
|
),
|
||||||
|
label: Text(
|
||||||
|
"Cari Staff",
|
||||||
|
style: Constant.titleH1_500_18(context: context)
|
||||||
|
.copyWith(
|
||||||
|
color: staffFocuseNode.hasFocus
|
||||||
|
? Constant.textOrange
|
||||||
|
: Colors.grey.shade400),
|
||||||
|
),
|
||||||
|
hintText: "Cari Staff",
|
||||||
|
isDense: false,
|
||||||
|
contentPadding: EdgeInsets.symmetric(
|
||||||
|
vertical: Constant.getActualYPhone(
|
||||||
|
context: context, y: 16),
|
||||||
|
horizontal: Constant.getActualXPhone(
|
||||||
|
context: context, x: 14)),
|
||||||
|
hintStyle:
|
||||||
|
Constant.titleH1_500_18(context: context),
|
||||||
|
focusedBorder: OutlineInputBorder(
|
||||||
|
borderSide:
|
||||||
|
BorderSide(color: Constant.textOrange),
|
||||||
|
borderRadius: BorderRadius.circular(8)),
|
||||||
|
enabledBorder: OutlineInputBorder(
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: Colors.grey.shade500, width: 1),
|
||||||
|
borderRadius: BorderRadius.circular(8)),
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderSide:
|
||||||
|
BorderSide(color: Colors.grey.shade500),
|
||||||
|
borderRadius: BorderRadius.circular(8))),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height:
|
||||||
|
Constant.getActualYPhone(context: context, y: 20),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
"Tanggal Awal",
|
||||||
|
style: Constant.titleH1_700_18(context: context)
|
||||||
|
.copyWith(fontWeight: FontWeight.w700),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: Constant.getActualXPhone(
|
||||||
|
context: context, x: 20),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
"Tanggal Akhir",
|
||||||
|
style: Constant.titleH1_700_18(context: context)
|
||||||
|
.copyWith(fontWeight: FontWeight.w700),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height:
|
||||||
|
Constant.getActualYPhone(context: context, y: 20),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: TextFormField(
|
||||||
|
key: ValueKey(dateKey.value),
|
||||||
|
controller: startDateCtr,
|
||||||
|
focusNode: startDateFocusNode,
|
||||||
|
readOnly: true,
|
||||||
|
style: Constant.titleH1_500_18(context: context),
|
||||||
|
decoration: InputDecoration(
|
||||||
|
focusColor: Constant.textOrange,
|
||||||
|
// hoverColor: Constant.textOrange,
|
||||||
|
suffixIcon: Icon(
|
||||||
|
EvaIcons.calendar,
|
||||||
|
color: startDateFocusNode.hasFocus
|
||||||
|
? Constant.textOrange
|
||||||
|
: Color(0xff212B36),
|
||||||
|
),
|
||||||
|
label: Text(
|
||||||
|
"Tanggal Awal",
|
||||||
|
style: Constant.titleH1_500_18(
|
||||||
|
context: context)
|
||||||
|
.copyWith(
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
color: startDateFocusNode.hasFocus
|
||||||
|
? Constant.textOrange
|
||||||
|
: Colors.grey.shade400),
|
||||||
|
),
|
||||||
|
hintText: "Tanggal Awal",
|
||||||
|
isDense: false,
|
||||||
|
contentPadding: EdgeInsets.symmetric(
|
||||||
|
vertical: Constant.getActualYPhone(
|
||||||
|
context: context, y: 16),
|
||||||
|
horizontal: Constant.getActualXPhone(
|
||||||
|
context: context, x: 14)),
|
||||||
|
hintStyle:
|
||||||
|
Constant.titleH1_500_18(context: context)
|
||||||
|
.copyWith(
|
||||||
|
overflow: TextOverflow.ellipsis),
|
||||||
|
focusedBorder: OutlineInputBorder(
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: Constant.textOrange),
|
||||||
|
borderRadius: BorderRadius.circular(8)),
|
||||||
|
enabledBorder: OutlineInputBorder(
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: Colors.grey.shade500,
|
||||||
|
width: 1),
|
||||||
|
borderRadius: BorderRadius.circular(8)),
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: Colors.grey.shade500),
|
||||||
|
borderRadius: BorderRadius.circular(8))),
|
||||||
|
onTap: () async {
|
||||||
|
startDateFocusNode.requestFocus();
|
||||||
|
dateKey.value = dateKey.value + 1;
|
||||||
|
DateTime? pickedDate = await showDatePicker(
|
||||||
|
helpText: "Tanggal Awal",
|
||||||
|
// locale: Locale('id', 'ID'),
|
||||||
|
builder: (context, child) {
|
||||||
|
return Theme(
|
||||||
|
data: ThemeData().copyWith(
|
||||||
|
datePickerTheme:
|
||||||
|
DatePickerThemeData(
|
||||||
|
dayBackgroundColor:
|
||||||
|
MaterialStateProperty
|
||||||
|
.resolveWith(
|
||||||
|
(states) {
|
||||||
|
if (states.contains(
|
||||||
|
MaterialState
|
||||||
|
.selected)) {
|
||||||
|
return Constant
|
||||||
|
.textOrange;
|
||||||
|
}
|
||||||
|
return Colors.white;
|
||||||
|
}),
|
||||||
|
todayBackgroundColor:
|
||||||
|
MaterialStateProperty
|
||||||
|
.resolveWith(
|
||||||
|
(states) {
|
||||||
|
if (states.contains(
|
||||||
|
MaterialState
|
||||||
|
.selected)) {
|
||||||
|
return Constant
|
||||||
|
.textOrange;
|
||||||
|
}
|
||||||
|
return Colors.white;
|
||||||
|
}),
|
||||||
|
todayBorder: BorderSide(
|
||||||
|
style:
|
||||||
|
BorderStyle.solid,
|
||||||
|
color: Constant
|
||||||
|
.textOrange,
|
||||||
|
width: 1),
|
||||||
|
headerBackgroundColor:
|
||||||
|
Constant.textOrange,
|
||||||
|
headerForegroundColor:
|
||||||
|
Colors.white,
|
||||||
|
surfaceTintColor:
|
||||||
|
Colors.white,
|
||||||
|
backgroundColor:
|
||||||
|
Colors.white),
|
||||||
|
primaryColor: Constant.textOrange,
|
||||||
|
primaryColorDark:
|
||||||
|
Constant.textOrange,
|
||||||
|
primaryColorLight:
|
||||||
|
Constant.textOrange),
|
||||||
|
child: child!);
|
||||||
|
},
|
||||||
|
confirmText: "OK",
|
||||||
|
cancelText: "Batal",
|
||||||
|
context: context,
|
||||||
|
initialDate: startDateState.value,
|
||||||
|
firstDate: DateTime(1950),
|
||||||
|
initialEntryMode:
|
||||||
|
DatePickerEntryMode.calendarOnly,
|
||||||
|
lastDate: DateTime(2100));
|
||||||
|
|
||||||
|
if (pickedDate != null) {
|
||||||
|
print(
|
||||||
|
pickedDate); //pickedDate output format => 2021-03-10 00:00:00.000
|
||||||
|
String formattedDate =
|
||||||
|
DateFormat('dd-MM-yyyy')
|
||||||
|
.format(pickedDate);
|
||||||
|
print(
|
||||||
|
formattedDate); //formatted date output using intl package => 2021-03-16
|
||||||
|
startDateCtr.text =
|
||||||
|
formattedDate; //set output date to TextField value.
|
||||||
|
startDateState.value = pickedDate;
|
||||||
|
startDateFocusNode.requestFocus();
|
||||||
|
} else {}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: Constant.getActualXPhone(
|
||||||
|
context: context, x: 20),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: TextFormField(
|
||||||
|
key: ValueKey(dateKey.value),
|
||||||
|
controller: endDateCtr,
|
||||||
|
focusNode: endDateFocusNode,
|
||||||
|
readOnly: true,
|
||||||
|
style: Constant.titleH1_500_18(context: context),
|
||||||
|
decoration: InputDecoration(
|
||||||
|
focusColor: Constant.textOrange,
|
||||||
|
// hoverColor: Constant.textOrange,
|
||||||
|
suffixIcon: Icon(
|
||||||
|
EvaIcons.calendar,
|
||||||
|
color: endDateFocusNode.hasFocus
|
||||||
|
? Constant.textOrange
|
||||||
|
: Color(0xff212B36),
|
||||||
|
),
|
||||||
|
label: Text(
|
||||||
|
"Tanggal Akhir",
|
||||||
|
style: Constant.titleH1_500_18(
|
||||||
|
context: context)
|
||||||
|
.copyWith(
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
color: endDateFocusNode.hasFocus
|
||||||
|
? Constant.textOrange
|
||||||
|
: Colors.grey.shade400),
|
||||||
|
),
|
||||||
|
hintText: "Tanggal Akhir",
|
||||||
|
isDense: false,
|
||||||
|
contentPadding: EdgeInsets.symmetric(
|
||||||
|
vertical: Constant.getActualYPhone(
|
||||||
|
context: context, y: 16),
|
||||||
|
horizontal: Constant.getActualXPhone(
|
||||||
|
context: context, x: 14)),
|
||||||
|
hintStyle:
|
||||||
|
Constant.titleH1_500_18(context: context)
|
||||||
|
.copyWith(
|
||||||
|
overflow: TextOverflow.ellipsis),
|
||||||
|
focusedBorder: OutlineInputBorder(
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: Constant.textOrange),
|
||||||
|
borderRadius: BorderRadius.circular(8)),
|
||||||
|
enabledBorder: OutlineInputBorder(
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: Colors.grey.shade500,
|
||||||
|
width: 1),
|
||||||
|
borderRadius: BorderRadius.circular(8)),
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: Colors.grey.shade500),
|
||||||
|
borderRadius: BorderRadius.circular(8))),
|
||||||
|
onTap: () async {
|
||||||
|
endDateFocusNode.requestFocus();
|
||||||
|
dateKey.value = dateKey.value + 1;
|
||||||
|
DateTime? pickedDate = await showDatePicker(
|
||||||
|
helpText: "Tanggal Akhir",
|
||||||
|
// locale: Locale('id', 'ID'),
|
||||||
|
builder: (context, child) {
|
||||||
|
return Theme(
|
||||||
|
data: ThemeData().copyWith(
|
||||||
|
datePickerTheme:
|
||||||
|
DatePickerThemeData(
|
||||||
|
dayBackgroundColor:
|
||||||
|
MaterialStateProperty
|
||||||
|
.resolveWith(
|
||||||
|
(states) {
|
||||||
|
if (states.contains(
|
||||||
|
MaterialState
|
||||||
|
.selected)) {
|
||||||
|
return Constant
|
||||||
|
.textOrange;
|
||||||
|
}
|
||||||
|
return Colors.white;
|
||||||
|
}),
|
||||||
|
todayBackgroundColor:
|
||||||
|
MaterialStateProperty
|
||||||
|
.resolveWith(
|
||||||
|
(states) {
|
||||||
|
if (states.contains(
|
||||||
|
MaterialState
|
||||||
|
.selected)) {
|
||||||
|
return Constant
|
||||||
|
.textOrange;
|
||||||
|
}
|
||||||
|
return Colors.white;
|
||||||
|
}),
|
||||||
|
todayBorder: BorderSide(
|
||||||
|
style:
|
||||||
|
BorderStyle.solid,
|
||||||
|
color: Constant
|
||||||
|
.textOrange,
|
||||||
|
width: 1),
|
||||||
|
headerBackgroundColor:
|
||||||
|
Constant.textOrange,
|
||||||
|
headerForegroundColor:
|
||||||
|
Colors.white,
|
||||||
|
surfaceTintColor:
|
||||||
|
Colors.white,
|
||||||
|
backgroundColor:
|
||||||
|
Colors.white),
|
||||||
|
primaryColor: Constant.textOrange,
|
||||||
|
primaryColorDark:
|
||||||
|
Constant.textOrange,
|
||||||
|
primaryColorLight:
|
||||||
|
Constant.textOrange),
|
||||||
|
child: child!);
|
||||||
|
},
|
||||||
|
confirmText: "OK",
|
||||||
|
cancelText: "Batal",
|
||||||
|
context: context,
|
||||||
|
initialDate: startDateState.value,
|
||||||
|
firstDate: DateTime(1950),
|
||||||
|
initialEntryMode:
|
||||||
|
DatePickerEntryMode.calendarOnly,
|
||||||
|
lastDate: DateTime(2100));
|
||||||
|
|
||||||
|
if (pickedDate != null) {
|
||||||
|
print(
|
||||||
|
pickedDate); //pickedDate output format => 2021-03-10 00:00:00.000
|
||||||
|
String formattedDate =
|
||||||
|
DateFormat('dd-MM-yyyy')
|
||||||
|
.format(pickedDate);
|
||||||
|
print(
|
||||||
|
formattedDate); //formatted date output using intl package => 2021-03-16
|
||||||
|
endDateCtr.text =
|
||||||
|
formattedDate; //set output date to TextField value.
|
||||||
|
endDateState.value = pickedDate;
|
||||||
|
endDateFocusNode.requestFocus();
|
||||||
|
} else {}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height:
|
||||||
|
Constant.getActualYPhone(context: context, y: 16),
|
||||||
|
),
|
||||||
|
// Text(
|
||||||
|
// ref
|
||||||
|
// .watch(approvalFilterProvider)
|
||||||
|
// .selectedApprovalType
|
||||||
|
// .toString(),
|
||||||
|
// style: Constant.titleH1_700_18(context: context),
|
||||||
|
// ),
|
||||||
|
Text(
|
||||||
|
"Approval",
|
||||||
|
style: Constant.titleH1_700_18(context: context)
|
||||||
|
.copyWith(fontWeight: FontWeight.w700),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height:
|
||||||
|
Constant.getActualYPhone(context: context, y: 16),
|
||||||
|
),
|
||||||
|
...approvalTypeList.map(
|
||||||
|
(e) {
|
||||||
|
return Row(
|
||||||
|
children: [
|
||||||
|
Checkbox(
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(4)),
|
||||||
|
value: selectedApprovalTypeState.value
|
||||||
|
.contains(e.value),
|
||||||
|
onChanged: (val) {
|
||||||
|
selectApprovalTypeFunction(e.value!);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
e.name ?? "",
|
||||||
|
style: Constant.titleH1_700_18(context: context)
|
||||||
|
.copyWith(fontWeight: FontWeight.normal),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: MediaQuery.of(context).size.height * 0.1,
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: CustomButtonWhite(
|
||||||
|
btnText: "Reset",
|
||||||
|
onPressed: () {
|
||||||
|
ref.read(approvalFilterProvider.notifier).state =
|
||||||
|
ApprovalFilterProvider(
|
||||||
|
startDate: DateTime.now(),
|
||||||
|
endDate: DateTime.now(),
|
||||||
|
keyword: "",
|
||||||
|
selectedApprovalType: []);
|
||||||
|
Navigator.pop(context);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: Constant.getActualXPhone(context: context, x: 24),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: CustomButtonOrange(
|
||||||
|
btnText: "Simpan",
|
||||||
|
onPressed: () {
|
||||||
|
ref.read(approvalFilterProvider.notifier).state =
|
||||||
|
ApprovalFilterProvider(
|
||||||
|
endDate: endDateState.value,
|
||||||
|
keyword: staffCtr.text,
|
||||||
|
selectedApprovalType:
|
||||||
|
selectedApprovalTypeState.value,
|
||||||
|
startDate: startDateState.value);
|
||||||
|
Navigator.pop(context);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
368
lib/screen/approval_detail/approval_detail_screen.dart
Normal file
368
lib/screen/approval_detail/approval_detail_screen.dart
Normal file
@@ -0,0 +1,368 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:absensi_sas/app/constant.dart';
|
||||||
|
import 'package:absensi_sas/model/approval_detail_model.dart';
|
||||||
|
import 'package:absensi_sas/screen/approval/approval_mockup.dart';
|
||||||
|
import 'package:absensi_sas/screen/approval/widget/approval_dialog_confirmation.dart';
|
||||||
|
import 'package:absensi_sas/widget/custom_button_approval.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
|
import 'package:flutter_map/flutter_map.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:latlong2/latlong.dart';
|
||||||
|
|
||||||
|
class ApprovalDetailScreen extends HookConsumerWidget {
|
||||||
|
const ApprovalDetailScreen({super.key});
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final loading = useState(true);
|
||||||
|
final data = useState<ApprovalDetailModel>(
|
||||||
|
ApprovalDetailModel(imagePath: "", lat: 0, long: 0));
|
||||||
|
init() {
|
||||||
|
loading.value = true;
|
||||||
|
var randIdx = Random().nextInt(approvalDetailMockup.length);
|
||||||
|
var tmp = approvalDetailMockup[randIdx];
|
||||||
|
Timer(Duration(seconds: 2), () {
|
||||||
|
data.value = tmp;
|
||||||
|
loading.value = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
|
||||||
|
init();
|
||||||
|
return;
|
||||||
|
});
|
||||||
|
return () {};
|
||||||
|
}, []);
|
||||||
|
return SafeArea(
|
||||||
|
minimum: EdgeInsets.only(
|
||||||
|
top: Constant.getActualYPhone(context: context, y: 30)),
|
||||||
|
child: Scaffold(
|
||||||
|
backgroundColor: Constant.textWhite,
|
||||||
|
appBar: AppBar(
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
shadowColor: Colors.white,
|
||||||
|
surfaceTintColor: Colors.white,
|
||||||
|
scrolledUnderElevation: 0,
|
||||||
|
elevation: 0,
|
||||||
|
leading: Container(
|
||||||
|
child: IconButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
icon: Icon(Icons.arrow_back_ios_new_rounded)),
|
||||||
|
),
|
||||||
|
centerTitle: true,
|
||||||
|
title: Text(
|
||||||
|
"Detail",
|
||||||
|
style: Constant.title_screen(context: context),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
body: loading.value
|
||||||
|
? Center(
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
)
|
||||||
|
: Container(
|
||||||
|
color: Colors.white,
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal:
|
||||||
|
Constant.getActualXPhone(context: context, x: 20)),
|
||||||
|
child: RefreshIndicator(
|
||||||
|
onRefresh: () async {
|
||||||
|
init();
|
||||||
|
},
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
height: Constant.getActualYPhone(
|
||||||
|
context: context, y: 36),
|
||||||
|
),
|
||||||
|
if (data.value.statusID == "1" ||
|
||||||
|
data.value.statusID == "2")
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Spacer(),
|
||||||
|
if (data.value.statusID == "1")
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
color: Constant.bgGreen),
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: Constant.getActualXPhone(
|
||||||
|
context: context, x: 8),
|
||||||
|
vertical: Constant.getActualYPhone(
|
||||||
|
context: context, y: 2)),
|
||||||
|
child: Text(
|
||||||
|
"Approve",
|
||||||
|
style: Constant.body_12(context: context)
|
||||||
|
.copyWith(
|
||||||
|
color: Constant.primaryGreen),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (data.value.statusID == "2")
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
color: Constant.bgRed),
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: Constant.getActualXPhone(
|
||||||
|
context: context, x: 8),
|
||||||
|
vertical: Constant.getActualYPhone(
|
||||||
|
context: context, y: 2)),
|
||||||
|
child: Text(
|
||||||
|
"Reject",
|
||||||
|
style: Constant.body_12(context: context)
|
||||||
|
.copyWith(color: Constant.primaryRed),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
if (data.value.statusID == "1" ||
|
||||||
|
data.value.statusID == "2")
|
||||||
|
SizedBox(
|
||||||
|
height: Constant.getActualYPhone(
|
||||||
|
context: context, y: 8),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
margin: EdgeInsets.only(bottom: 8),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
flex: 4,
|
||||||
|
child: Text("Nama : ",
|
||||||
|
style: Constant.body_16(context: context)
|
||||||
|
.copyWith(
|
||||||
|
color: Constant.textDarkGrey,
|
||||||
|
fontWeight: FontWeight.w400)),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
flex: 9,
|
||||||
|
child: Text(data.value.name ?? "",
|
||||||
|
style: Constant.body_16(context: context)
|
||||||
|
.copyWith(
|
||||||
|
fontWeight: FontWeight.w400)),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
margin: EdgeInsets.only(bottom: 8),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
flex: 4,
|
||||||
|
child: Text("NIP : ",
|
||||||
|
style: Constant.body_16(context: context)
|
||||||
|
.copyWith(
|
||||||
|
color: Constant.textDarkGrey,
|
||||||
|
fontWeight: FontWeight.w400)),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
flex: 9,
|
||||||
|
child: Text(data.value.nip ?? "",
|
||||||
|
style: Constant.body_16(context: context)
|
||||||
|
.copyWith(
|
||||||
|
fontWeight: FontWeight.w400)),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
margin: EdgeInsets.only(bottom: 8),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
flex: 4,
|
||||||
|
child: Text("Tanggal : ",
|
||||||
|
style: Constant.body_16(context: context)
|
||||||
|
.copyWith(
|
||||||
|
color: Constant.textDarkGrey,
|
||||||
|
fontWeight: FontWeight.w400)),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
flex: 9,
|
||||||
|
child: Text(data.value.date ?? "",
|
||||||
|
style: Constant.body_16(context: context)
|
||||||
|
.copyWith(
|
||||||
|
fontWeight: FontWeight.w400)),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
margin: EdgeInsets.only(bottom: 8),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
flex: 4,
|
||||||
|
child: Text("Jam : ",
|
||||||
|
style: Constant.body_16(context: context)
|
||||||
|
.copyWith(
|
||||||
|
color: Constant.textDarkGrey,
|
||||||
|
fontWeight: FontWeight.w400)),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
flex: 9,
|
||||||
|
child: Text(data.value.time ?? "",
|
||||||
|
style: Constant.body_16(context: context)
|
||||||
|
.copyWith(
|
||||||
|
fontWeight: FontWeight.w400)),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
margin: EdgeInsets.only(bottom: 8),
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
flex: 4,
|
||||||
|
child: Text("Alamat : ",
|
||||||
|
style: Constant.body_16(context: context)
|
||||||
|
.copyWith(
|
||||||
|
color: Constant.textDarkGrey,
|
||||||
|
fontWeight: FontWeight.w400)),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
flex: 9,
|
||||||
|
child: Text(data.value.address ?? "",
|
||||||
|
style: Constant.body_16(context: context)
|
||||||
|
.copyWith(
|
||||||
|
fontWeight: FontWeight.w400)),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
margin: EdgeInsets.only(top: 16),
|
||||||
|
width: MediaQuery.of(context).size.width,
|
||||||
|
height: Constant.getActualYPhone(
|
||||||
|
context: context, y: 400),
|
||||||
|
child: FlutterMap(
|
||||||
|
options: MapOptions(
|
||||||
|
center: LatLng(data.value.lat ?? 0,
|
||||||
|
data.value.long ?? 0),
|
||||||
|
zoom: 16,
|
||||||
|
),
|
||||||
|
children: [
|
||||||
|
TileLayer(
|
||||||
|
urlTemplate:
|
||||||
|
'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||||
|
userAgentPackageName: 'com.example.app',
|
||||||
|
),
|
||||||
|
MarkerLayer(
|
||||||
|
markers: [
|
||||||
|
Marker(
|
||||||
|
point: LatLng(-7.539538, 110.798357),
|
||||||
|
child: const Icon(
|
||||||
|
Icons.location_on,
|
||||||
|
color: Colors.red,
|
||||||
|
size: 50,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
// Marker(
|
||||||
|
// point: LatLng(lat, long),
|
||||||
|
// width: 100,
|
||||||
|
// height: 100,
|
||||||
|
// builder: (context) => const Icon(
|
||||||
|
// Icons.location_on,
|
||||||
|
// color: Colors.red,
|
||||||
|
// size: 50,
|
||||||
|
// )),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
if (data.value.imagePath != "" &&
|
||||||
|
data.value.imagePath != null)
|
||||||
|
Container(
|
||||||
|
margin: EdgeInsets.only(top: 16, bottom: 48),
|
||||||
|
child: Image.network(
|
||||||
|
data.value.imagePath!,
|
||||||
|
errorBuilder: (context, error, stackTrace) {
|
||||||
|
return Text(
|
||||||
|
"Error load image : ${error.toString()}",
|
||||||
|
style: Constant.body_12(context: context)
|
||||||
|
.copyWith(color: Constant.primaryRed),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
loadingBuilder:
|
||||||
|
(context, child, loadingProgress) {
|
||||||
|
if (loadingProgress == null) return child;
|
||||||
|
return Container(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Text(loadingProgress.expectedTotalBytes !=
|
||||||
|
null
|
||||||
|
? ((loadingProgress.cumulativeBytesLoaded /
|
||||||
|
loadingProgress
|
||||||
|
.expectedTotalBytes!) *
|
||||||
|
100)
|
||||||
|
.round()
|
||||||
|
.toString() +
|
||||||
|
" %"
|
||||||
|
: ""),
|
||||||
|
LinearProgressIndicator(
|
||||||
|
value: loadingProgress
|
||||||
|
.expectedTotalBytes !=
|
||||||
|
null
|
||||||
|
? loadingProgress
|
||||||
|
.cumulativeBytesLoaded /
|
||||||
|
loadingProgress
|
||||||
|
.expectedTotalBytes!
|
||||||
|
: null,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (data.value.statusID != "1" &&
|
||||||
|
data.value.statusID != "2")
|
||||||
|
Container(
|
||||||
|
margin: EdgeInsets.symmetric(vertical: 24),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: CustomButtonWhite(
|
||||||
|
btnText: "Reject",
|
||||||
|
onPressed: () {
|
||||||
|
ApprovalDialogConfirmation(
|
||||||
|
context: context,
|
||||||
|
typename: "presensi ",
|
||||||
|
textInformation: "menolak ",
|
||||||
|
staffName: data.value.name ?? "",
|
||||||
|
confirmFunc: () {});
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: Constant.getActualXPhone(
|
||||||
|
context: context, x: 24),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: CustomButtonOrange(
|
||||||
|
btnText: "Approve",
|
||||||
|
onPressed: () {
|
||||||
|
ApprovalDialogConfirmation(
|
||||||
|
context: context,
|
||||||
|
typename: "presensi ",
|
||||||
|
textInformation: "menyetujui ",
|
||||||
|
staffName: data.value.name ?? "",
|
||||||
|
confirmFunc: () {});
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ import 'package:geolocator/geolocator.dart';
|
|||||||
import 'package:google_sign_in/google_sign_in.dart';
|
import 'package:google_sign_in/google_sign_in.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:permission_handler/permission_handler.dart';
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
|
import 'package:fluentui_system_icons/fluentui_system_icons.dart';
|
||||||
|
|
||||||
import '../../app/route.dart';
|
import '../../app/route.dart';
|
||||||
import '../../provider/current_check_distance_provider.dart';
|
import '../../provider/current_check_distance_provider.dart';
|
||||||
@@ -720,6 +721,69 @@ class HomeScreen extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: Constant.getActualXPhone(
|
||||||
|
context: context, x: 18),
|
||||||
|
),
|
||||||
|
|
||||||
|
//Menu
|
||||||
|
Container(
|
||||||
|
width: Constant.getActualXPhone(
|
||||||
|
context: context, x: 98),
|
||||||
|
// color: Colors.amber,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Color.fromRGBO(145, 158, 171, 0.20),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.only(
|
||||||
|
left: Constant.getActualXPhone(
|
||||||
|
context: context, x: 12),
|
||||||
|
right: Constant.getActualXPhone(
|
||||||
|
context: context, x: 12),
|
||||||
|
top: Constant.getActualYPhone(
|
||||||
|
context: context, y: 8),
|
||||||
|
bottom: Constant.getActualYPhone(
|
||||||
|
context: context, y: 8),
|
||||||
|
),
|
||||||
|
child: InkWell(
|
||||||
|
onTap: () {
|
||||||
|
Navigator.pushNamed(context, approvalRoute);
|
||||||
|
},
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
child: Image(
|
||||||
|
width: Constant.getActualXPhone(
|
||||||
|
context: context, x: 50),
|
||||||
|
height: Constant.getActualYPhone(
|
||||||
|
context: context, y: 50),
|
||||||
|
image: AssetImage(
|
||||||
|
'images/btn_approval.png'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: Constant.getActualYPhone(
|
||||||
|
context: context, y: 8),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'Approval',
|
||||||
|
style: Constant.titleH2_600_14(
|
||||||
|
context: context)
|
||||||
|
.copyWith(
|
||||||
|
color: Constant.textDarkGrey,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -790,7 +854,9 @@ class HomeScreen extends HookConsumerWidget {
|
|||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
// '24 hari',
|
// '24 hari',
|
||||||
varCurrentRekapKehadiranProvider?.kehadiran ?? "",
|
varCurrentRekapKehadiranProvider
|
||||||
|
?.kehadiran ??
|
||||||
|
"",
|
||||||
style: Constant.subtitle_600_14(
|
style: Constant.subtitle_600_14(
|
||||||
context: context)
|
context: context)
|
||||||
.copyWith(
|
.copyWith(
|
||||||
|
|||||||
77
lib/widget/custom_button_approval.dart
Normal file
77
lib/widget/custom_button_approval.dart
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
import 'package:absensi_sas/app/constant.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class CustomButtonOrange extends StatelessWidget {
|
||||||
|
const CustomButtonOrange({super.key, required this.btnText, this.onPressed});
|
||||||
|
final Function()? onPressed;
|
||||||
|
final String btnText;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Constant.textOrange.withOpacity(0.24),
|
||||||
|
spreadRadius: 0,
|
||||||
|
blurRadius: 16,
|
||||||
|
offset: Offset(0, 8), // changes position of shadow
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
child: ElevatedButton(
|
||||||
|
style: ButtonStyle(
|
||||||
|
elevation: MaterialStatePropertyAll(0),
|
||||||
|
shape: MaterialStatePropertyAll(RoundedRectangleBorder(
|
||||||
|
side: BorderSide(
|
||||||
|
color: Constant.textOrange,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(8))),
|
||||||
|
backgroundColor: MaterialStateProperty.resolveWith((states) {
|
||||||
|
return Constant.textOrange;
|
||||||
|
}),
|
||||||
|
overlayColor:
|
||||||
|
MaterialStatePropertyAll(Colors.white.withOpacity(0.3)),
|
||||||
|
foregroundColor: MaterialStatePropertyAll(Constant.textOrange),
|
||||||
|
shadowColor: MaterialStatePropertyAll(Constant.textOrange),
|
||||||
|
surfaceTintColor: MaterialStatePropertyAll(Constant.textOrange)),
|
||||||
|
onPressed: onPressed,
|
||||||
|
child: Text(
|
||||||
|
btnText,
|
||||||
|
style: Constant.body_14(context: context)
|
||||||
|
.copyWith(color: Colors.white, fontWeight: FontWeight.w700),
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CustomButtonWhite extends StatelessWidget {
|
||||||
|
const CustomButtonWhite({super.key, required this.btnText, this.onPressed});
|
||||||
|
final Function()? onPressed;
|
||||||
|
final String btnText;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ElevatedButton(
|
||||||
|
onPressed: onPressed,
|
||||||
|
child: Text(
|
||||||
|
btnText,
|
||||||
|
style: Constant.body_14(context: context)
|
||||||
|
.copyWith(color: Colors.black, fontWeight: FontWeight.w700),
|
||||||
|
),
|
||||||
|
style: ButtonStyle(
|
||||||
|
elevation: MaterialStatePropertyAll(0),
|
||||||
|
shape: MaterialStatePropertyAll(RoundedRectangleBorder(
|
||||||
|
side: BorderSide(
|
||||||
|
color: Colors.grey.shade300,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(8))),
|
||||||
|
backgroundColor: MaterialStateProperty.resolveWith((states) {
|
||||||
|
return Colors.white;
|
||||||
|
}),
|
||||||
|
overlayColor:
|
||||||
|
MaterialStatePropertyAll(Constant.textOrange.withOpacity(0.48)),
|
||||||
|
foregroundColor: MaterialStatePropertyAll(Colors.white),
|
||||||
|
shadowColor: MaterialStatePropertyAll(Colors.white),
|
||||||
|
surfaceTintColor: MaterialStatePropertyAll(Colors.white)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
98
pubspec.lock
98
pubspec.lock
@@ -93,10 +93,18 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: collection
|
name: collection
|
||||||
sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c"
|
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.17.1"
|
version: "1.18.0"
|
||||||
|
colorful_iconify_flutter:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: colorful_iconify_flutter
|
||||||
|
sha256: "5ebc63d10c3e97279849162b415fda8e71b7ff24ddd663539d7328279dae9c1d"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.0.2"
|
||||||
convert:
|
convert:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -161,6 +169,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.5"
|
version: "2.0.5"
|
||||||
|
eva_icons_flutter:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: eva_icons_flutter
|
||||||
|
sha256: "6d48a10b93590ab83eb092bee5adacdeb14f3d83f527a4b9e4092c363d56e2a8"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.0"
|
||||||
fake_async:
|
fake_async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -225,6 +241,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.9.3+1"
|
version: "0.9.3+1"
|
||||||
|
fluentui_system_icons:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: fluentui_system_icons
|
||||||
|
sha256: abe7c343e2151e0ad6544653e0b6601686b993bc436ccde72b88cea677db0c0a
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.226"
|
||||||
flutter:
|
flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
@@ -278,6 +302,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.4"
|
version: "1.0.4"
|
||||||
|
flutter_svg:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_svg
|
||||||
|
sha256: "6ff9fa12892ae074092de2fa6a9938fb21dbabfdaa2ff57dc697ff912fc8d4b2"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.6"
|
||||||
flutter_test:
|
flutter_test:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description: flutter
|
description: flutter
|
||||||
@@ -528,6 +560,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.2"
|
version: "4.0.2"
|
||||||
|
iconify_flutter:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: iconify_flutter
|
||||||
|
sha256: a2d5d36a8381331c8d4e0a6b71378fca51bd6d15e38192568a30c0a91133a9af
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.0.5"
|
||||||
image:
|
image:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -660,26 +700,26 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: matcher
|
name: matcher
|
||||||
sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb"
|
sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.12.15"
|
version: "0.12.16"
|
||||||
material_color_utilities:
|
material_color_utilities:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: material_color_utilities
|
name: material_color_utilities
|
||||||
sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724
|
sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.0"
|
version: "0.5.0"
|
||||||
meta:
|
meta:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: meta
|
name: meta
|
||||||
sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
|
sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.9.1"
|
version: "1.10.0"
|
||||||
mgrs_dart:
|
mgrs_dart:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -736,6 +776,22 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.8.3"
|
version: "1.8.3"
|
||||||
|
path_drawing:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_drawing
|
||||||
|
sha256: bbb1934c0cbb03091af082a6389ca2080345291ef07a5fa6d6e078ba8682f977
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.1"
|
||||||
|
path_parsing:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_parsing
|
||||||
|
sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.1"
|
||||||
path_provider:
|
path_provider:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -977,10 +1033,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: source_span
|
name: source_span
|
||||||
sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250
|
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.9.1"
|
version: "1.10.0"
|
||||||
sprintf:
|
sprintf:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -993,10 +1049,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: stack_trace
|
name: stack_trace
|
||||||
sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
|
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.11.0"
|
version: "1.11.1"
|
||||||
state_notifier:
|
state_notifier:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1009,10 +1065,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: stream_channel
|
name: stream_channel
|
||||||
sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
|
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "2.1.2"
|
||||||
string_scanner:
|
string_scanner:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1033,10 +1089,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb
|
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.1"
|
version: "0.6.1"
|
||||||
top_snackbar_flutter:
|
top_snackbar_flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -1125,6 +1181,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0"
|
version: "1.1.0"
|
||||||
|
web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: web
|
||||||
|
sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.3.0"
|
||||||
web_socket_channel:
|
web_socket_channel:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1174,5 +1238,5 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.2"
|
version: "3.1.2"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.0.6 <4.0.0"
|
dart: ">=3.2.0-194.0.dev <4.0.0"
|
||||||
flutter: ">=3.10.0"
|
flutter: ">=3.10.0"
|
||||||
|
|||||||
@@ -61,6 +61,9 @@ dependencies:
|
|||||||
photo_view: ^0.14.0
|
photo_view: ^0.14.0
|
||||||
mime: ^1.0.4
|
mime: ^1.0.4
|
||||||
flutter_launcher_icons: ^0.13.1
|
flutter_launcher_icons: ^0.13.1
|
||||||
|
iconify_flutter: ^0.0.5
|
||||||
|
fluentui_system_icons: ^1.1.226
|
||||||
|
eva_icons_flutter: ^3.1.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|||||||
Reference in New Issue
Block a user