first commit

This commit is contained in:
Sas Andy
2025-01-31 10:12:08 +07:00
commit 6554441a4b
180 changed files with 8490 additions and 0 deletions

View File

@@ -0,0 +1,242 @@
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:ticket_booth/app/constant.dart';
import 'package:ticket_booth/app/print_ticket.dart';
import 'package:ticket_booth/app/route.dart';
import 'package:ticket_booth/provider/all_service_provider.dart';
import 'package:ticket_booth/screen/initial/service_list_provider.dart';
import '../widgets/error_dialog.dart';
class InitialScreen extends HookConsumerWidget {
const InitialScreen({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final isLoading = useState(false);
final errorMsg = useState('');
final hostIp = useState('N');
final testPrintDisabled = useState(true);
Future getData() async {
try {
final prefs = await SharedPreferences.getInstance();
var raw_data = prefs.getString('tb-westerindo') ?? 'a';
if (raw_data != 'a') {
var data = json.decode(raw_data);
hostIp.value = data['hostIp'];
testPrintDisabled.value = false;
}
} catch (e) {
print(e);
ErrorDialog(context, e.toString(), 'ERROR');
}
}
useEffect(() {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
await getData();
if (hostIp.value != 'N') {
ref.read(ServiceListProvider.notifier).list(hostIp: hostIp.value);
}
});
// Navigator.of(context).pushNamed(queueRoute);
// final timer = Timer(const Duration(seconds: 10), () {
// });
return () {
// timer.cancel();
};
}, []);
ref.listen(ServiceListProvider, (previous, next) {
if (next is ServiceListStateLoading) {
isLoading.value = true;
} else if (next is ServiceListStateError) {
errorMsg.value = next.message;
ErrorDialog(context, errorMsg.value, 'ERROR');
} else if (next is ServiceListStateDone) {
ref.read(allServiceProvider.notifier).state = next.model;
// print(ref.read(allServiceProvider));
}
});
return Material(
child: Container(
height: Constant.getActualY(context: context, y: 982),
width: Constant.getActualX(context: context, x: 1512),
decoration: const BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
image: AssetImage("assets/images/new-bg-icon.png"))),
child: Column(
children: [
SizedBox(
height: Constant.getActualY(context: context, y: 600),
width: Constant.getActualX(context: context, x: 1512),
),
Text(
Constant.versi,
style: Constant.subTitle(context: context)
.copyWith(fontStyle: FontStyle.italic, color: Colors.grey),
),
SizedBox(
height: Constant.getActualY(context: context, y: 302),
width: Constant.getActualX(context: context, x: 1512),
child: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
style: ElevatedButton.styleFrom(
maximumSize: Size(
Constant.getActualX(context: context, x: 350),
Constant.getActualY(context: context, y: 100)),
elevation: 5,
side: const BorderSide(
width: 0.5,
color: Color.fromARGB(162, 204, 92, 146)),
backgroundColor: Colors.white,
foregroundColor: Colors.grey,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50))),
onPressed: () {
Navigator.of(context).popAndPushNamed(settingRoute);
},
child: Padding(
padding: EdgeInsets.symmetric(
horizontal:
Constant.getActualX(context: context, x: 51),
vertical:
Constant.getActualY(context: context, y: 21)),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
'assets/images/setting.png',
height:
Constant.getActualY(context: context, y: 57),
width: Constant.getActualY(context: context, y: 57),
),
SizedBox(
width: Constant.getActualX(context: context, x: 15),
),
Text(
'Setting',
style: Constant.title(context: context)
.copyWith(color: Colors.black),
),
],
),
),
),
SizedBox(
width: Constant.getActualX(context: context, x: 166.5),
),
ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 5,
maximumSize: Size(
Constant.getActualX(context: context, x: 350),
Constant.getActualY(context: context, y: 100)),
foregroundColor: Colors.grey,
side: const BorderSide(
width: 0.5,
color: Color.fromARGB(162, 204, 92, 146)),
backgroundColor: testPrintDisabled.value
? Colors.grey
: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50))),
onPressed: () {
if (testPrintDisabled.value) {
} else {
PrintTicket().printTest();
}
},
child: Padding(
padding: EdgeInsets.symmetric(
horizontal:
Constant.getActualX(context: context, x: 51),
vertical:
Constant.getActualY(context: context, y: 21)),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
'assets/images/next.png',
height:
Constant.getActualY(context: context, y: 57),
width: Constant.getActualY(context: context, y: 57),
),
SizedBox(
width: Constant.getActualX(context: context, x: 15),
),
Text(
'Test Print',
style: Constant.title(context: context).copyWith(
color: testPrintDisabled.value
? Colors.white
: Colors.black),
),
],
),
),
),
SizedBox(
width: Constant.getActualX(context: context, x: 166.5),
),
ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 5,
maximumSize: Size(
Constant.getActualX(context: context, x: 350),
Constant.getActualY(context: context, y: 100)),
foregroundColor: Colors.grey,
side: const BorderSide(
width: 0.5,
color: Color.fromARGB(162, 204, 92, 146)),
backgroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50))),
onPressed: () {
Navigator.of(context).pushNamed(queueRoute);
},
child: Padding(
padding: EdgeInsets.symmetric(
horizontal:
Constant.getActualX(context: context, x: 51),
vertical:
Constant.getActualY(context: context, y: 21)),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
'assets/images/next.png',
height:
Constant.getActualY(context: context, y: 57),
width: Constant.getActualY(context: context, y: 57),
),
SizedBox(
width: Constant.getActualX(context: context, x: 15),
),
Text(
'Next',
style: Constant.title(context: context)
.copyWith(color: Colors.black),
),
],
),
),
),
],
),
),
)
],
),
));
}
}

View File

@@ -0,0 +1,63 @@
import 'package:equatable/equatable.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:ticket_booth/model/layanan.dart';
import 'package:ticket_booth/provider/dio_provider.dart';
import 'package:ticket_booth/repository/base_repository.dart';
import 'package:ticket_booth/repository/service_repository.dart';
abstract class ServiceListState extends Equatable {
final DateTime date;
const ServiceListState(this.date);
@override
List<Object?> get props => [date];
}
class ServiceListStateInit extends ServiceListState {
ServiceListStateInit() : super(DateTime.now());
}
class ServiceListStateLoading extends ServiceListState {
ServiceListStateLoading() : super(DateTime.now());
}
class ServiceListStateError extends ServiceListState {
final String message;
ServiceListStateError({
required this.message,
}) : super(DateTime.now());
}
class ServiceListStateDone extends ServiceListState {
final List<Layanan> model;
ServiceListStateDone({
required this.model,
}) : super(DateTime.now());
}
//notifier
class ServiceListNotifier extends StateNotifier<ServiceListState> {
final Ref ref;
ServiceListNotifier({
required this.ref,
}) : super(ServiceListStateInit());
void list({required hostIp}) async {
try {
state = ServiceListStateLoading();
final dio = ref.read(dioProvider);
final resp = await ServiceRepository(dio: dio).getData(hostIp: hostIp);
state = ServiceListStateDone(model: resp);
} catch (e) {
if (e is BaseRepositoryException) {
state = ServiceListStateError(message: e.message);
} else {
state = ServiceListStateError(message: e.toString());
}
}
}
}
//provider
final ServiceListProvider =
StateNotifierProvider<ServiceListNotifier, ServiceListState>(
(ref) => ServiceListNotifier(ref: ref));

View File

@@ -0,0 +1,71 @@
import 'package:equatable/equatable.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:ticket_booth/provider/dio_provider.dart';
import 'package:ticket_booth/repository/base_repository.dart';
import 'package:ticket_booth/repository/queue_repository.dart';
abstract class QueueState extends Equatable {
final DateTime date;
const QueueState(this.date);
@override
List<Object?> get props => [date];
}
class QueueStateInit extends QueueState {
QueueStateInit() : super(DateTime.now());
}
class QueueStateLoading extends QueueState {
QueueStateLoading() : super(DateTime.now());
}
class QueueStateError extends QueueState {
final String message;
QueueStateError({
required this.message,
}) : super(DateTime.now());
}
class QueueStateDone extends QueueState {
final Map<String, dynamic> response;
QueueStateDone({
required this.response,
}) : super(DateTime.now());
}
//notifier
class QueueNotifier extends StateNotifier<QueueState> {
final Ref ref;
QueueNotifier({
required this.ref,
}) : super(QueueStateInit());
void get(
{required service_id,
required booth_id,
required hostIp,
required branchID}) async {
try {
state = QueueStateLoading();
final dio = ref.read(dioProvider);
final resp = await QueueRepository(dio: dio).getData(
service_id: service_id,
booth_id: booth_id,
hostIp: hostIp,
branchID: branchID);
state = QueueStateDone(response: resp);
} catch (e) {
if (e is BaseRepositoryException) {
state = QueueStateError(message: e.message);
} else {
state = QueueStateError(message: e.toString());
}
}
}
}
//provider
final QueueProvider = StateNotifierProvider<QueueNotifier, QueueState>(
(ref) => QueueNotifier(ref: ref));

View File

@@ -0,0 +1,543 @@
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_pos_printer_platform_image_3/flutter_pos_printer_platform_image_3.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:ticket_booth/app/print_ticket.dart';
import 'package:ticket_booth/app/route.dart';
import 'package:ticket_booth/model/booth.dart';
import 'package:ticket_booth/model/branch_model.dart';
import 'package:ticket_booth/model/printer_device.dart';
import 'package:ticket_booth/provider/all_service_provider.dart';
import 'package:intl/intl.dart';
import 'package:ticket_booth/screen/queue/queue_provider.dart';
import 'package:ticket_booth/screen/widgets/dialog_print.dart';
import 'package:ticket_booth/screen/widgets/pasien_online_dialog.dart';
import '../../app/constant.dart';
import '../../model/cabapility_model.dart';
import '../../model/layanan.dart';
import '../widgets/error_dialog.dart';
class QueueScreen extends HookConsumerWidget {
const QueueScreen({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final isLoading = useState(true);
final lyn = useState<List<Layanan>>(List.empty());
final activeLayanan = useState<List<dynamic>>(List.empty());
final selectedPrinter =
useState<PrinterDev>(PrinterDev(deviceName: "a", id: 0));
final selectedBooth =
useState<Booth>(Booth(name: 'B001', id: 0, code: 'a'));
final hostIp = useState('N');
final hostqR = useState('N');
final headerDisplay = useState('N');
final headerTicket = useState('N');
final footerTicket = useState('N');
final footerDisplay = useState('N');
final isLoadingPrint = useState(false);
final errorMsg = useState('');
final splitedHost = useState('');
final tapAnimation = useState(0);
final selectedCapabilityProfile = useState(CapabilityProfileModel());
final selectedBranch = useState<BranchModel?>(null);
final selectedLayanan = useState<Layanan>(Layanan(
name: 'x', id: 0, priority: 0, isConsultDoctor: 'n', code: '0'));
final getNumberLoading = useState(false);
final btnSize = useState<Map<String, dynamic>>({'name': 'n'});
Future getData() async {
try {
final prefs = await SharedPreferences.getInstance();
var raw_data = prefs.getString('tb-westerindo') ?? 'a';
if (raw_data != 'a') {
List<Layanan> allLayanan = ref.read(allServiceProvider);
var data = json.decode(raw_data);
hostIp.value = data['hostIp'];
hostqR.value = data['hostQrIp'];
headerDisplay.value = data['headerDisplay'];
headerTicket.value = data['headerTicket'];
footerTicket.value = data['footerTicket'];
footerDisplay.value = data['footerDisplay'];
selectedPrinter.value = PrinterDev.fromJson(data['selectedPrinter']);
selectedBooth.value = Booth.fromJson(data['selectedBooth']);
selectedBranch.value = BranchModel.fromJson(data['selectedBranch']);
selectedCapabilityProfile.value =
CapabilityProfileModel.fromJson(data['selectedCapability']);
activeLayanan.value = data['activeLayanan'];
btnSize.value = data['buttonSize'];
print(btnSize.value);
var sp = hostIp.value.split(':');
splitedHost.value = sp[0] + ":" + sp[1];
List<Layanan> actvLayanan = [];
activeLayanan.value.forEach((e) {
allLayanan.forEach((f) {
if (e == f.id) {
actvLayanan.add(f);
}
});
});
actvLayanan.sort(((a, b) => a.priority.compareTo(b.priority)));
lyn.value = actvLayanan;
} else {
Navigator.of(context).popAndPushNamed(settingRoute);
}
isLoading.value = false;
} catch (e) {
print(e);
ErrorDialog(context, e.toString(), 'ERROR');
isLoading.value = false;
}
}
getDataApi(e) {
ref.read(QueueProvider.notifier).get(
branchID: selectedBranch.value?.mBranchID,
booth_id: selectedBooth.value.id,
service_id: e.id,
hostIp: hostIp.value);
}
printTicketDialog(String number) {
try {
// DialogPrint(context, number);
PrintTicket().printTicket(
boothId: selectedBooth.value.name.toString(),
header: headerTicket.value,
date: 'a',
time: 'a',
antrianNumb: number,
name: '',
StringqrCode: hostqR.value,
location: '',
footer: footerTicket.value,
DoctorName: selectedLayanan.value.doctorName,
isConsult: selectedLayanan.value.isConsultDoctor,
capabilityName: selectedCapabilityProfile.value.key ?? "default",
layananName: selectedLayanan.value.name);
} catch (e) {
errorMsg.value = e.toString();
ErrorDialog(context, errorMsg.value, 'ERROR');
}
}
ref.listen(QueueProvider, (previous, next) {
if (next is QueueStateLoading) {
isLoadingPrint.value = true;
} else if (next is QueueStateError) {
errorMsg.value = next.message;
ErrorDialog(context, errorMsg.value, 'ERROR');
getNumberLoading.value = false;
} else if (next is QueueStateDone) {
String number = next.response['data']['number'].toString();
String location = next.response['data']['location'].toString();
// print(location);
DialogPrint(
context, number, printTicketDialog, selectedLayanan.value.name);
try {
// PrintTicket().printTicket(
// boothId: selectedBooth.value.name.toString(),
// header: headerTicket.value,
// date: 'a',
// time: 'a',
// antrianNumb: number,
// name: '',
// StringqrCode: hostqR.value,
// location: location,
// footer: footerTicket.value,
// DoctorName: selectedLayanan.value.doctorName,
// isConsult: selectedLayanan.value.isConsultDoctor,
// capabilityName: selectedCapabilityProfile.value.key ?? "default",
// layananName: selectedLayanan.value.name);
} catch (e) {
errorMsg.value = e.toString();
ErrorDialog(context, errorMsg.value, 'ERROR');
}
Timer(Duration(seconds: 2), () {
getNumberLoading.value = false;
});
}
});
useEffect(() {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
getData();
});
return () {};
}, []);
return Material(
child: Container(
height: Constant.getActualY(context: context, y: 982),
width: Constant.getActualX(context: context, x: 1512),
decoration: const BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
image: AssetImage("assets/images/new-bg.png"))),
child: isLoading.value
? const SpinKitCubeGrid(
color: Colors.blue,
)
: Column(
children: [
SizedBox(
height: Constant.getActualY(context: context, y: 150),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
GestureDetector(
onTap: () {
// Navigator.of(context).popAndPushNamed(displayRoute);
},
child: Container(
width:
Constant.getActualX(context: context, x: 150),
height:
Constant.getActualY(context: context, y: 150),
margin: EdgeInsets.only(
left: Constant.getActualX(
context: context, x: 30)),
padding: const EdgeInsets.all(20),
child: Image.network(
'${splitedHost.value.toString()}/one-media/one-queue/logo-westerindo.png',
loadingBuilder:
(context, child, loadingProgress) {
if (loadingProgress == null) return child;
return const CircularProgressIndicator();
},
errorBuilder: (context, error, stackTrace) {
return Image.asset(
'assets/images/logo-westerindo.png',
);
},
)),
),
Text(
headerDisplay.value,
style: Constant.title(context: context),
),
Container(
alignment: Alignment.center,
margin: EdgeInsets.only(
right:
Constant.getActualX(context: context, x: 30)),
padding: const EdgeInsets.all(20),
width: Constant.getActualX(context: context, x: 150),
height: Constant.getActualY(context: context, y: 150),
child: Text(selectedBranch.value?.mBranchName ?? "",
textAlign: TextAlign.center,
style: Constant.label(context: context).copyWith(
fontWeight: FontWeight.bold,
)),
),
],
),
),
SizedBox(
height: Constant.getActualY(context: context, y: 682),
child: Row(
children: [
Container(
width: Constant.getActualX(
context: context,
x: double.parse(btnSize.value['rightLeftWidth'])),
// color: Colors.green,
),
Container(
// color: Colors.red,
width: Constant.getActualX(
context: context,
x: double.parse(btnSize.value['centerWidth'])),
child: GridView.count(
crossAxisCount: int.parse(btnSize.value['column']),
childAspectRatio:
double.parse(btnSize.value['childAspectRatio']),
mainAxisSpacing: Constant.getActualY(
context: context,
y: double.parse(
btnSize.value['mainAxisSpacing'])),
crossAxisSpacing: Constant.getActualY(
context: context,
y: double.parse(
btnSize.value['crossAxisSpacing'])),
children: lyn.value
.map((e) => ButtonLayanan(
getNumberLoading,
tapAnimation,
e,
selectedLayanan,
context,
getDataApi,
btnSize,
splitedHost))
.toList()),
),
Container(
width: Constant.getActualX(
context: context,
x: double.parse(btnSize.value['rightLeftWidth'])),
// color: Colors.green,
)
],
),
),
SizedBox(
height: Constant.getActualY(context: context, y: 150),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: Constant.getActualX(context: context, x: 200),
margin: EdgeInsets.only(
left:
Constant.getActualX(context: context, x: 30)),
padding: EdgeInsets.all(20),
child: Center(
child: Text(
selectedBooth.value.name,
style: Constant.subTitle(context: context),
),
)),
Text(
footerDisplay.value,
style: Constant.title(context: context).copyWith(
fontStyle: FontStyle.italic,
fontWeight: FontWeight.normal),
),
const DisplayClock(),
],
),
)
],
),
));
}
Container ButtonLayanan(
ValueNotifier<bool> getNumberLoading,
ValueNotifier<int> tapAnimation,
Layanan e,
ValueNotifier<Layanan> selectedLayanan,
BuildContext context,
Null getDataApi(dynamic e),
ValueNotifier<Map<String, dynamic>> btnSize,
ValueNotifier<String> splitedHost) {
return Container(
// color: Colors.amber,
child: Center(
child: InkWell(
onTap: getNumberLoading.value
? null
: () {
// DialogPrint(context, 'A0001');
// PasienOnlineDialog(context);
// return;
tapAnimation.value = e.id;
selectedLayanan.value = e;
getNumberLoading.value = true;
if (e.name == "Pasien Online" && e.id == 5) {
} else {
getDataApi(e);
}
Timer(Duration(milliseconds: 250), () {
tapAnimation.value = 0;
});
Timer(Duration(seconds: 2), () {
getNumberLoading.value = false;
print("tidak loading");
});
},
child: Ink(
// color: Colors.green,
height: Constant.getActualY(
context: context, y: double.parse(btnSize.value['btnHeight'])),
width: Constant.getActualX(
context: context, x: double.parse(btnSize.value['btnWidth'])),
child: Stack(
alignment: AlignmentDirectional.center,
children: [
Image.network(
'${splitedHost.value.toString()}/one-media/one-queue/${e.code}.png',
fit: BoxFit.cover,
color:
e.id == tapAnimation.value ? Colors.grey : Colors.white,
// color: Colors.white
// .withOpacity(e.id ==
// tapAnimation.value
// ? 0.7
// : 1),
colorBlendMode: BlendMode.modulate,
height: Constant.getActualY(
context: context,
y: e.id == tapAnimation.value ? 310 : 400),
width: Constant.getActualX(
context: context,
x: e.id == tapAnimation.value ? 280 : 300),
loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null) return child;
return const CircularProgressIndicator();
},
errorBuilder: (context, error, stackTrace) {
return Image.asset(
'assets/images/cpone-default.png',
fit: BoxFit.cover,
color: e.id == tapAnimation.value
? Colors.grey
: Colors.white,
colorBlendMode: BlendMode.modulate,
height: Constant.getActualY(
context: context,
y: e.id == tapAnimation.value ? 310 : 400),
width: Constant.getActualX(
context: context,
x: e.id == tapAnimation.value ? 280 : 300),
);
},
),
Positioned(
top: 1,
child: Container(
margin: EdgeInsets.only(
top: Constant.getActualY(context: context, y: 10)),
padding: EdgeInsets.symmetric(
horizontal:
Constant.getActualX(context: context, x: 10)),
// color: Colors.red,
height: Constant.getActualY(context: context, y: 110),
width: Constant.getActualX(context: context, x: 280),
child: Center(
child: e.isConsultDoctor == 'N'
? Text(
e.name,
maxLines: 2,
textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis,
style: Constant.layananTitle(context: context)
.copyWith(color: Colors.white),
)
: Column(
children: [
Text(
e.name,
maxLines: 2,
textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis,
style: Constant.layananTitle(context: context)
.copyWith(color: Colors.white),
),
Text(
e.doctorName,
maxLines: 1,
textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis,
style: Constant.layananTitle(context: context)
.copyWith(color: Colors.white),
)
],
),
),
),
)
],
),
),
),
),
);
}
}
class DisplayClock extends HookConsumerWidget {
const DisplayClock({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
final strDate = useState("");
final strMonth = useState("");
final strYear = useState("");
final strHour = useState("");
final strMinute = useState("");
final strSeconds = useState("");
useEffect(() {
final tmr = Timer.periodic(const Duration(seconds: 1), (timer) {
final dt = DateFormat('yyyy-MMM-dd-HH-mm-ss').format(DateTime.now());
final splited = dt.split('-');
final date = splited[2].toString();
final month = splited[1].toString();
final year = splited[0].toString();
final hour = splited[3].toString();
final minute = splited[4].toString();
final second = splited[5].toString();
if (date != strDate.value) strDate.value = date;
if (month != strMonth.value) strMonth.value = month;
if (year != strYear.value) strYear.value = year;
if (hour != strHour.value) strHour.value = hour;
if (minute != strMinute.value) strMinute.value = minute;
if (second != strSeconds.value) strSeconds.value = second;
});
return () {
tmr.cancel();
};
}, []);
return Container(
width: Constant.getActualX(context: context, x: 200),
margin: EdgeInsets.only(
right: Constant.getActualX(context: context, x: 30)),
padding: EdgeInsets.all(0),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
strDate.value,
style: Constant.title(context: context).copyWith(
color: Colors.blue[900],
fontSize: Constant.getActualX(context: context, x: 64)),
),
SizedBox(
width: Constant.getActualX(context: context, x: 10),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
strMonth.value,
style: Constant.subTitle(context: context).copyWith(
color: Colors.blue[900],
fontSize:
Constant.getActualX(context: context, x: 25)),
),
Text(
strYear.value,
style: Constant.subTitle(context: context).copyWith(
color: Colors.blue[900],
fontSize:
Constant.getActualX(context: context, x: 25)),
)
],
)
],
),
Text(
'${strHour.value} . ${strMinute.value} . ${strSeconds.value}',
style: Constant.subTitle(context: context).copyWith(
color: Colors.blue[900],
fontSize: Constant.getActualX(context: context, x: 25)),
)
],
));
}
}

View File

@@ -0,0 +1,63 @@
import 'package:equatable/equatable.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:ticket_booth/model/booth.dart';
import 'package:ticket_booth/provider/dio_provider.dart';
import 'package:ticket_booth/repository/base_repository.dart';
import 'package:ticket_booth/repository/booth_repository.dart';
abstract class BoothListState extends Equatable {
final DateTime date;
const BoothListState(this.date);
@override
List<Object?> get props => [date];
}
class BoothListStateInit extends BoothListState {
BoothListStateInit() : super(DateTime.now());
}
class BoothListStateLoading extends BoothListState {
BoothListStateLoading() : super(DateTime.now());
}
class BoothListStateError extends BoothListState {
final String message;
BoothListStateError({
required this.message,
}) : super(DateTime.now());
}
class BoothListStateDone extends BoothListState {
final List<Booth> model;
BoothListStateDone({
required this.model,
}) : super(DateTime.now());
}
//notifier
class BoothListNotifier extends StateNotifier<BoothListState> {
final Ref ref;
BoothListNotifier({
required this.ref,
}) : super(BoothListStateInit());
void list({required hostIp}) async {
try {
state = BoothListStateLoading();
final dio = ref.read(dioProvider);
final resp = await BoothRepository(dio: dio).getData(hostIP: hostIp);
state = BoothListStateDone(model: resp);
} catch (e) {
if (e is BaseRepositoryException) {
state = BoothListStateError(message: e.message);
} else {
state = BoothListStateError(message: e.toString());
}
}
}
}
//provider
final BoothListProvider =
StateNotifierProvider<BoothListNotifier, BoothListState>(
(ref) => BoothListNotifier(ref: ref));

View File

@@ -0,0 +1,63 @@
import 'package:equatable/equatable.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:ticket_booth/model/branch_model.dart';
import 'package:ticket_booth/provider/dio_provider.dart';
import 'package:ticket_booth/repository/base_repository.dart';
import 'package:ticket_booth/repository/booth_repository.dart';
abstract class BranchListState extends Equatable {
final DateTime date;
const BranchListState(this.date);
@override
List<Object?> get props => [date];
}
class BranchListStateInit extends BranchListState {
BranchListStateInit() : super(DateTime.now());
}
class BranchListStateLoading extends BranchListState {
BranchListStateLoading() : super(DateTime.now());
}
class BranchListStateError extends BranchListState {
final String message;
BranchListStateError({
required this.message,
}) : super(DateTime.now());
}
class BranchListStateDone extends BranchListState {
final List<BranchModel> model;
BranchListStateDone({
required this.model,
}) : super(DateTime.now());
}
//notifier
class BranchListNotifier extends StateNotifier<BranchListState> {
final Ref ref;
BranchListNotifier({
required this.ref,
}) : super(BranchListStateInit());
void list({required hostIp}) async {
try {
state = BranchListStateLoading();
final dio = ref.read(dioProvider);
final resp = await BoothRepository(dio: dio).getBranch(hostIP: hostIp);
state = BranchListStateDone(model: resp);
} catch (e) {
if (e is BaseRepositoryException) {
state = BranchListStateError(message: e.message);
} else {
state = BranchListStateError(message: e.toString());
}
}
}
}
//provider
final BranchListProvider =
StateNotifierProvider<BranchListNotifier, BranchListState>(
(ref) => BranchListNotifier(ref: ref));

View File

@@ -0,0 +1,496 @@
import 'dart:convert';
import 'package:clippy_flutter/ticket.dart';
import 'package:esc_pos_utils/esc_pos_utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_pos_printer_platform_image_3/flutter_pos_printer_platform_image_3.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:ticket_booth/app/print_ticket.dart';
import 'package:ticket_booth/model/branch_model.dart';
import 'package:ticket_booth/model/cabapility_model.dart';
import 'package:ticket_booth/screen/widgets/error_dialog.dart';
import '../../app/constant.dart';
import '../../model/booth.dart';
import '../../model/printer_device.dart';
class FormInput extends HookConsumerWidget {
FormInput(
{Key? key,
required this.selected_booth,
required this.pm,
required this.booth,
required this.selected_printer,
required this.prnt,
required this.hostIpController,
required this.hostQrController,
required this.headerDisplayController,
required this.footerDisplayController,
required this.headerTicketController,
required this.footerTicketController,
required this.isLoading,
required this.capabilityList,
required this.selectedCapability,
required this.getServiceBooth,
required this.branch,
required this.selected_branch})
: super(key: key);
final ValueNotifier<Booth> selected_booth;
final ValueNotifier<List<Booth>> booth;
final ValueNotifier<List<BranchModel>> branch;
final ValueNotifier<BranchModel> selected_branch;
final ValueNotifier<PrinterDev?> selected_printer;
final ValueNotifier<List<PrinterDev>> prnt;
final ValueNotifier<List<CapabilityProfileModel>> capabilityList;
final ValueNotifier<CapabilityProfileModel?> selectedCapability;
final TextEditingController hostIpController;
final TextEditingController hostQrController;
final TextEditingController headerDisplayController;
final TextEditingController footerDisplayController;
final TextEditingController headerTicketController;
final TextEditingController footerTicketController;
final PrinterManager pm;
final Function getServiceBooth;
final bool isLoading;
@override
Widget build(BuildContext context, WidgetRef ref) {
final hostIpError = useState(false);
final hostQrError = useState(false);
;
final usbStream =
useStream<USBStatus>(pm.stateUSB, initialData: USBStatus.none);
_connectDevice(PrinterDev selectedPrinter, PrinterType type,
{bool reconnect = true, String? ipAddress = null}) async {
try {
await pm.connect(
type: type,
model: UsbPrinterInput(
name: selectedPrinter.deviceName,
productId: selectedPrinter.productId,
vendorId: selectedPrinter.vendorId));
} catch (e) {
print(e);
}
}
return Row(
children: [
SizedBox(
width: Constant.getActualX(context: context, x: 625),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
child: Tooltip(
message: "Pilih salah satu cabang ",
child: Text(
'Cabang*',
style: Constant.label(context: context),
),
),
),
SizedBox(
height: Constant.getActualY(context: context, y: 60),
child: DropdownButtonFormField<BranchModel>(
style: Constant.normal(context: context)
.copyWith(color: Colors.black),
decoration: const InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(8),
),
),
),
menuMaxHeight: Constant.getActualY(context: context, y: 500),
hint: Text(selected_branch.value.mBranchName ?? ''),
items: branch.value
.map((e) => DropdownMenuItem<BranchModel>(
value: e, child: Text(e.mBranchName ?? '')))
.toList(),
onChanged: (BranchModel? e) {
// print(e);
selected_branch.value = e!;
},
),
),
SizedBox(
height: Constant.getActualY(context: context, y: 20),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
width: Constant.getActualX(context: context, x: 170),
child: Tooltip(
message:
"Pilih salah satu capability profile yang akan digunakan",
child: Text(
'Printer*',
style: Constant.label(context: context),
),
),
),
SizedBox(
width: Constant.getActualX(context: context, x: 170),
child: Tooltip(
message:
"Pilih salah satu printer yang akan digunakan",
child: Text(
'Capability Profile*',
style: Constant.label(context: context),
),
),
),
SizedBox(
width: Constant.getActualX(context: context, x: 100),
),
SizedBox(
width: Constant.getActualX(context: context, x: 100),
)
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
width: Constant.getActualX(context: context, x: 170),
height: Constant.getActualY(context: context, y: 60),
child: DropdownButtonFormField<PrinterDev>(
value: selected_printer.value,
isExpanded: true,
style: Constant.normal(context: context)
.copyWith(color: Colors.black),
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(8),
),
),
),
menuMaxHeight:
Constant.getActualY(context: context, y: 500),
hint: Text(
selected_printer.value?.deviceName
.replaceAll(' ', '\u00A0') ??
'',
// softWrap: true,
overflow: TextOverflow.ellipsis,
),
items: prnt.value
.map((e) => DropdownMenuItem<PrinterDev>(
value: e,
child: Text(
e.deviceName.replaceAll(' ', '\u00A0'),
// softWrap: true,
overflow: TextOverflow.ellipsis,
)))
.toList(),
onChanged: (PrinterDev? e) {
selected_printer.value = e!;
},
)),
SizedBox(
width: Constant.getActualX(context: context, x: 170),
height: Constant.getActualY(context: context, y: 60),
child:
DropdownButtonFormField<CapabilityProfileModel>(
value: selectedCapability.value,
isExpanded: true,
style: Constant.normal(context: context)
.copyWith(color: Colors.black),
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(8),
),
),
),
menuMaxHeight:
Constant.getActualY(context: context, y: 500),
hint: Text(
selectedCapability.value?.key
?.replaceAll(' ', '\u00A0') ??
'',
// softWrap: true,
overflow: TextOverflow.ellipsis,
),
items: capabilityList.value
.map((e) =>
DropdownMenuItem<CapabilityProfileModel>(
value: e,
child: Text(
e.key!.replaceAll(' ', '\u00A0'),
// softWrap: true,
overflow: TextOverflow.ellipsis,
)))
.toList(),
onChanged: (CapabilityProfileModel? e) {
selectedCapability.value = e!;
},
)),
SizedBox(
// width: Constant.getActualX(context: context, x: 100),
height: Constant.getActualY(context: context, y: 60),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red),
onPressed: () {
try {
if (selected_printer.value != null) {
_connectDevice(
selected_printer.value!, PrinterType.usb);
} else {
throw Exception("Printer tidak dipilih");
}
} catch (e) {
ErrorDialog(context, e.toString(), 'ERROR');
print(e);
}
},
child: Tooltip(
message:
"Tombol untuk menyambungkan printer yang elah dipilih",
child: Text(
"Connect",
style: Constant.label(context: context)
.copyWith(color: Colors.white),
),
)),
),
SizedBox(
// width: Constant.getActualX(context: context, x: 100),
height: Constant.getActualY(context: context, y: 60),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.green),
onPressed: () {
try {
PrintTicket().printTest();
} catch (e) {
ErrorDialog(context, e.toString(), 'ERROR');
print(e);
}
},
child: Tooltip(
message:
"Tombol untuk tes print, setelah terhubung akan mencetak teks tes print",
child: Text(
"Test Print",
style: Constant.label(context: context)
.copyWith(color: Colors.white),
),
)),
),
],
),
],
),
SizedBox(
height: Constant.getActualY(context: context, y: 20),
),
Tooltip(
message:
"Domain yang akan digunakan untuk mendapatkan daftar layanan dan nomor antrian",
child: Text(
'Host IP*',
style: Constant.label(context: context),
),
),
SizedBox(
height: Constant.getActualY(context: context, y: 60),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
width: Constant.getActualX(context: context, x: 500),
child: TextField(
controller: hostIpController,
onChanged: (value) {
if (value.trim() == "") {
hostIpError.value = true;
}
if (value.trim() != "") {
hostIpError.value = false;
}
},
decoration: InputDecoration(
errorText:
hostIpError.value ? "Tidak boleh kosong" : null,
border: const OutlineInputBorder(),
focusedBorder: const OutlineInputBorder(
borderSide:
BorderSide(color: Colors.blue, width: 2)),
hintText: "http://devone.aplikasi.web.id",
hintStyle: Constant.label(context: context)),
),
),
SizedBox(
// width: Constant.getActualX(context: context, x: 200),
height: Constant.getActualY(context: context, y: 60),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.green),
onPressed: hostIpController.text == ""
? null
: () {
getServiceBooth();
},
child: Tooltip(
message:
"Tombol untuk menampilkan daftar layanan apabila tidak muncul",
child: isLoading
? CircularProgressIndicator(
color: Colors.white,
)
: Text(
"Layanan ",
style: Constant.label(context: context)
.copyWith(color: Colors.white),
),
)),
),
],
),
),
SizedBox(
height: Constant.getActualY(context: context, y: 20),
),
Tooltip(
message:
"Teks yang akan di cetak dibagian atas tiket. Maksimal 2 baris",
child: Text(
'Header Ticket',
style: Constant.label(context: context),
),
),
SizedBox(
height: Constant.getActualY(context: context, y: 80),
child: TextField(
controller: headerTicketController,
maxLines: 2,
decoration: InputDecoration(
border: const OutlineInputBorder(),
hintText: "Masukkan header ticket",
hintStyle: Constant.label(context: context)),
),
),
],
),
),
SizedBox(
width: Constant.getActualX(context: context, x: 50),
),
SizedBox(
width: Constant.getActualX(context: context, x: 625),
child:
Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Tooltip(
message: "Teks yang akan di tampilkan di display bagian atas",
child: Text(
'Header Display',
style: Constant.label(context: context),
),
),
SizedBox(
height: Constant.getActualY(context: context, y: 60),
child: TextField(
controller: headerDisplayController,
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: "Masukkan header display",
hintStyle: Constant.label(context: context)),
),
),
SizedBox(
height: Constant.getActualY(context: context, y: 20),
),
Tooltip(
message: "Teks yang akan di tampilkan di bagian bawah display",
child: Text(
'Footer Display',
style: Constant.label(context: context),
),
),
SizedBox(
height: Constant.getActualY(context: context, y: 60),
child: TextField(
controller: footerDisplayController,
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: "Masukkan footer display",
hintStyle: Constant.label(context: context)),
),
),
SizedBox(
height: Constant.getActualY(context: context, y: 20),
),
SizedBox(
child: Tooltip(
message: "Pilih salah satu booth ",
child: Text(
'Booth*',
style: Constant.label(context: context),
),
),
),
SizedBox(
height: Constant.getActualY(context: context, y: 60),
child: DropdownButtonFormField<Booth>(
style: Constant.normal(context: context)
.copyWith(color: Colors.black),
decoration: const InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(8),
),
),
),
menuMaxHeight: Constant.getActualY(context: context, y: 500),
hint: Text(selected_booth.value.name),
items: booth.value
.map((e) => DropdownMenuItem<Booth>(
value: e, child: Text(e.name)))
.toList(),
onChanged: (Booth? e) {
// print(e);
selected_booth.value = e!;
},
),
),
SizedBox(
height: Constant.getActualY(context: context, y: 20),
),
Tooltip(
message:
"Teks yang akan di cetak di bagian bawah tiket. Maksimal 2 baris",
child: Text(
'Footer Ticket',
style: Constant.label(context: context),
),
),
SizedBox(
height: Constant.getActualY(context: context, y: 80),
child: TextField(
maxLines: 2,
controller: footerTicketController,
decoration: InputDecoration(
border: const OutlineInputBorder(),
hintText: "Masukkan footer ticket",
hintStyle: Constant.label(context: context)),
),
),
]))
],
);
}
}

View File

@@ -0,0 +1,63 @@
import 'package:equatable/equatable.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:ticket_booth/model/layanan.dart';
import 'package:ticket_booth/provider/dio_provider.dart';
import 'package:ticket_booth/repository/base_repository.dart';
import 'package:ticket_booth/repository/service_repository.dart';
abstract class ServiceListState extends Equatable {
final DateTime date;
const ServiceListState(this.date);
@override
List<Object?> get props => [date];
}
class ServiceListStateInit extends ServiceListState {
ServiceListStateInit() : super(DateTime.now());
}
class ServiceListStateLoading extends ServiceListState {
ServiceListStateLoading() : super(DateTime.now());
}
class ServiceListStateError extends ServiceListState {
final String message;
ServiceListStateError({
required this.message,
}) : super(DateTime.now());
}
class ServiceListStateDone extends ServiceListState {
final List<Layanan> model;
ServiceListStateDone({
required this.model,
}) : super(DateTime.now());
}
//notifier
class ServiceListNotifier extends StateNotifier<ServiceListState> {
final Ref ref;
ServiceListNotifier({
required this.ref,
}) : super(ServiceListStateInit());
void list({required hostIp}) async {
try {
state = ServiceListStateLoading();
final dio = ref.read(dioProvider);
final resp = await ServiceRepository(dio: dio).getData(hostIp: hostIp);
state = ServiceListStateDone(model: resp);
} catch (e) {
if (e is BaseRepositoryException) {
state = ServiceListStateError(message: e.message);
} else {
state = ServiceListStateError(message: e.toString());
}
}
}
}
//provider
final ServiceListProvider =
StateNotifierProvider<ServiceListNotifier, ServiceListState>(
(ref) => ServiceListNotifier(ref: ref));

View File

@@ -0,0 +1,559 @@
import 'dart:convert';
import 'package:esc_pos_utils/esc_pos_utils.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_pos_printer_platform_image_3/flutter_pos_printer_platform_image_3.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:ticket_booth/app/print_ticket.dart';
import 'package:ticket_booth/app/route.dart';
import 'package:ticket_booth/model/booth.dart';
import 'package:ticket_booth/model/branch_model.dart';
import 'package:ticket_booth/model/cabapility_model.dart';
import 'package:ticket_booth/model/layanan.dart';
import 'package:ticket_booth/model/printer_device.dart';
import 'package:ticket_booth/provider/all_service_provider.dart';
import 'package:ticket_booth/screen/settings/booth_list_provider.dart';
import 'package:ticket_booth/screen/settings/branch_list_provider.dart';
import 'package:ticket_booth/screen/settings/service_list_provider.dart';
import '../../app/constant.dart';
import '../widgets/error_dialog.dart';
import 'form_input.dart';
class SettingScreen extends HookConsumerWidget {
const SettingScreen({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final hostIpController = useTextEditingController(text: '');
final hostQrController = useTextEditingController(text: '');
final headerDisplayController = useTextEditingController(text: '');
final footerDisplayController = useTextEditingController(text: '');
final footerTicketController = useTextEditingController(text: '');
final headerTicketController = useTextEditingController(text: '');
final activeLayanan = useState<List>(List.empty());
final capabilityProfileList = useState<List<CapabilityProfileModel>>([]);
final selectedCapabilityProfile = useState<CapabilityProfileModel?>(null);
final isLoading = useState(false);
final data = useState('N');
final PrinterManager pm = PrinterManager.instance;
final dvcs = useState<List<PrinterDev>>([]);
var devices3 = <PrinterDev>[];
final selectedBtnSize = useState<Map<String, dynamic>>({
'name': '4',
'message': 'Tombol yang akan ditampilkan berjumlah 4 ',
'rightLeftWidth': "300",
'centerWidth': "912",
'childAspectRatio': '1.559',
'mainAxisSpacing': "10",
'crossAxisSpacing': '10',
'btnHeight': "330",
'btnWidth': '300',
'column': '2'
});
final List<Map<String, dynamic>> listBtnSize = [
{
'name': '10',
'message': 'Tombol yang akan ditampilkan berjumlah 10',
'rightLeftWidth': "40",
'centerWidth': "1432",
'childAspectRatio': '1',
'mainAxisSpacing': "20",
'crossAxisSpacing': '10',
'btnHeight': "290",
'btnWidth': '260',
'column': '5'
},
{
'name': '8',
'message': 'Tombol yang akan ditampilkan berjumlah 8 ',
'rightLeftWidth': "100",
'centerWidth': "1312",
'childAspectRatio': '1.1',
'mainAxisSpacing': "40",
'crossAxisSpacing': '10',
'btnHeight': "310",
'btnWidth': '280',
'column': '4'
},
{
'name': '6',
'message': 'Tombol yang akan ditampilkan berjumlah 6 ',
'rightLeftWidth': "200",
'centerWidth': "1112",
'childAspectRatio': '1.33',
'mainAxisSpacing': "40",
'crossAxisSpacing': '10',
'btnHeight': "310",
'btnWidth': '280',
'column': '3'
},
{
'name': '4',
'message': 'Tombol yang akan ditampilkan berjumlah 4 ',
'rightLeftWidth': "300",
'centerWidth': "912",
'childAspectRatio': '1.559',
'mainAxisSpacing': "10",
'crossAxisSpacing': '10',
'btnHeight': "330",
'btnWidth': '300',
'column': '2'
}
];
getServiceBooth() async {
activeLayanan.value = List.empty();
ref.read(BoothListProvider.notifier).list(hostIp: hostIpController.text);
ref
.read(ServiceListProvider.notifier)
.list(hostIp: hostIpController.text);
ref.read(BranchListProvider.notifier).list(hostIp: hostIpController.text);
}
_scan(PrinterType type) async {
// Find printers
pm.discovery(type: PrinterType.usb, isBle: false).listen((device) {
devices3.add(PrinterDev(
id: int.parse(device.productId ?? '0'),
deviceName: device.name,
address: device.address,
isBle: false,
vendorId: device.vendorId,
productId: device.productId,
));
});
}
full() async {
// await FullScreen.enterFullScreen(FullScreenMode.EMERSIVE_STICKY);
}
final lyn = useState<List<Layanan>>(List.empty());
final booth = useState<List<Booth>>(List.empty());
final branch = useState<List<BranchModel>>(List.empty());
final selected_printer = useState<PrinterDev?>(null);
final selected_booth =
useState<Booth>(Booth(name: 'Pilih salah satu', id: 0, code: 'b1'));
final selected_branch = useState<BranchModel>(
BranchModel(mBranchID: '0', mBranchName: 'Pilih salah satu cabang'));
Future delData() async {
// Obtain shared preferences.
try {
final prefs = await SharedPreferences.getInstance();
await prefs.remove('tb-westerindo');
} catch (e) {
print(e);
}
}
Future getData() async {
try {
final prefs = await SharedPreferences.getInstance();
var raw_data = prefs.getString('tb-westerindo') ?? 'a';
data.value = raw_data;
print(raw_data);
if (raw_data != 'a') {
lyn.value = ref.read(allServiceProvider);
var data = json.decode(raw_data);
selected_booth.value = Booth.fromJson(data['selectedBooth']);
selected_branch.value = BranchModel.fromJson(data['selectedBranch']);
selected_printer.value = PrinterDev.fromJson(data['selectedPrinter']);
hostIpController.text = data['hostIp'];
hostQrController.text = data['hostQrIp'];
headerDisplayController.text = data['headerDisplay'];
footerDisplayController.text = data['footerDisplay'];
footerTicketController.text = data['footerTicket'];
headerTicketController.text = data['headerTicket'];
activeLayanan.value = data['activeLayanan'] ?? List.empty();
selectedBtnSize.value = data['buttonSize'];
selectedCapabilityProfile.value =
CapabilityProfileModel.fromJson(data['selectedCapability']);
if (activeLayanan.value.isNotEmpty) {
activeLayanan.value.forEach((e) {
lyn.value.forEach((f) {
if (e == f.id) {
f.value = true;
}
});
});
}
}
} catch (e) {
print(e);
ErrorDialog(context, e.toString(), 'ERROR');
}
}
useEffect(() {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
await getData();
var capabilityList = await CapabilityProfile.getAvailableProfiles();
List<CapabilityProfileModel> cl = List.empty(growable: true);
for (var i = 0; i < capabilityList.length; i++) {
var data = capabilityList[i];
final model = CapabilityProfileModel.fromJson(data);
cl.add(model);
}
capabilityProfileList.value = cl;
var stb = capabilityProfileList.value.firstWhere(
(element) => element.key == selectedCapabilityProfile.value?.key,
orElse: () => CapabilityProfileModel());
if (stb.key != null) {
selectedCapabilityProfile.value = stb;
}
_scan(PrinterType.usb);
dvcs.value = devices3;
if (data.value != 'a') {
ref
.read(BoothListProvider.notifier)
.list(hostIp: hostIpController.text);
ref
.read(BranchListProvider.notifier)
.list(hostIp: hostIpController.text);
}
});
full();
return () {};
}, []);
ref.listen(BoothListProvider, (previous, next) {
if (next is BoothListStateLoading) {
isLoading.value = true;
} else if (next is BoothListStateError) {
ErrorDialog(context, next.message, 'ERROR');
isLoading.value = false;
} else if (next is BoothListStateDone) {
booth.value = next.model;
isLoading.value = false;
}
});
ref.listen(ServiceListProvider, (previous, next) {
if (next is ServiceListStateLoading) {
isLoading.value = true;
} else if (next is ServiceListStateError) {
ErrorDialog(context, next.message, 'ERROR');
isLoading.value = false;
} else if (next is ServiceListStateDone) {
// ref.read(allServiceProvider.notifier).state = next.model;
// print(ref.read(allServiceProvider));
lyn.value = next.model;
isLoading.value = false;
}
});
ref.listen(BranchListProvider, (previous, next) {
if (next is BranchListStateLoading) {
isLoading.value = true;
} else if (next is BranchListStateError) {
ErrorDialog(context, next.message, 'ERROR');
isLoading.value = false;
} else if (next is BranchListStateDone) {
// ref.read(allServiceProvider.notifier).state = next.model;
// print(ref.read(allServiceProvider));
branch.value = next.model;
isLoading.value = false;
}
});
Future<bool> saveData() async {
try {
final prefs = await SharedPreferences.getInstance();
final Map<String, dynamic> data = {
"headerDisplay": headerDisplayController.text != ''
? headerDisplayController.text
: 'Selamat Datang Di Pramita',
"footerDisplay": footerDisplayController.text != ''
? footerDisplayController.text
: 'Sentuh Salah Satu Layanan',
"footerTicket": footerTicketController.text != ''
? footerTicketController.text
: 'SCAN QR CODE UNTUK MELIHAT STATUS ANTRIAN',
"headerTicket": headerTicketController.text != ''
? headerTicketController.text
: 'Labratorium Medis & Klinik PRAMITA',
"hostQrIp": hostQrController.text,
"hostIp": hostIpController.text,
"selectedPrinter": selected_printer.value,
"selectedBooth": selected_booth.value,
"selectedBranch": selected_branch.value,
"activeLayanan": activeLayanan.value,
'buttonSize': selectedBtnSize.value,
"selectedCapability": selectedCapabilityProfile.value
};
json.encode(data);
await prefs.setString('tb-westerindo', json.encode(data));
return true;
} catch (e) {
ErrorDialog(context, e.toString(), 'ERROR');
print(e);
return false;
}
}
Color getColor(Set<MaterialState> states) {
const Set<MaterialState> interactiveStates = <MaterialState>{
MaterialState.pressed,
MaterialState.hovered,
MaterialState.focused,
};
if (states.any(interactiveStates.contains)) {
return Colors.blue;
}
if (states.contains(MaterialState.selected)) {
return Colors.green;
}
return Colors.white;
}
return Material(
child: Container(
height: Constant.getActualY(context: context, y: 982),
width: Constant.getActualX(context: context, x: 1512),
decoration: const BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
image: AssetImage("assets/images/new-bg-icon.png"))),
child: Center(
child: Card(
color: Colors.white,
shadowColor: Colors.white,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(10))),
elevation: 5,
child: SizedBox(
height: Constant.getActualY(context: context, y: 880),
width: Constant.getActualX(context: context, x: 1360),
child: Padding(
padding: EdgeInsets.symmetric(
horizontal: Constant.getActualX(context: context, x: 30),
vertical: Constant.getActualY(context: context, y: 30)),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
// TextButton(
// onPressed: () {
// Navigator.of(context)
// .popAndPushNamed(displayRoute);
// // print(pm.currentStatusUSB);
// // print(pm.currentStatusUSB);
// },
// child: const Text('back')),
Text(
'Setting',
style: Constant.subTitle(context: context),
),
// TextButton(
// onPressed: () {
// delData();
// },
// child: const Text('Delete All')),
],
),
SizedBox(
height: Constant.getActualY(context: context, y: 30),
),
FormInput(
pm: pm,
selected_booth: selected_booth,
booth: booth,
selected_printer: selected_printer,
prnt: dvcs,
branch: branch,
selected_branch: selected_branch,
hostIpController: hostIpController,
hostQrController: hostQrController,
headerDisplayController: headerDisplayController,
footerDisplayController: footerDisplayController,
headerTicketController: headerTicketController,
getServiceBooth: getServiceBooth,
isLoading: isLoading.value,
selectedCapability: selectedCapabilityProfile,
capabilityList: capabilityProfileList,
footerTicketController: footerTicketController),
SizedBox(
height: Constant.getActualY(context: context, y: 20),
),
Container(
// color: Colors.red,
height: Constant.getActualY(context: context, y: 40),
child: Row(
children: [
Tooltip(
message: "Jumlah tombol pada display",
child: Text('Button display',
style: Constant.label(context: context)),
),
SizedBox(
width: Constant.getActualX(context: context, x: 10),
),
Row(
children: [
SizedBox(
width: Constant.getActualX(
context: context, x: 10),
),
Row(
children: listBtnSize
.map(
(e) => Row(
children: [
Checkbox(
fillColor: MaterialStateProperty
.resolveWith(getColor),
value: e['name'].toString() ==
selectedBtnSize
.value['name']
? true
: false,
onChanged: ((value) {
selectedBtnSize.value = e;
})),
SizedBox(
width: Constant.getActualX(
context: context, x: 3),
),
Tooltip(
message: e['message'].toString(),
child: Text(
e['name'].toString(),
style: Constant.normal(
context: context),
),
),
SizedBox(
width: Constant.getActualX(
context: context, x: 15),
),
],
),
)
.toList(),
),
],
),
],
),
),
SizedBox(
height: Constant.getActualY(context: context, y: 190),
child: GridView.count(
childAspectRatio:
Constant.getActualY(context: context, y: 150) /
Constant.getActualX(context: context, x: 15),
crossAxisCount: 3,
children: lyn.value
.map((e) => Row(
children: [
Transform.scale(
scale: 0.8,
child: CupertinoSwitch(
value: e.value,
onChanged: (val) {
if (val) {
var rw_data = json.encode(
activeLayanan.value);
List data =
json.decode(rw_data);
List actlyn = data;
actlyn.add(e.id);
activeLayanan.value = actlyn;
}
if (!val) {
var rw_data = json.encode(
activeLayanan.value);
List data =
json.decode(rw_data);
List actlyn = data;
actlyn.remove(e.id);
activeLayanan.value = actlyn;
}
e.value = val;
}),
),
Expanded(
child: e.isConsultDoctor == 'N'
? Text(
e.name,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: Constant.normal(
context: context),
)
: Text(
"${e.name} ${e.doctorName}",
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: Constant.normal(
context: context),
),
)
],
))
.toList()),
),
SizedBox(
height: Constant.getActualY(context: context, y: 20),
),
Center(
child: SizedBox(
height: Constant.getActualY(context: context, y: 60),
width: Constant.getActualX(context: context, x: 200),
child: ElevatedButton(
onPressed: () {
if (selected_booth.value != null &&
selected_booth.value.id > 0 &&
selected_printer.value != null &&
selectedCapabilityProfile.value?.key !=
null &&
selected_branch.value != null &&
selected_branch.value.mBranchID != '0' &&
hostIpController.text.isNotEmpty &&
activeLayanan.value.isNotEmpty) {
saveData();
ref.read(allServiceProvider.notifier).state =
lyn.value;
Navigator.of(context).pushNamed(queueRoute);
} else {
if (selected_booth.value == null ||
selected_printer.value == null ||
selectedCapabilityProfile.value == null ||
hostIpController.text.isEmpty) {
ErrorDialog(
context,
'Input bertanda * tidak boleh kosong',
'PERINGATAN');
} else if (activeLayanan.value.isEmpty) {
ErrorDialog(
context,
'Layanan belum ada yang aktif',
'PERINGATAN');
}
}
},
style: ElevatedButton.styleFrom(
elevation: 5, backgroundColor: Colors.blue),
child: Text(
'Save',
style: Constant.subTitle(context: context)
.copyWith(color: Colors.white),
),
)),
)
],
),
),
),
),
),
),
));
}
}

View File

@@ -0,0 +1,103 @@
import 'dart:async';
import 'dart:convert';
import 'package:animated_text_kit/animated_text_kit.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_pos_printer_platform_image_3/flutter_pos_printer_platform_image_3.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:ticket_booth/app/constant.dart';
import 'package:ticket_booth/app/route.dart';
import 'package:ticket_booth/model/printer_device.dart';
import '../widgets/error_dialog.dart';
class SplashScreen extends HookConsumerWidget {
const SplashScreen({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final PrinterManager pm = PrinterManager.instance;
_connectDevice(PrinterDev selectedPrinter, PrinterType type,
{bool reconnect = true, String? ipAddress = null}) async {
try {
await pm.connect(
type: type,
model: UsbPrinterInput(
name: selectedPrinter.deviceName,
productId: selectedPrinter.productId,
vendorId: selectedPrinter.vendorId));
} catch (e) {
print(e);
}
}
Future getData() async {
try {
final prefs = await SharedPreferences.getInstance();
var raw_data = prefs.getString('tb-westerindo') ?? 'a';
if (raw_data != 'a') {
var data = json.decode(raw_data);
PrinterDev selectedPrinter =
PrinterDev.fromJson(data['selectedPrinter']);
_connectDevice(selectedPrinter, PrinterType.usb);
}
} catch (e) {
print(e);
ErrorDialog(context, e.toString(), 'ERROR');
}
}
useEffect(() {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
await getData();
Timer(const Duration(seconds: 3), () {
Navigator.of(context).pushNamed(displayRoute);
});
});
return () {};
}, []);
return Material(
child: Container(
height: Constant.getActualY(context: context, y: 982),
width: Constant.getActualX(context: context, x: 1512),
decoration: const BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
image: AssetImage("assets/images/new-bg-icon.png"))),
child: Column(
children: [
SizedBox(
height: Constant.getActualY(context: context, y: 600),
width: Constant.getActualX(context: context, x: 1512),
),
const SpinKitFadingCube(
color: Colors.redAccent,
size: 50.0,
),
SizedBox(
height: Constant.getActualY(context: context, y: 50),
),
DefaultTextStyle(
style: Constant.title(context: context)
.copyWith(fontStyle: FontStyle.italic, color: Colors.black),
child: AnimatedTextKit(animatedTexts: [
TyperAnimatedText('Loading ...',
speed: Duration(milliseconds: 300))
])),
SizedBox(
height: Constant.getActualY(context: context, y: 50),
),
Text(
Constant.versi,
style: Constant.subTitle(context: context)
.copyWith(fontStyle: FontStyle.italic, color: Colors.grey),
)
],
),
));
}
}

View File

@@ -0,0 +1,135 @@
import 'package:flutter/material.dart';
import 'package:qr_flutter/qr_flutter.dart';
import '../../app/constant.dart';
// ignore: non_constant_identifier_names
Future<String?> DialogPrint(BuildContext context, String noAntrian,
Function funcPrintTicket, String serviceName) {
return showDialog<String>(
context: context,
builder: (BuildContext context) => Dialog(
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
width: Constant.getActualX(context: context, x: 700),
alignment: Alignment.center,
child: Text(
textAlign: TextAlign.center,
'CETAK TIKET ANTRIAN',
style: Constant.subTitle(context: context),
),
),
const SizedBox(
height: 10,
),
SizedBox(
width: Constant.getActualX(context: context, x: 700),
child: const Divider()),
Container(
width: Constant.getActualX(context: context, x: 700),
alignment: Alignment.center,
child: Text(
textAlign: TextAlign.center,
serviceName,
style: Constant.subTitle(context: context),
),
),
const SizedBox(
height: 10,
),
Container(
width: Constant.getActualX(context: context, x: 700),
alignment: Alignment.center,
child: Text(
textAlign: TextAlign.center,
noAntrian,
style: Constant.subTitle(context: context),
),
),
Container(
width: Constant.getActualX(context: context, x: 700),
alignment: Alignment.center,
child: QrImageView(
data: noAntrian,
version: QrVersions.auto,
size: 290,
// embeddedImage: AssetImage('assets/images/logo-westerindo.png'),
// embeddedImageStyle: ,
gapless: false,
),
),
SizedBox(
height: 10,
),
Container(
width: Constant.getActualX(context: context, x: 700),
alignment: Alignment.center,
child: ElevatedButton(
onPressed: () {
funcPrintTicket(noAntrian);
},
style: ElevatedButton.styleFrom(
elevation: 5, backgroundColor: Colors.blue),
child: Text(
'Cetak Tiket',
style: Constant.label(context: context)
.copyWith(color: Colors.white),
),
),
),
SizedBox(
height: 10,
),
Container(
width: Constant.getActualX(context: context, x: 700),
alignment: Alignment.center,
child: Text(
textAlign: TextAlign.center,
"Scan qr code atau tekan tombol 'cetak tiket' untuk mendapatkan tiket",
style: Constant.label(context: context),
),
),
const SizedBox(
height: 10,
),
Container(
width: Constant.getActualX(context: context, x: 700),
alignment: Alignment.center,
child: Text(
textAlign: TextAlign.center,
"Tutup dialog setelah mendapatkan tiket",
style: Constant.label(context: context),
),
),
SizedBox(
width: Constant.getActualX(context: context, x: 700),
child: const Divider()),
const SizedBox(
height: 10,
),
SizedBox(
width: Constant.getActualX(context: context, x: 700),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text('Tutup'),
),
],
),
),
],
),
),
),
);
}

View File

@@ -0,0 +1,59 @@
import 'package:flutter/material.dart';
import '../../app/constant.dart';
Future<String?> ErrorDialog(
BuildContext context, String errorMsg, String header) {
return showDialog<String>(
context: context,
builder: (BuildContext context) => Dialog(
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
header,
style: Constant.subTitle(context: context),
),
const SizedBox(
height: 10,
),
SizedBox(
width: Constant.getActualX(context: context, x: 700),
child: const Divider()),
SizedBox(
height: Constant.getActualY(context: context, y: 500),
width: Constant.getActualX(context: context, x: 700),
child: ListView(
children: [Text(errorMsg)],
),
),
SizedBox(
width: Constant.getActualX(context: context, x: 700),
child: const Divider()),
const SizedBox(
height: 10,
),
SizedBox(
width: Constant.getActualX(context: context, x: 700),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text('Tutup'),
),
],
),
),
],
),
),
),
);
}

View File

@@ -0,0 +1,59 @@
import 'package:flutter/material.dart';
import '../../app/constant.dart';
// ignore: non_constant_identifier_names
Future<String?> PasienOnlineDialog(BuildContext context) {
return showDialog<String>(
context: context,
builder: (BuildContext context) => Dialog(
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Pasien Online',
style: Constant.subTitle(context: context),
),
const SizedBox(
height: 10,
),
SizedBox(
width: Constant.getActualX(context: context, x: 700),
child: const Divider()),
SizedBox(
height: Constant.getActualY(context: context, y: 500),
width: Constant.getActualX(context: context, x: 700),
child: ListView(
children: [TextField()],
),
),
SizedBox(
width: Constant.getActualX(context: context, x: 700),
child: const Divider()),
const SizedBox(
height: 10,
),
SizedBox(
width: Constant.getActualX(context: context, x: 700),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text('Tutup'),
),
],
),
),
],
),
),
),
);
}