- Creating Api Client Class and Loading Notifier Class [Fully Documented].

- Recoding Login & Register & Update Profile.
- Reformat the lib folder on Dart Format (200 char on each line).
merge-requests/11/head
zaid_daoud 3 years ago
parent 942fa0f0ba
commit 1ef45711af

@ -71,6 +71,7 @@ android {
signingConfig signingConfigs.release
}
}
namespace 'com.example.test_sa'
}
flutter {

@ -1,5 +1,4 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.test_sa">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.

@ -1,5 +1,4 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.test_sa">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.

@ -1,12 +1,12 @@
buildscript {
ext.kotlin_version = '1.6.10'
ext.kotlin_version = '1.6.21'
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.1.2'
classpath 'com.android.tools.build:gradle:7.4.2'
classpath 'com.google.gms:google-services:4.3.13'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}

@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip

@ -0,0 +1,233 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart';
import 'package:http/io_client.dart';
import '../exceptions/api_exception.dart';
typedef FactoryConstructor<U> = U Function(dynamic);
class APIError {
int? errorCode;
String? errorMessage;
APIError(this.errorCode, this.errorMessage);
Map<String, dynamic> toJson() => {'errorCode': errorCode, 'errorMessage': errorMessage};
@override
String toString() {
return jsonEncode(this);
}
}
APIException _throwAPIException(Response response) {
switch (response.statusCode) {
case 200:
APIError? apiError;
if (response.body.isNotEmpty) {
var jsonError = jsonDecode(response.body);
debugPrint(jsonError);
apiError = APIError(response.statusCode, jsonError[0]);
}
return APIException(APIException.BAD_REQUEST, error: apiError);
case 400:
APIError? apiError;
if (response.body.isNotEmpty) {
var jsonError = jsonDecode(response.body);
debugPrint("json error : $jsonError");
apiError = APIError(response.statusCode, jsonError[0]);
}
return APIException(APIException.BAD_REQUEST, error: apiError);
case 401:
return const APIException(APIException.UNAUTHORIZED);
case 403:
return const APIException(APIException.FORBIDDEN);
case 404:
return const APIException(APIException.NOT_FOUND);
case 500:
return const APIException(APIException.INTERNAL_SERVER_ERROR);
case 444:
var downloadUrl = response.headers["location"];
return APIException(APIException.UPGRADE_REQUIRED, arguments: downloadUrl);
default:
return const APIException(APIException.OTHER);
}
}
class ApiClient {
static final ApiClient _instance = ApiClient._internal();
ApiClient._internal();
factory ApiClient() => _instance;
Future<U> postJsonForObject<T, U>(FactoryConstructor<U> factoryConstructor, String url, T jsonObject,
{String? token, Map<String, dynamic>? queryParameters, Map<String, String>? headers, int retryTimes = 0, bool isFormData = false}) async {
var defaultHeaders = {'Accept': 'application/json'};
if (headers != null && headers.isNotEmpty) {
defaultHeaders.addAll(headers);
}
if (!kReleaseMode) {
debugPrint("Url:$url");
var bodyJson = json.encode(jsonObject);
debugPrint("body:$bodyJson");
}
var response = await postJsonForResponse(url, jsonObject, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes, isFormData: isFormData);
try {
var jsonData = jsonDecode(response.body);
if (jsonData != null) {
debugPrint(jsonData.runtimeType.toString());
return factoryConstructor(jsonData);
} else {
APIError? apiError;
apiError = APIError(response.statusCode, jsonData[0]);
throw APIException(APIException.BAD_REQUEST, error: apiError);
}
} catch (ex) {
if (ex is APIException) {
rethrow;
} else {
throw APIException(APIException.BAD_RESPONSE_FORMAT, arguments: ex);
}
}
}
Future<Response> postJsonForResponse<T>(String url, T jsonObject,
{String? token, Map<String, dynamic>? queryParameters, Map<String, String>? headers, int retryTimes = 0, bool isFormData = false}) async {
int currentRetryTime = retryTimes;
String? requestBody;
late Map<String, String> stringObj;
if (jsonObject != null) {
requestBody = jsonEncode(jsonObject);
if (headers == null) {
headers = {'Content-Type': 'application/json'};
} else {
headers['Content-Type'] = 'application/json';
}
}
if (isFormData) {
headers = {'Content-Type': 'application/x-www-form-urlencoded'};
stringObj = ((jsonObject ?? {}) as Map<String, dynamic>).map((key, value) => MapEntry(key, value?.toString() ?? ""));
}
Future<Response> retry(APIException exception) async {
if (currentRetryTime > 0) {
currentRetryTime -= 1;
debugPrint('will retry after 3 seconds...');
await Future.delayed(const Duration(seconds: 3));
return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers);
} else {
throw exception;
}
}
try {
return await _postForResponse(url, isFormData ? stringObj : requestBody, token: token, queryParameters: queryParameters, headers: headers);
} on SocketException catch (e) {
return await retry(APIException(APIException.OTHER, arguments: e));
} on HttpException catch (e) {
return await retry(APIException(APIException.OTHER, arguments: e));
} on TimeoutException catch (e) {
throw APIException(APIException.TIMEOUT, arguments: e);
} on ClientException catch (e) {
return await retry(APIException(APIException.OTHER, arguments: e));
}
}
Future<Response> _postForResponse(String url, requestBody, {String? token, Map<String, dynamic>? queryParameters, Map<String, String>? headers}) async {
var defaultHeaders = <String, String>{};
if (token != null) {
defaultHeaders['Authorization'] = 'Bearer $token';
}
if (headers != null && headers.isNotEmpty) {
defaultHeaders.addAll(headers);
}
if (queryParameters != null) {
var queryString = Uri(queryParameters: queryParameters).query;
url = '$url?$queryString';
}
var response = await _post(Uri.parse(url), body: requestBody, headers: defaultHeaders).timeout(const Duration(seconds: 120));
if (response.statusCode >= 200 && response.statusCode < 300) {
return response;
} else {
throw _throwAPIException(response);
}
}
Future<Response> getJsonForResponse<T>(String url, {String? token, Map<String, dynamic>? queryParameters, Map<String, String>? headers, int retryTimes = 0}) async {
int currentRetryTime = retryTimes;
if (headers == null) {
headers = {'Content-Type': 'application/json'};
} else {
headers['Content-Type'] = 'application/json';
}
Future<Response> retry(APIException exception) async {
if (currentRetryTime > 0) {
currentRetryTime -= 1;
debugPrint('will retry after 3 seconds...');
await Future.delayed(const Duration(seconds: 3));
return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers);
} else {
throw exception;
}
}
try {
return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers);
} on SocketException catch (e) {
return await retry(APIException(APIException.OTHER, arguments: e));
} on HttpException catch (e) {
return await retry(APIException(APIException.OTHER, arguments: e));
} on TimeoutException catch (e) {
throw APIException(APIException.TIMEOUT, arguments: e);
} on ClientException catch (e) {
return await retry(APIException(APIException.OTHER, arguments: e));
}
}
Future<Response> _getForResponse(String url, {String? token, Map<String, dynamic>? queryParameters, Map<String, String>? headers}) async {
var defaultHeaders = <String, String>{};
if (token != null) {
defaultHeaders['Authorization'] = 'Bearer $token';
}
if (headers != null && headers.isNotEmpty) {
defaultHeaders.addAll(headers);
}
if (queryParameters != null) {
var queryString = Uri(queryParameters: queryParameters).query;
url = '$url?$queryString';
}
var response = await _get(Uri.parse(url), headers: defaultHeaders).timeout(const Duration(seconds: 60));
if (response.statusCode >= 200 && response.statusCode < 300) {
return response;
} else {
throw _throwAPIException(response);
}
}
Future<Response> _get(url, {Map<String, String>? headers}) => _withClient((client) => client.get(url, headers: headers));
bool _certificateCheck(X509Certificate cert, String host, int port) => true;
Future<T> _withClient<T>(Future<T> Function(Client) fn) async {
var httpClient = HttpClient()..badCertificateCallback = _certificateCheck;
var client = IOClient(httpClient);
try {
return await fn(client);
} finally {
client.close();
}
}
Future<Response> _post(url, {Map<String, String>? headers, body, Encoding? encoding}) => _withClient((client) => client.post(url, headers: headers, body: body, encoding: encoding));
}

@ -0,0 +1,81 @@
import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/models/user.dart';
import 'api_client.dart';
class UserApiClient {
static final UserApiClient _instance = UserApiClient._internal();
/// ### This instance will be [NULL] until the login or registration process completed successfully by calling [login] or [register] functions
User? user;
UserApiClient._internal();
factory UserApiClient() => _instance;
/// - [user] object have to contains username & password
/// - If the request completed successfully the [UserApiClient.user] object inside [UserApiClient] class won't be null and will contains the data comes from the response.
/// - Returns exception of type [APIException] if any error happened.
///
///#### lib\client\login_api_client.dart
Future login({required User user}) async {
return await ApiClient().postJsonForObject(
(json) {
this.user = User.fromJson(json[0]);
},
"${URLs.host1}${URLs.login}",
await user.toLoginJson(), //body
isFormData: true,
);
}
/// - [newUser] object have to contains the new user data [email, phone, ...]
/// - If the request completed successfully the [user] object inside [UserApiClient] class won't be null and will contains the data comes from the response.
/// - Returns exception of type [APIException] if any error happened.
///
///#### lib\client\login_api_client.dart
Future register({required User newUser}) async {
return await ApiClient().postJsonForObject(
(json) {
user = User.fromJson(json);
},
"${URLs.host1}${URLs.register}",
await newUser.toRegisterJson(), //body
);
}
/// [updatedUser] have to contains the new data for the current user
/// - If the request completed successfully the [user] object inside [UserApiClient] class won't be null and will contains the data comes from the response.
/// - Returns exception of type [APIException] if any error happened.
///
///#### lib\client\login_api_client.dart
Future updateProfile({required User updatedUser}) async {
return await ApiClient().postJsonForObject(
(json) {
user = User.fromJson(json);
},
"${URLs.host1}${URLs.updateProfile}",
updatedUser.toUpdateProfileJson(), //body
);
// Map<String, dynamic> jsonObject = {};
// jsonObject["uid"] = user.id;
// jsonObject["token"] = user.token;
// if (user.department?.id != user.department?.id) {
// jsonObject["department"] = user.department?.id;
// }
// if (user.whatsApp != user.whatsApp) {
// jsonObject["whatsapp"] = user.whatsApp;
// }
// if (user.phoneNumber != user.phoneNumber) {
// jsonObject["phone"] = user.phoneNumber;
// }
// final response = await ApiClient().postJsonForResponse(URLs.updateProfile, jsonObject);
//
// if (response.statusCode >= 200 && response.statusCode < 300) {
// // client's request was successfully received
// this.user = User.fromJson(jsonDecode(utf8.decode(response.bodyBytes))[0]);
// this.user?.hospital = user.hospital;
// this.user?.department = user.department;
// }
}
}

@ -1,4 +1,4 @@
class URLs{
class URLs {
URLs._();
static const host2 = "http://194.163.164.213/atoms/api";
static const host1 = "https://atoms.hmg.com/api";
@ -31,7 +31,7 @@ class URLs{
static const getServiceReport = "/handle/view/service/report"; // get
static const createDuplicatedReport = "/handle/duplicate/request"; // get
static const getServiceReportReasons = "/return/service/report/reasons"; // get
static const getServiceReportReasons = "/return/service/report/reasons"; // get
static const getServiceReportTypes = "/return/service/report/type"; // get
static const getServiceReportStatus = "/return/service/report/status"; // get
static const getServiceReportLastCalls = "/return/call/last/situation"; // get
@ -63,5 +63,4 @@ class URLs{
static const getPentryStatus = "/return/pentry/status/list"; // get
// contacts
static const getPentryContacts = "/handle/return/all/contacts"; // get
}
}

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

@ -5,8 +5,6 @@ import 'package:flutter/services.dart';
import '../../models/subtitle.dart';
class AppLocalization {
AppLocalization(this.locale);
@ -21,18 +19,15 @@ class AppLocalization {
Subtitle? get subtitle => _subtitle;
Future<void> load() async {
String jsonStringValues = await rootBundle
.loadString('assets/subtitles/${locale.languageCode}_subtitle.json');
String jsonStringValues = await rootBundle.loadString('assets/subtitles/${locale.languageCode}_subtitle.json');
_subtitle = Subtitle.fromJson(json.decode(jsonStringValues));
}
// static member to have simple access to the delegate from Material App
static const LocalizationsDelegate<AppLocalization> delegate =
_DemoLocalizationsDelegate();
static const LocalizationsDelegate<AppLocalization> delegate = _DemoLocalizationsDelegate();
}
class _DemoLocalizationsDelegate
extends LocalizationsDelegate<AppLocalization> {
class _DemoLocalizationsDelegate extends LocalizationsDelegate<AppLocalization> {
const _DemoLocalizationsDelegate();
@override

@ -57,7 +57,7 @@ class FirebaseNotificationManger {
AppNotification notification = AppNotification.fromJson(message.data);
Navigator.pushNamed(
context,
notification.path??"",
notification.path ?? "",
arguments: notification.requestId,
);
});
@ -67,7 +67,7 @@ class FirebaseNotificationManger {
NotificationManger.showNotification(
title: message.notification?.title,
subtext: message.notification?.body,
hashcode: int.tryParse(notification.requestId??"0") ?? 1,
hashcode: int.tryParse(notification.requestId ?? "0") ?? 1,
payload: json.encode(message.data),
);
return;

@ -6,35 +6,24 @@ class NotificationManger {
// private constructor to avoid create object
NotificationManger._();
static FlutterLocalNotificationsPlugin localNotificationsPlugin =
FlutterLocalNotificationsPlugin();
static FlutterLocalNotificationsPlugin localNotificationsPlugin = FlutterLocalNotificationsPlugin();
/// initialisation setting for all platform
/// onNotificationPressed action when notification pressed to open tap
/// onIOSNotificationPressed action when notification pressed
/// to open tap in iOS versions older than 10
static initialisation(Function(NotificationResponse) onNotificationPressed,
DidReceiveLocalNotificationCallback onIOSNotificationPressed) async {
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
static initialisation(Function(NotificationResponse) onNotificationPressed, DidReceiveLocalNotificationCallback onIOSNotificationPressed) async {
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
// initialise the plugin. app_icon needs to be a added as a drawable resource to the Android head project
const AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings(
const AndroidInitializationSettings initializationSettingsAndroid = AndroidInitializationSettings(
'app_icon',
);
final DarwinInitializationSettings initializationSettingsDarwin =
DarwinInitializationSettings(
onDidReceiveLocalNotification: onIOSNotificationPressed);
final DarwinInitializationSettings initializationSettingsDarwin = DarwinInitializationSettings(onDidReceiveLocalNotification: onIOSNotificationPressed);
final InitializationSettings initializationSettings =
InitializationSettings(
android: initializationSettingsAndroid,
iOS: initializationSettingsDarwin,
macOS: initializationSettingsDarwin);
final InitializationSettings initializationSettings = InitializationSettings(android: initializationSettingsAndroid, iOS: initializationSettingsDarwin, macOS: initializationSettingsDarwin);
await flutterLocalNotificationsPlugin.initialize(initializationSettings,
onDidReceiveNotificationResponse: onNotificationPressed);
await flutterLocalNotificationsPlugin.initialize(initializationSettings, onDidReceiveNotificationResponse: onNotificationPressed);
}
// push new notification
@ -44,8 +33,7 @@ class NotificationManger {
required int hashcode,
String? payload,
}) async {
const AndroidNotificationDetails androidChannel =
AndroidNotificationDetails(
const AndroidNotificationDetails androidChannel = AndroidNotificationDetails(
'com.newtrack.testsa',
'Test SA',
channelDescription: 'Push notification service for Test SA',
@ -62,8 +50,7 @@ class NotificationManger {
groupKey: 'com.newtrack.testsa',
);
const DarwinNotificationDetails iosNotificationDetails =
DarwinNotificationDetails(
const DarwinNotificationDetails iosNotificationDetails = DarwinNotificationDetails(
categoryIdentifier: "testSA",
);

@ -53,11 +53,8 @@ class DepartmentsProvider extends ChangeNotifier {
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
List listJson =
json.decode(utf8.decode(response.bodyBytes).replaceAll("\\", ""));
departments = listJson
.map((department) => Department.fromJson(department))
.toList();
List listJson = json.decode(utf8.decode(response.bodyBytes).replaceAll("\\", ""));
departments = listJson.map((department) => Department.fromJson(department)).toList();
}
isLoading = false;
notifyListeners();

@ -28,7 +28,7 @@ class DeviceTransferProvider extends ChangeNotifier {
bool? nextPage = true;
// list of user requests
List<DeviceTransfer> items=[];
List<DeviceTransfer> items = [];
// when requests in-process _loading = true
// done _loading = true
@ -72,12 +72,9 @@ class DeviceTransferProvider extends ChangeNotifier {
stateCode = response.statusCode;
if (stateCode != null && stateCode! >= 200 && stateCode! < 300) {
// client's request was successfully received
List listJson =
json.decode(utf8.decode(response.bodyBytes).replaceAll("\\", ""));
List listJson = json.decode(utf8.decode(response.bodyBytes).replaceAll("\\", ""));
print(listJson);
List<DeviceTransfer> itemsPage = listJson
.map((request) => DeviceTransfer.fromJson(request))
.toList();
List<DeviceTransfer> itemsPage = listJson.map((request) => DeviceTransfer.fromJson(request)).toList();
print(itemsPage.length);
items.clear();
items.addAll(itemsPage);
@ -121,10 +118,7 @@ class DeviceTransferProvider extends ChangeNotifier {
if (response.statusCode >= 200 && response.statusCode < 300) {
final items = this.items;
if (items != null) {
items.insert(
0,
DeviceTransfer.fromJson(
json.decode(utf8.decode(response.bodyBytes))[0]));
items.insert(0, DeviceTransfer.fromJson(json.decode(utf8.decode(response.bodyBytes))[0]));
notifyListeners();
}
}

@ -57,9 +57,7 @@ class GasRefillProvider extends ChangeNotifier {
if (stateCode != null && stateCode! >= 200 && stateCode! < 300) {
// client's request was successfully received
List requestsListJson = json.decode(utf8.decode(response.bodyBytes));
List<GasRefillModel> itemsPage = requestsListJson
.map((request) => GasRefillModel.fromJson(request))
.toList();
List<GasRefillModel> itemsPage = requestsListJson.map((request) => GasRefillModel.fromJson(request)).toList();
items ??= [];
items?.addAll(itemsPage);
if (itemsPage.length == pageItemNumber) {
@ -110,10 +108,7 @@ class GasRefillProvider extends ChangeNotifier {
if (response.statusCode >= 200 && response.statusCode < 300) {
final items = this.items;
if (items != null) {
items.insert(
0,
GasRefillModel.fromJson(
json.decode(utf8.decode(response.bodyBytes))[0]));
items.insert(0, GasRefillModel.fromJson(json.decode(utf8.decode(response.bodyBytes))[0]));
notifyListeners();
}
}

@ -75,9 +75,7 @@ class HospitalsProvider extends ChangeNotifier {
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
List categoriesListJson = json.decode(utf8.decode(response.bodyBytes));
List<Hospital> page = categoriesListJson
.map((category) => Hospital.fromJson(category))
.toList();
List<Hospital> page = categoriesListJson.map((category) => Hospital.fromJson(category)).toList();
if (hospitals == null) _hospitals = [];
_hospitals?.addAll(page);
@ -117,9 +115,7 @@ class HospitalsProvider extends ChangeNotifier {
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
List categoriesListJson = json.decode(utf8.decode(response.bodyBytes));
page = categoriesListJson
.map((category) => Hospital.fromJson(category))
.toList();
page = categoriesListJson.map((category) => Hospital.fromJson(category)).toList();
}
return page;
} catch (error) {

@ -61,9 +61,7 @@ class NotificationsProvider extends ChangeNotifier {
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
List requestsListJson = json.decode(utf8.decode(response.bodyBytes));
List<AppNotification> serviceRequestsPage = requestsListJson
.map((request) => AppNotification.fromJson(request))
.toList();
List<AppNotification> serviceRequestsPage = requestsListJson.map((request) => AppNotification.fromJson(request)).toList();
notifications.addAll(serviceRequestsPage);
if (serviceRequestsPage.length == pageItemNumber) {
nextPage = true;
@ -95,18 +93,13 @@ class NotificationsProvider extends ChangeNotifier {
//userId = 397.toString(); // testing id to view data
try {
response = await get(
Uri.parse(
"$host${URLs.getNotifications}?uid=${user.id}&token=${user.token}"),
headers: {"Content-Type": "application/json; charset=utf-8"});
response = await get(Uri.parse("$host${URLs.getNotifications}?uid=${user.id}&token=${user.token}"), headers: {"Content-Type": "application/json; charset=utf-8"});
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
List requestsListJson = json.decode(utf8.decode(response.bodyBytes));
List<AppNotification> recentNotifications = requestsListJson
.map((request) => AppNotification.fromJson(request))
.toList();
List<AppNotification> recentNotifications = requestsListJson.map((request) => AppNotification.fromJson(request)).toList();
return recentNotifications;
}
return null;

@ -73,8 +73,7 @@ class PartsProvider extends ChangeNotifier {
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
List categoriesListJson = json.decode(utf8.decode(response.bodyBytes));
List<Part> page =
categoriesListJson.map((part) => Part.fromJson(part)).toList();
List<Part> page = categoriesListJson.map((part) => Part.fromJson(part)).toList();
if (parts == null) _parts = [];
_parts?.addAll(page);
@ -107,11 +106,7 @@ class PartsProvider extends ChangeNotifier {
}) async {
Response response;
try {
response = await get(
Uri.parse(host +
URLs.getPartNumber +
(title == null || title.isEmpty ? "" : "?name=$title")),
headers: {"Content-Type": "application/json; charset=utf-8"});
response = await get(Uri.parse(host + URLs.getPartNumber + (title == null || title.isEmpty ? "" : "?name=$title")), headers: {"Content-Type": "application/json; charset=utf-8"});
List<Part> page = [];
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received

@ -69,8 +69,7 @@ class PreventiveMaintenanceVisitsProvider extends ChangeNotifier {
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
List requestsListJson = json.decode(utf8.decode(response.bodyBytes));
List<Visit> visits =
requestsListJson.map((request) => Visit.fromJson(request)).toList();
List<Visit> visits = requestsListJson.map((request) => Visit.fromJson(request)).toList();
visits.addAll(visits);
if (visits.length == pageItemNumber) {
nextPage = true;
@ -95,8 +94,8 @@ class PreventiveMaintenanceVisitsProvider extends ChangeNotifier {
}) async {
Response response;
Map<String, String> body = group.toJson();
body["token"] = user.token??"";
body["uid"] = user.id??"";
body["token"] = user.token ?? "";
body["uid"] = user.id ?? "";
//userId = 397.toString(); // testing id to view data
try {
response = await post(
@ -107,7 +106,7 @@ class PreventiveMaintenanceVisitsProvider extends ChangeNotifier {
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
for (var visit in (group.visits??[])) {
for (var visit in (group.visits ?? [])) {
visit.status = group.status;
visit.actualDate = group.date.toString().split(" ").first;
}

@ -68,11 +68,8 @@ class ServiceRequestsProvider extends ChangeNotifier {
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
List requestsListJson =
json.decode(utf8.decode(response.bodyBytes).replaceAll("\\", ""));
List<ServiceRequest> _serviceRequestsPage = requestsListJson
.map((request) => ServiceRequest.fromJson(request))
.toList();
List requestsListJson = json.decode(utf8.decode(response.bodyBytes).replaceAll("\\", ""));
List<ServiceRequest> _serviceRequestsPage = requestsListJson.map((request) => ServiceRequest.fromJson(request)).toList();
serviceRequests ??= [];
serviceRequests?.addAll(_serviceRequestsPage);
if (_serviceRequestsPage.length == pageItemNumber) {
@ -108,23 +105,17 @@ class ServiceRequestsProvider extends ChangeNotifier {
'$host${URLs.getSingleServiceRequest}?call_nid=$requestId$userData',
));
} 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 (response.statusCode >= 200 && response.statusCode < 300) {
// If the call to the server was successful, parse the JSON.
List jsonList =
json.decode(utf8.decode(response.bodyBytes).replaceAll("\\", ""));
List<ServiceRequest> requests =
jsonList.map((i) => ServiceRequest.fromJson(i)).toList();
List jsonList = json.decode(utf8.decode(response.bodyBytes).replaceAll("\\", ""));
List<ServiceRequest> requests = jsonList.map((i) => ServiceRequest.fromJson(i)).toList();
return requests[0];
} else {
throw (HttpStatusManger.getStatusMessage(
status: response.statusCode, subtitle: subtitle) ??
"");
throw (HttpStatusManger.getStatusMessage(status: response.statusCode, subtitle: subtitle) ?? "");
}
}
@ -320,12 +311,9 @@ class ServiceRequestsProvider extends ChangeNotifier {
body["uid"] = user.id ?? "";
body["token"] = user.token ?? "";
body["job_id"] = request.id ?? '';
body["start_time"] = ((timer.startAt?.millisecondsSinceEpoch ?? 0) / 1000)
.toStringAsFixed(0);
body["end_time"] =
((timer.endAt?.millisecondsSinceEpoch ?? 0) / 1000).toStringAsFixed(0);
body["working_hours"] =
((timer.durationInSecond ?? 0) / 60 / 60).toStringAsFixed(5);
body["start_time"] = ((timer.startAt?.millisecondsSinceEpoch ?? 0) / 1000).toStringAsFixed(0);
body["end_time"] = ((timer.endAt?.millisecondsSinceEpoch ?? 0) / 1000).toStringAsFixed(0);
body["working_hours"] = ((timer.durationInSecond ?? 0) / 60 / 60).toStringAsFixed(5);
body["report_id"] = request.reportID ?? '';
try {
response = await post(
@ -360,16 +348,13 @@ class ServiceRequestsProvider extends ChangeNotifier {
'$host${URLs.getServiceReport}?report_id=$reportId$userData',
));
} 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 (response.statusCode >= 200 && response.statusCode < 300) {
// If the call to the server was successful, parse the JSON.
return ServiceReport.fromJson(
json.decode(utf8.decode(response.bodyBytes)), reportId);
return ServiceReport.fromJson(json.decode(utf8.decode(response.bodyBytes)), reportId);
} else {
throw (HttpStatusManger.getStatusMessage(
status: response.statusCode,

@ -58,8 +58,7 @@ class EmployeesProvider extends ChangeNotifier {
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
List categoriesListJson = json.decode(utf8.decode(response.bodyBytes));
_items =
categoriesListJson.map((type) => Lookup.fromJson(type)).toList();
_items = categoriesListJson.map((type) => Lookup.fromJson(type)).toList();
}
_loading = false;
notifyListeners();

@ -64,8 +64,7 @@ class GasCylinderSizesProvider extends ChangeNotifier {
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
List categoriesListJson = json.decode(utf8.decode(response.bodyBytes));
_items =
categoriesListJson.map((item) => Lookup.fromJson(item)).toList();
_items = categoriesListJson.map((item) => Lookup.fromJson(item)).toList();
}
_loading = false;
notifyListeners();

@ -57,8 +57,7 @@ class GasStatusProvider extends ChangeNotifier {
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
List categoriesListJson = json.decode(utf8.decode(response.bodyBytes));
_items =
categoriesListJson.map((item) => Lookup.fromJson(item)).toList();
_items = categoriesListJson.map((item) => Lookup.fromJson(item)).toList();
}
_loading = false;
notifyListeners();

@ -57,8 +57,7 @@ class GasTypesProvider extends ChangeNotifier {
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
List categoriesListJson = json.decode(utf8.decode(response.bodyBytes));
_items =
categoriesListJson.map((item) => Lookup.fromJson(item)).toList();
_items = categoriesListJson.map((item) => Lookup.fromJson(item)).toList();
}
_loading = false;
notifyListeners();

@ -59,9 +59,7 @@ class PentryTaskStatusProvider extends ChangeNotifier {
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
List categoriesListJson = json.decode(utf8.decode(response.bodyBytes));
_items = categoriesListJson
.map((type) => Lookup.fromIntIdJson(type))
.toList();
_items = categoriesListJson.map((type) => Lookup.fromIntIdJson(type)).toList();
}
_loading = false;
notifyListeners();

@ -58,18 +58,14 @@ class ServiceReportLastCallsProvider extends ChangeNotifier {
try {
response = await get(
Uri.parse(
(host ?? '') +
URLs.getServiceReportLastCalls +
(serviceStatus == null ? "" : "?service_status=$serviceStatus"),
(host ?? '') + URLs.getServiceReportLastCalls + (serviceStatus == null ? "" : "?service_status=$serviceStatus"),
),
);
_stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
List categoriesListJson = json.decode(utf8.decode(response.bodyBytes));
_calls = categoriesListJson
.map((type) => Lookup.fromIntIdJson(type))
.toList();
_calls = categoriesListJson.map((type) => Lookup.fromIntIdJson(type)).toList();
}
_loading = false;
notifyListeners();

@ -58,9 +58,7 @@ class ServiceReportReasonsProvider extends ChangeNotifier {
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
List categoriesListJson = json.decode(utf8.decode(response.bodyBytes));
_reasons = categoriesListJson
.map((type) => Lookup.fromIntIdJson(type))
.toList();
_reasons = categoriesListJson.map((type) => Lookup.fromIntIdJson(type)).toList();
}
_loading = false;
notifyListeners();

@ -58,9 +58,7 @@ class ServiceReportStatusProvider extends ChangeNotifier {
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
List categoriesListJson = json.decode(utf8.decode(response.bodyBytes));
_status = categoriesListJson
.map((type) => Lookup.fromIntIdJson(type))
.toList();
_status = categoriesListJson.map((type) => Lookup.fromIntIdJson(type)).toList();
}
_loading = false;
notifyListeners();

@ -58,9 +58,7 @@ class ServiceReportTypesProvider extends ChangeNotifier {
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
List categoriesListJson = json.decode(utf8.decode(response.bodyBytes));
_types = categoriesListJson
.map((type) => Lookup.fromIntIdJson(type))
.toList();
_types = categoriesListJson.map((type) => Lookup.fromIntIdJson(type)).toList();
}
_loading = false;
notifyListeners();

@ -58,8 +58,7 @@ class ServiceStatusProvider extends ChangeNotifier {
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
List categoriesListJson = json.decode(utf8.decode(response.bodyBytes));
_statuses =
categoriesListJson.map((e) => Lookup.fromIntIdJson(e)).toList();
_statuses = categoriesListJson.map((e) => Lookup.fromIntIdJson(e)).toList();
}
_loading = false;
notifyListeners();

@ -1,162 +0,0 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart';
import '../../../models/user.dart';
import '../../api_routes/urls.dart';
class UserProvider extends ChangeNotifier {
//reset provider data
void reset() {
_user = null;
_loading = false;
}
// contain user data
// when user not login or register _user = null
User? _user;
User? get user => _user;
set user(User? user) {
_user = user;
notifyListeners();
}
// when login or register in-process _login = true
// when login or register is done or not start = false
bool _loading = false;
bool get isLoading => _loading;
set isLoading(bool isLoading) {
_loading = isLoading;
notifyListeners();
}
/// sign in with user - need (email or phone) and password;
/// return -2 if request in progress
/// return -1 if error happen when sending request
/// return state code if request complete may be 200, 404 or 403
/// for more details check http state manager
/// lib\controllers\http_status_manger\http_status_manger.dart
Future<int> login({
required String host,
required User user,
}) async {
if (_loading == true) {
return -2;
}
_loading = true;
notifyListeners();
Response response;
try {
response = await post(
Uri.parse(host + URLs.login),
body: await user.toLoginJson(),
);
_loading = false;
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
_user = User.fromJson(jsonDecode(utf8.decode(response.bodyBytes))[0]);
return response.statusCode;
}
notifyListeners();
return response.statusCode;
} catch (error) {
_loading = false;
notifyListeners();
return -1;
}
}
/// sign up with User object;
/// return -2 if request in progress
/// return -1 if error happen when sending request
/// return state code if request complete may be 200, 404 or 403
/// for more details about state codes check http state manager
/// lib\controllers\http_status_manger\http_status_manger.dart
Future<int> register({
required String host,
required User user,
}) async {
if (_loading == true) {
return -2;
}
_loading = true;
notifyListeners();
Response response;
try {
response = await post(Uri.parse(host + URLs.register),
body: await user.toRegisterJson());
} catch (error) {
_loading = false;
notifyListeners();
return -1;
}
_loading = false;
notifyListeners();
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
_user = User.fromJson(jsonDecode(utf8.decode(response.bodyBytes))[0]);
_user?.hospital = user.hospital;
notifyListeners();
return response.statusCode;
}
return response.statusCode;
}
/// sign up with User object;
/// return -2 if request in progress
/// return -1 if error happen when sending request
/// return state code if request complete may be 200, 404 or 403
/// for more details about state codes check http state manager
/// lib\controllers\http_status_manger\http_status_manger.dart
Future<int> updateProfile({
required String host,
required User user,
}) async {
if (_loading == true) {
return -2;
}
_loading = true;
notifyListeners();
Response response;
Map<String, dynamic> jsonObject = {};
jsonObject["uid"] = user.id;
jsonObject["token"] = user.token;
if (user.department?.id != _user?.department?.id) {
jsonObject["department"] = user.department?.id;
}
if (user.whatsApp != _user?.whatsApp) {
jsonObject["whatsapp"] = user.whatsApp;
}
if (user.phoneNumber != _user?.phoneNumber) {
jsonObject["phone"] = user.phoneNumber;
}
try {
response =
await post(Uri.parse(host + URLs.updateProfile), body: jsonObject);
} catch (error) {
_loading = false;
notifyListeners();
return -1;
}
_loading = false;
notifyListeners();
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
_user = User.fromJson(jsonDecode(utf8.decode(response.bodyBytes))[0]);
_user?.hospital = user.hospital;
_user?.department = user.department;
notifyListeners();
return response.statusCode;
}
return response.statusCode;
}
}

@ -0,0 +1,45 @@
import 'package:flutter/material.dart';
import '../../exceptions/api_exception.dart';
/// ## Change Notifier Class To Handle The State While Waiting The Futures Value
class LoadingNotifier with ChangeNotifier {
bool _loading = false;
/// - Returns [TRUE] if [waitApiResult] function called
/// - Returns [FALSE] if [waitApiResult] function completed in both states (failed, succeed)
bool get loading => _loading;
/// - [fun] : Callback function that contains the API request.
/// - [onError] : Optional callback function to handle the request on failure with [APIException] parameter.
/// - [onSuccess] : Optional callback function to handle the request on succeed.
void waitApiRequest(Function fun, {Function(APIException)? onError, Function? onSuccess}) async {
if (_loading == true) {
debugPrint('loading_notifier.dart : another action already started');
return;
}
_loading = true;
debugPrint('loading_notifier.dart : start loading');
notifyListeners();
try {
await fun();
if (onSuccess != null) {
await onSuccess();
}
} on APIException catch (error) {
debugPrint("loading_notifier.dart : [_waitResult] returns this message ${error.message} : ${error.arguments}");
if (onError != null) {
await onError(error);
}
} finally {
stopLoading();
debugPrint('loading_notifier.dart : stop loading');
}
}
/// ## Stop loading and Notify listeners
void stopLoading() {
_loading = false;
notifyListeners();
}
}

@ -3,4 +3,4 @@ class ASettings {
static final String host = "host";
static final String language = "language";
static final String speechToText = "speech_to_text";
}
}

@ -0,0 +1,103 @@
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/api/login_api_client.dart';
import '../../models/user.dart';
import '../../views/pages/user/land_page.dart';
import '../http_status_manger/http_status_manger.dart';
import '../localization/localization.dart';
import 'loading_notifier.dart';
import 'settings/setting_provider.dart';
class UserProvider extends LoadingNotifier {
/// - [user] data will be null
/// - loading process will stop
void reset() {
UserApiClient().user = null;
stopLoading();
}
/// ## Login & Fill [UserApiClient.user] data
/// - onSuccess and user is Active : push to [LandPage]
/// - onSuccess and user isn't Active : toast message will appears
/// - onError : SnackBar will appears
Future login(BuildContext context, {required User user}) async {
final subtitle = AppLocalization.of(context)?.subtitle;
waitApiRequest(
() async {
await UserApiClient().login(user: user);
},
onSuccess: () {
if (context.mounted) {
Provider.of<SettingProvider>(context, listen: false).setUser(UserApiClient().user ?? User());
if (UserApiClient().user?.isActive ?? false) {
Navigator.of(context).pushNamed(LandPage.id);
} else {
Fluttertoast.showToast(msg: subtitle?.activationAlert ?? "");
}
}
},
onError: (error) {
String errorMessage = error.error?.errorCode == 400 ? subtitle?.wrongEmailOrPassword ?? "" : HttpStatusManger.getStatusMessage(status: error.error?.errorCode, subtitle: subtitle);
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(errorMessage)));
},
);
}
/// ## Register & Fill [UserApiClient.user] data
/// - onSuccess : toast message will appears
/// - onError : SnackBar will appears
Future register(BuildContext context, {required User newUser}) async {
final subtitle = AppLocalization.of(context)?.subtitle;
if (newUser.hospital == null) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(subtitle?.hospitalRequired ?? "")));
return;
}
if (newUser.department == null) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(subtitle?.unitRequired ?? "")));
return;
}
waitApiRequest(
() async {
await UserApiClient().register(newUser: newUser);
},
onSuccess: () {
Fluttertoast.showToast(msg: subtitle?.activationAlert ?? "");
Navigator.of(context).pop();
},
onError: (error) {
String? errorMessage = error.error?.errorCode == 402
? subtitle?.nameExist
: error.error?.errorCode == 401
? subtitle?.emailExist
: HttpStatusManger.getStatusMessage(status: error.error?.errorCode, subtitle: subtitle);
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(errorMessage ?? "")));
},
);
}
/// ## Register & Fill [UserApiClient.user] data
/// - onSuccess : SnackBar will appears
/// - onError : SnackBar will appears
Future updateProfile(BuildContext context, {required User updatedUser}) async {
final subtitle = AppLocalization.of(context)?.subtitle;
if (updatedUser.department?.id == null) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(subtitle?.unitRequired ?? "")));
return;
}
waitApiRequest(
() async {
await UserApiClient().updateProfile(updatedUser: updatedUser);
},
onSuccess: () {
Provider.of<SettingProvider>(context, listen: false).setUser(UserApiClient().user!);
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(subtitle?.requestCompleteSuccessfully ?? '')));
},
onError: (error) {
String errorMessage = HttpStatusManger.getStatusMessage(status: error.error?.errorCode, subtitle: subtitle);
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(errorMessage)));
},
);
}
}

@ -1,24 +1,22 @@
class Validator{
class Validator {
// private constructor to avoid create class object
Validator._();
// check if string not empty and has value
static bool hasValue(String string){
if (string == null || string.isEmpty)
return false;
static bool hasValue(String string) {
if (string == null || string.isEmpty) return false;
return true;
}
// Return true if email is valid. Otherwise, return false
static bool isEmail(String email){
static bool isEmail(String email) {
RegExp exp = new RegExp(r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+");
if(exp.hasMatch(email))
return true;
if (exp.hasMatch(email)) return true;
return false;
}
// Return true if phone number is valid. Otherwise, return false
static bool isPhoneNumber(String phoneNumber){
static bool isPhoneNumber(String phoneNumber) {
if (phoneNumber == null || phoneNumber.isEmpty) {
return false;
}
@ -26,17 +24,14 @@ class Validator{
final pattern = r'^[+]*[(]{0,1}[0-9]{1,4}[)]{0,1}[-\s\./0-9]*$';
final regExp = RegExp(pattern);
if (regExp.hasMatch(phoneNumber))
return true;
if (regExp.hasMatch(phoneNumber)) return true;
return false;
}
// Return true if password is valid. Otherwise, return false
static bool isValidPassword(String password){
if(password == null)
return false;
if(password.length <6)
return false;
static bool isValidPassword(String password) {
if (password == null) return false;
if (password.length < 6) return false;
return true;
}
@ -55,4 +50,4 @@ class Validator{
}
return int.tryParse(value) != null;
}
}
}

@ -0,0 +1,29 @@
import 'dart:convert';
import '../api/api_client.dart';
class APIException implements Exception {
static const String BAD_REQUEST = 'api_common_bad_request';
static const String UNAUTHORIZED = 'api_common_unauthorized';
static const String FORBIDDEN = 'api_common_forbidden';
static const String NOT_FOUND = 'api_common_not_found';
static const String INTERNAL_SERVER_ERROR = 'api_common_internal_server_error';
static const String UPGRADE_REQUIRED = 'api_common_upgrade_required';
static const String BAD_RESPONSE_FORMAT = 'api_common_bad_response_format';
static const String OTHER = 'api_common_http_error';
static const String TIMEOUT = 'api_common_http_timeout';
static const String UNKNOWN = 'unexpected_error';
final String message;
final APIError? error;
final arguments;
const APIException(this.message, {this.arguments, this.error});
Map<String, dynamic> toJson() => {'message': message, 'error': error, 'arguments': '$arguments'};
@override
String toString() {
return jsonEncode(this);
}
}

@ -7,8 +7,7 @@ extension IntExtensions on int {
Widget get width => SizedBox(width: toDouble());
Widget get divider =>
Divider(height: toDouble(), thickness: toDouble(), color: AColors.greyEF);
Widget get divider => Divider(height: toDouble(), thickness: toDouble(), color: AColors.greyEF);
Widget get makeItSquare => SizedBox(width: toDouble(), height: toDouble());
}

@ -47,8 +47,8 @@ import 'controllers/providers/api/status_drop_down/report/service_report_reasons
import 'controllers/providers/api/status_drop_down/report/service_report_status_provider.dart';
import 'controllers/providers/api/status_drop_down/report/service_report_types_provider.dart';
import 'controllers/providers/api/status_drop_down/report/service_types_provider.dart';
import 'controllers/providers/api/user_provider.dart';
import 'controllers/providers/settings/setting_provider.dart';
import 'controllers/providers/user_provider.dart';
import 'views/pages/device_transfer/request_device_transfer.dart';
import 'views/pages/device_transfer/track_device_transfer.dart';
import 'views/widgets/hospitals/single_hospital_picker.dart';
@ -57,11 +57,8 @@ void main() async {
WidgetsFlutterBinding.ensureInitialized();
if (Platform.isIOS) {
await Firebase.initializeApp(
options: const FirebaseOptions(
apiKey: "AIzaSyACQkSleNwU1jzEKR5ho1uSfZERokwwAbc",
appId: "1:973582662416:ios:bc4a8061444c6a08fbc395",
messagingSenderId: "973582662416",
projectId: "atoms-fb912"),
options:
const FirebaseOptions(apiKey: "AIzaSyACQkSleNwU1jzEKR5ho1uSfZERokwwAbc", appId: "1:973582662416:ios:bc4a8061444c6a08fbc395", messagingSenderId: "973582662416", projectId: "atoms-fb912"),
);
} else {
await Firebase.initializeApp();
@ -87,8 +84,7 @@ class MyApp extends StatelessWidget {
ChangeNotifierProvider(create: (_) => ServiceRequestsProvider()),
ChangeNotifierProvider(create: (_) => DepartmentsProvider()),
ChangeNotifierProvider(create: (_) => NotificationsProvider()),
ChangeNotifierProvider(
create: (_) => PreventiveMaintenanceVisitsProvider()),
ChangeNotifierProvider(create: (_) => PreventiveMaintenanceVisitsProvider()),
ChangeNotifierProvider(create: (_) => RegularVisitsProvider()),
ChangeNotifierProvider(create: (_) => PartsProvider()),
ChangeNotifierProvider(create: (_) => ServiceReportReasonsProvider()),
@ -106,8 +102,7 @@ class MyApp extends StatelessWidget {
ChangeNotifierProvider(create: (_) => PentryVisitStatusProvider()),
ChangeNotifierProvider(create: (_) => PentryStatusProvider()),
ChangeNotifierProvider(create: (_) => ServiceRequestPriorityProvider()),
ChangeNotifierProvider(
create: (_) => ServiceRequestDefectTypesProvider()),
ChangeNotifierProvider(create: (_) => ServiceRequestDefectTypesProvider()),
],
child: GestureDetector(
onTap: () {
@ -125,11 +120,7 @@ class MyApp extends StatelessWidget {
scaffoldBackgroundColor: AColors.scaffoldBackgroundColor,
primaryColor: AColors.primaryColor,
indicatorColor: AColors.primaryColor,
colorScheme: const ColorScheme.light(
primary: AColors.primaryColor,
onPrimary: Colors.white,
secondary: AColors.secondaryColor,
onSecondary: Colors.white)),
colorScheme: const ColorScheme.light(primary: AColors.primaryColor, onPrimary: Colors.white, secondary: AColors.secondaryColor, onSecondary: Colors.white)),
localizationsDelegates: const [
// ... app-specific localization delegate[s] here
AppLocalization.delegate,
@ -157,10 +148,8 @@ class MyApp extends StatelessWidget {
SingleDepartmentPicker.id: (_) => SingleDepartmentPicker(),
ServiceRequestsPage.id: (_) => ServiceRequestsPage(),
NotificationsPage.id: (_) => NotificationsPage(),
FutureRequestServiceDetails.id: (_) =>
const FutureRequestServiceDetails(),
PreventiveMaintenanceVisitsPage.id: (_) =>
PreventiveMaintenanceVisitsPage(),
FutureRequestServiceDetails.id: (_) => const FutureRequestServiceDetails(),
PreventiveMaintenanceVisitsPage.id: (_) => PreventiveMaintenanceVisitsPage(),
RegularVisitsPage.id: (_) => const RegularVisitsPage(),
TrackGasRefillPage.id: (_) => const TrackGasRefillPage(),
RequestDeviceTransfer.id: (_) => const RequestDeviceTransfer(),

@ -1,7 +1,6 @@
import '../views/pages/user/requests/future_request_service_details.dart';
class AppNotification{
class AppNotification {
String? requestId;
String? title;
String? description;
@ -16,13 +15,12 @@ class AppNotification{
this.path,
});
factory AppNotification.fromJson(Map<String,dynamic> parsedJson){
factory AppNotification.fromJson(Map<String, dynamic> parsedJson) {
return AppNotification(
requestId: parsedJson["nid"],
title: parsedJson["call_client"] ?? parsedJson["title"],
description: parsedJson["task_description"],
date: parsedJson["creation_date"],
path: FutureRequestServiceDetails.id
);
requestId: parsedJson["nid"],
title: parsedJson["call_client"] ?? parsedJson["title"],
description: parsedJson["task_description"],
date: parsedJson["creation_date"],
path: FutureRequestServiceDetails.id);
}
}
}

@ -1,4 +1,4 @@
class Department{
class Department {
String? id;
String? name;
@ -7,16 +7,16 @@ class Department{
this.name,
});
factory Department.fromJson(Map<String,dynamic> parsedJson){
factory Department.fromJson(Map<String, dynamic> parsedJson) {
return Department(
id: parsedJson["nid"] ?? parsedJson["id"],
name: parsedJson["dept_name"] ?? parsedJson["value"],
);
}
factory Department.fromDepartment(Department? department){
factory Department.fromDepartment(Department? department) {
return Department(
id: department?.id,
name: department?.name,
);
}
}
}

@ -52,8 +52,7 @@ class DeviceTransferInfo {
userId = old?.userId;
name = old?.name;
client = old?.client != null ? Hospital.fromHospital(old?.client) : null;
department =
department != null ? Department.fromDepartment(old?.department!) : null;
department = department != null ? Department.fromDepartment(old?.department!) : null;
workingHours = old?.workingHours;
travelingHours = old?.travelingHours;
comment = old?.comment;
@ -61,8 +60,7 @@ class DeviceTransferInfo {
status = old?.status;
}
factory DeviceTransferInfo.fromJson(
Map<String, dynamic> parsedJson, String key) {
factory DeviceTransferInfo.fromJson(Map<String, dynamic> parsedJson, String key) {
return DeviceTransferInfo(
workingHours: parsedJson["${key}working_hours"],
travelingHours: parsedJson["${key}travel_hours"],

@ -1,4 +1,4 @@
enum UsersTypes{
enum UsersTypes {
engineer, // 0
normal_user, // 1
}
}

@ -10,7 +10,8 @@ class GasRefillDetails {
this.type,
this.cylinderSize,
this.requestedQuantity,
this.deliveredQuantity, required model,
this.deliveredQuantity,
required model,
});
bool validate() {
@ -24,23 +25,19 @@ class GasRefillDetails {
return GasRefillDetails(
type: Lookup.fromJson(parsedJson["type"]),
cylinderSize: Lookup.fromJson(parsedJson["size"]),
requestedQuantity: parsedJson["requsted_qty"] == null
? 0
: int.tryParse(parsedJson["requsted_qty"].toString()) ?? 0,
deliveredQuantity: parsedJson["deliverd_qty"] == null
? 0
: int.tryParse(parsedJson["deliverd_qty"].toString()) ?? 0, model: null,
requestedQuantity: parsedJson["requsted_qty"] == null ? 0 : int.tryParse(parsedJson["requsted_qty"].toString()) ?? 0,
deliveredQuantity: parsedJson["deliverd_qty"] == null ? 0 : int.tryParse(parsedJson["deliverd_qty"].toString()) ?? 0,
model: null,
);
}
factory GasRefillDetails.fromDetails(GasRefillDetails details) {
return GasRefillDetails(
type: details.type != null ? Lookup.fromStatus(details.type!) : null,
cylinderSize: details.cylinderSize != null
? Lookup.fromStatus(details.cylinderSize!)
: null,
cylinderSize: details.cylinderSize != null ? Lookup.fromStatus(details.cylinderSize!) : null,
requestedQuantity: details.requestedQuantity,
deliveredQuantity: details.deliveredQuantity, model: null,
deliveredQuantity: details.deliveredQuantity,
model: null,
);
}
}

@ -31,9 +31,7 @@ class GasRefillModel {
clientName = model.clientName;
title = model.title;
status = model.status != null ? Lookup.fromStatus(model.status!) : null;
details = model.details
?.map<GasRefillDetails>((e) => GasRefillDetails.fromDetails(e))
.toList();
details = model.details?.map<GasRefillDetails>((e) => GasRefillDetails.fromDetails(e)).toList();
}
factory GasRefillModel.fromJson(Map<String, dynamic> parsedJson) {

@ -1,4 +1,4 @@
class Hospital{
class Hospital {
String? id;
String? name;
@ -7,17 +7,17 @@ class Hospital{
this.name,
});
factory Hospital.fromJson(Map<String,dynamic> parsedJson){
factory Hospital.fromJson(Map<String, dynamic> parsedJson) {
return Hospital(
id: parsedJson["nid"] ?? parsedJson["id"],
name: parsedJson["client_name"] ?? parsedJson["value"],
);
}
factory Hospital.fromHospital(Hospital? hospital){
factory Hospital.fromHospital(Hospital? hospital) {
return Hospital(
id: hospital?.id,
name: hospital?.name,
);
}
}
}

@ -1,4 +1,4 @@
class Issue{
class Issue {
String? title;
String? userId;
List<int>? reports;
@ -15,13 +15,13 @@ class Issue{
this.serviceRequestId,
});
Map<String,String> toMap(){
Map<String,String> map ={};
if(title != null) map["title"] = title??"";
if(reports != null) map["issue_report"] = reports.toString();
if(userId != null) map["uid"] = userId??"";
if(description != null) map["desc"] = description??"";
if(serviceRequestId != null) map["call_id"] = serviceRequestId??"";
Map<String, String> toMap() {
Map<String, String> map = {};
if (title != null) map["title"] = title ?? "";
if (reports != null) map["issue_report"] = reports.toString();
if (userId != null) map["uid"] = userId ?? "";
if (description != null) map["desc"] = description ?? "";
if (serviceRequestId != null) map["call_id"] = serviceRequestId ?? "";
return map;
}
}
}

@ -1,5 +1,4 @@
class Lookup{
class Lookup {
final String? label;
final String? key;
final int? id;
@ -11,16 +10,12 @@ class Lookup{
});
@override
bool operator == (Object other) =>
identical(this, other) || other is Lookup &&
key == other.key &&
id == other.id;
bool operator ==(Object other) => identical(this, other) || other is Lookup && key == other.key && id == other.id;
@override
int get hashCode => id.hashCode;
factory Lookup.fromStatus(Lookup old){
factory Lookup.fromStatus(Lookup old) {
return Lookup(
label: old.label,
id: old.id,
@ -28,19 +23,17 @@ class Lookup{
);
}
factory Lookup.fromJson(Map<String,dynamic> parsedJson){
factory Lookup.fromJson(Map<String, dynamic> parsedJson) {
return Lookup(
label: parsedJson["value"],
id: parsedJson["id"] is int?
? parsedJson["id"]
: int.tryParse(parsedJson["id"] ?? parsedJson["uid"]),
id: parsedJson["id"] is int? ? parsedJson["id"] : int.tryParse(parsedJson["id"] ?? parsedJson["uid"]),
);
}
factory Lookup.fromIntIdJson(Map<String,dynamic> parsedJson){
factory Lookup.fromIntIdJson(Map<String, dynamic> parsedJson) {
return Lookup(
label: parsedJson["value"],
id: parsedJson["id"],
);
}
}
}

@ -12,9 +12,7 @@ class CalibrationTool {
Map<String, String> toMap() {
return {
if (assetsNumber != null) 'assetsSN': (assetsNumber?.id).toString(),
if (dataOfTesting != null)
'dataOfTesting':
((dataOfTesting?.millisecondsSinceEpoch ?? 0) ~/ 1000).toString(),
if (dataOfTesting != null) 'dataOfTesting': ((dataOfTesting?.millisecondsSinceEpoch ?? 0) ~/ 1000).toString(),
};
}

@ -8,13 +8,7 @@ class Contact {
String? telephone;
String? landLine;
Contact(
{this.title,
this.contactPerson,
this.job,
this.email,
this.telephone,
this.landLine});
Contact({this.title, this.contactPerson, this.job, this.email, this.telephone, this.landLine});
Map<String, String> toMap() {
return {

@ -1,16 +1,12 @@
import '../../lookup.dart';
class ContactTitle extends Lookup {
ContactTitle({
required int id,
required String label
}):super(id: id,label: label);
ContactTitle({required int id, required String label}) : super(id: id, label: label);
factory ContactTitle.fromMap(Map<String,dynamic> parsedJson){
factory ContactTitle.fromMap(Map<String, dynamic> parsedJson) {
return ContactTitle(
label: parsedJson["value"],
id: parsedJson["id"],
);
}
}
}

@ -1,8 +1,7 @@
import '../../lookup.dart';
class ContactTitle extends Lookup {
ContactTitle({required int id, required String label})
: super(id: id, label: label);
ContactTitle({required int id, required String label}) : super(id: id, label: label);
factory ContactTitle.fromMap(Map<String, dynamic> parsedJson) {
return ContactTitle(

@ -1,4 +1,4 @@
class Part{
class Part {
String? id;
String? code;
String? name;
@ -11,13 +11,12 @@ class Part{
this.quantity = 1,
});
factory Part.fromJson(Map<String,dynamic> parsedJson){
factory Part.fromJson(Map<String, dynamic> parsedJson) {
return Part(
id: parsedJson["nid"] ?? parsedJson["id"],
code: parsedJson["part_code"] ?? parsedJson["name"],
name: parsedJson["part_name"],
quantity: parsedJson["qty"] == null
? 1 : int.tryParse(parsedJson["qty"].toString()) ?? 1,
quantity: parsedJson["qty"] == null ? 1 : int.tryParse(parsedJson["qty"].toString()) ?? 1,
);
}
}
}

@ -50,99 +50,95 @@ class ServiceReport {
this.timer,
});
Map<String,String> toMap(){
Map<String,String> _map = {};
if(id != null) _map["id"] = id??"";
if(visitDate != null) _map["visit_date"] = ((visitDate?.millisecondsSinceEpoch??0) ~/ 1000).toString();
if(serviceType != null) _map["service_type"] = serviceType?.id.toString()??"";
if(status != null) _map["status"] = status?.id.toString()??"";
if(type != null) _map["service_report_type"] = type?.id.toString()??"";
if(faultDescription != null && (faultDescription?.isNotEmpty??false)) _map["fault_description"] = faultDescription??"";
Map<String, String> toMap() {
Map<String, String> _map = {};
if (id != null) _map["id"] = id ?? "";
if (visitDate != null) _map["visit_date"] = ((visitDate?.millisecondsSinceEpoch ?? 0) ~/ 1000).toString();
if (serviceType != null) _map["service_type"] = serviceType?.id.toString() ?? "";
if (status != null) _map["status"] = status?.id.toString() ?? "";
if (type != null) _map["service_report_type"] = type?.id.toString() ?? "";
if (faultDescription != null && (faultDescription?.isNotEmpty ?? false)) _map["fault_description"] = faultDescription ?? "";
//if(workHours != null && workHours.isNotEmpty) _map["working_hours"] = workHours;
if(timer != null){
_map["start_time"] = ((timer?.startAt?.millisecondsSinceEpoch??0) / 1000).toStringAsFixed(0);
_map["end_time"] = ((timer?.endAt ?? DateTime.now()).millisecondsSinceEpoch / 1000).toStringAsFixed(0);
_map["working_hours"] = ((timer?.durationInSecond??0) / 60 / 60).toStringAsFixed(5);
if (timer != null) {
_map["start_time"] = ((timer?.startAt?.millisecondsSinceEpoch ?? 0) / 1000).toStringAsFixed(0);
_map["end_time"] = ((timer?.endAt ?? DateTime.now()).millisecondsSinceEpoch / 1000).toStringAsFixed(0);
_map["working_hours"] = ((timer?.durationInSecond ?? 0) / 60 / 60).toStringAsFixed(5);
}
if(travelingHours != null && (travelingHours?.isNotEmpty??false)) _map["traveling_hours"] = travelingHours??"";
if(workPreformed != null && (workPreformed?.isNotEmpty??false)) _map["work_performed"] = workPreformed??"";
if(jobSheetNumber != null && (jobSheetNumber?.isNotEmpty??false)) _map["job_sheet_no"] = jobSheetNumber??"";
if(parts != null && (parts?.isNotEmpty??false)){
Map<String,int> _partsMap = {};
if (travelingHours != null && (travelingHours?.isNotEmpty ?? false)) _map["traveling_hours"] = travelingHours ?? "";
if (workPreformed != null && (workPreformed?.isNotEmpty ?? false)) _map["work_performed"] = workPreformed ?? "";
if (jobSheetNumber != null && (jobSheetNumber?.isNotEmpty ?? false)) _map["job_sheet_no"] = jobSheetNumber ?? "";
if (parts != null && (parts?.isNotEmpty ?? false)) {
Map<String, int> _partsMap = {};
parts?.forEach((part) {
if((part.id?.isNotEmpty??false)) {
_partsMap[part?.id??""] = part.quantity;
if ((part.id?.isNotEmpty ?? false)) {
_partsMap[part?.id ?? ""] = part.quantity;
}
});
_map["parts"] = json.encode(_partsMap);
}
if(device?.id != null && device?.id != null) _map["eq_id"] = device?.id??"";
if(quantity != null && (quantity?.isNotEmpty??false)) _map["qty"] = quantity??"";
if(endDate != null) _map["end_date"] = ((endDate?.millisecondsSinceEpoch??0) ~/ 1000).toString();
if(reason != null) _map["reasons"] = reason?.id.toString()??"";
if(operatingHours != null && (operatingHours?.isNotEmpty??false)) _map["operation_hours"] = operatingHours??"";
if(callLastSituation != null) _map["call_last_situtation"] = callLastSituation?.id.toString()??"";
if(image != null) _map["image"] = image??"";
if(invoiceCode != null) _map["invoice_no"] = invoiceCode??"";
if(invoiceNumber != null) _map["invoice_code"] = invoiceNumber??"";
if (device?.id != null && device?.id != null) _map["eq_id"] = device?.id ?? "";
if (quantity != null && (quantity?.isNotEmpty ?? false)) _map["qty"] = quantity ?? "";
if (endDate != null) _map["end_date"] = ((endDate?.millisecondsSinceEpoch ?? 0) ~/ 1000).toString();
if (reason != null) _map["reasons"] = reason?.id.toString() ?? "";
if (operatingHours != null && (operatingHours?.isNotEmpty ?? false)) _map["operation_hours"] = operatingHours ?? "";
if (callLastSituation != null) _map["call_last_situtation"] = callLastSituation?.id.toString() ?? "";
if (image != null) _map["image"] = image ?? "";
if (invoiceCode != null) _map["invoice_no"] = invoiceCode ?? "";
if (invoiceNumber != null) _map["invoice_code"] = invoiceNumber ?? "";
return _map;
}
bool validate(){
if(visitDate == null) return false;
if(serviceType == null) return false;
if(status == null) return false;
if(type == null) return false;
if(callLastSituation == null) return false;
if(callLastSituation?.id == 12){
if(invoiceCode != null || invoiceCode?.isEmpty == true) return false;
if(invoiceNumber != null || invoiceNumber?.isEmpty== true ) return false;
bool validate() {
if (visitDate == null) return false;
if (serviceType == null) return false;
if (status == null) return false;
if (type == null) return false;
if (callLastSituation == null) return false;
if (callLastSituation?.id == 12) {
if (invoiceCode != null || invoiceCode?.isEmpty == true) return false;
if (invoiceNumber != null || invoiceNumber?.isEmpty == true) return false;
}
if(parts == null) return false;
if (parts == null) return false;
//if(endDate == null) return false;
//if(reason == null) return false;
if((device?.id == null ||(device?.id?.isEmpty??false)) && type?.id != 1) return false;
if ((device?.id == null || (device?.id?.isEmpty ?? false)) && type?.id != 1) return false;
//if(quantity == null || quantity.isEmpty) return false;
//if(image == null) return false;
return true;
}
factory ServiceReport.fromJson(Map<String,dynamic> parsedJson,String id){
List<Part> _parts = [];
if(parsedJson["parts"] != null){
if(parsedJson["parts"][0]["id"] != null){
List partsList = parsedJson["parts"];
_parts = partsList.map((e) => Part.fromJson(e)).toList();
}
factory ServiceReport.fromJson(Map<String, dynamic> parsedJson, String id) {
List<Part> _parts = [];
if (parsedJson["parts"] != null) {
if (parsedJson["parts"][0]["id"] != null) {
List partsList = parsedJson["parts"];
_parts = partsList.map((e) => Part.fromJson(e)).toList();
}
}
return ServiceReport(
id: id,
serviceType: Lookup.fromJson(parsedJson["service_type"]),
callLastSituation: Lookup.fromJson(parsedJson["call_last_situtation"]),
reason: Lookup.fromJson(parsedJson["reasons"]),
status: Lookup.fromJson(parsedJson["service_report_status"]),
type: Lookup.fromJson(parsedJson["service_report_type"]),
faultDescription: parsedJson["fault_description"],
endDate:getDate(parsedJson["end_date"]),
invoiceCode: parsedJson["invoice_code"],
invoiceNumber: parsedJson["invoice_no"],
jobSheetNumber: parsedJson["job_sheet_no"],
operatingHours: parsedJson["operation_hours"],
parts: _parts,
quantity: parsedJson["nid"],
travelingHours: parsedJson["traveling_hours"],
visitDate: getDate(parsedJson["visit_date"]),
//workHours: parsedJson["working_hours"],
timer: TimerModel(
durationInSecond: (int.tryParse(parsedJson["working_hours"] ?? "") ?? 0) * 60 *60),
workPreformed: parsedJson["work_performed"],
device: parsedJson["eq_nid"] == null ? null : Device(id: parsedJson["eq_nid"],serialNumber: parsedJson["eq_serial"])
);
id: id,
serviceType: Lookup.fromJson(parsedJson["service_type"]),
callLastSituation: Lookup.fromJson(parsedJson["call_last_situtation"]),
reason: Lookup.fromJson(parsedJson["reasons"]),
status: Lookup.fromJson(parsedJson["service_report_status"]),
type: Lookup.fromJson(parsedJson["service_report_type"]),
faultDescription: parsedJson["fault_description"],
endDate: getDate(parsedJson["end_date"]),
invoiceCode: parsedJson["invoice_code"],
invoiceNumber: parsedJson["invoice_no"],
jobSheetNumber: parsedJson["job_sheet_no"],
operatingHours: parsedJson["operation_hours"],
parts: _parts,
quantity: parsedJson["nid"],
travelingHours: parsedJson["traveling_hours"],
visitDate: getDate(parsedJson["visit_date"]),
//workHours: parsedJson["working_hours"],
timer: TimerModel(durationInSecond: (int.tryParse(parsedJson["working_hours"] ?? "") ?? 0) * 60 * 60),
workPreformed: parsedJson["work_performed"],
device: parsedJson["eq_nid"] == null ? null : Device(id: parsedJson["eq_nid"], serialNumber: parsedJson["eq_serial"]));
}
static getDate(String date){
return date == null || date.isEmpty
? null : DateTime.fromMillisecondsSinceEpoch((int.tryParse(date)??0) * 1000);
static getDate(String date) {
return date == null || date.isEmpty ? null : DateTime.fromMillisecondsSinceEpoch((int.tryParse(date) ?? 0) * 1000);
}
}
}

@ -70,12 +70,8 @@ class ServiceRequest {
deviceNumber: parsedJson["device_no"],
deviceId: parsedJson["deviceid"],
audio: parsedJson["audio"] ?? "",
deviceArName: parsedJson["equipment_arabic_name"] == false
? "No Name found"
: parsedJson["equipment_arabic_name"],
deviceEnName: parsedJson["equipment_english_name"] == false
? "No Name found"
: parsedJson["equipment_english_name"],
deviceArName: parsedJson["equipment_arabic_name"] == false ? "No Name found" : parsedJson["equipment_arabic_name"],
deviceEnName: parsedJson["equipment_english_name"] == false ? "No Name found" : parsedJson["equipment_english_name"],
devicePhotos: List<String>.from(parsedJson["image"]),
deviceSerialNumber: parsedJson["call_sn"],
date: parsedJson["call_data"],
@ -85,9 +81,7 @@ class ServiceRequest {
departmentName: parsedJson["department_name"],
engineerName: parsedJson["employee_name"],
hospitalId: parsedJson["client"],
reportID: parsedJson["service_report_nid"] is String
? parsedJson["service_report_nid"]
: null,
reportID: parsedJson["service_report_nid"] is String ? parsedJson["service_report_nid"] : null,
viewReport: parsedJson["service_report_nid"] is bool ? false : true,
deviceModel: parsedJson["device_model"],
engineerMobile: parsedJson["engineer_mobile"],

@ -22,8 +22,7 @@ class ServiceRequestSearch {
String toSearchString() {
String search = "";
if (deviceSerialNumber != null &&
(deviceSerialNumber?.isNotEmpty ?? false)) {
if (deviceSerialNumber != null && (deviceSerialNumber?.isNotEmpty ?? false)) {
search += "&sn_id=$deviceSerialNumber";
}

@ -1,6 +1,4 @@
import 'package:meta/meta.dart';
class Subtitle{
class Subtitle {
// http requests status messages
String currentlyServiceNotAvailable;
String waitUntilYourRequestComplete;
@ -216,7 +214,7 @@ class Subtitle{
String duplicateAlertMessage;
String alert;
void setIssues(List<String> issues){
void setIssues(List<String> issues) {
issues.clear();
issues.add(reason1);
issues.add(reason2);
@ -278,7 +276,6 @@ class Subtitle{
required this.titleValidateMessage,
required this.to,
required this.urlNotFound,
required this.nameExist,
required this.unitRequired,
required this.unite,
@ -384,7 +381,6 @@ class Subtitle{
required this.pickImage,
required this.requiredImage,
required this.activationAlert,
required this.callId,
required this.requiredWord,
required this.quantity,
@ -409,7 +405,7 @@ class Subtitle{
required this.duplicateRequest,
});
factory Subtitle.fromJson(Map<String,dynamic> parsedJson){
factory Subtitle.fromJson(Map<String, dynamic> parsedJson) {
return Subtitle(
currentlyServiceNotAvailable: parsedJson["server_error_message"],
failedToCompleteRequest: parsedJson["failed_request_message"],
@ -423,7 +419,6 @@ class Subtitle{
signOut: parsedJson["sign_out"],
signOutAlert: parsedJson["logout_alert"],
language: parsedJson["language"],
name: parsedJson["name"],
email: parsedJson["email"],
phoneNumber: parsedJson["phone_number"],
@ -437,7 +432,6 @@ class Subtitle{
passwordValidateMessage: parsedJson["password_validate_message"],
confirmPasswordValidateMessage: parsedJson["confirm_password_validate_message"],
phoneNumberValidateMessage: parsedJson["phone_number_validate_message"],
forgetPasswordWithMark: parsedJson["forget_password_with_mark"],
showPassword: parsedJson["show_password"],
wrongEmailOrPassword: parsedJson["wrong_email_or_password"],
@ -447,7 +441,6 @@ class Subtitle{
back: parsedJson["back"],
search: parsedJson["search"],
searchByName: parsedJson["search_by_name"],
address: parsedJson["address"],
addressNotFound: parsedJson["address_not_found"],
addressValidateMessage: parsedJson["address_validate_message"],
@ -466,7 +459,6 @@ class Subtitle{
titleNotFound: parsedJson["title_not_found"],
titleValidateMessage: parsedJson["title_validate_message"],
urlNotFound: parsedJson["url_not_found"],
date: parsedJson["date"],
status: parsedJson["status"],
code: parsedJson["code"],
@ -542,7 +534,6 @@ class Subtitle{
visitDate: parsedJson["visitDate"],
whatsApp: parsedJson["whatsApp"],
workPerformed: parsedJson["workPerformed"],
actualDate: parsedJson["actualDate"],
done: parsedJson["done"],
expectDate: parsedJson["expectDate"],
@ -573,7 +564,6 @@ class Subtitle{
requiredImage: parsedJson["requiredImage"],
taskStatus: parsedJson["taskStatus"],
activationAlert: parsedJson["activationAlert"],
attachImage: parsedJson["attachImage"],
callLastSituation: parsedJson["callLastSituation"],
customer: parsedJson["customer"],
@ -592,12 +582,10 @@ class Subtitle{
requiredWord: parsedJson["requiredWord"],
serviceType: parsedJson["serviceType"],
workPreformed: parsedJson["workPreformed"],
alert: parsedJson["alert"],
duplicateAlert: parsedJson["duplicateAlert"],
duplicateAlertMessage: parsedJson["duplicateAlertMessage"],
duplicateRequest: parsedJson["duplicateRequest"],
);
}
}
}

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

@ -1,5 +1,3 @@
import '../controllers/notification/firebase_notification_manger.dart';
import 'department.dart';
import 'enums/user_types.dart';
@ -19,34 +17,22 @@ class User {
String? token;
bool isActive;
User(
{this.id,
this.userName = "",
this.email = "",
this.password = "",
this.phoneNumber,
this.hospital,
this.image,
this.department,
this.type,
this.whatsApp,
this.token,
this.isActive = false});
User({this.id, this.userName = "", this.email = "", this.password = "", this.phoneNumber, this.hospital, this.image, this.department, this.type, this.whatsApp, this.token, this.isActive = false});
Future<Map<String, dynamic>> toLoginJson() async {
if (FirebaseNotificationManger.token == null) await FirebaseNotificationManger.getToken();
return {
"username": userName,
"pass": password,
"firebase_token": FirebaseNotificationManger?.token ?? "",
"firebase_token": FirebaseNotificationManger.token ?? "",
};
}
Map<String, dynamic> toUpdateProfileJson() {
Map<String, dynamic> jsonObject = {};
if (department?.id != null && (department?.id?.isNotEmpty??false)) jsonObject["department"] = department?.id??"";
if (whatsApp != null && (whatsApp?.isNotEmpty??false)) jsonObject["whatsapp"] = whatsApp;
if (phoneNumber != null && (phoneNumber?.isNotEmpty??false)) jsonObject["phone"] = phoneNumber;
if (department?.id != null && (department?.id?.isNotEmpty ?? false)) jsonObject["department"] = department?.id ?? "";
if (whatsApp != null && (whatsApp?.isNotEmpty ?? false)) jsonObject["whatsapp"] = whatsApp;
if (phoneNumber != null && (phoneNumber?.isNotEmpty ?? false)) jsonObject["phone"] = phoneNumber;
return jsonObject;
}
@ -60,7 +46,7 @@ class User {
"department": department?.id,
"phone": phoneNumber,
"pass": password,
"firebase_token": FirebaseNotificationManger?.token ?? "",
"firebase_token": FirebaseNotificationManger.token ?? "",
};
}

@ -1,10 +1,7 @@
import '../lookup.dart';
import 'visit.dart';
class VisitsGroup{
class VisitsGroup {
String? userId;
String? workingHours;
String? travelingHours;
@ -27,24 +24,22 @@ class VisitsGroup{
this.taskStatus,
});
Map<String,String> toJson(){
Map<String,String> jsonObject = {};
Map<String, String> toJson() {
Map<String, String> jsonObject = {};
jsonObject["nids"] = visits!.map((e) => e.id).toList().join(',');
if(status != null) jsonObject["status"] = status?.id.toString()??"";
if(date != null) jsonObject["date"] = date.toString().split(" ").first;
if(jobSheetNumber != null && (jobSheetNumber?.isNotEmpty??false)) {
if (status != null) jsonObject["status"] = status?.id.toString() ?? "";
if (date != null) jsonObject["date"] = date.toString().split(" ").first;
if (jobSheetNumber != null && (jobSheetNumber?.isNotEmpty ?? false)) {
jsonObject["job_sheet_no"] = jobSheetNumber!;
}
if(travelingHours != null &&(travelingHours?.isNotEmpty??false)) {
jsonObject["traveling_hours"] = travelingHours??"";
if (travelingHours != null && (travelingHours?.isNotEmpty ?? false)) {
jsonObject["traveling_hours"] = travelingHours ?? "";
}
if(workingHours != null && (workingHours?.isNotEmpty??false)) {
jsonObject["working_hours"] = workingHours??"";
if (workingHours != null && (workingHours?.isNotEmpty ?? false)) {
jsonObject["working_hours"] = workingHours ?? "";
}
if(image != null) jsonObject["image"] = image??"";
if(taskStatus != null) jsonObject["task_status"] = taskStatus?.id.toString()??"";
if (image != null) jsonObject["image"] = image ?? "";
if (taskStatus != null) jsonObject["task_status"] = taskStatus?.id.toString() ?? "";
return jsonObject;
}
}
}

@ -1,4 +1,4 @@
class VisitsSearch{
class VisitsSearch {
String? deviceSerialNumber;
String? hospitalName;
String? brand;
@ -23,7 +23,7 @@ class VisitsSearch{
this.expectedDateTo,
});
fromSearch(VisitsSearch newSearch){
fromSearch(VisitsSearch newSearch) {
deviceSerialNumber = newSearch.deviceSerialNumber;
brand = newSearch.brand;
hospitalName = newSearch.hospitalName;
@ -36,48 +36,47 @@ class VisitsSearch{
statusValue = newSearch.statusValue;
}
String toSearchString(){
String toSearchString() {
String _search = "";
if(deviceSerialNumber != null && (deviceSerialNumber?.isNotEmpty??false)){
if (deviceSerialNumber != null && (deviceSerialNumber?.isNotEmpty ?? false)) {
_search += "&sn_id=$deviceSerialNumber";
}
if(hospitalName != null && (hospitalName?.isNotEmpty??false)){
if (hospitalName != null && (hospitalName?.isNotEmpty ?? false)) {
_search += "&client=$hospitalName";
}
if(brand != null && (brand?.isNotEmpty??false)){
if (brand != null && (brand?.isNotEmpty ?? false)) {
_search += "&brand=$brand";
}
if(model != null && (model?.isNotEmpty??false)){
if (model != null && (model?.isNotEmpty ?? false)) {
_search += "&model=$model";
}
if(expectedDateFrom != null){
_search += "&expected_date_from=${(expectedDateFrom?.millisecondsSinceEpoch??0) ~/ 1000}";
if (expectedDateFrom != null) {
_search += "&expected_date_from=${(expectedDateFrom?.millisecondsSinceEpoch ?? 0) ~/ 1000}";
}
if(expectedDateTo != null){
_search += "&expected_date_to=${(expectedDateTo?.millisecondsSinceEpoch??0) ~/1000}";
if (expectedDateTo != null) {
_search += "&expected_date_to=${(expectedDateTo?.millisecondsSinceEpoch ?? 0) ~/ 1000}";
}
if(actualDateFrom != null){
_search += "&actual_date_from=${(actualDateFrom?.millisecondsSinceEpoch??0) ~/ 1000}";
if (actualDateFrom != null) {
_search += "&actual_date_from=${(actualDateFrom?.millisecondsSinceEpoch ?? 0) ~/ 1000}";
}
if(actualDateTo != null){
_search += "&actual_date_to=${(actualDateTo?.millisecondsSinceEpoch??0) ~/1000}";
if (actualDateTo != null) {
_search += "&actual_date_to=${(actualDateTo?.millisecondsSinceEpoch ?? 0) ~/ 1000}";
}
if(statusValue != null){
if (statusValue != null) {
_search += "&status=$statusValue";
}
if(contactStatus != null){
if (contactStatus != null) {
_search += "&assigned_to=$contactStatus";
}
return _search;
}
}

@ -3,40 +3,48 @@ import 'package:flutter/material.dart';
class AColors {
AColors._();
static const Color white = Color(0xffffffff);
static const Color black = Color(0xff000000);
static const Color grey3A = Color(0xff2e303a);
static const Color grey = Color(0xffe1e7e7);
static const green = Colors.green;
static const Color orange = Colors.orange;
static const Color deepOrange = Colors.deepOrangeAccent;
static const Color red = Colors.red;
static const Color deepRed = Color(0xFFD32F2F);
static const Color white = Color(0xffffffff);
static const Color black = Color(0xff000000);
static const Color grey3A = Color(0xff2e303a);
static const Color grey = Color(0xffe1e7e7);
static const green = Colors.green;
static const Color orange = Colors.orange;
static const Color deepOrange = Colors.deepOrangeAccent;
static const Color red = Colors.red;
static const Color deepRed = Color(0xFFD32F2F);
static const Color scaffoldBackgroundColor = Color(0xffffffff);
static const Color secondaryColor = Color(0xff111427);
static const Color primaryColor = Color(0xff5bb0da);
static const Color cyan = Color(0xff4A8DB7);
static const Color onPrimaryColor = Color(0xffffffff);
static const Color secondaryColor = Color(0xff111427);
static const Color primaryColor = Color(0xff5bb0da);
static const Color cyan = Color(0xff4A8DB7);
static const Color onPrimaryColor = Color(0xffffffff);
static Color inputFieldBackgroundColor = Color(0xfff5f5f5);
static Color greyEF = Color(0xffEFEFEF);
static Color getRequestStatusColor(int id){
switch(id){
case 4: return AColors.deepRed;
case 6: return AColors.green;
case 5: return AColors.orange;
case 8: return AColors.green;
case 9: return AColors.orange;
default : return AColors.grey;
static Color getRequestStatusColor(int id) {
switch (id) {
case 4:
return AColors.deepRed;
case 6:
return AColors.green;
case 5:
return AColors.orange;
case 8:
return AColors.green;
case 9:
return AColors.orange;
default:
return AColors.grey;
}
}
static Color getGasStatusColor(int id){
switch(id){
case 0: return AColors.orange;
case 1: return AColors.green;
default : return AColors.grey;
static Color getGasStatusColor(int id) {
switch (id) {
case 0:
return AColors.orange;
case 1:
return AColors.green;
default:
return AColors.grey;
}
}
}

@ -1,39 +1,31 @@
import 'package:flutter/material.dart';
class AppStyle {
AppStyle._();
static const double borderRadius = 10;
static const BoxShadow boxShadow = BoxShadow(
color: Colors.black26,
blurRadius: 3,
offset: Offset(0,2)
);
static const BoxShadow boxShadow = BoxShadow(color: Colors.black26, blurRadius: 3, offset: Offset(0, 2));
static double getBorderRadius(BuildContext context){
static double getBorderRadius(BuildContext context) {
return borderRadius * getScaleFactor(context);
}
static double getScaleFactor(BuildContext context){
static double getScaleFactor(BuildContext context) {
return MediaQuery.of(context).orientation == Orientation.portrait
? MediaQuery.of(context).size.width/(360) > 1.5
? 1.5 : MediaQuery.of(context).size.width/(360)
: MediaQuery.of(context).size.height/(360) > 1.5
? 1.5 : MediaQuery.of(context).size.height/(360);
? MediaQuery.of(context).size.width / (360) > 1.5
? 1.5
: MediaQuery.of(context).size.width / (360)
: MediaQuery.of(context).size.height / (360) > 1.5
? 1.5
: MediaQuery.of(context).size.height / (360);
}
static BorderRadius getCardBorder(BuildContext context){
static BorderRadius getCardBorder(BuildContext context) {
return BorderRadius.only(
topRight: Radius.circular(
AppStyle.borderRadius * AppStyle.getScaleFactor(context)
),
topLeft: Radius.circular(
AppStyle.borderRadius * AppStyle.getScaleFactor(context)
),
bottomRight: Radius.circular(
AppStyle.borderRadius * AppStyle.getScaleFactor(context)
),
topRight: Radius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)),
topLeft: Radius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)),
bottomRight: Radius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)),
);
}
}
}

@ -1,9 +1,11 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../../api/login_api_client.dart';
import '../../../controllers/localization/localization.dart';
import '../../../controllers/providers/api/device_transfer_provider.dart';
import '../../../controllers/providers/api/user_provider.dart';
import '../../../controllers/providers/settings/setting_provider.dart';
import '../../../controllers/providers/user_provider.dart';
import '../../../models/device/device_transfer.dart';
import '../../../models/device/device_transfer_info.dart';
import '../../../models/subtitle.dart';
@ -25,7 +27,6 @@ class DeviceTransferDetails extends StatefulWidget {
}
class _DeviceTransferDetailsState extends State<DeviceTransferDetails> {
final DeviceTransferInfo _model = DeviceTransferInfo();
bool _isSender = false;
bool _isReceiver = false;
@ -48,8 +49,8 @@ class _DeviceTransferDetailsState extends State<DeviceTransferDetails> {
_userProvider = Provider.of<UserProvider>(context);
_settingProvider = Provider.of<SettingProvider>(context);
_deviceTransferProvider = Provider.of<DeviceTransferProvider>(context);
_isSender = _userProvider?.user?.id == widget.model.sender?.userId;
_isReceiver = _userProvider?.user?.id == widget.model.receiver?.userId;
_isSender = UserApiClient().user?.id == widget.model.sender?.userId;
_isReceiver = UserApiClient().user?.id == widget.model.receiver?.userId;
return Scaffold(
key: _scaffoldKey,
body: SafeArea(
@ -64,18 +65,15 @@ class _DeviceTransferDetailsState extends State<DeviceTransferDetails> {
children: [
Container(
color: Theme.of(context).colorScheme.primary,
padding: const EdgeInsets.symmetric(horizontal: 0,vertical: 4),
padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 4),
child: Row(
children: [
ABackButton(),
Expanded(
child: Center(
child: Text(
_subtitle?.details??"",
style: Theme.of(context).textTheme.headline6?.copyWith(
color: AColors.white,
fontStyle: FontStyle.italic
),
_subtitle?.details ?? "",
style: Theme.of(context).textTheme.headline6?.copyWith(color: AColors.white, fontStyle: FontStyle.italic),
),
),
),
@ -85,7 +83,7 @@ class _DeviceTransferDetailsState extends State<DeviceTransferDetails> {
),
Expanded(
child: SingleChildScrollView(
padding: EdgeInsets.all(16*AppStyle.getScaleFactor(context)),
padding: EdgeInsets.all(16 * AppStyle.getScaleFactor(context)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -97,59 +95,52 @@ class _DeviceTransferDetailsState extends State<DeviceTransferDetails> {
title: _subtitle?.device,
info: widget.model.device?.serialNumber,
),
const SizedBox(height:8),
const SizedBox(height: 8),
Row(
children: [
Expanded(
child: Text(
"Sender",
style: Theme.of(context).textTheme.headline6
),
child: Text("Sender", style: Theme.of(context).textTheme.headline6),
),
if(_isSender)
if (_isSender)
ASmallButton(
text: _subtitle?.edit??"",
onPressed: (){
Navigator.of(context).push(
MaterialPageRoute(
builder: (_)=> UpdateDeviceTransfer(model: widget.model,isSender: _isSender,)
)
);
text: _subtitle?.edit ?? "",
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (_) => UpdateDeviceTransfer(
model: widget.model,
isSender: _isSender,
)));
},
),
],
),
const SizedBox(height:12),
const SizedBox(height: 12),
DeviceTransferInfoSection(
info: widget.model.sender!,
),
const SizedBox(height:8),
const SizedBox(height: 8),
Row(
children: [
Expanded(
child: Text(
"Receiver",
style: Theme.of(context).textTheme.headline6
),
),
if(_isReceiver)
ASmallButton(
text: _subtitle?.edit??"",
onPressed: (){
Navigator.of(context).push(
MaterialPageRoute(
builder: (_)=> UpdateDeviceTransfer(model: widget.model,isSender: _isSender,)
)
);
},
child: Text("Receiver", style: Theme.of(context).textTheme.headline6),
),
if (_isReceiver)
ASmallButton(
text: _subtitle?.edit ?? "",
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (_) => UpdateDeviceTransfer(
model: widget.model,
isSender: _isSender,
)));
},
),
],
),
const SizedBox(height:12),
const SizedBox(height: 12),
DeviceTransferInfoSection(
info: widget.model.receiver!,
),
],
),
),

@ -3,11 +3,12 @@ import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/models/hospital.dart';
import '../../../api/login_api_client.dart';
import '../../../controllers/http_status_manger/http_status_manger.dart';
import '../../../controllers/localization/localization.dart';
import '../../../controllers/providers/api/device_transfer_provider.dart';
import '../../../controllers/providers/api/user_provider.dart';
import '../../../controllers/providers/settings/setting_provider.dart';
import '../../../controllers/providers/user_provider.dart';
import '../../../extensions/int_extensions.dart';
import '../../../models/device/device_transfer.dart';
import '../../../models/device/device_transfer_info.dart';
@ -35,10 +36,8 @@ class _RequestDeviceTransferState extends State<RequestDeviceTransfer> {
UserProvider? _userProvider;
SettingProvider? _settingProvider;
DeviceTransferProvider? _deviceTransferProvider;
final TextEditingController _requestedQuantityController =
TextEditingController();
final DeviceTransfer _formModel =
DeviceTransfer(receiver: DeviceTransferInfo());
final TextEditingController _requestedQuantityController = TextEditingController();
final DeviceTransfer _formModel = DeviceTransfer(receiver: DeviceTransferInfo());
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
@ -64,7 +63,7 @@ class _RequestDeviceTransferState extends State<RequestDeviceTransfer> {
setState(() {});
int? status = await _deviceTransferProvider?.createRequest(
user: _userProvider?.user,
user: UserApiClient().user,
host: _settingProvider?.host ?? "",
model: _formModel,
);
@ -76,8 +75,7 @@ class _RequestDeviceTransferState extends State<RequestDeviceTransfer> {
);
Navigator.of(context).pop();
} else {
String errorMessage = HttpStatusManger.getStatusMessage(
status: status, subtitle: _subtitle);
String errorMessage = HttpStatusManger.getStatusMessage(status: status, subtitle: _subtitle);
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(errorMessage),
));
@ -95,8 +93,7 @@ class _RequestDeviceTransferState extends State<RequestDeviceTransfer> {
_subtitle = AppLocalization.of(context)?.subtitle;
_userProvider = Provider.of<UserProvider>(context);
_settingProvider = Provider.of<SettingProvider>(context);
_deviceTransferProvider =
Provider.of<DeviceTransferProvider>(context, listen: false);
_deviceTransferProvider = Provider.of<DeviceTransferProvider>(context, listen: false);
return Scaffold(
key: _scaffoldKey,
body: Form(
@ -117,10 +114,7 @@ class _RequestDeviceTransferState extends State<RequestDeviceTransfer> {
padding: const EdgeInsets.all(8.0),
child: Text(
"Transfer Device",
style: Theme.of(context).textTheme.headline5?.copyWith(
color: Theme.of(context).primaryColor,
fontSize: 28,
fontWeight: FontWeight.bold),
style: Theme.of(context).textTheme.headline5?.copyWith(color: Theme.of(context).primaryColor, fontSize: 28, fontWeight: FontWeight.bold),
),
),
),
@ -174,7 +168,7 @@ class _RequestDeviceTransferState extends State<RequestDeviceTransfer> {
),
6.height,
HospitalButton(
hospital: _formModel.receiver?.client??Hospital(),
hospital: _formModel.receiver?.client ?? Hospital(),
onHospitalPick: (hospital) {
_formModel.receiver?.client = hospital;
setState(() {});

@ -1,10 +1,11 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../../api/login_api_client.dart';
import '../../../controllers/localization/localization.dart';
import '../../../controllers/providers/api/device_transfer_provider.dart';
import '../../../controllers/providers/api/user_provider.dart';
import '../../../controllers/providers/settings/setting_provider.dart';
import '../../../controllers/providers/user_provider.dart';
import '../../../models/subtitle.dart';
import '../../../models/user.dart';
import '../../app_style/colors.dart';
@ -21,8 +22,7 @@ class TrackDeviceTransferPage extends StatefulWidget {
State<TrackDeviceTransferPage> createState() => _TrackDeviceTransferPageState();
}
class _TrackDeviceTransferPageState extends State<TrackDeviceTransferPage>
with TickerProviderStateMixin{
class _TrackDeviceTransferPageState extends State<TrackDeviceTransferPage> with TickerProviderStateMixin {
late DeviceTransferProvider _deviceTransferProvider;
UserProvider? _userProvider;
late SettingProvider _settingProvider;
@ -43,8 +43,8 @@ class _TrackDeviceTransferPageState extends State<TrackDeviceTransferPage>
onRefresh: () async {
_deviceTransferProvider.reset();
await _deviceTransferProvider.getRequests(
user: _userProvider?.user??User(),
host: _settingProvider.host??"",
user: UserApiClient().user ?? User(),
host: _settingProvider.host ?? "",
);
},
child: Stack(
@ -52,8 +52,8 @@ class _TrackDeviceTransferPageState extends State<TrackDeviceTransferPage>
Column(
children: [
Container(
color:AColors.primaryColor,
padding: const EdgeInsets.symmetric(horizontal: 0,vertical: 4),
color: AColors.primaryColor,
padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 4),
child: Column(
children: [
Row(
@ -63,17 +63,15 @@ class _TrackDeviceTransferPageState extends State<TrackDeviceTransferPage>
child: Center(
child: Text(
"Device Transfer",
style: Theme.of(context).textTheme.headline6?.copyWith(
color: AColors.white,
fontStyle: FontStyle.italic
),
style: Theme.of(context).textTheme.headline6?.copyWith(color: AColors.white, fontStyle: FontStyle.italic),
),
),
),
const SizedBox(width: 48,)
const SizedBox(
width: 48,
)
],
),
],
),
),
@ -82,8 +80,8 @@ class _TrackDeviceTransferPageState extends State<TrackDeviceTransferPage>
nextPage: _deviceTransferProvider.nextPage,
onLazyLoad: () async {
await _deviceTransferProvider.getRequests(
user: _userProvider?.user??User(),
host: _settingProvider.host??"",
user: UserApiClient().user ?? User(),
host: _settingProvider.host ?? "",
);
},
items: _deviceTransferProvider.items,

@ -5,11 +5,12 @@ import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart';
import '../../../api/login_api_client.dart';
import '../../../controllers/http_status_manger/http_status_manger.dart';
import '../../../controllers/localization/localization.dart';
import '../../../controllers/providers/api/device_transfer_provider.dart';
import '../../../controllers/providers/api/user_provider.dart';
import '../../../controllers/providers/settings/setting_provider.dart';
import '../../../controllers/providers/user_provider.dart';
import '../../../models/device/device_transfer.dart';
import '../../../models/device/device_transfer_info.dart';
import '../../../models/subtitle.dart';
@ -46,54 +47,41 @@ class _UpdateDeviceTransferState extends State<UpdateDeviceTransfer> {
_update() async {
_validate = true;
if((_formKey.currentState?.validate()??false)){
if ((_formKey.currentState?.validate() ?? false)) {
setState(() {});
return false;
}
_formKey.currentState?.save();
_isLoading =true;
_isLoading = true;
setState(() {});
int? status = await _deviceTransferProvider?.updateRequest(
user: _userProvider?.user??User(),
host: _settingProvider?.host??"",
requestId: widget.model?.id??"",
isSender: widget.isSender??false,
newModel: _formModel,
oldModel: widget.model
);
_isLoading =false;
user: UserApiClient().user ?? User(), host: _settingProvider?.host ?? "", requestId: widget.model?.id ?? "", isSender: widget.isSender ?? false, newModel: _formModel, oldModel: widget.model);
_isLoading = false;
setState(() {});
if(status!=null && status >= 200 && status < 300){
if (status != null && status >= 200 && status < 300) {
Fluttertoast.showToast(
msg: _subtitle?.requestCompleteSuccessfully??"",
msg: _subtitle?.requestCompleteSuccessfully ?? "",
);
_validate = false;
Navigator.of(context).pop();
Navigator.of(context).pop();
}else{
String errorMessage = HttpStatusManger.getStatusMessage(
status: status, subtitle: _subtitle);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
errorMessage
),
)
);
} else {
String errorMessage = HttpStatusManger.getStatusMessage(status: status, subtitle: _subtitle);
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(errorMessage),
));
}
}
@override
void setState(VoidCallback fn){
if(mounted) super.setState(() {});
void setState(VoidCallback fn) {
if (mounted) super.setState(() {});
}
@override
void initState() {
_formModel.fromDetails((widget.isSender??false) ? widget.model?.sender : widget.model?.receiver,
withSignature: false
);
_formModel.fromDetails((widget.isSender ?? false) ? widget.model?.sender : widget.model?.receiver, withSignature: false);
super.initState();
}
@ -108,7 +96,7 @@ class _UpdateDeviceTransferState extends State<UpdateDeviceTransfer> {
_subtitle = AppLocalization.of(context)?.subtitle;
_userProvider = Provider.of<UserProvider>(context);
_settingProvider = Provider.of<SettingProvider>(context);
_deviceTransferProvider = Provider.of<DeviceTransferProvider>(context,listen: false);
_deviceTransferProvider = Provider.of<DeviceTransferProvider>(context, listen: false);
return Scaffold(
key: _scaffoldKey,
body: Form(
@ -129,84 +117,100 @@ class _UpdateDeviceTransferState extends State<UpdateDeviceTransfer> {
padding: const EdgeInsets.all(8.0),
child: Text(
"Edit Transfer Device",
style: Theme.of(context).textTheme.headline5?.copyWith(
color: Theme.of(context).primaryColor,
fontSize: 28,
fontWeight: FontWeight.bold
),
style: Theme.of(context).textTheme.headline5?.copyWith(color: Theme.of(context).primaryColor, fontSize: 28, fontWeight: FontWeight.bold),
),
),
),
const SizedBox(height: 8,),
const SizedBox(
height: 8,
),
ASubTitle("Comment"),
const SizedBox(height: 4,),
const SizedBox(
height: 4,
),
ATextFormField(
initialValue: _formModel.comment??"",
initialValue: _formModel.comment ?? "",
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.subtitle1,
textInputType: TextInputType.text,
onSaved: (value){
onSaved: (value) {
_formModel.comment = value;
},
),
const SizedBox(height: 8,),
ASubTitle(_subtitle?.travelingHours??""),
const SizedBox(height: 4,),
const SizedBox(
height: 8,
),
ASubTitle(_subtitle?.travelingHours ?? ""),
const SizedBox(
height: 4,
),
ATextFormField(
initialValue: _formModel.travelingHours??"",
initialValue: _formModel.travelingHours ?? "",
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.subtitle1,
textInputType: TextInputType.number,
onSaved: (value){
onSaved: (value) {
_formModel.travelingHours = value;
},
),
const SizedBox(height: 8,),
ASubTitle(_subtitle?.workingHours??""),
const SizedBox(height: 4,),
const SizedBox(
height: 8,
),
ASubTitle(_subtitle?.workingHours ?? ""),
const SizedBox(
height: 4,
),
ATextFormField(
initialValue: _formModel.workingHours??"",
initialValue: _formModel.workingHours ?? "",
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.subtitle1,
textInputType: TextInputType.number,
onSaved: (value){
onSaved: (value) {
_formModel.workingHours = value;
},
),
const SizedBox(height: 8,),
ASubTitle(_subtitle?.status??""),
const SizedBox(height: 4,),
const SizedBox(
height: 8,
),
ASubTitle(_subtitle?.status ?? ""),
const SizedBox(
height: 4,
),
GasStatusMenu(
initialValue: _formModel.status,
onSelect: (status){
onSelect: (status) {
_formModel.status = status;
setState(() {});
},
),
const SizedBox(height: 8,),
const SizedBox(
height: 8,
),
const ASubTitle("Signature"),
// if(_validate && _formModel.signature == null)
// ASubTitle(_subtitle.requiredWord,color: Colors.red,),
const SizedBox(height: 4,),
const SizedBox(
height: 4,
),
ESignature(
oldSignature: (widget.isSender??false)
? widget.model?.sender?.signature
: widget.model?.receiver?.signature,
newSignature: _signature,
onSaved: (signature){
_signature = signature;
_formModel.signature = base64Encode(signature);
},
oldSignature: (widget.isSender ?? false) ? widget.model?.sender?.signature : widget.model?.receiver?.signature,
newSignature: _signature,
onSaved: (signature) {
_signature = signature;
_formModel.signature = base64Encode(signature);
},
),
Padding(
padding: const EdgeInsets.all(16.0),
child: AButton(
text: _subtitle?.update??"",
text: _subtitle?.update ?? "",
onPressed: _update,
),
),
const SizedBox(height: 100,)
const SizedBox(
height: 100,
)
],
),
),
@ -216,4 +220,3 @@ class _UpdateDeviceTransferState extends State<UpdateDeviceTransfer> {
);
}
}

@ -1,11 +1,9 @@
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart';
import '../../controllers/http_status_manger/http_status_manger.dart';
import '../../controllers/localization/localization.dart';
import '../../controllers/providers/api/user_provider.dart';
import '../../controllers/providers/settings/setting_provider.dart';
import '../../controllers/providers/user_provider.dart';
import '../../controllers/validator/validator.dart';
import '../../models/subtitle.dart';
import '../../models/user.dart';
@ -13,7 +11,6 @@ import '../app_style/sizing.dart';
import '../widgets/app_text_form_field.dart';
import '../widgets/buttons/app_button.dart';
import '../widgets/loaders/loading_manager.dart';
import 'user/land_page.dart';
class Login extends StatefulWidget {
static const String id = "/login";
@ -21,18 +18,16 @@ class Login extends StatefulWidget {
const Login({super.key});
@override
_LoginState createState() => _LoginState();
LoginState createState() => LoginState();
}
class _LoginState extends State<Login> {
UserProvider? _userProvider;
SettingProvider? _settingProvider;
final User _user = User();
class LoginState extends State<Login> {
late UserProvider _userProvider;
late SettingProvider _settingProvider;
bool _obscurePassword = true;
final bool _firstTime = true;
late double _height;
late double _width;
late String _payload;
final User _user = User();
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
@ -41,14 +36,12 @@ class _LoginState extends State<Login> {
_userProvider = Provider.of<UserProvider>(context);
_settingProvider = Provider.of<SettingProvider>(context);
_height = MediaQuery.of(context).size.height;
_width = MediaQuery.of(context).size.width;
Subtitle? subtitle = AppLocalization.of(context)?.subtitle;
return Scaffold(
key: _scaffoldKey,
body: SafeArea(
child: LoadingManager(
isLoading: (_userProvider?.isLoading ?? false) ||
!(_settingProvider?.isLoaded ?? false),
isLoading: (_userProvider.loading) || !(_settingProvider.isLoaded),
isFailedLoading: false,
stateCode: 200,
onRefresh: () async {},
@ -71,9 +64,7 @@ class _LoginState extends State<Login> {
),
),
Padding(
padding: EdgeInsets.symmetric(
horizontal: 24 * AppStyle.getScaleFactor(context),
vertical: 24 * AppStyle.getScaleFactor(context)),
padding: EdgeInsets.symmetric(horizontal: 24 * AppStyle.getScaleFactor(context), vertical: 24 * AppStyle.getScaleFactor(context)),
child: Column(
children: [
SizedBox(
@ -85,12 +76,12 @@ class _LoginState extends State<Login> {
textAlign: TextAlign.left,
style: Theme.of(context).textTheme.bodyLarge,
prefixIconData: Icons.account_circle,
validator: (value) => Validator.hasValue(value ?? '')
? null
: subtitle?.nameValidateMessage,
validator: (value) => Validator.hasValue(value ?? '') ? null : subtitle?.nameValidateMessage,
textInputType: TextInputType.name,
onSaved: (value) {
_user.userName = value!;
if (value != null) {
_user.userName = value;
}
},
),
const SizedBox(height: 12),
@ -98,13 +89,10 @@ class _LoginState extends State<Login> {
initialValue: _user.password,
hintText: subtitle?.password ?? "",
obscureText: _obscurePassword,
style: Theme.of(context).textTheme.bodyText1,
style: Theme.of(context).textTheme.bodyLarge,
prefixIconData: Icons.vpn_key_sharp,
textAlign: TextAlign.left,
validator: (value) =>
Validator.isValidPassword(value ?? '')
? null
: subtitle?.passwordValidateMessage,
validator: (value) => Validator.isValidPassword(value ?? '') ? null : subtitle?.passwordValidateMessage,
showPassword: () {
_obscurePassword = !_obscurePassword;
setState(() {});
@ -119,35 +107,9 @@ class _LoginState extends State<Login> {
AButton(
text: subtitle?.signIn ?? "",
onPressed: () async {
if (!(_formKey.currentState?.validate() ?? true)) {
return;
}
_formKey.currentState?.save();
int? status = await _userProvider?.login(
user: _user,
host: _settingProvider?.host ?? "",
);
if (status != null &&
status >= 200 &&
status < 300) {
_settingProvider
?.setUser(_userProvider?.user ?? User());
if (_userProvider?.user?.isActive ?? false) {
Navigator.of(context).pushNamed(LandPage.id);
} else {
Fluttertoast.showToast(
msg: subtitle?.activationAlert ?? "",
);
}
} else {
String errorMessage = status == 400
? subtitle?.wrongEmailOrPassword ?? ""
: HttpStatusManger.getStatusMessage(
status: status, subtitle: subtitle);
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(
content: Text(errorMessage),
));
if (_formKey.currentState?.validate() ?? false) {
_formKey.currentState?.save();
await _userProvider.login(context, user: _user);
}
},
),

@ -1,12 +1,9 @@
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:provider/provider.dart';
import '../../controllers/http_status_manger/http_status_manger.dart';
import '../../controllers/localization/localization.dart';
import '../../controllers/providers/api/user_provider.dart';
import '../../controllers/providers/settings/setting_provider.dart';
import '../../controllers/providers/user_provider.dart';
import '../../controllers/validator/validator.dart';
import '../../models/hospital.dart';
import '../../models/subtitle.dart';
@ -18,20 +15,19 @@ import '../widgets/departments/department_button.dart';
import '../widgets/hospitals/hospital_button.dart';
import '../widgets/loaders/loading_manager.dart';
class Register extends StatefulWidget {
static final String id = "/register";
static const String id = "/register";
const Register({super.key});
@override
_RegisterState createState() => _RegisterState();
RegisterState createState() => RegisterState();
}
class _RegisterState extends State<Register> {
UserProvider? _userProvider;
SettingProvider? _settingProvider;
late double _width;
class RegisterState extends State<Register> {
late UserProvider _userProvider;
late double _height;
User _user = User();
final User _user = User();
bool _obscurePassword = true;
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
@ -39,14 +35,12 @@ class _RegisterState extends State<Register> {
@override
Widget build(BuildContext context) {
_userProvider = Provider.of<UserProvider>(context);
_settingProvider = Provider.of<SettingProvider>(context);
_width = MediaQuery.of(context).size.width;
_height = MediaQuery.of(context).size.height;
Subtitle? _subtitle = AppLocalization.of(context)?.subtitle;
Subtitle? subtitle = AppLocalization.of(context)?.subtitle;
return Scaffold(
key: _scaffoldKey,
body: LoadingManager(
isLoading: _userProvider?.isLoading??false,
isLoading: _userProvider.loading,
isFailedLoading: false,
stateCode: 200,
onRefresh: () async {},
@ -66,16 +60,16 @@ class _RegisterState extends State<Register> {
padding: const EdgeInsets.all(16),
child: Image(
height: _height / 6,
image: AssetImage("assets/images/logo.png"),
image: const AssetImage("assets/images/logo.png"),
),
),
),
ATextFormField(
initialValue: _user.userName,
hintText: _subtitle?.name??"",
hintText: subtitle?.name ?? "",
prefixIconData: Icons.account_circle,
style: Theme.of(context).textTheme.headline6,
validator: (value) => Validator.hasValue(value!) ? '' : _subtitle?.nameValidateMessage??"",
style: Theme.of(context).textTheme.titleLarge,
validator: (value) => Validator.hasValue(value!) ? '' : subtitle?.nameValidateMessage ?? "",
onSaved: (value) {
_user.userName = value!;
},
@ -83,11 +77,11 @@ class _RegisterState extends State<Register> {
const SizedBox(height: 12),
ATextFormField(
initialValue: _user.email,
hintText: _subtitle?.email??"",
hintText: subtitle?.email ?? "",
prefixIconData: Icons.email,
textInputType: TextInputType.emailAddress,
style: Theme.of(context).textTheme.headline6,
validator: (value) => Validator.isEmail(value!) ? '' : _subtitle?.emailValidateMessage??"",
style: Theme.of(context).textTheme.titleLarge,
validator: (value) => Validator.isEmail(value!) ? '' : subtitle?.emailValidateMessage ?? "",
onSaved: (value) {
_user.email = value!;
},
@ -95,11 +89,11 @@ class _RegisterState extends State<Register> {
const SizedBox(height: 12),
ATextFormField(
initialValue: _user.password,
hintText: _subtitle?.password??"",
hintText: subtitle?.password ?? "",
prefixIconData: Icons.vpn_key_sharp,
style: Theme.of(context).textTheme.headline6,
style: Theme.of(context).textTheme.titleLarge,
obscureText: _obscurePassword,
validator: (value) => Validator.isValidPassword(value!) ? '' : _subtitle?.passwordValidateMessage??'',
validator: (value) => Validator.isValidPassword(value!) ? '' : subtitle?.passwordValidateMessage ?? '',
showPassword: () {
_obscurePassword = !_obscurePassword;
setState(() {});
@ -115,10 +109,10 @@ class _RegisterState extends State<Register> {
ATextFormField(
initialValue: _user.password,
prefixIconData: Icons.vpn_key_sharp,
hintText: _subtitle?.confirmPassword??"",
style: Theme.of(context).textTheme.headline6,
hintText: subtitle?.confirmPassword ?? "",
style: Theme.of(context).textTheme.titleLarge,
obscureText: _obscurePassword,
validator: (value) => _user.password == value ? '' : _subtitle?.confirmPasswordValidateMessage??"",
validator: (value) => _user.password == value ? '' : subtitle?.confirmPasswordValidateMessage ?? "",
showPassword: () {
_obscurePassword = !_obscurePassword;
setState(() {});
@ -126,7 +120,7 @@ class _RegisterState extends State<Register> {
),
const SizedBox(height: 12),
HospitalButton(
hospital: _user.hospital??Hospital(),
hospital: _user.hospital ?? Hospital(),
onHospitalPick: (hospital) {
_user.hospital = hospital;
setState(() {});
@ -142,24 +136,24 @@ class _RegisterState extends State<Register> {
),
const SizedBox(height: 12),
ATextFormField(
initialValue: _user.phoneNumber??"",
hintText: _subtitle?.phoneNumber??"",
style: Theme.of(context).textTheme.headline6,
initialValue: _user.phoneNumber ?? "",
hintText: subtitle?.phoneNumber ?? "",
style: Theme.of(context).textTheme.titleLarge,
prefixIconData: Icons.phone_android,
validator: (value) => Validator.isPhoneNumber(value!) ? '' : _subtitle?.phoneNumberValidateMessage??"",
validator: (value) => Validator.isPhoneNumber(value!) ? '' : subtitle?.phoneNumberValidateMessage ?? "",
textInputType: TextInputType.phone,
onSaved: (value) {
_user.phoneNumber = value;
},
),
SizedBox(height: 8),
const SizedBox(height: 8),
ATextFormField(
initialValue: _user.whatsApp??"",
hintText: _subtitle?.whatsApp??"",
style: Theme.of(context).textTheme.headline6,
initialValue: _user.whatsApp ?? "",
hintText: subtitle?.whatsApp ?? "",
style: Theme.of(context).textTheme.titleLarge,
prefixIconData: FontAwesomeIcons.whatsapp,
prefixIconSize: 36,
validator: (value) => (Validator.isPhoneNumber(value!)) ? "" : _subtitle?.phoneNumberValidateMessage??"",
validator: (value) => (Validator.isPhoneNumber(value!)) ? "" : subtitle?.phoneNumberValidateMessage ?? "",
textInputType: TextInputType.phone,
onSaved: (value) {
_user.whatsApp = value;
@ -167,45 +161,18 @@ class _RegisterState extends State<Register> {
),
const SizedBox(height: 12),
AButton(
text: _subtitle?.signUp??"",
text: subtitle?.signUp ?? "",
onPressed: () async {
if (!(_formKey.currentState?.validate()??false)) return;
_formKey.currentState?.save();
if (_user.hospital == null) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(_subtitle?.hospitalRequired??""),
));
return;
}
if (_user.department == null) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(_subtitle?.unitRequired??""),
));
return;
}
int? status = await _userProvider?.register(
user: _user,
host: _settingProvider?.host??"",
);
if (status != null && status >= 200 && status < 300) {
Fluttertoast.showToast(msg: _subtitle?.activationAlert??"");
Navigator.of(context).pop();
} else {
String? errorMessage = status == 402
? _subtitle?.nameExist
: status == 401
? _subtitle?.emailExist
: HttpStatusManger.getStatusMessage(status: status, subtitle: _subtitle);
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(errorMessage??""),
));
if (_formKey.currentState?.validate() ?? false) {
_formKey.currentState?.save();
await _userProvider.register(context, newUser: _user);
}
},
),
],
),
),
ABackButton(),
const ABackButton(),
],
),
),

@ -5,9 +5,9 @@ import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flare_flutter/flare_actor.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/api/login_api_client.dart';
import '../../controllers/notification/notification_manger.dart';
import '../../controllers/providers/api/user_provider.dart';
import '../../controllers/providers/settings/setting_provider.dart';
import '../../models/app_notification.dart';
import '../../models/user.dart';
@ -24,11 +24,10 @@ class SplashScreen extends StatefulWidget {
}
class _SplashScreenState extends State<SplashScreen> {
SettingProvider? _settingProvider;
UserProvider? _userProvider;
late SettingProvider _settingProvider;
_goToUserScreen(User? user) {
_userProvider?.user = user;
UserApiClient().user = user;
// Navigator.of(context).pushNamed(Login.id);
Navigator.of(context).pushNamed(LandPage.id);
}
@ -36,14 +35,12 @@ class _SplashScreenState extends State<SplashScreen> {
@override
void initState() {
Firebase.initializeApp();
NotificationManger.initialisation((notificationDetails) {
AppNotification notification = AppNotification.fromJson(
json.decode(notificationDetails.payload ?? ""));
if (notification.path == null || (notification.path?.isEmpty ?? false))
AppNotification notification = AppNotification.fromJson(json.decode(notificationDetails.payload ?? ""));
if (notification.path == null || (notification.path?.isEmpty ?? false)) {
return;
Navigator.pushNamed(context, notification.path ?? "",
arguments: notification.requestId);
}
Navigator.pushNamed(context, notification.path ?? "", arguments: notification.requestId);
}, (id, title, body, payload) async {});
super.initState();
}
@ -51,7 +48,6 @@ class _SplashScreenState extends State<SplashScreen> {
@override
Widget build(BuildContext context) {
_settingProvider = Provider.of<SettingProvider>(context, listen: false);
_userProvider = Provider.of<UserProvider>(context, listen: false);
return Scaffold(
backgroundColor: Colors.white,
body: Center(
@ -62,11 +58,12 @@ class _SplashScreenState extends State<SplashScreen> {
fit: BoxFit.contain,
animation: "splash",
callback: (animation) async {
print(await FirebaseMessaging.instance.getToken());
Navigator.of(context).pushNamed(Login.id);
if ((_settingProvider?.isLoaded ?? false) &&
_settingProvider?.user != null) {
_goToUserScreen(_settingProvider?.user);
debugPrint(await FirebaseMessaging.instance.getToken());
if (context.mounted) {
Navigator.of(context).pushNamed(Login.id);
if (_settingProvider.isLoaded && _settingProvider.user != null) {
_goToUserScreen(_settingProvider.user);
}
}
},
),

@ -2,11 +2,12 @@ import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart';
import '../../../../api/login_api_client.dart';
import '../../../../controllers/http_status_manger/http_status_manger.dart';
import '../../../../controllers/localization/localization.dart';
import '../../../../controllers/providers/api/gas_refill_provider.dart';
import '../../../../controllers/providers/api/user_provider.dart';
import '../../../../controllers/providers/settings/setting_provider.dart';
import '../../../../controllers/providers/user_provider.dart';
import '../../../../models/enums/user_types.dart';
import '../../../../models/gas_refill/gas_refill_model.dart';
import '../../../../models/subtitle.dart';
@ -22,6 +23,7 @@ import '../../../widgets/requests/info_row.dart';
import '../../../widgets/requests/request_status.dart';
import '../../../widgets/status/gas_refill/gas_status.dart';
import '../../../widgets/titles/app_sub_title.dart';
class GasRefillDetails extends StatefulWidget {
final GasRefillModel? model;
const GasRefillDetails({Key? key, this.model}) : super(key: key);
@ -31,7 +33,6 @@ class GasRefillDetails extends StatefulWidget {
}
class _GasRefillDetailsState extends State<GasRefillDetails> {
final GasRefillModel _model = GasRefillModel();
bool _enableEdit = false;
bool _validate = false;
@ -44,45 +45,35 @@ class _GasRefillDetailsState extends State<GasRefillDetails> {
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
_update() async {
_validate = true;
if(!(_formKey.currentState?.validate()??false)){
if (!(_formKey.currentState?.validate() ?? false)) {
setState(() {});
return false;
}
_formKey.currentState?.save();
_isLoading =true;
_isLoading = true;
setState(() {});
int? status = await _gasRefillProvider?.updateModel(
user: _userProvider?.user??User(),
host: _settingProvider?.host??"",
newModel: _model,
oldModel: widget.model
);
_isLoading =false;
int? status = await _gasRefillProvider?.updateModel(user: UserApiClient().user ?? User(), host: _settingProvider?.host ?? "", newModel: _model, oldModel: widget.model);
_isLoading = false;
setState(() {});
if(status != null && status >= 200 && status < 300){
if (status != null && status >= 200 && status < 300) {
Fluttertoast.showToast(
msg: _subtitle?.requestCompleteSuccessfully??"",
msg: _subtitle?.requestCompleteSuccessfully ?? "",
);
_enableEdit = false;
_validate = false;
//Navigator.of(context).pop();
}else{
String errorMessage = HttpStatusManger.getStatusMessage(
status: status, subtitle: _subtitle);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
errorMessage
),
)
);
} else {
String errorMessage = HttpStatusManger.getStatusMessage(status: status, subtitle: _subtitle);
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(errorMessage),
));
}
}
@override
void initState() {
_model.fromGasRefillModel(widget.model??GasRefillModel());
_model.fromGasRefillModel(widget.model ?? GasRefillModel());
super.initState();
}
@ -106,108 +97,117 @@ class _GasRefillDetailsState extends State<GasRefillDetails> {
children: [
Container(
color: Theme.of(context).colorScheme.primary,
padding: const EdgeInsets.symmetric(horizontal: 0,vertical: 4),
padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 4),
child: Row(
children: [
ABackButton(),
Expanded(
child: Center(
child: Text(
_subtitle?.details??"",
style: Theme.of(context).textTheme.headline6?.copyWith(
color: AColors.white,
fontStyle: FontStyle.italic
),
_subtitle?.details ?? "",
style: Theme.of(context).textTheme.headline6?.copyWith(color: AColors.white, fontStyle: FontStyle.italic),
),
),
),
if(_userProvider?.user?.type == UsersTypes.engineer)
AIconButton(
iconData: _enableEdit ? Icons.cancel : Icons.edit,
color: Theme.of(context).colorScheme.onPrimary,
buttonSize: 42,
backgroundColor: AColors.green,
onPressed: () async {
_enableEdit = !_enableEdit;
_model.fromGasRefillModel(widget.model??GasRefillModel());
setState(() {});
},
),
const SizedBox(width: 16,)
if (UserApiClient().user?.type == UsersTypes.engineer)
AIconButton(
iconData: _enableEdit ? Icons.cancel : Icons.edit,
color: Theme.of(context).colorScheme.onPrimary,
buttonSize: 42,
backgroundColor: AColors.green,
onPressed: () async {
_enableEdit = !_enableEdit;
_model.fromGasRefillModel(widget.model ?? GasRefillModel());
setState(() {});
},
),
const SizedBox(
width: 16,
)
],
),
),
Expanded(
child: SingleChildScrollView(
padding: EdgeInsets.all(16*AppStyle.getScaleFactor(context)),
padding: EdgeInsets.all(16 * AppStyle.getScaleFactor(context)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
RequestInfoRow(
title: _subtitle?.title??"",
info: _model.title??"",
title: _subtitle?.title ?? "",
info: _model.title ?? "",
),
RequestInfoRow(
title: _subtitle?.hospital??"",
info: _model.clientName??"",
title: _subtitle?.hospital ?? "",
info: _model.clientName ?? "",
),
_enableEdit ?
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 8,),
ASubTitle(_subtitle?.status??""),
if(_validate && _model.status == null)
ASubTitle(_subtitle?.requiredWord??"",color: Colors.red,),
const SizedBox(height: 4,),
GasStatusMenu(
initialValue: _model.status,
onSelect: (status){
_model.status = status;
},
)
],
):
Row(
children: [
Expanded(
child: Text(
"${_subtitle?.status} : ",
style: Theme.of(context).textTheme.subtitle2,
textScaleFactor: AppStyle.getScaleFactor(context),
_enableEdit
? Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(
height: 8,
),
ASubTitle(_subtitle?.status ?? ""),
if (_validate && _model.status == null)
ASubTitle(
_subtitle?.requiredWord ?? "",
color: Colors.red,
),
const SizedBox(
height: 4,
),
GasStatusMenu(
initialValue: _model.status,
onSelect: (status) {
_model.status = status;
},
)
],
)
: Row(
children: [
Expanded(
child: Text(
"${_subtitle?.status} : ",
style: Theme.of(context).textTheme.subtitle2,
textScaleFactor: AppStyle.getScaleFactor(context),
),
),
StatusLabel(label: _model.status?.label ?? "", color: AColors.getGasStatusColor(_model.status?.id ?? 0)),
],
),
),
StatusLabel(label: _model.status?.label??"",
color: AColors.getGasStatusColor(_model.status?.id??0)
),
],
const SizedBox(
height: 8,
),
const SizedBox(height: 8,),
const ASubTitle("Gas Requests"),
const SizedBox(height: 8,),
const SizedBox(
height: 8,
),
ListView.builder(
shrinkWrap: true,
physics: const ClampingScrollPhysics(),
itemCount: _model.details?.length,
itemBuilder: (context,index){
itemBuilder: (context, index) {
final details = _model.details![index];
return GasRefillUpdateDetailsItem(
details: details,
validate: _validate,
enableEdit: _enableEdit,
);
}
),
if(_enableEdit)
Column(
children: [
const SizedBox(height: 16,),
AButton(
text: _subtitle?.update??"",
onPressed: _update,
),
],
),
}),
if (_enableEdit)
Column(
children: [
const SizedBox(
height: 16,
),
AButton(
text: _subtitle?.update ?? "",
onPressed: _update,
),
],
),
],
),
),

@ -2,11 +2,12 @@ import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart';
import '../../../../api/login_api_client.dart';
import '../../../../controllers/http_status_manger/http_status_manger.dart';
import '../../../../controllers/localization/localization.dart';
import '../../../../controllers/providers/api/gas_refill_provider.dart';
import '../../../../controllers/providers/api/user_provider.dart';
import '../../../../controllers/providers/settings/setting_provider.dart';
import '../../../../controllers/providers/user_provider.dart';
import '../../../../controllers/validator/validator.dart';
import '../../../../models/gas_refill/gas_refill_details.dart';
import '../../../../models/gas_refill/gas_refill_model.dart';
@ -19,6 +20,7 @@ import '../../../widgets/gas_refill/gas_refill_create_details_item.dart';
import '../../../widgets/loaders/loading_manager.dart';
import '../../../widgets/status/gas_refill/gas_type.dart';
import '../../../widgets/titles/app_sub_title.dart';
class RequestGasRefill extends StatefulWidget {
static const String id = "/request-gas-refill";
const RequestGasRefill({Key? key}) : super(key: key);
@ -42,57 +44,51 @@ class _RequestGasRefillState extends State<RequestGasRefill> {
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
@override
void setState(VoidCallback fn){
if(mounted) super.setState(() {});
void setState(VoidCallback fn) {
if (mounted) super.setState(() {});
}
_onSubmit() async {
if((_formModel.details?.isEmpty??false)){
if(!_addNewModel()) return;
if ((_formModel.details?.isEmpty ?? false)) {
if (!_addNewModel()) return;
}
_isLoading =true;
_isLoading = true;
setState(() {});
int? status = await _gasRefillProvider?.createModel(
user: _userProvider?.user??User(),
host: _settingProvider?.host??"",
user: UserApiClient().user ?? User(),
host: _settingProvider?.host ?? "",
model: _formModel,
);
_isLoading =false;
_isLoading = false;
setState(() {});
if(status != null && status >= 200 && status < 300){
if (status != null && status >= 200 && status < 300) {
Fluttertoast.showToast(
msg: _subtitle?.requestCompleteSuccessfully??"",
msg: _subtitle?.requestCompleteSuccessfully ?? "",
);
Navigator.of(context).pop();
}else{
String errorMessage = HttpStatusManger.getStatusMessage(
status: status, subtitle: _subtitle);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
errorMessage
),
)
);
} else {
String errorMessage = HttpStatusManger.getStatusMessage(status: status, subtitle: _subtitle);
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(errorMessage),
));
}
}
bool _addNewModel(){
bool _addNewModel() {
_validate = true;
if(!(_formKey.currentState?.validate()??false)){
if (!(_formKey.currentState?.validate() ?? false)) {
setState(() {});
return false;
}
_formKey.currentState?.save();
if(!_currentDetails.validate()) {
setState(() { });
if (!_currentDetails.validate()) {
setState(() {});
return false;
}
_formModel.details?.insert(0,_currentDetails);
_formModel.details?.insert(0, _currentDetails);
_validate = false;
Scrollable.ensureVisible(_DetailsKey.currentContext!);
_requestedQuantityController.clear();
@ -106,12 +102,13 @@ class _RequestGasRefillState extends State<RequestGasRefill> {
_requestedQuantityController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
_subtitle = AppLocalization.of(context)?.subtitle;
_userProvider = Provider.of<UserProvider>(context);
_settingProvider = Provider.of<SettingProvider>(context);
_gasRefillProvider = Provider.of<GasRefillProvider>(context,listen: false);
_gasRefillProvider = Provider.of<GasRefillProvider>(context, listen: false);
return Scaffold(
key: _scaffoldKey,
body: Form(
@ -132,11 +129,7 @@ class _RequestGasRefillState extends State<RequestGasRefill> {
padding: const EdgeInsets.all(8.0),
child: Text(
"Request Gas Refill",
style: Theme.of(context).textTheme.headline5?.copyWith(
color: Theme.of(context).primaryColor,
fontSize: 28,
fontWeight: FontWeight.bold
),
style: Theme.of(context).textTheme.headline5?.copyWith(color: Theme.of(context).primaryColor, fontSize: 28, fontWeight: FontWeight.bold),
),
),
),
@ -167,14 +160,21 @@ class _RequestGasRefillState extends State<RequestGasRefill> {
// ),
// const SizedBox(height: 8,),
// Divider(color: Theme.of(context).colorScheme.primary,),
const SizedBox(height: 4,),
const SizedBox(
height: 4,
),
const ASubTitle("Type"),
if(_validate && _currentDetails.type == null)
ASubTitle(_subtitle?.requiredWord??"",color: Colors.red,),
const SizedBox(height: 4,),
if (_validate && _currentDetails.type == null)
ASubTitle(
_subtitle?.requiredWord ?? "",
color: Colors.red,
),
const SizedBox(
height: 4,
),
GasTypeMenu(
initialValue: _currentDetails.type,
onSelect: (status){
onSelect: (status) {
_currentDetails.type = status;
},
),
@ -190,53 +190,58 @@ class _RequestGasRefillState extends State<RequestGasRefill> {
// _currentDetails.cylinderSize = status;
// },
// ),
const SizedBox(height: 8,),
ASubTitle(_subtitle?.quantity??""),
if(_validate && _currentDetails.requestedQuantity == null)
ASubTitle(_subtitle?.requiredWord??"",color: Colors.red,),
SizedBox(height: 4,),
const SizedBox(
height: 8,
),
ASubTitle(_subtitle?.quantity ?? ""),
if (_validate && _currentDetails.requestedQuantity == null)
ASubTitle(
_subtitle?.requiredWord ?? "",
color: Colors.red,
),
SizedBox(
height: 4,
),
ATextFormField(
initialValue: (_currentDetails?.requestedQuantity ?? "").toString(),
textAlign: TextAlign.center,
controller: _requestedQuantityController,
style: Theme.of(context).textTheme.subtitle1,
validator: (value) =>
Validator.isNumeric(value!)
? '' : "allow numbers only",
validator: (value) => Validator.isNumeric(value!) ? '' : "allow numbers only",
textInputType: TextInputType.number,
onSaved: (value){
onSaved: (value) {
_currentDetails.requestedQuantity = int.tryParse(value!);
},
),
const SizedBox(height: 16),
AButton(
text: _subtitle?.add??"",
text: _subtitle?.add ?? "",
onPressed: _addNewModel,
),
if((_formModel.details?.isNotEmpty??false))
const ASubTitle("Gas Requests"),
if ((_formModel.details?.isNotEmpty ?? false)) const ASubTitle("Gas Requests"),
ListView.builder(
key: _DetailsKey,
shrinkWrap: true,
physics: const ClampingScrollPhysics(),
itemCount: _formModel.details?.length,
itemBuilder: (context,index){
final model = _formModel.details![index];
return GasRefillCreateDetailsItem(
model: model,
onDelete: (){
_formModel.details?.remove(model);
setState(() {});
},
);
}
),
key: _DetailsKey,
shrinkWrap: true,
physics: const ClampingScrollPhysics(),
itemCount: _formModel.details?.length,
itemBuilder: (context, index) {
final model = _formModel.details![index];
return GasRefillCreateDetailsItem(
model: model,
onDelete: () {
_formModel.details?.remove(model);
setState(() {});
},
);
}),
const SizedBox(height: 16),
AButton(
text: _subtitle?.submit??"",
text: _subtitle?.submit ?? "",
onPressed: _onSubmit,
),
const SizedBox(height: 100,)
const SizedBox(
height: 100,
)
],
),
),
@ -246,4 +251,3 @@ class _RequestGasRefillState extends State<RequestGasRefill> {
);
}
}

@ -1,10 +1,11 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../../../api/login_api_client.dart';
import '../../../../controllers/localization/localization.dart';
import '../../../../controllers/providers/api/gas_refill_provider.dart';
import '../../../../controllers/providers/api/user_provider.dart';
import '../../../../controllers/providers/settings/setting_provider.dart';
import '../../../../controllers/providers/user_provider.dart';
import '../../../../models/subtitle.dart';
import '../../../../models/user.dart';
import '../../../app_style/colors.dart';
@ -21,8 +22,7 @@ class TrackGasRefillPage extends StatefulWidget {
State<TrackGasRefillPage> createState() => _TrackGasRefillPageState();
}
class _TrackGasRefillPageState extends State<TrackGasRefillPage>
with TickerProviderStateMixin{
class _TrackGasRefillPageState extends State<TrackGasRefillPage> with TickerProviderStateMixin {
GasRefillProvider? _gasRefillProvider;
UserProvider? _userProvider;
SettingProvider? _settingProvider;
@ -42,8 +42,8 @@ class _TrackGasRefillPageState extends State<TrackGasRefillPage>
onRefresh: () async {
_gasRefillProvider?.reset();
await _gasRefillProvider?.getRequests(
user: _userProvider?.user??User(),
host: _settingProvider?.host??"",
user: UserApiClient().user ?? User(),
host: _settingProvider?.host ?? "",
);
},
child: Stack(
@ -51,8 +51,8 @@ class _TrackGasRefillPageState extends State<TrackGasRefillPage>
Column(
children: [
Container(
color:AColors.white,
padding: const EdgeInsets.symmetric(horizontal: 0,vertical: 4),
color: AColors.white,
padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 4),
child: Column(
children: [
Row(
@ -61,36 +61,33 @@ class _TrackGasRefillPageState extends State<TrackGasRefillPage>
Expanded(
child: Center(
child: Text(
_subtitle?.serviceRequests??"",
style: Theme.of(context).textTheme.headline6?.copyWith(
color: AColors.grey3A,
fontStyle: FontStyle.italic
),
_subtitle?.serviceRequests ?? "",
style: Theme.of(context).textTheme.headline6?.copyWith(color: AColors.grey3A, fontStyle: FontStyle.italic),
),
),
),
const SizedBox(width: 48,)
const SizedBox(
width: 48,
)
],
),
],
),
),
Expanded(
child: GasRefillList(
nextPage: _gasRefillProvider?.nextPage??false,
nextPage: _gasRefillProvider?.nextPage ?? false,
onLazyLoad: () async {
await _gasRefillProvider?.getRequests(
user: _userProvider?.user??User(),
host: _settingProvider?.host??"",
user: UserApiClient().user ?? User(),
host: _settingProvider?.host ?? "",
);
},
items: _gasRefillProvider?.items??[],
items: _gasRefillProvider?.items ?? [],
),
),
],
),
],
),
),

@ -8,6 +8,7 @@ import 'package:provider/provider.dart';
import 'package:share/share.dart';
import 'package:url_launcher/url_launcher.dart';
import '../../../api/login_api_client.dart';
import '../../../controllers/localization/localization.dart';
import '../../../controllers/notification/firebase_notification_manger.dart';
import '../../../controllers/providers/api/departments_provider.dart';
@ -15,8 +16,8 @@ import '../../../controllers/providers/api/devices_provider.dart';
import '../../../controllers/providers/api/preventive_maintenance_visits_provider.dart';
import '../../../controllers/providers/api/regular_visits_provider.dart';
import '../../../controllers/providers/api/service_requests_provider.dart';
import '../../../controllers/providers/api/user_provider.dart';
import '../../../controllers/providers/settings/setting_provider.dart';
import '../../../controllers/providers/user_provider.dart';
import '../../../extensions/int_extensions.dart';
import '../../../extensions/widget_extensions.dart';
import '../../../models/enums/user_types.dart';
@ -80,14 +81,12 @@ class _LandPageState extends State<LandPage> {
_departmentsProvider = Provider.of<DepartmentsProvider>(context);
_devicesProvider = Provider.of<DevicesProvider>(context);
_serviceRequestsProvider = Provider.of<ServiceRequestsProvider>(context);
_preventiveMaintenanceVisitsProvider =
Provider.of<PreventiveMaintenanceVisitsProvider>(context);
_preventiveMaintenanceVisitsProvider = Provider.of<PreventiveMaintenanceVisitsProvider>(context);
_regularVisitsProvider = Provider.of<RegularVisitsProvider>(context);
Subtitle _subtitle = AppLocalization.of(context)!.subtitle!;
if (firstTime) {
if (path != null) {
Navigator.of(context).pushNamed("/" + path.split("/").first,
arguments: path.split("/").last);
Navigator.of(context).pushNamed("/" + path.split("/").first, arguments: path.split("/").last);
}
firstTime = false;
}
@ -154,21 +153,19 @@ class _LandPageState extends State<LandPage> {
mainAxisSpacing: 12,
childAspectRatio: 1,
children: [
if (_userProvider.user!.type == UsersTypes.normal_user)
if (UserApiClient().user!.type == UsersTypes.normal_user)
LandPageItem(
text: _subtitle.newServiceRequest,
icon: FontAwesomeIcons.tools,
onPressed: () {
Navigator.of(context)
.pushNamed(CreateRequestPage.id);
Navigator.of(context).pushNamed(CreateRequestPage.id);
},
),
LandPageItem(
text: _subtitle.trackServiceRequest,
icon: FontAwesomeIcons.tasks,
onPressed: () {
Navigator.of(context)
.pushNamed(ServiceRequestsPage.id);
Navigator.of(context).pushNamed(ServiceRequestsPage.id);
},
),
//if (_userProvider.user.type == UsersTypes.engineer)
@ -187,37 +184,33 @@ class _LandPageState extends State<LandPage> {
// Navigator.of(context).pushNamed(PreventiveMaintenanceVisitsPage.id);
// },
// ),
if (_userProvider.user?.type != UsersTypes.engineer)
if (UserApiClient().user?.type != UsersTypes.engineer)
LandPageItem(
text: "Request Gas Refill",
icon: FontAwesomeIcons.truckFast,
onPressed: () {
Navigator.of(context)
.pushNamed(RequestGasRefill.id);
Navigator.of(context).pushNamed(RequestGasRefill.id);
},
),
LandPageItem(
text: "Track Gas Refill",
icon: Icons.content_paste_search,
onPressed: () {
Navigator.of(context)
.pushNamed(TrackGasRefillPage.id);
Navigator.of(context).pushNamed(TrackGasRefillPage.id);
},
),
LandPageItem(
text: "transfer Device",
icon: FontAwesomeIcons.rightLeft,
onPressed: () {
Navigator.of(context)
.pushNamed(RequestDeviceTransfer.id);
Navigator.of(context).pushNamed(RequestDeviceTransfer.id);
},
),
LandPageItem(
text: "Track Device Transfer",
icon: FontAwesomeIcons.peopleCarryBox,
onPressed: () {
Navigator.of(context)
.pushNamed(TrackDeviceTransferPage.id);
Navigator.of(context).pushNamed(TrackDeviceTransferPage.id);
},
),
],
@ -250,8 +243,7 @@ class _LandPageState extends State<LandPage> {
Align(
alignment: Alignment.topRight,
child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
child: AIconButton(
iconData: Icons.menu,
color: AColors.primaryColor,
@ -283,10 +275,7 @@ class _LandPageState extends State<LandPage> {
height: 50 * AppStyle.getScaleFactor(context),
width: 50 * AppStyle.getScaleFactor(context),
padding: EdgeInsets.all(4),
decoration: BoxDecoration(
border: Border.all(
color: Theme.of(context).primaryColor, width: 2),
shape: BoxShape.circle),
decoration: BoxDecoration(border: Border.all(color: Theme.of(context).primaryColor, width: 2), shape: BoxShape.circle),
child: ClipOval(
child: ClipOval(
child: Icon(
@ -299,7 +288,7 @@ class _LandPageState extends State<LandPage> {
),
12.width,
Text(
_userProvider.user?.userName ?? "",
UserApiClient().user?.userName ?? "",
style: Theme.of(context).textTheme.headline6?.copyWith(
fontWeight: FontWeight.w600,
),
@ -326,10 +315,7 @@ class _LandPageState extends State<LandPage> {
}),
Text(
"English",
style: Theme.of(context)
.textTheme
.bodyText1
?.copyWith(color: AColors.grey3A),
style: Theme.of(context).textTheme.bodyText1?.copyWith(color: AColors.grey3A),
textScaleFactor: AppStyle.getScaleFactor(context),
),
Radio(
@ -342,10 +328,7 @@ class _LandPageState extends State<LandPage> {
}),
Text(
"عربي",
style: Theme.of(context)
.textTheme
.bodyText1
?.copyWith(color: AColors.grey3A),
style: Theme.of(context).textTheme.bodyText1?.copyWith(color: AColors.grey3A),
textScaleFactor: AppStyle.getScaleFactor(context),
),
],
@ -389,12 +372,8 @@ class _LandPageState extends State<LandPage> {
icon: Icons.share,
title: _subtitle.shareApp,
onPressed: () async {
PackageInfo packageInfo =
await PackageInfo.fromPlatform();
String shareLink =
"\n https://play.google.com/store/apps/details?id=" +
packageInfo.packageName +
"\n https://apps.apple.com/us/app/";
PackageInfo packageInfo = await PackageInfo.fromPlatform();
String shareLink = "\n https://play.google.com/store/apps/details?id=" + packageInfo.packageName + "\n https://apps.apple.com/us/app/";
Share.share(shareLink);
},
),
@ -406,15 +385,11 @@ class _LandPageState extends State<LandPage> {
children: [
Text(
"Powered By NewTrack",
style: Theme.of(context).textTheme.headline6?.copyWith(
fontWeight: FontWeight.w500,
color: AColors.grey3A,
fontSize: 12),
style: Theme.of(context).textTheme.headline6?.copyWith(fontWeight: FontWeight.w500, color: AColors.grey3A, fontSize: 12),
textScaleFactor: AppStyle.getScaleFactor(context),
),
6.width,
Image.asset("assets/images/qr.jpeg",
width: 32, height: 32, color: AColors.grey3A)
Image.asset("assets/images/qr.jpeg", width: 32, height: 32, color: AColors.grey3A)
],
).paddingOnly(left: 20, right: 20, top: 8, bottom: 8),
],

@ -1,4 +1,3 @@
import 'package:flutter/material.dart';
import '../../../../controllers/localization/localization.dart';
@ -8,6 +7,7 @@ import '../../../widgets/loaders/lazy_loading.dart';
import '../../../widgets/loaders/no_item_found.dart';
import '../../../widgets/notifications/notification_item.dart';
import '../requests/future_request_service_details.dart';
class NotificationsList extends StatelessWidget {
final List<AppNotification>? notifications;
final bool? nextPage;
@ -18,29 +18,27 @@ class NotificationsList extends StatelessWidget {
@override
Widget build(BuildContext context) {
Subtitle? _subtitle = AppLocalization.of(context)?.subtitle;
if((notifications?.isEmpty??false)){
return NoItemFound(message: _subtitle?.notificationsNotFound??"",);
if ((notifications?.isEmpty ?? false)) {
return NoItemFound(
message: _subtitle?.notificationsNotFound ?? "",
);
}
return LazyLoading(
nextPage: nextPage??false,
onLazyLoad: onLazyLoad??()async{},
onLoadingEnd: () { },
nextPage: nextPage ?? false,
onLazyLoad: onLazyLoad ?? () async {},
onLoadingEnd: () {},
child: ListView.builder(
physics: BouncingScrollPhysics(),
itemCount: notifications?.length,
padding: EdgeInsets.symmetric(horizontal: 16,vertical: 8),
itemBuilder: (context,itemIndex){
physics: BouncingScrollPhysics(),
itemCount: notifications?.length,
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
itemBuilder: (context, itemIndex) {
return NotificationItem(
notification: notifications![itemIndex],
onPressed: (notification){
Navigator.of(context).pushNamed(
FutureRequestServiceDetails.id,
arguments: notification.requestId
);
onPressed: (notification) {
Navigator.of(context).pushNamed(FutureRequestServiceDetails.id, arguments: notification.requestId);
},
);
}
),
}),
);
}
}

@ -1,10 +1,11 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../../../api/login_api_client.dart';
import '../../../../controllers/localization/localization.dart';
import '../../../../controllers/providers/api/notifications_provider.dart';
import '../../../../controllers/providers/api/user_provider.dart';
import '../../../../controllers/providers/settings/setting_provider.dart';
import '../../../../controllers/providers/user_provider.dart';
import '../../../../models/subtitle.dart';
import '../../../../models/user.dart';
import '../../../app_style/colors.dart';
@ -18,8 +19,7 @@ class NotificationsPage extends StatefulWidget {
_NotificationsPageState createState() => _NotificationsPageState();
}
class _NotificationsPageState extends State<NotificationsPage>
with TickerProviderStateMixin{
class _NotificationsPageState extends State<NotificationsPage> with TickerProviderStateMixin {
NotificationsProvider? _notificationsProvider;
UserProvider? _userProvider;
SettingProvider? _settingProvider;
@ -33,15 +33,15 @@ class _NotificationsPageState extends State<NotificationsPage>
return Scaffold(
body: SafeArea(
child: LoadingManager(
isLoading: _notificationsProvider?.isLoading??false,
isLoading: _notificationsProvider?.isLoading ?? false,
isFailedLoading: _notificationsProvider?.notifications == null,
stateCode: _notificationsProvider?.stateCode??0,
stateCode: _notificationsProvider?.stateCode ?? 0,
onRefresh: () async {
_notificationsProvider?.reset();
await _notificationsProvider?.getNotifications(
user: _userProvider?.user??User(),
host: _settingProvider?.host??"",
hospitalId: _userProvider?.user?.hospital?.id??"",
user: UserApiClient().user ?? User(),
host: _settingProvider?.host ?? "",
hospitalId: UserApiClient().user?.hospital?.id ?? "",
);
},
child: Stack(
@ -49,8 +49,8 @@ class _NotificationsPageState extends State<NotificationsPage>
Column(
children: [
Container(
color:AColors.primaryColor,
padding: const EdgeInsets.symmetric(horizontal: 0,vertical: 4),
color: AColors.primaryColor,
padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 4),
child: Column(
children: [
Row(
@ -59,18 +59,16 @@ class _NotificationsPageState extends State<NotificationsPage>
Expanded(
child: Center(
child: Text(
_subtitle?.notifications??"",
style: Theme.of(context).textTheme.headline6?.copyWith(
color: AColors.white,
fontStyle: FontStyle.italic
),
_subtitle?.notifications ?? "",
style: Theme.of(context).textTheme.headline6?.copyWith(color: AColors.white, fontStyle: FontStyle.italic),
),
),
),
SizedBox(width: 48,)
SizedBox(
width: 48,
)
],
),
],
),
),
@ -79,9 +77,9 @@ class _NotificationsPageState extends State<NotificationsPage>
nextPage: _notificationsProvider?.nextPage,
onLazyLoad: () async {
await _notificationsProvider?.getNotifications(
user: _userProvider?.user??User(),
host: _settingProvider?.host??"",
hospitalId: _userProvider?.user?.hospital?.id??"",
user: UserApiClient().user ?? User(),
host: _settingProvider?.host ?? "",
hospitalId: UserApiClient().user?.hospital?.id ?? "",
);
},
notifications: _notificationsProvider?.notifications,
@ -89,7 +87,6 @@ class _NotificationsPageState extends State<NotificationsPage>
),
],
),
],
),
),

@ -2,10 +2,10 @@ import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:provider/provider.dart';
import '../../../controllers/http_status_manger/http_status_manger.dart';
import '../../../api/login_api_client.dart';
import '../../../controllers/localization/localization.dart';
import '../../../controllers/providers/api/user_provider.dart';
import '../../../controllers/providers/settings/setting_provider.dart';
import '../../../controllers/providers/user_provider.dart';
import '../../../controllers/validator/validator.dart';
import '../../../models/subtitle.dart';
import '../../../models/user.dart';
@ -17,13 +17,17 @@ import '../../widgets/buttons/app_button.dart';
import '../../widgets/departments/department_button.dart';
import '../../widgets/hospitals/hospital_button.dart';
import '../../widgets/loaders/loading_manager.dart';
class ProfilePage extends StatefulWidget {
static final String id = "/user/profile";
static const String id = "/user/profile";
const ProfilePage({super.key});
@override
_ProfilePageState createState() => _ProfilePageState();
ProfilePageState createState() => ProfilePageState();
}
class _ProfilePageState extends State<ProfilePage> {
class ProfilePageState extends State<ProfilePage> {
late UserProvider _userProvider;
late SettingProvider _settingProvider;
late double _width;
@ -32,21 +36,22 @@ class _ProfilePageState extends State<ProfilePage> {
bool _firstTime = true;
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
@override
Widget build(BuildContext context) {
_userProvider = Provider.of<UserProvider>(context);
_settingProvider = Provider.of<SettingProvider>(context);
_width = MediaQuery.of(context).size.width;
_height = MediaQuery.of(context).size.height;
Subtitle _subtitle = AppLocalization.of(context)!.subtitle!;
if(_firstTime){
_user = User.fromJson(_userProvider.user!.toJson());
Subtitle subtitle = AppLocalization.of(context)!.subtitle!;
if (_firstTime) {
_user = User.fromJson(UserApiClient().user!.toJson());
_firstTime = false;
}
return Scaffold(
key: _scaffoldKey,
body:LoadingManager(
isLoading: _userProvider.isLoading,
body: LoadingManager(
isLoading: _userProvider.loading,
isFailedLoading: false,
stateCode: 200,
onRefresh: () async {},
@ -61,153 +66,111 @@ class _ProfilePageState extends State<ProfilePage> {
Hero(
tag: "logo",
child: Image(
height: _height/4,
image: AssetImage("assets/images/logo.png"),
height: _height / 4,
image: const AssetImage("assets/images/logo.png"),
),
),
Container(
padding: EdgeInsets.symmetric(horizontal: 16,vertical: 16),
margin: EdgeInsets.symmetric(horizontal: 16),
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
margin: const EdgeInsets.symmetric(horizontal: 16),
decoration: BoxDecoration(
color: AColors.primaryColor,
borderRadius: BorderRadius.circular(AppStyle.getBorderRadius(context)),
boxShadow: [
BoxShadow(
color: AColors.grey,
offset: Offset(0,-1),
)
]
color: AColors.primaryColor,
borderRadius: BorderRadius.circular(AppStyle.getBorderRadius(context)),
boxShadow: const [BoxShadow(color: AColors.grey, offset: Offset(0, -1))],
),
child: Column(
children: [
ATextFormField(
initialValue: _user.userName,
hintText: _subtitle.name,
hintText: subtitle.name,
enable: false,
prefixIconData: Icons.account_circle,
style: Theme.of(context).textTheme.headline6,
validator: (value) => Validator.hasValue(value!)
? '' : _subtitle.nameValidateMessage,
onSaved: (value){
style: Theme.of(context).textTheme.titleLarge,
validator: (value) => Validator.hasValue(value!) ? '' : subtitle.nameValidateMessage,
onSaved: (value) {
_user.userName = value!;
},
),
SizedBox(height: 8,),
const SizedBox(height: 8),
ATextFormField(
initialValue: _user.email,
hintText: _subtitle.email,
hintText: subtitle.email,
enable: false,
prefixIconData: Icons.email,
textInputType: TextInputType.emailAddress,
style: Theme.of(context).textTheme.headline6,
validator: (value) => Validator.isEmail(value!)
? '' : _subtitle.emailValidateMessage,
onSaved: (value){
style: Theme.of(context).textTheme.titleLarge,
validator: (value) => Validator.isEmail(value!) ? '' : subtitle.emailValidateMessage,
onSaved: (value) {
_user.email = value!;
},
),
SizedBox(height: 8,),
const SizedBox(height: 8),
AbsorbPointer(
child: HospitalButton(
hospital: _user.hospital!,
onHospitalPick: (hospital){
onHospitalPick: (hospital) {
_user.hospital = hospital;
setState(() {});
},
),
),
SizedBox(height: 8,),
const SizedBox(height: 8),
DepartmentButton(
department: _user.department,
onDepartmentPick: (department){
onDepartmentPick: (department) {
_user.department = department;
setState(() {});
},
),
SizedBox(height: 8,),
const SizedBox(height: 8),
ATextFormField(
initialValue: _user.phoneNumber,
hintText: _subtitle.phoneNumber,
style: Theme.of(context).textTheme.headline6,
hintText: subtitle.phoneNumber,
style: Theme.of(context).textTheme.titleLarge,
prefixIconData: Icons.phone_android,
validator: (value) =>
Validator.isPhoneNumber(value!) ? '' : _subtitle.phoneNumberValidateMessage,
validator: (value) => Validator.isPhoneNumber(value!) ? '' : subtitle.phoneNumberValidateMessage,
textInputType: TextInputType.phone,
onSaved: (value){
onSaved: (value) {
_user.phoneNumber = value;
},
),
SizedBox(height: 8,),
const SizedBox(height: 8),
ATextFormField(
initialValue: _user.whatsApp,
hintText: _subtitle.whatsApp,
style: Theme.of(context).textTheme.headline6,
hintText: subtitle.whatsApp,
style: Theme.of(context).textTheme.titleLarge,
prefixIconData: FontAwesomeIcons.whatsapp,
prefixIconSize: 36,
validator: (value) =>
Validator.isPhoneNumber(value!) ? '' : _subtitle.phoneNumberValidateMessage,
validator: (value) => Validator.isPhoneNumber(value!) ? '' : subtitle.phoneNumberValidateMessage,
textInputType: TextInputType.phone,
onSaved: (value){
onSaved: (value) {
_user.whatsApp = value;
},
),
],
),
),
SizedBox(height: 16,),
const SizedBox(height: 16),
Center(
child: SizedBox(
height: _width / 8,
width: _width/1.2,
width: _width / 1.2,
child: AButton(
text: _subtitle.update,
text: subtitle.update,
onPressed: () async {
if(!(_formKey.currentState?.validate()??false))
return;
_formKey.currentState?.save();
if(_user.department?.id == null){
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
_subtitle.unitRequired
),
)
);
return;
}
int status = await _userProvider.updateProfile(
user: _user,
host: _settingProvider.host!,
);
if(status >= 200 && status < 300){
_settingProvider.setUser(_userProvider.user!);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
_subtitle.requestCompleteSuccessfully
),
)
);
}else{
String errorMessage = HttpStatusManger.getStatusMessage(
status: status, subtitle: _subtitle);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
errorMessage
),
)
);
if (_formKey.currentState?.validate() ?? false) {
_formKey.currentState?.save();
await _userProvider.updateProfile(context, updatedUser: _user);
}
},
),
),
),
SizedBox(height: 32,),
const SizedBox(height: 32),
],
),
),
ABackButton(),
const ABackButton(),
],
),
),

@ -2,10 +2,11 @@ import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart';
import '../../../api/login_api_client.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 '../../../controllers/providers/user_provider.dart';
import '../../../controllers/validator/validator.dart';
import '../../../models/issue.dart';
import '../../../models/service_request/service_request.dart';
@ -67,12 +68,7 @@ class _ReportIssuesPageState extends State<ReportIssuesPage> {
),
child: Text(
_subtitle.reportIssue,
style: Theme.of(context)
.textTheme
.headline5
?.copyWith(
color: AColors.cyan,
fontWeight: FontWeight.bold),
style: Theme.of(context).textTheme.headline5?.copyWith(color: AColors.cyan, fontWeight: FontWeight.bold),
),
),
),
@ -88,10 +84,8 @@ class _ReportIssuesPageState extends State<ReportIssuesPage> {
decoration: BoxDecoration(
color: AColors.grey,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(
AppStyle.getBorderRadius(context)),
topRight: Radius.circular(
AppStyle.getBorderRadius(context)),
topLeft: Radius.circular(AppStyle.getBorderRadius(context)),
topRight: Radius.circular(AppStyle.getBorderRadius(context)),
),
boxShadow: [
BoxShadow(
@ -107,9 +101,7 @@ class _ReportIssuesPageState extends State<ReportIssuesPage> {
hintText: _subtitle.title,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.headline6,
validator: (value) => Validator.hasValue(value!)
? ''
: _subtitle.titleValidateMessage,
validator: (value) => Validator.hasValue(value!) ? '' : _subtitle.titleValidateMessage,
textInputType: TextInputType.name,
onSaved: (value) {
_issue.title = value;
@ -122,8 +114,7 @@ class _ReportIssuesPageState extends State<ReportIssuesPage> {
children: List.generate(
_issues.length,
(index) => ReportIssueItem(
isSelected:
_issue.reports?.contains(index),
isSelected: _issue.reports?.contains(index),
issueInfo: _issues[index],
onChange: (info, value) {
if (value) {
@ -154,16 +145,13 @@ class _ReportIssuesPageState extends State<ReportIssuesPage> {
child: AButton(
text: _subtitle.submit,
onPressed: () async {
if (!(_formKey.currentState?.validate() ??
false)) return;
if (!(_formKey.currentState?.validate() ?? false)) return;
_formKey.currentState?.save();
_issue.serviceRequestId =
widget.serviceRequest?.id;
_issue.serviceRequestId = widget.serviceRequest?.id;
_isLoading = true;
setState(() {});
int status = await _serviceRequestsProvider
.createIssueReport(
user: _userProvider.user ?? User(),
int status = await _serviceRequestsProvider.createIssueReport(
user: UserApiClient().user ?? User(),
host: _settingProvider.host ?? "",
issue: _issue,
);
@ -171,8 +159,7 @@ class _ReportIssuesPageState extends State<ReportIssuesPage> {
setState(() {});
if (status >= 200 && status < 300) {
Fluttertoast.showToast(
msg:
_subtitle.requestCompleteSuccessfully,
msg: _subtitle.requestCompleteSuccessfully,
);
Navigator.of(context).pop();
}

@ -6,11 +6,12 @@ import 'package:fluttertoast/fluttertoast.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:provider/provider.dart';
import '../../../../api/login_api_client.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 '../../../../controllers/providers/user_provider.dart';
import '../../../../controllers/validator/validator.dart';
import '../../../../extensions/int_extensions.dart';
import '../../../../extensions/widget_extensions.dart';
@ -100,12 +101,7 @@ class _CreateRequestPageState extends State<CreateRequestPage> {
padding: const EdgeInsets.all(8.0),
child: Text(
_subtitle.newServiceRequest,
style: Theme.of(context)
.textTheme
.headline5
?.copyWith(
color: AColors.cyan,
fontWeight: FontWeight.w600),
style: Theme.of(context).textTheme.headline5?.copyWith(color: AColors.cyan, fontWeight: FontWeight.w600),
),
),
),
@ -113,25 +109,21 @@ class _CreateRequestPageState extends State<CreateRequestPage> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
12.height,
_userProvider.user?.hospital == null
UserApiClient().user?.hospital == null
? SizedBox.shrink()
: ATextFormField(
enable: false,
initialValue:
_userProvider.user?.hospital?.name ??
_subtitle.noHospitalFound,
initialValue: UserApiClient().user?.hospital?.name ?? _subtitle.noHospitalFound,
hintText: _subtitle.hospital,
prefixIconData: FontAwesomeIcons.hospital,
style: Theme.of(context).textTheme.subtitle1,
),
12.height,
_userProvider.user?.department == null
UserApiClient().user?.department == null
? SizedBox.shrink()
: ATextFormField(
enable: false,
initialValue:
_userProvider.user?.department?.name ??
_subtitle.noUniteFound,
initialValue: UserApiClient().user?.department?.name ?? _subtitle.noUniteFound,
hintText: _subtitle.unite,
prefixIconData: FontAwesomeIcons.hospitalUser,
style: Theme.of(context).textTheme.subtitle1,
@ -185,9 +177,7 @@ class _CreateRequestPageState extends State<CreateRequestPage> {
prefixIconData: FontAwesomeIcons.triangleExclamation,
style: Theme.of(context).textTheme.headline6,
textInputType: TextInputType.multiline,
validator: (value) => Validator.hasValue(value!)
? ''
: _subtitle.maintenanceIssueRequired,
validator: (value) => Validator.hasValue(value!) ? '' : _subtitle.maintenanceIssueRequired,
onSaved: (value) {
_serviceRequest.maintenanceIssue = value;
},
@ -204,23 +194,18 @@ class _CreateRequestPageState extends State<CreateRequestPage> {
child: AButton(
text: _subtitle.submit,
onPressed: () async {
if (!(_formKey.currentState?.validate() ?? false))
return;
if (!(_formKey.currentState?.validate() ?? false)) return;
_formKey.currentState?.save();
_serviceRequest.deviceId = _device?.id ?? "";
_isLoading = true;
setState(() {});
_serviceRequest.devicePhotos = _deviceImages
.map((e) => base64Encode(e.readAsBytesSync()))
.toList();
_serviceRequest.devicePhotos = _deviceImages.map((e) => base64Encode(e.readAsBytesSync())).toList();
if (_serviceRequest.audio != null) {
final file = File(_serviceRequest.audio!);
_serviceRequest.audio =
base64Encode(file.readAsBytesSync());
_serviceRequest.audio = base64Encode(file.readAsBytesSync());
}
int status =
await _serviceRequestsProvider.createRequest(
user: _userProvider.user!,
int status = await _serviceRequestsProvider.createRequest(
user: UserApiClient().user!,
host: _settingProvider.host ?? "",
serviceRequest: _serviceRequest,
);
@ -232,9 +217,7 @@ class _CreateRequestPageState extends State<CreateRequestPage> {
);
Navigator.of(context).pop();
} else {
String errorMessage =
HttpStatusManger.getStatusMessage(
status: status, subtitle: _subtitle);
String errorMessage = HttpStatusManger.getStatusMessage(status: status, subtitle: _subtitle);
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(errorMessage),
));

@ -1,10 +1,11 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../../../api/login_api_client.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 '../../../../controllers/providers/user_provider.dart';
import '../../../../models/service_request/service_request.dart';
import '../../../../models/subtitle.dart';
import '../../../widgets/loaders/app_loading.dart';
@ -17,12 +18,10 @@ class FutureRequestServiceDetails extends StatefulWidget {
const FutureRequestServiceDetails({super.key});
@override
_FutureRequestServiceDetailsState createState() =>
_FutureRequestServiceDetailsState();
_FutureRequestServiceDetailsState createState() => _FutureRequestServiceDetailsState();
}
class _FutureRequestServiceDetailsState
extends State<FutureRequestServiceDetails> {
class _FutureRequestServiceDetailsState extends State<FutureRequestServiceDetails> {
late UserProvider _userProvider;
late SettingProvider _settingProvider;
@override
@ -33,13 +32,8 @@ class _FutureRequestServiceDetailsState
Subtitle _subtitle = AppLocalization.of(context)!.subtitle!;
return Scaffold(
body: FutureBuilder<ServiceRequest>(
future: ServiceRequestsProvider().getSingleServiceRequest(
requestId: requestId ?? '',
user: _userProvider.user!,
host: _settingProvider.host ?? "",
subtitle: _subtitle),
builder:
(BuildContext context, AsyncSnapshot<ServiceRequest> snapshot) {
future: ServiceRequestsProvider().getSingleServiceRequest(requestId: requestId ?? '', user: UserApiClient().user!, host: _settingProvider.host ?? "", subtitle: _subtitle),
builder: (BuildContext context, AsyncSnapshot<ServiceRequest> snapshot) {
if (snapshot.hasError) {
return FailedLoading(
message: snapshot.error.toString(),

@ -2,15 +2,14 @@ import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart';
import '../../../../../api/login_api_client.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/status_drop_down/report/service_report_last_calls_provider.dart';
import '../../../../../controllers/providers/api/user_provider.dart';
import '../../../../../controllers/providers/settings/setting_provider.dart';
import '../../../../../controllers/validator/validator.dart';
import '../../../../../models/device/device.dart';
@ -37,19 +36,18 @@ import '../../../../widgets/status/report/service_report_status.dart';
import '../../../../widgets/status/report/service_status.dart';
import '../../../../widgets/timer/app_timer.dart';
import '../../../../widgets/titles/app_sub_title.dart';
class CreateServiceReport extends StatefulWidget {
static final String id = "/create-service-report";
final ServiceRequest? request ;
static const String id = "/create-service-report";
final ServiceRequest? request;
const CreateServiceReport({Key? key, this.request}) : super(key: key);
@override
_CreateServiceReportState createState() => _CreateServiceReportState();
CreateServiceReportState createState() => CreateServiceReportState();
}
class _CreateServiceReportState extends State<CreateServiceReport> with TickerProviderStateMixin{
UserProvider? _userProvider;
class CreateServiceReportState extends State<CreateServiceReport> with TickerProviderStateMixin {
SettingProvider? _settingProvider;
ServiceRequestsProvider? _serviceRequestsProvider;
@ -61,20 +59,19 @@ class _CreateServiceReportState extends State<CreateServiceReport> with TickerPr
File? _image;
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
TextEditingController _faultController = TextEditingController();
TextEditingController _workPreformedController = TextEditingController();
final TextEditingController _faultController = TextEditingController();
final TextEditingController _workPreformedController = TextEditingController();
@override
void initState() {
_serviceReport = ServiceReport(
visitDate: DateTime.now(),
type: const Lookup(id: 2),
device: Device(
id: widget.request?.deviceId,
serialNumber: widget.request?.deviceSerialNumber,
),
parts: []
);
visitDate: DateTime.now(),
type: const Lookup(id: 2),
device: Device(
id: widget.request?.deviceId,
serialNumber: widget.request?.deviceSerialNumber,
),
parts: []);
super.initState();
}
@ -84,9 +81,9 @@ class _CreateServiceReportState extends State<CreateServiceReport> with TickerPr
_workPreformedController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
_userProvider = Provider.of<UserProvider>(context);
_settingProvider = Provider.of<SettingProvider>(context);
_serviceRequestsProvider = Provider.of<ServiceRequestsProvider>(context);
_subtitle = AppLocalization.of(context)?.subtitle;
@ -105,52 +102,54 @@ class _CreateServiceReportState extends State<CreateServiceReport> with TickerPr
ListView(
children: [
//AppNameBar(),
const SizedBox(height: 16,),
const SizedBox(
height: 16,
),
Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
_subtitle?.newServiceReport??"",
style: Theme.of(context).textTheme.headline5?.copyWith(
color: AColors.cyan,
fontSize: 28,
fontWeight: FontWeight.bold
),
_subtitle?.newServiceReport ?? "",
style: Theme.of(context).textTheme.headline5?.copyWith(color: AColors.cyan, fontSize: 28, fontWeight: FontWeight.bold),
),
),
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 16),
margin: const EdgeInsets.symmetric(horizontal: 16,vertical: 16),
decoration: BoxDecoration(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
decoration: BoxDecoration(color: AColors.grey, borderRadius: BorderRadius.circular(AppStyle.getBorderRadius(context)), boxShadow: [
const BoxShadow(
color: AColors.grey,
borderRadius: BorderRadius.circular(AppStyle.getBorderRadius(context)),
boxShadow: [
const BoxShadow(
color: AColors.grey,
offset: Offset(0,-1),
)
]
),
offset: Offset(0, -1),
)
]),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 8,),
const SizedBox(
height: 8,
),
Wrap(
spacing: 10,
children: [
ASubTitle("${_subtitle?.callId}: ${widget.request?.requestCode}",font: 14,),
widget.request?.deviceSerialNumber == null ? const SizedBox():
ASubTitle("${_subtitle?.deviceSN}: ${widget.request?.deviceSerialNumber}",font: 14,),
ASubTitle(
"${_subtitle?.callId}: ${widget.request?.requestCode}",
font: 14,
),
widget.request?.deviceSerialNumber == null
? const SizedBox()
: ASubTitle(
"${_subtitle?.deviceSN}: ${widget.request?.deviceSerialNumber}",
font: 14,
),
Text(
"${_subtitle?.customer}: ${widget.request?.hospitalName}",
style: Theme.of(context).textTheme.subtitle1?.copyWith(
fontWeight: FontWeight.bold,
fontSize: 12,
),
fontWeight: FontWeight.bold,
fontSize: 12,
),
textScaleFactor: AppStyle.getScaleFactor(context),
)
],
),
const Divider(),
@ -183,18 +182,21 @@ class _CreateServiceReportState extends State<CreateServiceReport> with TickerPr
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(_subtitle?.visitDate??""),
_validate && _serviceReport?.visitDate == null ?
ASubTitle(_subtitle?.requiredWord??"",color: Colors.red,):
const SizedBox.shrink(),
ASubTitle(_subtitle?.visitDate ?? ""),
_validate && _serviceReport?.visitDate == null
? ASubTitle(
_subtitle?.requiredWord ?? "",
color: Colors.red,
)
: const SizedBox.shrink(),
Row(
children: [
Expanded(
child: ADatePicker(
date: _serviceReport?.visitDate??DateTime.now(),
date: _serviceReport?.visitDate ?? DateTime.now(),
from: DateTime.now().subtract(const Duration(days: 365)),
to: DateTime.now().add(const Duration(days: 365)),
onDatePicker: (date){
onDatePicker: (date) {
_serviceReport?.visitDate = date;
setState(() {});
},
@ -205,44 +207,59 @@ class _CreateServiceReportState extends State<CreateServiceReport> with TickerPr
],
),
),
],
),
const SizedBox(height: 8,),
const SizedBox(
height: 8,
),
// device sn
Visibility(
visible: widget.request?.deviceSerialNumber == null,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(_subtitle?.deviceSN??""),
_validate && _serviceReport?.device?.id == null ?
ASubTitle(_subtitle?.requiredWord??"",color: Colors.red,):
const SizedBox.shrink(),
ASubTitle(_subtitle?.deviceSN ?? ""),
_validate && _serviceReport?.device?.id == null
? ASubTitle(
_subtitle?.requiredWord ?? "",
color: Colors.red,
)
: const SizedBox.shrink(),
AutoCompleteDeviceField(
hospitalId: widget.request?.hospitalId??"",
hospitalId: widget.request?.hospitalId ?? "",
initialValue: _serviceReport!.device!,
onPick: (id){
onPick: (id) {
_serviceReport?.device?.id = id;
},
),
const SizedBox(height: 8,),
const SizedBox(
height: 8,
),
],
),
),
const SizedBox(height: 8,),
ASubTitle(_subtitle?.serviceType??""),
_validate && _serviceReport?.serviceType == null ?
ASubTitle(_subtitle?.requiredWord??"",color: Colors.red,):
const SizedBox.shrink(),
const SizedBox(height: 4,),
const SizedBox(
height: 8,
),
ASubTitle(_subtitle?.serviceType ?? ""),
_validate && _serviceReport?.serviceType == null
? ASubTitle(
_subtitle?.requiredWord ?? "",
color: Colors.red,
)
: const SizedBox.shrink(),
const SizedBox(
height: 4,
),
ServiceStatusMenu(
initialValue: _serviceReport?.serviceType,
onSelect: (status){
onSelect: (status) {
_serviceReport?.serviceType = status;
},
),
const SizedBox(height: 8,),
const SizedBox(
height: 8,
),
// Report status and Service Type
Row(
children: [
@ -251,106 +268,124 @@ class _CreateServiceReportState extends State<CreateServiceReport> with TickerPr
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(_subtitle?.reportStatus??""),
_validate && _serviceReport?.status == null ?
ASubTitle(_subtitle?.requiredWord??"",color: Colors.red,):
const SizedBox.shrink(),
const SizedBox(height: 4,),
ASubTitle(_subtitle?.reportStatus ?? ""),
_validate && _serviceReport?.status == null
? ASubTitle(
_subtitle?.requiredWord ?? "",
color: Colors.red,
)
: const SizedBox.shrink(),
const SizedBox(
height: 4,
),
ServiceReportStatusMenu(
report: _serviceReport,
onSelect: (status){
onSelect: (status) {
_serviceReport?.status = status;
},
),
],
),
),
const SizedBox(width: 8,),
const SizedBox(
width: 8,
),
Provider.of<ServiceReportLastCallsProvider>(context).isLoading == null
? const SizedBox.shrink():
// Call's last Situation
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(_subtitle?.callLastSituation??""),
_validate && _serviceReport?.callLastSituation == null ?
ASubTitle(_subtitle?.requiredWord??"",color: Colors.red,):
const SizedBox.shrink(),
const SizedBox(height: 4,),
ServiceReportLastCallsMenu(
report: _serviceReport,
onSelect: (status){
if(status?.id == 12
|| _serviceReport?.callLastSituation?.id == 12){
_serviceReport?.callLastSituation = status;
setState(() {});
} else {
_serviceReport?.callLastSituation = status;
}
},
? const SizedBox.shrink()
:
// Call's last Situation
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(_subtitle?.callLastSituation ?? ""),
_validate && _serviceReport?.callLastSituation == null
? ASubTitle(
_subtitle?.requiredWord ?? "",
color: Colors.red,
)
: const SizedBox.shrink(),
const SizedBox(
height: 4,
),
ServiceReportLastCallsMenu(
report: _serviceReport,
onSelect: (status) {
if (status?.id == 12 || _serviceReport?.callLastSituation?.id == 12) {
_serviceReport?.callLastSituation = status;
setState(() {});
} else {
_serviceReport?.callLastSituation = status;
}
},
),
],
),
),
],
),
),
],
),
const SizedBox(height: 8,),
const SizedBox(
height: 8,
),
// invoice number & code
_serviceReport?.callLastSituation?.id != 12 ? const SizedBox.shrink():
Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
_serviceReport?.callLastSituation?.id != 12
? const SizedBox.shrink()
: Row(
children: [
ASubTitle(_subtitle?.invoiceNumber??""),
const SizedBox(height: 8,),
ATextFormField(
initialValue: _serviceReport?.invoiceNumber??"",
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.subtitle1,
validator: (value) =>
Validator.hasValue(value!)
? '' : _subtitle?.requiredWord??"",
textInputType: TextInputType.number,
onSaved: (value){
_serviceReport?.invoiceNumber = value;
},
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(_subtitle?.invoiceNumber ?? ""),
const SizedBox(
height: 8,
),
ATextFormField(
initialValue: _serviceReport?.invoiceNumber ?? "",
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.subtitle1,
validator: (value) => Validator.hasValue(value!) ? '' : _subtitle?.requiredWord ?? "",
textInputType: TextInputType.number,
onSaved: (value) {
_serviceReport?.invoiceNumber = value;
},
),
],
),
),
],
),
),
const SizedBox(width: 8,),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(_subtitle?.invoiceCode??""),
const SizedBox(height: 4,),
ATextFormField(
initialValue: _serviceReport?.invoiceCode??"",
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.subtitle1,
validator: (value) =>
Validator.hasValue(value!)
? '' : _subtitle?.requiredWord??"",
textInputType: TextInputType.text,
onSaved: (value){
_serviceReport?.invoiceCode = value;
},
const SizedBox(
width: 8,
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(_subtitle?.invoiceCode ?? ""),
const SizedBox(
height: 4,
),
ATextFormField(
initialValue: _serviceReport?.invoiceCode ?? "",
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.subtitle1,
validator: (value) => Validator.hasValue(value!) ? '' : _subtitle?.requiredWord ?? "",
textInputType: TextInputType.text,
onSaved: (value) {
_serviceReport?.invoiceCode = value;
},
),
],
),
),
],
),
),
],
),
const SizedBox(height: 8,),
const SizedBox(
height: 8,
),
Row(
children: [
ASubTitle(_subtitle?.faultDescription??""),
ASubTitle(_subtitle?.faultDescription ?? ""),
Expanded(
child: SizedBox(
height: 32 * AppStyle.getScaleFactor(context),
@ -362,24 +397,26 @@ class _CreateServiceReportState extends State<CreateServiceReport> with TickerPr
),
],
),
const SizedBox(height: 4,),
const SizedBox(
height: 4,
),
ATextFormField(
initialValue: _serviceReport?.faultDescription??"",
initialValue: _serviceReport?.faultDescription ?? "",
textAlign: TextAlign.center,
controller: _faultController,
style: Theme.of(context).textTheme.subtitle1,
validator: (value) =>
Validator.hasValue(value!)
? '' : _subtitle?.requiredWord??"",
validator: (value) => Validator.hasValue(value!) ? '' : _subtitle?.requiredWord ?? "",
textInputType: TextInputType.multiline,
onSaved: (value){
onSaved: (value) {
_serviceReport?.faultDescription = value;
},
),
const SizedBox(height: 8,),
const SizedBox(
height: 8,
),
Row(
children: [
ASubTitle(_subtitle?.workPreformed??""),
ASubTitle(_subtitle?.workPreformed ?? ""),
Expanded(
child: SizedBox(
height: 32 * AppStyle.getScaleFactor(context),
@ -391,23 +428,27 @@ class _CreateServiceReportState extends State<CreateServiceReport> with TickerPr
),
],
),
const SizedBox(height: 4,),
const SizedBox(
height: 4,
),
ATextFormField(
initialValue: _serviceReport?.workPreformed??"",
initialValue: _serviceReport?.workPreformed ?? "",
textAlign: TextAlign.center,
controller: _workPreformedController,
style: Theme.of(context).textTheme.subtitle1,
validator: (value) =>
Validator.hasValue(value!)
? '' : _subtitle?.requiredWord??"",
validator: (value) => Validator.hasValue(value!) ? '' : _subtitle?.requiredWord ?? "",
textInputType: TextInputType.multiline,
onSaved: (value){
onSaved: (value) {
_serviceReport?.workPreformed = value;
},
),
const SizedBox(height: 8,),
const SizedBox(
height: 8,
),
const SizedBox(height: 8,),
const SizedBox(
height: 8,
),
Row(
children: [
// reasons
@ -415,28 +456,32 @@ class _CreateServiceReportState extends State<CreateServiceReport> with TickerPr
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(_subtitle?.reasons??""),
const SizedBox(height: 4,),
ASubTitle(_subtitle?.reasons ?? ""),
const SizedBox(
height: 4,
),
ServiceReportReasonsMenu(
initialValue: _serviceReport?.reason,
onSelect: (status){
onSelect: (status) {
_serviceReport?.reason = status;
},
),
],
),
),
const SizedBox(width: 8,),
const SizedBox(
width: 8,
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(_subtitle?.attachImage??""),
ASubTitle(_subtitle?.attachImage ?? ""),
AMiniOneImagePicker(
//error: _validate && _serviceReport.image == null,
image: _image,
onPick: (image){
_image =image;
onPick: (image) {
_image = image;
_serviceReport?.image = base64Encode(image.readAsBytesSync());
},
),
@ -445,7 +490,9 @@ class _CreateServiceReportState extends State<CreateServiceReport> with TickerPr
),
],
),
const SizedBox(height: 8,),
const SizedBox(
height: 8,
),
// Traveling Hours & Working Hours
Row(
children: [
@ -453,11 +500,13 @@ class _CreateServiceReportState extends State<CreateServiceReport> with TickerPr
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(_subtitle?.workingHours??""),
const SizedBox(height: 8,),
ASubTitle(_subtitle?.workingHours ?? ""),
const SizedBox(
height: 8,
),
AppTimer(
timer: _serviceReport?.timer,
onChange: (timer) async{
onChange: (timer) async {
_serviceReport?.timer = timer;
return true;
},
@ -478,13 +527,17 @@ class _CreateServiceReportState extends State<CreateServiceReport> with TickerPr
],
),
),
const SizedBox(width: 8,),
const SizedBox(
width: 8,
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(_subtitle?.travelingHours??""),
const SizedBox(height: 4,),
ASubTitle(_subtitle?.travelingHours ?? ""),
const SizedBox(
height: 4,
),
ATextFormField(
initialValue: _serviceReport?.travelingHours,
textAlign: TextAlign.center,
@ -494,7 +547,7 @@ class _CreateServiceReportState extends State<CreateServiceReport> with TickerPr
// Validator.isNumeric(value)
// ? null : _subtitle.requiredWord,
textInputType: TextInputType.number,
onSaved: (value){
onSaved: (value) {
_serviceReport?.travelingHours = value;
},
),
@ -503,7 +556,9 @@ class _CreateServiceReportState extends State<CreateServiceReport> with TickerPr
),
],
),
const SizedBox(height: 8,),
const SizedBox(
height: 8,
),
// Operating Hours and Job Sheet Number
Row(
children: [
@ -534,14 +589,16 @@ class _CreateServiceReportState extends State<CreateServiceReport> with TickerPr
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(_subtitle?.jobSheetNumber??""),
const SizedBox(height: 4,),
ASubTitle(_subtitle?.jobSheetNumber ?? ""),
const SizedBox(
height: 4,
),
ATextFormField(
initialValue: _serviceReport?.jobSheetNumber,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.subtitle1,
textInputType: TextInputType.name,
onSaved: (value){
onSaved: (value) {
_serviceReport?.jobSheetNumber = value;
},
),
@ -550,7 +607,9 @@ class _CreateServiceReportState extends State<CreateServiceReport> with TickerPr
),
],
),
const SizedBox(height: 8,),
const SizedBox(
height: 8,
),
// Part Number and Quantity
Row(
children: [
@ -559,95 +618,92 @@ class _CreateServiceReportState extends State<CreateServiceReport> with TickerPr
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(_subtitle?.partNumber??""),
_validate && _serviceReport?.parts == null ?
ASubTitle(_subtitle?.requiredWord??"",color: Colors.red,):
const SizedBox.shrink(),
const SizedBox(height: 4,),
ASubTitle(_subtitle?.partNumber ?? ""),
_validate && _serviceReport?.parts == null
? ASubTitle(
_subtitle?.requiredWord ?? "",
color: Colors.red,
)
: const SizedBox.shrink(),
const SizedBox(
height: 4,
),
AutoCompletePartsField(
onPick: (part){
onPick: (part) {
_serviceReport?.parts?.add(part);
},
),
],
),
),
],
),
SizedBox(height: 8*AppStyle.getScaleFactor(context),),
SizedBox(
height: 8 * AppStyle.getScaleFactor(context),
),
Row(
children: [
Expanded(flex:3,child: Text(_subtitle?.number??"")),
Expanded(flex: 1,child: Text(_subtitle?.quantity??"")),
Expanded(flex: 3, child: Text(_subtitle?.number ?? "")),
Expanded(flex: 1, child: Text(_subtitle?.quantity ?? "")),
],
),
Column(
children: List.generate(
_serviceReport!.parts!.length,
(index) {
Part _part = _serviceReport!.parts![index];
return PartItem(
part: _part,
onDelete: (part){
_serviceReport!.parts!.remove(part);
setState(() {});
},
);
}
),
children: List.generate(_serviceReport!.parts!.length, (index) {
Part _part = _serviceReport!.parts![index];
return PartItem(
part: _part,
onDelete: (part) {
_serviceReport!.parts!.remove(part);
setState(() {});
},
);
}),
),
const SizedBox(height: 16,),
const SizedBox(
height: 16,
),
],
),
),
Padding(
padding: const EdgeInsets.all(16.0),
child: AButton(
text: _subtitle?.submit??"",
text: _subtitle?.submit ?? "",
onPressed: () async {
_validate = true;
if(!(_formKey.currentState?.validate()??false)){
if (!(_formKey.currentState?.validate() ?? false)) {
setState(() {});
return;
}
if(!(_serviceReport?.validate()??false)) return;
if (!(_serviceReport?.validate() ?? false)) return;
_formKey.currentState?.save();
_isLoading =true;
_isLoading = true;
setState(() {});
int? status = await _serviceRequestsProvider?.createServiceReport(
user: _userProvider!.user!,
host: _settingProvider?.host??"",
report: _serviceReport!,
request: widget.request!
);
_isLoading =false;
int? status =
await _serviceRequestsProvider?.createServiceReport(user: UserApiClient().user!, host: _settingProvider?.host ?? "", report: _serviceReport!, request: widget.request!);
_isLoading = false;
setState(() {});
if(status != null && status >= 200 && status < 300){
if (status != null && status >= 200 && status < 300) {
Fluttertoast.showToast(
msg: _subtitle?.requestCompleteSuccessfully??"",
msg: _subtitle?.requestCompleteSuccessfully ?? "",
);
Navigator.of(context).pop();
Navigator.of(context).pop();
}else{
String errorMessage = HttpStatusManger.getStatusMessage(
status: status, subtitle: _subtitle);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
errorMessage
),
)
);
} else {
String errorMessage = HttpStatusManger.getStatusMessage(status: status, subtitle: _subtitle);
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(errorMessage),
));
}
},
),
),
const SizedBox(height: 300,)
const SizedBox(
height: 300,
)
],
),
const ABackButton(),

@ -2,16 +2,16 @@ import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart';
import '../../../../../api/login_api_client.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/status_drop_down/report/service_report_last_calls_provider.dart';
import '../../../../../controllers/providers/api/user_provider.dart';
import '../../../../../controllers/providers/settings/setting_provider.dart';
import '../../../../../controllers/providers/user_provider.dart';
import '../../../../../controllers/validator/validator.dart';
import '../../../../../models/part.dart';
import '../../../../../models/service_report.dart';
@ -39,7 +39,7 @@ import '../../../../widgets/titles/app_sub_title.dart';
class EditServiceReport extends StatefulWidget {
static final String id = "/edit-service-report";
final ServiceRequest request ;
final ServiceRequest request;
final ServiceReport report;
const EditServiceReport({Key? key, required this.request, required this.report}) : super(key: key);
@ -47,9 +47,7 @@ class EditServiceReport extends StatefulWidget {
_EditServiceReportState createState() => _EditServiceReportState();
}
class _EditServiceReportState extends State<EditServiceReport> with TickerProviderStateMixin{
class _EditServiceReportState extends State<EditServiceReport> with TickerProviderStateMixin {
late UserProvider _userProvider;
late SettingProvider _settingProvider;
late ServiceRequestsProvider _serviceRequestsProvider;
@ -77,6 +75,7 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
_workPreformedController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
_userProvider = Provider.of<UserProvider>(context);
@ -98,52 +97,54 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
ListView(
children: [
//AppNameBar(),
const SizedBox(height: 16,),
const SizedBox(
height: 16,
),
Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
_subtitle.editServiceReport,
style: Theme.of(context).textTheme.headline5?.copyWith(
color: AColors.cyan,
fontSize: 28,
fontWeight: FontWeight.bold
),
style: Theme.of(context).textTheme.headline5?.copyWith(color: AColors.cyan, fontSize: 28, fontWeight: FontWeight.bold),
),
),
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 16),
margin: const EdgeInsets.symmetric(horizontal: 16,vertical: 16),
decoration: BoxDecoration(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
decoration: BoxDecoration(color: AColors.grey, borderRadius: BorderRadius.circular(AppStyle.getBorderRadius(context)), boxShadow: [
BoxShadow(
color: AColors.grey,
borderRadius: BorderRadius.circular(AppStyle.getBorderRadius(context)),
boxShadow: [
BoxShadow(
color: AColors.grey,
offset: Offset(0,-1),
)
]
),
offset: Offset(0, -1),
)
]),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 8,),
const SizedBox(
height: 8,
),
Wrap(
spacing: 10,
children: [
ASubTitle("${_subtitle.callId}: ${widget.request.requestCode}",font: 14,),
widget.request.deviceSerialNumber == null ? const SizedBox():
ASubTitle("${_subtitle.deviceSN}: ${widget.request.deviceSerialNumber}",font: 14,),
ASubTitle(
"${_subtitle.callId}: ${widget.request.requestCode}",
font: 14,
),
widget.request.deviceSerialNumber == null
? const SizedBox()
: ASubTitle(
"${_subtitle.deviceSN}: ${widget.request.deviceSerialNumber}",
font: 14,
),
Text(
"${_subtitle.customer}: ${widget.request.hospitalName}",
style: Theme.of(context).textTheme.subtitle1?.copyWith(
fontWeight: FontWeight.bold,
fontSize: 12,
),
fontWeight: FontWeight.bold,
fontSize: 12,
),
textScaleFactor: AppStyle.getScaleFactor(context),
)
],
),
const Divider(),
@ -157,29 +158,39 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(_subtitle.reportType),
_validate && _serviceReport.type == null ?
ASubTitle(_subtitle.requiredWord,color: Colors.red,):
const SizedBox.shrink(),
const SizedBox(height: 4,),
_validate && _serviceReport.type == null
? ASubTitle(
_subtitle.requiredWord,
color: Colors.red,
)
: const SizedBox.shrink(),
const SizedBox(
height: 4,
),
ServiceReportTypeMenu(
initialValue: _serviceReport.type,
onSelect: (status){
onSelect: (status) {
_serviceReport.type = status;
},
),
],
),
),
const SizedBox(width: 8,),
const SizedBox(
width: 8,
),
// visit date
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(_subtitle.visitDate),
_validate && _serviceReport.visitDate == null ?
ASubTitle(_subtitle.requiredWord,color: Colors.red,):
const SizedBox.shrink(),
_validate && _serviceReport.visitDate == null
? ASubTitle(
_subtitle.requiredWord,
color: Colors.red,
)
: const SizedBox.shrink(),
Row(
children: [
Expanded(
@ -187,7 +198,7 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
date: _serviceReport.visitDate,
from: DateTime.now().subtract(const Duration(days: 365)),
to: DateTime.now().add(const Duration(days: 365)),
onDatePicker: (date){
onDatePicker: (date) {
_serviceReport.visitDate = date;
setState(() {});
},
@ -198,44 +209,59 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
],
),
),
],
),
const SizedBox(height: 8,),
const SizedBox(
height: 8,
),
// device sn
Visibility(
visible: true,//widget.report.device == null,
visible: true, //widget.report.device == null,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(_subtitle.deviceSN),
_validate && _serviceReport.device?.id == null ?
ASubTitle(_subtitle.requiredWord,color: Colors.red,):
const SizedBox.shrink(),
_validate && _serviceReport.device?.id == null
? ASubTitle(
_subtitle.requiredWord,
color: Colors.red,
)
: const SizedBox.shrink(),
AutoCompleteDeviceField(
hospitalId: widget.request.hospitalId,
initialValue: _serviceReport.device!,
onPick: (id){
onPick: (id) {
_serviceReport.device?.id = id;
},
),
const SizedBox(height: 8,),
const SizedBox(
height: 8,
),
],
),
),
const SizedBox(height: 8,),
const SizedBox(
height: 8,
),
ASubTitle(_subtitle.serviceType),
_validate && _serviceReport.serviceType == null ?
ASubTitle(_subtitle.requiredWord,color: Colors.red,):
const SizedBox.shrink(),
const SizedBox(height: 4,),
_validate && _serviceReport.serviceType == null
? ASubTitle(
_subtitle.requiredWord,
color: Colors.red,
)
: const SizedBox.shrink(),
const SizedBox(
height: 4,
),
ServiceStatusMenu(
initialValue: _serviceReport.serviceType,
onSelect: (status){
onSelect: (status) {
_serviceReport.serviceType = status;
},
),
const SizedBox(height: 8,),
const SizedBox(
height: 8,
),
// Report status and Service Type
Row(
children: [
@ -245,102 +271,120 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(_subtitle.reportStatus),
_validate && _serviceReport.status == null ?
ASubTitle(_subtitle.requiredWord,color: Colors.red,):
const SizedBox.shrink(),
const SizedBox(height: 4,),
_validate && _serviceReport.status == null
? ASubTitle(
_subtitle.requiredWord,
color: Colors.red,
)
: const SizedBox.shrink(),
const SizedBox(
height: 4,
),
ServiceReportStatusMenu(
report: _serviceReport,
onSelect: (status){
onSelect: (status) {
_serviceReport.status = status;
},
),
],
),
),
const SizedBox(width: 8,),
const SizedBox(
width: 8,
),
Provider.of<ServiceReportLastCallsProvider>(context).isLoading == null
? const SizedBox.shrink():
// Call's last Situation
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(_subtitle.callLastSituation),
_validate && _serviceReport.callLastSituation == null ?
ASubTitle(_subtitle.requiredWord,color: Colors.red,):
const SizedBox.shrink(),
const SizedBox(height: 4,),
ServiceReportLastCallsMenu(
report: _serviceReport,
onSelect: (status){
if(status?.id == 12
|| _serviceReport.callLastSituation?.id == 12){
_serviceReport.callLastSituation = status;
setState(() {});
} else {
_serviceReport.callLastSituation = status;
}
},
? const SizedBox.shrink()
:
// Call's last Situation
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(_subtitle.callLastSituation),
_validate && _serviceReport.callLastSituation == null
? ASubTitle(
_subtitle.requiredWord,
color: Colors.red,
)
: const SizedBox.shrink(),
const SizedBox(
height: 4,
),
ServiceReportLastCallsMenu(
report: _serviceReport,
onSelect: (status) {
if (status?.id == 12 || _serviceReport.callLastSituation?.id == 12) {
_serviceReport.callLastSituation = status;
setState(() {});
} else {
_serviceReport.callLastSituation = status;
}
},
),
],
),
),
],
),
),
],
),
const SizedBox(height: 8,),
const SizedBox(
height: 8,
),
// invoice number & code
_serviceReport.callLastSituation?.id != 12 ? const SizedBox.shrink():
Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
_serviceReport.callLastSituation?.id != 12
? const SizedBox.shrink()
: Row(
children: [
ASubTitle(_subtitle.invoiceNumber),
const SizedBox(height: 8,),
ATextFormField(
initialValue: _serviceReport?.invoiceNumber,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.subtitle1,
validator: (value) =>
Validator.hasValue(value!)
? '' : _subtitle.requiredWord,
textInputType: TextInputType.number,
onSaved: (value){
_serviceReport.invoiceNumber = value;
},
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(_subtitle.invoiceNumber),
const SizedBox(
height: 8,
),
ATextFormField(
initialValue: _serviceReport?.invoiceNumber,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.subtitle1,
validator: (value) => Validator.hasValue(value!) ? '' : _subtitle.requiredWord,
textInputType: TextInputType.number,
onSaved: (value) {
_serviceReport.invoiceNumber = value;
},
),
],
),
),
],
),
),
const SizedBox(width: 8,),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(_subtitle.invoiceCode),
const SizedBox(height: 4,),
ATextFormField(
initialValue: _serviceReport?.invoiceCode,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.subtitle1,
validator: (value) =>
Validator.hasValue(value!)
? '' : _subtitle.requiredWord,
textInputType: TextInputType.text,
onSaved: (value){
_serviceReport.invoiceCode = value;
},
const SizedBox(
width: 8,
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(_subtitle.invoiceCode),
const SizedBox(
height: 4,
),
ATextFormField(
initialValue: _serviceReport?.invoiceCode,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.subtitle1,
validator: (value) => Validator.hasValue(value!) ? '' : _subtitle.requiredWord,
textInputType: TextInputType.text,
onSaved: (value) {
_serviceReport.invoiceCode = value;
},
),
],
),
),
],
),
),
],
),
const SizedBox(height: 8,),
const SizedBox(
height: 8,
),
Row(
children: [
ASubTitle(_subtitle.faultDescription),
@ -355,21 +399,23 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
),
],
),
const SizedBox(height: 4,),
const SizedBox(
height: 4,
),
ATextFormField(
initialValue: _serviceReport?.faultDescription,
textAlign: TextAlign.center,
controller: _faultController,
style: Theme.of(context).textTheme.subtitle1,
validator: (value) =>
Validator.hasValue(value!)
? '' : _subtitle.requiredWord,
validator: (value) => Validator.hasValue(value!) ? '' : _subtitle.requiredWord,
textInputType: TextInputType.multiline,
onSaved: (value){
onSaved: (value) {
_serviceReport.faultDescription = value;
},
),
const SizedBox(height: 8,),
const SizedBox(
height: 8,
),
Row(
children: [
ASubTitle(_subtitle.workPreformed),
@ -384,23 +430,27 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
),
],
),
const SizedBox(height: 4,),
const SizedBox(
height: 4,
),
ATextFormField(
initialValue: _serviceReport?.workPreformed,
textAlign: TextAlign.center,
controller: _workPreformedController,
style: Theme.of(context).textTheme.subtitle1,
validator: (value) =>
Validator.hasValue(value!)
? '' : _subtitle.requiredWord,
validator: (value) => Validator.hasValue(value!) ? '' : _subtitle.requiredWord,
textInputType: TextInputType.multiline,
onSaved: (value){
onSaved: (value) {
_serviceReport.workPreformed = value;
},
),
const SizedBox(height: 8,),
const SizedBox(
height: 8,
),
const SizedBox(height: 8,),
const SizedBox(
height: 8,
),
Row(
children: [
// reasons
@ -409,17 +459,21 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(_subtitle.reasons),
const SizedBox(height: 4,),
const SizedBox(
height: 4,
),
ServiceReportReasonsMenu(
initialValue: _serviceReport.reason,
onSelect: (status){
onSelect: (status) {
_serviceReport.reason = status;
},
),
],
),
),
const SizedBox(width: 8,),
const SizedBox(
width: 8,
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@ -428,8 +482,8 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
AMiniOneImagePicker(
//error: _validate && _serviceReport.image == null,
image: _image,
onPick: (image){
_image =image;
onPick: (image) {
_image = image;
_serviceReport.image = base64Encode(image.readAsBytesSync());
},
),
@ -438,7 +492,9 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
),
],
),
const SizedBox(height: 8,),
const SizedBox(
height: 8,
),
// Traveling Hours & Working Hours
Row(
children: [
@ -447,10 +503,12 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(_subtitle.workingHours),
const SizedBox(height: 8,),
const SizedBox(
height: 8,
),
AppTimer(
timer: _serviceReport.timer,
onChange: (timer) async{
onChange: (timer) async {
_serviceReport.timer = timer;
return true;
},
@ -471,23 +529,25 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
],
),
),
const SizedBox(width: 8,),
const SizedBox(
width: 8,
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(_subtitle.travelingHours),
const SizedBox(height: 4,),
const SizedBox(
height: 4,
),
ATextFormField(
initialValue: _serviceReport?.travelingHours,
textAlign: TextAlign.center,
hintText: "i.e 3, 3.5, 4",
style: Theme.of(context).textTheme.subtitle1,
validator: (value) =>
Validator.isNumeric(value!)
? '' : _subtitle.requiredWord,
validator: (value) => Validator.isNumeric(value!) ? '' : _subtitle.requiredWord,
textInputType: TextInputType.number,
onSaved: (value){
onSaved: (value) {
_serviceReport.travelingHours = value;
},
),
@ -496,7 +556,9 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
),
],
),
const SizedBox(height: 8,),
const SizedBox(
height: 8,
),
// Operating Hours and Job Sheet Number
Row(
children: [
@ -505,36 +567,40 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(_subtitle.operatingHours),
const SizedBox(height: 4,),
const SizedBox(
height: 4,
),
ATextFormField(
initialValue: _serviceReport?.operatingHours,
textAlign: TextAlign.center,
hintText: "i.e 3, 3.5, 4",
style: Theme.of(context).textTheme.subtitle1,
validator: (value) =>
Validator.isNumeric(value!)
? '' : _subtitle.requiredWord,
validator: (value) => Validator.isNumeric(value!) ? '' : _subtitle.requiredWord,
textInputType: TextInputType.number,
onSaved: (value){
onSaved: (value) {
_serviceReport.operatingHours = value;
},
),
],
),
),
const SizedBox(width: 8,),
const SizedBox(
width: 8,
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(_subtitle.jobSheetNumber),
const SizedBox(height: 4,),
const SizedBox(
height: 4,
),
ATextFormField(
initialValue: _serviceReport?.jobSheetNumber,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.subtitle1,
textInputType: TextInputType.name,
onSaved: (value){
onSaved: (value) {
_serviceReport.jobSheetNumber = value;
},
),
@ -543,7 +609,9 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
),
],
),
const SizedBox(height: 8,),
const SizedBox(
height: 8,
),
// Part Number and Quantity
Row(
children: [
@ -553,12 +621,17 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(_subtitle.partNumber),
_validate && _serviceReport.parts == null ?
ASubTitle(_subtitle.requiredWord,color: Colors.red,):
const SizedBox.shrink(),
const SizedBox(height: 4,),
_validate && _serviceReport.parts == null
? ASubTitle(
_subtitle.requiredWord,
color: Colors.red,
)
: const SizedBox.shrink(),
const SizedBox(
height: 4,
),
AutoCompletePartsField(
onPick: (part){
onPick: (part) {
_serviceReport.parts?.add(part);
setState(() {});
},
@ -566,34 +639,33 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
],
),
),
],
),
SizedBox(height: 8*AppStyle.getScaleFactor(context),),
SizedBox(
height: 8 * AppStyle.getScaleFactor(context),
),
Row(
children: [
Expanded(flex:3,child: Text(_subtitle.number)),
Expanded(flex: 1,child: Text(_subtitle.quantity)),
Expanded(flex: 3, child: Text(_subtitle.number)),
Expanded(flex: 1, child: Text(_subtitle.quantity)),
],
),
Column(
children: List.generate(
_serviceReport.parts!.length,
(index) {
Part _part = _serviceReport.parts![index];
return PartItem(
part: _part,
onDelete: (part){
_serviceReport.parts?.remove(part);
setState(() {});
},
);
}
),
children: List.generate(_serviceReport.parts!.length, (index) {
Part _part = _serviceReport.parts![index];
return PartItem(
part: _part,
onDelete: (part) {
_serviceReport.parts?.remove(part);
setState(() {});
},
);
}),
),
const SizedBox(height: 16,),
const SizedBox(
height: 16,
),
],
),
),
@ -603,48 +675,41 @@ class _EditServiceReportState extends State<EditServiceReport> with TickerProvid
text: _subtitle.update,
onPressed: () async {
_validate = true;
if(!(_formKey.currentState?.validate()??false)){
if (!(_formKey.currentState?.validate() ?? false)) {
setState(() {});
return;
}
if(!_serviceReport.validate()) {
if (!_serviceReport.validate()) {
setState(() {});
return;
}
_formKey.currentState?.save();
_isLoading =true;
_isLoading = true;
setState(() {});
int status = await _serviceRequestsProvider.updateServiceReport(
user: _userProvider.user!,
host: _settingProvider.host??"",
report: _serviceReport,
request: widget.request
);
_isLoading =false;
int status =
await _serviceRequestsProvider.updateServiceReport(user: UserApiClient().user!, host: _settingProvider.host ?? "", report: _serviceReport, request: widget.request);
_isLoading = false;
setState(() {});
if(status >= 200 && status < 300){
if (status >= 200 && status < 300) {
Fluttertoast.showToast(
msg: _subtitle.requestCompleteSuccessfully,
msg: _subtitle.requestCompleteSuccessfully,
);
Navigator.of(context).pop();
Navigator.of(context).pop();
}else{
String errorMessage = HttpStatusManger.getStatusMessage(
status: status, subtitle: _subtitle);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
errorMessage
),
)
);
} else {
String errorMessage = HttpStatusManger.getStatusMessage(status: status, subtitle: _subtitle);
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(errorMessage),
));
}
},
),
),
const SizedBox(height: 300,)
const SizedBox(
height: 300,
)
],
),
const ABackButton(),

@ -1,16 +1,18 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../../../../api/login_api_client.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 '../../../../../controllers/providers/user_provider.dart';
import '../../../../../models/service_report.dart';
import '../../../../../models/service_request/service_request.dart';
import '../../../../../models/subtitle.dart';
import '../../../../widgets/loaders/app_loading.dart';
import '../../../../widgets/loaders/failed_loading.dart';
import 'edit_service_report.dart';
class FutureServiceReport extends StatefulWidget {
final ServiceRequest request;
@ -21,7 +23,6 @@ class FutureServiceReport extends StatefulWidget {
}
class _FutureServiceReportState extends State<FutureServiceReport> {
late UserProvider _userProvider;
late SettingProvider _settingProvider;
@override
@ -31,19 +32,16 @@ class _FutureServiceReportState extends State<FutureServiceReport> {
Subtitle _subtitle = AppLocalization.of(context)!.subtitle!;
return Scaffold(
body: FutureBuilder<ServiceReport>(
future: ServiceRequestsProvider().getSingleServiceReport(
reportId: widget.request.reportID??"",
user: _userProvider.user!,
host: _settingProvider.host??"",
subtitle: _subtitle
),
builder: (BuildContext context, AsyncSnapshot<ServiceReport> snapshot){
if(snapshot.hasError)
future: ServiceRequestsProvider().getSingleServiceReport(reportId: widget.request.reportID ?? "", user: UserApiClient().user!, host: _settingProvider.host ?? "", subtitle: _subtitle),
builder: (BuildContext context, AsyncSnapshot<ServiceReport> snapshot) {
if (snapshot.hasError)
return FailedLoading(
message: snapshot.error.toString(),
onReload: (){setState(() {});},
onReload: () {
setState(() {});
},
);
if(snapshot.hasData){
if (snapshot.hasData) {
return EditServiceReport(
report: snapshot.data!,
request: widget.request,

@ -1,14 +1,13 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import '../../../../api/login_api_client.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 '../../../../controllers/providers/user_provider.dart';
import '../../../../models/enums/user_types.dart';
import '../../../../models/service_request/service_request.dart';
import '../../../../models/subtitle.dart';
@ -28,6 +27,7 @@ import '../../../widgets/titles/app_sub_title.dart';
import '../report_issues_page.dart';
import 'report/create_service_report.dart';
import 'report/future_service_report.dart';
class RequestDetailsPage extends StatelessWidget {
static final String id = "/call-details";
final ServiceRequest serviceRequest;
@ -46,8 +46,8 @@ class RequestDetailsPage extends StatelessWidget {
child: Column(
children: [
Container(
color:AColors.primaryColor,
padding: const EdgeInsets.symmetric(horizontal: 0,vertical: 4),
color: AColors.primaryColor,
padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 4),
child: Row(
children: [
ABackButton(),
@ -55,26 +55,25 @@ class RequestDetailsPage extends StatelessWidget {
child: Center(
child: Text(
_subtitle.details,
style: Theme.of(context).textTheme.headline6?.copyWith(
color: AColors.white,
fontStyle: FontStyle.italic
),
style: Theme.of(context).textTheme.headline6?.copyWith(color: AColors.white, fontStyle: FontStyle.italic),
),
),
),
Visibility(
visible: _userProvider.user?.type == UsersTypes.normal_user,
replacement: AIconButton(
visible: UserApiClient().user?.type == UsersTypes.normal_user,
replacement: AIconButton(
iconData: Icons.edit,
color: AColors.white,
buttonSize: 42,
backgroundColor: AColors.green,
onPressed: () async {
showModalBottomSheet(
context: context,
builder: (context){
return ServiceRequestsUpdateDialog(request: serviceRequest,);
});
showModalBottomSheet(
context: context,
builder: (context) {
return ServiceRequestsUpdateDialog(
request: serviceRequest,
);
});
// DateTime picked = await showDatePicker(
// context: context,
// initialDate: DateTime.now(),
@ -109,71 +108,75 @@ class RequestDetailsPage extends StatelessWidget {
color: AColors.white,
buttonSize: 42,
backgroundColor: AColors.deepOrange,
onPressed: (){
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => ReportIssuesPage(serviceRequest: serviceRequest,)
)
);
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (_) => ReportIssuesPage(
serviceRequest: serviceRequest,
)));
},
),
),
SizedBox(width: 16,)
SizedBox(
width: 16,
)
],
),
),
(serviceRequest.devicePhotos?.isEmpty??false) ? SizedBox.shrink():
Column(
children: [
SizedBox(height: 8,),
MaterialButton(
padding: EdgeInsets.zero,
onPressed: (){
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => Scaffold(
body: InteractiveViewer(
child: Center(
child: ImageLoader(
url: serviceRequest.devicePhotos?.first,
boxFit: BoxFit.contain,
),
),
),
)
)
);
},
child: SizedBox(
height: 140 * AppStyle.getScaleFactor(context),
width: MediaQuery.of(context).size.width,
child: ImageLoader(
url: serviceRequest.devicePhotos?.first,
boxFit: BoxFit.cover,
),
),
),
SizedBox(height: 8,),
SizedBox(
height: 60* AppStyle.getScaleFactor(context),
child: ImagesList(
images: serviceRequest.devicePhotos!,
(serviceRequest.devicePhotos?.isEmpty ?? false)
? SizedBox.shrink()
: Column(
children: [
SizedBox(
height: 8,
),
MaterialButton(
padding: EdgeInsets.zero,
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (_) => Scaffold(
body: InteractiveViewer(
child: Center(
child: ImageLoader(
url: serviceRequest.devicePhotos?.first,
boxFit: BoxFit.contain,
),
),
),
)));
},
child: SizedBox(
height: 140 * AppStyle.getScaleFactor(context),
width: MediaQuery.of(context).size.width,
child: ImageLoader(
url: serviceRequest.devicePhotos?.first,
boxFit: BoxFit.cover,
),
),
),
SizedBox(
height: 8,
),
SizedBox(
height: 60 * AppStyle.getScaleFactor(context),
child: ImagesList(
images: serviceRequest.devicePhotos!,
),
),
],
),
),
],
),
TabBar(
labelColor: AColors.primaryColor,
tabs: [
Tab(text: _subtitle.general,),
Tab(text: _subtitle.serviceRequestInformation,),
TabBar(labelColor: AColors.primaryColor, tabs: [
Tab(
text: _subtitle.general,
),
Tab(
text: _subtitle.serviceRequestInformation,
),
]),
SizedBox(height: 8,),
SizedBox(
height: 8,
),
Expanded(
child: TabBarView(
children: [
ListView(
padding: EdgeInsets.symmetric(horizontal: 16),
@ -192,7 +195,7 @@ class RequestDetailsPage extends StatelessWidget {
),
RequestInfoRow(
title: _subtitle.deviceModel,
info : serviceRequest.deviceModel,
info: serviceRequest.deviceModel,
),
RequestInfoRow(
title: _subtitle.engineerName,
@ -206,11 +209,12 @@ class RequestDetailsPage extends StatelessWidget {
title: _subtitle.date,
info: serviceRequest.date,
),
serviceRequest.nextVisitDate == null ? SizedBox.shrink() :
RequestInfoRow(
title: _subtitle.nextVisitDate,
info: DateFormat('EE dd/MM/yyyy').format(serviceRequest.nextVisitDate!),
),
serviceRequest.nextVisitDate == null
? SizedBox.shrink()
: RequestInfoRow(
title: _subtitle.nextVisitDate,
info: DateFormat('EE dd/MM/yyyy').format(serviceRequest.nextVisitDate!),
),
Row(
children: [
Expanded(
@ -220,12 +224,12 @@ class RequestDetailsPage extends StatelessWidget {
textScaleFactor: AppStyle.getScaleFactor(context),
),
),
StatusLabel(label: serviceRequest.statusLabel,
color: AColors.getRequestStatusColor(serviceRequest.statusValue!)
),
StatusLabel(label: serviceRequest.statusLabel, color: AColors.getRequestStatusColor(serviceRequest.statusValue!)),
],
),
Divider(color: Theme.of(context).primaryColor,),
Divider(
color: Theme.of(context).primaryColor,
),
RequestInfoRow(
title: _subtitle.hospital,
info: serviceRequest.hospitalName,
@ -246,10 +250,10 @@ class RequestDetailsPage extends StatelessWidget {
title: _subtitle.maintenanceIssue,
content: serviceRequest.maintenanceIssue,
),
if(serviceRequest.audio?.isNotEmpty == true)
ASoundPlayer(
audio: serviceRequest.audio,
),
if (serviceRequest.audio?.isNotEmpty == true)
ASoundPlayer(
audio: serviceRequest.audio,
),
Center(
child: Padding(
padding: EdgeInsets.all(32),
@ -259,30 +263,18 @@ class RequestDetailsPage extends StatelessWidget {
bool result = await showDialog(
context: context,
builder: (_) => AAlertDialog(
title: _subtitle.duplicateAlert,
content: _subtitle.duplicateAlertMessage,
)
);
if(result == true){
title: _subtitle.duplicateAlert,
content: _subtitle.duplicateAlertMessage,
));
if (result == true) {
showDialog(
context: context,
builder: (context){
builder: (context) {
return Center(child: CircularProgressIndicator());
}
);
int status = await _serviceRequestsProvider.createDuplicatedReport(
host: _settingProvider.host??"",
user: _userProvider.user!,
request: serviceRequest
);
});
int status = await _serviceRequestsProvider.createDuplicatedReport(host: _settingProvider.host ?? "", user: UserApiClient().user!, request: serviceRequest);
Navigator.of(context).pop();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
HttpStatusManger.getStatusMessage(status: status, subtitle: _subtitle)
)
)
);
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(HttpStatusManger.getStatusMessage(status: status, subtitle: _subtitle))));
}
},
),
@ -290,64 +282,64 @@ class RequestDetailsPage extends StatelessWidget {
)
],
),
serviceRequest.viewReport??false ?
ListView(
padding: EdgeInsets.symmetric(horizontal: 16),
children: [
RequestInfoRow(
title: _subtitle.faultDescription,
content: serviceRequest.faultDescription,
),
RequestInfoRow(
title: _subtitle.workPerformed,
content: serviceRequest.workPerformed,
),
RequestInfoRow(
title: _subtitle.visitDate,
info: serviceRequest.visitDate,
),
RequestInfoRow(
title: _subtitle.jobSheetNumber,
info: serviceRequest.jobSheetNumber,
),
_userProvider.user?.type == UsersTypes.engineer ?
Padding(
padding: EdgeInsets.all(32),
child: AButton(
text: _subtitle.editServiceReport,
onPressed: (){
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => FutureServiceReport(
request: serviceRequest,
serviceRequest.viewReport ?? false
? ListView(
padding: EdgeInsets.symmetric(horizontal: 16),
children: [
RequestInfoRow(
title: _subtitle.faultDescription,
content: serviceRequest.faultDescription,
),
RequestInfoRow(
title: _subtitle.workPerformed,
content: serviceRequest.workPerformed,
),
RequestInfoRow(
title: _subtitle.visitDate,
info: serviceRequest.visitDate,
),
RequestInfoRow(
title: _subtitle.jobSheetNumber,
info: serviceRequest.jobSheetNumber,
),
UserApiClient().user?.type == UsersTypes.engineer
? Padding(
padding: EdgeInsets.all(32),
child: AButton(
text: _subtitle.editServiceReport,
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => FutureServiceReport(
request: serviceRequest,
)),
);
},
),
)
: SizedBox.shrink(),
],
)
: UserApiClient().user?.type == UsersTypes.engineer
? Center(
child: Padding(
padding: EdgeInsets.all(32),
child: AButton(
text: "Create Report",
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => CreateServiceReport(
request: serviceRequest,
)),
);
},
),
),
);
},
),
): SizedBox.shrink(),
],
):
_userProvider.user?.type == UsersTypes.engineer ?
Center(
child: Padding(
padding: EdgeInsets.all(32),
child: AButton(
text: "Create Report",
onPressed: (){
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => CreateServiceReport(
request: serviceRequest,
)
)
: Center(
child: ASubTitle(_subtitle.noDateFound),
),
);
},
),
),
): Center(child: ASubTitle(_subtitle.noDateFound),),
],
),
),

@ -1,10 +1,11 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../../../api/login_api_client.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 '../../../../controllers/providers/user_provider.dart';
import '../../../../models/service_request/service_request_search.dart';
import '../../../../models/subtitle.dart';
import '../../../app_style/colors.dart';
@ -21,8 +22,7 @@ class ServiceRequestsPage extends StatefulWidget {
_ServiceRequestsPageState createState() => _ServiceRequestsPageState();
}
class _ServiceRequestsPageState extends State<ServiceRequestsPage>
with TickerProviderStateMixin {
class _ServiceRequestsPageState extends State<ServiceRequestsPage> with TickerProviderStateMixin {
late ServiceRequestsProvider _serviceRequestsProvider;
late UserProvider _userProvider;
late SettingProvider _settingProvider;
@ -49,9 +49,9 @@ class _ServiceRequestsPageState extends State<ServiceRequestsPage>
onRefresh: () async {
_serviceRequestsProvider.reset();
await _serviceRequestsProvider.getRequests(
user: _userProvider.user!,
user: UserApiClient().user!,
host: _settingProvider.host ?? "",
hospitalId: _userProvider.user!.hospital!.id,
hospitalId: UserApiClient().user!.hospital!.id,
);
},
child: Stack(
@ -60,8 +60,7 @@ class _ServiceRequestsPageState extends State<ServiceRequestsPage>
children: [
Container(
color: AColors.primaryColor,
padding:
const EdgeInsets.symmetric(horizontal: 0, vertical: 4),
padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 4),
child: Column(
children: [
Row(
@ -71,10 +70,7 @@ class _ServiceRequestsPageState extends State<ServiceRequestsPage>
child: Center(
child: Text(
subtitle?.serviceRequests ?? '',
style: Theme.of(context)
.textTheme
.titleLarge
?.copyWith(
style: Theme.of(context).textTheme.titleLarge?.copyWith(
color: AColors.white,
fontStyle: FontStyle.italic,
),
@ -88,14 +84,12 @@ class _ServiceRequestsPageState extends State<ServiceRequestsPage>
buttonSize: 42,
backgroundColor: AColors.white,
onPressed: () async {
ServiceRequestSearch? temp =
await showModalBottomSheet(
ServiceRequestSearch? temp = await showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (context) {
return ServiceRequestsSearchDialog(
initialSearchValue:
_serviceRequestsProvider.search!,
initialSearchValue: _serviceRequestsProvider.search!,
);
},
);
@ -117,9 +111,9 @@ class _ServiceRequestsPageState extends State<ServiceRequestsPage>
nextPage: _serviceRequestsProvider.nextPage!,
onLazyLoad: () async {
await _serviceRequestsProvider.getRequests(
user: _userProvider.user,
user: UserApiClient().user,
host: _settingProvider.host ?? "",
hospitalId: _userProvider.user?.hospital?.id,
hospitalId: UserApiClient().user?.hospital?.id,
);
},
requests: _serviceRequestsProvider.serviceRequests ?? [],

@ -2,10 +2,10 @@ import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart';
import '../../../../../api/login_api_client.dart';
import '../../../../../controllers/http_status_manger/http_status_manger.dart';
import '../../../../../controllers/localization/localization.dart';
import '../../../../../controllers/providers/api/regular_visits_provider.dart';
import '../../../../../controllers/providers/api/user_provider.dart';
import '../../../../../controllers/providers/settings/setting_provider.dart';
import '../../../../../models/pantry/pentry.dart';
import '../../../../../models/subtitle.dart';
@ -31,7 +31,6 @@ class _EditPentryState extends State<EditPentry> with SingleTickerProviderStateM
bool _isLoading = false;
bool _validate = false;
Subtitle? _subtitle;
late UserProvider _userProvider;
late SettingProvider _settingProvider;
late RegularVisitsProvider _regularVisitsProvider;
Pentry? _pentry;
@ -50,7 +49,7 @@ class _EditPentryState extends State<EditPentry> with SingleTickerProviderStateM
_isLoading = true;
setState(() {});
int status = await _regularVisitsProvider.updatePentry(user: _userProvider.user, host: _settingProvider.host, pentry: _pentry, visit: widget.visit);
int status = await _regularVisitsProvider.updatePentry(user: UserApiClient().user, host: _settingProvider.host, pentry: _pentry, visit: widget.visit);
_isLoading = false;
setState(() {});
if (status >= 200 && status < 300) {
@ -84,7 +83,6 @@ class _EditPentryState extends State<EditPentry> with SingleTickerProviderStateM
@override
Widget build(BuildContext context) {
_subtitle = AppLocalization.of(context)?.subtitle;
_userProvider = Provider.of<UserProvider>(context);
_settingProvider = Provider.of<SettingProvider>(context);
_regularVisitsProvider = Provider.of<RegularVisitsProvider>(context);
return Scaffold(

@ -1,9 +1,9 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../../../../api/login_api_client.dart';
import '../../../../../controllers/localization/localization.dart';
import '../../../../../controllers/providers/api/regular_visits_provider.dart';
import '../../../../../controllers/providers/api/user_provider.dart';
import '../../../../../controllers/providers/settings/setting_provider.dart';
import '../../../../../models/pantry/pentry.dart';
import '../../../../../models/subtitle.dart';
@ -13,7 +13,6 @@ import '../../../../widgets/loaders/failed_loading.dart';
import 'edit_pentry.dart';
class FutureEditPentry extends StatefulWidget {
final Visit visit;
const FutureEditPentry({Key? key, required this.visit}) : super(key: key);
@ -23,31 +22,25 @@ class FutureEditPentry extends StatefulWidget {
}
class _FutureEditPentryState extends State<FutureEditPentry> {
late UserProvider _userProvider;
late SettingProvider _settingProvider;
@override
Widget build(BuildContext context) {
_userProvider = Provider.of<UserProvider>(context);
_settingProvider = Provider.of<SettingProvider>(context);
//String requestId = ModalRoute.of(context).settings.arguments;
Subtitle subtitle = AppLocalization.of(context)!.subtitle!;
return Scaffold(
body: FutureBuilder<Pentry?>(
future: RegularVisitsProvider().getPently(
user: _userProvider.user!,
host: _settingProvider.host??"",
id: widget.visit.id!
),
builder: (BuildContext context, AsyncSnapshot<Pentry?> snapshot){
if(snapshot.hasError) {
future: RegularVisitsProvider().getPently(user: UserApiClient().user!, host: _settingProvider.host ?? "", id: widget.visit.id!),
builder: (BuildContext context, AsyncSnapshot<Pentry?> snapshot) {
if (snapshot.hasError) {
return FailedLoading(
message: subtitle.failedToCompleteRequest,
onReload: (){setState(() {});},
onReload: () {
setState(() {});
},
);
}
if(snapshot.hasData){
if (snapshot.hasData) {
return EditPentry(
pentry: snapshot.data,
visit: widget.visit,

@ -3,11 +3,12 @@ import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart';
import '../../../../api/login_api_client.dart';
import '../../../../controllers/http_status_manger/http_status_manger.dart';
import '../../../../controllers/localization/localization.dart';
import '../../../../controllers/providers/api/preventive_maintenance_visits_provider.dart';
import '../../../../controllers/providers/api/user_provider.dart';
import '../../../../controllers/providers/settings/setting_provider.dart';
import '../../../../controllers/providers/user_provider.dart';
import '../../../../models/subtitle.dart';
import '../../../../models/visits/visits_group.dart';
import '../../../../models/visits/visits_search.dart';
@ -26,8 +27,7 @@ class PreventiveMaintenanceVisitsPage extends StatefulWidget {
_PreventiveMaintenanceVisitsPageState createState() => _PreventiveMaintenanceVisitsPageState();
}
class _PreventiveMaintenanceVisitsPageState extends State<PreventiveMaintenanceVisitsPage>
with TickerProviderStateMixin{
class _PreventiveMaintenanceVisitsPageState extends State<PreventiveMaintenanceVisitsPage> with TickerProviderStateMixin {
late PreventiveMaintenanceVisitsProvider _visitsProvider;
late UserProvider _userProvider;
late SettingProvider _settingProvider;
@ -49,8 +49,8 @@ class _PreventiveMaintenanceVisitsPageState extends State<PreventiveMaintenanceV
//_visitsProvider.visitsSearch = VisitsSearch();
_visitsProvider.reset();
await _visitsProvider.getVisits(
user: _userProvider.user!,
host: _settingProvider.host??"",
user: UserApiClient().user!,
host: _settingProvider.host ?? "",
//visitsSearch: _visitsSearch
);
},
@ -59,8 +59,8 @@ class _PreventiveMaintenanceVisitsPageState extends State<PreventiveMaintenanceV
Column(
children: [
Container(
color:AColors.primaryColor,
padding: const EdgeInsets.symmetric(horizontal: 0,vertical: 4),
color: AColors.primaryColor,
padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 4),
child: Column(
children: [
Row(
@ -70,10 +70,7 @@ class _PreventiveMaintenanceVisitsPageState extends State<PreventiveMaintenanceV
child: Center(
child: Text(
_subtitle.preventiveMaintenance,
style: Theme.of(context).textTheme.headline6?.copyWith(
color: AColors.white,
fontStyle: FontStyle.italic
),
style: Theme.of(context).textTheme.headline6?.copyWith(color: AColors.white, fontStyle: FontStyle.italic),
),
),
),
@ -86,37 +83,39 @@ class _PreventiveMaintenanceVisitsPageState extends State<PreventiveMaintenanceV
VisitsSearch? _temp = await showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (context){
builder: (context) {
return VisitsSearchDialog(
initialSearchValue: _visitsProvider.visitsSearch!, onSearch: (VisitsSearch ) {},
initialSearchValue: _visitsProvider.visitsSearch!,
onSearch: (VisitsSearch) {},
);
});
if(_temp != null){
if (_temp != null) {
_visitsProvider.visitsSearch = _temp;
_visitsProvider.reset();
setState(() {});
await _visitsProvider.getVisits(
user: _userProvider.user!,
host: _settingProvider.host??"",
//visitsSearch: _visitsSearch
user: UserApiClient().user!,
host: _settingProvider.host ?? "",
//visitsSearch: _visitsSearch
);
}
},
),
SizedBox(width: 16,)
SizedBox(
width: 16,
)
],
),
],
),
),
Visibility(
visible:_visitsProvider.visitsSearch?.toSearchString().isNotEmpty??false,
visible: _visitsProvider.visitsSearch?.toSearchString().isNotEmpty ?? false,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: AButton(
text: _subtitle.clearSearch,
onPressed: (){
onPressed: () {
_visitsProvider.visitsSearch = VisitsSearch();
_visitsProvider.reset();
setState(() {});
@ -129,9 +128,9 @@ class _PreventiveMaintenanceVisitsPageState extends State<PreventiveMaintenanceV
nextPage: _visitsProvider.nextPage!,
onLazyLoad: () async {
await _visitsProvider.getVisits(
user: _userProvider.user!,
host: _settingProvider.host??"",
//visitsSearch: _visitsSearch
user: UserApiClient().user!,
host: _settingProvider.host ?? "",
//visitsSearch: _visitsSearch
);
},
onEditGroup: (visits) async {
@ -139,10 +138,13 @@ class _PreventiveMaintenanceVisitsPageState extends State<PreventiveMaintenanceV
isScrollControlled: true,
context: context,
builder: (context) {
return UpdateVisitsGroupSheet(visits: visits,title:_subtitle.updatePreventiveMaintenance,);
return UpdateVisitsGroupSheet(
visits: visits,
title: _subtitle.updatePreventiveMaintenance,
);
},
)as VisitsGroup;
if(_group != null){
) as VisitsGroup;
if (_group != null) {
showDialog<void>(
context: context,
barrierDismissible: false,
@ -153,24 +155,17 @@ class _PreventiveMaintenanceVisitsPageState extends State<PreventiveMaintenanceV
);
},
);
int status = await _visitsProvider.updateGroupOfVisits(
user: _userProvider.user!,
host: _settingProvider.host??"",
group: _group
);
int status = await _visitsProvider.updateGroupOfVisits(user: UserApiClient().user!, host: _settingProvider.host ?? "", group: _group);
Navigator.of(context).pop();
if(status >= 200 && status < 300){
if (status >= 200 && status < 300) {
Fluttertoast.showToast(
msg: _subtitle.preventiveMaintenanceUpdatedSuccessfully,
toastLength: Toast.LENGTH_LONG,
gravity: ToastGravity.BOTTOM,
);
}else{
} else {
Fluttertoast.showToast(
msg: HttpStatusManger.getStatusMessage(
status: status,
subtitle: _subtitle
),
msg: HttpStatusManger.getStatusMessage(status: status, subtitle: _subtitle),
toastLength: Toast.LENGTH_LONG,
gravity: ToastGravity.BOTTOM,
);
@ -182,7 +177,6 @@ class _PreventiveMaintenanceVisitsPageState extends State<PreventiveMaintenanceV
),
],
),
],
),
),

@ -3,11 +3,12 @@ import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart';
import '../../../../api/login_api_client.dart';
import '../../../../controllers/http_status_manger/http_status_manger.dart';
import '../../../../controllers/localization/localization.dart';
import '../../../../controllers/providers/api/regular_visits_provider.dart';
import '../../../../controllers/providers/api/user_provider.dart';
import '../../../../controllers/providers/settings/setting_provider.dart';
import '../../../../controllers/providers/user_provider.dart';
import '../../../../models/subtitle.dart';
import '../../../../models/visits/visits_group.dart';
import '../../../../models/visits/visits_search.dart';
@ -28,8 +29,7 @@ class RegularVisitsPage extends StatefulWidget {
_RegularVisitsPageState createState() => _RegularVisitsPageState();
}
class _RegularVisitsPageState extends State<RegularVisitsPage>
with TickerProviderStateMixin {
class _RegularVisitsPageState extends State<RegularVisitsPage> with TickerProviderStateMixin {
late RegularVisitsProvider _visitsProvider;
late UserProvider _userProvider;
late SettingProvider _settingProvider;
@ -50,7 +50,7 @@ class _RegularVisitsPageState extends State<RegularVisitsPage>
_visitsProvider.reset();
//_visitsProvider.visitsSearch = VisitsSearch();
await _visitsProvider.getVisits(
user: _userProvider.user,
user: UserApiClient().user,
host: _settingProvider.host,
);
},
@ -60,8 +60,7 @@ class _RegularVisitsPageState extends State<RegularVisitsPage>
children: [
Container(
color: AColors.primaryColor,
padding:
const EdgeInsets.symmetric(horizontal: 0, vertical: 4),
padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 4),
child: Column(
children: [
Row(
@ -71,12 +70,7 @@ class _RegularVisitsPageState extends State<RegularVisitsPage>
child: Center(
child: Text(
_subtitle.preventiveMaintenance,
style: Theme.of(context)
.textTheme
.headline6
?.copyWith(
color: AColors.white,
fontStyle: FontStyle.italic),
style: Theme.of(context).textTheme.headline6?.copyWith(color: AColors.white, fontStyle: FontStyle.italic),
),
),
),
@ -84,26 +78,21 @@ class _RegularVisitsPageState extends State<RegularVisitsPage>
duration: Duration(milliseconds: 400),
child: AIconButton(
key: ValueKey(_expandedSearch),
iconData: _expandedSearch
? Icons.keyboard_arrow_up
: Icons.search,
iconData: _expandedSearch ? Icons.keyboard_arrow_up : Icons.search,
color: AColors.secondaryColor,
buttonSize: 42,
backgroundColor: AColors.white,
onPressed: () async {
VisitsSearch _temp =
await showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (context) {
return VisitsSearchDialog(
initialSearchValue:
_visitsProvider.visitsSearch!,
onSearch: (VisitsSearch) {},
);
});
_visitsProvider.visitsSearch
?.fromSearch(_temp);
VisitsSearch _temp = await showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (context) {
return VisitsSearchDialog(
initialSearchValue: _visitsProvider.visitsSearch!,
onSearch: (VisitsSearch) {},
);
});
_visitsProvider.visitsSearch?.fromSearch(_temp);
_visitsProvider.reset();
setState(() {});
},
@ -118,10 +107,7 @@ class _RegularVisitsPageState extends State<RegularVisitsPage>
),
),
Visibility(
visible: _visitsProvider.visitsSearch
?.toSearchString()
.isNotEmpty ??
false,
visible: _visitsProvider.visitsSearch?.toSearchString().isNotEmpty ?? false,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: AButton(
@ -139,7 +125,7 @@ class _RegularVisitsPageState extends State<RegularVisitsPage>
nextPage: _visitsProvider.nextPage,
onLazyLoad: () async {
await _visitsProvider.getVisits(
user: _userProvider.user!,
user: UserApiClient().user!,
host: _settingProvider.host ?? "",
);
},
@ -161,16 +147,11 @@ class _RegularVisitsPageState extends State<RegularVisitsPage>
builder: (BuildContext context) {
return CupertinoAlertDialog(
title: Text(_subtitle.updatingDots),
content:
Center(child: CircularProgressIndicator()),
content: Center(child: CircularProgressIndicator()),
);
},
);
int status =
await _visitsProvider.updateGroupOfVisits(
user: _userProvider.user!,
host: _settingProvider.host ?? "",
group: group);
int status = await _visitsProvider.updateGroupOfVisits(user: UserApiClient().user!, host: _settingProvider.host ?? "", group: group);
Navigator.of(context).pop();
if (status >= 200 && status < 300) {
Fluttertoast.showToast(
@ -180,8 +161,7 @@ class _RegularVisitsPageState extends State<RegularVisitsPage>
);
} else {
Fluttertoast.showToast(
msg: HttpStatusManger.getStatusMessage(
status: status, subtitle: _subtitle),
msg: HttpStatusManger.getStatusMessage(status: status, subtitle: _subtitle),
toastLength: Toast.LENGTH_LONG,
gravity: ToastGravity.BOTTOM,
);

@ -29,13 +29,22 @@ class UpdateVisitsGroupSheet extends StatefulWidget {
class _UpdateVisitsGroupSheetState extends State<UpdateVisitsGroupSheet> {
List<Lookup> status = [
Lookup(label: "Done", id: 0,),
Lookup(
label: "Done",
id: 0,
),
Lookup(label: "Not Yet", id: 1),
Lookup(label: "On Hold", id: 2,),
Lookup(
label: "On Hold",
id: 2,
),
];
List<Lookup> taskStatus = [
Lookup(label: "Passed", id: 0,),
Lookup(
label: "Passed",
id: 0,
),
Lookup(label: "Failed", id: 1),
];
VisitsGroup _group = VisitsGroup();
@ -74,7 +83,7 @@ class _UpdateVisitsGroupSheetState extends State<UpdateVisitsGroupSheet> {
),
ASmallButton(
text: _subtitle.cancel,
onPressed: (){
onPressed: () {
Navigator.of(context).pop();
},
),
@ -83,87 +92,93 @@ class _UpdateVisitsGroupSheetState extends State<UpdateVisitsGroupSheet> {
AOneImagePicker(
image: _image,
onPick: (image){
_image =image;
onPick: (image) {
_image = image;
_group.image = base64Encode(image.readAsBytesSync());
},
),
SizedBox(height: 12 * AppStyle.getScaleFactor(context),),
SizedBox(
height: 12 * AppStyle.getScaleFactor(context),
),
ATextFormField(
initialValue: _group.jobSheetNumber,
hintText: _subtitle.jobSheetNumber,
style: Theme.of(context).textTheme.headline6,
onSaved: (value){
style: Theme.of(context).textTheme.headline6,
onSaved: (value) {
_group.jobSheetNumber = value;
},
),
SizedBox(height: 8 * AppStyle.getScaleFactor(context),),
SizedBox(
height: 8 * AppStyle.getScaleFactor(context),
),
ATextFormField(
initialValue: _group.workingHours,
hintText: _subtitle.workingHours,
style: Theme.of(context).textTheme.headline6,
onSaved: (value){
style: Theme.of(context).textTheme.headline6,
onSaved: (value) {
_group.workingHours = value;
},
),
SizedBox(height: 8 * AppStyle.getScaleFactor(context),),
SizedBox(
height: 8 * AppStyle.getScaleFactor(context),
),
ATextFormField(
initialValue: _group.travelingHours,
hintText: _subtitle.travelingHours,
style: Theme.of(context).textTheme.headline6,
onSaved: (value){
style: Theme.of(context).textTheme.headline6,
onSaved: (value) {
_group.travelingHours = value;
},
),
SizedBox(height: 8 * AppStyle.getScaleFactor(context),),
SizedBox(
height: 8 * AppStyle.getScaleFactor(context),
),
Row(
children: [
Expanded(
child: Text(
"${_subtitle.date} :",
"${_subtitle.date} :",
style: Theme.of(context).textTheme.subtitle1,
textScaleFactor: AppStyle.getScaleFactor(context),
),
),
ADatePicker(
date: _group.date ?? DateTime.now(),
onDatePicker: (date){
onDatePicker: (date) {
_group.date = date;
setState(() {});
},
),
],
),
// SizedBox(height: 8 * AStyling.getScaleFactor(context),),
// SizedBox(height: 8 * AStyling.getScaleFactor(context),),
Text(
"${_subtitle.status} :",
style: Theme.of(context).textTheme.subtitle1,
textScaleFactor: AppStyle.getScaleFactor(context),
),
SizedBox(height: 8 * AppStyle.getScaleFactor(context),),
SizedBox(
height: 8 * AppStyle.getScaleFactor(context),
),
Center(
child: Wrap(
spacing: 10,
runSpacing: 10,
children: List.generate(
status.length,
(index) {
bool isSelected = _group.status == status[index];
return FilterItem(
isSelected: isSelected,
onSelected: (){
if(isSelected)
_group.status = null;
else
_group.status = status[index];
setState(() {});
},
status: status[index],
);
}
children: List.generate(status.length, (index) {
bool isSelected = _group.status == status[index];
return FilterItem(
isSelected: isSelected,
onSelected: () {
if (isSelected)
_group.status = null;
else
_group.status = status[index];
),
setState(() {});
},
status: status[index],
);
}),
),
),
Text(
@ -171,63 +186,53 @@ class _UpdateVisitsGroupSheetState extends State<UpdateVisitsGroupSheet> {
style: Theme.of(context).textTheme.subtitle1,
textScaleFactor: AppStyle.getScaleFactor(context),
),
SizedBox(height: 8 * AppStyle.getScaleFactor(context),),
SizedBox(
height: 8 * AppStyle.getScaleFactor(context),
),
Center(
child: Wrap(
spacing: 10,
runSpacing: 10,
children: List.generate(
taskStatus.length,
(index) {
bool isSelected = _group.taskStatus == taskStatus[index];
return FilterItem(
isSelected: isSelected,
onSelected: (){
if(isSelected)
_group.taskStatus = null;
else
_group.taskStatus = taskStatus[index];
setState(() {});
},
status: taskStatus[index],
);
}
children: List.generate(taskStatus.length, (index) {
bool isSelected = _group.taskStatus == taskStatus[index];
return FilterItem(
isSelected: isSelected,
onSelected: () {
if (isSelected)
_group.taskStatus = null;
else
_group.taskStatus = taskStatus[index];
),
setState(() {});
},
status: taskStatus[index],
);
}),
),
),
SizedBox(height: 8 * AppStyle.getScaleFactor(context),),
SizedBox(
height: 8 * AppStyle.getScaleFactor(context),
),
Expanded(
child: ListView.builder(
itemCount: widget.visits?.length,
itemBuilder: (context,index){
itemBuilder: (context, index) {
Visit visit = widget.visits![index];
return Container(
padding: EdgeInsets.symmetric(vertical: 8,horizontal: 8),
padding: EdgeInsets.symmetric(vertical: 8, horizontal: 8),
margin: EdgeInsets.symmetric(vertical: 4),
decoration: BoxDecoration(
color: AColors.primaryColor,
borderRadius: BorderRadius.circular(
AppStyle.getBorderRadius(context)
),
boxShadow: [
AppStyle.boxShadow
]
),
decoration: BoxDecoration(color: AColors.primaryColor, borderRadius: BorderRadius.circular(AppStyle.getBorderRadius(context)), boxShadow: [AppStyle.boxShadow]),
child: Row(
children: [
Expanded(
child: Text(
"${_subtitle.sn}: ${visit.deviceSerialNumber?? _subtitle.noSerialNumberFound}" ,
style: Theme.of(context).textTheme.headline6?.copyWith(
color: AColors.white,
fontSize: 16,
fontWeight: FontWeight.bold
),
"${_subtitle.sn}: ${visit.deviceSerialNumber ?? _subtitle.noSerialNumberFound}",
style: Theme.of(context).textTheme.headline6?.copyWith(color: AColors.white, fontSize: 16, fontWeight: FontWeight.bold),
),
),
VisitStatusLabel(visit: visit,)
VisitStatusLabel(
visit: visit,
)
],
),
);
@ -236,15 +241,14 @@ class _UpdateVisitsGroupSheetState extends State<UpdateVisitsGroupSheet> {
),
AButton(
text: _subtitle.update,
onPressed: (){
Navigator.of(context).pop(_group);
onPressed: () {
Navigator.of(context).pop(_group);
},
),
],
),
Align(
alignment: Alignment.topRight,
),
],
),

@ -15,7 +15,6 @@ import '../../../widgets/requests/info_row.dart';
import '../../../widgets/visits/visit_status.dart';
import 'pantry/future_edit_pently.dart';
class VisitDetailsPage extends StatelessWidget {
static final String id = "/visit-details";
final Visit visit;
@ -31,8 +30,8 @@ class VisitDetailsPage extends StatelessWidget {
child: Column(
children: [
Container(
color:AColors.primaryColor,
padding: const EdgeInsets.symmetric(horizontal: 0,vertical: 4),
color: AColors.primaryColor,
padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 4),
child: Row(
children: [
ABackButton(),
@ -40,10 +39,7 @@ class VisitDetailsPage extends StatelessWidget {
child: Center(
child: Text(
_subtitle.visitInformation,
style: Theme.of(context).textTheme.headline6?.copyWith(
color: AColors.white,
fontStyle: FontStyle.italic
),
style: Theme.of(context).textTheme.headline6?.copyWith(color: AColors.white, fontStyle: FontStyle.italic),
),
),
),
@ -53,12 +49,15 @@ class VisitDetailsPage extends StatelessWidget {
buttonSize: 42,
backgroundColor: AColors.green,
onPressed: () async {
Navigator.of(context).push(
MaterialPageRoute(builder: (_)=> FutureEditPentry(visit: visit,))
);
Navigator.of(context).push(MaterialPageRoute(
builder: (_) => FutureEditPentry(
visit: visit,
)));
},
),
SizedBox(width: 16,)
SizedBox(
width: 16,
)
],
),
),
@ -66,13 +65,14 @@ class VisitDetailsPage extends StatelessWidget {
child: ListView(
padding: EdgeInsets.symmetric(horizontal: 16),
children: [
SizedBox(height: 8,),
SizedBox(
height: 8,
),
MaterialButton(
padding: EdgeInsets.zero,
onPressed: (){
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => Scaffold(
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (_) => Scaffold(
body: InteractiveViewer(
child: Center(
child: ImageLoader(
@ -81,27 +81,29 @@ class VisitDetailsPage extends StatelessWidget {
),
),
),
)
)
);
)));
},
child: SizedBox(
height: 140 * AppStyle.getScaleFactor(context),
width: MediaQuery.of(context).size.width,
child: ImageLoader(
url: (visit.images?.isEmpty??false) ? " ":visit.images?.first,
url: (visit.images?.isEmpty ?? false) ? " " : visit.images?.first,
boxFit: BoxFit.cover,
),
),
),
SizedBox(height: 8,),
SizedBox(
height: 60* AppStyle.getScaleFactor(context),
height: 8,
),
SizedBox(
height: 60 * AppStyle.getScaleFactor(context),
child: ImagesList(
images: visit.images!,
),
),
SizedBox(height: 8,),
SizedBox(
height: 8,
),
RequestInfoRow(
title: _subtitle.code,
info: visit.serialNumber,
@ -114,7 +116,6 @@ class VisitDetailsPage extends StatelessWidget {
title: _subtitle.deviceSN,
info: visit.deviceSerialNumber,
),
RequestInfoRow(
title: _subtitle.expectDate,
info: visit.expectDate,
@ -128,17 +129,18 @@ class VisitDetailsPage extends StatelessWidget {
Expanded(
child: Text(
"${_subtitle.status} : ",
style: Theme.of(context).textTheme.subtitle1?.copyWith(
fontWeight: FontWeight.bold
),
style: Theme.of(context).textTheme.subtitle1?.copyWith(fontWeight: FontWeight.bold),
textScaleFactor: AppStyle.getScaleFactor(context),
),
),
VisitStatusLabel(visit: visit,),
VisitStatusLabel(
visit: visit,
),
],
),
Divider(color: Theme.of(context).primaryColor,),
Divider(
color: Theme.of(context).primaryColor,
),
RequestInfoRow(
title: _subtitle.contactStatus,
info: visit.assignTo,

@ -15,10 +15,7 @@ class AppNameBar extends StatelessWidget {
child: Center(
child: Text(
"Test SA",
style: Theme.of(context)
.textTheme
.titleLarge
?.copyWith(color: AColors.white, fontStyle: FontStyle.italic),
style: Theme.of(context).textTheme.titleLarge?.copyWith(color: AColors.white, fontStyle: FontStyle.italic),
),
),
);

@ -86,11 +86,8 @@ class _ATextFormFieldState extends State<ATextFormField> {
maxLines: widget.textInputType == TextInputType.multiline ? null : 1,
obscuringCharacter: "",
controller: widget.controller,
textInputAction: widget.textInputType == TextInputType.multiline
? null
: widget.textInputAction ?? TextInputAction.next,
onEditingComplete:
widget.onAction ?? () => FocusScope.of(context).nextFocus(),
textInputAction: widget.textInputType == TextInputType.multiline ? null : widget.textInputAction ?? TextInputAction.next,
onEditingComplete: widget.onAction ?? () => FocusScope.of(context).nextFocus(),
// style: widget.style,
style: Theme.of(context).textTheme.bodyLarge,
decoration: InputDecoration(
@ -108,11 +105,7 @@ class _ATextFormFieldState extends State<ATextFormField> {
suffixIcon: widget.prefixIconData == null
? null
: Icon(widget.prefixIconData,
size: widget.prefixIconSize == null
? 20 * AppStyle.getScaleFactor(context)
: (widget.prefixIconSize! - 10) *
AppStyle.getScaleFactor(context),
color: const Color(0xff2e303a))),
size: widget.prefixIconSize == null ? 20 * AppStyle.getScaleFactor(context) : (widget.prefixIconSize! - 10) * AppStyle.getScaleFactor(context), color: const Color(0xff2e303a))),
),
);
}

@ -28,7 +28,7 @@ class AButton extends StatelessWidget {
onPressed: onPressed,
child: Text(
text ?? "",
style: textStyle ?? Theme.of(context).textTheme.subtitle2?.copyWith(color: AColors.white, fontSize: 14,fontWeight: FontWeight.w600),
style: textStyle ?? Theme.of(context).textTheme.subtitle2?.copyWith(color: AColors.white, fontSize: 14, fontWeight: FontWeight.w600),
textScaleFactor: AppStyle.getScaleFactor(context),
),
),

@ -9,19 +9,19 @@ class AFlatButton extends StatelessWidget {
final EdgeInsets? padding;
final VoidCallback? onPressed;
const AFlatButton({Key? key, required this.text, this.textColor,this.style ,this.onPressed, this.padding}) : super(key: key);
const AFlatButton({Key? key, required this.text, this.textColor, this.style, this.onPressed, this.padding}) : super(key: key);
@override
Widget build(BuildContext context) {
return TextButton(
style: TextButton.styleFrom(
foregroundColor: this.textColor ?? Colors.black, padding: padding,
),
onPressed: onPressed,
child: Text(
text??"",
style: style ?? Theme.of(context).textTheme.bodyText1,
textScaleFactor: AppStyle.getScaleFactor(context),
)
);
style: TextButton.styleFrom(
foregroundColor: this.textColor ?? Colors.black,
padding: padding,
),
onPressed: onPressed,
child: Text(
text ?? "",
style: style ?? Theme.of(context).textTheme.bodyText1,
textScaleFactor: AppStyle.getScaleFactor(context),
));
}
}

@ -5,7 +5,6 @@ import '../../app_style/colors.dart';
import '../../app_style/sizing.dart';
class AIconButton extends StatelessWidget {
final IconData iconData;
final Color? color;
final Color? backgroundColor;
@ -13,16 +12,7 @@ class AIconButton extends StatelessWidget {
final double? iconSize;
final double buttonSize;
const AIconButton({
Key? key,
required this.iconData,
this.onPressed,
this.color,
this.iconSize,
this.buttonSize = 54,
this.backgroundColor
}) : super(key: key);
const AIconButton({Key? key, required this.iconData, this.onPressed, this.color, this.iconSize, this.buttonSize = 54, this.backgroundColor}) : super(key: key);
@override
Widget build(BuildContext context) {
@ -32,12 +22,8 @@ class AIconButton extends StatelessWidget {
child: ElevatedButton(
style: ElevatedButton.styleFrom(
padding: EdgeInsets.zero,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
(AppStyle.borderRadius - 4) * AppStyle.getScaleFactor(context)
)
),
backgroundColor: backgroundColor ?? AColors.onPrimaryColor,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular((AppStyle.borderRadius - 4) * AppStyle.getScaleFactor(context))),
backgroundColor: backgroundColor ?? AColors.onPrimaryColor,
),
onPressed: onPressed,
child: FaIcon(

@ -2,8 +2,8 @@ import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import '../../app_style/sizing.dart';
class AIconButton2 extends StatelessWidget {
class AIconButton2 extends StatelessWidget {
final IconData iconData;
final Color? color;
final VoidCallback? onPressed;

@ -17,11 +17,7 @@ class AOutLinedButton extends StatelessWidget {
return OutlinedButton(
style: ElevatedButton.styleFrom(
padding: padding ?? EdgeInsets.symmetric(vertical: 12),
textStyle: textStyle ?? Theme
.of(context)
.textTheme
.subtitle2
?.copyWith(fontSize: 18),
textStyle: textStyle ?? Theme.of(context).textTheme.subtitle2?.copyWith(fontSize: 18),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(AppStyle.getBorderRadius(context))),
),
onPressed: onPressed,
@ -30,11 +26,7 @@ class AOutLinedButton extends StatelessWidget {
Expanded(
child: Text(
text ?? "",
style: Theme
.of(context)
.textTheme
.subtitle2
?.copyWith(color: AColors.primaryColor, fontSize: 14, fontWeight: FontWeight.w600),
style: Theme.of(context).textTheme.subtitle2?.copyWith(color: AColors.primaryColor, fontSize: 14, fontWeight: FontWeight.w600),
textAlign: TextAlign.center,
textScaleFactor: AppStyle.getScaleFactor(context),
),

@ -9,26 +9,20 @@ class ASmallButton extends StatelessWidget {
final EdgeInsets? padding;
final VoidCallback? onPressed;
const ASmallButton({Key? key, required this.text, this.style ,this.onPressed,this.padding, this.color}) : super(key: key);
const ASmallButton({Key? key, required this.text, this.style, this.onPressed, this.padding, this.color}) : super(key: key);
@override
Widget build(BuildContext context) {
return ElevatedButton(
style: ElevatedButton.styleFrom(
padding: padding,
primary: color ?? Theme.of(context).primaryColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8)
style: ElevatedButton.styleFrom(
padding: padding,
primary: color ?? Theme.of(context).primaryColor,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
),
),
child: Text(
text??"",
style: style ?? Theme.of(context).textTheme.bodyText1?.copyWith(
color: color == Colors.white
? Theme.of(context).primaryColor : Colors.white
child: Text(
text ?? "",
style: style ?? Theme.of(context).textTheme.bodyText1?.copyWith(color: color == Colors.white ? Theme.of(context).primaryColor : Colors.white),
textScaleFactor: AppStyle.getScaleFactor(context),
),
textScaleFactor: AppStyle.getScaleFactor(context),
),
onPressed: onPressed
);
onPressed: onPressed);
}
}

@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
class CarveInImage extends CustomClipper<Path> {
final double gab;
var radius=10.0;
var radius = 10.0;
CarveInImage(this.gab);
@ -10,14 +10,14 @@ class CarveInImage extends CustomClipper<Path> {
Path getClip(Size size) {
Path path = Path();
path.lineTo(0, size.height);
path.lineTo(size.width/2 - gab / 2, size.height);
path.arcToPoint(Offset(size.width/2 + gab / 2, size.height),
radius: Radius.circular(gab/2));
path.lineTo(size.width / 2 - gab / 2, size.height);
path.arcToPoint(Offset(size.width / 2 + gab / 2, size.height), radius: Radius.circular(gab / 2));
path.lineTo(size.width, size.height);
path.lineTo(size.width, 0);
path.lineTo(0, 0);
return path;
}
@override
bool shouldReclip(CustomClipper<Path> oldClipper) => true;
}
}

@ -17,24 +17,16 @@ class ADatePicker extends StatelessWidget {
foregroundColor: Colors.white,
textStyle: Theme.of(context).textTheme.subtitle2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
12 * AppStyle.getScaleFactor(context)
),
borderRadius: BorderRadius.circular(12 * AppStyle.getScaleFactor(context)),
),
),
child: Text(
date == null ? "Pick Date" :
date.toString().split(" ").first,
date == null ? "Pick Date" : date.toString().split(" ").first,
style: Theme.of(context).textTheme.subtitle2,
textScaleFactor: AppStyle.getScaleFactor(context),
),
onPressed: () async {
DateTime? picked = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: from ?? DateTime.now(),
lastDate: to ?? DateTime.now().add(Duration(days: 365))
);
DateTime? picked = await showDatePicker(context: context, initialDate: DateTime.now(), firstDate: from ?? DateTime.now(), lastDate: to ?? DateTime.now().add(Duration(days: 365)));
onDatePicker!(picked!);
},
);

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save