Null Safety - Widgets Folder

merge-requests/2/head
omar alqaseer 3 years ago
parent b906ca60e6
commit 429c8136ee

@ -1,9 +1,9 @@
import '../../models/subtitle.dart'; import '../../models/subtitle.dart';
class HttpStatusManger { class HttpStatusManger {
static String getStatusMessage({ static String? getStatusMessage({
required int? status, required int? status,
required Subtitle subtitle, required Subtitle? subtitle,
String? messageFor400, String? messageFor400,
String? messageFor200, String? messageFor200,
}) { }) {
@ -11,28 +11,28 @@ class HttpStatusManger {
return "careful null status"; return "careful null status";
} }
if (status == -1) { if (status == -1) {
return subtitle.currentlyServiceNotAvailable; return subtitle?.currentlyServiceNotAvailable;
} }
if (status == -2) { if (status == -2) {
// client's request in process // client's request in process
return subtitle.waitUntilYourRequestComplete; return subtitle?.waitUntilYourRequestComplete;
} else if (status >= 200 && status < 300) { } else if (status >= 200 && status < 300) {
// client's request was successfully received // client's request was successfully received
return messageFor200 ?? subtitle.requestCompleteSuccessfully; return messageFor200 ?? subtitle?.requestCompleteSuccessfully;
} else if (status >= 400 && status < 500) { } else if (status >= 400 && status < 500) {
// client's request have error // client's request have error
switch (status) { switch (status) {
case 400: case 400:
return messageFor400 ?? subtitle.failedToCompleteRequest; return messageFor400 ?? subtitle?.failedToCompleteRequest;
default: default:
return subtitle.failedToCompleteRequest; return subtitle?.failedToCompleteRequest;
} }
} else if (status >= 500) { } else if (status >= 500) {
// server error // server error
return subtitle.currentlyServiceNotAvailable; return subtitle?.currentlyServiceNotAvailable;
} else { } else {
// no error match so return default error // no error match so return default error
return subtitle.failedToCompleteRequest; return subtitle?.failedToCompleteRequest;
} }
} }
} }

@ -108,7 +108,7 @@ class ServiceRequestsProvider extends ChangeNotifier {
'$host${URLs.getSingleServiceRequest}?call_nid=$requestId$userData', '$host${URLs.getSingleServiceRequest}?call_nid=$requestId$userData',
)); ));
} catch (error) { } catch (error) {
throw (HttpStatusManger.getStatusMessage(status: -1, subtitle: subtitle)); throw (HttpStatusManger.getStatusMessage(status: -1, subtitle: subtitle) ?? '');
} }
// If the call to the server was successful, parse the JSON. // If the call to the server was successful, parse the JSON.
@ -121,7 +121,7 @@ class ServiceRequestsProvider extends ChangeNotifier {
return requests[0]; return requests[0];
} else { } else {
throw (HttpStatusManger.getStatusMessage( throw (HttpStatusManger.getStatusMessage(
status: response.statusCode, subtitle: subtitle)); status: response.statusCode, subtitle: subtitle) ?? "");
} }
} }
@ -191,27 +191,27 @@ class ServiceRequestsProvider extends ChangeNotifier {
} }
Future<int> updateDate({ Future<int> updateDate({
required String host, required String? host,
required User user, required User? user,
required String newDate, required String? newDate,
required Lookup employee, required Lookup? employee,
required ServiceRequest request, required ServiceRequest? request,
}) async { }) async {
Response response; Response response;
Map<String, String> body = {}; Map<String, String> body = {};
body["uid"] = user.id; body["uid"] = user?.id ?? '';
body["token"] = user.token; body["token"] = user?.token ?? '';
body["nid"] = request.id ?? ''; body["nid"] = request?.id ?? '';
body["date"] = newDate; body["date"] = newDate ?? '';
body["ass_emp"] = employee.id.toString(); body["ass_emp"] = employee?.id.toString() ?? '';
try { try {
response = await post( response = await post(
Uri.parse(host + URLs.updateRequestDate), Uri.parse((host ?? '') + URLs.updateRequestDate),
body: body, body: body,
); );
stateCode = response.statusCode; stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) { if (response.statusCode >= 200 && response.statusCode < 300) {
request.engineerName = employee.label; request?.engineerName = employee?.label;
notifyListeners(); notifyListeners();
} }
return response.statusCode; return response.statusCode;
@ -317,12 +317,12 @@ class ServiceRequestsProvider extends ChangeNotifier {
body["uid"] = user.id; body["uid"] = user.id;
body["token"] = user.token; body["token"] = user.token;
body["job_id"] = request.id ?? ''; body["job_id"] = request.id ?? '';
body["start_time"] = body["start_time"] = ((timer.startAt?.millisecondsSinceEpoch ?? 0) / 1000)
(timer.startAt.millisecondsSinceEpoch / 1000).toStringAsFixed(0); .toStringAsFixed(0);
body["end_time"] = body["end_time"] =
(timer.endAt.millisecondsSinceEpoch / 1000).toStringAsFixed(0); ((timer.endAt?.millisecondsSinceEpoch ?? 0) / 1000).toStringAsFixed(0);
body["working_hours"] = body["working_hours"] =
(timer.durationInSecond / 60 / 60).toStringAsFixed(5); ((timer.durationInSecond ?? 0) / 60 / 60).toStringAsFixed(5);
body["report_id"] = request.reportID ?? ''; body["report_id"] = request.reportID ?? '';
try { try {
response = await post( response = await post(
@ -357,7 +357,9 @@ class ServiceRequestsProvider extends ChangeNotifier {
'$host${URLs.getServiceReport}?report_id=$reportId$userData', '$host${URLs.getServiceReport}?report_id=$reportId$userData',
)); ));
} catch (error) { } catch (error) {
throw (HttpStatusManger.getStatusMessage(status: -1, subtitle: subtitle)); throw (HttpStatusManger.getStatusMessage(
status: -1, subtitle: subtitle) ??
'');
} }
// If the call to the server was successful, parse the JSON. // If the call to the server was successful, parse the JSON.
@ -367,7 +369,10 @@ class ServiceRequestsProvider extends ChangeNotifier {
json.decode(utf8.decode(response.bodyBytes)), reportId); json.decode(utf8.decode(response.bodyBytes)), reportId);
} else { } else {
throw (HttpStatusManger.getStatusMessage( throw (HttpStatusManger.getStatusMessage(
status: response.statusCode, subtitle: subtitle)); status: response.statusCode,
subtitle: subtitle,
) ??
'');
} }
} }
} }

@ -45,14 +45,14 @@ class EmployeesProvider extends ChangeNotifier {
/// return state code if request complete may be 200, 404 or 403 /// return state code if request complete may be 200, 404 or 403
/// for more details check http state manager /// for more details check http state manager
/// lib\controllers\http_status_manger\http_status_manger.dart /// lib\controllers\http_status_manger\http_status_manger.dart
Future<int> getData({required String host, required User user}) async { Future<int> getData({required String? host, required User? user}) async {
if (_loading == true) return -2; if (_loading == true) return -2;
_loading = true; _loading = true;
notifyListeners(); notifyListeners();
Response response; Response response;
try { try {
response = await get( response = await get(
Uri.parse(host + URLs.getEmployees), Uri.parse((host ?? '') + URLs.getEmployees),
); );
_stateCode = response.statusCode; _stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) { if (response.statusCode >= 200 && response.statusCode < 300) {

@ -47,8 +47,8 @@ class GasCylinderSizesProvider extends ChangeNotifier {
/// for more details check http state manager /// for more details check http state manager
/// lib\controllers\http_status_manger\http_status_manger.dart /// lib\controllers\http_status_manger\http_status_manger.dart
Future<int> getData({ Future<int> getData({
required String host, required String? host,
required User user, required User? user,
}) async { }) async {
if (_loading == true) { if (_loading == true) {
return -2; return -2;
@ -58,7 +58,7 @@ class GasCylinderSizesProvider extends ChangeNotifier {
Response response; Response response;
try { try {
response = await get( response = await get(
Uri.parse(host + URLs.getGasCylinderSize), Uri.parse((host ?? '') + URLs.getGasCylinderSize),
); );
_stateCode = response.statusCode; _stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) { if (response.statusCode >= 200 && response.statusCode < 300) {

@ -46,13 +46,13 @@ class GasStatusProvider extends ChangeNotifier {
/// return state code if request complete may be 200, 404 or 403 /// return state code if request complete may be 200, 404 or 403
/// for more details check http state manager /// for more details check http state manager
/// lib\controllers\http_status_manger\http_status_manger.dart /// lib\controllers\http_status_manger\http_status_manger.dart
Future<int> getData({required String host, required User user}) async { Future<int> getData({required String? host, required User? user}) async {
if (_loading == true) return -2; if (_loading == true) return -2;
_loading = true; _loading = true;
notifyListeners(); notifyListeners();
Response response; Response response;
try { try {
response = await get(Uri.parse(host + URLs.getGasStatus)); response = await get(Uri.parse((host ?? '') + URLs.getGasStatus));
_stateCode = response.statusCode; _stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) { if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received // client's request was successfully received

@ -46,13 +46,13 @@ class GasTypesProvider extends ChangeNotifier {
/// return state code if request complete may be 200, 404 or 403 /// return state code if request complete may be 200, 404 or 403
/// for more details check http state manager /// for more details check http state manager
/// lib\controllers\http_status_manger\http_status_manger.dart /// lib\controllers\http_status_manger\http_status_manger.dart
Future<int> getData({required String host, required User user}) async { Future<int> getData({required String? host, required User? user}) async {
if (_loading == true) return -2; if (_loading == true) return -2;
_loading = true; _loading = true;
notifyListeners(); notifyListeners();
Response response; Response response;
try { try {
response = await get(Uri.parse(host + URLs.getGasTypes)); response = await get(Uri.parse((host ?? '') + URLs.getGasTypes));
_stateCode = response.statusCode; _stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) { if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received // client's request was successfully received

@ -45,7 +45,7 @@ class PentryStatusProvider extends ChangeNotifier {
/// return state code if request complete may be 200, 404 or 403 /// return state code if request complete may be 200, 404 or 403
/// for more details check http state manager /// for more details check http state manager
/// lib\controllers\http_status_manger\http_status_manger.dart /// lib\controllers\http_status_manger\http_status_manger.dart
Future<int> getData({required String host, required User user}) async { Future<int> getData({required String? host, required User? user}) async {
if (_loading == true) { if (_loading == true) {
return -2; return -2;
} }
@ -53,7 +53,7 @@ class PentryStatusProvider extends ChangeNotifier {
notifyListeners(); notifyListeners();
Response response; Response response;
try { try {
response = await get(Uri.parse(host + URLs.getPentryStatus)); response = await get(Uri.parse((host ?? '') + URLs.getPentryStatus));
_stateCode = response.statusCode; _stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) { if (response.statusCode >= 200 && response.statusCode < 300) {

@ -45,7 +45,7 @@ class PentryTaskStatusProvider extends ChangeNotifier {
/// return state code if request complete may be 200, 404 or 403 /// return state code if request complete may be 200, 404 or 403
/// for more details check http state manager /// for more details check http state manager
/// lib\controllers\http_status_manger\http_status_manger.dart /// lib\controllers\http_status_manger\http_status_manger.dart
Future<int> getData({required String host, required User user}) async { Future<int> getData({required String? host, required User? user}) async {
if (_loading == true) { if (_loading == true) {
return -2; return -2;
} }
@ -53,7 +53,7 @@ class PentryTaskStatusProvider extends ChangeNotifier {
notifyListeners(); notifyListeners();
Response response; Response response;
try { try {
response = await get(Uri.parse(host + URLs.getPentryTaskStatus)); response = await get(Uri.parse((host ?? '') + URLs.getPentryTaskStatus));
_stateCode = response.statusCode; _stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) { if (response.statusCode >= 200 && response.statusCode < 300) {

@ -45,7 +45,7 @@ class PentryVisitStatusProvider extends ChangeNotifier {
/// return state code if request complete may be 200, 404 or 403 /// return state code if request complete may be 200, 404 or 403
/// for more details check http state manager /// for more details check http state manager
/// lib\controllers\http_status_manger\http_status_manger.dart /// lib\controllers\http_status_manger\http_status_manger.dart
Future<int> getData({required String host, required User user}) async { Future<int> getData({required String? host, required User? user}) async {
if (_loading == true) { if (_loading == true) {
return -2; return -2;
} }
@ -53,7 +53,7 @@ class PentryVisitStatusProvider extends ChangeNotifier {
notifyListeners(); notifyListeners();
Response response; Response response;
try { try {
response = await get(Uri.parse(host + URLs.getPentryVisitStatus)); response = await get(Uri.parse((host ?? '') + URLs.getPentryVisitStatus));
_stateCode = response.statusCode; _stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) { if (response.statusCode >= 200 && response.statusCode < 300) {

@ -45,7 +45,7 @@ class ServiceRequestDefectTypesProvider extends ChangeNotifier {
/// return state code if request complete may be 200, 404 or 403 /// return state code if request complete may be 200, 404 or 403
/// for more details check http state manager /// for more details check http state manager
/// lib\controllers\http_status_manger\http_status_manger.dart /// lib\controllers\http_status_manger\http_status_manger.dart
Future<int> getData({required String host, required User user}) async { Future<int> getData({required String? host, required User? user}) async {
if (_loading == true) { if (_loading == true) {
return -2; return -2;
} }
@ -53,7 +53,7 @@ class ServiceRequestDefectTypesProvider extends ChangeNotifier {
notifyListeners(); notifyListeners();
Response response; Response response;
try { try {
response = await get(Uri.parse(host + URLs.getServiceReportDefectTypes)); response = await get(Uri.parse((host ?? '') + URLs.getServiceReportDefectTypes));
_stateCode = response.statusCode; _stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) { if (response.statusCode >= 200 && response.statusCode < 300) {

@ -47,8 +47,8 @@ class ServiceReportLastCallsProvider extends ChangeNotifier {
/// for more details check http state manager /// for more details check http state manager
/// lib\controllers\http_status_manger\http_status_manger.dart /// lib\controllers\http_status_manger\http_status_manger.dart
Future<int> getCalls({ Future<int> getCalls({
required String host, required String? host,
required User user, required User? user,
String? serviceStatus, String? serviceStatus,
}) async { }) async {
if (_loading == true) return -2; if (_loading == true) return -2;
@ -58,7 +58,7 @@ class ServiceReportLastCallsProvider extends ChangeNotifier {
try { try {
response = await get( response = await get(
Uri.parse( Uri.parse(
host + (host ?? '') +
URLs.getServiceReportLastCalls + URLs.getServiceReportLastCalls +
(serviceStatus == null ? "" : "?service_status=$serviceStatus"), (serviceStatus == null ? "" : "?service_status=$serviceStatus"),
), ),

@ -45,7 +45,7 @@ class ServiceRequestPriorityProvider extends ChangeNotifier {
/// return state code if request complete may be 200, 404 or 403 /// return state code if request complete may be 200, 404 or 403
/// for more details check http state manager /// for more details check http state manager
/// lib\controllers\http_status_manger\http_status_manger.dart /// lib\controllers\http_status_manger\http_status_manger.dart
Future<int> getData({required String host, required User user}) async { Future<int> getData({required String? host, required User? user}) async {
if (_loading == true) { if (_loading == true) {
return -2; return -2;
} }
@ -53,7 +53,7 @@ class ServiceRequestPriorityProvider extends ChangeNotifier {
notifyListeners(); notifyListeners();
Response response; Response response;
try { try {
response = await get(Uri.parse(host + URLs.getServiceReportPriority)); response = await get(Uri.parse((host ?? '') + URLs.getServiceReportPriority));
_stateCode = response.statusCode; _stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) { if (response.statusCode >= 200 && response.statusCode < 300) {

@ -45,7 +45,7 @@ class ServiceReportReasonsProvider extends ChangeNotifier {
/// return state code if request complete may be 200, 404 or 403 /// return state code if request complete may be 200, 404 or 403
/// for more details check http state manager /// for more details check http state manager
/// lib\controllers\http_status_manger\http_status_manger.dart /// lib\controllers\http_status_manger\http_status_manger.dart
Future<int> getTypes({required String host, required User user}) async { Future<int> getTypes({required String? host, required User? user}) async {
if (_loading == true) { if (_loading == true) {
return -2; return -2;
} }
@ -53,7 +53,7 @@ class ServiceReportReasonsProvider extends ChangeNotifier {
notifyListeners(); notifyListeners();
Response response; Response response;
try { try {
response = await get(Uri.parse(host + URLs.getServiceReportReasons)); response = await get(Uri.parse((host ?? '') + URLs.getServiceReportReasons));
_stateCode = response.statusCode; _stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) { if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received // client's request was successfully received

@ -45,7 +45,7 @@ class ServiceReportStatusProvider extends ChangeNotifier {
/// return state code if request complete may be 200, 404 or 403 /// return state code if request complete may be 200, 404 or 403
/// for more details check http state manager /// for more details check http state manager
/// lib\controllers\http_status_manger\http_status_manger.dart /// lib\controllers\http_status_manger\http_status_manger.dart
Future<int> getTypes({required String host, required User user}) async { Future<int> getTypes({required String? host, required User? user}) async {
if (_loading == true) { if (_loading == true) {
return -2; return -2;
} }
@ -53,7 +53,7 @@ class ServiceReportStatusProvider extends ChangeNotifier {
notifyListeners(); notifyListeners();
Response response; Response response;
try { try {
response = await get(Uri.parse(host + URLs.getServiceReportStatus)); response = await get(Uri.parse((host ?? '') + URLs.getServiceReportStatus));
_stateCode = response.statusCode; _stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) { if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received // client's request was successfully received

@ -45,7 +45,7 @@ class ServiceReportTypesProvider extends ChangeNotifier {
/// return state code if request complete may be 200, 404 or 403 /// return state code if request complete may be 200, 404 or 403
/// for more details check http state manager /// for more details check http state manager
/// lib\controllers\http_status_manger\http_status_manger.dart /// lib\controllers\http_status_manger\http_status_manger.dart
Future<int> getTypes({required String host, required User user}) async { Future<int> getTypes({required String? host, required User? user}) async {
if (_loading == true) { if (_loading == true) {
return -2; return -2;
} }
@ -53,7 +53,7 @@ class ServiceReportTypesProvider extends ChangeNotifier {
notifyListeners(); notifyListeners();
Response response; Response response;
try { try {
response = await get(Uri.parse(host + URLs.getServiceReportTypes)); response = await get(Uri.parse((host ?? '') + URLs.getServiceReportTypes));
_stateCode = response.statusCode; _stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) { if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received // client's request was successfully received

@ -45,7 +45,7 @@ class ServiceStatusProvider extends ChangeNotifier {
/// return state code if request complete may be 200, 404 or 403 /// return state code if request complete may be 200, 404 or 403
/// for more details check http state manager /// for more details check http state manager
/// lib\controllers\http_status_manger\http_status_manger.dart /// lib\controllers\http_status_manger\http_status_manger.dart
Future<int> getTypes({required String host, required User user}) async { Future<int> getTypes({required String? host, required User? user}) async {
if (_loading == true) { if (_loading == true) {
return -2; return -2;
} }
@ -53,7 +53,7 @@ class ServiceStatusProvider extends ChangeNotifier {
notifyListeners(); notifyListeners();
Response response; Response response;
try { try {
response = await get(Uri.parse(host + URLs.getServiceTypes)); response = await get(Uri.parse((host ?? '') + URLs.getServiceTypes));
_stateCode = response.statusCode; _stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) { if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received // client's request was successfully received

@ -1,8 +1,8 @@
class Lookup{ class Lookup{
final String label; final String? label;
final String key; final String? key;
final int id; final int? id;
const Lookup({ const Lookup({
this.label, this.label,

@ -179,7 +179,7 @@ class Subtitle{
String requiredStatus; String requiredStatus;
String visitInformation; String visitInformation;
String expectDate; String expectDate;
String actualDate; String? actualDate;
String noVisitsFound; String noVisitsFound;
String contactStatus; String contactStatus;
String workingHours; String workingHours;

@ -1,7 +1,7 @@
class TimerModel { class TimerModel {
DateTime startAt; DateTime? startAt;
DateTime endAt; DateTime? endAt;
int durationInSecond; int? durationInSecond;
TimerModel({this.startAt,this.endAt,this.durationInSecond}); TimerModel({this.startAt,this.endAt,this.durationInSecond});
} }

@ -3,12 +3,12 @@ class VisitsSearch{
String hospitalName; String hospitalName;
String brand; String brand;
String model; String model;
String contactStatus; String? contactStatus;
DateTime expectedDateFrom; DateTime expectedDateFrom;
DateTime expectedDateTo; DateTime expectedDateTo;
DateTime actualDateFrom; DateTime actualDateFrom;
DateTime actualDateTo; DateTime actualDateTo;
int statusValue; int? statusValue;
VisitsSearch({ VisitsSearch({
this.deviceSerialNumber, this.deviceSerialNumber,

@ -1,20 +1,24 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:test_sa/views/app_style/colors.dart';
import 'package:test_sa/views/app_style/sizing.dart'; import '../app_style/colors.dart';
import '../app_style/sizing.dart';
class AppNameBar extends StatelessWidget { class AppNameBar extends StatelessWidget {
const AppNameBar({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
height: 50 * AppStyle.getScaleFactor(context), height: 50 * AppStyle.getScaleFactor(context),
color:AColors.primaryColor, color: AColors.primaryColor,
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: Center( child: Center(
child: Text( child: Text(
"Test SA", "Test SA",
style: Theme.of(context).textTheme.headline6.copyWith( style: Theme.of(context)
color: AColors.white, .textTheme
fontStyle: FontStyle.italic .titleLarge
), ?.copyWith(color: AColors.white, fontStyle: FontStyle.italic),
), ),
), ),
); );

@ -1,49 +1,50 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:test_sa/views/app_style/sizing.dart';
import '../app_style/sizing.dart';
class ATextFormField extends StatefulWidget { class ATextFormField extends StatefulWidget {
final Function(String) onSaved; final Function(String?)? onSaved;
final Function(String) validator; final String Function(String?)? validator;
final Function(String) onChange; final Function(String)? onChange;
final bool obscureText; final bool? obscureText;
final VoidCallback showPassword; final VoidCallback? showPassword;
final String hintText; final String? hintText;
final String labelText; final String? labelText;
final TextInputType textInputType; final TextInputType? textInputType;
final String initialValue; final String? initialValue;
final TextStyle style; final TextStyle? style;
final bool enable; final bool? enable;
final TextAlign textAlign; final TextAlign? textAlign;
final FocusNode node; final FocusNode? node;
final Widget suffixIcon; final Widget? suffixIcon;
final IconData prefixIconData; final IconData? prefixIconData;
final double prefixIconSize; final double? prefixIconSize;
final TextEditingController controller; final TextEditingController? controller;
final TextInputAction textInputAction; final TextInputAction? textInputAction;
final VoidCallback onAction; final VoidCallback? onAction;
const ATextFormField( const ATextFormField({
{Key key, Key? key,
this.onSaved, this.initialValue,
this.validator, this.node,
this.node, this.onChange,
this.onChange, this.showPassword,
this.obscureText, this.hintText,
this.showPassword, this.labelText,
this.hintText, this.style,
this.labelText, this.textAlign,
this.textInputType = TextInputType.text, this.suffixIcon,
this.initialValue, this.prefixIconSize,
this.enable = true, this.textInputAction,
this.style, this.onAction,
this.textAlign, this.obscureText,
this.suffixIcon, this.textInputType = TextInputType.text,
this.prefixIconData, this.enable = true,
this.prefixIconSize, this.prefixIconData,
this.controller, this.controller,
this.textInputAction, this.onSaved,
this.onAction}) this.validator,
: super(key: key); }) : super(key: key);
@override @override
State<ATextFormField> createState() => _ATextFormFieldState(); State<ATextFormField> createState() => _ATextFormFieldState();
@ -52,7 +53,9 @@ class ATextFormField extends StatefulWidget {
class _ATextFormFieldState extends State<ATextFormField> { class _ATextFormFieldState extends State<ATextFormField> {
@override @override
void initState() { void initState() {
if (widget.controller != null) widget.controller.text = widget.initialValue; if (widget.controller != null) {
widget.controller!.text = widget.initialValue ?? '';
}
super.initState(); super.initState();
} }
@ -60,13 +63,15 @@ class _ATextFormFieldState extends State<ATextFormField> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
height: widget.textInputType == TextInputType.multiline ? null : 50, height: widget.textInputType == TextInputType.multiline ? null : 50,
padding: EdgeInsets.only(left: 12, right: 12), padding: const EdgeInsets.only(left: 12, right: 12),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Color(0xfff5f5f5), color: const Color(0xfff5f5f5),
border: Border.all( border: Border.all(
color: Color(0xffefefef), color: const Color(0xffefefef),
),
borderRadius: BorderRadius.circular(
AppStyle.borderRadius * AppStyle.getScaleFactor(context),
), ),
borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)),
), ),
child: TextFormField( child: TextFormField(
focusNode: widget.node, focusNode: widget.node,
@ -81,18 +86,21 @@ class _ATextFormFieldState extends State<ATextFormField> {
maxLines: widget.textInputType == TextInputType.multiline ? null : 1, maxLines: widget.textInputType == TextInputType.multiline ? null : 1,
obscuringCharacter: "", obscuringCharacter: "",
controller: widget.controller, controller: widget.controller,
textInputAction: widget.textInputType == TextInputType.multiline ? null : widget.textInputAction ?? TextInputAction.next, textInputAction: widget.textInputType == TextInputType.multiline
onEditingComplete: widget.onAction ?? () => FocusScope.of(context).nextFocus(), ? null
: widget.textInputAction ?? TextInputAction.next,
onEditingComplete:
widget.onAction ?? () => FocusScope.of(context).nextFocus(),
// style: widget.style, // style: widget.style,
style: Theme.of(context).textTheme.bodyText1, style: Theme.of(context).textTheme.bodyLarge,
decoration: InputDecoration( decoration: InputDecoration(
border: InputBorder.none, border: InputBorder.none,
suffixIconConstraints: BoxConstraints(minWidth: 0), suffixIconConstraints: const BoxConstraints(minWidth: 0),
disabledBorder: InputBorder.none, disabledBorder: InputBorder.none,
focusedBorder: InputBorder.none, focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none, enabledBorder: InputBorder.none,
constraints: BoxConstraints(), constraints: const BoxConstraints(),
errorStyle: TextStyle(height: 0.3), errorStyle: const TextStyle(height: 0.3),
//contentPadding: EdgeInsets.only(left: 0), //contentPadding: EdgeInsets.only(left: 0),
hintText: widget.hintText, hintText: widget.hintText,
labelText: widget.labelText, labelText: widget.labelText,
@ -100,7 +108,11 @@ class _ATextFormFieldState extends State<ATextFormField> {
suffixIcon: widget.prefixIconData == null suffixIcon: widget.prefixIconData == null
? null ? null
: Icon(widget.prefixIconData, : Icon(widget.prefixIconData,
size: widget.prefixIconSize == null ? 20 * AppStyle.getScaleFactor(context) : (widget.prefixIconSize - 10) * AppStyle.getScaleFactor(context), color: Color(0xff2e303a))), size: widget.prefixIconSize == null
? 20 * AppStyle.getScaleFactor(context)
: (widget.prefixIconSize! - 10) *
AppStyle.getScaleFactor(context),
color: const Color(0xff2e303a))),
), ),
); );
} }

@ -2,13 +2,13 @@ import 'package:test_sa/views/app_style/sizing.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class ASmallButton extends StatelessWidget { class ASmallButton extends StatelessWidget {
final String text; final String? text;
final TextStyle style; final TextStyle style;
final Color color; final Color color;
final EdgeInsets padding; final EdgeInsets padding;
final VoidCallback onPressed; final VoidCallback onPressed;
const ASmallButton({Key key, this.text, this.style ,this.onPressed,this.padding, this.color}) : super(key: key); const ASmallButton({Key? key, this.text, this.style ,this.onPressed,this.padding, this.color}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ElevatedButton( return ElevatedButton(

@ -5,12 +5,12 @@ import 'package:test_sa/views/app_style/sizing.dart';
import 'date_picker.dart'; import 'date_picker.dart';
class FromToDateBar extends StatefulWidget { class FromToDateBar extends StatefulWidget {
final DateTime from; final DateTime? from;
final DateTime to; final DateTime? to;
final Function(DateTime) onPickFrom; final Function(DateTime) onPickFrom;
final Function(DateTime) onPickTo; final Function(DateTime) onPickTo;
const FromToDateBar({Key key, this.from, this.to, this.onPickFrom, this.onPickTo}) : super(key: key); const FromToDateBar({Key? key, this.from, this.to, this.onPickFrom, this.onPickTo}) : super(key: key);
@override @override
_FromToDateBarState createState() => _FromToDateBarState(); _FromToDateBarState createState() => _FromToDateBarState();
} }

@ -5,24 +5,25 @@ import 'package:test_sa/models/subtitle.dart';
import 'app_loading.dart'; import 'app_loading.dart';
import 'failed_loading.dart'; import 'failed_loading.dart';
class LoadingManager extends StatefulWidget { class LoadingManager extends StatefulWidget {
final bool isLoading; final bool? isLoading;
final bool isFailedLoading; final bool isFailedLoading;
final bool isNotPage; final bool isNotPage;
final int progress; final int? progress;
final bool askOnBack; final bool askOnBack;
final int stateCode; final int? stateCode;
final Future<void> Function() onRefresh; final Future<void> Function() onRefresh;
final Widget child; final Widget child;
LoadingManager({ const LoadingManager({
Key key, Key? key,
@required this.isLoading, required this.isFailedLoading,
@required this.isFailedLoading, required this.onRefresh,
@required this.stateCode, required this.child,
@required this.onRefresh,
@required this.child,
this.progress, this.progress,
this.stateCode,
this.isLoading,
this.isNotPage = false, this.isNotPage = false,
this.askOnBack = false, this.askOnBack = false,
}) : super(key: key); }) : super(key: key);
@ -32,10 +33,9 @@ class LoadingManager extends StatefulWidget {
} }
class _LoadingManagerState extends State<LoadingManager> { class _LoadingManagerState extends State<LoadingManager> {
@override @override
void initState() { void initState() {
if(widget.onRefresh != null && widget.stateCode == null){ if (widget.onRefresh != null && widget.stateCode == null) {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) { WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
widget.onRefresh(); widget.onRefresh();
}); });
@ -48,7 +48,7 @@ class _LoadingManagerState extends State<LoadingManager> {
Subtitle subtitle = AppLocalization.of(context).subtitle; Subtitle subtitle = AppLocalization.of(context).subtitle;
Widget placeHolder; Widget placeHolder;
// to load data if load not start // to load data if load not start
if(widget.isLoading == false && widget.stateCode == null){ if (widget.isLoading == false && widget.stateCode == null) {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) { WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
widget.onRefresh(); widget.onRefresh();
}); });
@ -56,9 +56,9 @@ class _LoadingManagerState extends State<LoadingManager> {
// if loading of still not start in loading (true or null) // if loading of still not start in loading (true or null)
// return loading widget // return loading widget
if(widget.isLoading != false || widget.stateCode == null){ if (widget.isLoading != false || widget.stateCode == null) {
placeHolder = ALoading(); placeHolder = ALoading();
}else if(widget.isFailedLoading && !widget.isNotPage){ } else if (widget.isFailedLoading && !widget.isNotPage) {
// if failed return failed widget // if failed return failed widget
placeHolder = FailedLoading( placeHolder = FailedLoading(
message: HttpStatusManger.getStatusMessage( message: HttpStatusManger.getStatusMessage(
@ -69,7 +69,7 @@ class _LoadingManagerState extends State<LoadingManager> {
// if load end successfully return loaded widget // if load end successfully return loaded widget
return RefreshIndicator( return RefreshIndicator(
onRefresh: () async{ onRefresh: () async {
await widget.onRefresh(); await widget.onRefresh();
}, },
child: AnimatedSwitcher( child: AnimatedSwitcher(

@ -1,10 +1,12 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:test_sa/views/app_style/sizing.dart';
import '../../app_style/sizing.dart';
class NoItemFound extends StatelessWidget { class NoItemFound extends StatelessWidget {
final String message; final String? message;
const NoItemFound({ const NoItemFound({
Key key, Key? key,
this.message, this.message,
}) : super(key: key); }) : super(key: key);
@ -14,7 +16,7 @@ class NoItemFound extends StatelessWidget {
children: [ children: [
Center( Center(
child: Text( child: Text(
message ?? "no item found", message ?? "no item found",
style: Theme.of(context).textTheme.headline6, style: Theme.of(context).textTheme.headline6,
textScaleFactor: AppStyle.getScaleFactor(context), textScaleFactor: AppStyle.getScaleFactor(context),
), ),

@ -5,16 +5,16 @@ import 'package:qr_code_scanner/qr_code_scanner.dart';
import '../buttons/app_icon_button.dart'; import '../buttons/app_icon_button.dart';
class ScanQr extends StatefulWidget { class ScanQr extends StatefulWidget {
const ScanQr({Key key}) : super(key: key); const ScanQr({Key? key}) : super(key: key);
@override @override
_ScanQrState createState() => _ScanQrState(); ScanQrState createState() => ScanQrState();
} }
class _ScanQrState extends State<ScanQr> { class ScanQrState extends State<ScanQr> {
Barcode result; Barcode? result;
QRViewController _controller; QRViewController? _controller;
bool _scanDone = false; bool _scanDone = false;
final GlobalKey qrKey = GlobalKey(debugLabel: 'QR_scanner'); final GlobalKey qrKey = GlobalKey(debugLabel: 'QR_scanner');
@ -64,7 +64,7 @@ class _ScanQrState extends State<ScanQr> {
), ),
SafeArea( SafeArea(
child: Padding( child: Padding(
padding: EdgeInsets.all(12.0), padding: const EdgeInsets.all(12.0),
child: AIconButton( child: AIconButton(
iconData:Icons.arrow_back, iconData:Icons.arrow_back,
onPressed: (){ onPressed: (){

@ -1,74 +1,83 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:test_sa/views/app_style/sizing.dart';
import '../../app_style/sizing.dart';
class RequestInfoRow extends StatelessWidget { class RequestInfoRow extends StatelessWidget {
final String title; final String? title;
final String info; final String? info;
final String content; final String? content;
final Widget contentWidget; final Widget? contentWidget;
final Widget infoWidget; final Widget? infoWidget;
const RequestInfoRow({
Key? key,
this.title,
this.info,
this.content,
this.contentWidget,
this.infoWidget,
}) : super(key: key);
const RequestInfoRow({Key key, this.title, this.info,this.content, this.contentWidget, this.infoWidget}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if(info != null && info.isEmpty){ if (info != null && info!.isEmpty) {
return SizedBox.shrink(); return const SizedBox.shrink();
} }
if(content != null && content.isEmpty){ if (content != null && content!.isEmpty) {
return SizedBox.shrink(); return const SizedBox.shrink();
} }
return Column( return Column(
children: [ children: [
Row( Row(
children: [ children: [
Text( Text(
title + " : ", "$title : ",
style: Theme.of(context).textTheme.subtitle2.copyWith( style: Theme.of(context).textTheme.titleSmall?.copyWith(
//fontSize: 12 //fontSize: 12
), ),
textScaleFactor: AppStyle.getScaleFactor(context), textScaleFactor: AppStyle.getScaleFactor(context),
), ),
if (info != null)
if(info != null) Expanded(
Expanded( child: Text(
child: Text( info ?? '',
info, style: Theme.of(context).textTheme.bodyMedium,
style: Theme.of(context).textTheme.bodyText2, textAlign: TextAlign.right,
textAlign: TextAlign.right, textScaleFactor: AppStyle.getScaleFactor(context),
textScaleFactor: AppStyle.getScaleFactor(context), ),
), ),
), if (infoWidget != null)
if(infoWidget != null)
Expanded( Expanded(
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
children: [ children: [
infoWidget, infoWidget ?? const SizedBox(),
], ],
), ),
), ),
], ],
), ),
if (content != null)
if(content != null) Padding(
Padding( padding: const EdgeInsets.symmetric(horizontal: 8),
padding: const EdgeInsets.symmetric(horizontal: 8), child: Row(
child: Row( children: [
children: [ Expanded(
Expanded( child: Text(
child: Text( content ?? 'No data found',
content ?? 'No data found', style: Theme.of(context).textTheme.bodyMedium,
style: Theme.of(context).textTheme.bodyText2, textAlign: TextAlign.center,
textAlign: TextAlign.center, textScaleFactor: AppStyle.getScaleFactor(context),
textScaleFactor: AppStyle.getScaleFactor(context), ),
), ),
), ],
], ),
), ),
if (contentWidget != null) contentWidget!,
Divider(
color: Theme.of(context).primaryColor,
), ),
if(contentWidget != null)
contentWidget,
Divider(color: Theme.of(context).primaryColor,),
], ],
); );
} }
} }

@ -1,35 +1,39 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:test_sa/views/app_style/colors.dart';
import 'package:test_sa/views/app_style/sizing.dart';
class StatusLabel extends StatelessWidget {
final String label;
final Color color;
const StatusLabel({Key key, this.label, this.color}) : super(key: key); import '../../app_style/colors.dart';
import '../../app_style/sizing.dart';
class StatusLabel extends StatelessWidget {
final String? label;
final Color? color;
const StatusLabel({
Key? key,
this.label,
this.color,
}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
padding: EdgeInsets.symmetric(vertical: 2,horizontal: 8), padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 8),
alignment: Alignment.center, alignment: Alignment.center,
decoration: BoxDecoration( decoration: BoxDecoration(
color: color ?? Colors.green, color: color ?? Colors.green,
borderRadius: BorderRadius.circular( borderRadius: BorderRadius.circular(
AppStyle.getBorderRadius(context) AppStyle.getBorderRadius(context),
), ),
boxShadow: [ boxShadow: const [AppStyle.boxShadow],
AppStyle.boxShadow
]
), ),
child: Text( child: Text(
label ?? "no status", label ?? "no status",
style: Theme.of(context).textTheme.subtitle2.copyWith( style: Theme.of(context).textTheme.titleSmall?.copyWith(
color: color.computeLuminance() > 0.5 color: color != null
? AColors.black : Colors.white, ? color!.computeLuminance() > 0.5
), ? AColors.black
) : Colors.white
); : null,
),
));
} }
} }

@ -1,37 +1,37 @@
import 'package:fluttertoast/fluttertoast.dart';
import 'package:test_sa/controllers/localization/localization.dart';
import 'package:test_sa/controllers/providers/api/service_requests_provider.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart';
import 'package:test_sa/controllers/providers/settings/setting_provider.dart';
import 'package:test_sa/models/enums/user_types.dart';
import 'package:test_sa/models/service_request/service_request.dart';
import 'package:test_sa/models/subtitle.dart';
import 'package:test_sa/models/user.dart';
import 'package:test_sa/views/app_style/colors.dart';
import 'package:test_sa/views/app_style/sizing.dart';
import 'package:test_sa/views/pages/user/requests/report/create_service_report.dart';
import 'package:test_sa/views/pages/user/requests/report/future_service_report.dart';
import 'package:test_sa/views/widgets/loaders/image_loader.dart';
import 'package:test_sa/views/widgets/requests/request_status.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:test_sa/views/widgets/timer/app_timer.dart';
import '../../../controllers/http_status_manger/http_status_manger.dart'; import '../../../controllers/localization/localization.dart';
import '../../../controllers/providers/api/service_requests_provider.dart';
import '../../../controllers/providers/api/user_provider.dart';
import '../../../controllers/providers/settings/setting_provider.dart';
import '../../../models/enums/user_types.dart';
import '../../../models/service_request/service_request.dart';
import '../../../models/subtitle.dart';
import '../../../models/user.dart';
import '../../app_style/colors.dart';
import '../../app_style/sizing.dart';
import '../../pages/user/requests/report/create_service_report.dart';
import '../loaders/image_loader.dart';
import 'request_status.dart';
class ServiceRequestItem extends StatelessWidget { class ServiceRequestItem extends StatelessWidget {
final int index; final int index;
final ServiceRequest request; final ServiceRequest request;
final Function(ServiceRequest) onPressed; final Function(ServiceRequest) onPressed;
const ServiceRequestItem({Key key, this.request, this.onPressed, this.index}) : super(key: key);
const ServiceRequestItem({
Key? key,
required this.request,
required this.onPressed,
required this.index,
}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Subtitle _subtitle = AppLocalization.of(context).subtitle; Subtitle? subtitle = AppLocalization.of(context)?.subtitle;
User _user = Provider.of<UserProvider>(context,listen: false).user; User? user = Provider.of<UserProvider>(context, listen: false).user;
final servicesProvider = Provider.of<ServiceRequestsProvider>(context,listen: false);
final settingProvider = Provider.of<SettingProvider>(context,listen: false);
Color itemColor = index % 2 == 0 Color itemColor = index % 2 == 0
? Theme.of(context).colorScheme.primary ? Theme.of(context).colorScheme.primary
: Theme.of(context).colorScheme.onPrimary; : Theme.of(context).colorScheme.onPrimary;
@ -42,71 +42,76 @@ class ServiceRequestItem extends StatelessWidget {
return Padding( return Padding(
padding: const EdgeInsets.symmetric(vertical: 4), padding: const EdgeInsets.symmetric(vertical: 4),
child: ElevatedButton( child: ElevatedButton(
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
padding: EdgeInsets.symmetric(vertical: 8,horizontal: 8), padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 8),
primary: itemColor, backgroundColor: itemColor,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular( borderRadius: BorderRadius.circular(
AppStyle.getBorderRadius(context) AppStyle.getBorderRadius(context),
), ),
), ),
), ),
//padding: EdgeInsets.symmetric(vertical: 8,horizontal: 8), onPressed: () {
onPressed: (){
onPressed(request); onPressed(request);
}, },
child: Row( child: Row(
children: [ children: [
//Placeholder(color: onItemColor,fallbackWidth: 80,fallbackHeight: 80,), user?.type == UsersTypes.normal_user &&
_user.type == UsersTypes.normal_user && request.devicePhotos.isEmpty ? SizedBox.shrink(): (request.devicePhotos?.isEmpty ?? true)
SizedBox( ? const SizedBox.shrink()
width: 80, : SizedBox(
child: Column( width: 80,
mainAxisAlignment: MainAxisAlignment.spaceBetween, child: Column(
children: [ mainAxisAlignment: MainAxisAlignment.spaceBetween,
request.devicePhotos.isEmpty ? SizedBox.shrink(): children: [
Column( request.devicePhotos?.isEmpty ?? true
children: [ ? const SizedBox.shrink()
SizedBox( : Column(
height: 80, children: [
width: 80, SizedBox(
child: ImageLoader( height: 80,
url: request.devicePhotos.first, width: 80,
boxFit: BoxFit.cover, child: ImageLoader(
), url: request.devicePhotos?.first ?? '',
), boxFit: BoxFit.cover,
SizedBox(height: 24,), ),
], ),
), const SizedBox(
height: 24,
),
],
),
_user.type == UsersTypes.engineer ? user?.type == UsersTypes.engineer
Material( ? Material(
color: onItemColor, color: onItemColor,
elevation: 6, elevation: 6,
shape: CircleBorder(), shape: const CircleBorder(),
child: IconButton( child: IconButton(
icon: Icon( icon: Icon(
Icons.description, Icons.description,
color: itemColor, color: itemColor,
size: 32, size: 32,
), ),
onPressed: (){ onPressed: () {
Navigator.of(context).push( Navigator.of(context).push(
MaterialPageRoute( MaterialPageRoute(
builder: (_) => CreateServiceReport( builder: (_) => CreateServiceReport(
request: request, request: request,
),
),
);
},
),
) )
), : const SizedBox.shrink(),
); //SizedBox(height: 8,),
}, ],
), ),
) :SizedBox.shrink(), ),
//SizedBox(height: 8,), const SizedBox(
width: 8,
],
),
), ),
SizedBox(width: 8,),
Expanded( Expanded(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -120,141 +125,182 @@ class ServiceRequestItem extends StatelessWidget {
Row( Row(
children: [ children: [
Expanded( Expanded(
child: request.requestCode == null ? SizedBox.shrink(): child: request.requestCode == null
Text( ? const SizedBox.shrink()
request.requestCode ?? "-----", : Text(
style: Theme.of(context).textTheme.headline6.copyWith( request.requestCode ?? "-----",
color: onItemColor, style: Theme.of(context)
fontSize: 16, .textTheme
fontWeight: FontWeight.bold .titleLarge
), ?.copyWith(
), color: onItemColor,
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
), ),
request.engineerName == null ? SizedBox.shrink(): request.engineerName == null
Text( ? const SizedBox.shrink()
request.engineerName ?? "", : Text(
style: Theme.of(context).textTheme.subtitle2.copyWith( request.engineerName ?? "",
color: onItemColor, style: Theme.of(context)
fontSize: 12, .textTheme
fontWeight: FontWeight.normal .titleSmall
), ?.copyWith(
), color: onItemColor,
fontSize: 12,
fontWeight: FontWeight.normal,
),
),
], ],
), ),
Divider(color: onItemColor,), Divider(
Row( color: onItemColor,
children: [
Expanded(
child: request.deviceModel == null ? SizedBox.shrink():
Text(
request.deviceModel ?? "Model not available",
style: Theme.of(context).textTheme.subtitle2.copyWith(
color: onItemColor,
fontSize: 12,
fontWeight: FontWeight.normal
),
),
),
request.engineerMobile == null ? SizedBox.shrink():
Text(
request.engineerMobile,
style: Theme.of(context).textTheme.subtitle1.copyWith(
color: onItemColor,
fontSize: 12,
fontWeight: FontWeight.normal
),
),
],
), ),
Divider(color: onItemColor,),
Row( Row(
children: [ children: [
Expanded( Expanded(
child: request.deviceSerialNumber == null ? SizedBox.shrink(): child: request.deviceModel == null
Text( ? const SizedBox.shrink()
request.deviceSerialNumber, : Text(
style: Theme.of(context).textTheme.subtitle2.copyWith( request.deviceModel ??
color: onItemColor, "Model not available",
fontSize: 12, style: Theme.of(context)
fontWeight: FontWeight.normal .textTheme
), .titleSmall
), ?.copyWith(
color: onItemColor,
fontSize: 12,
fontWeight: FontWeight.normal,
),
),
), ),
request.engineerMobile == null
? const SizedBox.shrink()
: Text(
request.engineerMobile ?? '',
style: Theme.of(context)
.textTheme
.titleMedium
?.copyWith(
color: onItemColor,
fontSize: 12,
fontWeight: FontWeight.normal,
),
),
], ],
), ),
request.deviceEnName == null ? SizedBox.shrink(): Divider(
color: onItemColor,
),
Row( Row(
children: [ children: [
Expanded( Expanded(
child: Text( child: request.deviceSerialNumber == null
request.deviceEnName, ? const SizedBox.shrink()
style: Theme.of(context).textTheme.subtitle1.copyWith( : Text(
color: onItemColor, request.deviceSerialNumber ?? '',
fontSize: 12, style: Theme.of(context)
fontWeight: FontWeight.normal .textTheme
), .titleSmall
), ?.copyWith(
color: onItemColor,
fontSize: 12,
fontWeight: FontWeight.normal,
),
),
), ),
], ],
), ),
request.deviceEnName == null
? const SizedBox.shrink()
: Row(
children: [
Expanded(
child: Text(
request.deviceEnName ?? '',
style: Theme.of(context)
.textTheme
.titleMedium
?.copyWith(
color: onItemColor,
fontSize: 12,
fontWeight: FontWeight.normal,
),
),
),
],
),
], ],
), ),
), ),
], ],
), ),
Divider(
Divider(color: onItemColor,), color: onItemColor,
),
Center( Center(
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8), padding: const EdgeInsets.symmetric(horizontal: 8),
child: Text( child: Text(
request.maintenanceIssue ?? "No maintenance issue found", request.maintenanceIssue ??
style: Theme.of(context).textTheme.subtitle1.copyWith( "No maintenance issue found",
color: onItemColor style: Theme.of(context)
), .textTheme
.titleMedium
?.copyWith(color: onItemColor),
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
), ),
), ),
Divider(color: onItemColor,), Divider(color: onItemColor),
Row( Row(
children: [ children: [
Text( Text(
request.date ?? "Date not available", request.date ?? "Date not available",
style: Theme.of(context).textTheme.subtitle2.copyWith( style: Theme.of(context)
color: onItemColor .textTheme
.titleSmall
?.copyWith(color: onItemColor),
),
const Spacer(),
StatusLabel(
label: request.statusLabel,
color: AColors.getRequestStatusColor(
request.statusValue ?? 0,
), ),
), ),
Spacer(),
StatusLabel(label: request.statusLabel,
color: AColors.getRequestStatusColor(request.statusValue)),
], ],
), ),
request.nextVisitDate == null ? SizedBox.shrink() : request.nextVisitDate == null
Column( ? const SizedBox.shrink()
children: [ : Column(
Divider(color: onItemColor,), children: [
Row( Divider(
children: [ color: onItemColor,
Text(
_subtitle.nextVisitDate,
style: Theme.of(context).textTheme.subtitle2.copyWith(
color: onItemColor
), ),
), Row(
Spacer(), children: [
Text( Text(
DateFormat('EE dd/MM/yyyy').format(request.nextVisitDate), subtitle?.nextVisitDate ?? '',
style: Theme.of(context).textTheme.subtitle2.copyWith( style: Theme.of(context)
color: onItemColor .textTheme
.titleSmall
?.copyWith(color: onItemColor),
),
const Spacer(),
Text(
DateFormat('EE dd/MM/yyyy')
.format(request.nextVisitDate!),
style: Theme.of(context)
.textTheme
.titleSmall
?.copyWith(color: onItemColor),
),
],
), ),
), ],
], ),
),
],
),
], ],
), ),
), ),

@ -1,24 +1,30 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:test_sa/controllers/localization/localization.dart';
import 'package:test_sa/models/service_request/service_request.dart'; import '../../../controllers/localization/localization.dart';
import 'package:test_sa/models/subtitle.dart'; import '../../../models/service_request/service_request.dart';
import 'package:test_sa/views/pages/user/requests/request_details.dart'; import '../../../models/subtitle.dart';
import 'package:test_sa/views/widgets/loaders/lazy_loading.dart'; import '../../pages/user/requests/request_details.dart';
import 'package:test_sa/views/widgets/loaders/no_item_found.dart'; import '../loaders/lazy_loading.dart';
import 'package:test_sa/views/widgets/requests/service_request_item.dart'; import '../loaders/no_item_found.dart';
import 'service_request_item.dart';
class ServiceRequestsList extends StatelessWidget { class ServiceRequestsList extends StatelessWidget {
final List<ServiceRequest> requests; final List<ServiceRequest> requests;
final bool nextPage; final bool nextPage;
final Future<void> Function() onLazyLoad; final Future<void> Function() onLazyLoad;
const ServiceRequestsList({Key key, this.requests, this.nextPage, this.onLazyLoad}) : super(key: key); const ServiceRequestsList({
Key? key,
required this.requests,
required this.nextPage,
required this.onLazyLoad,
}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Subtitle? subtitle = AppLocalization.of(context)?.subtitle;
Subtitle _subtitle = AppLocalization.of(context).subtitle; if (requests.isEmpty) {
if(requests.length == 0){ return NoItemFound(message: subtitle?.noServiceRequestFound);
return NoItemFound(message: _subtitle.noServiceRequestFound,);
} }
return LazyLoading( return LazyLoading(
nextPage: nextPage, nextPage: nextPage,
@ -26,20 +32,22 @@ class ServiceRequestsList extends StatelessWidget {
child: ListView.builder( child: ListView.builder(
//physics: BouncingScrollPhysics(), //physics: BouncingScrollPhysics(),
itemCount: requests.length, itemCount: requests.length,
padding: EdgeInsets.symmetric(horizontal: 16,vertical: 8), padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
itemBuilder: (context,itemIndex){ itemBuilder: (context, itemIndex) {
return ServiceRequestItem( return ServiceRequestItem(
index: itemIndex, index: itemIndex,
request: requests[itemIndex], request: requests[itemIndex],
onPressed: (request){ onPressed: (request) {
Navigator.of(context).push( Navigator.of(context).push(
MaterialPageRoute( MaterialPageRoute(
builder: (_)=> RequestDetailsPage(serviceRequest: request,) builder: (_) => RequestDetailsPage(
) serviceRequest: request,
); ),
}, ),
); );
} },
);
},
), ),
); );
} }

@ -1,51 +1,48 @@
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:fluttertoast/fluttertoast.dart'; import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:test_sa/controllers/http_status_manger/http_status_manger.dart';
import 'package:test_sa/controllers/localization/localization.dart';
import 'package:test_sa/controllers/providers/api/service_requests_provider.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart';
import 'package:test_sa/controllers/providers/settings/setting_provider.dart';
import 'package:test_sa/models/service_request/service_request.dart';
import 'package:test_sa/models/service_request/service_request_search.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/models/subtitle.dart';
import 'package:test_sa/views/app_style/sizing.dart';
import 'package:test_sa/views/widgets/buttons/app_button.dart';
import 'package:test_sa/views/widgets/buttons/app_small_button.dart';
import 'package:test_sa/views/widgets/date_and_time/date_picker.dart';
import 'package:test_sa/views/widgets/hospitals/hospital_auto_complete_field.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:test_sa/views/widgets/status/employee/employee_mune.dart';
import '../app_text_form_field.dart'; import '../../../controllers/http_status_manger/http_status_manger.dart';
import '../../../controllers/localization/localization.dart';
import '../../../controllers/providers/api/service_requests_provider.dart';
import '../../../controllers/providers/api/user_provider.dart';
import '../../../controllers/providers/settings/setting_provider.dart';
import '../../../models/lookup.dart';
import '../../../models/service_request/service_request.dart';
import '../../../models/subtitle.dart';
import '../../app_style/sizing.dart';
import '../buttons/app_small_button.dart';
import '../date_and_time/date_picker.dart';
import '../status/employee/employee_mune.dart';
class ServiceRequestsUpdateDialog extends StatefulWidget { class ServiceRequestsUpdateDialog extends StatefulWidget {
final ServiceRequest request; final ServiceRequest request;
const ServiceRequestsUpdateDialog({ const ServiceRequestsUpdateDialog({
Key key, this.request, Key? key,
required this.request,
}) : super(key: key); }) : super(key: key);
@override @override
State<ServiceRequestsUpdateDialog> createState() => _ServiceRequestsUpdateDialogState(); State<ServiceRequestsUpdateDialog> createState() =>
_ServiceRequestsUpdateDialogState();
} }
class _ServiceRequestsUpdateDialogState extends State<ServiceRequestsUpdateDialog> class _ServiceRequestsUpdateDialogState
with TickerProviderStateMixin{ extends State<ServiceRequestsUpdateDialog> with TickerProviderStateMixin {
DateTime? _dateTime;
DateTime _dateTime; Lookup? _employee;
Lookup _employee; Subtitle? _subtitle;
Subtitle _subtitle; UserProvider? _userProvider;
UserProvider _userProvider; SettingProvider? _settingProvider;
SettingProvider _settingProvider; ServiceRequestsProvider? _serviceRequestsProvider;
ServiceRequestsProvider _serviceRequestsProvider;
final GlobalKey<FormState> _formKey = GlobalKey<FormState>(); final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
_update() async { _update() async {
if(_dateTime == null && _employee == null){ if (_dateTime == null && _employee == null) {
Fluttertoast.showToast( Fluttertoast.showToast(msg: _subtitle?.noDateFound ?? '');
msg: _subtitle.noDateFound,
);
return; return;
} }
showDialog<void>( showDialog<void>(
@ -53,22 +50,26 @@ class _ServiceRequestsUpdateDialogState extends State<ServiceRequestsUpdateDialo
barrierDismissible: false, barrierDismissible: false,
builder: (BuildContext context) { builder: (BuildContext context) {
return CupertinoAlertDialog( return CupertinoAlertDialog(
title: Text(_subtitle.updatingDots), title: Text(_subtitle?.updatingDots ?? ''),
content: Center(child: CircularProgressIndicator()), content: const Center(child: CircularProgressIndicator()),
); );
}, },
); );
int status = await _serviceRequestsProvider.updateDate( int? status = await _serviceRequestsProvider?.updateDate(
user: _userProvider.user, user: _userProvider?.user,
host: _settingProvider.host, host: _settingProvider?.host,
request: widget.request, request: widget.request,
newDate: _dateTime?.toString()?.split(" ")?.first, newDate: _dateTime?.toString().split(" ").first,
employee: _employee employee: _employee,
); );
if(status == 200) Navigator.of(context).pop(); if (status == 200) Navigator.of(context).pop();
Navigator.of(context).pop(); Navigator.of(context).pop();
Fluttertoast.showToast( Fluttertoast.showToast(
msg: HttpStatusManger.getStatusMessage(status: status, subtitle: _subtitle), msg: HttpStatusManger.getStatusMessage(
status: status,
subtitle: _subtitle,
) ??
'',
); );
} }
@ -79,15 +80,16 @@ class _ServiceRequestsUpdateDialogState extends State<ServiceRequestsUpdateDialo
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
_subtitle = AppLocalization.of(context).subtitle; _subtitle = AppLocalization.of(context)?.subtitle;
_userProvider = Provider.of<UserProvider>(context,listen: false); _userProvider = Provider.of<UserProvider>(context, listen: false);
_settingProvider = Provider.of<SettingProvider>(context,listen: false); _settingProvider = Provider.of<SettingProvider>(context, listen: false);
_serviceRequestsProvider = Provider.of<ServiceRequestsProvider>(context,listen: false); _serviceRequestsProvider =
return Column( Provider.of<ServiceRequestsProvider>(context, listen: false);
return Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
SizedBox( SizedBox(
// height: MediaQuery.of(context).size.height / 1.2, // height: MediaQuery.of(context).size.height / 1.2,
child: Form( child: Form(
key: _formKey, key: _formKey,
child: Padding( child: Padding(
@ -98,46 +100,49 @@ class _ServiceRequestsUpdateDialogState extends State<ServiceRequestsUpdateDialo
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
ASmallButton( ASmallButton(
text: _subtitle.cancel, text: _subtitle?.cancel,
onPressed: (){ onPressed: () {
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
), ),
ASmallButton( ASmallButton(
text: _subtitle.update, text: _subtitle?.update,
onPressed: _update, onPressed: _update,
) )
], ],
), ),
SizedBox(height: 8.0 * AppStyle.getScaleFactor(context),), SizedBox(height: 8.0 * AppStyle.getScaleFactor(context)),
Row( Row(
children: [ children: [
Expanded( Expanded(
child: Text( child: Text(
_subtitle.date, _subtitle?.date ?? '',
style: Theme.of(context).textTheme.subtitle1, style: Theme.of(context).textTheme.subtitle1,
textScaleFactor: AppStyle.getScaleFactor(context), textScaleFactor: AppStyle.getScaleFactor(context),
), ),
), ),
ADatePicker( ADatePicker(
date: _dateTime, date: _dateTime!,
from: DateTime.now(), from: DateTime.now(),
onDatePicker: (date){ onDatePicker: (date) {
_dateTime = date; _dateTime = date;
setState(() {}); setState(() {});
}, },
), ),
], ],
), ),
SizedBox(height: 8.0 * AppStyle.getScaleFactor(context),), SizedBox(
height: 8.0 * AppStyle.getScaleFactor(context),
),
EmployeeMenu( EmployeeMenu(
initialValue: _employee, initialValue: _employee,
onSelect: (employee){ onSelect: (employee) {
_employee = employee; _employee = employee;
}, },
), ),
SizedBox(height: 8.0 * AppStyle.getScaleFactor(context),), SizedBox(
height: 8.0 * AppStyle.getScaleFactor(context),
),
], ],
), ),
), ),

@ -1,29 +1,36 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:test_sa/models/lookup.dart'; import '../../../models/lookup.dart';
import 'package:test_sa/views/app_style/colors.dart'; import '../../app_style/colors.dart';
import 'package:test_sa/views/app_style/sizing.dart'; import '../../app_style/sizing.dart';
class FilterItem extends StatelessWidget { class FilterItem extends StatelessWidget {
final bool isSelected; final bool isSelected;
final Lookup status; final Lookup? status;
final VoidCallback onSelected; final VoidCallback onSelected;
const FilterItem({ const FilterItem({
Key key, Key? key,
this.status, this.status,
this.isSelected, required this.isSelected,
this.onSelected required this.onSelected,
}) : super(key: key); }) : super(key: key);
Color getStatusColor(){ Color getStatusColor() {
switch(status.id){ switch (status?.id) {
case 0: return AColors.green; case 0:
case 4: return AColors.deepRed; return AColors.green;
case 6: return AColors.green; case 4:
case 5: return AColors.orange; return AColors.deepRed;
case 8: return AColors.green; case 6:
case 9: return AColors.orange; return AColors.green;
default : return AColors.grey; case 5:
return AColors.orange;
case 8:
return AColors.green;
case 9:
return AColors.orange;
default:
return AColors.grey;
} }
} }
@ -35,23 +42,24 @@ class FilterItem extends StatelessWidget {
height: 30, height: 30,
child: ElevatedButton( child: ElevatedButton(
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
padding: EdgeInsets.symmetric(horizontal: 8), padding: const EdgeInsets.symmetric(horizontal: 8),
backgroundColor: getStatusColor(),
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular( borderRadius: BorderRadius.circular(
AppStyle.getBorderRadius(context) AppStyle.getBorderRadius(context),
) ),
), ),
primary: getStatusColor(),
), ),
onPressed: onSelected,
child: Text( child: Text(
status.label??"", status?.label ?? "",
style: Theme.of(context).textTheme.bodyText1.copyWith( style: Theme.of(context).textTheme.bodyLarge?.copyWith(
color:getStatusColor().computeLuminance() > 0.5 color: getStatusColor().computeLuminance() > 0.5
? AColors.black : Colors.white, ? AColors.black
), : Colors.white,
),
textScaleFactor: AppStyle.getScaleFactor(context), textScaleFactor: AppStyle.getScaleFactor(context),
), ),
onPressed:onSelected,
), ),
), ),
); );

@ -1,54 +1,56 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:test_sa/controllers/localization/localization.dart'; import '../../../controllers/localization/localization.dart';
import 'package:test_sa/models/lookup.dart'; import '../../../models/lookup.dart';
import 'package:test_sa/models/service_request/service_request_search.dart'; import '../../../models/service_request/service_request_search.dart';
import 'package:test_sa/models/subtitle.dart'; import '../../../models/subtitle.dart';
import 'package:test_sa/views/app_style/sizing.dart'; import '../../app_style/sizing.dart';
import 'package:test_sa/views/widgets/buttons/app_button.dart';
import 'package:test_sa/views/widgets/buttons/app_small_button.dart';
import 'package:test_sa/views/widgets/hospitals/hospital_auto_complete_field.dart';
import '../app_text_form_field.dart'; import '../app_text_form_field.dart';
import '../buttons/app_button.dart';
import '../buttons/app_small_button.dart';
import '../hospitals/hospital_auto_complete_field.dart';
import 'filter_item.dart'; import 'filter_item.dart';
class ServiceRequestsSearchDialog extends StatefulWidget { class ServiceRequestsSearchDialog extends StatefulWidget {
final ServiceRequestSearch initialSearchValue; final ServiceRequestSearch initialSearchValue;
final bool expandedSearch; final bool? expandedSearch;
final Function(ServiceRequestSearch) onSearch; final Function(ServiceRequestSearch)? onSearch;
const ServiceRequestsSearchDialog({ const ServiceRequestsSearchDialog({
Key key, Key? key,
this.initialSearchValue, required this.initialSearchValue,
this.expandedSearch, this.expandedSearch,
this.onSearch this.onSearch,
}) : super(key: key); }) : super(key: key);
@override @override
_ServiceRequestsSearchDialogState createState() => _ServiceRequestsSearchDialogState(); ServiceRequestsSearchDialogState createState() =>
ServiceRequestsSearchDialogState();
} }
class _ServiceRequestsSearchDialogState extends State<ServiceRequestsSearchDialog> class ServiceRequestsSearchDialogState
with TickerProviderStateMixin{ extends State<ServiceRequestsSearchDialog> with TickerProviderStateMixin {
ServiceRequestSearch _search; final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
List<Lookup> status = [
Lookup(label: "New", id: 4,),
Lookup(label: "Repaired", id: 6,), late ServiceRequestSearch _search;
late List<Lookup> status = const [
Lookup(label: "New", id: 4),
Lookup(label: "Repaired", id: 6),
Lookup(label: "Repeated", id: 8), Lookup(label: "Repeated", id: 8),
Lookup(label: "Closed", id: 9,), Lookup(label: "Closed", id: 9),
Lookup(label: "Under Repair", id: 5,), Lookup(label: "Under Repair", id: 5),
]; ];
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_search = ServiceRequestSearch(); _search = ServiceRequestSearch();
_search.fromSearch(widget.initialSearchValue); _search.fromSearch(widget.initialSearchValue);
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Subtitle _subtitle = AppLocalization.of(context).subtitle; Subtitle? subtitle = AppLocalization.of(context)?.subtitle;
return SizedBox( return SizedBox(
height: MediaQuery.of(context).size.height / 1.2, height: MediaQuery.of(context).size.height / 1.2,
child: Form( child: Form(
key: _formKey, key: _formKey,
@ -60,121 +62,120 @@ class _ServiceRequestsSearchDialogState extends State<ServiceRequestsSearchDialo
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
ASmallButton( ASmallButton(
text: _subtitle.cancel, text: subtitle?.cancel,
onPressed: (){ onPressed: () {
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
), ),
ASmallButton( ASmallButton(
text: _subtitle.search, text: subtitle?.search,
onPressed: (){ onPressed: () {
if(!_formKey.currentState.validate()) if (!(_formKey.currentState?.validate() ?? true)) return;
return; _formKey.currentState?.save();
_formKey.currentState.save();
Navigator.of(context).pop(_search); Navigator.of(context).pop(_search);
}, },
) )
], ],
), ),
SizedBox(height: 8.0 * AppStyle.getScaleFactor(context),), SizedBox(height: 8.0 * AppStyle.getScaleFactor(context)),
ATextFormField( ATextFormField(
initialValue: _search.deviceSerialNumber, initialValue: _search.deviceSerialNumber,
hintText: _subtitle.serialNumber, hintText: subtitle?.serialNumber,
style: Theme.of(context).textTheme.headline6, style: Theme.of(context).textTheme.titleLarge,
textInputAction: TextInputAction.search, textInputAction: TextInputAction.search,
onAction: (){ onAction: () {
if(!_formKey.currentState.validate()) if (!(_formKey.currentState?.validate() ?? true)) return;
return; _formKey.currentState?.save();
_formKey.currentState.save();
Navigator.of(context).pop(_search); Navigator.of(context).pop(_search);
}, },
onSaved: (value){ onSaved: (value) {
_search.deviceSerialNumber = value; _search.deviceSerialNumber = value;
}, },
), ),
SizedBox(height: 8.0 * AppStyle.getScaleFactor(context),), SizedBox(
height: 8.0 * AppStyle.getScaleFactor(context),
),
HospitalAutoCompleteField( HospitalAutoCompleteField(
initialValue: _search.hospital, initialValue: _search.hospital ?? '',
onSave: (value){ onSave: (value) {
_search.hospital = value; _search.hospital = value;
}, },
onSearch: (value){ onSearch: (value) {
_search.hospital = value; _search.hospital = value;
Navigator.of(context).pop(_search); Navigator.of(context).pop(_search);
}, },
), ),
SizedBox(height: 8.0 * AppStyle.getScaleFactor(context),), SizedBox(
height: 8.0 * AppStyle.getScaleFactor(context),
),
ATextFormField( ATextFormField(
initialValue: _search.deviceName, initialValue: _search.deviceName,
hintText: _subtitle.deviceName, hintText: subtitle?.deviceName,
style: Theme.of(context).textTheme.headline6, style: Theme.of(context).textTheme.titleLarge,
textInputAction: TextInputAction.search, textInputAction: TextInputAction.search,
onAction: (){ onAction: () {
if(!_formKey.currentState.validate()) if (!(_formKey.currentState?.validate() ?? true)) return;
return; _formKey.currentState?.save();
_formKey.currentState.save();
Navigator.of(context).pop(_search); Navigator.of(context).pop(_search);
}, },
onSaved: (value){ onSaved: (value) {
_search.deviceName = value; _search.deviceName = value;
}, },
), ),
SizedBox(height: 8.0 * AppStyle.getScaleFactor(context),), SizedBox(height: 8.0 * AppStyle.getScaleFactor(context)),
ATextFormField( ATextFormField(
initialValue: _search.model, initialValue: _search.model,
hintText: _subtitle.model, hintText: subtitle?.model,
style: Theme.of(context).textTheme.headline6, style: Theme.of(context).textTheme.titleLarge,
textInputAction: TextInputAction.search, textInputAction: TextInputAction.search,
onAction: (){ onAction: () {
if(!_formKey.currentState.validate()) if (!(_formKey.currentState?.validate() ?? true)) return;
return; _formKey.currentState?.save();
_formKey.currentState.save();
Navigator.of(context).pop(_search); Navigator.of(context).pop(_search);
}, },
onSaved: (value){ onSaved: (value) {
_search.model = value; _search.model = value;
}, },
), ),
SizedBox(height: 16 * AppStyle.getScaleFactor(context),), SizedBox(
height: 16 * AppStyle.getScaleFactor(context),
),
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 12), padding: const EdgeInsets.symmetric(horizontal: 12),
child: Wrap( child: Wrap(
spacing: 10, spacing: 10,
runSpacing: 10, runSpacing: 10,
alignment: WrapAlignment.spaceEvenly, alignment: WrapAlignment.spaceEvenly,
children: List.generate( children: List.generate(status.length, (index) {
status.length, bool isSelected = _search.statusValue == status[index].id;
(index) { return FilterItem(
bool isSelected = _search.statusValue == status[index].id; isSelected: isSelected,
return FilterItem( onSelected: () {
isSelected: isSelected, if (isSelected) {
onSelected: (){ _search.statusValue = null;
if(isSelected) } else {
_search.statusValue = null; _search.statusValue = status[index].id;
else }
_search.statusValue = status[index].id; setState(() {});
},
setState(() {}); status: status[index],
}, );
status: status[index], }),
);
}
),
), ),
), ),
Visibility( Visibility(
visible: widget.initialSearchValue.toSearchString().isNotEmpty, visible: widget.initialSearchValue.toSearchString().isNotEmpty,
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8,horizontal: 16), padding: const EdgeInsets.symmetric(
vertical: 8,
horizontal: 16,
),
child: AButton( child: AButton(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
text: _subtitle.clearSearch, text: subtitle?.clearSearch ?? '',
onPressed: (){ onPressed: () {
_search = ServiceRequestSearch(); _search = ServiceRequestSearch();
Navigator.of(context).pop(_search); Navigator.of(context).pop(_search);
}, },
), ),
), ),

@ -1,233 +1,263 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:test_sa/controllers/localization/localization.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/models/subtitle.dart';
import 'package:test_sa/models/visits/visits_search.dart';
import 'package:test_sa/views/app_style/sizing.dart';
import 'package:test_sa/views/widgets/buttons/app_button.dart';
import 'package:test_sa/views/widgets/buttons/app_small_button.dart';
import 'package:test_sa/views/widgets/date_and_time/from_to_date_bar.dart';
import 'package:test_sa/views/widgets/hospitals/hospital_auto_complete_field.dart';
import 'package:test_sa/views/widgets/titles/app_sub_title.dart';
import '../../../controllers/localization/localization.dart';
import '../../../models/lookup.dart';
import '../../../models/subtitle.dart';
import '../../../models/visits/visits_search.dart';
import '../../app_style/sizing.dart';
import '../app_text_form_field.dart'; import '../app_text_form_field.dart';
import '../buttons/app_button.dart';
import '../buttons/app_small_button.dart';
import '../date_and_time/from_to_date_bar.dart';
import '../hospitals/hospital_auto_complete_field.dart';
import '../titles/app_sub_title.dart';
import 'filter_item.dart'; import 'filter_item.dart';
class VisitsSearchDialog extends StatefulWidget { class VisitsSearchDialog extends StatefulWidget {
final VisitsSearch initialSearchValue; final VisitsSearch initialSearchValue;
final bool expandedSearch; final bool expandedSearch;
final Function(VisitsSearch) onSearch; final Function(VisitsSearch) onSearch;
const VisitsSearchDialog({ const VisitsSearchDialog({
Key key, Key? key,
this.initialSearchValue, required this.initialSearchValue,
this.expandedSearch, required this.expandedSearch,
this.onSearch required this.onSearch,
}) : super(key: key); }) : super(key: key);
@override @override
_VisitsSearchDialogState createState() => _VisitsSearchDialogState(); VisitsSearchDialogState createState() => VisitsSearchDialogState();
} }
class _VisitsSearchDialogState extends State<VisitsSearchDialog> class VisitsSearchDialogState extends State<VisitsSearchDialog>
with TickerProviderStateMixin{ with TickerProviderStateMixin {
VisitsSearch _search; VisitsSearch? _search;
List<Lookup> status = [ List<Lookup> status = const [
Lookup(label: "Done", id: 0,), Lookup(
label: "Done",
id: 0,
),
Lookup(label: "Not Yet", id: 1), Lookup(label: "Not Yet", id: 1),
Lookup(label: "On Hold", id: 2,), Lookup(
label: "On Hold",
id: 2,
),
]; ];
List<Lookup> contactStatus = [ List<Lookup> contactStatus = const [
Lookup(label: "Hospital Employee", key: "H",), Lookup(
label: "Hospital Employee",
key: "H",
),
Lookup(label: "Under Warranty", key: "CW"), Lookup(label: "Under Warranty", key: "CW"),
Lookup(label: "Under Maintenance Contract", key: "CC",), Lookup(
label: "Under Maintenance Contract",
key: "CC",
),
]; ];
final GlobalKey<FormState> _formKey = GlobalKey<FormState>(); final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_search = VisitsSearch(); _search = VisitsSearch();
_search.fromSearch(widget.initialSearchValue); _search?.fromSearch(widget.initialSearchValue);
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Subtitle _subtitle = AppLocalization.of(context).subtitle; Subtitle? subtitle = AppLocalization.of(context)?.subtitle;
DateTime today = DateTime.now(); DateTime today = DateTime.now();
return SizedBox( return SizedBox(
height: MediaQuery.of(context).size.height / 1.3, height: MediaQuery.of(context).size.height / 1.3,
child: Form( child: Form(
key: _formKey, key: _formKey,
child: ListView( child: ListView(
padding: const EdgeInsets.symmetric(vertical: 8,horizontal: 16), padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16),
children: [ children: [
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
ASmallButton( ASmallButton(
text: _subtitle.cancel, text: subtitle?.cancel,
onPressed: (){ onPressed: () {
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
), ),
ASmallButton( ASmallButton(
text: _subtitle.search, text: subtitle?.search,
onPressed: (){ onPressed: () {
if(!_formKey.currentState.validate()) if (!(_formKey.currentState?.validate() ?? true)) {
return; return;
_formKey.currentState.save(); }
_formKey.currentState?.save();
Navigator.of(context).pop(_search); Navigator.of(context).pop(_search);
}, },
) )
], ],
), ),
ATextFormField( ATextFormField(
initialValue: _search.deviceSerialNumber, initialValue: _search?.deviceSerialNumber,
hintText: _subtitle.serialNumber, hintText: subtitle?.serialNumber,
style: Theme.of(context).textTheme.headline6, style: Theme.of(context).textTheme.titleLarge,
textInputAction: TextInputAction.search, textInputAction: TextInputAction.search,
onAction: (){ onAction: () {
if(!_formKey.currentState.validate()) if (!(_formKey.currentState?.validate() ?? true)) return;
return; _formKey.currentState?.save();
_formKey.currentState.save();
Navigator.of(context).pop(_search); Navigator.of(context).pop(_search);
}, },
onSaved: (value){ onSaved: (value) {
_search.deviceSerialNumber = value; _search?.deviceSerialNumber = value ?? '';
}, },
), ),
SizedBox(height: 8.0 * AppStyle.getScaleFactor(context),), SizedBox(height: 8.0 * AppStyle.getScaleFactor(context)),
HospitalAutoCompleteField( HospitalAutoCompleteField(
initialValue: _search.hospitalName, initialValue: _search?.hospitalName ?? '',
onSave: (value){ onSave: (value) {
_search.hospitalName = value; _search?.hospitalName = value;
}, },
onSearch: (value){ onSearch: (value) {
_search.hospitalName = value; _search?.hospitalName = value;
Navigator.of(context).pop(_search); Navigator.of(context).pop(_search);
}, },
), ),
SizedBox(height: 8.0 * AppStyle.getScaleFactor(context),), SizedBox(
height: 8.0 * AppStyle.getScaleFactor(context),
),
ATextFormField( ATextFormField(
initialValue: _search.brand, initialValue: _search?.brand,
hintText: _subtitle.brand, hintText: subtitle?.brand,
style: Theme.of(context).textTheme.headline6, style: Theme.of(context).textTheme.titleLarge,
textInputAction: TextInputAction.search, textInputAction: TextInputAction.search,
onAction: (){ onAction: () {
if(!_formKey.currentState.validate()) if (!(_formKey.currentState?.validate() ?? false)) return;
return; _formKey.currentState?.save();
_formKey.currentState.save();
Navigator.of(context).pop(_search); Navigator.of(context).pop(_search);
}, },
onSaved: (value){ onSaved: (value) {
_search.brand = value; _search?.brand = value ?? '';
}, },
), ),
SizedBox(height: 8.0 * AppStyle.getScaleFactor(context),), SizedBox(
height: 8.0 * AppStyle.getScaleFactor(context),
),
ATextFormField( ATextFormField(
initialValue: _search.model, initialValue: _search?.model,
hintText: _subtitle.model, hintText: subtitle?.model,
style: Theme.of(context).textTheme.headline6, style: Theme.of(context).textTheme.titleLarge,
textInputAction: TextInputAction.search, textInputAction: TextInputAction.search,
onAction: (){ onAction: () {
if(!_formKey.currentState.validate()) if (!(_formKey.currentState?.validate() ?? true)) return;
return; _formKey.currentState?.save();
_formKey.currentState.save();
Navigator.of(context).pop(_search); Navigator.of(context).pop(_search);
}, },
onSaved: (value){ onSaved: (value) {
_search.model = value; _search?.model = value ?? '';
}, },
), ),
SizedBox(height: 8.0 * AppStyle.getScaleFactor(context),), SizedBox(
ASubTitle(_subtitle.status), height: 8.0 * AppStyle.getScaleFactor(context),
SizedBox(height: 4.0 * AppStyle.getScaleFactor(context),), ),
ASubTitle(subtitle?.status ?? ''),
SizedBox(
height: 4.0 * AppStyle.getScaleFactor(context),
),
Wrap( Wrap(
spacing: 10, spacing: 10,
runSpacing: 10, runSpacing: 10,
children: List.generate( children: List.generate(status.length, (index) {
status.length, bool isSelected = _search?.statusValue == status[index].id;
(index) { return FilterItem(
bool isSelected = _search.statusValue == status[index].id; isSelected: isSelected,
return FilterItem( onSelected: () {
isSelected: isSelected, if (isSelected) {
onSelected: (){ _search?.statusValue = null;
if(isSelected) } else {
_search.statusValue = null; _search?.statusValue = status[index].id;
else }
_search.statusValue = status[index].id; setState(() {});
},
setState(() {}); status: status[index],
}, );
status: status[index], }),
); ),
} SizedBox(
height: 8.0 * AppStyle.getScaleFactor(context),
), ),
ASubTitle(subtitle?.contactStatus ?? ''),
SizedBox(
height: 4.0 * AppStyle.getScaleFactor(context),
), ),
SizedBox(height: 8.0 * AppStyle.getScaleFactor(context),),
ASubTitle(_subtitle.contactStatus),
SizedBox(height: 4.0 * AppStyle.getScaleFactor(context),),
Wrap( Wrap(
spacing: 10, spacing: 10,
runSpacing: 10, runSpacing: 10,
children: List.generate( children: List.generate(
contactStatus.length, contactStatus.length,
(index) { (index) {
bool isSelected = _search.contactStatus == contactStatus[index].key; bool isSelected =
return FilterItem( _search?.contactStatus == contactStatus[index].key;
isSelected: isSelected, return FilterItem(
onSelected: (){ isSelected: isSelected,
if(isSelected) onSelected: () {
_search.contactStatus = null; if (isSelected) {
else _search?.contactStatus = null;
_search.contactStatus = contactStatus[index].key; } else {
_search?.contactStatus = contactStatus[index].key;
setState(() {}); }
}, setState(() {});
status: contactStatus[index], },
); status: contactStatus[index],
} );
},
), ),
), ),
SizedBox(height: 8.0 * AppStyle.getScaleFactor(context),), SizedBox(
ASubTitle(_subtitle.actualDate), height: 8.0 * AppStyle.getScaleFactor(context),
SizedBox(height: 4.0 * AppStyle.getScaleFactor(context),), ),
ASubTitle(subtitle?.actualDate ?? ''),
SizedBox(
height: 4.0 * AppStyle.getScaleFactor(context),
),
FromToDateBar( FromToDateBar(
from: _search.actualDateFrom , from: _search?.actualDateFrom,
to: _search.actualDateTo, to: _search?.actualDateTo,
onPickFrom: (date){ onPickFrom: (date) {
_search.actualDateFrom = date; _search?.actualDateFrom = date;
}, },
onPickTo: (date){ onPickTo: (date) {
_search.actualDateTo = date; _search?.actualDateTo = date;
}, },
), ),
SizedBox(height: 8.0 * AppStyle.getScaleFactor(context),), SizedBox(
ASubTitle(_subtitle.expectDate), height: 8.0 * AppStyle.getScaleFactor(context),
SizedBox(height: 4.0 * AppStyle.getScaleFactor(context),), ),
ASubTitle(subtitle?.expectDate ?? ''),
SizedBox(
height: 4.0 * AppStyle.getScaleFactor(context),
),
FromToDateBar( FromToDateBar(
from: _search.expectedDateFrom ?? DateTime(today.year, today.month, 1), from: _search?.expectedDateFrom ??
to: _search.expectedDateTo ?? DateTime(today.year, (today.month +1).clamp(1, 12) , today.month == 12 ? 31 : 0), DateTime(today.year, today.month, 1),
onPickFrom: (date){ to: _search?.expectedDateTo ??
_search.expectedDateFrom = date; DateTime(today.year, (today.month + 1).clamp(1, 12),
today.month == 12 ? 31 : 0),
onPickFrom: (date) {
_search?.expectedDateFrom = date;
}, },
onPickTo: (date){ onPickTo: (date) {
_search.expectedDateTo = date; _search?.expectedDateTo = date;
}, },
), ),
Visibility( Visibility(
visible: _search.toSearchString().isNotEmpty, visible: _search?.toSearchString().isNotEmpty ?? false,
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8,horizontal: 16), padding:
const EdgeInsets.symmetric(vertical: 8, horizontal: 16),
child: AButton( child: AButton(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
text: _subtitle.clearSearch, text: subtitle?.clearSearch ?? '',
onPressed: (){ onPressed: () {
_search = VisitsSearch(); _search = VisitsSearch();
Navigator.of(context).pop(_search); Navigator.of(context).pop(_search);
}, },

@ -3,28 +3,30 @@ import 'package:flutter/services.dart';
import 'package:flutter_sound/flutter_sound.dart'; import 'package:flutter_sound/flutter_sound.dart';
import 'package:permission_handler/permission_handler.dart'; import 'package:permission_handler/permission_handler.dart';
import 'package:rive/rive.dart'; import 'package:rive/rive.dart';
import 'package:test_sa/views/widgets/buttons/app_icon_button2.dart';
import 'package:test_sa/views/widgets/buttons/app_small_button.dart';
import 'package:test_sa/views/widgets/sound/sound_player.dart';
import '../../app_style/sizing.dart'; import '../../app_style/sizing.dart';
import '../buttons/app_icon_button2.dart';
import '../buttons/app_small_button.dart';
import 'sound_player.dart';
class RecordSound extends StatefulWidget { class RecordSound extends StatefulWidget {
final Function(String) onRecord; final Function(String?) onRecord;
const RecordSound({Key key, @required this.onRecord}) : super(key: key); const RecordSound({
Key? key,
required this.onRecord,
}) : super(key: key);
@override @override
State<RecordSound> createState() => _RecordSoundState(); State<RecordSound> createState() => _RecordSoundState();
} }
class _RecordSoundState extends State<RecordSound> { class _RecordSoundState extends State<RecordSound> {
FlutterSoundRecorder _myRecorder = FlutterSoundRecorder(); FlutterSoundRecorder? _myRecorder = FlutterSoundRecorder();
bool _recorderIsOpened = false; bool _recorderIsOpened = false;
bool _recording = false; bool _recording = false;
bool _fastTab = false; bool _fastTab = false;
String _record; String? _record;
Artboard _rive; late Artboard _rive;
@override @override
void setState(VoidCallback fn) { void setState(VoidCallback fn) {
@ -34,7 +36,7 @@ class _RecordSoundState extends State<RecordSound> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_myRecorder.openRecorder().then((value) { _myRecorder?.openRecorder().then((value) {
_recorderIsOpened = true; _recorderIsOpened = true;
setState(() {}); setState(() {});
}); });
@ -61,7 +63,7 @@ class _RecordSoundState extends State<RecordSound> {
@override @override
void dispose() { void dispose() {
// Be careful : you must `close` the audio session when you have finished with it. // Be careful : you must `close` the audio session when you have finished with it.
_myRecorder.closeRecorder(); _myRecorder?.closeRecorder();
_myRecorder = null; _myRecorder = null;
super.dispose(); super.dispose();
} }
@ -75,11 +77,15 @@ class _RecordSoundState extends State<RecordSound> {
} }
_rive.addController(SimpleAnimation('recording')); _rive.addController(SimpleAnimation('recording'));
if (!_recorderIsOpened) { if (!_recorderIsOpened) {
await _myRecorder.openRecorder(); await _myRecorder?.openRecorder();
_recorderIsOpened = true; _recorderIsOpened = true;
} }
await _myRecorder.startRecorder(toFile: "record_${DateTime.now().millisecondsSinceEpoch}.mp4", codec: Codec.aacMP4, sampleRate: 360000, bitRate: 360000); await _myRecorder?.startRecorder(
toFile: "record_${DateTime.now().millisecondsSinceEpoch}.mp4",
codec: Codec.aacMP4,
sampleRate: 360000,
bitRate: 360000);
_recording = true; _recording = true;
setState(() {}); setState(() {});
@ -91,7 +97,7 @@ class _RecordSoundState extends State<RecordSound> {
setState(() {}); setState(() {});
return; return;
} }
String path = (await _myRecorder.stopRecorder()).toString(); String path = (await _myRecorder?.stopRecorder()).toString();
_record = path; _record = path;
widget.onRecord(path); widget.onRecord(path);
_recording = false; _recording = false;
@ -100,8 +106,8 @@ class _RecordSoundState extends State<RecordSound> {
_cancelRecording() async { _cancelRecording() async {
if (!_recording) return; if (!_recording) return;
String path = await _myRecorder.stopRecorder(); final path = await _myRecorder?.stopRecorder();
_myRecorder.deleteRecord(fileName: path); _myRecorder?.deleteRecord(fileName: path ?? '');
_rive.addController(SimpleAnimation('delete')); _rive.addController(SimpleAnimation('delete'));
// rebuild(); // rebuild();
@ -114,13 +120,14 @@ class _RecordSoundState extends State<RecordSound> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
padding: EdgeInsets.only(left: 12, right: 0), padding: const EdgeInsets.only(left: 12, right: 0),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Color(0xfff5f5f5), color: const Color(0xfff5f5f5),
border: Border.all( border: Border.all(
color: Color(0xffefefef), color: const Color(0xffefefef),
), ),
borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)), borderRadius: BorderRadius.circular(
AppStyle.borderRadius * AppStyle.getScaleFactor(context)),
), ),
child: Column( child: Column(
children: [ children: [
@ -140,13 +147,15 @@ class _RecordSoundState extends State<RecordSound> {
child: Stack( child: Stack(
children: [ children: [
SizedBox( SizedBox(
height: 24 * AppStyle.getScaleFactor(context), height:
24 * AppStyle.getScaleFactor(context),
child: Rive( child: Rive(
artboard: _rive, artboard: _rive,
)), )),
InkWell( InkWell(
child: SizedBox( child: SizedBox(
height: 32 * AppStyle.getScaleFactor(context), height:
32 * AppStyle.getScaleFactor(context),
width: MediaQuery.of(context).size.width, width: MediaQuery.of(context).size.width,
), ),
onTap: () { onTap: () {

@ -1,115 +1,106 @@
import 'dart:typed_data';
import 'package:audioplayers/audioplayers.dart'; import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:test_sa/views/app_style/sizing.dart';
import '../../app_style/colors.dart'; import '../../app_style/colors.dart';
import '../../app_style/sizing.dart';
class ASoundPlayer extends StatefulWidget { class ASoundPlayer extends StatefulWidget {
final String? audio;
final String audio; const ASoundPlayer({Key? key, this.audio}) : super(key: key);
const ASoundPlayer({Key key, this.audio}) : super(key: key);
@override @override
_ASoundPlayerState createState() => _ASoundPlayerState(); ASoundPlayerState createState() => ASoundPlayerState();
} }
class _ASoundPlayerState extends State<ASoundPlayer> { class ASoundPlayerState extends State<ASoundPlayer> {
//FlutterSoundPlayer _myPlayer = FlutterSoundPlayer(); //FlutterSoundPlayer _myPlayer = FlutterSoundPlayer();
bool _sliderMoving = false; bool _sliderMoving = false;
Duration _audioTime; Duration? _audioTime;
Duration _audioPosition; Duration? _audioPosition;
String _audio; String? _audio;
bool _isLocalFile = false; bool _isLocalFile = false;
bool _failedToLoad = false; bool _failedToLoad = false;
AudioPlayer _audioPlayer; AudioPlayer? _audioPlayer;
Widget _getAudioButton(){ Widget _getAudioButton() {
switch(_audioPlayer.state){ switch (_audioPlayer?.state) {
case PlayerState.playing: case PlayerState.playing:
return IconButton( return IconButton(
icon: const Icon(Icons.pause_rounded), icon: const Icon(Icons.pause_rounded),
onPressed: () async { onPressed: () async {
_failedToLoad = false; _failedToLoad = false;
await _audioPlayer.pause(); await _audioPlayer?.pause();
rebuild(); rebuild();
} });
);
case PlayerState.paused: case PlayerState.paused:
return IconButton( return IconButton(
icon: const Icon(Icons.play_arrow_rounded), icon: const Icon(Icons.play_arrow_rounded),
onPressed: () async { onPressed: () async {
_failedToLoad = false; _failedToLoad = false;
await _audioPlayer.resume(); await _audioPlayer?.resume();
rebuild(); rebuild();
} });
);
case PlayerState.completed: case PlayerState.completed:
return IconButton( return IconButton(
icon: const Icon(Icons.replay_rounded), icon: const Icon(Icons.replay_rounded),
onPressed: () async { onPressed: () async {
_failedToLoad = false; _failedToLoad = false;
await _audioPlayer.stop(); await _audioPlayer?.stop();
await _audioPlayer.resume(); await _audioPlayer?.resume();
rebuild(); rebuild();
} });
);
case PlayerState.stopped: case PlayerState.stopped:
return IconButton( return IconButton(
icon: Icon( _isLocalFile icon: Icon(_isLocalFile
? Icons.play_circle_fill_outlined ? Icons.play_circle_fill_outlined
: Icons.download_rounded : Icons.download_rounded),
),
onPressed: () async { onPressed: () async {
_failedToLoad = false; _failedToLoad = false;
try { try {
await _audioPlayer.play( await _audioPlayer?.play(
_isLocalFile? _isLocalFile
DeviceFileSource(_audio):UrlSource(_audio), ? DeviceFileSource(_audio ?? '')
: UrlSource(_audio ?? ''),
); );
rebuild(); rebuild();
} on Exception catch (e) { } on Exception catch (e) {
_failedToLoad = true; _failedToLoad = true;
} }
} });
); default:
default: return IconButton( return IconButton(
icon: const Icon( Icons.replay_rounded), icon: const Icon(Icons.replay_rounded),
onPressed: () async { onPressed: () async {
_failedToLoad = false; _failedToLoad = false;
try { try {
_audioPlayer.seek(const Duration(milliseconds: 0)); _audioPlayer?.seek(const Duration(milliseconds: 0));
_audioPlayer.stop(); _audioPlayer?.stop();
await _audioPlayer.play( await _audioPlayer?.play(
_isLocalFile? _isLocalFile
DeviceFileSource(_audio):UrlSource(_audio), ? DeviceFileSource(_audio ?? '')
); : UrlSource(_audio ?? ''),
rebuild(); );
} on Exception catch (e) { rebuild();
_failedToLoad = true; } on Exception catch (e) {
} _failedToLoad = true;
} }
); });
} }
} }
String format(Duration d) { String format(Duration? d) {
if(d == null) if (d == null) return "00:00";
return "00:00";
return d.toString().substring(2, 7); return d.toString().substring(2, 7);
} }
rebuild(){ rebuild() {
if (!mounted) return; if (!mounted) return;
setState(() {}); setState(() {});
} }
bool _isLocalUrl(String url) { bool _isLocalUrl(String url) {
if(url?.isEmpty != false) return false; if (url.isEmpty != false) return false;
return url.startsWith("/") || return url.startsWith("/") ||
url.startsWith("file://") || url.startsWith("file://") ||
url.substring(1).startsWith(':\\'); url.substring(1).startsWith(':\\');
@ -119,32 +110,34 @@ class _ASoundPlayerState extends State<ASoundPlayer> {
void initState() { void initState() {
super.initState(); super.initState();
_audioPlayer = AudioPlayer(); _audioPlayer = AudioPlayer();
_audioPlayer.release(); _audioPlayer?.release();
_audio = widget.audio; _audio = widget.audio;
_isLocalFile = _isLocalUrl(_audio); _isLocalFile = _isLocalUrl(_audio ?? '');
_audioPlayer.setReleaseMode(ReleaseMode.stop); _audioPlayer?.setReleaseMode(ReleaseMode.stop);
if(_isLocalFile){ if (_isLocalFile) {
_audioPlayer.setSourceDeviceFile(_audio).then((value) {rebuild();}); _audioPlayer?.setSourceDeviceFile(_audio ?? '').then((value) {
} else{ rebuild();
_audioPlayer.setReleaseMode(ReleaseMode.stop); });
} else {
_audioPlayer?.setReleaseMode(ReleaseMode.stop);
} }
// set up listeners // set up listeners
_audioPlayer.onPositionChanged.listen((Duration duration) { _audioPlayer?.onPositionChanged.listen((Duration duration) {
if(!_sliderMoving){ if (!_sliderMoving) {
_audioPosition = duration; _audioPosition = duration;
rebuild(); rebuild();
} }
//setState(() => position = p); //setState(() => position = p);
}); });
_audioPlayer.onPlayerStateChanged.listen((event) { _audioPlayer?.onPlayerStateChanged.listen((event) {
//_audioPosition = _audioTime; //_audioPosition = _audioTime;
rebuild(); rebuild();
}); });
_audioPlayer.onDurationChanged.listen((Duration duration) { _audioPlayer?.onDurationChanged.listen((Duration duration) {
_audioTime = duration; _audioTime = duration;
rebuild(); rebuild();
}); });
_audioPlayer.onSeekComplete.listen((event) { _audioPlayer?.onSeekComplete.listen((event) {
rebuild(); rebuild();
}); });
} }
@ -152,55 +145,49 @@ class _ASoundPlayerState extends State<ASoundPlayer> {
@override @override
void dispose() { void dispose() {
super.dispose(); super.dispose();
// _myPlayer.closeAudioSession(); // _myPlayer.closeAudioSession();
_audioPlayer.release(); _audioPlayer?.release();
_audioPlayer.dispose(); _audioPlayer?.dispose();
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if(_audio != widget.audio){ if (_audio != widget.audio) {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
_audio = widget.audio; _audio = widget.audio;
if(_isLocalFile){ if (_isLocalFile) {
await _audioPlayer.setSourceDeviceFile(_audio); await _audioPlayer?.setSourceDeviceFile(_audio ?? '');
}else{ } else {
await _audioPlayer.setSourceUrl(_audio); await _audioPlayer?.setSourceUrl(_audio ?? '');
} }
_audioPlayer.seek(const Duration(milliseconds: 0)); _audioPlayer?.seek(const Duration(milliseconds: 0));
_audioPlayer.stop(); _audioPlayer?.stop();
rebuild(); rebuild();
}); });
} }
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
Row( Row(
children: [ children: [
Material( Material(color: Colors.transparent, child: _getAudioButton()),
color: Colors.transparent,
child: _getAudioButton()
),
Expanded( Expanded(
child: Slider( child: Slider(
value: _audioPosition?.inMilliseconds?.toDouble() ?? 0.0, value: _audioPosition?.inMilliseconds.toDouble() ?? 0.0,
min: 0, min: 0,
max: _audioTime?.inMilliseconds?.toDouble() ?? 60.0, max: _audioTime?.inMilliseconds.toDouble() ?? 60.0,
onChangeStart: (value){ onChangeStart: (value) {
_sliderMoving = true; _sliderMoving = true;
}, },
onChanged: (value){ onChanged: (value) {
_audioPosition = Duration(milliseconds: value.round()); _audioPosition = Duration(milliseconds: value.round());
rebuild(); rebuild();
}, },
onChangeEnd: (value){ onChangeEnd: (value) {
_sliderMoving = false; _sliderMoving = false;
_audioPlayer.seek(Duration(milliseconds: value.round())); _audioPlayer?.seek(Duration(milliseconds: value.round()));
rebuild(); rebuild();
} }),
),
), ),
], ],
), ),
@ -213,21 +200,21 @@ class _ASoundPlayerState extends State<ASoundPlayer> {
children: [ children: [
Text( Text(
"Failed to load", "Failed to load",
style: Theme.of(context).textTheme.overline.copyWith( style: Theme.of(context)
color: AColors.red .textTheme
), .labelSmall
?.copyWith(color: AColors.red),
textScaleFactor: AppStyle.getScaleFactor(context), textScaleFactor: AppStyle.getScaleFactor(context),
), ),
], ],
), ),
), ),
), ),
Visibility( Visibility(
visible: _audioPlayer.state != PlayerState.stopped, visible: _audioPlayer?.state != PlayerState.stopped,
child: Text( child: Text(
"${format(_audioPosition)}/${format(_audioTime)}", "${format(_audioPosition)}/${format(_audioTime)}",
style: Theme.of(context).textTheme.overline, style: Theme.of(context).textTheme.labelSmall,
textScaleFactor: AppStyle.getScaleFactor(context), textScaleFactor: AppStyle.getScaleFactor(context),
), ),
), ),

@ -4,25 +4,27 @@ import 'package:provider/provider.dart';
import 'package:speech_to_text/speech_recognition_error.dart'; import 'package:speech_to_text/speech_recognition_error.dart';
import 'package:speech_to_text/speech_recognition_result.dart'; import 'package:speech_to_text/speech_recognition_result.dart';
import 'package:speech_to_text/speech_to_text.dart'; import 'package:speech_to_text/speech_to_text.dart';
import 'package:test_sa/controllers/providers/settings/setting_provider.dart';
import 'package:test_sa/views/app_style/sizing.dart'; import '../../../controllers/providers/settings/setting_provider.dart';
import 'package:test_sa/views/widgets/buttons/app_icon_button2.dart'; import '../../app_style/sizing.dart';
import 'package:test_sa/views/widgets/titles/app_sub_title.dart'; import '../buttons/app_icon_button2.dart';
import '../titles/app_sub_title.dart';
class SpeechToTextButton extends StatefulWidget { class SpeechToTextButton extends StatefulWidget {
final TextEditingController controller; final TextEditingController? controller;
final bool mini; final bool mini;
const SpeechToTextButton({Key key, this.controller, this.mini = false}) : super(key: key); const SpeechToTextButton({Key? key, this.controller, this.mini = false})
: super(key: key);
@override @override
_SpeechToTextButtonState createState() => _SpeechToTextButtonState(); SpeechToTextButtonState createState() => SpeechToTextButtonState();
} }
class _SpeechToTextButtonState extends State<SpeechToTextButton> { class SpeechToTextButtonState extends State<SpeechToTextButton> {
bool _speechEnabled = false; bool _speechEnabled = false;
SettingProvider _settingProvider; SettingProvider? _settingProvider;
SpeechToText _speechToText = SpeechToText(); final SpeechToText _speechToText = SpeechToText();
/// This has to happen only once per app /// This has to happen only once per app
void _initSpeech() async { void _initSpeech() async {
@ -44,10 +46,10 @@ class _SpeechToTextButtonState extends State<SpeechToTextButton> {
if (!_speechEnabled) return; if (!_speechEnabled) return;
await _speechToText.listen( await _speechToText.listen(
onResult: (SpeechRecognitionResult result) { onResult: (SpeechRecognitionResult result) {
widget.controller.text = result.recognizedWords; widget.controller?.text = result.recognizedWords;
setState(() {}); setState(() {});
}, },
localeId: _settingProvider.speechToText); localeId: _settingProvider?.speechToText);
setState(() {}); setState(() {});
} }
@ -68,7 +70,7 @@ class _SpeechToTextButtonState extends State<SpeechToTextButton> {
@override @override
void setState(VoidCallback fn) { void setState(VoidCallback fn) {
if (!this.mounted) return; if (!mounted) return;
super.setState(fn); super.setState(fn);
} }
@ -76,41 +78,43 @@ class _SpeechToTextButtonState extends State<SpeechToTextButton> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
_settingProvider = Provider.of<SettingProvider>(context); _settingProvider = Provider.of<SettingProvider>(context);
return Container( return Container(
padding: EdgeInsets.only(left: 12, right: 12), padding: const EdgeInsets.only(left: 12, right: 12),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Color(0xfff5f5f5), color: const Color(0xfff5f5f5),
border: Border.all( border: Border.all(
color: Color(0xffefefef), color: const Color(0xffefefef),
),
borderRadius: BorderRadius.circular(
AppStyle.borderRadius * AppStyle.getScaleFactor(context),
), ),
borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)),
), ),
child: Row( child: Row(
children: [ children: [
widget.mini ? SizedBox.shrink() : ASubTitle("Text To Speech"), widget.mini ? const SizedBox.shrink() : ASubTitle("Text To Speech"),
widget.controller.text.isNotEmpty widget.controller?.text.isNotEmpty ?? false
? AIconButton2( ? AIconButton2(
iconData: Icons.delete, iconData: Icons.delete,
onPressed: () { onPressed: () {
widget.controller.clear(); widget.controller?.clear();
setState(() {}); setState(() {});
}, },
) )
: SizedBox.shrink(), : const SizedBox.shrink(),
Spacer(), const Spacer(),
TextButton( TextButton(
onPressed: () { onPressed: () {
if (_speechToText.isListening) return; if (_speechToText.isListening) return;
if (_settingProvider.speechToText == "ar") { if (_settingProvider?.speechToText == "ar") {
_settingProvider.setSpeechToText("en"); _settingProvider?.setSpeechToText("en");
} else { } else {
_settingProvider.setSpeechToText("ar"); _settingProvider?.setSpeechToText("ar");
} }
}, },
child: Text(_settingProvider.speechToText)), child: Text(_settingProvider?.speechToText ?? '')),
GestureDetector( GestureDetector(
child: _speechToText.isListening child: _speechToText.isListening
? Icon( ? const Icon(
Icons.fiber_manual_record, Icons.fiber_manual_record,
color: Colors.red, color: Colors.red,
) )

@ -1,37 +1,44 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/employee/employee_provider.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart'; import '../../../../controllers/providers/api/status_drop_down/employee/employee_provider.dart';
import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; import '../../../../controllers/providers/api/user_provider.dart';
import 'package:test_sa/models/lookup.dart'; import '../../../../controllers/providers/settings/setting_provider.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; import '../../../../models/lookup.dart';
import 'package:test_sa/views/widgets/status/single_status_menu.dart'; import '../../loaders/loading_manager.dart';
import '../single_status_menu.dart';
class EmployeeMenu extends StatelessWidget { class EmployeeMenu extends StatelessWidget {
final Function(Lookup) onSelect; final Function(Lookup?) onSelect;
final Lookup initialValue; final Lookup? initialValue;
const EmployeeMenu({
Key? key,
required this.onSelect,
required this.initialValue,
}) : super(key: key);
const EmployeeMenu({Key key, this.onSelect, this.initialValue}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final settingProvider = Provider.of<SettingProvider>(context); final settingProvider = Provider.of<SettingProvider>(context);
final userProvider = Provider.of<UserProvider>(context); final userProvider = Provider.of<UserProvider>(context);
final menuProvider = Provider.of<EmployeesProvider>(context); final menuProvider = Provider.of<EmployeesProvider>(context);
return LoadingManager( return LoadingManager(
isLoading: menuProvider.isLoading, isLoading: menuProvider.isLoading,
isFailedLoading: menuProvider.items == null, isFailedLoading: menuProvider.items == null,
stateCode: menuProvider.stateCode, stateCode: menuProvider.stateCode,
onRefresh: () async { onRefresh: () async {
menuProvider.reset(); menuProvider.reset();
await menuProvider.getData( await menuProvider.getData(
user: userProvider.user, user: userProvider.user,
host: settingProvider.host host: settingProvider.host,
); );
}, },
child: SingleStatusMenu( child: SingleStatusMenu(
initialStatus: initialValue, initialStatus: initialValue,
statuses: menuProvider.items, statuses: menuProvider.items,
onSelect: onSelect, onSelect: onSelect,
) ),
); );
} }
} }

@ -1,37 +1,44 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/gas_refill/gas_cylinder_size_provider.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart'; import '../../../../controllers/providers/api/status_drop_down/gas_refill/gas_cylinder_size_provider.dart';
import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; import '../../../../controllers/providers/api/user_provider.dart';
import 'package:test_sa/models/lookup.dart'; import '../../../../controllers/providers/settings/setting_provider.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; import '../../../../models/lookup.dart';
import 'package:test_sa/views/widgets/status/single_status_menu.dart'; import '../../loaders/loading_manager.dart';
import '../single_status_menu.dart';
class GasCylinderSizeMenu extends StatelessWidget { class GasCylinderSizeMenu extends StatelessWidget {
final Function(Lookup) onSelect; final Function(Lookup?)? onSelect;
final Lookup initialValue; final Lookup? initialValue;
const GasCylinderSizeMenu({
Key? key,
this.onSelect,
this.initialValue,
}) : super(key: key);
const GasCylinderSizeMenu({Key key, this.onSelect, this.initialValue}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final settingProvider = Provider.of<SettingProvider>(context); final settingProvider = Provider.of<SettingProvider>(context);
final userProvider = Provider.of<UserProvider>(context); final userProvider = Provider.of<UserProvider>(context);
final menuProvider = Provider.of<GasCylinderSizesProvider>(context); final menuProvider = Provider.of<GasCylinderSizesProvider>(context);
return LoadingManager( return LoadingManager(
isLoading: menuProvider.isLoading, isLoading: menuProvider.isLoading,
isFailedLoading: menuProvider.items == null, isFailedLoading: menuProvider.items == null,
stateCode: menuProvider.stateCode, stateCode: menuProvider.stateCode,
onRefresh: () async { onRefresh: () async {
menuProvider.reset(); menuProvider.reset();
await menuProvider.getData( await menuProvider.getData(
user: userProvider.user, user: userProvider.user,
host: settingProvider.host host: settingProvider.host,
); );
}, },
child: SingleStatusMenu( child: SingleStatusMenu(
initialStatus: initialValue, initialStatus: initialValue,
statuses: menuProvider.items, statuses: menuProvider.items,
onSelect: onSelect, onSelect: onSelect,
) ),
); );
} }
} }

@ -1,16 +1,20 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/gas_refill/gas_status_provider.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart'; import '../../../../controllers/providers/api/status_drop_down/gas_refill/gas_status_provider.dart';
import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; import '../../../../controllers/providers/api/user_provider.dart';
import 'package:test_sa/models/lookup.dart'; import '../../../../controllers/providers/settings/setting_provider.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; import '../../../../models/lookup.dart';
import 'package:test_sa/views/widgets/status/single_status_menu.dart'; import '../../loaders/loading_manager.dart';
import '../single_status_menu.dart';
class GasStatusMenu extends StatelessWidget { class GasStatusMenu extends StatelessWidget {
final Function(Lookup) onSelect; final Function(Lookup?)? onSelect;
final Lookup initialValue; final Lookup? initialValue;
const GasStatusMenu({Key? key, this.onSelect, this.initialValue})
: super(key: key);
const GasStatusMenu({Key key, this.onSelect, this.initialValue}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final settingProvider = Provider.of<SettingProvider>(context); final settingProvider = Provider.of<SettingProvider>(context);
@ -23,15 +27,12 @@ class GasStatusMenu extends StatelessWidget {
onRefresh: () async { onRefresh: () async {
menuProvider.reset(); menuProvider.reset();
await menuProvider.getData( await menuProvider.getData(
user: userProvider.user, user: userProvider.user, host: settingProvider.host);
host: settingProvider.host
);
}, },
child: SingleStatusMenu( child: SingleStatusMenu(
initialStatus: initialValue, initialStatus: initialValue,
statuses: menuProvider.items, statuses: menuProvider.items,
onSelect: onSelect, onSelect: onSelect,
) ));
);
} }
} }

@ -1,37 +1,42 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/gas_refill/gas_types_provider.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart'; import '../../../../controllers/providers/api/status_drop_down/gas_refill/gas_types_provider.dart';
import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; import '../../../../controllers/providers/api/user_provider.dart';
import 'package:test_sa/models/lookup.dart'; import '../../../../controllers/providers/settings/setting_provider.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; import '../../../../models/lookup.dart';
import 'package:test_sa/views/widgets/status/single_status_menu.dart'; import '../../loaders/loading_manager.dart';
import '../single_status_menu.dart';
class GasTypeMenu extends StatelessWidget { class GasTypeMenu extends StatelessWidget {
final Function(Lookup) onSelect; final Function(Lookup?)? onSelect;
final Lookup initialValue; final Lookup? initialValue;
const GasTypeMenu({
Key? key,
this.onSelect,
this.initialValue,
}) : super(key: key);
const GasTypeMenu({Key key, this.onSelect, this.initialValue}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final settingProvider = Provider.of<SettingProvider>(context); final settingProvider = Provider.of<SettingProvider>(context);
final userProvider = Provider.of<UserProvider>(context); final userProvider = Provider.of<UserProvider>(context);
final menuProvider = Provider.of<GasTypesProvider>(context); final menuProvider = Provider.of<GasTypesProvider>(context);
return LoadingManager( return LoadingManager(
isLoading: menuProvider.isLoading, isLoading: menuProvider.isLoading,
isFailedLoading: menuProvider.items == null, isFailedLoading: menuProvider.items == null,
stateCode: menuProvider.stateCode, stateCode: menuProvider.stateCode,
onRefresh: () async { onRefresh: () async {
menuProvider.reset(); menuProvider.reset();
await menuProvider.getData( await menuProvider.getData(
user: userProvider.user, user: userProvider.user, host: settingProvider.host);
host: settingProvider.host },
); child: SingleStatusMenu(
}, initialStatus: initialValue,
child: SingleStatusMenu( statuses: menuProvider.items,
initialStatus: initialValue, onSelect: onSelect,
statuses: menuProvider.items, ),
onSelect: onSelect,
)
); );
} }
} }

@ -1,23 +1,29 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_typeahead/flutter_typeahead.dart'; import 'package:flutter_typeahead/flutter_typeahead.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/views/app_style/colors.dart'; import '../../../models/lookup.dart';
import 'package:test_sa/views/app_style/sizing.dart'; import '../../app_style/colors.dart';
import '../../app_style/sizing.dart';
class MultiStatusMenu extends StatefulWidget { class MultiStatusMenu extends StatefulWidget {
final List<Lookup> statuses; final List<Lookup> statuses;
final List<Lookup> initialSelectedStatus; final List<Lookup> initialSelectedStatus;
final Function(List<Lookup>) onSelect; final Function(List<Lookup>) onSelect;
const MultiStatusMenu({Key key, this.statuses, this.onSelect, this.initialSelectedStatus}) : super(key: key); const MultiStatusMenu({
Key? key,
required this.statuses,
required this.onSelect,
required this.initialSelectedStatus,
}) : super(key: key);
@override @override
_MultiStatusMenuState createState() => _MultiStatusMenuState(); MultiStatusMenuState createState() => MultiStatusMenuState();
} }
class _MultiStatusMenuState extends State<MultiStatusMenu> { class MultiStatusMenuState extends State<MultiStatusMenu> {
final List<Lookup> _selectedStatus = [];
List<Lookup> _selectedStatus = []; late TextEditingController _controller;
TextEditingController _controller;
@override @override
void initState() { void initState() {
@ -31,101 +37,90 @@ class _MultiStatusMenuState extends State<MultiStatusMenu> {
_controller.clear(); _controller.clear();
super.dispose(); super.dispose();
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return return Column(
Column( crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start, children: [
children: [ Wrap(
Wrap( crossAxisAlignment: WrapCrossAlignment.start,
crossAxisAlignment: WrapCrossAlignment.start, alignment: WrapAlignment.start,
alignment: WrapAlignment.start, runAlignment: WrapAlignment.start,
runAlignment: WrapAlignment.start, children: List.generate(_selectedStatus.length, (index) {
children: List.generate( final status = _selectedStatus[index];
_selectedStatus.length, return Container(
(index) { height: (36 * AppStyle.getScaleFactor(context)).toDouble(),
final status = _selectedStatus[index]; margin: EdgeInsets.all(4 * AppStyle.getScaleFactor(context)),
return Container( //padding: EdgeInsets.all(4 * AppStyle.getScaleFactor(context)),
height: 36 * AppStyle.getScaleFactor(context), decoration: BoxDecoration(
margin: EdgeInsets.all(4 * AppStyle.getScaleFactor(context)),
//padding: EdgeInsets.all(4 * AppStyle.getScaleFactor(context)),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primary, color: Theme.of(context).colorScheme.primary,
borderRadius: BorderRadius.circular(8) borderRadius: BorderRadius.circular(8)),
), child: Row(
child: Row( mainAxisSize: MainAxisSize.min,
mainAxisSize: MainAxisSize.min, children: [
children: [ const SizedBox(
const SizedBox(width: 12,), width: 12,
Text( ),
status.label, Text(
style: Theme.of(context).textTheme.bodyText1.copyWith( status.label ?? '',
color:Theme.of(context).colorScheme.onPrimary, style: Theme.of(context).textTheme.bodyLarge?.copyWith(
color: Theme.of(context).colorScheme.onPrimary,
), ),
), ),
IconButton( IconButton(
color:Theme.of(context).colorScheme.onPrimary, color: Theme.of(context).colorScheme.onPrimary,
onPressed: (){ onPressed: () {
_selectedStatus.remove(status); _selectedStatus.remove(status);
widget.onSelect(_selectedStatus); widget.onSelect(_selectedStatus);
setState(() {}); setState(() {});
}, },
icon: const Icon(Icons.delete) icon: const Icon(Icons.delete))
) ],
], ));
) }),
); ),
} Container(
), padding: const EdgeInsets.symmetric(horizontal: 16),
), decoration: BoxDecoration(
Container( color: Colors.white,
padding: const EdgeInsets.symmetric( border: Border.all(color: AColors.black),
horizontal: 16 borderRadius: BorderRadius.circular(
), AppStyle.borderRadius * AppStyle.getScaleFactor(context)),
decoration: BoxDecoration( boxShadow: const [AppStyle.boxShadow]),
color: Colors.white, child: TypeAheadField<Lookup>(
border: Border.all(color:AColors.black), textFieldConfiguration: TextFieldConfiguration(
borderRadius: BorderRadius.circular( style: Theme.of(context).textTheme.titleMedium,
AppStyle.borderRadius * AppStyle.getScaleFactor(context) controller: _controller,
), textAlign: TextAlign.center,
boxShadow: const [ decoration: const InputDecoration(
AppStyle.boxShadow border: InputBorder.none,
] disabledBorder: InputBorder.none,
), focusedBorder: InputBorder.none,
child: TypeAheadField<Lookup>( enabledBorder: InputBorder.none,
textFieldConfiguration: TextFieldConfiguration(
style: Theme.of(context).textTheme.subtitle1,
controller: _controller,
textAlign: TextAlign.center,
decoration: const InputDecoration(
border: InputBorder.none,
disabledBorder: InputBorder.none,
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
),
textInputAction: TextInputAction.search,
), ),
suggestionsCallback: (vale) { textInputAction: TextInputAction.search,
return widget.statuses.where((Lookup option) {
return option.label.toLowerCase().contains(_controller.text);
});
},
itemBuilder: (context, part) {
return ListTile(
title: Text(part.label),
);
},
onSuggestionSelected: (status) {
_controller.clear();
if(!_selectedStatus.contains(status)){
_selectedStatus.add(status);
widget.onSelect(_selectedStatus);
setState(() {});
}
},
), ),
suggestionsCallback: (vale) {
return widget.statuses.where((Lookup option) {
return option.label?.toLowerCase().contains(_controller.text) ??
false;
});
},
itemBuilder: (context, part) {
return ListTile(title: Text(part.label ?? ''));
},
onSuggestionSelected: (status) {
_controller.clear();
if (!_selectedStatus.contains(status)) {
_selectedStatus.add(status);
widget.onSelect(_selectedStatus);
setState(() {});
}
},
), ),
], ),
); ],
);
} }
} }

@ -1,37 +1,40 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/pentry/pentry_status_provider.dart'; import '../../../../controllers/providers/api/status_drop_down/pentry/pentry_status_provider.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart'; import '../../../../controllers/providers/api/user_provider.dart';
import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; import '../../../../controllers/providers/settings/setting_provider.dart';
import 'package:test_sa/models/lookup.dart'; import '../../../../models/lookup.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; import '../../loaders/loading_manager.dart';
import 'package:test_sa/views/widgets/status/single_status_menu.dart'; import '../single_status_menu.dart';
class PentryStatusMenu extends StatelessWidget { class PentryStatusMenu extends StatelessWidget {
final Function(Lookup) onSelect; final Function(Lookup?)? onSelect;
final Lookup initialValue; final Lookup? initialValue;
const PentryStatusMenu({Key? key, this.onSelect, this.initialValue})
: super(key: key);
const PentryStatusMenu({Key key, this.onSelect, this.initialValue}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final settingProvider = Provider.of<SettingProvider>(context); final settingProvider = Provider.of<SettingProvider>(context);
final userProvider = Provider.of<UserProvider>(context); final userProvider = Provider.of<UserProvider>(context);
final menuProvider = Provider.of<PentryStatusProvider>(context); final menuProvider = Provider.of<PentryStatusProvider>(context);
return LoadingManager( return LoadingManager(
isLoading: menuProvider.isLoading, isLoading: menuProvider.isLoading,
isFailedLoading: menuProvider.items == null, isFailedLoading: menuProvider.items == null,
stateCode: menuProvider.stateCode, stateCode: menuProvider.stateCode,
onRefresh: () async { onRefresh: () async {
menuProvider.reset(); menuProvider.reset();
await menuProvider.getData( await menuProvider.getData(
user: userProvider.user, user: userProvider.user,
host: settingProvider.host host: settingProvider.host,
); );
}, },
child: SingleStatusMenu( child: SingleStatusMenu(
initialStatus: initialValue, initialStatus: initialValue,
statuses: menuProvider.items, statuses: menuProvider.items,
onSelect: onSelect, onSelect: onSelect,
) ),
); );
} }
} }

@ -1,37 +1,44 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/pentry/pentry_task_status_provider.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart'; import '../../../../controllers/providers/api/status_drop_down/pentry/pentry_task_status_provider.dart';
import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; import '../../../../controllers/providers/api/user_provider.dart';
import 'package:test_sa/models/lookup.dart'; import '../../../../controllers/providers/settings/setting_provider.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; import '../../../../models/lookup.dart';
import 'package:test_sa/views/widgets/status/single_status_menu.dart'; import '../../loaders/loading_manager.dart';
import '../single_status_menu.dart';
class PentryTaskStatusMenu extends StatelessWidget { class PentryTaskStatusMenu extends StatelessWidget {
final Function(Lookup) onSelect; final Function(Lookup?)? onSelect;
final Lookup initialValue; final Lookup? initialValue;
const PentryTaskStatusMenu({
Key? key,
this.onSelect,
this.initialValue,
}) : super(key: key);
const PentryTaskStatusMenu({Key key, this.onSelect, this.initialValue}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final settingProvider = Provider.of<SettingProvider>(context); final settingProvider = Provider.of<SettingProvider>(context);
final userProvider = Provider.of<UserProvider>(context); final userProvider = Provider.of<UserProvider>(context);
final menuProvider = Provider.of<PentryTaskStatusProvider>(context); final menuProvider = Provider.of<PentryTaskStatusProvider>(context);
return LoadingManager( return LoadingManager(
isLoading: menuProvider.isLoading, isLoading: menuProvider.isLoading,
isFailedLoading: menuProvider.items == null, isFailedLoading: menuProvider.items == null,
stateCode: menuProvider.stateCode, stateCode: menuProvider.stateCode,
onRefresh: () async { onRefresh: () async {
menuProvider.reset(); menuProvider.reset();
await menuProvider.getData( await menuProvider.getData(
user: userProvider.user, user: userProvider.user,
host: settingProvider.host host: settingProvider.host,
); );
}, },
child: SingleStatusMenu( child: SingleStatusMenu(
initialStatus: initialValue, initialStatus: initialValue,
statuses: menuProvider.items, statuses: menuProvider.items,
onSelect: onSelect, onSelect: onSelect,
) ),
); );
} }
} }

@ -1,37 +1,44 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/pentry/pentry_visit_status_provider.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart'; import '../../../../controllers/providers/api/status_drop_down/pentry/pentry_visit_status_provider.dart';
import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; import '../../../../controllers/providers/api/user_provider.dart';
import 'package:test_sa/models/lookup.dart'; import '../../../../controllers/providers/settings/setting_provider.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; import '../../../../models/lookup.dart';
import 'package:test_sa/views/widgets/status/single_status_menu.dart'; import '../../loaders/loading_manager.dart';
import '../single_status_menu.dart';
class PentryVisitsStatusMenu extends StatelessWidget { class PentryVisitsStatusMenu extends StatelessWidget {
final Function(Lookup) onSelect; final Function(Lookup?)? onSelect;
final Lookup initialValue; final Lookup? initialValue;
const PentryVisitsStatusMenu({
Key? key,
this.onSelect,
this.initialValue,
}) : super(key: key);
const PentryVisitsStatusMenu({Key key, this.onSelect, this.initialValue}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final settingProvider = Provider.of<SettingProvider>(context); final settingProvider = Provider.of<SettingProvider>(context);
final userProvider = Provider.of<UserProvider>(context); final userProvider = Provider.of<UserProvider>(context);
final menuProvider = Provider.of<PentryVisitStatusProvider>(context); final menuProvider = Provider.of<PentryVisitStatusProvider>(context);
return LoadingManager( return LoadingManager(
isLoading: menuProvider.isLoading, isLoading: menuProvider.isLoading,
isFailedLoading: menuProvider.items == null, isFailedLoading: menuProvider.items == null,
stateCode: menuProvider.stateCode, stateCode: menuProvider.stateCode,
onRefresh: () async { onRefresh: () async {
menuProvider.reset(); menuProvider.reset();
await menuProvider.getData( await menuProvider.getData(
user: userProvider.user, user: userProvider.user,
host: settingProvider.host host: settingProvider.host,
); );
}, },
child: SingleStatusMenu( child: SingleStatusMenu(
initialStatus: initialValue, initialStatus: initialValue,
statuses: menuProvider.items, statuses: menuProvider.items,
onSelect: onSelect, onSelect: onSelect,
) ),
); );
} }
} }

@ -1,29 +1,36 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_report_last_calls_provider.dart';
import 'package:test_sa/models/lookup.dart'; import '../../../../controllers/providers/api/status_drop_down/report/service_report_last_calls_provider.dart';
import 'package:test_sa/models/service_report.dart'; import '../../../../models/lookup.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; import '../../../../models/service_report.dart';
import 'package:test_sa/views/widgets/status/single_status_menu.dart'; import '../../loaders/loading_manager.dart';
import '../single_status_menu.dart';
class ServiceReportLastCallsMenu extends StatelessWidget { class ServiceReportLastCallsMenu extends StatelessWidget {
final Function(Lookup) onSelect; final Function(Lookup?)? onSelect;
final ServiceReport report; final ServiceReport? report;
const ServiceReportLastCallsMenu({ const ServiceReportLastCallsMenu({
Key key,@required this.onSelect,@required this.report}) : super(key: key); Key? key,
required this.onSelect,
required this.report,
}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
ServiceReportLastCallsProvider _menuProvider = Provider.of<ServiceReportLastCallsProvider>(context); ServiceReportLastCallsProvider menuProvider =
Provider.of<ServiceReportLastCallsProvider>(context);
return LoadingManager( return LoadingManager(
isLoading: _menuProvider.isLoading, isLoading: menuProvider.isLoading,
isFailedLoading: _menuProvider.calls == null, isFailedLoading: menuProvider.calls == null,
stateCode: _menuProvider.stateCode, stateCode: menuProvider.stateCode,
onRefresh: () async {}, onRefresh: () async {},
child: SingleStatusMenu( child: SingleStatusMenu(
initialStatus: report?.callLastSituation, initialStatus: report?.callLastSituation,
statuses: _menuProvider.calls, statuses: menuProvider.calls,
onSelect: onSelect, onSelect: onSelect,
) ),
); );
} }
} }

@ -1,38 +1,44 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_report_reasons_provider.dart'; import '../../../../controllers/providers/api/status_drop_down/report/service_report_reasons_provider.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart'; import '../../../../controllers/providers/api/user_provider.dart';
import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; import '../../../../controllers/providers/settings/setting_provider.dart';
import 'package:test_sa/models/lookup.dart'; import '../../../../models/lookup.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; import '../../loaders/loading_manager.dart';
import 'package:test_sa/views/widgets/status/single_status_menu.dart'; import '../single_status_menu.dart';
class ServiceReportReasonsMenu extends StatelessWidget { class ServiceReportReasonsMenu extends StatelessWidget {
final Lookup initialValue; final Lookup? initialValue;
final Function(Lookup) onSelect; final Function(Lookup?)? onSelect;
const ServiceReportReasonsMenu({
Key? key,
this.onSelect,
this.initialValue,
}) : super(key: key);
const ServiceReportReasonsMenu({Key key, this.onSelect, this.initialValue}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
SettingProvider _settingProvider = Provider.of<SettingProvider>(context); SettingProvider settingProvider = Provider.of<SettingProvider>(context);
UserProvider _userProvider = Provider.of<UserProvider>(context); UserProvider userProvider = Provider.of<UserProvider>(context);
ServiceReportReasonsProvider _menuProvider = Provider.of<ServiceReportReasonsProvider>(context); ServiceReportReasonsProvider menuProvider =
Provider.of<ServiceReportReasonsProvider>(context);
return LoadingManager( return LoadingManager(
isLoading: _menuProvider.isLoading, isLoading: menuProvider.isLoading,
isFailedLoading: _menuProvider.reasons == null, isFailedLoading: menuProvider.reasons == null,
stateCode: _menuProvider.stateCode, stateCode: menuProvider.stateCode,
onRefresh: () async { onRefresh: () async {
_menuProvider.reset(); menuProvider.reset();
await _menuProvider.getTypes( await menuProvider.getTypes(
user: _userProvider.user, user: userProvider.user,
host: _settingProvider.host, host: settingProvider.host,
);
); },
}, child: SingleStatusMenu(
child: SingleStatusMenu( initialStatus: initialValue,
initialStatus: initialValue, statuses: menuProvider.reasons,
statuses: _menuProvider.reasons, onSelect: onSelect,
onSelect: onSelect, ),
)
); );
} }
} }

@ -2,69 +2,81 @@ import 'dart:math';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_report_last_calls_provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_report_status_provider.dart'; import '../../../../controllers/providers/api/status_drop_down/report/service_report_last_calls_provider.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart'; import '../../../../controllers/providers/api/status_drop_down/report/service_report_status_provider.dart';
import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; import '../../../../controllers/providers/api/user_provider.dart';
import 'package:test_sa/models/lookup.dart'; import '../../../../controllers/providers/settings/setting_provider.dart';
import 'package:test_sa/models/service_report.dart'; import '../../../../models/lookup.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; import '../../../../models/service_report.dart';
import 'package:test_sa/views/widgets/status/single_status_menu.dart'; import '../../loaders/loading_manager.dart';
import '../single_status_menu.dart';
class ServiceReportStatusMenu extends StatefulWidget { class ServiceReportStatusMenu extends StatefulWidget {
final Function(Lookup) onSelect; final Function(Lookup?) onSelect;
final ServiceReport report; final ServiceReport? report;
const ServiceReportStatusMenu({Key key, this.onSelect, this.report}) : super(key: key); const ServiceReportStatusMenu({
Key? key,
required this.onSelect,
this.report,
}) : super(key: key);
@override @override
State<ServiceReportStatusMenu> createState() => _ServiceReportStatusMenuState(); State<ServiceReportStatusMenu> createState() =>
_ServiceReportStatusMenuState();
} }
class _ServiceReportStatusMenuState extends State<ServiceReportStatusMenu> { class _ServiceReportStatusMenuState extends State<ServiceReportStatusMenu> {
bool firstTime = true; bool firstTime = true;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
SettingProvider _settingProvider = Provider.of<SettingProvider>(context); SettingProvider settingProvider = Provider.of<SettingProvider>(context);
UserProvider _userProvider = Provider.of<UserProvider>(context); UserProvider userProvider = Provider.of<UserProvider>(context);
ServiceReportStatusProvider _menuProvider = Provider.of<ServiceReportStatusProvider>(context); ServiceReportStatusProvider menuProvider =
ServiceReportLastCallsProvider _callsLastSituationsProvider = Provider.of<ServiceReportLastCallsProvider>(context,listen: false); Provider.of<ServiceReportStatusProvider>(context);
if(firstTime){ ServiceReportLastCallsProvider callsLastSituationsProvider =
_callsLastSituationsProvider.reset(); Provider.of<ServiceReportLastCallsProvider>(context, listen: false);
if (firstTime) {
callsLastSituationsProvider.reset();
firstTime = false; firstTime = false;
} }
return LoadingManager( return LoadingManager(
isLoading: _menuProvider.isLoading == true || _callsLastSituationsProvider.isLoading == true, isLoading: menuProvider.isLoading == true ||
isFailedLoading: _menuProvider.statuses == null || _callsLastSituationsProvider.calls == null, callsLastSituationsProvider.isLoading == true,
stateCode: _menuProvider.stateCode == null || _callsLastSituationsProvider.stateCode == null ? null: isFailedLoading: menuProvider.statuses == null ||
max(_menuProvider.stateCode ?? 0,_callsLastSituationsProvider.stateCode ?? 0), callsLastSituationsProvider.calls == null,
stateCode: menuProvider.stateCode == null ||
callsLastSituationsProvider.stateCode == null
? null
: max(menuProvider.stateCode ?? 0,
callsLastSituationsProvider.stateCode ?? 0),
onRefresh: () async { onRefresh: () async {
if(_menuProvider.stateCode == null){ if (menuProvider.stateCode == null) {
_menuProvider.reset(); menuProvider.reset();
await _menuProvider.getTypes( await menuProvider.getTypes(
user: _userProvider.user, user: userProvider.user,
host: _settingProvider.host host: settingProvider.host,
); );
} }
await _callsLastSituationsProvider.getCalls( await callsLastSituationsProvider.getCalls(
user: _userProvider.user, user: userProvider.user,
host: _settingProvider.host, host: settingProvider.host,
serviceStatus: widget.report.status?.id.toString() serviceStatus: widget.report?.status?.id.toString());
);
}, },
child: SingleStatusMenu( child: SingleStatusMenu(
statuses: _menuProvider.statuses, statuses: menuProvider.statuses,
initialStatus: widget.report.status, initialStatus: widget.report?.status,
onSelect: (status){ onSelect: (status) {
_callsLastSituationsProvider.getCalls( callsLastSituationsProvider.getCalls(
user: _userProvider.user, user: userProvider.user,
host: _settingProvider.host, host: settingProvider.host,
serviceStatus: status.id.toString() serviceStatus: status?.id.toString());
); widget.report?.callLastSituation = null;
widget.report.callLastSituation = null;
widget.onSelect(status); widget.onSelect(status);
}, },
) ));
);
} }
} }

@ -1,21 +1,29 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_report_types_provider.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart'; import '../../../../controllers/providers/api/status_drop_down/report/service_report_types_provider.dart';
import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; import '../../../../controllers/providers/api/user_provider.dart';
import 'package:test_sa/models/lookup.dart'; import '../../../../controllers/providers/settings/setting_provider.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; import '../../../../models/lookup.dart';
import 'package:test_sa/views/widgets/status/single_status_menu.dart'; import '../../loaders/loading_manager.dart';
import '../single_status_menu.dart';
class ServiceReportTypeMenu extends StatelessWidget { class ServiceReportTypeMenu extends StatelessWidget {
final Function(Lookup) onSelect; final Function(Lookup?) onSelect;
final Lookup initialValue; final Lookup? initialValue;
const ServiceReportTypeMenu({
Key? key,
required this.onSelect,
this.initialValue,
}) : super(key: key);
const ServiceReportTypeMenu({Key key, this.onSelect, this.initialValue}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
SettingProvider settingProvider = Provider.of<SettingProvider>(context); SettingProvider settingProvider = Provider.of<SettingProvider>(context);
UserProvider userProvider = Provider.of<UserProvider>(context); UserProvider userProvider = Provider.of<UserProvider>(context);
ServiceReportTypesProvider menuProvider = Provider.of<ServiceReportTypesProvider>(context); ServiceReportTypesProvider menuProvider =
Provider.of<ServiceReportTypesProvider>(context);
return LoadingManager( return LoadingManager(
isLoading: menuProvider.isLoading, isLoading: menuProvider.isLoading,
isFailedLoading: menuProvider.types == null, isFailedLoading: menuProvider.types == null,
@ -24,7 +32,7 @@ class ServiceReportTypeMenu extends StatelessWidget {
menuProvider.reset(); menuProvider.reset();
await menuProvider.getTypes( await menuProvider.getTypes(
user: userProvider.user, user: userProvider.user,
host: settingProvider.host host: settingProvider.host,
); );
onSelect(initialValue ?? menuProvider.types?.last); onSelect(initialValue ?? menuProvider.types?.last);
}, },
@ -32,7 +40,6 @@ class ServiceReportTypeMenu extends StatelessWidget {
initialStatus: initialValue ?? menuProvider.types?.last, initialStatus: initialValue ?? menuProvider.types?.last,
statuses: menuProvider.types, statuses: menuProvider.types,
onSelect: onSelect, onSelect: onSelect,
) ));
);
} }
} }

@ -1,37 +1,44 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_types_provider.dart'; import '../../../../controllers/providers/api/status_drop_down/report/service_types_provider.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart'; import '../../../../controllers/providers/api/user_provider.dart';
import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; import '../../../../controllers/providers/settings/setting_provider.dart';
import 'package:test_sa/models/lookup.dart'; import '../../../../models/lookup.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; import '../../loaders/loading_manager.dart';
import 'package:test_sa/views/widgets/status/single_status_menu.dart'; import '../single_status_menu.dart';
class ServiceStatusMenu extends StatelessWidget { class ServiceStatusMenu extends StatelessWidget {
final Function(Lookup) onSelect; final Function(Lookup?)? onSelect;
final Lookup initialValue; final Lookup? initialValue;
const ServiceStatusMenu({
Key? key,
this.onSelect,
this.initialValue,
}) : super(key: key);
const ServiceStatusMenu({Key key, this.onSelect, this.initialValue}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
SettingProvider _settingProvider = Provider.of<SettingProvider>(context); SettingProvider settingProvider = Provider.of<SettingProvider>(context);
UserProvider _userProvider = Provider.of<UserProvider>(context); UserProvider userProvider = Provider.of<UserProvider>(context);
ServiceStatusProvider _menuProvider = Provider.of<ServiceStatusProvider>(context); ServiceStatusProvider menuProvider =
Provider.of<ServiceStatusProvider>(context);
return LoadingManager( return LoadingManager(
isLoading: _menuProvider.isLoading, isLoading: menuProvider.isLoading,
isFailedLoading: _menuProvider.statuses == null, isFailedLoading: menuProvider.statuses == null,
stateCode: _menuProvider.stateCode, stateCode: menuProvider.stateCode,
onRefresh: () async { onRefresh: () async {
_menuProvider.reset(); menuProvider.reset();
await _menuProvider.getTypes( await menuProvider.getTypes(
user: _userProvider.user, user: userProvider.user,
host: _settingProvider.host host: settingProvider.host,
); );
}, },
child: SingleStatusMenu( child: SingleStatusMenu(
initialStatus: initialValue, initialStatus: initialValue,
statuses: _menuProvider.statuses, statuses: menuProvider.statuses,
onSelect: onSelect, onSelect: onSelect,
) ),
); );
} }
} }

@ -1,37 +1,44 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_report_defect_types_provider.dart'; import '../../../../controllers/providers/api/status_drop_down/report/service_report_defect_types_provider.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart'; import '../../../../controllers/providers/api/user_provider.dart';
import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; import '../../../../controllers/providers/settings/setting_provider.dart';
import 'package:test_sa/models/lookup.dart'; import '../../../../models/lookup.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; import '../../loaders/loading_manager.dart';
import 'package:test_sa/views/widgets/status/single_status_menu.dart'; import '../single_status_menu.dart';
class ServiceRequestDefectTypesMenu extends StatelessWidget { class ServiceRequestDefectTypesMenu extends StatelessWidget {
final Function(Lookup) onSelect; final Function(Lookup?)? onSelect;
final Lookup initialValue; final Lookup? initialValue;
const ServiceRequestDefectTypesMenu({
Key? key,
this.onSelect,
this.initialValue,
}) : super(key: key);
const ServiceRequestDefectTypesMenu({Key key, this.onSelect, this.initialValue}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final settingProvider = Provider.of<SettingProvider>(context); final settingProvider = Provider.of<SettingProvider>(context);
final userProvider = Provider.of<UserProvider>(context); final userProvider = Provider.of<UserProvider>(context);
final menuProvider = Provider.of<ServiceRequestDefectTypesProvider>(context); final menuProvider =
Provider.of<ServiceRequestDefectTypesProvider>(context);
return LoadingManager( return LoadingManager(
isLoading: menuProvider.isLoading, isLoading: menuProvider.isLoading,
isFailedLoading: menuProvider.items == null, isFailedLoading: menuProvider.items == null,
stateCode: menuProvider.stateCode, stateCode: menuProvider.stateCode,
onRefresh: () async { onRefresh: () async {
menuProvider.reset(); menuProvider.reset();
await menuProvider.getData( await menuProvider.getData(
user: userProvider.user, user: userProvider.user,
host: settingProvider.host host: settingProvider.host,
); );
}, },
child: SingleStatusMenu( child: SingleStatusMenu(
initialStatus: initialValue, initialStatus: initialValue,
statuses: menuProvider.items, statuses: menuProvider.items,
onSelect: onSelect, onSelect: onSelect,
) ),
); );
} }
} }

@ -1,37 +1,43 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_report_priority_provider.dart'; import '../../../../controllers/providers/api/status_drop_down/report/service_report_priority_provider.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart'; import '../../../../controllers/providers/api/user_provider.dart';
import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; import '../../../../controllers/providers/settings/setting_provider.dart';
import 'package:test_sa/models/lookup.dart'; import '../../../../models/lookup.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; import '../../loaders/loading_manager.dart';
import 'package:test_sa/views/widgets/status/single_status_menu.dart'; import '../single_status_menu.dart';
class ServiceRequestPriorityMenu extends StatelessWidget { class ServiceRequestPriorityMenu extends StatelessWidget {
final Function(Lookup) onSelect; final Function(Lookup?)? onSelect;
final Lookup initialValue; final Lookup? initialValue;
const ServiceRequestPriorityMenu({
Key? key,
this.onSelect,
this.initialValue,
}) : super(key: key);
const ServiceRequestPriorityMenu({Key key, this.onSelect, this.initialValue}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final settingProvider = Provider.of<SettingProvider>(context); final settingProvider = Provider.of<SettingProvider>(context);
final userProvider = Provider.of<UserProvider>(context); final userProvider = Provider.of<UserProvider>(context);
final menuProvider = Provider.of<ServiceRequestPriorityProvider>(context); final menuProvider = Provider.of<ServiceRequestPriorityProvider>(context);
return LoadingManager( return LoadingManager(
isLoading: menuProvider.isLoading, isLoading: menuProvider.isLoading,
isFailedLoading: menuProvider.items == null, isFailedLoading: menuProvider.items == null,
stateCode: menuProvider.stateCode, stateCode: menuProvider.stateCode,
onRefresh: () async { onRefresh: () async {
menuProvider.reset(); menuProvider.reset();
await menuProvider.getData( await menuProvider.getData(
user: userProvider.user, user: userProvider.user,
host: settingProvider.host host: settingProvider.host,
); );
}, },
child: SingleStatusMenu( child: SingleStatusMenu(
initialStatus: initialValue, initialStatus: initialValue,
statuses: menuProvider.items, statuses: menuProvider.items,
onSelect: onSelect, onSelect: onSelect,
) ),
); );
} }
} }

@ -1,27 +1,33 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/views/app_style/colors.dart'; import '../../../models/lookup.dart';
import 'package:test_sa/views/app_style/sizing.dart'; import '../../app_style/colors.dart';
import '../../app_style/sizing.dart';
class SingleStatusMenu extends StatefulWidget { class SingleStatusMenu extends StatefulWidget {
final List<Lookup> statuses; final List<Lookup>? statuses;
final Lookup initialStatus; final Lookup? initialStatus;
final Function(Lookup) onSelect; final Function(Lookup?)? onSelect;
const SingleStatusMenu({Key key, this.statuses, this.onSelect, this.initialStatus}) : super(key: key); const SingleStatusMenu({
Key? key,
this.onSelect,
this.statuses,
this.initialStatus,
}) : super(key: key);
@override @override
_SingleStatusMenuState createState() => _SingleStatusMenuState(); SingleStatusMenuState createState() => SingleStatusMenuState();
} }
class _SingleStatusMenuState extends State<SingleStatusMenu> { class SingleStatusMenuState extends State<SingleStatusMenu> {
Lookup _selectedStatus; Lookup? _selectedStatus;
@override @override
void didUpdateWidget(covariant SingleStatusMenu oldWidget) { void didUpdateWidget(covariant SingleStatusMenu oldWidget) {
if (widget.initialStatus != null) { if (widget.initialStatus != null) {
_selectedStatus = widget.statuses?.firstWhere((element) { _selectedStatus = widget.statuses?.firstWhere((element) {
return element?.id == widget.initialStatus.id; return element.id == widget.initialStatus?.id;
}); });
} else { } else {
_selectedStatus = null; _selectedStatus = null;
@ -33,7 +39,7 @@ class _SingleStatusMenuState extends State<SingleStatusMenu> {
void initState() { void initState() {
if (widget.initialStatus != null) { if (widget.initialStatus != null) {
_selectedStatus = widget.statuses?.firstWhere((element) { _selectedStatus = widget.statuses?.firstWhere((element) {
return element?.id == widget.initialStatus.id; return element.id == widget.initialStatus?.id;
}); });
} }
@ -47,9 +53,11 @@ class _SingleStatusMenuState extends State<SingleStatusMenu> {
decoration: BoxDecoration( decoration: BoxDecoration(
color: AColors.inputFieldBackgroundColor, color: AColors.inputFieldBackgroundColor,
border: Border.all( border: Border.all(
color: Color(0xffefefef), color: const Color(0xffefefef),
),
borderRadius: BorderRadius.circular(
AppStyle.borderRadius * AppStyle.getScaleFactor(context),
), ),
borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)),
// boxShadow: const [ // boxShadow: const [
// AppStyle.boxShadow // AppStyle.boxShadow
// ] // ]
@ -57,7 +65,7 @@ class _SingleStatusMenuState extends State<SingleStatusMenu> {
child: DropdownButton<Lookup>( child: DropdownButton<Lookup>(
value: _selectedStatus, value: _selectedStatus,
iconSize: 24, iconSize: 24,
icon: Icon(Icons.keyboard_arrow_down_rounded), icon: const Icon(Icons.keyboard_arrow_down_rounded),
elevation: 0, elevation: 0,
isExpanded: true, isExpanded: true,
hint: Text( hint: Text(
@ -65,19 +73,23 @@ class _SingleStatusMenuState extends State<SingleStatusMenu> {
style: Theme.of(context).textTheme.subtitle1, style: Theme.of(context).textTheme.subtitle1,
), ),
style: TextStyle(color: Theme.of(context).primaryColor), style: TextStyle(color: Theme.of(context).primaryColor),
underline: SizedBox.shrink(), underline: const SizedBox.shrink(),
onChanged: (Lookup newValue) { onChanged: (Lookup? newValue) {
setState(() { setState(() {
_selectedStatus = newValue; _selectedStatus = newValue;
}); });
widget.onSelect(newValue); if (widget.onSelect != null) {
widget.onSelect!(newValue);
}
}, },
items: widget.statuses.map<DropdownMenuItem<Lookup>>((Lookup value) { items: widget.statuses?.map<DropdownMenuItem<Lookup>>((Lookup value) {
return DropdownMenuItem<Lookup>( return DropdownMenuItem<Lookup>(
value: value, value: value,
child: Text( child: Text(
value.label, value.label ?? '',
style: Theme.of(context).textTheme.subtitle1.copyWith(color: Theme.of(context).primaryColor, fontWeight: FontWeight.w600), style: Theme.of(context).textTheme.titleMedium?.copyWith(
color: Theme.of(context).primaryColor,
fontWeight: FontWeight.w600),
), ),
); );
}).toList(), }).toList(),

@ -1,19 +1,21 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:test_sa/models/timer_model.dart';
import 'package:test_sa/views/app_style/colors.dart'; import '../../../models/timer_model.dart';
import 'package:test_sa/views/app_style/sizing.dart'; import '../../app_style/colors.dart';
import 'package:test_sa/views/widgets/loaders/app_loading.dart'; import '../../app_style/sizing.dart';
class AppTimer extends StatefulWidget { class AppTimer extends StatefulWidget {
final TimerModel timer; final TimerModel? timer;
final Future<bool> Function(TimerModel) onChange; final Future<bool> Function(TimerModel) onChange;
final TextStyle style; final TextStyle? style;
const AppTimer({ const AppTimer({
Key key, Key? key,
this.timer, this.timer,
this.onChange,
this.style, this.style,
required this.onChange,
}) : super(key: key); }) : super(key: key);
@override @override
@ -21,43 +23,46 @@ class AppTimer extends StatefulWidget {
} }
class _AppTimerState extends State<AppTimer> { class _AppTimerState extends State<AppTimer> {
Timer _timer; Timer? _timer;
DateTime _startAt; DateTime? _startAt;
DateTime _endAt; DateTime? _endAt;
int _delay = 0; int _delay = 0;
bool _running = false; bool _running = false;
bool _loading = false; bool _loading = false;
final ValueNotifier<String> _period = ValueNotifier("0:00:00"); final ValueNotifier<String> _period = ValueNotifier("0:00:00");
_startTimer() async { _startTimer() async {
if (!_running) { if (!_running) {
final time = DateTime.now(); final time = DateTime.now();
bool result = await widget.onChange( bool result = await widget.onChange(
TimerModel(startAt: time,endAt: null,durationInSecond: _delay)); TimerModel(startAt: time, endAt: null, durationInSecond: _delay),
if(!result) return; );
if (!result) return;
_running = true; _running = true;
if(_endAt != null){ if (_endAt != null && _startAt != null) {
_delay += _endAt.difference(_startAt).inSeconds; _delay += _endAt!.difference(_startAt!).inSeconds;
} }
_startAt = time.subtract(Duration(seconds: _delay)); _startAt = time.subtract(Duration(seconds: _delay));
_endAt = null; _endAt = null;
} }
_timer = Timer.periodic(const Duration(seconds: 1), (timer) { _timer = Timer.periodic(const Duration(seconds: 1), (timer) {
if(_loading == true) return; if (_loading == true) return;
_period.value = (_endAt ?? DateTime.now()).difference( _period.value = (_endAt ?? DateTime.now())
_startAt .difference(_startAt!)
).toString().split(".").first; .toString()
.split(".")
.first;
}); });
} }
_stopTimer() async { _stopTimer() async {
final time = DateTime.now(); final time = DateTime.now();
final tempStartAt = _startAt.add(Duration(seconds: _delay)); final tempStartAt = _startAt?.add(Duration(seconds: _delay));
bool result = await widget.onChange( bool result = await widget.onChange(TimerModel(
TimerModel(startAt: tempStartAt,endAt: time,durationInSecond: _delay)); startAt: tempStartAt, endAt: time, durationInSecond: _delay));
if(!result) return; if (!result) return;
_running = false; _running = false;
_endAt = time; _endAt = time;
_startAt = tempStartAt; _startAt = tempStartAt;
@ -67,9 +72,9 @@ class _AppTimerState extends State<AppTimer> {
_onPressed() async { _onPressed() async {
_loading = true; _loading = true;
setState(() {}); setState(() {});
if(!_running){ if (!_running) {
await _startTimer(); await _startTimer();
}else{ } else {
await _stopTimer(); await _stopTimer();
} }
_loading = false; _loading = false;
@ -82,17 +87,25 @@ class _AppTimerState extends State<AppTimer> {
_endAt = widget.timer?.endAt; _endAt = widget.timer?.endAt;
_running = _startAt != null && _endAt == null; _running = _startAt != null && _endAt == null;
_delay = (widget.timer?.durationInSecond ?? 0); _delay = (widget.timer?.durationInSecond ?? 0);
final difference = _startAt == null ? 0: final difference = _startAt == null
(_endAt ?? DateTime.now())?.difference(_startAt)?.inSeconds ?? 0; ? 0
_period.value = Duration(seconds: _running ? difference : _delay + difference).toString().split(".").first; : (_endAt ?? DateTime.now()).difference(_startAt!).inSeconds;
_period.value =
Duration(seconds: _running ? difference : _delay + difference)
.toString()
.split(".")
.first;
super.initState(); super.initState();
if(_running){_startTimer();} if (_running) {
_startTimer();
}
} }
@override @override
void dispose() { void dispose() {
super.dispose(); super.dispose();
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SizedBox( return SizedBox(
@ -100,31 +113,34 @@ class _AppTimerState extends State<AppTimer> {
height: 28 * AppStyle.getScaleFactor(context), height: 28 * AppStyle.getScaleFactor(context),
child: ElevatedButton( child: ElevatedButton(
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
minimumSize: const Size(1, 1), minimumSize: const Size(1, 1),
padding: EdgeInsets.all(4 * AppStyle.getScaleFactor(context)), padding: EdgeInsets.all(4 * AppStyle.getScaleFactor(context)),
backgroundColor: _running ? AColors.green[300] : AColors.grey, backgroundColor: _running ? AColors.green[300] : AColors.grey,
foregroundColor: Colors.black foregroundColor: Colors.black),
),
onPressed: _loading ? null : _onPressed, onPressed: _loading ? null : _onPressed,
child: _loading ? const SizedBox.square( child: _loading
dimension: 18,child: CircularProgressIndicator(color: Colors.white,)): ? const SizedBox.square(
Row( dimension: 18,
children: [ child: CircularProgressIndicator(
Icon(_running ? Icons.pause : Icons.play_arrow), color: Colors.white,
Expanded( ))
child: Center( : Row(
child: ValueListenableBuilder<String>( children: [
valueListenable: _period, Icon(_running ? Icons.pause : Icons.play_arrow),
builder: (context,value,_){ Expanded(
return Text(value, child: Center(
style: widget.style, child: ValueListenableBuilder<String>(
); valueListenable: _period,
} builder: (context, value, _) {
), return Text(
value,
style: widget.style,
);
}),
),
),
],
), ),
),
],
),
), ),
); );
} }

@ -1,22 +1,26 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:test_sa/views/app_style/sizing.dart';
import '../../app_style/sizing.dart';
class ASubTitle extends StatelessWidget { class ASubTitle extends StatelessWidget {
final String text; final String text;
final EdgeInsets padding; final EdgeInsets? padding;
final Color color; final Color? color;
final double font; final double? font;
const ASubTitle(this.text, {Key key,this.padding, this.color, this.font}) : super(key: key);
const ASubTitle(this.text, {Key? key, this.padding, this.color, this.font})
: super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Padding( return Padding(
padding: padding ?? EdgeInsets.zero, padding: padding ?? EdgeInsets.zero,
child: Text( child: Text(
text, text,
style: Theme.of(context).textTheme.bodyText1.copyWith( style: Theme.of(context).textTheme.bodyLarge?.copyWith(
// fontWeight: FontWeight.bold, // fontWeight: FontWeight.bold,
fontSize: font, fontSize: font,
color: color color: color),
),
textScaleFactor: AppStyle.getScaleFactor(context), textScaleFactor: AppStyle.getScaleFactor(context),
), ),
); );

@ -1,22 +1,30 @@
import 'package:test_sa/views/app_style/sizing.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../../app_style/sizing.dart';
class ATitle extends StatelessWidget { class ATitle extends StatelessWidget {
final String text; final String text;
final EdgeInsets padding; final EdgeInsets? padding;
final bool center; final bool center;
const ATitle(this.text, {Key key,this.padding,this.center= false}) : super(key: key);
const ATitle(this.text, {Key? key, this.padding, this.center = false})
: super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Padding( return Padding(
padding: padding ?? EdgeInsets.symmetric(horizontal: 16,vertical: 8), padding: padding ??
const EdgeInsets.symmetric(
horizontal: 16,
vertical: 8,
),
child: Row( child: Row(
mainAxisAlignment: center mainAxisAlignment:
? MainAxisAlignment.center center ? MainAxisAlignment.center : MainAxisAlignment.start,
: MainAxisAlignment.start,
children: [ children: [
Text( Text(
text, text,
style: Theme.of(context).textTheme.headline6, style: Theme.of(context).textTheme.titleLarge,
textScaleFactor: AppStyle.getScaleFactor(context), textScaleFactor: AppStyle.getScaleFactor(context),
), ),
], ],

@ -1,24 +1,32 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:test_sa/views/app_style/sizing.dart';
import '../../app_style/sizing.dart';
class ExpandableInfoRow extends StatefulWidget { class ExpandableInfoRow extends StatefulWidget {
final IconData iconData; final IconData? iconData;
final String title; final String title;
final Widget child; final Widget child;
const ExpandableInfoRow({Key key, this.iconData, this.title, this.child}) : super(key: key); const ExpandableInfoRow({
Key? key,
this.iconData,
required this.title,
required this.child,
}) : super(key: key);
@override @override
_ExpandableInfoRowState createState() => _ExpandableInfoRowState(); ExpandableInfoRowState createState() => ExpandableInfoRowState();
} }
class _ExpandableInfoRowState extends State<ExpandableInfoRow> class ExpandableInfoRowState extends State<ExpandableInfoRow>
with TickerProviderStateMixin{ with TickerProviderStateMixin {
bool _isExpanded = false; bool _isExpanded = false;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return InkWell( return InkWell(
onTap: (){ onTap: () {
_isExpanded = !_isExpanded; _isExpanded = !_isExpanded;
setState(() {}); setState(() {});
}, },
@ -26,39 +34,37 @@ class _ExpandableInfoRowState extends State<ExpandableInfoRow>
children: [ children: [
Row( Row(
children: <Widget>[ children: <Widget>[
widget.iconData != null ? widget.iconData != null
Padding( ? Padding(
padding: EdgeInsets.symmetric( padding: EdgeInsets.symmetric(
horizontal: 8 * AppStyle.getScaleFactor(context), horizontal: 8 * AppStyle.getScaleFactor(context),
vertical: 2 * AppStyle.getScaleFactor(context), vertical: 2 * AppStyle.getScaleFactor(context),
), ),
child: FaIcon( child: FaIcon(
widget.iconData, widget.iconData,
color: Theme.of(context).primaryColor, color: Theme.of(context).primaryColor,
size: 20 * AppStyle.getScaleFactor(context), size: 20 * AppStyle.getScaleFactor(context),
), ),
):SizedBox.shrink(), )
: const SizedBox.shrink(),
Expanded( Expanded(
flex: 2, flex: 2,
child: Text( child: Text(
widget.title, widget.title,
style: TextStyle( style: const TextStyle(
//color: Theme.of(context).dividerColor, //color: Theme.of(context).dividerColor,
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
textScaleFactor: AppStyle.getScaleFactor(context), textScaleFactor: AppStyle.getScaleFactor(context),
), ),
), ),
AnimatedSwitcher( AnimatedSwitcher(
duration: Duration(milliseconds: 400), duration: const Duration(milliseconds: 400),
transitionBuilder: (Widget child, Animation<double> animation) { transitionBuilder: (Widget child, Animation<double> animation) {
return FadeTransition( return FadeTransition(
child: ScaleTransition(
child: child,
scale: animation
),
opacity: animation, opacity: animation,
child: ScaleTransition(scale: animation, child: child),
); );
}, },
child: Icon( child: Icon(
@ -75,17 +81,21 @@ class _ExpandableInfoRowState extends State<ExpandableInfoRow>
], ],
), ),
AnimatedSize( AnimatedSize(
duration: Duration(milliseconds: 300), duration: const Duration(milliseconds: 300),
child: Visibility( child: Visibility(
visible: _isExpanded, visible: _isExpanded,
child: Padding( child: Padding(
padding: EdgeInsets.symmetric(vertical: 8 * AppStyle.getScaleFactor(context)), padding: EdgeInsets.symmetric(
child: widget.child, vertical: 8 * AppStyle.getScaleFactor(context)),
) child: widget.child,
), )),
),
Divider(
height: 2 * AppStyle.getScaleFactor(context),
),
SizedBox(
height: 8 * AppStyle.getScaleFactor(context),
), ),
Divider(height: 2 * AppStyle.getScaleFactor(context),),
SizedBox(height: 8 * AppStyle.getScaleFactor(context),),
], ],
), ),
); );

@ -1,13 +1,12 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:test_sa/controllers/localization/localization.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart'; import '../../../controllers/localization/localization.dart';
import 'package:test_sa/models/enums/user_types.dart'; import '../../../controllers/providers/api/user_provider.dart';
import 'package:test_sa/models/subtitle.dart'; import '../../../models/enums/user_types.dart';
import 'package:test_sa/models/visits/visit.dart'; import '../../../models/visits/visit.dart';
import 'package:test_sa/views/app_style/sizing.dart'; import '../../app_style/sizing.dart';
import 'package:test_sa/views/widgets/visits/visit_status.dart'; import 'visit_status.dart';
class VisitItem extends StatelessWidget { class VisitItem extends StatelessWidget {
final Visit visit; final Visit visit;
@ -18,31 +17,47 @@ class VisitItem extends StatelessWidget {
final Function(Visit) onLongPress; final Function(Visit) onLongPress;
final Function(Visit) onSelect; final Function(Visit) onSelect;
const VisitItem({Key key, this.visit, this.onPressed, this.isSelected = false, this.activeSelectMod = false, this.onLongPress, this.onSelect, this.index}) : super(key: key); const VisitItem({
Key? key,
this.isSelected = false,
this.activeSelectMod = false,
required this.visit,
required this.onPressed,
required this.onLongPress,
required this.onSelect,
required this.index,
}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
UserProvider _userProvider = Provider.of<UserProvider>(context); UserProvider userProvider = Provider.of<UserProvider>(context);
Color itemColor = index % 2 == 0 ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.onPrimary; Color itemColor = index % 2 == 0
Color onItemColor = index % 2 != 0 ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.onPrimary; ? Theme.of(context).colorScheme.primary
Subtitle _subtitle = AppLocalization.of(context).subtitle; : Theme.of(context).colorScheme.onPrimary;
Color onItemColor = index % 2 != 0
? Theme.of(context).colorScheme.primary
: Theme.of(context).colorScheme.onPrimary;
final subtitle = AppLocalization.of(context)?.subtitle;
return Padding( return Padding(
padding: const EdgeInsets.symmetric(vertical: 4), padding: const EdgeInsets.symmetric(vertical: 4),
child: ElevatedButton( child: ElevatedButton(
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
padding: EdgeInsets.symmetric(vertical: 8, horizontal: 8), padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 8),
primary: itemColor, primary: itemColor,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppStyle.getBorderRadius(context)), borderRadius:
BorderRadius.circular(AppStyle.getBorderRadius(context)),
), ),
), ),
onPressed: () { onPressed: () {
if (activeSelectMod && _userProvider.user.type == UsersTypes.engineer) if (activeSelectMod &&
userProvider.user?.type == UsersTypes.engineer) {
onSelect(visit); onSelect(visit);
else } else {
onPressed(visit); onPressed(visit);
}
}, },
onLongPress: _userProvider.user.type == UsersTypes.engineer onLongPress: userProvider.user?.type == UsersTypes.engineer
? () { ? () {
onLongPress(visit); onLongPress(visit);
} }
@ -55,11 +70,14 @@ class VisitItem extends StatelessWidget {
Expanded( Expanded(
child: Text( child: Text(
"S.N: " + visit.deviceSerialNumber ?? "No serial number", "S.N: " + visit.deviceSerialNumber ?? "No serial number",
style: Theme.of(context).textTheme.headline6.copyWith(color: onItemColor, fontSize: 16, fontWeight: FontWeight.bold), style: Theme.of(context).textTheme.titleLarge?.copyWith(
color: onItemColor,
fontSize: 16,
fontWeight: FontWeight.bold),
), ),
), ),
AnimatedSwitcher( AnimatedSwitcher(
duration: Duration(milliseconds: 400), duration: const Duration(milliseconds: 400),
child: Visibility( child: Visibility(
key: ValueKey(activeSelectMod), key: ValueKey(activeSelectMod),
visible: activeSelectMod, visible: activeSelectMod,
@ -87,7 +105,7 @@ class VisitItem extends StatelessWidget {
Expanded( Expanded(
child: Text( child: Text(
visit.hospitalName ?? "No client found", visit.hospitalName ?? "No client found",
style: Theme.of(context).textTheme.subtitle1.copyWith( style: Theme.of(context).textTheme.titleMedium?.copyWith(
color: onItemColor, color: onItemColor,
fontSize: 14, fontSize: 14,
), ),
@ -97,7 +115,7 @@ class VisitItem extends StatelessWidget {
), ),
Text( Text(
visit.modelAndBrand ?? "", visit.modelAndBrand ?? "",
style: Theme.of(context).textTheme.subtitle1.copyWith( style: Theme.of(context).textTheme.titleMedium?.copyWith(
color: onItemColor, color: onItemColor,
fontSize: 14, fontSize: 14,
), ),
@ -110,12 +128,15 @@ class VisitItem extends StatelessWidget {
Expanded( Expanded(
child: Text( child: Text(
visit.employName ?? "No employ found", visit.employName ?? "No employ found",
style: Theme.of(context).textTheme.headline6.copyWith(color: onItemColor, fontSize: 14, fontWeight: FontWeight.bold), style: Theme.of(context).textTheme.titleLarge?.copyWith(
color: onItemColor,
fontSize: 14,
fontWeight: FontWeight.bold),
), ),
), ),
Text( Text(
visit.contactStatus ?? "", visit.contactStatus ?? "",
style: Theme.of(context).textTheme.subtitle1.copyWith( style: Theme.of(context).textTheme.titleMedium?.copyWith(
color: onItemColor, color: onItemColor,
fontSize: 14, fontSize: 14,
), ),
@ -132,15 +153,15 @@ class VisitItem extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
_subtitle.expectDate, subtitle?.expectDate ?? '',
style: Theme.of(context).textTheme.headline6.copyWith( style: Theme.of(context).textTheme.titleLarge?.copyWith(
color: onItemColor, color: onItemColor,
fontSize: 14, fontSize: 14,
), ),
), ),
Text( Text(
visit.expectDate ?? _subtitle.noDateFound, visit.expectDate ?? subtitle?.noDateFound ?? '',
style: Theme.of(context).textTheme.headline6.copyWith( style: Theme.of(context).textTheme.titleLarge?.copyWith(
color: onItemColor, color: onItemColor,
fontSize: 14, fontSize: 14,
), ),
@ -152,15 +173,15 @@ class VisitItem extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
_subtitle.actualDate, subtitle?.actualDate ?? '',
style: Theme.of(context).textTheme.headline6.copyWith( style: Theme.of(context).textTheme.titleLarge?.copyWith(
color: onItemColor, color: onItemColor,
fontSize: 14, fontSize: 14,
), ),
), ),
Text( Text(
visit.actualDate ?? _subtitle.noDateFound, visit.actualDate ?? subtitle?.noDateFound ?? '',
style: Theme.of(context).textTheme.headline6.copyWith( style: Theme.of(context).textTheme.titleLarge?.copyWith(
color: onItemColor, color: onItemColor,
fontSize: 14, fontSize: 14,
), ),

@ -1,44 +1,47 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:test_sa/models/visits/visit.dart';
import 'package:test_sa/views/app_style/colors.dart'; import '../../../models/visits/visit.dart';
import 'package:test_sa/views/app_style/sizing.dart'; import '../../app_style/colors.dart';
import '../../app_style/sizing.dart';
class VisitStatusLabel extends StatelessWidget { class VisitStatusLabel extends StatelessWidget {
final Visit visit; final Visit visit;
const VisitStatusLabel({Key key, this.visit}) : super(key: key); const VisitStatusLabel({Key? key, required this.visit}) : super(key: key);
Color getStatusColor(){ Color getStatusColor() {
switch(visit.status.id){ switch (visit.status.id) {
case 0: return AColors.green; case 0:
case 1: return AColors.grey; return AColors.green;
case 2: return AColors.grey; case 1:
default : return AColors.grey; return AColors.grey;
case 2:
return AColors.grey;
default:
return AColors.grey;
} }
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
padding: EdgeInsets.symmetric(vertical: 2,horizontal: 8), padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 8),
alignment: Alignment.center, alignment: Alignment.center,
decoration: BoxDecoration( decoration: BoxDecoration(
color: getStatusColor(), color: getStatusColor(),
borderRadius: BorderRadius.circular( borderRadius: BorderRadius.circular(AppStyle.getBorderRadius(context)),
AppStyle.getBorderRadius(context) boxShadow: const [AppStyle.boxShadow],
),
child: Text(
visit.status.label == null || visit.status.label.isEmpty
? "no status"
: visit.status.label,
style: Theme.of(context).textTheme.titleSmall?.copyWith(
color: getStatusColor().computeLuminance() > 0.5
? AColors.black
: Colors.white,
), ),
boxShadow: [ ),
AppStyle.boxShadow
]
),
child: Text(
visit.status.label == null
|| visit.status.label.isEmpty
? "no status" :visit.status.label,
style: Theme.of(context).textTheme.subtitle2.copyWith(
color: getStatusColor().computeLuminance() > 0.5
? AColors.black : Colors.white,
),
)
); );
} }
} }

@ -1,12 +1,14 @@
import 'package:test_sa/controllers/localization/localization.dart';
import 'package:test_sa/models/subtitle.dart';
import 'package:test_sa/models/visits/visit.dart';
import 'package:test_sa/views/app_style/sizing.dart';
import 'package:test_sa/views/pages/user/visits/visit_details.dart';
import 'package:test_sa/views/widgets/loaders/lazy_loading.dart';
import 'package:test_sa/views/widgets/loaders/no_item_found.dart';
import 'package:test_sa/views/widgets/visits/visit_item.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../../../controllers/localization/localization.dart';
import '../../../models/subtitle.dart';
import '../../../models/visits/visit.dart';
import '../../app_style/sizing.dart';
import '../../pages/user/visits/visit_details.dart';
import '../loaders/lazy_loading.dart';
import '../loaders/no_item_found.dart';
import 'visit_item.dart';
class VisitsList extends StatefulWidget { class VisitsList extends StatefulWidget {
final List<Visit> visits; final List<Visit> visits;
final bool nextPage; final bool nextPage;
@ -14,29 +16,31 @@ class VisitsList extends StatefulWidget {
final Function(List<Visit>) onEditGroup; final Function(List<Visit>) onEditGroup;
const VisitsList({ const VisitsList({
Key key, Key? key,
this.visits, required this.visits,
this.nextPage, required this.nextPage,
this.onLazyLoad, required this.onLazyLoad,
this.onEditGroup required this.onEditGroup,
}) : super(key: key); }) : super(key: key);
@override @override
_VisitsListState createState() => _VisitsListState(); VisitsListState createState() => VisitsListState();
} }
class _VisitsListState extends State<VisitsList> { class VisitsListState extends State<VisitsList> {
List<Visit> _selectedVisits = []; final List<Visit> _selectedVisits = [];
@override @override
void initState() { void initState() {
_selectedVisits.clear(); _selectedVisits.clear();
super.initState(); super.initState();
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Subtitle _subtitle = AppLocalization.of(context).subtitle; Subtitle? subtitle = AppLocalization.of(context)?.subtitle;
if(widget.visits.length == 0){ if (widget.visits.isEmpty) {
return NoItemFound(message: _subtitle.noVisitsFound,); return NoItemFound(message: subtitle?.noVisitsFound);
} }
return Stack( return Stack(
children: [ children: [
@ -44,34 +48,33 @@ class _VisitsListState extends State<VisitsList> {
nextPage: widget.nextPage, nextPage: widget.nextPage,
onLazyLoad: widget.onLazyLoad, onLazyLoad: widget.onLazyLoad,
child: ListView.builder( child: ListView.builder(
//physics: BouncingScrollPhysics(), //physics: BouncingScrollPhysics(),
itemCount: widget.visits.length, itemCount: widget.visits.length,
padding: EdgeInsets.symmetric(horizontal: 16,vertical: 8), padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
itemBuilder: (context,itemIndex){ itemBuilder: (context, itemIndex) {
Visit _visit = widget.visits[itemIndex]; Visit visit = widget.visits[itemIndex];
bool _isSelected = _selectedVisits.contains(_visit); bool isSelected = _selectedVisits.contains(visit);
return VisitItem( return VisitItem(
visit: _visit, visit: visit,
isSelected: _isSelected, isSelected: isSelected,
index: itemIndex, index: itemIndex,
activeSelectMod: _selectedVisits.isNotEmpty, activeSelectMod: _selectedVisits.isNotEmpty,
onPressed: (visit){ onPressed: (visit) {
Navigator.of(context).push( Navigator.of(context).push(MaterialPageRoute(
MaterialPageRoute( builder: (_) => VisitDetailsPage(
builder: (_)=> VisitDetailsPage(visit: visit,) visit: visit,
) )));
);
}, },
onSelect: (visit){ onSelect: (visit) {
if(_isSelected){ if (isSelected) {
_selectedVisits.remove(visit); _selectedVisits.remove(visit);
} else { } else {
_selectedVisits.add(visit); _selectedVisits.add(visit);
} }
setState(() {}); setState(() {});
}, },
onLongPress: (visit){ onLongPress: (visit) {
if(_isSelected){ if (isSelected) {
_selectedVisits.remove(visit); _selectedVisits.remove(visit);
} else { } else {
_selectedVisits.add(visit); _selectedVisits.add(visit);
@ -79,15 +82,14 @@ class _VisitsListState extends State<VisitsList> {
setState(() {}); setState(() {});
}, },
); );
} }),
),
), ),
Align( Align(
alignment: Alignment.bottomLeft, alignment: Alignment.bottomLeft,
child: Padding( child: Padding(
padding: EdgeInsets.all(8.0 * AppStyle.getScaleFactor(context)), padding: EdgeInsets.all(8.0 * AppStyle.getScaleFactor(context)),
child: AnimatedSwitcher( child: AnimatedSwitcher(
duration: Duration(milliseconds: 400), duration: const Duration(milliseconds: 400),
child: Visibility( child: Visibility(
key: ValueKey(_selectedVisits.isNotEmpty), key: ValueKey(_selectedVisits.isNotEmpty),
visible: _selectedVisits.isNotEmpty, visible: _selectedVisits.isNotEmpty,
@ -96,17 +98,17 @@ class _VisitsListState extends State<VisitsList> {
children: [ children: [
FloatingActionButton( FloatingActionButton(
heroTag: "cancel", heroTag: "cancel",
child: Icon(Icons.cancel), child: const Icon(Icons.cancel),
onPressed: (){ onPressed: () {
_selectedVisits.clear(); _selectedVisits.clear();
setState(() {}); setState(() {});
}, },
), ),
FloatingActionButton( FloatingActionButton(
heroTag: "edit", heroTag: "edit",
child: Icon(Icons.edit), child: const Icon(Icons.edit),
onPressed: (){ onPressed: () {
if(!widget.visits.contains(_selectedVisits.first)){ if (!widget.visits.contains(_selectedVisits.first)) {
_selectedVisits.clear(); _selectedVisits.clear();
setState(() {}); setState(() {});
return; return;

Loading…
Cancel
Save