Commit e8e4274e authored by Dio Maulana's avatar Dio Maulana

fixed API for onboarding and HOME view

parent bc1bc4a3
import 'dart:convert'; import 'dart:convert';
import 'package:excelso_attendance/helper/logger.dart'; import 'package:excelso_attendance/helper/logger.dart';
import 'package:excelso_attendance/helper/pref.dart';
import 'package:excelso_attendance/main.dart'; import 'package:excelso_attendance/main.dart';
import 'package:excelso_attendance/models/branch.dart'; import 'package:excelso_attendance/models/branch.dart';
import 'package:excelso_attendance/models/shift.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
String baseUrl = "";
String endPoint = "rav/attendance/";
class Api { class Api {
static Future<Map<String, dynamic>> getNearestBranch() async { static Future<ApiResponse> getNearestBranch() async {
String apiUrl = "$baseUrl${endPoint}nearest_branch_list"; String apiUrl = "$baseUrl${endPoint}nearest_branch_list";
Map<String, dynamic> result;
try { try {
dynamic jsonObject = Map<String, dynamic> data = {
await httpRequest(typePost, apiUrl, "getNearestBranch"); "brand_code": brandCode,
"user_lat": getLatitude(),
"user_long": getLongitude(),
};
String bodies = jsonEncode(data);
dynamic jsonObject = await httpRequest(
typePost, apiUrl, "getNearestBranch",
bodies: bodies);
if (jsonObject == false) { if (jsonObject == false) {
result = {"error": true, "msg": "Can't connect to server"}; return ApiResponse(error: true, msg: "Can't connect to server");
return result;
} else { } else {
List<BranchModel> branchList = []; List<BranchModel> branchList = [];
...@@ -30,20 +34,50 @@ class Api { ...@@ -30,20 +34,50 @@ class Api {
), ),
); );
} }
return ApiResponse(
result = { error: false,
"error": false, msg: "Success get data",
"msg": "Success get data", data: branchList,
"branchs": branchList, );
};
return result;
} }
} catch (e) { } catch (e) {
result = { return ApiResponse(
"error": true, error: true, msg: "Something wrong with our server, refresh page");
"msg": "Something wrong with our server, try again later" }
}
static Future<ApiResponse> getShiftList() async {
String apiUrl = "$baseUrl${endPoint}shift_list";
try {
Map<String, dynamic> data = {
"brand_code": brandCode,
}; };
return result; String bodies = jsonEncode(data);
dynamic jsonObject =
await httpRequest(typePost, apiUrl, "getShiftList", bodies: bodies);
if (jsonObject == false) {
return ApiResponse(error: true, msg: "Can't connect to server");
} else {
List<ShiftModel> shiftList = [];
List<dynamic> shift = jsonObject['data']['shift_list'];
for (int i = 0; i < shift.length; i++) {
shiftList.add(
ShiftModel.json(
shift[i],
),
);
}
return ApiResponse(
error: false,
msg: "Success get data",
data: shiftList,
);
}
} catch (e) {
return ApiResponse(
error: true, msg: "Something wrong with our server, refresh page");
} }
} }
} }
...@@ -79,3 +113,15 @@ Future<dynamic> httpRequest(int typeRequest, String apiUrl, String namaFungsi, ...@@ -79,3 +113,15 @@ Future<dynamic> httpRequest(int typeRequest, String apiUrl, String namaFungsi,
return false; return false;
} }
} }
class ApiResponse {
bool error;
String msg;
dynamic data;
ApiResponse({
required this.error,
required this.msg,
this.data,
});
}
import 'package:excelso_attendance/models/branch.dart';
import 'package:excelso_attendance/models/shift.dart';
class AbsentCameraArguments { class AbsentCameraArguments {
final bool isIn; final bool isIn;
final String outletName; final BranchModel branchModel;
final ShiftModel? shiftModel;
AbsentCameraArguments({ AbsentCameraArguments({
required this.isIn, required this.isIn,
required this.outletName, required this.branchModel,
this.shiftModel,
});
}
class HomeArguments {
final List<BranchModel> branchModel;
final List<ShiftModel> shiftModel;
HomeArguments({
required this.branchModel,
required this.shiftModel,
}); });
} }
class DateFormatCustom { class DateFormatCustom {
static String monthLocal(String month) { static String monthLocal(String m) {
String month;
if (m.length == 1) {
month = "0$m";
} else {
month = m;
}
switch (month) { switch (month) {
case "01": case "01":
return "Januari"; return "Januari";
...@@ -44,24 +50,41 @@ class DateFormatCustom { ...@@ -44,24 +50,41 @@ class DateFormatCustom {
} }
} }
static String getLocalTime({bool timeZoneActive = false}) { static String getLocalTime(
{bool timeZoneActive = false, bool secondActive = false}) {
DateTime localTime = DateTime.now().toLocal(); DateTime localTime = DateTime.now().toLocal();
int hour = localTime.hour; int hour = localTime.hour;
String min = localTime.minute.toString(); String min = localTime.minute.toString();
String second = localTime.second.toString();
String minute; String minute;
String sec;
if (min.length == 1) { if (min.length == 1) {
minute = "0$min"; minute = "0$min";
} else { } else {
minute = min; minute = min;
} }
if (second.length == 1) {
sec = "0$second";
} else {
sec = second;
}
// int sec = localTime.second; // int sec = localTime.second;
String timeZone = localTimeZoneName(localTime.timeZoneOffset.toString()); String timeZone = localTimeZoneName(localTime.timeZoneOffset.toString());
String result; String result;
if (timeZoneActive) { if (timeZoneActive) {
result = "$hour : $minute $timeZone"; if (secondActive) {
result = "$hour : $minute : $sec $timeZone";
} else {
result = "$hour : $minute $timeZone";
}
} else { } else {
result = "$hour : $minute"; if (secondActive) {
result = "$hour : $minute : $sec";
} else {
result = "$hour : $minute";
}
} }
return result; return result;
...@@ -76,4 +99,13 @@ class DateFormatCustom { ...@@ -76,4 +99,13 @@ class DateFormatCustom {
String result = "$day $month $year"; String result = "$day $month $year";
return result; return result;
} }
static String getTimeHourMinuteOnly(String time) {
// awalnya dari API 00:00:00, balikin 00:00 ke UI
List<String> timeSplit = time.split(":");
String result;
result = "${timeSplit[0]} : ${timeSplit[1]}";
return result;
}
} }
...@@ -4,9 +4,16 @@ import 'package:flutter_easyloading/flutter_easyloading.dart'; ...@@ -4,9 +4,16 @@ import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:url_strategy/url_strategy.dart'; import 'package:url_strategy/url_strategy.dart';
// all config here
bool debug = true; bool debug = true;
late SharedPreferences prefs; late SharedPreferences prefs;
String titleApp = 'Excelso Attendances'; String titleApp = 'Excelso Attendances';
String brandCode = "EXC";
String baseUrl = "https://hibiscus-dev.ravku.com/";
String endPoint = "rav/attendance/";
// final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>(); // final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
void main() async { void main() async {
......
...@@ -2,11 +2,13 @@ class BranchModel { ...@@ -2,11 +2,13 @@ class BranchModel {
String id; String id;
String code; String code;
String name; String name;
double distance;
BranchModel({ BranchModel({
required this.id, required this.id,
required this.code, required this.code,
required this.name, required this.name,
required this.distance,
}); });
factory BranchModel.json(Map<String, dynamic> json) { factory BranchModel.json(Map<String, dynamic> json) {
...@@ -14,6 +16,7 @@ class BranchModel { ...@@ -14,6 +16,7 @@ class BranchModel {
id: json['id'], id: json['id'],
code: json['code'], code: json['code'],
name: json['name'], name: json['name'],
distance: json['distance'],
); );
} }
} }
...@@ -5,6 +5,8 @@ import 'dart:io'; ...@@ -5,6 +5,8 @@ import 'dart:io';
import 'package:excelso_attendance/helper/arguments/error_args.dart'; import 'package:excelso_attendance/helper/arguments/error_args.dart';
import 'package:excelso_attendance/helper/widget_responsive.dart'; import 'package:excelso_attendance/helper/widget_responsive.dart';
import 'package:excelso_attendance/main.dart'; import 'package:excelso_attendance/main.dart';
import 'package:excelso_attendance/models/branch.dart';
import 'package:excelso_attendance/models/shift.dart';
import 'package:excelso_attendance/resource/routes.dart'; import 'package:excelso_attendance/resource/routes.dart';
import 'package:excelso_attendance/resource/strings.dart'; import 'package:excelso_attendance/resource/strings.dart';
import 'package:flutter/foundation.dart' show kIsWeb; import 'package:flutter/foundation.dart' show kIsWeb;
...@@ -21,11 +23,16 @@ import 'package:excelso_attendance/resource/style.dart'; ...@@ -21,11 +23,16 @@ import 'package:excelso_attendance/resource/style.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class AbsentCameraView extends StatefulWidget { class AbsentCameraView extends StatefulWidget {
const AbsentCameraView( const AbsentCameraView({
{super.key, required this.outletName, required this.isIn}); super.key,
required this.isIn,
required this.branchModel,
this.shiftModel,
});
final String outletName;
final bool isIn; final bool isIn;
final BranchModel branchModel;
final ShiftModel? shiftModel;
@override @override
State<AbsentCameraView> createState() => _AbsentCameraViewState(); State<AbsentCameraView> createState() => _AbsentCameraViewState();
...@@ -229,7 +236,7 @@ class _AbsentCameraViewState extends State<AbsentCameraView> { ...@@ -229,7 +236,7 @@ class _AbsentCameraViewState extends State<AbsentCameraView> {
), ),
WidgetAbsentAndTime( WidgetAbsentAndTime(
isIn: widget.isIn, isIn: widget.isIn,
outletName: widget.outletName, outletName: widget.branchModel.code,
), ),
const Spacer(), const Spacer(),
(pictureIsTaken) (pictureIsTaken)
...@@ -258,6 +265,14 @@ class _AbsentCameraViewState extends State<AbsentCameraView> { ...@@ -258,6 +265,14 @@ class _AbsentCameraViewState extends State<AbsentCameraView> {
onTap: () { onTap: () {
setState(() { setState(() {
pictureIsTaken = false; pictureIsTaken = false;
_controller = CameraController(
// Get a specific camera from the list of available cameras.
_cameraDescription!,
// Define the resolution to use.
ResolutionPreset.medium,
);
_initializeControllerFuture =
_controller!.initialize();
}); });
}, },
child: CustomButton( child: CustomButton(
...@@ -507,13 +522,17 @@ class _WidgetAbsentAndTimeState extends State<WidgetAbsentAndTime> { ...@@ -507,13 +522,17 @@ class _WidgetAbsentAndTimeState extends State<WidgetAbsentAndTime> {
fontFamily: FontConstants.poppins, fontFamily: FontConstants.poppins,
), ),
), ),
Text( Expanded(
"${widget.outletName} - ${DateFormatCustom.getLocalTime( child: Text(
timeZoneActive: true, "${widget.outletName} - ${DateFormatCustom.getLocalTime(
)}", timeZoneActive: true,
style: getSemiBoldStyle( )}",
color: Colors.black, style: getSemiBoldStyle(
fontSize: FontSize.s24, color: Colors.black,
fontSize: FontSize.s24,
),
maxLines: 3,
overflow: TextOverflow.ellipsis,
), ),
), ),
], ],
......
import 'package:autocomplete_textfield/autocomplete_textfield.dart'; import 'dart:async';
import 'package:excelso_attendance/helper/arguments/route_args.dart'; import 'package:excelso_attendance/helper/arguments/route_args.dart';
import 'package:excelso_attendance/helper/component/button.dart'; import 'package:excelso_attendance/helper/component/button.dart';
import 'package:excelso_attendance/helper/component/text_field.dart'; import 'package:excelso_attendance/helper/component/text_field.dart';
import 'package:excelso_attendance/helper/global_function/date_time.dart';
import 'package:excelso_attendance/helper/widget_responsive.dart'; import 'package:excelso_attendance/helper/widget_responsive.dart';
import 'package:excelso_attendance/models/branch.dart';
import 'package:excelso_attendance/models/shift.dart';
import 'package:excelso_attendance/resource/assets.dart'; import 'package:excelso_attendance/resource/assets.dart';
import 'package:excelso_attendance/resource/colors.dart'; import 'package:excelso_attendance/resource/colors.dart';
import 'package:excelso_attendance/resource/font.dart'; import 'package:excelso_attendance/resource/font.dart';
...@@ -10,16 +14,24 @@ import 'package:excelso_attendance/resource/routes.dart'; ...@@ -10,16 +14,24 @@ import 'package:excelso_attendance/resource/routes.dart';
import 'package:excelso_attendance/resource/size.dart'; import 'package:excelso_attendance/resource/size.dart';
import 'package:excelso_attendance/resource/style.dart'; import 'package:excelso_attendance/resource/style.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
class HomeView extends StatelessWidget { class HomeView extends StatelessWidget {
const HomeView({super.key}); const HomeView(
{super.key, required this.nearestBranch, required this.shiftList});
final List<BranchModel> nearestBranch;
final List<ShiftModel> shiftList;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
backgroundColor: ColorManager.backgroundColor, backgroundColor: ColorManager.backgroundColor,
body: ScreenResponsive( body: ScreenResponsive(
widget: const BodyWidget(), widget: BodyWidget(
nearestBranch: nearestBranch,
shiftList: shiftList,
),
widthScreen: MediaQuery.of(context).size.width, widthScreen: MediaQuery.of(context).size.width,
), ),
); );
...@@ -29,18 +41,20 @@ class HomeView extends StatelessWidget { ...@@ -29,18 +41,20 @@ class HomeView extends StatelessWidget {
class BodyWidget extends StatefulWidget { class BodyWidget extends StatefulWidget {
const BodyWidget({ const BodyWidget({
super.key, super.key,
required this.nearestBranch,
required this.shiftList,
}); });
final List<BranchModel> nearestBranch;
final List<ShiftModel> shiftList;
@override @override
State<BodyWidget> createState() => _BodyWidgetState(); State<BodyWidget> createState() => _BodyWidgetState();
} }
class _BodyWidgetState extends State<BodyWidget> { class _BodyWidgetState extends State<BodyWidget> {
final List<String> suggestion = const ["TEST", "TEST2", "ABC"];
final GlobalKey<AutoCompleteTextFieldState<String>> autoCompleteKey =
GlobalKey();
final TextEditingController nikController = TextEditingController(); final TextEditingController nikController = TextEditingController();
int selectedOutlet = 0;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
...@@ -110,98 +124,11 @@ class _BodyWidgetState extends State<BodyWidget> { ...@@ -110,98 +124,11 @@ class _BodyWidgetState extends State<BodyWidget> {
child: const TimerWidget(), child: const TimerWidget(),
), ),
), ),
Container( SelectOutlet(
margin: EdgeInsets.only( nearestBranch: widget.nearestBranch,
top: AppMargin.m16, onSelected: ((int val) {
left: AppMargin.m20, selectedOutlet = val;
right: AppMargin.m20, }),
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
border: Border.all(
width: 0.2,
color: Colors.grey,
),
color: ColorManager.backgroundColor,
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.3),
blurRadius: 2,
offset: const Offset(5, 5),
),
],
),
child: Container(
width: double.infinity,
padding: EdgeInsets.all(
AppPadding.p15,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Pilih Outlet",
style: getSemiBoldStyle(
color: Colors.black,
fontSize: 16,
),
),
GestureDetector(
onTap: () {
showModalBottomSheet(
backgroundColor: ColorManager.backgroundColor,
isScrollControlled: true,
context: context,
builder: (c) {
return const WidgetSelectOutlet();
});
},
child: Container(
margin: const EdgeInsets.only(
top: 10,
),
width: double.infinity,
decoration: BoxDecoration(
border:
Border.all(width: 0.2, color: Colors.grey),
borderRadius: BorderRadius.circular(5),
color: ColorManager.backgroundColor,
),
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 15,
),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
"CPM",
style: getRegularStyle(
color: ColorManager.grey,
fontSize: 16,
),
),
Icon(
Icons.arrow_drop_down,
color: ColorManager.grey,
size: 30,
),
// Text(
// "Ubah",
// style: getRegularStyle(
// color: ColorManager.link,
// ),
// )
],
),
),
),
),
],
),
),
), ),
Container( Container(
margin: EdgeInsets.only( margin: EdgeInsets.only(
...@@ -299,13 +226,23 @@ class _BodyWidgetState extends State<BodyWidget> { ...@@ -299,13 +226,23 @@ class _BodyWidgetState extends State<BodyWidget> {
child: CustomButton( child: CustomButton(
text: "Masuk", text: "Masuk",
onTap: () { onTap: () {
showModalBottomSheet( if (nikController.text.isEmpty) {
backgroundColor: ColorManager.backgroundColor, EasyLoading.showToast(
isScrollControlled: true, "Silakan isi NIK terlebih dahulu",
context: context, );
builder: (c) { } else {
return const WidgetSelectShift(); showModalBottomSheet(
}); backgroundColor: ColorManager.backgroundColor,
isScrollControlled: true,
context: context,
builder: (c) {
return WidgetSelectShift(
shiftList: widget.shiftList,
branchModel:
widget.nearestBranch[selectedOutlet],
);
});
}
}, },
)), )),
SizedBox( SizedBox(
...@@ -315,12 +252,21 @@ class _BodyWidgetState extends State<BodyWidget> { ...@@ -315,12 +252,21 @@ class _BodyWidgetState extends State<BodyWidget> {
child: CustomButton( child: CustomButton(
text: "Keluar", text: "Keluar",
onTap: () { onTap: () {
Navigator.pushNamed( if (nikController.text.isEmpty) {
context, EasyLoading.showToast(
Routes.absentCamera, "Silakan isi NIK terlebih dahulu",
arguments: AbsentCameraArguments( );
isIn: false, outletName: "CRM"), } else {
); Navigator.pushNamed(
context,
Routes.absentCamera,
arguments: AbsentCameraArguments(
isIn: false,
branchModel:
widget.nearestBranch[selectedOutlet],
),
);
}
}, },
), ),
), ),
...@@ -336,19 +282,155 @@ class _BodyWidgetState extends State<BodyWidget> { ...@@ -336,19 +282,155 @@ class _BodyWidgetState extends State<BodyWidget> {
} }
} }
class SelectOutlet extends StatefulWidget {
const SelectOutlet({
super.key,
required this.nearestBranch,
this.onSelected,
});
final List<BranchModel> nearestBranch;
final void Function(int)? onSelected;
@override
State<SelectOutlet> createState() => _SelectOutletState();
}
class _SelectOutletState extends State<SelectOutlet> {
int selectedBranchFromList = 0;
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.only(
top: AppMargin.m16,
left: AppMargin.m20,
right: AppMargin.m20,
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
border: Border.all(
width: 0.2,
color: Colors.grey,
),
color: ColorManager.backgroundColor,
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.3),
blurRadius: 2,
offset: const Offset(5, 5),
),
],
),
child: Container(
width: double.infinity,
padding: EdgeInsets.all(
AppPadding.p15,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Pilih Outlet",
style: getSemiBoldStyle(
color: Colors.black,
fontSize: 16,
),
),
GestureDetector(
onTap: () {
showModalBottomSheet(
backgroundColor: ColorManager.backgroundColor,
isScrollControlled: true,
context: context,
builder: (c) {
return WidgetSelectOutlet(
nearestBranch: widget.nearestBranch,
selectedOutlet: selectedBranchFromList,
onSelected: ((int val) {
setState(() {
selectedBranchFromList = val;
widget.onSelected!(val);
});
}),
);
});
},
child: Container(
margin: const EdgeInsets.only(
top: 10,
),
width: double.infinity,
decoration: BoxDecoration(
border: Border.all(width: 0.2, color: Colors.grey),
borderRadius: BorderRadius.circular(5),
color: ColorManager.backgroundColor,
),
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 15,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text(
"${widget.nearestBranch[selectedBranchFromList].name} (${widget.nearestBranch[selectedBranchFromList].code})",
style: getRegularStyle(
color: ColorManager.grey,
fontSize: 16,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
),
Icon(
Icons.arrow_drop_down,
color: ColorManager.grey,
size: 30,
),
// Text(
// "Ubah",
// style: getRegularStyle(
// color: ColorManager.link,
// ),
// )
],
),
),
),
),
],
),
),
);
}
}
class WidgetSelectOutlet extends StatefulWidget { class WidgetSelectOutlet extends StatefulWidget {
const WidgetSelectOutlet({ const WidgetSelectOutlet({
Key? key, Key? key,
this.onSelected, this.onSelected,
required this.nearestBranch,
required this.selectedOutlet,
}) : super(key: key); }) : super(key: key);
final void Function()? onSelected; final void Function(int val)? onSelected;
final List<BranchModel> nearestBranch;
final int selectedOutlet;
@override @override
State<WidgetSelectOutlet> createState() => _WidgetSelectOutletState(); State<WidgetSelectOutlet> createState() => _WidgetSelectOutletState();
} }
class _WidgetSelectOutletState extends State<WidgetSelectOutlet> { class _WidgetSelectOutletState extends State<WidgetSelectOutlet> {
int selectedOutlet = 0;
@override
void initState() {
selectedOutlet = widget.selectedOutlet;
super.initState();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Column( return Column(
...@@ -401,57 +483,82 @@ class _WidgetSelectOutletState extends State<WidgetSelectOutlet> { ...@@ -401,57 +483,82 @@ class _WidgetSelectOutletState extends State<WidgetSelectOutlet> {
), ),
child: ListView.builder( child: ListView.builder(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
itemCount: 5, itemCount: widget.nearestBranch.length,
itemBuilder: ((context, index) { itemBuilder: ((context, index) {
return Container( return GestureDetector(
margin: const EdgeInsets.symmetric(horizontal: 6), onTap: () {
padding: EdgeInsets.symmetric( setState(() {
horizontal: AppPadding.p10, selectedOutlet = index;
vertical: AppPadding.p14, });
), },
decoration: BoxDecoration( child: Container(
border: (index + 1 != 5) margin:
? Border( const EdgeInsets.symmetric(horizontal: 6, vertical: 3),
bottom: BorderSide( padding: EdgeInsets.symmetric(
width: 0.5, horizontal: AppPadding.p10,
color: ColorManager.grey.withOpacity(0.8), vertical: AppPadding.p14,
),
decoration: BoxDecoration(
border: (index + 1 != widget.nearestBranch.length)
? Border(
bottom: BorderSide(
width: 0.5,
color: ColorManager.grey.withOpacity(0.8),
),
)
: null,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Text(
"${widget.nearestBranch[index].name} (${widget.nearestBranch[index].code})",
style: getRegularStyle(
color: (selectedOutlet == index)
? ColorManager.link
: Colors.black,
fontSize: 20,
fontFamily: FontConstants.poppins,
), ),
) maxLines: 2,
: null, overflow: TextOverflow.ellipsis,
), ),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
"CPM ${index + 1}",
style: getRegularStyle(
color: Colors.black,
fontSize: 20,
fontFamily: FontConstants.poppins,
), ),
), const SizedBox(
Text( width: 10,
"1.2 Km",
style: getRegularStyle(
color: Colors.black,
fontSize: 12,
fontFamily: FontConstants.poppins,
), ),
) Text(
], "${widget.nearestBranch[index].distance} Km",
style: getRegularStyle(
color: (selectedOutlet == index)
? ColorManager.link
: Colors.black,
fontSize: 12,
fontFamily: FontConstants.poppins,
),
)
],
),
), ),
); );
}), }),
), ),
), ),
Container( GestureDetector(
padding: EdgeInsets.symmetric( onTap: () {
horizontal: AppPadding.p20, widget.onSelected!(selectedOutlet);
), Navigator.pop(context);
margin: EdgeInsets.symmetric(vertical: AppMargin.m16), },
child: const CustomButton( child: Container(
text: "Pilih OUtlet", padding: EdgeInsets.symmetric(
horizontal: AppPadding.p20,
),
margin: EdgeInsets.symmetric(vertical: AppMargin.m16),
child: const CustomButton(
text: "Pilih OUtlet",
),
), ),
) )
], ],
...@@ -469,19 +576,37 @@ class TimerWidget extends StatefulWidget { ...@@ -469,19 +576,37 @@ class TimerWidget extends StatefulWidget {
} }
class _TimerWidgetState extends State<TimerWidget> { class _TimerWidgetState extends State<TimerWidget> {
Timer? _timer;
@override
void initState() {
super.initState();
Timer.periodic(const Duration(seconds: 1), (timer) {
_timer = timer;
setState(() {});
});
}
@override
void dispose() {
super.dispose();
_timer?.cancel();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Column( return Column(
children: [ children: [
Text( Text(
"10 : 30", DateFormatCustom.getLocalTime(),
style: getSemiBoldStyle( style: getSemiBoldStyle(
color: Colors.white, color: Colors.white,
fontSize: 48, fontSize: 48,
), ),
), ),
Text( Text(
"30 Mei 2023", DateFormatCustom.getDateLocal(),
style: getSemiBoldStyle( style: getSemiBoldStyle(
color: Colors.white, color: Colors.white,
fontSize: 14, fontSize: 14,
...@@ -495,16 +620,20 @@ class _TimerWidgetState extends State<TimerWidget> { ...@@ -495,16 +620,20 @@ class _TimerWidgetState extends State<TimerWidget> {
class WidgetSelectShift extends StatefulWidget { class WidgetSelectShift extends StatefulWidget {
const WidgetSelectShift({ const WidgetSelectShift({
Key? key, Key? key,
this.onSelected, required this.shiftList,
required this.branchModel,
}) : super(key: key); }) : super(key: key);
final void Function()? onSelected; final List<ShiftModel> shiftList;
final BranchModel branchModel;
@override @override
State<WidgetSelectShift> createState() => _WidgetSelectShiftState(); State<WidgetSelectShift> createState() => _WidgetSelectShiftState();
} }
class _WidgetSelectShiftState extends State<WidgetSelectShift> { class _WidgetSelectShiftState extends State<WidgetSelectShift> {
int? selectedShift;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Column( return Column(
...@@ -523,7 +652,7 @@ class _WidgetSelectShiftState extends State<WidgetSelectShift> { ...@@ -523,7 +652,7 @@ class _WidgetSelectShiftState extends State<WidgetSelectShift> {
), ),
), ),
Container( Container(
height: 180, height: 300,
width: double.infinity, width: double.infinity,
margin: EdgeInsets.only( margin: EdgeInsets.only(
top: AppMargin.m20, top: AppMargin.m20,
...@@ -544,45 +673,66 @@ class _WidgetSelectShiftState extends State<WidgetSelectShift> { ...@@ -544,45 +673,66 @@ class _WidgetSelectShiftState extends State<WidgetSelectShift> {
), ),
child: ListView.builder( child: ListView.builder(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
itemCount: 3, itemCount: widget.shiftList.length,
itemBuilder: ((context, index) { itemBuilder: ((context, index) {
return Container( return GestureDetector(
margin: const EdgeInsets.symmetric(horizontal: 6), onTap: () {
padding: EdgeInsets.symmetric( setState(() {
horizontal: AppPadding.p10, selectedShift = index;
vertical: AppPadding.p14, });
), },
decoration: BoxDecoration( child: Container(
border: (index + 1 != 3) margin: const EdgeInsets.symmetric(
? Border( horizontal: 6,
bottom: BorderSide( vertical: 3,
width: 0.5, ),
color: ColorManager.grey.withOpacity(0.8), padding: EdgeInsets.symmetric(
horizontal: AppPadding.p10,
vertical: AppPadding.p14,
),
decoration: BoxDecoration(
border: (index + 1 != widget.shiftList.length)
? Border(
bottom: BorderSide(
width: 0.5,
color: ColorManager.grey.withOpacity(0.8),
),
)
: null,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Text(
widget.shiftList[index].name,
style: getRegularStyle(
color: (selectedShift == index)
? ColorManager.link
: Colors.black,
fontSize: FontSize.s16,
fontFamily: FontConstants.poppins,
), ),
) maxLines: 2,
: null, overflow: TextOverflow.ellipsis,
), ),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
"Pagi ${index + 1}",
style: getRegularStyle(
color: Colors.black,
fontSize: FontSize.s16,
fontFamily: FontConstants.poppins,
), ),
), const SizedBox(
Text( width: 10,
"08 : 00 - 16 : 00",
style: getRegularStyle(
color: Colors.black,
fontSize: FontSize.s20,
fontFamily: FontConstants.openSans,
), ),
) Text(
], "${DateFormatCustom.getTimeHourMinuteOnly(widget.shiftList[index].startTime)} - ${DateFormatCustom.getTimeHourMinuteOnly(widget.shiftList[index].endTime)}",
style: getRegularStyle(
color: (selectedShift == index)
? ColorManager.link
: Colors.black,
fontSize: FontSize.s20,
fontFamily: FontConstants.openSans,
),
)
],
),
), ),
); );
}), }),
...@@ -595,18 +745,24 @@ class _WidgetSelectShiftState extends State<WidgetSelectShift> { ...@@ -595,18 +745,24 @@ class _WidgetSelectShiftState extends State<WidgetSelectShift> {
margin: EdgeInsets.symmetric(vertical: AppMargin.m16), margin: EdgeInsets.symmetric(vertical: AppMargin.m16),
child: GestureDetector( child: GestureDetector(
onTap: () { onTap: () {
Navigator.pop(context); if (selectedShift != null) {
Navigator.pushNamed( Navigator.pop(context);
context, Navigator.pushNamed(
Routes.absentCamera, context,
arguments: AbsentCameraArguments( Routes.absentCamera,
isIn: true, arguments: AbsentCameraArguments(
outletName: "CRM", isIn: true,
), branchModel: widget.branchModel,
); shiftModel: widget.shiftList[selectedShift!],
),
);
} else {
EasyLoading.showToast("Silakan pilih shift");
}
}, },
child: const CustomButton( child: CustomButton(
text: "Pilih", text: "Pilih",
colorButton: (selectedShift == null) ? Colors.grey : null,
), ),
), ),
) )
......
import 'package:excelso_attendance/api/api.dart';
import 'package:excelso_attendance/helper/arguments/error_args.dart'; import 'package:excelso_attendance/helper/arguments/error_args.dart';
import 'package:excelso_attendance/helper/arguments/route_args.dart';
import 'package:excelso_attendance/helper/pref.dart'; import 'package:excelso_attendance/helper/pref.dart';
import 'package:excelso_attendance/helper/widget_responsive.dart'; import 'package:excelso_attendance/helper/widget_responsive.dart';
import 'package:excelso_attendance/models/branch.dart';
import 'package:excelso_attendance/models/shift.dart';
import 'package:excelso_attendance/resource/assets.dart'; import 'package:excelso_attendance/resource/assets.dart';
import 'package:excelso_attendance/resource/colors.dart'; import 'package:excelso_attendance/resource/colors.dart';
import 'package:excelso_attendance/resource/font.dart'; import 'package:excelso_attendance/resource/font.dart';
...@@ -21,10 +25,29 @@ class OnBoardingView extends StatefulWidget { ...@@ -21,10 +25,29 @@ class OnBoardingView extends StatefulWidget {
} }
class _OnBoardingViewState extends State<OnBoardingView> { class _OnBoardingViewState extends State<OnBoardingView> {
bool getAllApi = false;
String? errorMessage;
List<BranchModel> nearestBranch = [];
List<ShiftModel> shiftList = [];
@override @override
void initState() { void initState() {
super.initState(); super.initState();
getUserPermission(); getUserPermission().then((value) {
if (value) {
getNearestBranch().then((branchBool) {
if (branchBool) {
// ambil list shift kalau ada outlet
getShiftList();
} else {
// setstate aja, gausah ambil list shift karena gak ada utlet
setState(() {});
}
});
}
});
// final perm = // final perm =
// await html.window.navigator.permissions!.query({"name": "camera"}); // await html.window.navigator.permissions!.query({"name": "camera"});
// if (perm.state == "denied") { // if (perm.state == "denied") {
...@@ -35,7 +58,43 @@ class _OnBoardingViewState extends State<OnBoardingView> { ...@@ -35,7 +58,43 @@ class _OnBoardingViewState extends State<OnBoardingView> {
// } // }
} }
void getUserPermission() async { Future<bool> getNearestBranch() async {
ApiResponse getNearestBranch = await Api.getNearestBranch();
if (getNearestBranch.error) {
errorMessage = getNearestBranch.msg;
getAllApi = true;
return false;
} else {
List<BranchModel> dataBranchs =
getNearestBranch.data as List<BranchModel>;
nearestBranch = dataBranchs;
if (dataBranchs.isEmpty) {
errorMessage = Strings.noOutletArround;
getAllApi = true;
return false;
}
return true;
}
}
void getShiftList() async {
ApiResponse getShiftList = await Api.getShiftList();
setState(() {
getAllApi = true;
if (getShiftList.error) {
errorMessage = Strings.errorGetShiftList;
} else {
List<ShiftModel> dataShift = getShiftList.data as List<ShiftModel>;
shiftList = dataShift;
if (dataShift.isEmpty) {
errorMessage = Strings.errorGetShiftList;
}
}
});
}
Future<bool> getUserPermission() async {
LocationPermission permission = await Geolocator.requestPermission(); LocationPermission permission = await Geolocator.requestPermission();
if (permission == LocationPermission.always || if (permission == LocationPermission.always ||
permission == LocationPermission.whileInUse) { permission == LocationPermission.whileInUse) {
...@@ -43,6 +102,7 @@ class _OnBoardingViewState extends State<OnBoardingView> { ...@@ -43,6 +102,7 @@ class _OnBoardingViewState extends State<OnBoardingView> {
setLatitude(position.latitude.toString()); setLatitude(position.latitude.toString());
setLongitude(position.longitude.toString()); setLongitude(position.longitude.toString());
}); });
return true;
} else { } else {
// ignore: use_build_context_synchronously // ignore: use_build_context_synchronously
Navigator.pushNamedAndRemoveUntil( Navigator.pushNamedAndRemoveUntil(
...@@ -53,6 +113,7 @@ class _OnBoardingViewState extends State<OnBoardingView> { ...@@ -53,6 +113,7 @@ class _OnBoardingViewState extends State<OnBoardingView> {
errorMessage: Strings.locationNotActive, errorMessage: Strings.locationNotActive,
), ),
); );
return false;
} }
// await html.window.navigator.getUserMedia(audio: true, video: true); // await html.window.navigator.getUserMedia(audio: true, video: true);
} }
...@@ -62,7 +123,12 @@ class _OnBoardingViewState extends State<OnBoardingView> { ...@@ -62,7 +123,12 @@ class _OnBoardingViewState extends State<OnBoardingView> {
return Scaffold( return Scaffold(
backgroundColor: ColorManager.backgroundColor, backgroundColor: ColorManager.backgroundColor,
body: ScreenResponsive( body: ScreenResponsive(
widget: const BodyWidget(), widget: BodyWidget(
getAllApi: getAllApi,
errorMessage: errorMessage,
nearestBranch: nearestBranch,
shiftList: shiftList,
),
widthScreen: MediaQuery.of(context).size.width, widthScreen: MediaQuery.of(context).size.width,
), ),
); );
...@@ -72,8 +138,17 @@ class _OnBoardingViewState extends State<OnBoardingView> { ...@@ -72,8 +138,17 @@ class _OnBoardingViewState extends State<OnBoardingView> {
class BodyWidget extends StatelessWidget { class BodyWidget extends StatelessWidget {
const BodyWidget({ const BodyWidget({
super.key, super.key,
required this.getAllApi,
required this.nearestBranch,
this.errorMessage,
required this.shiftList,
}); });
final bool getAllApi;
final String? errorMessage;
final List<BranchModel> nearestBranch;
final List<ShiftModel> shiftList;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SingleChildScrollView( return SingleChildScrollView(
...@@ -157,28 +232,53 @@ dengan sekali klik''', ...@@ -157,28 +232,53 @@ dengan sekali klik''',
), ),
GestureDetector( GestureDetector(
onTap: () { onTap: () {
Navigator.pushNamed(context, Routes.home); if (getAllApi) {
Navigator.pushNamed(
context,
Routes.home,
arguments: HomeArguments(
branchModel: nearestBranch,
shiftModel: shiftList,
),
);
}
}, },
child: Container( child: Container(
margin: const EdgeInsets.only( margin: const EdgeInsets.only(
top: 60, top: 60,
), ),
padding: EdgeInsets.symmetric(
horizontal: AppPadding.p20,
),
child: Center( child: Center(
child: Container( child: (getAllApi)
width: 60, ? (errorMessage == null)
height: 60, ? Container(
decoration: BoxDecoration( width: 60,
borderRadius: BorderRadius.circular(100), height: 60,
color: ColorManager.primary, decoration: BoxDecoration(
), borderRadius: BorderRadius.circular(100),
child: const Center( color: ColorManager.primary,
child: Icon( ),
Icons.arrow_forward_ios_rounded, child: const Center(
color: Colors.white, child: Icon(
size: 23, Icons.arrow_forward_ios_rounded,
), color: Colors.white,
), size: 23,
), ),
),
)
: Text(
errorMessage!,
style: getSemiBoldStyle(
color: Colors.black,
fontSize: 16,
),
textAlign: TextAlign.center,
)
: CircularProgressIndicator(
color: ColorManager.primary,
),
), ),
), ),
), ),
......
...@@ -24,14 +24,24 @@ class RouteGenerator { ...@@ -24,14 +24,24 @@ class RouteGenerator {
return pageRouteCustom(const OnBoardingView(), return pageRouteCustom(const OnBoardingView(),
nameRoute: Routes.onBoarding); nameRoute: Routes.onBoarding);
case Routes.home: case Routes.home:
return pageRouteCustom(HomeView(), nameRoute: Routes.home); HomeArguments args = routeSettings.arguments as HomeArguments;
return pageRouteCustom(
HomeView(
nearestBranch: args.branchModel,
shiftList: args.shiftModel,
),
nameRoute: Routes.home,
routeSettings: routeSettings,
);
case Routes.absentCamera: case Routes.absentCamera:
AbsentCameraArguments args = AbsentCameraArguments args =
routeSettings.arguments as AbsentCameraArguments; routeSettings.arguments as AbsentCameraArguments;
return pageRouteCustom( return pageRouteCustom(
AbsentCameraView( AbsentCameraView(
outletName: args.outletName,
isIn: args.isIn, isIn: args.isIn,
branchModel: args.branchModel,
shiftModel: args.shiftModel,
), ),
nameRoute: Routes.absentCamera, nameRoute: Routes.absentCamera,
routeSettings: routeSettings, routeSettings: routeSettings,
...@@ -72,8 +82,9 @@ class RouteGenerator { ...@@ -72,8 +82,9 @@ class RouteGenerator {
routeSettings!.arguments as AbsentCameraArguments; routeSettings!.arguments as AbsentCameraArguments;
return PageRouteBuilder( return PageRouteBuilder(
pageBuilder: (context, a, b) => AbsentCameraView( pageBuilder: (context, a, b) => AbsentCameraView(
outletName: args.outletName,
isIn: args.isIn, isIn: args.isIn,
branchModel: args.branchModel,
shiftModel: args.shiftModel,
), ),
transitionDuration: Duration.zero, transitionDuration: Duration.zero,
reverseTransitionDuration: Duration.zero, reverseTransitionDuration: Duration.zero,
...@@ -94,6 +105,20 @@ class RouteGenerator { ...@@ -94,6 +105,20 @@ class RouteGenerator {
// name: nameRoute.replaceFirst("/", ""), arguments: args), // name: nameRoute.replaceFirst("/", ""), arguments: args),
); );
} }
if (nameRoute == Routes.home) {
HomeArguments args = routeSettings!.arguments as HomeArguments;
return PageRouteBuilder(
pageBuilder: (context, a, b) => HomeView(
nearestBranch: args.branchModel,
shiftList: args.shiftModel,
),
transitionDuration: Duration.zero,
reverseTransitionDuration: Duration.zero,
// settings: RouteSettings(
// name: nameRoute.replaceFirst("/", ""), arguments: args),
);
}
// else if (nameRoute == Routes.errorWidget) { // else if (nameRoute == Routes.errorWidget) {
// ErrorWidgetArguments args = // ErrorWidgetArguments args =
// routeSettings!.arguments as ErrorWidgetArguments; // routeSettings!.arguments as ErrorWidgetArguments;
......
...@@ -3,4 +3,8 @@ class Strings { ...@@ -3,4 +3,8 @@ class Strings {
"Silakan aktifkan permission kamera pada pengaturan browser anda"; "Silakan aktifkan permission kamera pada pengaturan browser anda";
static String locationNotActive = static String locationNotActive =
"Silakan aktifkan permission lokasi pada pengaturan browser anda"; "Silakan aktifkan permission lokasi pada pengaturan browser anda";
static String noOutletArround =
"Tidak ada outlet yang ditemukan dalam radius 10Km";
static String errorGetShiftList =
"Tidak dapat terhubung ke server, shift tidak ditemukan";
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment