diff --git a/assets/fonts/poppins/Poppins-Black.ttf b/assets/fonts/poppins/Poppins-Black.ttf new file mode 100644 index 00000000..a9520b78 Binary files /dev/null and b/assets/fonts/poppins/Poppins-Black.ttf differ diff --git a/assets/fonts/poppins/Poppins-Bold.ttf b/assets/fonts/poppins/Poppins-Bold.ttf new file mode 100644 index 00000000..b94d47f3 Binary files /dev/null and b/assets/fonts/poppins/Poppins-Bold.ttf differ diff --git a/assets/fonts/poppins/Poppins-ExtraBold.ttf b/assets/fonts/poppins/Poppins-ExtraBold.ttf new file mode 100644 index 00000000..8f008c36 Binary files /dev/null and b/assets/fonts/poppins/Poppins-ExtraBold.ttf differ diff --git a/assets/fonts/poppins/Poppins-ExtraLight.ttf b/assets/fonts/poppins/Poppins-ExtraLight.ttf new file mode 100644 index 00000000..ee623825 Binary files /dev/null and b/assets/fonts/poppins/Poppins-ExtraLight.ttf differ diff --git a/assets/fonts/poppins/Poppins-Light.ttf b/assets/fonts/poppins/Poppins-Light.ttf new file mode 100644 index 00000000..2ab02219 Binary files /dev/null and b/assets/fonts/poppins/Poppins-Light.ttf differ diff --git a/assets/fonts/poppins/Poppins-Medium.ttf b/assets/fonts/poppins/Poppins-Medium.ttf new file mode 100644 index 00000000..e90e87ed Binary files /dev/null and b/assets/fonts/poppins/Poppins-Medium.ttf differ diff --git a/assets/fonts/poppins/Poppins-Regular.ttf b/assets/fonts/poppins/Poppins-Regular.ttf new file mode 100644 index 00000000..be06e7fd Binary files /dev/null and b/assets/fonts/poppins/Poppins-Regular.ttf differ diff --git a/assets/fonts/poppins/Poppins-SemiBold.ttf b/assets/fonts/poppins/Poppins-SemiBold.ttf new file mode 100644 index 00000000..dabf7c24 Binary files /dev/null and b/assets/fonts/poppins/Poppins-SemiBold.ttf differ diff --git a/assets/fonts/poppins/Poppins-Thin.ttf b/assets/fonts/poppins/Poppins-Thin.ttf new file mode 100644 index 00000000..f5c0fdd5 Binary files /dev/null and b/assets/fonts/poppins/Poppins-Thin.ttf differ diff --git a/assets/subtitles/en_subtitle.json b/assets/subtitles/en_subtitle.json index 2353ebd1..e9eac980 100644 --- a/assets/subtitles/en_subtitle.json +++ b/assets/subtitles/en_subtitle.json @@ -96,7 +96,7 @@ "nameExist": "Name Exist", "newServiceRequest": "New Service Request", "newWord": "New", - "noDateFound": "No Date Found", + "noDateFound": "No Data Found", "noDeviceFound": "No Device Found", "noHospitalFound": "No Client Found", "noModelFound": "No Model Found", diff --git a/lib/extensions/int_extensions.dart b/lib/extensions/int_extensions.dart new file mode 100644 index 00000000..5f1e672e --- /dev/null +++ b/lib/extensions/int_extensions.dart @@ -0,0 +1,13 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:test_sa/views/app_style/colors.dart'; + +extension IntExtensions on int { + Widget get height => SizedBox(height: toDouble()); + + Widget get width => SizedBox(width: toDouble()); + + Widget get divider => Divider(height: toDouble(), thickness: toDouble(), color: AColors.greyEF); + + Widget get makeItSquare => SizedBox(width: toDouble(), height: toDouble()); +} diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart new file mode 100644 index 00000000..f49cc81e --- /dev/null +++ b/lib/extensions/string_extensions.dart @@ -0,0 +1,245 @@ +// +// import 'package:flutter/cupertino.dart'; +// import 'package:intl/intl.dart'; +// +// extension CapExtension on String { +// String get toCamelCase => "${this[0].toUpperCase()}${this.substring(1)}"; +// +// String get inCaps => '${this[0].toUpperCase()}${this.substring(1)}'; +// +// String get allInCaps => this.toUpperCase(); +// +// String get capitalizeFirstofEach => this.trim().length > 0 ? this.trim().toLowerCase().split(" ").map((str) => str.inCaps).join(" ") : ""; +// } +// +// extension EmailValidator on String { +// Widget get toWidget => Text(this); +// +// Widget toText10({Color? color, bool isBold = false, int? maxlines, FontStyle? fontStyle}) => Text( +// this, +// maxLines: maxlines, +// style: TextStyle(fontSize: 10, fontStyle: fontStyle ?? FontStyle.normal, fontWeight: isBold ? FontWeight.bold : FontWeight.w600, color: color ?? MyColors.darkTextColor, letterSpacing: -0.4), +// ); +// +// Widget toText11({Color? color, FontWeight? weight, bool isUnderLine = false, bool isBold = false, int maxLine = 0}) => Text( +// this, +// maxLines: (maxLine > 0) ? maxLine : null, +// style: TextStyle( +// fontSize: 11, +// fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.w600), +// color: color ?? MyColors.darkTextColor, +// letterSpacing: -0.33, +// decoration: isUnderLine ? TextDecoration.underline : null, +// ), +// ); +// +// Widget toText12({Color? color, bool isUnderLine = false, bool isBold = false, bool isCenter = false, int maxLine = 0}) => Text( +// this, +// textAlign: isCenter ? TextAlign.center : null, +// maxLines: (maxLine > 0) ? maxLine : null, +// style: TextStyle( +// fontSize: 12, +// fontWeight: isBold ? FontWeight.bold : FontWeight.w600, +// color: color ?? MyColors.darkTextColor, +// letterSpacing: -0.72, +// decoration: isUnderLine ? TextDecoration.underline : null, +// ), +// ); +// +// Widget toText12Auto({Color? color, bool isUnderLine = false, bool isBold = false, bool isCenter = false, int maxLine = 0}) => AutoSizeText( +// this, +// textAlign: isCenter ? TextAlign.center : null, +// maxLines: (maxLine > 0) ? maxLine : null, +// minFontSize: 8, +// style: TextStyle( +// fontSize: 12, +// fontWeight: isBold ? FontWeight.bold : FontWeight.w600, +// color: color ?? MyColors.darkTextColor, +// letterSpacing: -0.72, +// decoration: isUnderLine ? TextDecoration.underline : null, +// ), +// ); +// +// Widget toTextAuto({ +// Color? color, +// bool isUnderLine = false, +// bool isBold = false, +// bool isCenter = false, +// int maxLine = 0, +// double fontSize = 12, +// double letterSpacing = -0.72, +// double height = 1, +// }) => +// AutoSizeText( +// this, +// textAlign: isCenter ? TextAlign.center : null, +// maxLines: (maxLine > 0) ? maxLine : null, +// minFontSize: 5, +// style: TextStyle( +// fontSize: fontSize, +// fontWeight: isBold ? FontWeight.bold : FontWeight.w600, +// color: color ?? MyColors.darkTextColor, +// letterSpacing: letterSpacing, +// decoration: isUnderLine ? TextDecoration.underline : null, +// ), +// ); +// +// Widget toText13({Color? color, bool isUnderLine = false}) => Text( +// this, +// style: TextStyle(fontSize: 13, fontWeight: FontWeight.w600, color: color ?? MyColors.darkTextColor, letterSpacing: -0.52, decoration: isUnderLine ? TextDecoration.underline : null), +// ); +// +// Widget toText14({Color? color, bool isUnderLine = false, bool isBold = false, FontWeight? weight, int? maxlines, TextAlign? textAlign, bool isCenter = false}) => Text( +// this, +// textAlign: isCenter ? TextAlign.center : (textAlign ?? TextAlign.left), +// maxLines: maxlines, +// style: TextStyle( +// color: color ?? MyColors.darkTextColor, +// fontSize: 14, +// letterSpacing: -0.48, +// fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.w600), +// decoration: isUnderLine ? TextDecoration.underline : null), +// ); +// +// Widget toText16({Color? color, bool isUnderLine = false, bool isBold = false, int? maxlines, double? height}) => Text( +// this, +// maxLines: maxlines, +// style: TextStyle( +// color: color ?? MyColors.darkTextColor, +// fontSize: 16, +// letterSpacing: -0.64, +// height: height, +// fontWeight: isBold ? FontWeight.bold : FontWeight.w600, +// decoration: isUnderLine ? TextDecoration.underline : null, +// ), +// ); +// +// Widget toText17({Color? color, bool isBold = false}) => Text( +// this, +// style: TextStyle(color: color ?? MyColors.darkTextColor, fontSize: 17, letterSpacing: -0.68, fontWeight: isBold ? FontWeight.bold : FontWeight.w600), +// ); +// +// Widget toText18({Color? color, bool isBold = false, bool isCentered = false}) => Text( +// this, +// textAlign: isCentered ? TextAlign.center : null, +// style: TextStyle(fontSize: 18, fontWeight: isBold ? FontWeight.bold : FontWeight.w600, color: color ?? MyColors.darkTextColor, letterSpacing: -1.08), +// ); +// +// Widget toText19({Color? color, bool isBold = false}) => Text( +// this, +// style: TextStyle(fontSize: 19, fontWeight: isBold ? FontWeight.bold : FontWeight.w600, color: color ?? MyColors.darkTextColor, letterSpacing: -1.14), +// ); +// +// Widget toText20({Color? color, bool isBold = false, bool isCentered = false}) => Text( +// this, +// textAlign: isCentered ? TextAlign.center : null, +// style: TextStyle(fontSize: 20, fontWeight: isBold ? FontWeight.bold : FontWeight.w600, color: color ?? MyColors.darkTextColor, letterSpacing: -0.4), +// ); +// +// Widget toText21({Color? color, bool isBold = false, FontWeight? weight, int? maxlines}) => Text( +// this, +// maxLines: maxlines, +// style: TextStyle(color: color ?? MyColors.grey3AColor, fontSize: 21, letterSpacing: -0.84, fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.w600)), +// ); +// +// Widget toText22({Color? color, bool isBold = false, bool isCentered = false}) => Text( +// this, +// textAlign: isCentered ? TextAlign.center : null, +// style: TextStyle(height: 1, color: color ?? MyColors.darkTextColor, fontSize: 22, letterSpacing: -1.44, fontWeight: isBold ? FontWeight.bold : FontWeight.w600), +// ); +// +// Widget toText24({Color? color, bool isBold = false}) => Text( +// this, +// style: TextStyle(height: 23 / 24, color: color ?? MyColors.darkTextColor, fontSize: 24, letterSpacing: -1.44, fontWeight: isBold ? FontWeight.bold : FontWeight.w600), +// ); +// +// Widget toText30({Color? color, bool isBold = false}) => Text( +// this, +// style: TextStyle(height: 20 / 32, color: color ?? MyColors.darkTextColor, fontSize: 32, letterSpacing: -1.2, fontWeight: isBold ? FontWeight.bold : FontWeight.w600), +// ); +// +// Widget toText32({Color? color, bool isBold = false, bool isCentered = false}) => Text( +// this, +// textAlign: isCentered ? TextAlign.center : null, +// style: TextStyle(height: 32 / 32, color: color ?? MyColors.darkTextColor, fontSize: 32, letterSpacing: -1.92, fontWeight: isBold ? FontWeight.bold : FontWeight.w600), +// ); +// +// Widget toText44({Color? color, bool isBold = false}) => Text( +// this, +// style: TextStyle(height: 32 / 32, color: color ?? MyColors.darkTextColor, fontSize: 44, letterSpacing: -2.64, fontWeight: isBold ? FontWeight.bold : FontWeight.w600), +// ); +// +// Widget toSectionHeading({String upperHeading = "", String lowerHeading = ""}) { +// String upper = ""; +// String lower = ""; +// String heading = this; +// if (heading.isNotEmpty) { +// List data = heading.split(" "); +// +// if (data.length > 1) { +// upper = data[0]; +// data.removeAt(0); +// lower = data.join(" "); +// } else { +// lower = data[0]; +// } +// } +// if (upperHeading.isNotEmpty) { +// upper = upperHeading; +// } +// if (lowerHeading.isNotEmpty) { +// lower = lowerHeading; +// } +// +// return Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// mainAxisSize: MainAxisSize.min, +// children: [ +// if (upper.isNotEmpty) upper.toText12(), +// lower.toText24(isBold: true), +// ], +// ); +// } +// +// bool isValidEmail() { +// return RegExp(r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$').hasMatch(this); +// } +// +// String toFormattedDate() { +// String date = this.split("T")[0]; +// String time = this.split("T")[1]; +// var dates = date.split("-"); +// return "${dates[2]} ${getMonth(int.parse(dates[1]))} ${dates[0]} ${DateFormat('hh:mm a').format(DateFormat('hh:mm:ss').parse(time))}"; +// } +// +// String getMonth(int month) { +// switch (month) { +// case 1: +// return "January"; +// case 2: +// return "February"; +// case 3: +// return "March"; +// case 4: +// return "April"; +// case 5: +// return "May"; +// case 6: +// return "June"; +// case 7: +// return "July"; +// case 8: +// return "August"; +// case 9: +// return "September"; +// case 10: +// return "October"; +// case 11: +// return "November"; +// case 12: +// return "December"; +// default: +// return ""; +// } +// } +// } diff --git a/lib/extensions/widget_extensions.dart b/lib/extensions/widget_extensions.dart new file mode 100644 index 00000000..326dbb6d --- /dev/null +++ b/lib/extensions/widget_extensions.dart @@ -0,0 +1,20 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; +import 'package:test_sa/views/app_style/colors.dart'; + +extension WidgetExtensions on Widget { + Widget onPress(VoidCallback onTap) => InkWell(onTap: onTap, child: this); + + Widget get expanded => Expanded(child: this); + + Widget get center => Center(child: this); + + Widget circle(double _value) => ClipRRect(borderRadius: BorderRadius.circular(_value), child: this); + + Widget paddingAll(double _value) => Padding(padding: EdgeInsets.all(_value), child: this); + + Widget paddingOnly({double left = 0.0, double right = 0.0, double top = 0.0, double bottom = 0.0}) => + Padding(padding: EdgeInsets.only(left: left, right: right, top: top, bottom: bottom), child: this); + + Widget toExpanded({int flex = 1}) => Expanded(flex: flex, child: this); +} diff --git a/lib/main.dart b/lib/main.dart index 2cf47e62..e2deac02 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -92,7 +92,7 @@ class MyApp extends StatelessWidget { title: 'ATOMS', debugShowCheckedModeBanner: false, theme: ThemeData( - fontFamily: "Swiss", + fontFamily: "Poppins", //canvasColor: AColors.primaryColor, scaffoldBackgroundColor: AColors.scaffoldBackgroundColor, primaryColor: AColors.primaryColor, diff --git a/lib/views/app_style/colors.dart b/lib/views/app_style/colors.dart index 6d87c5f3..921cb636 100644 --- a/lib/views/app_style/colors.dart +++ b/lib/views/app_style/colors.dart @@ -4,6 +4,7 @@ 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; @@ -12,9 +13,11 @@ class AColors { static const Color deepRed = Color(0xFFD32F2F); static const Color scaffoldBackgroundColor = Color(0xffffffff); static const Color secondaryColor = Color(0xff111427); - static const Color primaryColor = Color(0xff3B7097); + 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){ diff --git a/lib/views/app_style/sizing.dart b/lib/views/app_style/sizing.dart index c7b94365..bb66b317 100644 --- a/lib/views/app_style/sizing.dart +++ b/lib/views/app_style/sizing.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; class AppStyle { AppStyle._(); - static const double borderRadius = 12; + static const double borderRadius = 10; static const BoxShadow boxShadow = BoxShadow( color: Colors.black26, diff --git a/lib/views/pages/device_transfer/request_device_transfer.dart b/lib/views/pages/device_transfer/request_device_transfer.dart index f8ad6948..66162778 100644 --- a/lib/views/pages/device_transfer/request_device_transfer.dart +++ b/lib/views/pages/device_transfer/request_device_transfer.dart @@ -5,6 +5,7 @@ import 'package:test_sa/controllers/http_status_manger/http_status_manger.dart'; import 'package:test_sa/controllers/providers/api/device_transfer_provider.dart'; import 'package:test_sa/controllers/providers/api/user_provider.dart'; import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/models/device/device_transfer.dart'; import 'package:test_sa/models/device/device_transfer_info.dart'; import 'package:test_sa/models/subtitle.dart'; @@ -18,6 +19,7 @@ import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; import 'package:test_sa/views/widgets/titles/app_sub_title.dart'; import '../../../../controllers/localization/localization.dart'; + class RequestDeviceTransfer extends StatefulWidget { static const String id = "/request-device-transfer"; const RequestDeviceTransfer({Key key}) : super(key: key); @@ -39,20 +41,20 @@ class _RequestDeviceTransferState extends State { final GlobalKey _scaffoldKey = GlobalKey(); @override - void setState(VoidCallback fn){ - if(mounted) super.setState(() {}); + void setState(VoidCallback fn) { + if (mounted) super.setState(() {}); } _onSubmit() async { _validate = true; - if(!_formKey.currentState.validate()){ + if (!_formKey.currentState.validate()) { setState(() {}); return false; } _formKey.currentState.save(); - if(!_formModel.validate()) { - setState(() { }); + if (!_formModel.validate()) { + setState(() {}); return false; } @@ -64,23 +66,18 @@ class _RequestDeviceTransferState extends State { host: _settingProvider.host, model: _formModel, ); - _isLoading =false; + _isLoading = false; setState(() {}); - if(status >= 200 && status < 300){ + if (status >= 200 && status < 300) { Fluttertoast.showToast( 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), + )); } } @@ -95,7 +92,7 @@ class _RequestDeviceTransferState extends State { _subtitle = AppLocalization.of(context).subtitle; _userProvider = Provider.of(context); _settingProvider = Provider.of(context); - _deviceTransferProvider = Provider.of(context,listen: false); + _deviceTransferProvider = Provider.of(context, listen: false); return Scaffold( key: _scaffoldKey, body: Form( @@ -116,11 +113,7 @@ class _RequestDeviceTransferState extends State { 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), ), ), ), @@ -138,14 +131,17 @@ class _RequestDeviceTransferState extends State { // _formModel.title = value; // }, // ), - const SizedBox(height: 8,), + 12.height, const ASubTitle("Device"), - if(_validate && _formModel.device == null) - ASubTitle(_subtitle.requiredWord,color: Colors.red,), - const SizedBox(height: 4,), + if (_validate && _formModel.device == null) + ASubTitle( + _subtitle.requiredWord, + color: Colors.red, + ), + 6.height, DeviceButton( device: _formModel.device, - onDevicePick: (device){ + onDevicePick: (device) { _formModel.device = device; setState(() {}); }, @@ -162,39 +158,44 @@ class _RequestDeviceTransferState extends State { // setState(() {}); // }, // ), - const SizedBox(height: 8,), + 12.height, const ASubTitle("Destination Client"), - if(_validate && _formModel.receiver.client == null) - ASubTitle(_subtitle.requiredWord,color: Colors.red,), - const SizedBox(height: 4,), + if (_validate && _formModel.receiver.client == null) + ASubTitle( + _subtitle.requiredWord, + color: Colors.red, + ), + 6.height, HospitalButton( hospital: _formModel.receiver.client, - onHospitalPick: (hospital){ + onHospitalPick: (hospital) { _formModel.receiver.client = hospital; setState(() {}); }, ), - const SizedBox(height: 8,), + 12.height, const ASubTitle("Destination Department"), - if(_validate && _formModel.receiver.department == null) - ASubTitle(_subtitle.requiredWord,color: Colors.red,), - const SizedBox(height: 4,), + if (_validate && _formModel.receiver.department == null) + ASubTitle( + _subtitle.requiredWord, + color: Colors.red, + ), + 6.height, DepartmentButton( department: _formModel.receiver.department, - onDepartmentPick: (department){ + onDepartmentPick: (department) { _formModel.receiver.department = department; setState(() {}); }, ), - - Padding( - padding: const EdgeInsets.all(16.0), - child: AButton( - text: _subtitle.submit, - onPressed: _onSubmit, - ), + 12.height, + AButton( + text: _subtitle.submit, + onPressed: _onSubmit, ), - const SizedBox(height: 100,) + const SizedBox( + height: 100, + ) ], ), ), @@ -204,4 +205,3 @@ class _RequestDeviceTransferState extends State { ); } } - diff --git a/lib/views/pages/login.dart b/lib/views/pages/login.dart index 9d06692b..e351b9f9 100644 --- a/lib/views/pages/login.dart +++ b/lib/views/pages/login.dart @@ -1,7 +1,8 @@ -import 'package:test_sa/controllers/api_routes/urls.dart'; +import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:provider/provider.dart'; import 'package:test_sa/controllers/http_status_manger/http_status_manger.dart'; import 'package:test_sa/controllers/localization/localization.dart'; -import 'package:test_sa/controllers/notification/notification_manger.dart'; import 'package:test_sa/controllers/providers/api/user_provider.dart'; import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; import 'package:test_sa/controllers/validator/validator.dart'; @@ -12,15 +13,13 @@ import 'package:test_sa/views/pages/register.dart'; import 'package:test_sa/views/pages/user/land_page.dart'; import 'package:test_sa/views/widgets/app_text_form_field.dart'; import 'package:test_sa/views/widgets/buttons/app_button.dart'; -import 'package:test_sa/views/widgets/buttons/app_flat_button.dart'; import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; -import 'package:flutter/material.dart'; -import 'package:fluttertoast/fluttertoast.dart'; -import 'package:provider/provider.dart'; import '../widgets/buttons/app_outlined_button.dart'; + class Login extends StatefulWidget { static final String id = "/login"; + @override _LoginState createState() => _LoginState(); } @@ -46,7 +45,7 @@ class _LoginState extends State { Subtitle _subtitle = AppLocalization.of(context).subtitle; return Scaffold( key: _scaffoldKey, - body:SafeArea( + body: SafeArea( child: LoadingManager( isLoading: _userProvider.isLoading || !_settingProvider.isLoaded, isFailedLoading: false, @@ -59,97 +58,92 @@ class _LoginState extends State { child: Column( children: [ //AppNameBar(), - SizedBox(height: MediaQuery.of(context).size.height / 5,), + SizedBox( + height: MediaQuery.of(context).size.height / 7, + ), Hero( tag: "logo", child: Image( - height: _height/6, + height: _height / 6, fit: BoxFit.contain, image: AssetImage("assets/images/logo.png"), ), ), 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(height: 24 * AppStyle.getScaleFactor(context),), + SizedBox( + height: 24 * AppStyle.getScaleFactor(context), + ), ATextFormField( initialValue: _user?.userName, hintText: _subtitle.name, - textAlign: TextAlign.center, - style: Theme.of(context).textTheme.headline6, + textAlign: TextAlign.left, + style: Theme.of(context).textTheme.bodyText1, 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){ + onSaved: (value) { _user.userName = value; }, ), - SizedBox(height: 24 * AppStyle.getScaleFactor(context),), + SizedBox(height: 12), ATextFormField( initialValue: _user?.password, hintText: _subtitle.password, obscureText: _obscurePassword, - style: Theme.of(context).textTheme.headline6, + style: Theme.of(context).textTheme.bodyText1, prefixIconData: Icons.vpn_key_sharp, - textAlign: TextAlign.center, - validator: (value) => Validator.isValidPassword(value) - ? null : _subtitle.passwordValidateMessage, - showPassword: (){ + textAlign: TextAlign.left, + validator: (value) => Validator.isValidPassword(value) ? null : _subtitle.passwordValidateMessage, + showPassword: () { _obscurePassword = !_obscurePassword; setState(() {}); }, - onSaved: (value){ + onSaved: (value) { _user.password = value; }, ), - SizedBox(height: 32 * AppStyle.getScaleFactor(context),), + SizedBox( + height: 32 * AppStyle.getScaleFactor(context), + ), AButton( text: _subtitle.signIn, onPressed: () async { - if(!_formKey.currentState.validate()) - return; + if (!_formKey.currentState.validate()) return; _formKey.currentState.save(); int status = await _userProvider.login( user: _user, host: _settingProvider.host, ); - if(status >= 200 && status < 300){ + if (status >= 200 && status < 300) { _settingProvider.setUser(_userProvider.user); - if(_userProvider.user.isActive) + if (_userProvider.user.isActive) 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 - ), - ) - ); + } else { + String errorMessage = status == 400 ? _subtitle.wrongEmailOrPassword : HttpStatusManger.getStatusMessage(status: status, subtitle: _subtitle); + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: Text(errorMessage), + )); } }, ), - SizedBox(height: 140 * AppStyle.getScaleFactor(context),), + SizedBox( + height: 140 * AppStyle.getScaleFactor(context), + ), AOutLinedButton( text: _subtitle.signUp, //color: AColors.cyan, - onPressed: (){ + onPressed: () { Navigator.of(context).pushNamed(Register.id); }, ), - - SizedBox(height: 32,), + SizedBox( + height: 32, + ), ], ), ), diff --git a/lib/views/pages/register.dart b/lib/views/pages/register.dart index 04312e9a..af5f83cd 100644 --- a/lib/views/pages/register.dart +++ b/lib/views/pages/register.dart @@ -1,3 +1,7 @@ +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 'package:test_sa/controllers/http_status_manger/http_status_manger.dart'; import 'package:test_sa/controllers/localization/localization.dart'; import 'package:test_sa/controllers/providers/api/user_provider.dart'; @@ -5,21 +9,16 @@ import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; import 'package:test_sa/controllers/validator/validator.dart'; import 'package:test_sa/models/subtitle.dart'; import 'package:test_sa/models/user.dart'; -import 'package:test_sa/views/app_style/colors.dart'; -import 'package:test_sa/views/app_style/sizing.dart'; import 'package:test_sa/views/widgets/app_text_form_field.dart'; import 'package:test_sa/views/widgets/buttons/app_back_button.dart'; import 'package:test_sa/views/widgets/buttons/app_button.dart'; import 'package:test_sa/views/widgets/departments/department_button.dart'; import 'package:test_sa/views/widgets/hospitals/hospital_button.dart'; import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; -import 'package:flutter/material.dart'; -import 'package:fluttertoast/fluttertoast.dart'; -import 'package:font_awesome_flutter/font_awesome_flutter.dart'; -import 'package:provider/provider.dart'; class Register extends StatefulWidget { static final String id = "/register"; + @override _RegisterState createState() => _RegisterState(); } @@ -33,6 +32,7 @@ class _RegisterState extends State { bool _obscurePassword = true; final GlobalKey _formKey = GlobalKey(); final GlobalKey _scaffoldKey = GlobalKey(); + @override Widget build(BuildContext context) { _userProvider = Provider.of(context); @@ -42,7 +42,7 @@ class _RegisterState extends State { Subtitle _subtitle = AppLocalization.of(context).subtitle; return Scaffold( key: _scaffoldKey, - body:LoadingManager( + body: LoadingManager( isLoading: _userProvider.isLoading, isFailedLoading: false, stateCode: 200, @@ -53,6 +53,7 @@ class _RegisterState extends State { Form( key: _formKey, child: ListView( + padding: const EdgeInsets.all(20), children: [ //AppNameBar(), //SizedBox(height: 16,), @@ -61,190 +62,143 @@ class _RegisterState extends State { child: Padding( padding: const EdgeInsets.all(16), child: Image( - height: _height/6, + height: _height / 6, image: AssetImage("assets/images/logo.png"), ), ), ), - Container( - padding: EdgeInsets.symmetric(horizontal: 16,vertical: 16), - margin: EdgeInsets.symmetric(horizontal: 16), - decoration: BoxDecoration( - color: AColors.cyan, - borderRadius: BorderRadius.circular(AppStyle.getBorderRadius(context)), - boxShadow: [ - BoxShadow( - color: AColors.grey, - offset: Offset(0,-1), - ) - ] - ), - child: Column( - children: [ - ATextFormField( - initialValue: _user.userName, - hintText: _subtitle.name, - prefixIconData: Icons.account_circle, - style: Theme.of(context).textTheme.headline6, - validator: (value) => Validator.hasValue(value) - ? null : _subtitle.nameValidateMessage, - onSaved: (value){ - _user.userName = value; - }, - ), - SizedBox(height: 8,), - ATextFormField( - initialValue: _user.email, - hintText: _subtitle.email, - prefixIconData: Icons.email, - textInputType: TextInputType.emailAddress, - style: Theme.of(context).textTheme.headline6, - validator: (value) => Validator.isEmail(value) - ? null : _subtitle.emailValidateMessage, - onSaved: (value){ - _user.email = value; - }, - ), - SizedBox(height: 8,), - ATextFormField( - initialValue: _user.password, - hintText: _subtitle.password, - prefixIconData: Icons.vpn_key_sharp, - style: Theme.of(context).textTheme.headline6, - obscureText: _obscurePassword, - validator: (value) => Validator.isValidPassword(value) - ? null : _subtitle.passwordValidateMessage, - showPassword: (){ - _obscurePassword = !_obscurePassword; - setState(() {}); - }, - onSaved: (value){ - _user.password = value; - }, - onChange: (value){ - _user.password = value; - }, - ), - SizedBox(height: 8,), - ATextFormField( - initialValue: _user.password, - prefixIconData: Icons.vpn_key_sharp, - hintText: _subtitle.confirmPassword, - style: Theme.of(context).textTheme.headline6, - obscureText: _obscurePassword, - validator: (value) => - _user.password == value - ? null : _subtitle.confirmPasswordValidateMessage, - showPassword: (){ - _obscurePassword = !_obscurePassword; - setState(() {}); - }, - ), - SizedBox(height: 8,), - HospitalButton( - hospital: _user.hospital, - onHospitalPick: (hospital){ - _user.hospital = hospital; - setState(() {}); - }, - ), - SizedBox(height: 8,), - DepartmentButton( - department: _user.department, - onDepartmentPick: (department){ - _user.department = department; - setState(() {}); - }, - ), - SizedBox(height: 8,), - ATextFormField( - initialValue: _user.phoneNumber, - hintText: _subtitle.phoneNumber, - style: Theme.of(context).textTheme.headline6, - prefixIconData: Icons.phone_android, - validator: (value) => - Validator.isPhoneNumber(value) - ? null : _subtitle.phoneNumberValidateMessage, - textInputType: TextInputType.phone, - onSaved: (value){ - _user.phoneNumber = value; - }, - ), - SizedBox(height: 8,), - ATextFormField( - initialValue: _user.whatsApp, - hintText: _subtitle.whatsApp, - style: Theme.of(context).textTheme.headline6, - prefixIconData: FontAwesomeIcons.whatsapp, - prefixIconSize: 36, - validator: (value) => - Validator.isPhoneNumber(value) ? null : _subtitle.phoneNumberValidateMessage, - textInputType: TextInputType.phone, - onSaved: (value){ - _user.whatsApp = value; - }, - ), - ], - ), + ATextFormField( + initialValue: _user.userName, + hintText: _subtitle.name, + prefixIconData: Icons.account_circle, + style: Theme.of(context).textTheme.headline6, + validator: (value) => Validator.hasValue(value) ? null : _subtitle.nameValidateMessage, + onSaved: (value) { + _user.userName = value; + }, + ), + const SizedBox(height: 12), + ATextFormField( + initialValue: _user.email, + hintText: _subtitle.email, + prefixIconData: Icons.email, + textInputType: TextInputType.emailAddress, + style: Theme.of(context).textTheme.headline6, + validator: (value) => Validator.isEmail(value) ? null : _subtitle.emailValidateMessage, + onSaved: (value) { + _user.email = value; + }, + ), + const SizedBox(height: 12), + ATextFormField( + initialValue: _user.password, + hintText: _subtitle.password, + prefixIconData: Icons.vpn_key_sharp, + style: Theme.of(context).textTheme.headline6, + obscureText: _obscurePassword, + validator: (value) => Validator.isValidPassword(value) ? null : _subtitle.passwordValidateMessage, + showPassword: () { + _obscurePassword = !_obscurePassword; + setState(() {}); + }, + onSaved: (value) { + _user.password = value; + }, + onChange: (value) { + _user.password = value; + }, + ), + const SizedBox(height: 12), + ATextFormField( + initialValue: _user.password, + prefixIconData: Icons.vpn_key_sharp, + hintText: _subtitle.confirmPassword, + style: Theme.of(context).textTheme.headline6, + obscureText: _obscurePassword, + validator: (value) => _user.password == value ? null : _subtitle.confirmPasswordValidateMessage, + showPassword: () { + _obscurePassword = !_obscurePassword; + setState(() {}); + }, + ), + const SizedBox(height: 12), + HospitalButton( + hospital: _user.hospital, + onHospitalPick: (hospital) { + _user.hospital = hospital; + setState(() {}); + }, ), - SizedBox(height: 16,), - Center( - child: SizedBox( - height: _width / 8, - width: _width/1.2, - child: AButton( - text: _subtitle.signUp, - onPressed: () async { - if(!_formKey.currentState.validate()) - 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 >= 200 && status < 300){ - Fluttertoast.showToast(msg: _subtitle.activationAlert); - Navigator.of(context).pop(); - }else{ - String errorMessage = status == 402 - ? _subtitle.nameExist - : status == 401 + const SizedBox(height: 12), + DepartmentButton( + department: _user.department, + onDepartmentPick: (department) { + _user.department = department; + setState(() {}); + }, + ), + const SizedBox(height: 12), + ATextFormField( + initialValue: _user.phoneNumber, + hintText: _subtitle.phoneNumber, + style: Theme.of(context).textTheme.headline6, + prefixIconData: Icons.phone_android, + validator: (value) => Validator.isPhoneNumber(value) ? null : _subtitle.phoneNumberValidateMessage, + textInputType: TextInputType.phone, + onSaved: (value) { + _user.phoneNumber = value; + }, + ), + SizedBox(height: 8), + ATextFormField( + initialValue: _user.whatsApp, + hintText: _subtitle.whatsApp, + style: Theme.of(context).textTheme.headline6, + prefixIconData: FontAwesomeIcons.whatsapp, + prefixIconSize: 36, + validator: (value) => Validator.isPhoneNumber(value) ? null : _subtitle.phoneNumberValidateMessage, + textInputType: TextInputType.phone, + onSaved: (value) { + _user.whatsApp = value; + }, + ), + const SizedBox(height: 12), + AButton( + text: _subtitle.signUp, + onPressed: () async { + if (!_formKey.currentState.validate()) 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 >= 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 - ), - ) - ); - } - }, - ), - ), + : HttpStatusManger.getStatusMessage(status: status, subtitle: _subtitle); + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: Text(errorMessage), + )); + } + }, ), - SizedBox(height: 32,), ], ), ), diff --git a/lib/views/pages/user/gas_refill/request_gas_refill.dart b/lib/views/pages/user/gas_refill/request_gas_refill.dart index 3b0cb343..8e1f05ca 100644 --- a/lib/views/pages/user/gas_refill/request_gas_refill.dart +++ b/lib/views/pages/user/gas_refill/request_gas_refill.dart @@ -209,13 +209,10 @@ class _RequestGasRefillState extends State { _currentDetails.requestedQuantity = int.tryParse(value); }, ), - const SizedBox(height: 8,), - Padding( - padding: const EdgeInsets.all(16.0), - child: AButton( - text: _subtitle.add, - onPressed: _addNewModel, - ), + const SizedBox(height: 16), + AButton( + text: _subtitle.add, + onPressed: _addNewModel, ), if(_formModel.details.isNotEmpty) const ASubTitle("Gas Requests"), @@ -235,12 +232,10 @@ class _RequestGasRefillState extends State { ); } ), - Padding( - padding: const EdgeInsets.all(16.0), - child: AButton( - text: _subtitle.submit, - onPressed: _onSubmit, - ), + const SizedBox(height: 16), + AButton( + text: _subtitle.submit, + onPressed: _onSubmit, ), const SizedBox(height: 100,) ], diff --git a/lib/views/pages/user/gas_refill/track_gas_refill.dart b/lib/views/pages/user/gas_refill/track_gas_refill.dart index 2b502f6d..ce9796fc 100644 --- a/lib/views/pages/user/gas_refill/track_gas_refill.dart +++ b/lib/views/pages/user/gas_refill/track_gas_refill.dart @@ -53,7 +53,7 @@ class _TrackGasRefillPageState extends State Column( children: [ Container( - color:AColors.primaryColor, + color:AColors.white, padding: const EdgeInsets.symmetric(horizontal: 0,vertical: 4), child: Column( children: [ @@ -65,7 +65,7 @@ class _TrackGasRefillPageState extends State child: Text( _subtitle.serviceRequests, style: Theme.of(context).textTheme.headline6.copyWith( - color: AColors.white, + color: AColors.grey3A, fontStyle: FontStyle.italic ), ), diff --git a/lib/views/pages/user/land_page.dart b/lib/views/pages/user/land_page.dart index d29f3600..c5ae3187 100644 --- a/lib/views/pages/user/land_page.dart +++ b/lib/views/pages/user/land_page.dart @@ -1,5 +1,12 @@ import 'dart:io'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:package_info/package_info.dart'; +import 'package:provider/provider.dart'; +import 'package:share/share.dart'; import 'package:test_sa/controllers/localization/localization.dart'; import 'package:test_sa/controllers/notification/firebase_notification_manger.dart'; import 'package:test_sa/controllers/providers/api/departments_provider.dart'; @@ -9,6 +16,8 @@ import 'package:test_sa/controllers/providers/api/regular_visits_provider.dart'; import 'package:test_sa/controllers/providers/api/service_requests_provider.dart'; import 'package:test_sa/controllers/providers/api/user_provider.dart'; import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/enums/user_types.dart'; import 'package:test_sa/models/subtitle.dart'; import 'package:test_sa/views/app_style/colors.dart'; @@ -19,25 +28,17 @@ import 'package:test_sa/views/pages/user/gas_refill/request_gas_refill.dart'; import 'package:test_sa/views/pages/user/gas_refill/track_gas_refill.dart'; import 'package:test_sa/views/pages/user/notifications/notifications_page.dart'; import 'package:test_sa/views/pages/user/requests/create_request.dart'; -import 'package:test_sa/views/pages/user/visits/preventive_maintenance_visits_page.dart'; import 'package:test_sa/views/pages/user/visits/regular_visits_page.dart'; import 'package:test_sa/views/widgets/buttons/app_back_button.dart'; import 'package:test_sa/views/widgets/buttons/app_icon_button.dart'; import 'package:test_sa/views/widgets/dialogs/dialog.dart'; import 'package:test_sa/views/widgets/drawer/drawer_item.dart'; import 'package:test_sa/views/widgets/loaders/image_loader.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:font_awesome_flutter/font_awesome_flutter.dart'; -import 'package:package_info/package_info.dart'; -import 'package:provider/provider.dart'; -import 'package:share/share.dart'; import 'package:url_launcher/url_launcher.dart'; import '../../widgets/land_page/land_page_item.dart'; -import 'profile_page.dart'; import 'requests/requests_page.dart'; + class LandPage extends StatefulWidget { static const String id = "/land-page"; @@ -64,10 +65,9 @@ class _LandPageState extends State { @override void initState() { WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { - try{ + try { FirebaseNotificationManger.initialized(context); - }catch(error){ - } + } catch (error) {} }); super.initState(); } @@ -85,12 +85,9 @@ class _LandPageState extends State { _preventiveMaintenanceVisitsProvider = Provider.of(context); _regularVisitsProvider = Provider.of(context); Subtitle _subtitle = AppLocalization.of(context).subtitle; - if(firstTime){ - if(path != null){ - Navigator.of(context).pushNamed( - "/"+path.split("/").first, - arguments: path.split("/").last - ); + if (firstTime) { + if (path != null) { + Navigator.of(context).pushNamed("/" + path.split("/").first, arguments: path.split("/").last); } firstTime = false; } @@ -101,26 +98,25 @@ class _LandPageState extends State { bool result = await showDialog( context: context, builder: (_) => AAlertDialog( - title: _subtitle.exit, - content: _subtitle.exitAlert, - ) - ); - if(result == true){ - if(Platform.isAndroid){ + title: _subtitle.exit, + content: _subtitle.exitAlert, + )); + if (result == true) { + if (Platform.isAndroid) { SystemChannels.platform.invokeMethod('SystemNavigator.pop'); } else { exit(0); } - } return false; }, child: Scaffold( - key: _scaffoldKey, + key: _scaffoldKey, //backgroundColor: Color(0xffF8F8F8), body: SafeArea( child: Stack( children: [ ListView( + padding: const EdgeInsets.all(16.0), children: [ //AppNameBar(), // SizedBox( @@ -141,102 +137,100 @@ class _LandPageState extends State { // ) // ), // ), - SizedBox(height: 48 * AppStyle.getScaleFactor(context),), - Hero( - tag: "logo", - child: Image( - height: _height/6, - image: const AssetImage("assets/images/logo.png"), - ), + SizedBox( + height: 48 * AppStyle.getScaleFactor(context), ), - Padding( - padding: const EdgeInsets.all(16.0), - child: GridView.count( - shrinkWrap: true, - physics: const ClampingScrollPhysics(), - crossAxisCount: 2, - crossAxisSpacing: 5, - mainAxisSpacing: 5, - childAspectRatio: 1.15, - children: [ - if (_userProvider.user.type == UsersTypes.normal_user) + // Hero( + // tag: "logo", + // child: Image( + // height: _height / 6, + // image: const AssetImage("assets/images/logo.png"), + // ), + // ), + GridView.count( + shrinkWrap: true, + physics: const ClampingScrollPhysics(), + crossAxisCount: 2, + crossAxisSpacing: 12, + mainAxisSpacing: 12, + childAspectRatio: 1, + children: [ + if (_userProvider.user.type == UsersTypes.normal_user) LandPageItem( text: _subtitle.newServiceRequest, icon: FontAwesomeIcons.tools, - onPressed: (){ + onPressed: () { Navigator.of(context).pushNamed(CreateRequestPage.id); }, ), - LandPageItem( - text: _subtitle.trackServiceRequest, - icon: FontAwesomeIcons.tasks, - onPressed: (){ - Navigator.of(context).pushNamed(ServiceRequestsPage.id); - }, - ), - //if (_userProvider.user.type == UsersTypes.engineer) - LandPageItem( - text: _subtitle.preventiveMaintenance, - icon: FontAwesomeIcons.personWalking, - onPressed: (){ - Navigator.of(context).pushNamed(RegularVisitsPage.id); - }, - ), - //if (_userProvider.user.type == UsersTypes.engineer) - // LandPageItem( - // text: _subtitle.preventiveMaintenance, - // icon: FontAwesomeIcons.toolbox, - // onPressed: (){ - // Navigator.of(context).pushNamed(PreventiveMaintenanceVisitsPage.id); - // }, - // ), - if (_userProvider.user.type != UsersTypes.engineer) + LandPageItem( + text: _subtitle.trackServiceRequest, + icon: FontAwesomeIcons.tasks, + onPressed: () { + Navigator.of(context).pushNamed(ServiceRequestsPage.id); + }, + ), + //if (_userProvider.user.type == UsersTypes.engineer) + LandPageItem( + text: _subtitle.preventiveMaintenance, + icon: FontAwesomeIcons.personWalking, + onPressed: () { + Navigator.of(context).pushNamed(RegularVisitsPage.id); + }, + ), + //if (_userProvider.user.type == UsersTypes.engineer) + // LandPageItem( + // text: _subtitle.preventiveMaintenance, + // icon: FontAwesomeIcons.toolbox, + // onPressed: (){ + // Navigator.of(context).pushNamed(PreventiveMaintenanceVisitsPage.id); + // }, + // ), + if (_userProvider.user.type != UsersTypes.engineer) LandPageItem( text: "Request Gas Refill", icon: FontAwesomeIcons.truckFast, - onPressed: (){ + onPressed: () { Navigator.of(context).pushNamed(RequestGasRefill.id); }, ), - LandPageItem( - text: "Track Gas Refill", - icon: Icons.content_paste_search, - onPressed: (){ - Navigator.of(context).pushNamed(TrackGasRefillPage.id); - }, - ), - LandPageItem( - text: "transfer Device", - icon: FontAwesomeIcons.rightLeft, - onPressed: (){ - Navigator.of(context).pushNamed(RequestDeviceTransfer.id); - }, - ), - LandPageItem( - text: "Track Device Transfer", - icon: FontAwesomeIcons.peopleCarryBox, - onPressed: (){ - Navigator.of(context).pushNamed(TrackDeviceTransferPage.id); - }, - ), - ], - ), + LandPageItem( + text: "Track Gas Refill", + icon: Icons.content_paste_search, + onPressed: () { + Navigator.of(context).pushNamed(TrackGasRefillPage.id); + }, + ), + LandPageItem( + text: "transfer Device", + icon: FontAwesomeIcons.rightLeft, + onPressed: () { + Navigator.of(context).pushNamed(RequestDeviceTransfer.id); + }, + ), + LandPageItem( + text: "Track Device Transfer", + icon: FontAwesomeIcons.peopleCarryBox, + onPressed: () { + Navigator.of(context).pushNamed(TrackDeviceTransferPage.id); + }, + ), + ], ), - SizedBox(height: 100,) ], ), Align( alignment: Alignment.topLeft, child: ABackButton( + icon: Icons.power_settings_new_rounded, onPressed: () async { bool result = await showDialog( context: context, builder: (_) => AAlertDialog( - title: _subtitle.signOut, - content: _subtitle.signOutAlert, - ) - ); - if(result){ + title: _subtitle.signOut, + content: _subtitle.signOutAlert, + )); + if (result) { _devicesProvider.reset(); _departmentsProvider.reset(); _serviceRequestsProvider.reset(); @@ -251,213 +245,152 @@ class _LandPageState extends State { 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, buttonSize: 42, backgroundColor: AColors.white, - onPressed: (){ + onPressed: () { _scaffoldKey.currentState.openEndDrawer(); }, ), ), ), - Align( - alignment: Alignment.bottomCenter, - child: Container( - padding: EdgeInsets.all(16), - color: AColors.primaryColor, - child: Row( - children: [ - AIconButton( - iconData: Icons.mail, - onPressed: (){ - launch("mailto:customerservice@Test SA.com"); - - }, - ), - Expanded( - child: MaterialButton( - splashColor: AColors.secondaryColor.withOpacity(.5), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - padding: EdgeInsets.all(12), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular( - 8 * AppStyle.getScaleFactor(context) - ), - color: AColors.onPrimaryColor - ), - child: Icon( - Icons.phone_in_talk, - color: AColors.primaryColor , - size: 32, - ), - ), - SizedBox( - width: 12 * AppStyle.getScaleFactor(context), - ), - Text( - "${_subtitle.hotLine}\n15564", - - style: Theme.of(context).textTheme.headline6.copyWith( - color: AColors.white, - letterSpacing: 2.75, - fontWeight: FontWeight.bold - ), - ), - ], - ), - onPressed: (){ - launch("tel:15564"); - }, - ), - ), - AIconButton( - iconData: Icons.notifications, - onPressed: (){ - Navigator.of(context).pushNamed(NotificationsPage.id); - }, - ), - ], - ), - ), - ), ], ), ), endDrawer: Drawer( - child: Container( - color: AColors.primaryColor, - child: Column( - children: [ - SizedBox( - width: MediaQuery.of(context).size.width, - child: DrawerHeader( - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.onPrimary, - ), - padding: EdgeInsets.zero, - child: MaterialButton( - padding: EdgeInsets.zero, - onPressed: (){ - Navigator.of(context).pop(); - Navigator.of(context).pushNamed(ProfilePage.id); - - }, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - height: 100 * AppStyle.getScaleFactor(context), - width: 100 * AppStyle.getScaleFactor(context), - padding: EdgeInsets.all(4), - decoration: BoxDecoration( - border: Border.all( - color: Theme.of(context).primaryColor, - width: 2 - ), - shape: BoxShape.circle - ), - child: ClipOval( - child: ImageLoader( - url: "https://cdn.business2community.com/wp-content/uploads/2017/08/blank-profile-picture-973460_640.png", - ), - ), - ), - Text( - _userProvider.user.userName, - style: Theme.of(context).textTheme.headline6.copyWith( - fontWeight: FontWeight.normal, - ), - textScaleFactor: AppStyle.getScaleFactor(context), - ), - ], + backgroundColor: Colors.white, + child: Column( + children: [ + 40.height, + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + const Icon(Icons.clear).onPress(() => Navigator.pop(context)), + ], + ).paddingOnly(left: 4, right: 14), + Row( + children: [ + Container( + 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), + child: ClipOval( + child: ImageLoader( + url: "https://cdn.business2community.com/wp-content/uploads/2017/08/blank-profile-picture-973460_640.png", ), ), ), - ), - Row( - children: [ - Radio( - value: "en", - activeColor: Colors.white, - focusColor: Colors.white, - groupValue: _settingProvider.language, - onChanged: (value){ - _settingProvider.setLanguage(value); - } - ), - Text( - "English", - style: Theme.of(context).textTheme.bodyText1.copyWith( - color: Colors.white + 12.width, + Text( + _userProvider.user.userName, + style: Theme.of(context).textTheme.headline6.copyWith( + fontWeight: FontWeight.w600, + ), + textScaleFactor: AppStyle.getScaleFactor(context), + ).expanded + ], + ).paddingOnly(left: 14, right: 14, top: 21, bottom: 21), + Divider( + height: 1, + thickness: 1, + color: AColors.greyEF, + ), + ListView( + children: [ + Row( + children: [ + Radio( + value: "en", + activeColor: AColors.grey3A, + focusColor: AColors.grey3A, + groupValue: _settingProvider.language, + onChanged: (value) { + _settingProvider.setLanguage(value); + }), + Text( + "English", + style: Theme.of(context).textTheme.bodyText1.copyWith(color: AColors.grey3A), + textScaleFactor: AppStyle.getScaleFactor(context), ), - textScaleFactor: AppStyle.getScaleFactor(context), - ), - Radio( - value: "ar", - activeColor: Colors.white, - focusColor: Colors.white, - groupValue: _settingProvider.language, - onChanged: (value){ - _settingProvider.setLanguage(value); - } - ), - Text( - "عربي", - style: Theme.of(context).textTheme.bodyText1.copyWith( - color: Colors.white + Radio( + value: "ar", + activeColor: AColors.grey3A, + focusColor: AColors.grey3A, + groupValue: _settingProvider.language, + onChanged: (value) { + _settingProvider.setLanguage(value); + }), + Text( + "عربي", + style: Theme.of(context).textTheme.bodyText1.copyWith(color: AColors.grey3A), + textScaleFactor: AppStyle.getScaleFactor(context), ), - textScaleFactor: AppStyle.getScaleFactor(context), - ), - ], - ), - DrawerItem( - icon: FontAwesomeIcons.linkedinIn, - title: _subtitle.linkedIn, - onPressed: (){ - launch("https://www.linkedin.com/company/Test SA/"); - }, - ), - DrawerItem( - icon: FontAwesomeIcons.globe, - title: _subtitle.ourWebsite, - onPressed: (){ - launch("https://www.Test SA.com/"); - }, - ), - DrawerItem( - 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/"; - Share.share(shareLink); - }, - ), - Expanded(child: Center(child: Image.asset("assets/images/qr.jpeg"))), - Padding( - padding: const EdgeInsets.all(8.0), - child: Text( + ], + ), + DrawerItem( + icon: Icons.notifications, + title: _subtitle.notifications, + onPressed: () { + Navigator.of(context).pushNamed(NotificationsPage.id); + }, + ), + DrawerItem( + icon: Icons.mail, + title: _subtitle.email, + onPressed: () { + launch("mailto:customerservice@Test SA.com"); + }, + ), + DrawerItem( + icon: Icons.phone_in_talk, + title: "${_subtitle.hotLine} 15564", + onPressed: () { + launch("tel:15564"); + }, + ), + DrawerItem( + icon: FontAwesomeIcons.linkedinIn, + title: _subtitle.linkedIn, + onPressed: () { + launch("https://www.linkedin.com/company/Test SA/"); + }, + ), + DrawerItem( + icon: FontAwesomeIcons.globe, + title: _subtitle.ourWebsite, + onPressed: () { + launch("https://www.Test SA.com/"); + }, + ), + DrawerItem( + 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/"; + Share.share(shareLink); + }, + ), + ], + ).expanded, + Divider(height: 1, thickness: 1, color: AColors.greyEF), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( "Powered By NewTrack", - style: Theme.of(context).textTheme.bodyText2.copyWith( - fontWeight: FontWeight.normal, - color: AColors.white - ), + 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) + ], + ).paddingOnly(left: 20, right: 20, top: 8, bottom: 8), + ], ), ), ), diff --git a/lib/views/pages/user/requests/create_request.dart b/lib/views/pages/user/requests/create_request.dart index 104ce32e..32a4e29f 100644 --- a/lib/views/pages/user/requests/create_request.dart +++ b/lib/views/pages/user/requests/create_request.dart @@ -11,11 +11,12 @@ import 'package:test_sa/controllers/providers/api/service_requests_provider.dart import 'package:test_sa/controllers/providers/api/user_provider.dart'; import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; import 'package:test_sa/controllers/validator/validator.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/device/device.dart'; import 'package:test_sa/models/service_request/service_request.dart'; import 'package:test_sa/models/subtitle.dart'; import 'package:test_sa/views/app_style/colors.dart'; -import 'package:test_sa/views/app_style/sizing.dart'; import 'package:test_sa/views/widgets/app_text_form_field.dart'; import 'package:test_sa/views/widgets/buttons/app_back_button.dart'; import 'package:test_sa/views/widgets/buttons/app_button.dart'; @@ -24,14 +25,15 @@ import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; import 'package:test_sa/views/widgets/sound/record_sound.dart'; import 'package:test_sa/views/widgets/speech_to_text/speech_to_text.dart'; + class CreateRequestPage extends StatefulWidget { static final String id = "/create-request"; + @override _CreateRequestPageState createState() => _CreateRequestPageState(); } class _CreateRequestPageState extends State { - double _height; UserProvider _userProvider; SettingProvider _settingProvider; @@ -56,6 +58,7 @@ class _CreateRequestPageState extends State { _controller.dispose(); super.dispose(); } + @override Widget build(BuildContext context) { _height = MediaQuery.of(context).size.height; @@ -78,11 +81,13 @@ class _CreateRequestPageState extends State { ListView( children: [ //AppNameBar(), - SizedBox(height: 16,), + SizedBox( + height: 16, + ), Hero( tag: "logo", child: Image( - height: _height/6, + height: _height / 6, image: AssetImage("assets/images/logo.png"), ), ), @@ -91,104 +96,80 @@ class _CreateRequestPageState extends State { padding: const EdgeInsets.all(8.0), child: Text( _subtitle.newServiceRequest, - 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.w600), ), ), ), - Container( - padding: EdgeInsets.symmetric(horizontal: 16), - margin: EdgeInsets.symmetric(horizontal: 16), - decoration: BoxDecoration( - color: AColors.grey, - borderRadius: BorderRadius.circular(AppStyle.getBorderRadius(context)), - boxShadow: const [ - BoxShadow( - color: AColors.grey, - offset: Offset(0,-1), - ) - ] - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SizedBox(height: 8,), - _userProvider.user.hospital == null ? SizedBox.shrink() : - ATextFormField( - enable: false, - initialValue: _userProvider.user.hospital?.name ?? _subtitle.noHospitalFound, - hintText: _subtitle.hospital, - prefixIconData: FontAwesomeIcons.hospitalAlt, - prefixIconSize: 36, - style: Theme.of(context).textTheme.headline6, - ), - const SizedBox(height: 8,), - _userProvider.user.department == null ? SizedBox.shrink() : - ATextFormField( - enable: false, - initialValue: _userProvider.user.department?.name ?? _subtitle.noUniteFound, - hintText: _subtitle.unite, - prefixIconData: FontAwesomeIcons.hospitalUser, - prefixIconSize: 36, - style: Theme.of(context).textTheme.headline6, - ), - const SizedBox(height: 8,), - DeviceButton( - device: _device, - onDevicePick: (device){ - _device = device; - setState(() {}); - }, - ), - MultiImagesPicker( - label: _subtitle.deviceImages, - images: _deviceImages, - ), - const SizedBox(height: 8,), - SpeechToTextButton( - controller: _controller, - ), - const SizedBox(height: 8,), - ATextFormField( - controller: _controller, - initialValue: _serviceRequest.maintenanceIssue, - hintText: _subtitle.maintenanceIssue, - prefixIconData: FontAwesomeIcons.exclamationTriangle, - prefixIconSize: 36, - style: Theme.of(context).textTheme.headline6, - textInputType: TextInputType.multiline, - validator: (value) => Validator.hasValue(value) - ? null : _subtitle.maintenanceIssueRequired, - onSaved: (value){ - _serviceRequest.maintenanceIssue = value; - }, - ), - const SizedBox(height: 8,), - RecordSound( - onRecord: (audio){ - _serviceRequest.audio = audio; - } - ), - const SizedBox(height: 8,), - ], - ), - ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + 12.height, + _userProvider.user.hospital == null + ? SizedBox.shrink() + : ATextFormField( + enable: false, + initialValue: _userProvider.user.hospital?.name ?? _subtitle.noHospitalFound, + hintText: _subtitle.hospital, + prefixIconData: FontAwesomeIcons.hospital, + style: Theme.of(context).textTheme.headline6, + ), + 12.height, + _userProvider.user.department == null + ? SizedBox.shrink() + : ATextFormField( + enable: false, + initialValue: _userProvider.user.department?.name ?? _subtitle.noUniteFound, + hintText: _subtitle.unite, + prefixIconData: FontAwesomeIcons.hospitalUser, + style: Theme.of(context).textTheme.headline6, + ), + 12.height, + DeviceButton( + device: _device, + onDevicePick: (device) { + _device = device; + setState(() {}); + }, + ), + 12.height, + MultiImagesPicker( + label: _subtitle.deviceImages, + images: _deviceImages, + ), + 12.height, + SpeechToTextButton(controller: _controller), + 12.height, + ATextFormField( + controller: _controller, + initialValue: _serviceRequest.maintenanceIssue, + hintText: _subtitle.maintenanceIssue, + prefixIconData: FontAwesomeIcons.triangleExclamation, + style: Theme.of(context).textTheme.headline6, + textInputType: TextInputType.multiline, + validator: (value) => Validator.hasValue(value) ? null : _subtitle.maintenanceIssueRequired, + onSaved: (value) { + _serviceRequest.maintenanceIssue = value; + }, + ), + 12.height, + RecordSound(onRecord: (audio) { + _serviceRequest.audio = audio; + }), + 12.height, + ], + ).paddingOnly(left: 20, right: 20), Padding( - padding: const EdgeInsets.all(16.0), + padding: const EdgeInsets.all(20.0), child: AButton( text: _subtitle.submit, onPressed: () async { - if(!_formKey.currentState.validate()) - return; + if (!_formKey.currentState.validate()) return; _formKey.currentState.save(); _serviceRequest.deviceId = _device?.id ?? ""; - _isLoading =true; + _isLoading = true; setState(() {}); - _serviceRequest.devicePhotos = _deviceImages.map( - (e) => base64Encode(e.readAsBytesSync())).toList(); - if(_serviceRequest.audio != null){ + _serviceRequest.devicePhotos = _deviceImages.map((e) => base64Encode(e.readAsBytesSync())).toList(); + if (_serviceRequest.audio != null) { final file = File(_serviceRequest.audio); _serviceRequest.audio = base64Encode(file.readAsBytesSync()); } @@ -198,23 +179,18 @@ class _CreateRequestPageState extends State { host: _settingProvider.host, serviceRequest: _serviceRequest, ); - _isLoading =false; + _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(); - }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), + )); } }, ), diff --git a/lib/views/widgets/app_text_form_field.dart b/lib/views/widgets/app_text_form_field.dart index 407b351f..24ea9922 100644 --- a/lib/views/widgets/app_text_form_field.dart +++ b/lib/views/widgets/app_text_form_field.dart @@ -1,6 +1,6 @@ -import 'package:test_sa/views/app_style/colors.dart'; -import 'package:test_sa/views/app_style/sizing.dart'; import 'package:flutter/material.dart'; +import 'package:test_sa/views/app_style/sizing.dart'; + class ATextFormField extends StatefulWidget { final Function(String) onSaved; final Function(String) validator; @@ -22,57 +22,51 @@ class ATextFormField extends StatefulWidget { final TextInputAction textInputAction; final VoidCallback onAction; - const ATextFormField({ - Key key, - this.onSaved, - this.validator, - this.node, - this.onChange, - this.obscureText, - this.showPassword, - this.hintText, - this.labelText, - this.textInputType = TextInputType.text, - this.initialValue, - this.enable = true, - this.style, - this.textAlign, - this.suffixIcon, - this.prefixIconData, - this.prefixIconSize, - this.controller, - this.textInputAction, - this.onAction - }) : super(key: key); + const ATextFormField( + {Key key, + this.onSaved, + this.validator, + this.node, + this.onChange, + this.obscureText, + this.showPassword, + this.hintText, + this.labelText, + this.textInputType = TextInputType.text, + this.initialValue, + this.enable = true, + this.style, + this.textAlign, + this.suffixIcon, + this.prefixIconData, + this.prefixIconSize, + this.controller, + this.textInputAction, + this.onAction}) + : super(key: key); @override State createState() => _ATextFormFieldState(); } class _ATextFormFieldState extends State { - @override void initState() { - if(widget.controller != null) - widget.controller.text = widget.initialValue; + if (widget.controller != null) widget.controller.text = widget.initialValue; super.initState(); } @override Widget build(BuildContext context) { return Container( - padding: EdgeInsets.symmetric( - horizontal: 16 - ), + height: widget.textInputType == TextInputType.multiline ? null : 50, + padding: EdgeInsets.only(left: 12, right: 12), decoration: BoxDecoration( - color: Colors.white, - border: Border.all(color:AColors.black), - borderRadius: BorderRadius.circular( - AppStyle.borderRadius * AppStyle.getScaleFactor(context) + color: Color(0xfff5f5f5), + border: Border.all( + color: Color(0xffefefef), ), - boxShadow: [ - AppStyle.boxShadow - ] + borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)), ), child: TextFormField( focusNode: widget.node, @@ -81,33 +75,32 @@ class _ATextFormFieldState extends State { initialValue: widget.controller != null ? null : widget.initialValue, validator: widget.validator, onChanged: widget.onChange, - textAlign: widget.textAlign ?? TextAlign.center, + textAlign: TextAlign.left, obscureText: widget.obscureText ?? false, keyboardType: widget.textInputType, maxLines: widget.textInputType == TextInputType.multiline ? null : 1, obscuringCharacter: "●", controller: widget.controller, - textInputAction: - widget.textInputType == TextInputType.multiline ? null : widget.textInputAction ?? TextInputAction.next, + textInputAction: widget.textInputType == TextInputType.multiline ? null : widget.textInputAction ?? TextInputAction.next, onEditingComplete: widget.onAction ?? () => FocusScope.of(context).nextFocus(), - style: widget.style, + // style: widget.style, + style: Theme.of(context).textTheme.bodyText1, decoration: InputDecoration( - border: InputBorder.none, - disabledBorder: InputBorder.none, - focusedBorder: InputBorder.none, - enabledBorder: InputBorder.none, - - hintText: widget.hintText, - labelText: widget.labelText, - suffixIcon: widget.suffixIcon, - prefixIcon: widget.prefixIconData == null ? null : Icon( - widget.prefixIconData, - size: widget.prefixIconSize == null - ? 32 * AppStyle.getScaleFactor(context) - : (widget.prefixIconSize - 10) * AppStyle.getScaleFactor(context), - color: AColors.black, - ) - ), + border: InputBorder.none, + suffixIconConstraints: BoxConstraints(minWidth: 0), + disabledBorder: InputBorder.none, + focusedBorder: InputBorder.none, + enabledBorder: InputBorder.none, + constraints: BoxConstraints(), + errorStyle: TextStyle(height: 0.3), + //contentPadding: EdgeInsets.only(left: 0), + hintText: widget.hintText, + labelText: widget.labelText, + //suffixIcon: widget.suffixIcon, + suffixIcon: widget.prefixIconData == null + ? null + : Icon(widget.prefixIconData, + size: widget.prefixIconSize == null ? 20 * AppStyle.getScaleFactor(context) : (widget.prefixIconSize - 10) * AppStyle.getScaleFactor(context), color: Color(0xff2e303a))), ), ); } diff --git a/lib/views/widgets/buttons/app_back_button.dart b/lib/views/widgets/buttons/app_back_button.dart index c7c72ce4..a7ce9c2b 100644 --- a/lib/views/widgets/buttons/app_back_button.dart +++ b/lib/views/widgets/buttons/app_back_button.dart @@ -1,29 +1,28 @@ - -import 'package:test_sa/views/app_style/colors.dart'; import 'package:flutter/material.dart'; -import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:test_sa/views/app_style/colors.dart'; import 'app_icon_button.dart'; + class ABackButton extends StatelessWidget { final VoidCallback onPressed; + final IconData icon; + + const ABackButton({Key key, this.onPressed,this.icon}) : super(key: key); - const ABackButton({Key key, this.onPressed}) : super(key: key); @override Widget build(BuildContext context) { return Padding( - padding: const EdgeInsets.symmetric( - vertical: 4, - horizontal: 16 - ), + padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 16), child: AIconButton( color: AColors.white, - backgroundColor: AColors.green, - iconData: FontAwesomeIcons.reply, + backgroundColor: AColors.primaryColor, + iconData: icon ?? Icons.arrow_back_ios_new, iconSize: 24, - buttonSize: 42, - onPressed: onPressed ?? (){ - Navigator.of(context).pop(); - }, + buttonSize: 40, + onPressed: onPressed ?? + () { + Navigator.of(context).pop(); + }, ), ); } diff --git a/lib/views/widgets/buttons/app_button.dart b/lib/views/widgets/buttons/app_button.dart index 231e1d80..6c0459d5 100644 --- a/lib/views/widgets/buttons/app_button.dart +++ b/lib/views/widgets/buttons/app_button.dart @@ -1,6 +1,6 @@ +import 'package:flutter/material.dart'; import 'package:test_sa/views/app_style/colors.dart'; import 'package:test_sa/views/app_style/sizing.dart'; -import 'package:flutter/material.dart'; class AButton extends StatelessWidget { final String text; @@ -10,40 +10,26 @@ class AButton extends StatelessWidget { final TextStyle textStyle; final VoidCallback onPressed; - const AButton({ - Key key, - this.color = AColors.primaryColor, - this.text, - this.padding, - this.onPressed, - this.textStyle - }) : super(key: key); + const AButton({Key key, this.color = AColors.primaryColor, this.text, this.padding, this.onPressed, this.textStyle}) : super(key: key); + @override Widget build(BuildContext context) { return SizedBox( width: MediaQuery.of(context).size.width, child: ElevatedButton( style: ElevatedButton.styleFrom( - foregroundColor: color.computeLuminance() > 0.5 - ? AColors.black : Colors.white, + elevation: 0, + foregroundColor: color.computeLuminance() > 0.5 ? AColors.black : Colors.white, backgroundColor: color, padding: padding ?? const EdgeInsets.symmetric(vertical: 12), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular( - AppStyle.getBorderRadius(context) - ) - ), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(AppStyle.getBorderRadius(context))), ), onPressed: onPressed, child: Text( - text??"", - style: textStyle - ?? Theme.of(context).textTheme.subtitle2.copyWith( - color: AColors.white, - fontSize: 18 - ), + text ?? "", + style: textStyle ?? Theme.of(context).textTheme.subtitle2.copyWith(color: AColors.white, fontSize: 14,fontWeight: FontWeight.w600), textScaleFactor: AppStyle.getScaleFactor(context), - ) + ), ), ); } diff --git a/lib/views/widgets/buttons/app_outlined_button.dart b/lib/views/widgets/buttons/app_outlined_button.dart index 7497d395..ddfb3042 100644 --- a/lib/views/widgets/buttons/app_outlined_button.dart +++ b/lib/views/widgets/buttons/app_outlined_button.dart @@ -1,6 +1,6 @@ +import 'package:flutter/material.dart'; import 'package:test_sa/views/app_style/colors.dart'; import 'package:test_sa/views/app_style/sizing.dart'; -import 'package:flutter/material.dart'; class AOutLinedButton extends StatelessWidget { final String text; @@ -9,42 +9,36 @@ class AOutLinedButton extends StatelessWidget { final TextStyle textStyle; final VoidCallback onPressed; - const AOutLinedButton({ - Key key, - this.color = AColors.primaryColor, - this.text, - this.padding, - this.onPressed, - this.textStyle - }) : super(key: key); + const AOutLinedButton({Key key, this.color = AColors.primaryColor, this.text, this.padding, this.onPressed, this.textStyle}) : super(key: key); + @override Widget build(BuildContext context) { return OutlinedButton( - style: ElevatedButton.styleFrom( - padding: padding ?? EdgeInsets.symmetric(vertical: 12), - textStyle: textStyle - ?? Theme.of(context).textTheme.subtitle2.copyWith( - fontSize: 18 + style: ElevatedButton.styleFrom( + padding: padding ?? EdgeInsets.symmetric(vertical: 12), + textStyle: textStyle ?? Theme + .of(context) + .textTheme + .subtitle2 + .copyWith(fontSize: 18), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(AppStyle.getBorderRadius(context))), ), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular( - AppStyle.getBorderRadius(context) - ) - ), - ), - onPressed: onPressed, - child: Row( - children: [ - Expanded( - child: Text( - text??"", - - textAlign: TextAlign.center, - textScaleFactor: AppStyle.getScaleFactor(context), + onPressed: onPressed, + child: Row( + children: [ + Expanded( + child: Text( + text ?? "", + style: Theme + .of(context) + .textTheme + .subtitle2 + .copyWith(color: AColors.primaryColor, fontSize: 14, fontWeight: FontWeight.w600), + textAlign: TextAlign.center, + textScaleFactor: AppStyle.getScaleFactor(context), + ), ), - ), - ], - ) - ); + ], + )); } } diff --git a/lib/views/widgets/departments/department_button.dart b/lib/views/widgets/departments/department_button.dart index 811f0898..5aa8b0e4 100644 --- a/lib/views/widgets/departments/department_button.dart +++ b/lib/views/widgets/departments/department_button.dart @@ -1,64 +1,50 @@ +import 'package:flutter/material.dart'; import 'package:test_sa/controllers/localization/localization.dart'; import 'package:test_sa/models/department.dart'; import 'package:test_sa/models/subtitle.dart'; import 'package:test_sa/views/app_style/colors.dart'; import 'package:test_sa/views/app_style/sizing.dart'; import 'package:test_sa/views/widgets/departments/single_department_picker.dart'; -import 'package:flutter/material.dart'; -import 'package:font_awesome_flutter/font_awesome_flutter.dart'; + class DepartmentButton extends StatelessWidget { final Function(Department) onDepartmentPick; final Department department; - const DepartmentButton({ - Key key, - this.department, - this.onDepartmentPick - }) : super(key: key); + const DepartmentButton({Key key, this.department, this.onDepartmentPick}) : super(key: key); @override Widget build(BuildContext context) { Subtitle _subtitle = AppLocalization.of(context).subtitle; return ElevatedButton( style: ElevatedButton.styleFrom( - padding: EdgeInsets.symmetric(horizontal: 16,vertical: 12), + elevation: 0, + padding: EdgeInsets.symmetric(horizontal: 8, vertical: 8), shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular( - AppStyle.borderRadius * AppStyle.getScaleFactor(context) - ), - side: BorderSide( - color: AColors.black - ) + borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)), ), foregroundColor: AColors.primaryColor, - backgroundColor: AColors.white, + backgroundColor: AColors.inputFieldBackgroundColor, ), child: Row( children: [ - FaIcon( - FontAwesomeIcons.hospitalUser, - size: 28, - color: AColors.black, - ), Expanded( child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 6), + padding: const EdgeInsets.symmetric(horizontal: 8), child: Text( department?.name ?? _subtitle.pickUnite, - style: Theme.of(context).textTheme.subtitle1, + style: Theme.of(context).textTheme.bodyText1, textScaleFactor: AppStyle.getScaleFactor(context), textDirection: TextDirection.rtl, - textAlign: TextAlign.center, + textAlign: TextAlign.left, ), ), ), - + const Icon(Icons.keyboard_arrow_down, size: 28, color: AColors.grey3A), ], ), onPressed: () async { Department _department = await Navigator.of(context).pushNamed(SingleDepartmentPicker.id) as Department; onDepartmentPick(_department); - } - ); + }); } } diff --git a/lib/views/widgets/drawer/drawer_item.dart b/lib/views/widgets/drawer/drawer_item.dart index 88f027dd..1bbc2474 100644 --- a/lib/views/widgets/drawer/drawer_item.dart +++ b/lib/views/widgets/drawer/drawer_item.dart @@ -1,48 +1,39 @@ -import 'package:test_sa/views/app_style/sizing.dart'; import 'package:flutter/material.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/views/app_style/colors.dart'; +import 'package:test_sa/views/app_style/sizing.dart'; + class DrawerItem extends StatelessWidget { final String title; final IconData icon; final VoidCallback onPressed; const DrawerItem({Key key, this.title, this.icon, this.onPressed}) : super(key: key); + @override Widget build(BuildContext context) { return Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.all(0.0), child: ElevatedButton( style: ElevatedButton.styleFrom( padding: EdgeInsets.zero, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular( - AppStyle.getBorderRadius(context) - ) - ), + elevation: 0, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(AppStyle.getBorderRadius(context))), primary: Theme.of(context).colorScheme.onPrimary, ), - onPressed: onPressed, child: Row( children: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: SizedBox( - width: 48, - child: Icon( - icon, color: Theme.of(context).colorScheme.primary - ), - ), - ), + Icon(icon, color: AColors.grey3A,size: 20), + 12.width, Text( title, - style: Theme.of(context).textTheme.headline6.copyWith( - fontSize: 16, - color: Theme.of(context).colorScheme.primary - ), + style: Theme.of(context).textTheme.headline6.copyWith(fontSize: 14, color: AColors.grey3A), textScaleFactor: AppStyle.getScaleFactor(context), ), ], - ), + ).paddingOnly(left: 20,right: 20), ), ); } diff --git a/lib/views/widgets/equipment/device_button.dart b/lib/views/widgets/equipment/device_button.dart index 78617fc2..571a0b02 100644 --- a/lib/views/widgets/equipment/device_button.dart +++ b/lib/views/widgets/equipment/device_button.dart @@ -1,86 +1,78 @@ +import 'package:flutter/material.dart'; import 'package:test_sa/controllers/localization/localization.dart'; import 'package:test_sa/models/device/device.dart'; import 'package:test_sa/models/subtitle.dart'; import 'package:test_sa/views/app_style/colors.dart'; import 'package:test_sa/views/app_style/sizing.dart'; import 'package:test_sa/views/widgets/equipment/single_device_picker.dart'; -import 'package:flutter/material.dart'; -import 'package:font_awesome_flutter/font_awesome_flutter.dart'; + class DeviceButton extends StatelessWidget { final Function(Device) onDevicePick; final Device device; - const DeviceButton({ - Key key, - this.device, - this.onDevicePick - }) : super(key: key); + const DeviceButton({Key key, this.device, this.onDevicePick}) : super(key: key); @override Widget build(BuildContext context) { Subtitle _subtitle = AppLocalization.of(context).subtitle; return ElevatedButton( - style: ElevatedButton.styleFrom( - padding: EdgeInsets.symmetric(horizontal: 16,vertical: device == null ? 12 : 8), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular( - AppStyle.borderRadius * AppStyle.getScaleFactor(context) - ), - side: BorderSide( - color: AColors.black - ) + style: ElevatedButton.styleFrom( + elevation: 0, + padding: EdgeInsets.symmetric(horizontal: 16, vertical: device == null ? 12 : 8), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)), + ), + foregroundColor: AColors.primaryColor, + backgroundColor: AColors.inputFieldBackgroundColor, ), - onPrimary: AColors.primaryColor, - primary: AColors.white, - ), - child: Row( children: [ - FaIcon( - FontAwesomeIcons.hardDrive, - size: 28, - color: AColors.black, - ), - device == null ? - Expanded( - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 6), - child: Text( - _subtitle.pickDevice, - style: Theme.of(context).textTheme.subtitle1, - textScaleFactor: AppStyle.getScaleFactor(context), - textDirection: TextDirection.rtl, - textAlign: TextAlign.center, - ), - ), - ): - Expanded( - child: ListTile( - title: Text("${_subtitle.sn} : " + device.serialNumber, - style: Theme.of(context).textTheme.subtitle1, - ), - subtitle: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Divider(color: Theme.of(context).textTheme.subtitle1.color,), - Text("${_subtitle.brand} : " + device.brand, - style: Theme.of(context).textTheme.subtitle2, + device == null + ? Expanded( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 6), + child: Text( + _subtitle.pickDevice, + style: Theme.of(context).textTheme.subtitle1, + textScaleFactor: AppStyle.getScaleFactor(context), + textDirection: TextDirection.rtl, + textAlign: TextAlign.left, + ), ), - Divider(color: Theme.of(context).textTheme.subtitle1.color,), - Text("${_subtitle.model} : " + device.model, - style: Theme.of(context).textTheme.subtitle2, + ) + : Expanded( + child: ListTile( + contentPadding: EdgeInsets.all(0), + title: Text( + "${_subtitle.sn} : " + device.serialNumber, + style: Theme.of(context).textTheme.subtitle1, ), - ], - ), - ) - ) - + subtitle: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Divider( + color: Theme.of(context).textTheme.subtitle1.color, + ), + Text( + "${_subtitle.brand} : " + device.brand, + style: Theme.of(context).textTheme.subtitle2, + ), + Divider( + color: Theme.of(context).textTheme.subtitle1.color, + ), + Text( + "${_subtitle.model} : " + device.model, + style: Theme.of(context).textTheme.subtitle2, + ), + ], + ), + )), + const Icon(Icons.keyboard_arrow_down, size: 28, color: AColors.grey3A), ], ), onPressed: () async { Device _device = await Navigator.of(context).pushNamed(SingleDevicePicker.id) as Device; onDevicePick(_device); - } - ); + }); } } diff --git a/lib/views/widgets/hospitals/auto_complete_field.dart b/lib/views/widgets/hospitals/auto_complete_field.dart index 6c51d23f..6ce29dcf 100644 --- a/lib/views/widgets/hospitals/auto_complete_field.dart +++ b/lib/views/widgets/hospitals/auto_complete_field.dart @@ -1,3 +1,6 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_typeahead/flutter_typeahead.dart'; +import 'package:provider/provider.dart'; import 'package:test_sa/controllers/localization/localization.dart'; import 'package:test_sa/controllers/providers/api/hospitals_provider.dart'; import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; @@ -6,9 +9,7 @@ import 'package:test_sa/models/subtitle.dart'; import 'package:test_sa/views/app_style/colors.dart'; import 'package:test_sa/views/app_style/sizing.dart'; import 'package:test_sa/views/widgets/hospitals/hospital_item.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_typeahead/flutter_typeahead.dart'; -import 'package:provider/provider.dart'; + class AutoCompleteField extends StatefulWidget { final String initialValue; final Function(String) onSearch; @@ -21,7 +22,6 @@ class AutoCompleteField extends StatefulWidget { } class _AutoCompleteFieldState extends State { - SettingProvider _settingProvider; TextEditingController _controller; @@ -36,29 +36,26 @@ class _AutoCompleteFieldState extends State { _controller.dispose(); super.dispose(); } + @override Widget build(BuildContext context) { _settingProvider = Provider.of(context); Subtitle _subtitle = AppLocalization.of(context).subtitle; return Container( - padding: EdgeInsets.symmetric( - horizontal: 16 - ), + padding: EdgeInsets.symmetric(horizontal: 16), decoration: BoxDecoration( - color: Colors.white, - border: Border.all(color:AColors.black), - - borderRadius: BorderRadius.circular( - AppStyle.borderRadius * AppStyle.getScaleFactor(context) - ), - boxShadow: [ - AppStyle.boxShadow - ] + color: AColors.inputFieldBackgroundColor, + border: Border.all( + color: Color(0xffefefef), + ), + borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)), + // boxShadow: [ + // AppStyle.boxShadow + // ] ), child: TypeAheadField( - textFieldConfiguration: TextFieldConfiguration( - style: Theme.of(context).textTheme.headline6, + style: Theme.of(context).textTheme.headline6, onSubmitted: widget.onSave, controller: _controller, textAlign: TextAlign.center, @@ -70,15 +67,11 @@ class _AutoCompleteFieldState extends State { enabledBorder: InputBorder.none, ), textInputAction: TextInputAction.search, - onEditingComplete:(){ + onEditingComplete: () { widget.onSearch(_controller.text); - } - ), + }), suggestionsCallback: (vale) async { - return await HospitalsProvider().getHospitalsList( - host: _settingProvider.host, - title: vale - ); + return await HospitalsProvider().getHospitalsList(host: _settingProvider.host, title: vale); }, itemBuilder: (context, hospital) { return HospitalItem( diff --git a/lib/views/widgets/hospitals/hospital_button.dart b/lib/views/widgets/hospitals/hospital_button.dart index 81c7d9e9..0abefbe4 100644 --- a/lib/views/widgets/hospitals/hospital_button.dart +++ b/lib/views/widgets/hospitals/hospital_button.dart @@ -1,65 +1,48 @@ +import 'package:flutter/material.dart'; import 'package:test_sa/controllers/localization/localization.dart'; import 'package:test_sa/models/hospital.dart'; import 'package:test_sa/models/subtitle.dart'; import 'package:test_sa/views/app_style/colors.dart'; import 'package:test_sa/views/app_style/sizing.dart'; import 'package:test_sa/views/widgets/hospitals/single_hospital_picker.dart'; -import 'package:flutter/material.dart'; -import 'package:font_awesome_flutter/font_awesome_flutter.dart'; + class HospitalButton extends StatelessWidget { final Function(Hospital) onHospitalPick; final Hospital hospital; - const HospitalButton({ - Key key, - this.hospital, - this.onHospitalPick - }) : super(key: key); + const HospitalButton({Key key, this.hospital, this.onHospitalPick}) : super(key: key); @override Widget build(BuildContext context) { - Subtitle _subtitle = AppLocalization.of(context).subtitle; return ElevatedButton( - style: ElevatedButton.styleFrom( - foregroundColor: AColors.primaryColor, - backgroundColor: AColors.white, - padding: EdgeInsets.symmetric(horizontal: 16,vertical: 12), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular( - AppStyle.borderRadius * AppStyle.getScaleFactor(context) - ), - side: const BorderSide( - color: AColors.black - ) + style: ElevatedButton.styleFrom( + elevation: 0, + foregroundColor: AColors.primaryColor, + backgroundColor: AColors.inputFieldBackgroundColor, + padding: EdgeInsets.symmetric(horizontal: 8, vertical: 8), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context))), ), - ), child: Row( children: [ - const FaIcon( - FontAwesomeIcons.solidHospital, - size: 28, - color: AColors.black, - ), Expanded( child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 6), + padding: const EdgeInsets.symmetric(horizontal: 8), child: Text( hospital?.name ?? _subtitle.pickHospital, - style: Theme.of(context).textTheme.subtitle1, - textScaleFactor: AppStyle.getScaleFactor(context), + style: Theme.of(context).textTheme.bodyText1.copyWith(fontSize: 14, color: AColors.grey3A), + // textScaleFactor: AppStyle.getScaleFactor(context), textDirection: TextDirection.rtl, - textAlign: TextAlign.center, + textAlign: TextAlign.left, ), ), ), - + const Icon(Icons.keyboard_arrow_down, size: 28, color: AColors.grey3A), ], ), onPressed: () async { Hospital _hospital = await Navigator.of(context).pushNamed(SingleHospitalPicker.id) as Hospital; onHospitalPick(_hospital); - } - ); + }); } } diff --git a/lib/views/widgets/images/multi_image_picker.dart b/lib/views/widgets/images/multi_image_picker.dart index ae0dddb6..0173336f 100644 --- a/lib/views/widgets/images/multi_image_picker.dart +++ b/lib/views/widgets/images/multi_image_picker.dart @@ -1,160 +1,170 @@ import 'dart:io'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:image_picker/image_picker.dart'; import 'package:test_sa/controllers/localization/localization.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/models/subtitle.dart'; import 'package:test_sa/views/app_style/colors.dart'; import 'package:test_sa/views/app_style/sizing.dart'; import 'package:test_sa/views/widgets/buttons/app_flat_button.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:fluttertoast/fluttertoast.dart'; -import 'package:image_picker/image_picker.dart'; import 'multi_image_picker_item.dart'; + class MultiImagesPicker extends StatefulWidget { final String label; final bool error; final List images; + const MultiImagesPicker({Key key, this.images, this.label, this.error = false}) : super(key: key); @override _MultiImagesPickerState createState() => _MultiImagesPickerState(); } -class _MultiImagesPickerState extends State - with TickerProviderStateMixin{ +class _MultiImagesPickerState extends State with TickerProviderStateMixin { Size _size; + @override Widget build(BuildContext context) { _size = MediaQuery.of(context).size; Subtitle _subtitle = AppLocalization.of(context).subtitle; - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox(height: 8 * AppStyle.getScaleFactor(context),), - Row( - children: [ - Expanded( - child: Text( - widget.label ?? _subtitle.images, - style: Theme.of(context).textTheme - .headline6.copyWith(fontSize: 18,), - textScaleFactor: AppStyle.getScaleFactor(context), - ), - ), - AFlatButton( - text: _subtitle.add, - onPressed: (){onImagePick(_subtitle);}, - ), - ], + return Container( + padding: EdgeInsets.all(12), + decoration: BoxDecoration( + color: Color(0xfff5f5f5), + border: Border.all( + color: Color(0xffefefef), ), - SizedBox(height: 8 * AppStyle.getScaleFactor(context),), - AnimatedSize( - duration: Duration(milliseconds: 400), - child: !widget.error ? SizedBox.shrink() : - Column( - crossAxisAlignment: CrossAxisAlignment.start, + borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // SizedBox(height: 8 * AppStyle.getScaleFactor(context),), + Row( children: [ - Text( - _subtitle.imagesRequired, - style: Theme.of(context).textTheme.headline6.copyWith( - fontSize: 14, - color: AColors.red, + Expanded( + child: Text( + widget.label ?? _subtitle.images, + style: Theme.of(context).textTheme.headline6.copyWith( + fontSize: 16, + ), + textScaleFactor: AppStyle.getScaleFactor(context), ), - textScaleFactor: AppStyle.getScaleFactor(context), ), - SizedBox(height: 8 * AppStyle.getScaleFactor(context),), + AFlatButton( + text: _subtitle.add, + onPressed: () { + onImagePick(_subtitle); + }, + ), ], ), - ), - AnimatedSwitcher( - duration: Duration(milliseconds: 400), - child: Container( - key: ValueKey(widget.images.length), - width: _size.width, - height: 200 * AppStyle.getScaleFactor(context), - padding: EdgeInsets.all(8 * AppStyle.getScaleFactor(context),), - alignment: Alignment.topLeft, - decoration: BoxDecoration( - border: Border.all( - color: Theme.of(context).primaryColor, - width: 2 + 12.height, + AnimatedSize( + duration: Duration(milliseconds: 400), + child: !widget.error + ? SizedBox.shrink() + : Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + _subtitle.imagesRequired, + style: Theme.of(context).textTheme.headline6.copyWith( + fontSize: 14, + color: AColors.red, + ), + textScaleFactor: AppStyle.getScaleFactor(context), + ), + SizedBox( + height: 8 * AppStyle.getScaleFactor(context), + ), + ], + ), + ), + AnimatedSwitcher( + duration: Duration(milliseconds: 400), + child: Container( + key: ValueKey(widget.images.length), + width: _size.width, + height: 200 * AppStyle.getScaleFactor(context), + padding: EdgeInsets.all( + 8 * AppStyle.getScaleFactor(context), ), - borderRadius: BorderRadius.circular( - 8 * AppStyle.getScaleFactor(context)), - ), - child: widget.images.isEmpty? - MaterialButton( - onPressed: (){onImagePick(_subtitle);}, - child: Center( - child: Icon( + alignment: Alignment.topLeft, + decoration: BoxDecoration( + border: Border.all(color: Theme.of(context).primaryColor, width: 2), + borderRadius: BorderRadius.circular(8 * AppStyle.getScaleFactor(context)), + ), + child: widget.images.isEmpty + ? MaterialButton( + onPressed: () { + onImagePick(_subtitle); + }, + child: Center( + child: Icon( Icons.add_a_photo_outlined, - size: 48 * AppStyle.getScaleFactor(context), - color: Theme.of(context).primaryColor, + size: 48 * AppStyle.getScaleFactor(context), + color: Theme.of(context).primaryColor, + )), ) - ), - ) : - GridView.count( - crossAxisCount: 2,//_size.width ~/ 80, - scrollDirection: Axis.horizontal, - mainAxisSpacing: 10, - crossAxisSpacing: 10, - children: List.generate( - widget.images.length, - (index) { - File _image = widget.images[index]; - return MultiImagesPickerItem( - image: _image, - onRemoveTap: (image){ - widget.images.remove(image); - setState(() {}); - }, - ); - } - ), + : GridView.count( + crossAxisCount: 2, + //_size.width ~/ 80, + scrollDirection: Axis.horizontal, + mainAxisSpacing: 10, + crossAxisSpacing: 10, + children: List.generate(widget.images.length, (index) { + File _image = widget.images[index]; + return MultiImagesPickerItem( + image: _image, + onRemoveTap: (image) { + widget.images.remove(image); + setState(() {}); + }, + ); + }), + ), ), ), - ), - ], + ], + ), ); } - onImagePick( Subtitle _subtitle) async { - if(widget.images.length >= 5){ + + onImagePick(Subtitle _subtitle) async { + if (widget.images.length >= 5) { Fluttertoast.showToast(msg: _subtitle.maxImagesNumberIs5); return; } ImageSource source = await showDialog( context: context, builder: (dialogContext) => CupertinoAlertDialog( - actions: [ - TextButton( - child: Text(_subtitle.pickFromCamera), - onPressed: () { - Navigator.of(dialogContext).pop(ImageSource.camera); - }, - ), - TextButton( - child: Text(_subtitle.pickFromGallery), - onPressed: () { - Navigator.of(dialogContext).pop(ImageSource.gallery); - }, - ), - ], - ) - ); - if(source == null) - return; + actions: [ + TextButton( + child: Text(_subtitle.pickFromCamera), + onPressed: () { + Navigator.of(dialogContext).pop(ImageSource.camera); + }, + ), + TextButton( + child: Text(_subtitle.pickFromGallery), + onPressed: () { + Navigator.of(dialogContext).pop(ImageSource.gallery); + }, + ), + ], + )); + if (source == null) return; - final pickedFile = await ImagePicker().pickImage( - source: source, - imageQuality: 70, - maxWidth: 800, - maxHeight: 800 - ); + final pickedFile = await ImagePicker().pickImage(source: source, imageQuality: 70, maxWidth: 800, maxHeight: 800); if (pickedFile != null) { File _fileImage = File(pickedFile.path); - if(_fileImage != null){ + if (_fileImage != null) { widget.images.insert(0, _fileImage); setState(() {}); } diff --git a/lib/views/widgets/land_page/land_page_item.dart b/lib/views/widgets/land_page/land_page_item.dart index 489d67f5..a3085e65 100644 --- a/lib/views/widgets/land_page/land_page_item.dart +++ b/lib/views/widgets/land_page/land_page_item.dart @@ -1,7 +1,8 @@ import 'package:flutter/material.dart'; +import 'package:test_sa/views/app_style/colors.dart'; import 'package:test_sa/views/app_style/sizing.dart'; -class LandPageItem extends StatelessWidget { +class LandPageItem extends StatelessWidget { final String text; final IconData icon; final VoidCallback onPressed; @@ -10,28 +11,34 @@ class LandPageItem extends StatelessWidget { @override Widget build(BuildContext context) { - return ElevatedButton( - style: ElevatedButton.styleFrom( - padding: EdgeInsets.all(10 * AppStyle.getScaleFactor(context),), - textStyle: Theme.of(context).textTheme.subtitle2, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular( - AppStyle.getBorderRadius(context) - ) - ), - //foregroundColor: Colors.white, + return InkWell( + onTap: onPressed, + child: Container( + padding: const EdgeInsets.only(left: 20, right: 20, bottom: 15, top: 28), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(15), + boxShadow: [ + BoxShadow( + color: const Color(0xff000000).withOpacity(.15), + blurRadius: 26, + offset: const Offset(0, -3), + ), + ], ), - onPressed: onPressed, child: Column( - children: [ - Expanded( - child: Center( - child: Icon(icon,size: 58 * AppStyle.getScaleFactor(context),) - ), + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Icon( + icon, + color: AColors.primaryColor, + size: 42 * AppStyle.getScaleFactor(context), ), - Text(text,textAlign: TextAlign.center,), + Text(text, style: TextStyle(color: AColors.grey3A)), ], - ) + ), + ), ); } } diff --git a/lib/views/widgets/sound/record_sound.dart b/lib/views/widgets/sound/record_sound.dart index 2f93c150..d53dbdb3 100644 --- a/lib/views/widgets/sound/record_sound.dart +++ b/lib/views/widgets/sound/record_sound.dart @@ -3,22 +3,22 @@ import 'package:flutter/services.dart'; import 'package:flutter_sound/flutter_sound.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:rive/rive.dart'; -import 'package:test_sa/views/widgets/buttons/app_button.dart'; import 'package:test_sa/views/widgets/buttons/app_icon_button2.dart'; import 'package:test_sa/views/widgets/buttons/app_small_button.dart'; import 'package:test_sa/views/widgets/sound/sound_player.dart'; import '../../app_style/sizing.dart'; + class RecordSound extends StatefulWidget { final Function(String) onRecord; - const RecordSound({Key key,@required this.onRecord}) : super(key: key); + + const RecordSound({Key key, @required this.onRecord}) : super(key: key); @override State createState() => _RecordSoundState(); } class _RecordSoundState extends State { - FlutterSoundRecorder _myRecorder = FlutterSoundRecorder(); bool _recorderIsOpened = false; bool _recording = false; @@ -28,8 +28,9 @@ class _RecordSoundState extends State { @override void setState(VoidCallback fn) { - if(mounted) super.setState(fn); + if (mounted) super.setState(fn); } + @override void initState() { super.initState(); @@ -41,7 +42,7 @@ class _RecordSoundState extends State { // Load the animation file from the bundle, note that you could also // download this. The RiveFile just expects a list of bytes. rootBundle.load('assets/rives/recording.riv').then( - (data) async { + (data) async { // Load the RiveFile from the binary data. final file = RiveFile.import(data); // The artboard is the root of the animation and gets drawn in the @@ -53,10 +54,8 @@ class _RecordSoundState extends State { _rive = artboard; setState(() {}); - }, ); - } @override @@ -71,21 +70,16 @@ class _RecordSoundState extends State { _fastTab = false; // await Permission.camera PermissionStatus status = await Permission.microphone.request(); - if(!status.isGranted){ + if (!status.isGranted) { return; } _rive.addController(SimpleAnimation('recording')); - if(!_recorderIsOpened){ + if (!_recorderIsOpened) { await _myRecorder.openRecorder(); _recorderIsOpened = true; } - await _myRecorder.startRecorder( - toFile: "record_${DateTime.now().millisecondsSinceEpoch}.mp4", - codec: Codec.aacMP4, - sampleRate: 360000, - bitRate: 360000 - ); + await _myRecorder.startRecorder(toFile: "record_${DateTime.now().millisecondsSinceEpoch}.mp4", codec: Codec.aacMP4, sampleRate: 360000, bitRate: 360000); _recording = true; setState(() {}); @@ -93,7 +87,7 @@ class _RecordSoundState extends State { } _stopRecording() async { - if(!_recording){ + if (!_recording) { _fastTab = true; setState(() {}); return; @@ -103,12 +97,12 @@ class _RecordSoundState extends State { _record = path; widget.onRecord(path); _recording = false; - setState(() { }); + setState(() {}); print("onTapUp"); } _cancelRecording() async { - if(!_recording) return; + if (!_recording) return; String path = await _myRecorder.stopRecorder(); _myRecorder.deleteRecord(fileName: path); _rive.addController(SimpleAnimation('delete')); @@ -116,86 +110,98 @@ class _RecordSoundState extends State { // rebuild(); _recording = false; await Future.delayed(const Duration(seconds: 1)); - if(!_recording) setState(() { }); + if (!_recording) setState(() {}); print("onTapCancel"); // _message.memoryAudio.; } @override Widget build(BuildContext context) { - return Column( - children: [ - Row( - children: [ - Expanded( - child: _recording ? - Row( - children: [ - ASmallButton( - text: "done", - onPressed: (){ - _stopRecording(); - }, - ), - Expanded( - child: Stack( - children: [ - SizedBox( - height: 24 * AppStyle.getScaleFactor(context), - child: Rive(artboard: _rive,) - ), - InkWell( - child: SizedBox( - height: 32 * AppStyle.getScaleFactor(context), - width: MediaQuery.of(context).size.width, + return Container( + padding: EdgeInsets.only(left: 12, right: 0), + decoration: BoxDecoration( + color: Color(0xfff5f5f5), + border: Border.all( + color: Color(0xffefefef), + ), + borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)), + ), + child: Column( + children: [ + Row( + children: [ + Expanded( + child: _recording + ? Row( + children: [ + ASmallButton( + text: "done", + onPressed: () { + _stopRecording(); + }, ), - onTap: (){ - _cancelRecording(); - }, - ), - ], - ), - ), - ], - ): _record != null - ? Row( - children: [ - Expanded(child: ASoundPlayer(audio: _record)), - AIconButton2( - iconData: Icons.delete, - onPressed: (){ - widget.onRecord(null); - _record = null; - setState(() { }); - }, + Expanded( + child: Stack( + children: [ + SizedBox( + height: 24 * AppStyle.getScaleFactor(context), + child: Rive( + artboard: _rive, + )), + InkWell( + child: SizedBox( + height: 32 * AppStyle.getScaleFactor(context), + width: MediaQuery.of(context).size.width, + ), + onTap: () { + _cancelRecording(); + }, + ), + ], + ), + ), + ], ) - ], - ) - : const Text("Record Voice"), - ), - Material( - color: Colors.transparent, - child: GestureDetector( - //key: ValueKey("voice"), - child: const Padding( - padding: EdgeInsets.all(16.0), - child: Icon(Icons.mic), - ), + : _record != null + ? Row( + children: [ + Expanded(child: ASoundPlayer(audio: _record)), + AIconButton2( + iconData: Icons.delete, + onPressed: () { + widget.onRecord(null); + _record = null; + setState(() {}); + }, + ) + ], + ) + : const Text("Record Voice"), + ), + Material( + color: Colors.transparent, + child: GestureDetector( + //key: ValueKey("voice"), + child: const Padding( + padding: EdgeInsets.all(12.0), + child: Icon(Icons.mic), + ), - onTapDown: (TapDownDetails details) async { - _startRecording(); - }, - onTapUp: (TapUpDetails details) async { - _stopRecording(); - }, - onTapCancel: () async { - _cancelRecording(); - }, + onTapDown: (TapDownDetails details) async { + _startRecording(); + }, + onTapUp: (TapUpDetails details) async { + _stopRecording(); + }, + onTapCancel: () async { + _cancelRecording(); + }, + ), ), - ), - ], - ), - ], + ], + ), + ], + ), ); } } diff --git a/lib/views/widgets/speech_to_text/speech_to_text.dart b/lib/views/widgets/speech_to_text/speech_to_text.dart index 03e2eda1..7d4b96d7 100644 --- a/lib/views/widgets/speech_to_text/speech_to_text.dart +++ b/lib/views/widgets/speech_to_text/speech_to_text.dart @@ -1,22 +1,19 @@ -import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; -import 'package:test_sa/views/widgets/buttons/app_icon_button.dart'; -import 'package:test_sa/views/widgets/buttons/app_icon_button2.dart'; -import 'package:test_sa/views/widgets/titles/app_sub_title.dart'; import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:provider/provider.dart'; import 'package:speech_to_text/speech_recognition_error.dart'; import 'package:speech_to_text/speech_recognition_result.dart'; import 'package:speech_to_text/speech_to_text.dart'; +import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; +import 'package:test_sa/views/app_style/sizing.dart'; +import 'package:test_sa/views/widgets/buttons/app_icon_button2.dart'; +import 'package:test_sa/views/widgets/titles/app_sub_title.dart'; -import '../app_text_form_field.dart'; class SpeechToTextButton extends StatefulWidget { - final TextEditingController controller; final bool mini; - const SpeechToTextButton({ - Key key, this.controller,this.mini = false - }) : super(key: key); + + const SpeechToTextButton({Key key, this.controller, this.mini = false}) : super(key: key); @override _SpeechToTextButtonState createState() => _SpeechToTextButtonState(); @@ -32,7 +29,7 @@ class _SpeechToTextButtonState extends State { _speechEnabled = await _speechToText.initialize( onError: (SpeechRecognitionError error) async { Fluttertoast.showToast(msg: "failed to convert text to speech"); - setState(() { }); + setState(() {}); }, ); } @@ -40,18 +37,17 @@ class _SpeechToTextButtonState extends State { /// Each time to start a speech recognition session void _startListening() async { _speechEnabled = _speechToText.isAvailable; - if(_speechToText.isListening){ + if (_speechToText.isListening) { Fluttertoast.showToast(msg: "Currently in use"); return; } - if(!_speechEnabled) return; + if (!_speechEnabled) return; await _speechToText.listen( - onResult: (SpeechRecognitionResult result){ - widget.controller.text = result.recognizedWords; - setState(() {}); - }, - localeId: _settingProvider.speechToText - ); + onResult: (SpeechRecognitionResult result) { + widget.controller.text = result.recognizedWords; + setState(() {}); + }, + localeId: _settingProvider.speechToText); setState(() {}); } @@ -72,51 +68,66 @@ class _SpeechToTextButtonState extends State { @override void setState(VoidCallback fn) { - if(!this.mounted) return; + if (!this.mounted) return; super.setState(fn); } + @override Widget build(BuildContext context) { _settingProvider = Provider.of(context); - return Row( - children: [ - widget.mini ? SizedBox.shrink() : - ASubTitle("Text To Speech"), - widget.controller.text.isNotEmpty? - AIconButton2( - iconData: Icons.delete, - onPressed: (){ - widget.controller.clear(); - setState(() {}); - }, - ):SizedBox.shrink(), - Spacer(), - TextButton( - onPressed: (){ - if(_speechToText.isListening) return; - - if(_settingProvider.speechToText == "ar"){ - _settingProvider.setSpeechToText("en"); - } else{ - _settingProvider.setSpeechToText("ar"); - } - }, - child: Text(_settingProvider.speechToText) + return Container( + padding: EdgeInsets.only(left: 12, right: 12), + decoration: BoxDecoration( + color: Color(0xfff5f5f5), + border: Border.all( + color: Color(0xffefefef), ), - GestureDetector( - child: _speechToText.isListening - ? Icon(Icons.fiber_manual_record,color: Colors.red,) - : Icon(Icons.mic,color: Theme.of(context).colorScheme.primary,), + borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)), + ), + child: Row( + children: [ + widget.mini ? SizedBox.shrink() : ASubTitle("Text To Speech"), + widget.controller.text.isNotEmpty + ? AIconButton2( + iconData: Icons.delete, + onPressed: () { + widget.controller.clear(); + setState(() {}); + }, + ) + : SizedBox.shrink(), + Spacer(), + TextButton( + onPressed: () { + if (_speechToText.isListening) return; - onTap: () async { - if(!_speechEnabled){ - Fluttertoast.showToast(msg: "microphone not available"); - return; - } - _startListening(); - }, - ), - ], + if (_settingProvider.speechToText == "ar") { + _settingProvider.setSpeechToText("en"); + } else { + _settingProvider.setSpeechToText("ar"); + } + }, + child: Text(_settingProvider.speechToText)), + GestureDetector( + child: _speechToText.isListening + ? Icon( + Icons.fiber_manual_record, + color: Colors.red, + ) + : Icon( + Icons.mic, + color: Theme.of(context).colorScheme.primary, + ), + onTap: () async { + if (!_speechEnabled) { + Fluttertoast.showToast(msg: "microphone not available"); + return; + } + _startListening(); + }, + ), + ], + ), ); } } diff --git a/lib/views/widgets/status/single_status_menu.dart b/lib/views/widgets/status/single_status_menu.dart index 6923b555..8e35e903 100644 --- a/lib/views/widgets/status/single_status_menu.dart +++ b/lib/views/widgets/status/single_status_menu.dart @@ -1,28 +1,28 @@ +import 'package:flutter/material.dart'; import 'package:test_sa/models/status.dart'; import 'package:test_sa/views/app_style/colors.dart'; import 'package:test_sa/views/app_style/sizing.dart'; -import 'package:flutter/material.dart'; + class SingleStatusMenu extends StatefulWidget { final List statuses; final Status initialStatus; final Function(Status) onSelect; const SingleStatusMenu({Key key, this.statuses, this.onSelect, this.initialStatus}) : super(key: key); + @override _SingleStatusMenuState createState() => _SingleStatusMenuState(); } class _SingleStatusMenuState extends State { - Status _selectedStatus; @override void didUpdateWidget(covariant SingleStatusMenu oldWidget) { - if(widget.initialStatus != null){ - _selectedStatus = widget.statuses?.firstWhere( - (element) { - return element?.id == widget.initialStatus.id; - }); + if (widget.initialStatus != null) { + _selectedStatus = widget.statuses?.firstWhere((element) { + return element?.id == widget.initialStatus.id; + }); } else { _selectedStatus = null; } @@ -31,43 +31,40 @@ class _SingleStatusMenuState extends State { @override void initState() { - if(widget.initialStatus != null){ - _selectedStatus = widget.statuses?.firstWhere( - (element) { - return element?.id == widget.initialStatus.id; - }); + if (widget.initialStatus != null) { + _selectedStatus = widget.statuses?.firstWhere((element) { + return element?.id == widget.initialStatus.id; + }); } super.initState(); } + @override Widget build(BuildContext context) { return Container( - padding: const EdgeInsets.symmetric( - horizontal: 16 - ), + padding: const EdgeInsets.symmetric(horizontal: 16), decoration: BoxDecoration( - color: Colors.white, - border: Border.all(color:AColors.black), - borderRadius: BorderRadius.circular( - AppStyle.borderRadius * AppStyle.getScaleFactor(context) - ), - boxShadow: const [ - AppStyle.boxShadow - ] + color: AColors.inputFieldBackgroundColor, + border: Border.all( + color: Color(0xffefefef), + ), + borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)), + // boxShadow: const [ + // AppStyle.boxShadow + // ] ), child: DropdownButton( value: _selectedStatus, iconSize: 24, - elevation: 16, + icon: Icon(Icons.keyboard_arrow_down_rounded), + elevation: 0, isExpanded: true, hint: Text( "Select", style: Theme.of(context).textTheme.subtitle1, ), - style: TextStyle( - color: Theme.of(context).primaryColor - ), + style: TextStyle(color: Theme.of(context).primaryColor), underline: SizedBox.shrink(), onChanged: (Status newValue) { setState(() { @@ -75,21 +72,15 @@ class _SingleStatusMenuState extends State { }); widget.onSelect(newValue); }, - items: widget.statuses - .map>((Status value) { + items: widget.statuses.map>((Status value) { return DropdownMenuItem( value: value, child: Text( - value.label, - style: Theme.of(context).textTheme.subtitle1.copyWith( - color: Theme.of(context).primaryColor, - fontSize: 11, - //fontWeight: FontWeight.bold - ), + value.label, + style: Theme.of(context).textTheme.subtitle1.copyWith(color: Theme.of(context).primaryColor, fontWeight: FontWeight.w600), ), ); - }) - .toList(), + }).toList(), ), ); } diff --git a/lib/views/widgets/titles/app_sub_title.dart b/lib/views/widgets/titles/app_sub_title.dart index 0d611db1..f70559b6 100644 --- a/lib/views/widgets/titles/app_sub_title.dart +++ b/lib/views/widgets/titles/app_sub_title.dart @@ -12,7 +12,7 @@ class ASubTitle extends StatelessWidget { padding: padding ?? EdgeInsets.zero, child: Text( text, - style: Theme.of(context).textTheme.subtitle2.copyWith( + style: Theme.of(context).textTheme.bodyText1.copyWith( // fontWeight: FontWeight.bold, fontSize: font, color: color diff --git a/pubspec.yaml b/pubspec.yaml index f4f9eb32..e51e2229 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -92,7 +92,7 @@ flutter: - assets/subtitles/ - assets/rives/ fonts: - - family: Swiss + - family: Swiss fonts: - asset: assets/fonts/Gotham_Rounded_Light.otf weight: 300 @@ -100,3 +100,23 @@ flutter: weight: 400 - asset: assets/fonts/Gotham_Rounded_Bold.otf weight: 700 + - family: Poppins + fonts: + - asset: assets/fonts/poppins/Poppins-Black.ttf + weight: 900 + - asset: assets/fonts/poppins/Poppins-ExtraBold.ttf + weight: 800 + - asset: assets/fonts/poppins/Poppins-Bold.ttf + weight: 700 + - asset: assets/fonts/poppins/Poppins-SemiBold.ttf + weight: 600 + - asset: assets/fonts/poppins/Poppins-Medium.ttf + weight: 500 + - asset: assets/fonts/poppins/Poppins-Regular.ttf + weight: 400 + - asset: assets/fonts/poppins/Poppins-Light.ttf + weight: 300 + - asset: assets/fonts/poppins/Poppins-ExtraLight.ttf + weight: 200 + - asset: assets/fonts/poppins/Poppins-Thin.ttf + weight: 100 \ No newline at end of file