From 3aec62dceb24e28590de29fc9112fc487aeaffea Mon Sep 17 00:00:00 2001 From: Elham Rababah Date: Tue, 18 Aug 2020 15:18:12 +0300 Subject: [PATCH 1/4] First step from login page --- ios/Podfile | 87 ++++++ lib/app-icons/config.json | 24 ++ lib/app-icons/driver_app_icons.dart | 25 ++ lib/app-icons/fonts/DriverApp.ttf | Bin 0 -> 2116 bytes lib/config/shared_pref_kay.dart | 2 + .../authentication/authenticated_user.dart | 282 ++++++++++++++++++ lib/core/service/authentication_service.dart | 29 ++ lib/core/service/base_service.dart | 19 +- .../viewModels/authentication_view_model.dart | 30 ++ lib/core/viewModels/base_view_model.dart | 18 +- lib/locator.dart | 4 + lib/main.dart | 7 +- lib/pages/authentication/login_page.dart | 85 ++++++ lib/root_page.dart | 36 +++ lib/widgets/buttons/secondary_button.dart | 27 +- lib/widgets/others/app_scaffold_widget.dart | 66 ++-- lib/widgets/others/network_base_view.dart | 3 +- pubspec.yaml | 4 + 18 files changed, 702 insertions(+), 46 deletions(-) create mode 100644 ios/Podfile create mode 100644 lib/app-icons/config.json create mode 100644 lib/app-icons/driver_app_icons.dart create mode 100644 lib/app-icons/fonts/DriverApp.ttf create mode 100644 lib/core/model/authentication/authenticated_user.dart create mode 100644 lib/core/service/authentication_service.dart create mode 100644 lib/core/viewModels/authentication_view_model.dart create mode 100644 lib/pages/authentication/login_page.dart create mode 100644 lib/root_page.dart diff --git a/ios/Podfile b/ios/Podfile new file mode 100644 index 0000000..6697f0a --- /dev/null +++ b/ios/Podfile @@ -0,0 +1,87 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def parse_KV_file(file, separator='=') + file_abs_path = File.expand_path(file) + if !File.exists? file_abs_path + return []; + end + generated_key_values = {} + skip_line_start_symbols = ["#", "/"] + File.foreach(file_abs_path) do |line| + next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } + plugin = line.split(pattern=separator) + if plugin.length == 2 + podname = plugin[0].strip() + path = plugin[1].strip() + podpath = File.expand_path("#{path}", file_abs_path) + generated_key_values[podname] = podpath + else + puts "Invalid plugin specification: #{line}" + end + end + generated_key_values +end + +target 'Runner' do + use_frameworks! + use_modular_headers! + + # Flutter Pod + + copied_flutter_dir = File.join(__dir__, 'Flutter') + copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework') + copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec') + unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path) + # Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet. + # That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration. + # CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist. + + generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig') + unless File.exist?(generated_xcode_build_settings_path) + raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path) + cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR']; + + unless File.exist?(copied_framework_path) + FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir) + end + unless File.exist?(copied_podspec_path) + FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir) + end + end + + # Keep pod path relative so it can be checked into Podfile.lock. + pod 'Flutter', :path => 'Flutter' + + # Plugin Pods + + # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock + # referring to absolute paths on developers' machines. + system('rm -rf .symlinks') + system('mkdir -p .symlinks/plugins') + plugin_pods = parse_KV_file('../.flutter-plugins') + plugin_pods.each do |name, path| + symlink = File.join('.symlinks', 'plugins', name) + File.symlink(path, symlink) + pod name, :path => File.join(symlink, 'ios') + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + target.build_configurations.each do |config| + config.build_settings['ENABLE_BITCODE'] = 'NO' + end + end +end diff --git a/lib/app-icons/config.json b/lib/app-icons/config.json new file mode 100644 index 0000000..cca5b07 --- /dev/null +++ b/lib/app-icons/config.json @@ -0,0 +1,24 @@ +{ + "name": "DriverApp", + "css_prefix_text": "", + "css_use_suffix": false, + "hinting": true, + "units_per_em": 1000, + "ascent": 850, + "glyphs": [ + { + "uid": "6b13cdbdada31c1cc88c63aedc146a9c", + "css": "logo", + "code": 59393, + "src": "custom_icons", + "selected": true, + "svg": { + "path": "M1572.1 336.4A308.4 308.4 0 0 0 1008.4 436.3C1007 443.1 1005.5 449.9 1003.6 458.7 972.3 454.4 941.8 450.3 911.4 446.1S850.1 437.4 818 432.8C818.4 426.5 818.3 421 819.2 415.9A498.9 498.9 0 1 1 1532.6 947.1 489.1 489.1 0 0 1 1117.1 960 21.8 21.8 0 0 1 1101 931.9C1116.5 824.5 1160.3 502.5 1164.7 470 1172.6 412.1 1179.8 354 1189 296.4A37.2 37.2 0 0 1 1207.3 272.1 252.3 252.3 0 0 1 1362.2 255.7C1379.3 259 1385.5 264.7 1382.3 283.6 1374.2 331.4 1368.2 379.7 1362.4 427.9 1361.1 438.9 1326.1 693.4 1309.7 810 1331.9 807.6 1351.9 806.7 1371.5 803.2A308.6 308.6 0 0 0 1619 493.2C1618.7 485.7 1616.7 459.2 1615.7 452.9A436.5 436.5 0 0 0 1590.8 372C1588.7 368.6 1577.1 344.3 1572.1 336.4ZM237.6 663.6A308.4 308.4 0 0 0 801.2 563.8C802.7 557 804.2 550.2 806.1 541.4 837.4 545.6 867.9 549.7 898.3 554S959.6 562.7 991.7 567.3C991.3 573.6 991.3 579.1 990.5 584.2A498.9 498.9 0 1 1 277 53 489.1 489.1 0 0 1 692.6 40.1 21.8 21.8 0 0 1 708.6 68.2C693.2 175.5 649.4 497.6 645 530.1 637.1 588 629.9 646 620.7 703.7A37.2 37.2 0 0 1 602.4 728 252.4 252.4 0 0 1 447.5 744.4C430.5 741.1 424.2 735.3 427.4 716.5 435.5 668.6 441.6 620.4 447.3 572.1 448.7 561.2 483.6 306.7 500 190.1 477.8 192.4 457.8 193.4 438.2 196.9A308.6 308.6 0 0 0 190.7 506.9C191 514.3 193 540.9 194.1 547.2A436.5 436.5 0 0 0 218.9 628.1C221 631.4 232.6 655.5 237.6 663.6Z", + "width": 1810 + }, + "search": [ + "logo" + ] + } + ] +} \ No newline at end of file diff --git a/lib/app-icons/driver_app_icons.dart b/lib/app-icons/driver_app_icons.dart new file mode 100644 index 0000000..f66e96e --- /dev/null +++ b/lib/app-icons/driver_app_icons.dart @@ -0,0 +1,25 @@ +/// Flutter icons DriverApp +/// Copyright (C) 2020 by original authors @ fluttericon.com, fontello.com +/// This font was generated by FlutterIcon.com, which is derived from Fontello. +/// +/// To use this font, place it in your fonts/ directory and include the +/// following in your pubspec.yaml +/// +/// flutter: +/// fonts: +/// - family: DriverApp +/// fonts: +/// - asset: fonts/DriverApp.ttf +/// +/// +/// +import 'package:flutter/widgets.dart'; + +class DriverApp { + DriverApp._(); + + static const _kFontFam = 'DriverApp'; + static const _kFontPkg = null; + + static const IconData logo = IconData(0xe801, fontFamily: _kFontFam, fontPackage: _kFontPkg); +} diff --git a/lib/app-icons/fonts/DriverApp.ttf b/lib/app-icons/fonts/DriverApp.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a9e0e9fc83c193bb1212377594424a3275f8043d GIT binary patch literal 2116 zcmd^A&u<%55T4n!*K0d*ev$+z&1;p!4M}ass+Q@A%9#@vI97rpaY!X3qzE|lQ1iX@Hci#^FW{}7-#6cU zGjHDPdY71pqI82)N-bP^=ZyGt@H!DsfL&g^luS(<4{fUjK)p>aJAWGu-bUuZS&#gqnq|lOkCRnMt9Kd|R>+Ttp2_Iix>A zDVic>ZvM?>idlwRrI#q+d7J)&n5}ZrK>ntOp_5()!=ycCgCFo`6vW2Y71^1XW)KWfN}Yi4Wa zLfDgpZLDazo)8h6i~$(s+>i|5Wy_Vu2fFB$jp;fNYO{z^m( z#0D4Rtr1m^G7rXLqWukLT4CmJyB2x)WBL|y1YgdSpOYf`VqZWCO52v7g}%Y}Hm-mdFPOYG!(y8h@d zlU22C<->E`?SWV0EnSa(xQHyPy#YNIiX5I~;qEubCZD8v?cENp98BWfDC(qN{d-0< z52|_pn8L7{SfLOt`d9^@^>G0BijRYMo0fd6fv@{GLL>CPkE7H@U(0`7AdG!>=#Gz> zI(gp53dQ)ck5%vm9|wT9d>o`6{=~-`_%D4Np)7yv<0uU&`m9~scFM()D^AP~i*zcT z5?8l{4XRuQY*)otBDK#gm{rp;Tr)4XtZx?6u3HcV$F7KZKewnk_PUvK6D8NJO(v5E z_oP{}sYcu6P??J8tV@DUfE~t~#`{-JL06#=P&QR%s**t#7=tztQSv->*fW>~cqHqR z>FIOuR`E5FYXxsWsgR8HTe$3f-<+r4^x{sVsv0c;7m>}vP7Xcmf0oI5(RG|g?jdLl z*;9u^E$HhI)7}XRUbT)_xxjP!bln0KO5Zy2(!9VMAesRSH;k(U$K20HxnM(*OVf literal 0 HcmV?d00001 diff --git a/lib/config/shared_pref_kay.dart b/lib/config/shared_pref_kay.dart index 8c03fcc..b1bfbc9 100644 --- a/lib/config/shared_pref_kay.dart +++ b/lib/config/shared_pref_kay.dart @@ -1,3 +1,5 @@ const TOKEN = 'token'; const APP_LANGUAGE = 'language'; +const USER_PROFILE = 'user-profile'; + diff --git a/lib/core/model/authentication/authenticated_user.dart b/lib/core/model/authentication/authenticated_user.dart new file mode 100644 index 0000000..7ca3a3e --- /dev/null +++ b/lib/core/model/authentication/authenticated_user.dart @@ -0,0 +1,282 @@ +class AuthenticatedUser { + String setupID; + int patientType; + int patientID; + String firstName; + String middleName; + String lastName; + String firstNameN; + String middleNameN; + String lastNameN; + int relationshipID; + int gender; + String dateofBirth; + dynamic dateofBirthN; + String nationalityID; + dynamic phoneResi; + dynamic phoneOffice; + String mobileNumber; + dynamic faxNumber; + String emailAddress; + dynamic bloodGroup; + dynamic rHFactor; + bool isEmailAlertRequired; + bool isSMSAlertRequired; + String preferredLanguage; + bool isPrivilegedMember; + dynamic memberID; + dynamic expiryDate; + dynamic isHmgEmployee; + dynamic employeeID; + dynamic emergencyContactName; + dynamic emergencyContactNo; + int patientPayType; + dynamic dHCCPatientRefID; + bool isPatientDummy; + int status; + dynamic isStatusCleared; + int patientIdentificationType; + String patientIdentificationNo; + int projectID; + int infoSourceID; + dynamic address; + int age; + String ageDesc; + int areaID; + int createdBy; + String genderDescription; + dynamic iR; + dynamic iSOCityID; + dynamic iSOCountryID; + List listPrivilege; + dynamic marital; + int outSA; + dynamic pOBox; + bool receiveHealthSummaryReport; + int sourceType; + dynamic strDateofBirth; + dynamic tempAddress; + dynamic zipCode; + // dynamic patientPayType; + // dynamic patientType; + // dynamic status; + + AuthenticatedUser({ + this.setupID, + this.patientType, + this.patientID, + this.firstName, + this.middleName, + this.lastName, + this.firstNameN, + this.middleNameN, + this.lastNameN, + this.relationshipID, + this.gender, + this.dateofBirth, + this.dateofBirthN, + this.nationalityID, + this.phoneResi, + this.phoneOffice, + this.mobileNumber, + this.faxNumber, + this.emailAddress, + this.bloodGroup, + this.rHFactor, + this.isEmailAlertRequired, + this.isSMSAlertRequired, + this.preferredLanguage, + this.isPrivilegedMember, + this.memberID, + this.expiryDate, + this.isHmgEmployee, + this.employeeID, + this.emergencyContactName, + this.emergencyContactNo, + this.patientPayType, + this.dHCCPatientRefID, + this.isPatientDummy, + this.status, + this.isStatusCleared, + this.patientIdentificationType, + this.patientIdentificationNo, + this.projectID, + this.infoSourceID, + this.address, + this.age, + this.ageDesc, + this.areaID, + this.createdBy, + this.genderDescription, + this.iR, + this.iSOCityID, + this.iSOCountryID, + this.listPrivilege, + this.marital, + this.outSA, + this.pOBox, + this.receiveHealthSummaryReport, + this.sourceType, + this.strDateofBirth, + this.tempAddress, + this.zipCode, + }); + + AuthenticatedUser.fromJson(Map json) { + setupID = json['SetupID']; + patientType = json['PatientType']; + patientID = json['PatientID']; + firstName = json['FirstName']; + middleName = json['MiddleName']; + lastName = json['LastName']; + firstNameN = json['FirstNameN']; + middleNameN = json['MiddleNameN']; + lastNameN = json['LastNameN']; + relationshipID = json['RelationshipID']; + gender = json['Gender']; + dateofBirth = json['DateofBirth']; + dateofBirthN = json['DateofBirthN']; + nationalityID = json['NationalityID']; + phoneResi = json['PhoneResi']; + phoneOffice = json['PhoneOffice']; + mobileNumber = json['MobileNumber']; + faxNumber = json['FaxNumber']; + emailAddress = json['EmailAddress']; + bloodGroup = json['BloodGroup']; + rHFactor = json['RHFactor']; + isEmailAlertRequired = json['IsEmailAlertRequired']; + isSMSAlertRequired = json['IsSMSAlertRequired']; + preferredLanguage = json['PreferredLanguage']; + isPrivilegedMember = json['IsPrivilegedMember']; + memberID = json['MemberID']; + expiryDate = json['ExpiryDate']; + isHmgEmployee = json['IsHmgEmployee']; + employeeID = json['EmployeeID']; + emergencyContactName = json['EmergencyContactName']; + emergencyContactNo = json['EmergencyContactNo']; + patientPayType = json['PatientPayType']; + dHCCPatientRefID = json['DHCCPatientRefID']; + isPatientDummy = json['IsPatientDummy']; + status = json['Status']; + isStatusCleared = json['IsStatusCleared']; + patientIdentificationType = json['PatientIdentificationType']; + patientIdentificationNo = json['PatientIdentificationNo']; + projectID = json['ProjectID']; + infoSourceID = json['InfoSourceID']; + address = json['Address']; + age = json['Age']; + ageDesc = json['AgeDesc']; + areaID = json['AreaID']; + createdBy = json['CreatedBy']; + genderDescription = json['GenderDescription']; + iR = json['IR']; + iSOCityID = json['ISOCityID']; + iSOCountryID = json['ISOCountryID']; + if (json['ListPrivilege'] != null) { + listPrivilege = new List(); + json['ListPrivilege'].forEach((v) { + listPrivilege.add(new ListPrivilege.fromJson(v)); + }); + } + marital = json['Marital']; + outSA = json['OutSA']; + pOBox = json['POBox']; + receiveHealthSummaryReport = json['ReceiveHealthSummaryReport']; + sourceType = json['SourceType']; + strDateofBirth = json['StrDateofBirth']; + tempAddress = json['TempAddress']; + zipCode = json['ZipCode']; + } + + Map toJson() { + final Map data = new Map(); + data['SetupID'] = this.setupID; + data['PatientType'] = this.patientType; + data['PatientID'] = this.patientID; + data['FirstName'] = this.firstName; + data['MiddleName'] = this.middleName; + data['LastName'] = this.lastName; + data['FirstNameN'] = this.firstNameN; + data['MiddleNameN'] = this.middleNameN; + data['LastNameN'] = this.lastNameN; + data['RelationshipID'] = this.relationshipID; + data['Gender'] = this.gender; + data['DateofBirth'] = this.dateofBirth; + data['DateofBirthN'] = this.dateofBirthN; + data['NationalityID'] = this.nationalityID; + data['PhoneResi'] = this.phoneResi; + data['PhoneOffice'] = this.phoneOffice; + data['MobileNumber'] = this.mobileNumber; + data['FaxNumber'] = this.faxNumber; + data['EmailAddress'] = this.emailAddress; + data['BloodGroup'] = this.bloodGroup; + data['RHFactor'] = this.rHFactor; + data['IsEmailAlertRequired'] = this.isEmailAlertRequired; + data['IsSMSAlertRequired'] = this.isSMSAlertRequired; + data['PreferredLanguage'] = this.preferredLanguage; + data['IsPrivilegedMember'] = this.isPrivilegedMember; + data['MemberID'] = this.memberID; + data['ExpiryDate'] = this.expiryDate; + data['IsHmgEmployee'] = this.isHmgEmployee; + data['EmployeeID'] = this.employeeID; + data['EmergencyContactName'] = this.emergencyContactName; + data['EmergencyContactNo'] = this.emergencyContactNo; + data['PatientPayType'] = this.patientPayType; + data['DHCCPatientRefID'] = this.dHCCPatientRefID; + data['IsPatientDummy'] = this.isPatientDummy; + data['Status'] = this.status; + data['IsStatusCleared'] = this.isStatusCleared; + data['PatientIdentificationType'] = this.patientIdentificationType; + data['PatientIdentificationNo'] = this.patientIdentificationNo; + data['ProjectID'] = this.projectID; + data['InfoSourceID'] = this.infoSourceID; + data['Address'] = this.address; + data['Age'] = this.age; + data['AgeDesc'] = this.ageDesc; + data['AreaID'] = this.areaID; + data['CreatedBy'] = this.createdBy; + data['GenderDescription'] = this.genderDescription; + data['IR'] = this.iR; + data['ISOCityID'] = this.iSOCityID; + data['ISOCountryID'] = this.iSOCountryID; + if (this.listPrivilege != null) { + data['ListPrivilege'] = + this.listPrivilege.map((v) => v.toJson()).toList(); + } + data['Marital'] = this.marital; + data['OutSA'] = this.outSA; + data['POBox'] = this.pOBox; + data['ReceiveHealthSummaryReport'] = this.receiveHealthSummaryReport; + data['SourceType'] = this.sourceType; + data['StrDateofBirth'] = this.strDateofBirth; + data['TempAddress'] = this.tempAddress; + data['ZipCode'] = this.zipCode; + + return data; + } +} + +class ListPrivilege { + int iD; + String serviceName; + bool previlege; + dynamic region; + + ListPrivilege({this.iD, this.serviceName, this.previlege, this.region}); + + ListPrivilege.fromJson(Map json) { + iD = json['ID']; + serviceName = json['ServiceName']; + previlege = json['Previlege']; + region = json['Region']; + } + + Map toJson() { + final Map data = new Map(); + data['ID'] = this.iD; + data['ServiceName'] = this.serviceName; + data['Previlege'] = this.previlege; + data['Region'] = this.region; + return data; + } +} diff --git a/lib/core/service/authentication_service.dart b/lib/core/service/authentication_service.dart new file mode 100644 index 0000000..ae26b38 --- /dev/null +++ b/lib/core/service/authentication_service.dart @@ -0,0 +1,29 @@ + +import 'package:driverapp/core/service/base_service.dart'; +import 'package:flutter/cupertino.dart'; + + +class AuthenticationService extends BaseService { + String selectedClinicName; + bool isLogin = false; + bool isLoading = true; + + AuthenticationService() { +// getUserAuthentication(); + } + +// void getUserAuthentication() async { +// if (profile != null) { +//// doctorProfile = new DoctorProfileModel.fromJson(profile); +// isLoading = false; +// isLogin = true; +// } else { +// isLoading = false; +// isLogin = false; +// } +// notifyListeners(); +// } + + + +} diff --git a/lib/core/service/base_service.dart b/lib/core/service/base_service.dart index 828420c..33ce779 100644 --- a/lib/core/service/base_service.dart +++ b/lib/core/service/base_service.dart @@ -1,9 +1,26 @@ +import 'package:driverapp/config/shared_pref_kay.dart'; +import 'package:driverapp/core/model/authentication/authenticated_user.dart'; +import 'package:driverapp/uitl/app_shared_preferences.dart'; import 'client/base_app_client.dart'; -class BaseService{ +class BaseService { String error; bool hasError = false; BaseAppClient baseAppClient = BaseAppClient(); + AuthenticatedUser user; + AppSharedPreferences sharedPref = AppSharedPreferences(); + + BaseService() { + getUser(); + } + + getUser() async { + var userProfile = await sharedPref.getObject(USER_PROFILE); + if (userProfile != null) { + user = + AuthenticatedUser.fromJson(await sharedPref.getObject(USER_PROFILE)); + } + } } \ No newline at end of file diff --git a/lib/core/viewModels/authentication_view_model.dart b/lib/core/viewModels/authentication_view_model.dart new file mode 100644 index 0000000..53aed7b --- /dev/null +++ b/lib/core/viewModels/authentication_view_model.dart @@ -0,0 +1,30 @@ +import 'package:driverapp/core/enum/viewstate.dart'; +import 'package:driverapp/core/service/authentication_service.dart'; +import 'package:driverapp/core/viewModels/base_view_model.dart'; + +import '../../locator.dart'; + +enum APP_STATUS { LOADING, UNAUTHENTICATED, AUTHENTICATED } + +class AuthenticationViewModel extends BaseViewModel { + AuthenticationService _authenticationService = locator(); + + APP_STATUS get status { + if (state == ViewState.Busy || state == ViewState.BusyLocal) { + return APP_STATUS.LOADING; + } else { + if (user != null) { + return APP_STATUS.AUTHENTICATED; + } else { + return APP_STATUS.UNAUTHENTICATED; + } + } + } + + login({String userName,String password}){ + setState(ViewState.BusyLocal); + // call api +// if() +// setState(viewState) + } +} diff --git a/lib/core/viewModels/base_view_model.dart b/lib/core/viewModels/base_view_model.dart index f48bc1b..2af07b6 100644 --- a/lib/core/viewModels/base_view_model.dart +++ b/lib/core/viewModels/base_view_model.dart @@ -1,4 +1,7 @@ +import 'package:driverapp/config/shared_pref_kay.dart'; import 'package:driverapp/core/enum/viewstate.dart'; +import 'package:driverapp/core/model/authentication/authenticated_user.dart'; +import 'package:driverapp/uitl/app_shared_preferences.dart'; import 'package:flutter/material.dart'; class BaseViewModel extends ChangeNotifier { @@ -6,8 +9,21 @@ class BaseViewModel extends ChangeNotifier { bool isInternetConnection = true; ViewState get state => _state; - + AuthenticatedUser user; String error = ""; + AppSharedPreferences sharedPref = AppSharedPreferences(); + + BaseViewModel(){ + getUser(); + } + + getUser() async { + var userProfile = await sharedPref.getObject(USER_PROFILE); + if (userProfile != null) { + user = + AuthenticatedUser.fromJson(await sharedPref.getObject(USER_PROFILE)); + } + } //TODO load user details from SP diff --git a/lib/locator.dart b/lib/locator.dart index 3d44f4c..b7f1052 100644 --- a/lib/locator.dart +++ b/lib/locator.dart @@ -1,6 +1,8 @@ import 'package:get_it/get_it.dart'; +import 'core/service/authentication_service.dart'; import 'core/service/hospital_service.dart'; +import 'core/viewModels/authentication_view_model.dart'; import 'core/viewModels/hospital_view_model.dart'; GetIt locator = GetIt.instance; @@ -9,7 +11,9 @@ GetIt locator = GetIt.instance; void setupLocator() { /// Services locator.registerLazySingleton(() => HospitalService()); + locator.registerLazySingleton(() => AuthenticationService()); /// View Model locator.registerFactory(() => HospitalViewModel()); + locator.registerFactory(() => AuthenticationViewModel()); } diff --git a/lib/main.dart b/lib/main.dart index 930ca7d..c93225c 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,9 +1,11 @@ +import 'package:driverapp/root_page.dart'; import 'package:driverapp/uitl/translations_delegate_base.dart'; import 'package:flutter/material.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:provider/provider.dart'; import 'config/size_config.dart'; +import 'core/service/authentication_service.dart'; import 'core/viewModels/project_view_model.dart'; import 'locator.dart'; import 'pages/landing/landing_page.dart'; @@ -25,7 +27,7 @@ class MyApp extends StatelessWidget { providers: [ ChangeNotifierProvider( create: (context) => ProjectViewModel(), - ), + ) ], child: Consumer( builder: (context, projectProvider, child) => MaterialApp( @@ -51,6 +53,7 @@ class MyApp extends StatelessWidget { TargetPlatform.iOS: CupertinoPageTransitionsBuilder(), }, ), + scaffoldBackgroundColor:Color.fromRGBO(239, 245, 245, 1) , hintColor: Colors.grey[400], disabledColor: Colors.grey[300], errorColor: Color.fromRGBO(235, 80, 60, 1.0), @@ -73,7 +76,7 @@ class MyApp extends StatelessWidget { ), ), initialRoute: '/', - routes: {'/': (context) => LandingPage()}, + routes: {'/': (context) => RootPage()}, debugShowCheckedModeBanner: false, ), ), diff --git a/lib/pages/authentication/login_page.dart b/lib/pages/authentication/login_page.dart new file mode 100644 index 0000000..0f860e7 --- /dev/null +++ b/lib/pages/authentication/login_page.dart @@ -0,0 +1,85 @@ +import 'package:driverapp/app-icons/driver_app_icons.dart'; +import 'package:driverapp/core/viewModels/authentication_view_model.dart'; +import 'package:driverapp/pages/base/base_view.dart'; +import 'package:driverapp/widgets/buttons/secondary_button.dart'; +import 'package:driverapp/widgets/others/app_scaffold_widget.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class LoginPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return AnimatedSwitcher( + duration: Duration(microseconds: 350), + child: BaseView( + builder: (_, model, widget) => AppScaffold( + baseViewModel: model, + body: Center( + child: Column( + + children: [ + FractionallySizedBox( + widthFactor: 0.9, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(DriverApp.logo, + size: 60, + color: Colors.red,), + ], + ), + Column(), + new Container( + height: 22.28, + width: 139.13, + decoration: BoxDecoration( + color: Color(0xffffffff), + border: Border.all( + width: 1.00, + color: Color(0xff707070), + ), + borderRadius: BorderRadius.circular(6.00), + ), + ), + Container( + height: 22.28, + width: 139.13, + decoration: BoxDecoration( + color: Color(0xffffffff), + border: Border.all( + width: 1.00, + color: Color(0xff707070), + ), + borderRadius: BorderRadius.circular(6.00), + ), + ), + new Container( + height: 22.28, + width: 139.13, + decoration: BoxDecoration( + color: Color(0xffffffff), + border: Border.all( + width: 1.00, + color: Color(0xff707070), + ), + borderRadius: BorderRadius.circular(6.00), + ), + ) + ], + ), + ), + FractionallySizedBox( + widthFactor: 0.90, + child: SecondaryButton(label: "DFDf"), + ) + ], + ), + ), + ), + ), + ); + } +} diff --git a/lib/root_page.dart b/lib/root_page.dart new file mode 100644 index 0000000..6e3125e --- /dev/null +++ b/lib/root_page.dart @@ -0,0 +1,36 @@ +import 'package:driverapp/pages/authentication/login_page.dart'; +import 'package:driverapp/pages/base/base_view.dart'; +import 'package:driverapp/pages/landing/landing_page.dart'; +import 'package:driverapp/widgets/others/app_scaffold_widget.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'core/viewModels/authentication_view_model.dart'; + +class RootPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + Widget buildRoot(APP_STATUS status) { + switch (status) { + case APP_STATUS.UNAUTHENTICATED: + return LoginPage(); + break; + case APP_STATUS.AUTHENTICATED: + return LandingPage(); + break; + } + } + + return AnimatedSwitcher( + duration: Duration(microseconds: 350), + child: BaseView( + builder: (_, model, widget) => AppScaffold( + baseViewModel: model, + body: buildRoot((model.status)), + ), + ), + ); + } +} + + diff --git a/lib/widgets/buttons/secondary_button.dart b/lib/widgets/buttons/secondary_button.dart index a63f027..dc88f3d 100644 --- a/lib/widgets/buttons/secondary_button.dart +++ b/lib/widgets/buttons/secondary_button.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:hexcolor/hexcolor.dart'; /// SecondaryButton widget /// [label] button label @@ -87,6 +88,7 @@ class _SecondaryButtonState extends State _rippleSize = _rippleAnimation.value; }); }); + super.initState(); } @@ -160,17 +162,22 @@ class _SecondaryButtonState extends State child: ClipRRect( borderRadius: widget.noBorderRadius ? BorderRadius.all(Radius.circular(0.0)) - : BorderRadius.all(Radius.circular(10.0)), + : BorderRadius.all(Radius.circular(40.0)), child: Stack( children: [ Positioned( left: 0, bottom: 0, child: Container( - width: MediaQuery.of(context).size.width, + width: MediaQuery + .of(context) + .size + .width, height: 100, decoration: BoxDecoration( - color: Theme.of(context).disabledColor, + color: Theme + .of(context) + .disabledColor, ), ), ), @@ -184,7 +191,8 @@ class _SecondaryButtonState extends State height: MediaQuery.of(context).size.width * 2.2, decoration: BoxDecoration( shape: BoxShape.circle, - color: widget.color, + color: widget.color != null ? widget.color : Hexcolor( + "#1CA4AA"), ), ), ), @@ -193,8 +201,8 @@ class _SecondaryButtonState extends State padding: widget.iconOnly ? EdgeInsets.symmetric(vertical: 4.0, horizontal: 5.0) : EdgeInsets.only( - top: widget.small ? 8.0 : 14.0, - bottom: widget.small ? 6.0 : 14.0, + top: widget.small ? 8.0 : 12.0, + bottom: widget.small ? 6.0 : 12.0, left: 18.0, right: 18.0), child: Stack( @@ -223,12 +231,13 @@ class _SecondaryButtonState extends State ) : Padding( padding: EdgeInsets.only( - bottom: widget.small ? 4.0 : 3.0), + bottom: widget.small ? 4.0 : 2.0), child: Text(widget.label, style: TextStyle( - color: widget.textColor, + color: widget.textColor != null + ? widget.textColor + : Colors.white, fontSize: 17.0, - fontWeight: FontWeight.w800, fontFamily: "WorkSans")), ) ], diff --git a/lib/widgets/others/app_scaffold_widget.dart b/lib/widgets/others/app_scaffold_widget.dart index d5e9c51..3005588 100644 --- a/lib/widgets/others/app_scaffold_widget.dart +++ b/lib/widgets/others/app_scaffold_widget.dart @@ -24,40 +24,42 @@ class AppScaffold extends StatelessWidget { @override Widget build(BuildContext context) { AppGlobal.context = context; - return Scaffold( - backgroundColor: Theme.of(context).scaffoldBackgroundColor, - appBar: isShowAppBar - ? AppBar( - elevation: 0, - backgroundColor: Theme.of(context).appBarTheme.color, - textTheme: TextTheme( - headline6: - TextStyle(color: Colors.white, fontWeight: FontWeight.bold), - ), - title: Text(appBarTitle.toUpperCase()), - leading: Builder( - builder: (BuildContext context) { - return ArrowBack(); - }, - ), - centerTitle: true, - actions: [ - IconButton( - icon: Icon(FontAwesomeIcons.home), - color: Colors.white, - onPressed: () { - // TODO add navigator to home page + return SafeArea( + child: Scaffold( + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + appBar: isShowAppBar + ? AppBar( + elevation: 0, + backgroundColor: Theme.of(context).appBarTheme.color, + textTheme: TextTheme( + headline6: + TextStyle(color: Colors.white, fontWeight: FontWeight.bold), + ), + title: Text(appBarTitle.toUpperCase()), + leading: Builder( + builder: (BuildContext context) { + return ArrowBack(); }, ), - ], - ) - : null, - body: baseViewModel != null - ? NetworkBaseView( - child: buildBodyWidget(), - baseViewModel: baseViewModel, - ) - : buildBodyWidget(), + centerTitle: true, + actions: [ + IconButton( + icon: Icon(FontAwesomeIcons.home), + color: Colors.white, + onPressed: () { + // TODO add navigator to home page + }, + ), + ], + ) + : null, + body: baseViewModel != null + ? NetworkBaseView( + child: buildBodyWidget(), + baseViewModel: baseViewModel, + ) + : buildBodyWidget(), + ), ); } diff --git a/lib/widgets/others/network_base_view.dart b/lib/widgets/others/network_base_view.dart index 5776e84..fe409bc 100644 --- a/lib/widgets/others/network_base_view.dart +++ b/lib/widgets/others/network_base_view.dart @@ -20,6 +20,8 @@ class NetworkBaseView extends StatelessWidget { buildBaseViewWidget() { switch (baseViewModel.state) { case ViewState.Idle: + case ViewState.BusyLocal: + case ViewState.ErrorLocal: return child; break; case ViewState.Busy: @@ -31,7 +33,6 @@ class NetworkBaseView extends StatelessWidget { error: baseViewModel.error, ), ); - break; } } } diff --git a/pubspec.yaml b/pubspec.yaml index fefcf54..358a44e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -92,3 +92,7 @@ flutter: - asset: assets/fonts/Work_Sans/WorkSans-Bold.ttf - asset: assets/fonts/Work_Sans/WorkSans-Bold.ttf weight: 700 + + - family: DriverApp + fonts: + - asset: lib/app-icons/fonts/DriverApp.ttf From 8a8dd6457dfefc57aa60b7c9345198a064bcf9be Mon Sep 17 00:00:00 2001 From: Elham Rababah Date: Wed, 19 Aug 2020 12:08:16 +0300 Subject: [PATCH 2/4] Finish login page --- lib/main.dart | 10 +- lib/pages/authentication/login_page.dart | 212 +++++++++++---- lib/widgets/input/text_field.dart | 331 +++++++++++++---------- 3 files changed, 364 insertions(+), 189 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index c93225c..9626777 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -5,10 +5,10 @@ import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:provider/provider.dart'; import 'config/size_config.dart'; -import 'core/service/authentication_service.dart'; import 'core/viewModels/project_view_model.dart'; import 'locator.dart'; -import 'pages/landing/landing_page.dart'; + + void main() { setupLocator(); @@ -56,6 +56,9 @@ class MyApp extends StatelessWidget { scaffoldBackgroundColor:Color.fromRGBO(239, 245, 245, 1) , hintColor: Colors.grey[400], disabledColor: Colors.grey[300], + bottomSheetTheme: BottomSheetThemeData( + backgroundColor: Color.fromRGBO(239, 245, 245, 1) + ), errorColor: Color.fromRGBO(235, 80, 60, 1.0), textSelectionColor: Color.fromRGBO(80, 100, 253, 0.5), textSelectionHandleColor: Color.fromRGBO(80, 100, 253, 1.0), @@ -63,9 +66,10 @@ class MyApp extends StatelessWidget { backgroundColor: Color.fromRGBO(255, 255, 255, 1), highlightColor: Colors.grey[100].withOpacity(0.4), splashColor: Colors.transparent, - primaryColor: Colors.grey, + primaryColor: Color.fromRGBO(69, 183, 174, 1.0), cursorColor: Color.fromRGBO(78, 62, 253, 1.0), iconTheme: IconThemeData(), + dividerColor: Color.fromRGBO(112, 112, 112, 1.0), appBarTheme: AppBarTheme( color: Colors.grey, brightness: Brightness.light, diff --git a/lib/pages/authentication/login_page.dart b/lib/pages/authentication/login_page.dart index 0f860e7..f5dd638 100644 --- a/lib/pages/authentication/login_page.dart +++ b/lib/pages/authentication/login_page.dart @@ -2,9 +2,11 @@ import 'package:driverapp/app-icons/driver_app_icons.dart'; import 'package:driverapp/core/viewModels/authentication_view_model.dart'; import 'package:driverapp/pages/base/base_view.dart'; import 'package:driverapp/widgets/buttons/secondary_button.dart'; -import 'package:driverapp/widgets/others/app_scaffold_widget.dart'; +import 'package:driverapp/widgets/input/text_field.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; +import 'package:hexcolor/hexcolor.dart'; class LoginPage extends StatelessWidget { @override @@ -12,74 +14,192 @@ class LoginPage extends StatelessWidget { return AnimatedSwitcher( duration: Duration(microseconds: 350), child: BaseView( - builder: (_, model, widget) => AppScaffold( - baseViewModel: model, + builder: (_, model, widget) => Scaffold( + //baseViewModel: model, body: Center( child: Column( - + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ FractionallySizedBox( - widthFactor: 0.9, + widthFactor: 0.80, child: Column( - crossAxisAlignment: CrossAxisAlignment.center, children: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, + SizedBox( + height: 40, + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - Icon(DriverApp.logo, - size: 60, - color: Colors.red,), + Container( + child: Icon( + DriverApp.logo, + size: 70, + color: Theme.of(context).primaryColor, + ), + margin: EdgeInsets.only( + right: + MediaQuery.of(context).size.width * 0.15), + ), ], ), - Column(), - new Container( - height: 22.28, - width: 139.13, - decoration: BoxDecoration( - color: Color(0xffffffff), - border: Border.all( - width: 1.00, - color: Color(0xff707070), + SizedBox( + height: 20, + ), + Column( + children: [ + Text( + "Driver", + style: TextStyle( + fontSize: 50, fontWeight: FontWeight.bold), + ), + Text( + "Delivery", + style: TextStyle(fontSize: 36, letterSpacing: 1), + ), + Text( + "APP", + style: TextStyle( + fontSize: 33, + letterSpacing: 33, + fontWeight: FontWeight.w400), ), - borderRadius: BorderRadius.circular(6.00), - ), + ], + ), + SizedBox( + height: 30, ), - Container( - height: 22.28, - width: 139.13, - decoration: BoxDecoration( - color: Color(0xffffffff), - border: Border.all( - width: 1.00, - color: Color(0xff707070), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + CircleContainer( + child: Text( + "English", + style: TextStyle( + fontSize: 12, color: Colors.white), + ), + color: Theme.of(context).primaryColor, borderWidth: 0,borderColor: Colors.transparent,), + SizedBox( + width: 20, ), - borderRadius: BorderRadius.circular(6.00), - ), + CircleContainer( + child: Text( + "Arabic", + style: TextStyle( + fontSize: 12, color: Colors.black), + ), + color: Colors.transparent, borderColor: Theme.of(context).primaryColor,borderWidth: 3,), + ], + ), + SizedBox( + height: 10, ), - new Container( - height: 22.28, - width: 139.13, - decoration: BoxDecoration( - color: Color(0xffffffff), - border: Border.all( - width: 1.00, - color: Color(0xff707070), + Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Text( + "Please insert username and password to login", + style: TextStyle( + fontSize: 13, color: Colors.grey), + ), + SizedBox( + height: 10, + ) + ], + ), + ), + SizedBox( + height: 10, ), - borderRadius: BorderRadius.circular(6.00), - ), - ) + Container( + child: TextFields( + onChanged: (value) => {}, + hintText: "User Name", + ), + ), + SizedBox( + height: 20, + ), + Container( + child: TextFields( + borderRadiusValue: 6, + onChanged: (value) => {}, + hintText: "Password", + ), + ), + SizedBox( + height: 25, + ), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Text( + "Forgot Password?", + style: TextStyle( + fontSize: 14, + color: Theme.of(context).primaryColor), + ), + ], + ), + ], + ), ], ), ), - FractionallySizedBox( - widthFactor: 0.90, - child: SecondaryButton(label: "DFDf"), + SizedBox( + height: 20, + ), + SizedBox( + height: 10, ) ], ), ), + bottomSheet: Container( + margin: EdgeInsets.all(10), + height: MediaQuery.of(context).size.height * 0.12, + child: Column( + children: [ + SecondaryButton(label: "Login"), + SizedBox( + height: 30, + ) + ], + )), ), ), ); } } + +class CircleContainer extends StatelessWidget { + const CircleContainer( + {this.child, + this.color = Colors.white, + this.borderColor, + this.borderWidth = 2.0}); + + final Widget child; + final Color color; + final Color borderColor; + final double borderWidth; + + @override + Widget build(BuildContext context) { + return Container( + child: Center(child: child), + decoration: BoxDecoration( + shape: BoxShape.circle, + color: color, + border: Border.all( + color: borderColor ?? Hexcolor("#707070"), + width: borderWidth)), + height: 60, + width: 60, + ); + } +} diff --git a/lib/widgets/input/text_field.dart b/lib/widgets/input/text_field.dart index 900c340..12b0adc 100644 --- a/lib/widgets/input/text_field.dart +++ b/lib/widgets/input/text_field.dart @@ -39,38 +39,44 @@ class NumberTextInputFormatter extends TextInputFormatter { final _mobileFormatter = NumberTextInputFormatter(); class TextFields extends StatefulWidget { - TextFields( - {Key key, - this.type, - this.hintText, - this.suffixIcon, - this.autoFocus, - this.onChanged, - this.initialValue, - this.minLines, - this.maxLines, - this.inputFormatters, - this.padding, - this.focus = false, - this.maxLengthEnforced = true, - this.suffixIconColor, - this.inputAction, - this.onSubmit, - this.keepPadding = true, - this.textCapitalization = TextCapitalization.none, - this.controller, - this.keyboardType, - this.validator, - this.borderOnlyError = false, - this.onSaved, - this.onSuffixTap, - this.readOnly: false, - this.maxLength, - this.prefixIcon, - this.bare = false, - this.fontSize = 16.0, - this.fontWeight = FontWeight.w700, - this.autoValidate = false}) + TextFields({Key key, + this.type, + this.hintText, + this.suffixIcon, + this.autoFocus, + this.onChanged, + this.initialValue, + this.minLines, + this.maxLines, + this.inputFormatters, + this.padding, + this.focus = false, + this.maxLengthEnforced = true, + this.suffixIconColor, + this.inputAction, + this.onSubmit, + this.keepPadding = true, + this.textCapitalization = TextCapitalization.none, + this.onTap, + this.controller, + this.keyboardType, + this.validator, + this.borderOnlyError = false, + this.onSaved, + this.onSuffixTap, + this.readOnly: false, + this.maxLength, + this.prefixIcon, + this.bare = false, + this.fontSize = 14.0, + this.color = Colors.black, + this.fontWeight = FontWeight.w600, + this.autoValidate = false, + this.borderRadiusValue = 8.0, + this.borderWidth = 1.5, + this.fieldTextColor, + this.textAlign = TextAlign.start, + this.borderRadius}) : super(key: key); final String hintText; @@ -80,6 +86,7 @@ class TextFields extends StatefulWidget { final IconData suffixIcon; final Color suffixIconColor; final IconData prefixIcon; + final VoidCallback onTap; final TextEditingController controller; final TextInputType keyboardType; final FormFieldValidator validator; @@ -96,6 +103,7 @@ class TextFields extends StatefulWidget { final TextInputAction inputAction; final double fontSize; final FontWeight fontWeight; + final Color color; final bool keepPadding; final TextCapitalization textCapitalization; final List inputFormatters; @@ -103,6 +111,11 @@ class TextFields extends StatefulWidget { final EdgeInsets padding; final bool focus; final bool borderOnlyError; + final double borderRadiusValue; + final BorderRadius borderRadius; + final double borderWidth; + final Color fieldTextColor; + final TextAlign textAlign; @override _TextFieldsState createState() => _TextFieldsState(); @@ -138,43 +151,46 @@ class _TextFieldsState extends State { Widget _buildSuffixIcon() { switch (widget.type) { case "password": - return Padding( - padding: const EdgeInsets.only(right: 8.0), - child: view - ? InkWell( + { + return Padding( + padding: const EdgeInsets.only(right: 8.0), + child: view + ? InkWell( onTap: () { - this.setState( - () { - view = false; - }, - ); + this.setState(() { + view = false; + }); }, - child: Icon( - EvaIcons.eye, - size: 24.0, - color: Color.fromRGBO(78, 62, 253, 1.0), - ), - ) - : InkWell( + child: Icon(EvaIcons.eye, + size: 24.0, color: Theme + .of(context) + .primaryColor)) + : InkWell( onTap: () { this.setState(() { view = true; }); }, child: Icon(EvaIcons.eyeOff, - size: 24.0, color: Colors.grey[500]), - ), - ); + size: 24.0, color: Colors.grey[500]))); + } + case "hourly": + return Align( + alignment: Alignment.centerRight, + child: Text( + '/ hr ', + style: TextStyle(fontSize: 18, fontWeight: FontWeight.w700), + )); + break; default: if (widget.suffixIcon != null) return InkWell( - onTap: widget.onSuffixTap, - child: Icon(widget.suffixIcon, - size: 22.0, - color: widget.suffixIconColor != null - ? widget.suffixIconColor - : Colors.grey[500]), - ); + onTap: widget.onSuffixTap, + child: Icon(widget.suffixIcon, + size: 22.0, + color: widget.suffixIconColor != null + ? widget.suffixIconColor + : Colors.grey[500])); else return null; } @@ -196,22 +212,26 @@ class _TextFieldsState extends State { decoration: widget.bare ? null : BoxDecoration(boxShadow: [ - BoxShadow( - color: Color.fromRGBO(110, 68, 80, focus ? 0.20 : 0), - offset: Offset(0.0, 13.0), - blurRadius: focus ? 34.0 : 12.0) - ]), + BoxShadow( + color: Color.fromRGBO(70, 68, 167, focus ? 0.20 : 0), + offset: Offset(0.0, 13.0), + blurRadius: focus ? 34.0 : 12.0) + ]), child: TextFormField( - keyboardAppearance: Theme.of(context).brightness, + keyboardAppearance: Theme + .of(context) + .brightness, scrollPhysics: BouncingScrollPhysics(), autovalidate: widget.autoValidate, + onTap: widget.onTap, + textAlign: widget.textAlign, textCapitalization: widget.textCapitalization, onFieldSubmitted: widget.inputAction == TextInputAction.next ? (widget.onSubmit != null - ? widget.onSubmit - : (val) { - _focusNode.nextFocus(); - }) + ? widget.onSubmit + : (val) { + _focusNode.nextFocus(); + }) : widget.onSubmit, textInputAction: widget.inputAction, minLines: widget.minLines ?? 1, @@ -228,87 +248,118 @@ class _TextFieldsState extends State { autofocus: widget.autoFocus ?? false, validator: widget.validator, onSaved: widget.onSaved, - style: Theme.of(context) + style: Theme + .of(context) .textTheme .body2 - .copyWith(fontSize: widget.fontSize, fontWeight: widget.fontWeight), + .copyWith( + fontSize: widget.fontSize, + fontWeight: widget.fontWeight, + color: widget.color), inputFormatters: widget.keyboardType == TextInputType.phone ? [ - WhitelistingTextInputFormatter.digitsOnly, - _mobileFormatter, - ] + WhitelistingTextInputFormatter.digitsOnly, + _mobileFormatter, + ] : widget.inputFormatters, decoration: InputDecoration( - counterText: "", - hintText: widget.hintText, - hintStyle: TextStyle( - fontSize: widget.fontSize, - fontWeight: widget.fontWeight, - color: Theme.of(context).hintColor), - contentPadding: widget.padding != null - ? widget.padding - : EdgeInsets.symmetric( - vertical: (widget.bare && !widget.keepPadding) ? 0.0 : 10.0, - horizontal: 16.0), - filled: true, - fillColor: widget.bare - ? Colors.transparent - : Theme.of(context).backgroundColor, - suffixIcon: _buildSuffixIcon(), - prefixIcon: widget.type != "search" - ? widget.prefixIcon != null - ? Padding( - padding: EdgeInsets.only( - left: 28.0, top: 14.0, bottom: 14.0, right: 0), - child: Text( - "\$", - style: TextStyle( - fontSize: 14, fontWeight: FontWeight.w800), - ), - ) - : null - : Icon(EvaIcons.search, size: 20.0, color: Colors.grey[500]), - errorStyle: TextStyle( - fontSize: 14.0, - fontWeight: widget.fontWeight, - height: widget.borderOnlyError ? 0.0 : null), - errorBorder: OutlineInputBorder( - borderSide: BorderSide( - color: Theme.of(context) - .errorColor - .withOpacity(widget.bare ? 0.0 : 0.5), - width: 2.0), - borderRadius: BorderRadius.circular(widget.bare ? 0.0 : 8.0)), - focusedErrorBorder: OutlineInputBorder( - borderSide: BorderSide( - color: Theme.of(context) - .errorColor - .withOpacity(widget.bare ? 0.0 : 0.5), - width: 2.0), - borderRadius: BorderRadius.circular(widget.bare ? 0.0 : 8.0)), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color: Theme.of(context) - .dividerColor - .withOpacity(widget.bare ? 0.0 : 1.0), - width: 2.0), - borderRadius: BorderRadius.circular(widget.bare ? 0.0 : 8.0)), - disabledBorder: OutlineInputBorder( + counterText: "", + hintText: widget.hintText, + hintStyle: TextStyle( + fontSize: widget.fontSize, + fontWeight: widget.fontWeight, + color: Theme + .of(context) + .hintColor), + contentPadding: widget.padding != null + ? widget.padding + : EdgeInsets.symmetric( + vertical: (widget.bare && !widget.keepPadding) ? 0.0 : 10.0, + horizontal: 16.0), + filled: true, + fillColor: widget.bare + ? Colors.transparent + : widget.fieldTextColor != null + ? widget.fieldTextColor + : Theme + .of(context) + .backgroundColor, + suffixIcon: _buildSuffixIcon(), + prefixIcon: widget.type != "search" + ? widget.prefixIcon != null + ? Padding( + padding: EdgeInsets.only( + left: 28.0, top: 14.0, bottom: 14.0, right: 0), + child: Text( + "\$", + style: TextStyle( + fontSize: 14, fontWeight: FontWeight.w800), + ), + ) + : null + : Icon(EvaIcons.search, size: 20.0, color: Colors.grey[500]), + errorStyle: TextStyle( + fontSize: 14.0, + fontWeight: widget.fontWeight, + height: widget.borderOnlyError ? 0.0 : null), + errorBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Theme + .of(context) + .errorColor + .withOpacity(widget.bare ? 0.0 : 0.5), + width: widget.borderWidth), + borderRadius: widget.bare + ? BorderRadius.circular(0.0) + : widget.borderRadius != null + ? widget.borderRadius + : BorderRadius.circular(widget.borderRadiusValue)), + focusedErrorBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Theme + .of(context) + .errorColor + .withOpacity(widget.bare ? 0.0 : 0.5), + width: widget.borderWidth), + borderRadius: widget.bare + ? BorderRadius.circular(0.0) + : widget.borderRadius != null + ? widget.borderRadius + : BorderRadius.circular(widget.borderRadiusValue)), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Theme + .of(context) + .dividerColor + .withOpacity(widget.bare ? 0.0 : 1.0), + width: widget.borderWidth), + borderRadius: widget.bare + ? BorderRadius.circular(0.0) + : widget.borderRadius != null + ? widget.borderRadius + : BorderRadius.circular(widget.borderRadiusValue)), + disabledBorder: + OutlineInputBorder(borderSide: BorderSide(color: Theme + .of(context) + .dividerColor + .withOpacity(widget.bare ? 0.0 : 1.0), + width: widget.borderWidth), + borderRadius: widget.bare ? BorderRadius.circular(0.0) : widget + .borderRadius != null ? widget.borderRadius : BorderRadius + .circular(widget.borderRadiusValue)), + enabledBorder: OutlineInputBorder( borderSide: BorderSide( - color: Theme.of(context) + color: Theme + .of(context) .dividerColor .withOpacity(widget.bare ? 0.0 : 1.0), - width: 2.0), - borderRadius: BorderRadius.circular(widget.bare ? 0.0 : 8.0)), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: Theme.of(context) - .dividerColor - .withOpacity(widget.bare ? 0.0 : 1.0), - width: 2.0), - borderRadius: BorderRadius.circular(widget.bare ? 0.0 : 8.0), - ), - ), + width: widget.borderWidth), + borderRadius: widget.bare + ? BorderRadius.circular(0.0) + : widget.borderRadius != null + ? widget.borderRadius + : BorderRadius.circular(widget.borderRadiusValue), + )), ), )); } From 7e50545dd181637df6c3142e21ba61bfa71f4c91 Mon Sep 17 00:00:00 2001 From: Elham Rababah Date: Sun, 23 Aug 2020 15:17:39 +0300 Subject: [PATCH 3/4] Finish login Functionality --- lib/config/config.dart | 2 + lib/config/localized_values.dart | 24 +- .../authentication/authenticated_user.dart | 318 +++--------------- .../model/authentication/login_request.dart | 18 + lib/core/service/authentication_service.dart | 40 ++- .../viewModels/authentication_view_model.dart | 18 +- lib/pages/authentication/login_page.dart | 228 ++++++++----- lib/uitl/translations_delegate_base.dart | 13 + .../data_display/circle-container.dart | 34 ++ 9 files changed, 320 insertions(+), 375 deletions(-) create mode 100644 lib/core/model/authentication/login_request.dart create mode 100644 lib/widgets/data_display/circle-container.dart diff --git a/lib/config/config.dart b/lib/config/config.dart index e6ae40e..2e70bf9 100644 --- a/lib/config/config.dart +++ b/lib/config/config.dart @@ -6,6 +6,8 @@ const MAX_SMALL_SCREEN = 660; const BASE_URL = 'https://uat.hmgwebservices.com/Services'; const GET_PROJECT = '/Lists.svc/REST/GetProject'; +const LOGIN = "/Authentication.svc/REST/CheckDriverAuthentication"; + class AppGlobal { diff --git a/lib/config/localized_values.dart b/lib/config/localized_values.dart index 5916d90..5cfdfbe 100644 --- a/lib/config/localized_values.dart +++ b/lib/config/localized_values.dart @@ -11,6 +11,28 @@ const Map> localizedValues = { 'services': {'en': 'SERVICES', 'ar': 'الخدمات'}, 'mySchedule': {'en': 'My Schedule', 'ar': 'جدولي'}, 'logout': {'en': 'Logout', 'ar': 'تسجيل خروج'}, - 'booking':{'en': 'Booking','ar':'حجز'} + 'booking':{'en': 'Booking','ar':'حجز'}, + 'enterId': {'en': 'User Name', 'ar': 'اسم المستخدم'}, + 'pleaseEnterYourID': { + 'en': 'Please enter your ', + 'ar': 'الرجاء ادخال اسم المستخدم' + }, + 'enterPassword': {'en': 'Password', 'ar': 'كلمه السر'}, + 'pleaseEnterPassword': { + 'en': 'Please Enter Your Password', + 'ar': 'الرجاء ادخال كلمه السر' + }, + 'enterCredentialsMsg': { + 'en': 'Please insert username and password to login', + 'ar': 'الرجاء إدخال اسم المستخدم وكلمة المرور لتسجيل الدخول' + }, + 'forgotPassword': { + 'en': 'Forgot Password?', + 'ar': 'هل نسيت كلمة المرور ؟' + }, + 'login': { + 'en': 'Login', + 'ar': 'تسجيل الدخول' + } }; diff --git a/lib/core/model/authentication/authenticated_user.dart b/lib/core/model/authentication/authenticated_user.dart index 7ca3a3e..0329bd5 100644 --- a/lib/core/model/authentication/authenticated_user.dart +++ b/lib/core/model/authentication/authenticated_user.dart @@ -1,282 +1,64 @@ class AuthenticatedUser { - String setupID; - int patientType; - int patientID; - String firstName; - String middleName; - String lastName; - String firstNameN; - String middleNameN; - String lastNameN; - int relationshipID; - int gender; - String dateofBirth; - dynamic dateofBirthN; - String nationalityID; - dynamic phoneResi; - dynamic phoneOffice; - String mobileNumber; - dynamic faxNumber; - String emailAddress; - dynamic bloodGroup; - dynamic rHFactor; - bool isEmailAlertRequired; - bool isSMSAlertRequired; - String preferredLanguage; - bool isPrivilegedMember; - dynamic memberID; - dynamic expiryDate; - dynamic isHmgEmployee; - dynamic employeeID; - dynamic emergencyContactName; - dynamic emergencyContactNo; - int patientPayType; - dynamic dHCCPatientRefID; - bool isPatientDummy; - int status; - dynamic isStatusCleared; - int patientIdentificationType; - String patientIdentificationNo; - int projectID; - int infoSourceID; - dynamic address; - int age; - String ageDesc; - int areaID; + int iD; + int userID; + String password; + String userName; + int roleID; + String name; + bool active; + String createdOn; int createdBy; - String genderDescription; - dynamic iR; - dynamic iSOCityID; - dynamic iSOCountryID; - List listPrivilege; - dynamic marital; - int outSA; - dynamic pOBox; - bool receiveHealthSummaryReport; - int sourceType; - dynamic strDateofBirth; - dynamic tempAddress; - dynamic zipCode; - // dynamic patientPayType; - // dynamic patientType; - // dynamic status; + Null editedOn; + Null editedBy; + String mobileNumber; + int realRoleID; - AuthenticatedUser({ - this.setupID, - this.patientType, - this.patientID, - this.firstName, - this.middleName, - this.lastName, - this.firstNameN, - this.middleNameN, - this.lastNameN, - this.relationshipID, - this.gender, - this.dateofBirth, - this.dateofBirthN, - this.nationalityID, - this.phoneResi, - this.phoneOffice, - this.mobileNumber, - this.faxNumber, - this.emailAddress, - this.bloodGroup, - this.rHFactor, - this.isEmailAlertRequired, - this.isSMSAlertRequired, - this.preferredLanguage, - this.isPrivilegedMember, - this.memberID, - this.expiryDate, - this.isHmgEmployee, - this.employeeID, - this.emergencyContactName, - this.emergencyContactNo, - this.patientPayType, - this.dHCCPatientRefID, - this.isPatientDummy, - this.status, - this.isStatusCleared, - this.patientIdentificationType, - this.patientIdentificationNo, - this.projectID, - this.infoSourceID, - this.address, - this.age, - this.ageDesc, - this.areaID, - this.createdBy, - this.genderDescription, - this.iR, - this.iSOCityID, - this.iSOCountryID, - this.listPrivilege, - this.marital, - this.outSA, - this.pOBox, - this.receiveHealthSummaryReport, - this.sourceType, - this.strDateofBirth, - this.tempAddress, - this.zipCode, - }); + AuthenticatedUser( + {this.iD, + this.userID, + this.password, + this.userName, + this.roleID, + this.name, + this.active, + this.createdOn, + this.createdBy, + this.editedOn, + this.editedBy, + this.mobileNumber, + this.realRoleID}); AuthenticatedUser.fromJson(Map json) { - setupID = json['SetupID']; - patientType = json['PatientType']; - patientID = json['PatientID']; - firstName = json['FirstName']; - middleName = json['MiddleName']; - lastName = json['LastName']; - firstNameN = json['FirstNameN']; - middleNameN = json['MiddleNameN']; - lastNameN = json['LastNameN']; - relationshipID = json['RelationshipID']; - gender = json['Gender']; - dateofBirth = json['DateofBirth']; - dateofBirthN = json['DateofBirthN']; - nationalityID = json['NationalityID']; - phoneResi = json['PhoneResi']; - phoneOffice = json['PhoneOffice']; - mobileNumber = json['MobileNumber']; - faxNumber = json['FaxNumber']; - emailAddress = json['EmailAddress']; - bloodGroup = json['BloodGroup']; - rHFactor = json['RHFactor']; - isEmailAlertRequired = json['IsEmailAlertRequired']; - isSMSAlertRequired = json['IsSMSAlertRequired']; - preferredLanguage = json['PreferredLanguage']; - isPrivilegedMember = json['IsPrivilegedMember']; - memberID = json['MemberID']; - expiryDate = json['ExpiryDate']; - isHmgEmployee = json['IsHmgEmployee']; - employeeID = json['EmployeeID']; - emergencyContactName = json['EmergencyContactName']; - emergencyContactNo = json['EmergencyContactNo']; - patientPayType = json['PatientPayType']; - dHCCPatientRefID = json['DHCCPatientRefID']; - isPatientDummy = json['IsPatientDummy']; - status = json['Status']; - isStatusCleared = json['IsStatusCleared']; - patientIdentificationType = json['PatientIdentificationType']; - patientIdentificationNo = json['PatientIdentificationNo']; - projectID = json['ProjectID']; - infoSourceID = json['InfoSourceID']; - address = json['Address']; - age = json['Age']; - ageDesc = json['AgeDesc']; - areaID = json['AreaID']; - createdBy = json['CreatedBy']; - genderDescription = json['GenderDescription']; - iR = json['IR']; - iSOCityID = json['ISOCityID']; - iSOCountryID = json['ISOCountryID']; - if (json['ListPrivilege'] != null) { - listPrivilege = new List(); - json['ListPrivilege'].forEach((v) { - listPrivilege.add(new ListPrivilege.fromJson(v)); - }); - } - marital = json['Marital']; - outSA = json['OutSA']; - pOBox = json['POBox']; - receiveHealthSummaryReport = json['ReceiveHealthSummaryReport']; - sourceType = json['SourceType']; - strDateofBirth = json['StrDateofBirth']; - tempAddress = json['TempAddress']; - zipCode = json['ZipCode']; - } - - Map toJson() { - final Map data = new Map(); - data['SetupID'] = this.setupID; - data['PatientType'] = this.patientType; - data['PatientID'] = this.patientID; - data['FirstName'] = this.firstName; - data['MiddleName'] = this.middleName; - data['LastName'] = this.lastName; - data['FirstNameN'] = this.firstNameN; - data['MiddleNameN'] = this.middleNameN; - data['LastNameN'] = this.lastNameN; - data['RelationshipID'] = this.relationshipID; - data['Gender'] = this.gender; - data['DateofBirth'] = this.dateofBirth; - data['DateofBirthN'] = this.dateofBirthN; - data['NationalityID'] = this.nationalityID; - data['PhoneResi'] = this.phoneResi; - data['PhoneOffice'] = this.phoneOffice; - data['MobileNumber'] = this.mobileNumber; - data['FaxNumber'] = this.faxNumber; - data['EmailAddress'] = this.emailAddress; - data['BloodGroup'] = this.bloodGroup; - data['RHFactor'] = this.rHFactor; - data['IsEmailAlertRequired'] = this.isEmailAlertRequired; - data['IsSMSAlertRequired'] = this.isSMSAlertRequired; - data['PreferredLanguage'] = this.preferredLanguage; - data['IsPrivilegedMember'] = this.isPrivilegedMember; - data['MemberID'] = this.memberID; - data['ExpiryDate'] = this.expiryDate; - data['IsHmgEmployee'] = this.isHmgEmployee; - data['EmployeeID'] = this.employeeID; - data['EmergencyContactName'] = this.emergencyContactName; - data['EmergencyContactNo'] = this.emergencyContactNo; - data['PatientPayType'] = this.patientPayType; - data['DHCCPatientRefID'] = this.dHCCPatientRefID; - data['IsPatientDummy'] = this.isPatientDummy; - data['Status'] = this.status; - data['IsStatusCleared'] = this.isStatusCleared; - data['PatientIdentificationType'] = this.patientIdentificationType; - data['PatientIdentificationNo'] = this.patientIdentificationNo; - data['ProjectID'] = this.projectID; - data['InfoSourceID'] = this.infoSourceID; - data['Address'] = this.address; - data['Age'] = this.age; - data['AgeDesc'] = this.ageDesc; - data['AreaID'] = this.areaID; - data['CreatedBy'] = this.createdBy; - data['GenderDescription'] = this.genderDescription; - data['IR'] = this.iR; - data['ISOCityID'] = this.iSOCityID; - data['ISOCountryID'] = this.iSOCountryID; - if (this.listPrivilege != null) { - data['ListPrivilege'] = - this.listPrivilege.map((v) => v.toJson()).toList(); - } - data['Marital'] = this.marital; - data['OutSA'] = this.outSA; - data['POBox'] = this.pOBox; - data['ReceiveHealthSummaryReport'] = this.receiveHealthSummaryReport; - data['SourceType'] = this.sourceType; - data['StrDateofBirth'] = this.strDateofBirth; - data['TempAddress'] = this.tempAddress; - data['ZipCode'] = this.zipCode; - - return data; - } -} - -class ListPrivilege { - int iD; - String serviceName; - bool previlege; - dynamic region; - - ListPrivilege({this.iD, this.serviceName, this.previlege, this.region}); - - ListPrivilege.fromJson(Map json) { iD = json['ID']; - serviceName = json['ServiceName']; - previlege = json['Previlege']; - region = json['Region']; + userID = json['UserID']; + password = json['password']; + userName = json['UserName']; + roleID = json['RoleID']; + name = json['Name']; + active = json['Active']; + createdOn = json['CreatedOn']; + createdBy = json['CreatedBy']; + editedOn = json['EditedOn']; + editedBy = json['EditedBy']; + mobileNumber = json['MobileNumber']; + realRoleID = json['RealRoleID']; } Map toJson() { final Map data = new Map(); data['ID'] = this.iD; - data['ServiceName'] = this.serviceName; - data['Previlege'] = this.previlege; - data['Region'] = this.region; + data['UserID'] = this.userID; + data['password'] = this.password; + data['UserName'] = this.userName; + data['RoleID'] = this.roleID; + data['Name'] = this.name; + data['Active'] = this.active; + data['CreatedOn'] = this.createdOn; + data['CreatedBy'] = this.createdBy; + data['EditedOn'] = this.editedOn; + data['EditedBy'] = this.editedBy; + data['MobileNumber'] = this.mobileNumber; + data['RealRoleID'] = this.realRoleID; return data; } } diff --git a/lib/core/model/authentication/login_request.dart b/lib/core/model/authentication/login_request.dart new file mode 100644 index 0000000..0e08b82 --- /dev/null +++ b/lib/core/model/authentication/login_request.dart @@ -0,0 +1,18 @@ +class LoginRequest { + int userID; + String password; + + LoginRequest({this.userID, this.password}); + + LoginRequest.fromJson(Map json) { + userID = json['UserID']; + password = json['Password']; + } + + Map toJson() { + final Map data = new Map(); + data['UserID'] = this.userID; + data['Password'] = this.password; + return data; + } +} \ No newline at end of file diff --git a/lib/core/service/authentication_service.dart b/lib/core/service/authentication_service.dart index ae26b38..266f2ae 100644 --- a/lib/core/service/authentication_service.dart +++ b/lib/core/service/authentication_service.dart @@ -1,29 +1,35 @@ - +import 'package:driverapp/config/config.dart'; +import 'package:driverapp/core/model/authentication/authenticated_user.dart'; +import 'package:driverapp/core/model/authentication/login_request.dart'; import 'package:driverapp/core/service/base_service.dart'; -import 'package:flutter/cupertino.dart'; - class AuthenticationService extends BaseService { String selectedClinicName; bool isLogin = false; bool isLoading = true; + AuthenticatedUser authenticatedUser; + String token; AuthenticationService() { // getUserAuthentication(); } -// void getUserAuthentication() async { -// if (profile != null) { -//// doctorProfile = new DoctorProfileModel.fromJson(profile); -// isLoading = false; -// isLogin = true; -// } else { -// isLoading = false; -// isLogin = false; -// } -// notifyListeners(); -// } - - - + login(LoginRequest loginRequest) async { + hasError = false; + try { + await baseAppClient.post(LOGIN, + onSuccess: (dynamic response, int statusCode) { + authenticatedUser = + AuthenticatedUser.fromJson(response['PatientER_DriverFile']); + token = response['LogInTokenID']; + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, body: loginRequest.toJson()); + } catch (error) { + hasError = true; + super.error = error; + throw error; + } + } } diff --git a/lib/core/viewModels/authentication_view_model.dart b/lib/core/viewModels/authentication_view_model.dart index 53aed7b..32b7df8 100644 --- a/lib/core/viewModels/authentication_view_model.dart +++ b/lib/core/viewModels/authentication_view_model.dart @@ -1,5 +1,8 @@ +import 'package:driverapp/config/shared_pref_kay.dart'; import 'package:driverapp/core/enum/viewstate.dart'; +import 'package:driverapp/core/model/authentication/login_request.dart'; import 'package:driverapp/core/service/authentication_service.dart'; +import 'package:driverapp/core/service/client/base_app_client.dart'; import 'package:driverapp/core/viewModels/base_view_model.dart'; import '../../locator.dart'; @@ -21,10 +24,17 @@ class AuthenticationViewModel extends BaseViewModel { } } - login({String userName,String password}){ + login(LoginRequest loginRequest) async { setState(ViewState.BusyLocal); - // call api -// if() -// setState(viewState) + await _authenticationService.login(loginRequest); + if (_authenticationService.hasError) { + error = _authenticationService.error; + setState(ViewState.ErrorLocal); + } else { + sharedPref.setObject( + USER_PROFILE, _authenticationService.authenticatedUser); + sharedPref.setString(TOKEN, _authenticationService.token); + setState(ViewState.Idle); + } } } diff --git a/lib/pages/authentication/login_page.dart b/lib/pages/authentication/login_page.dart index f5dd638..10fb9b6 100644 --- a/lib/pages/authentication/login_page.dart +++ b/lib/pages/authentication/login_page.dart @@ -1,21 +1,34 @@ import 'package:driverapp/app-icons/driver_app_icons.dart'; +import 'package:driverapp/core/enum/viewstate.dart'; +import 'package:driverapp/core/model/authentication/login_request.dart'; import 'package:driverapp/core/viewModels/authentication_view_model.dart'; +import 'package:driverapp/core/viewModels/project_view_model.dart'; import 'package:driverapp/pages/base/base_view.dart'; +import 'package:driverapp/pages/landing/landing_page.dart'; +import 'package:driverapp/uitl/translations_delegate_base.dart'; +import 'package:driverapp/uitl/utils.dart'; import 'package:driverapp/widgets/buttons/secondary_button.dart'; +import 'package:driverapp/widgets/data_display/circle-container.dart'; import 'package:driverapp/widgets/input/text_field.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; -import 'package:hexcolor/hexcolor.dart'; +import 'package:provider/provider.dart'; class LoginPage extends StatelessWidget { + LoginRequest loginRequest = LoginRequest(); + final loginFormKey = GlobalKey(); + ProjectViewModel projectViewModel; + @override Widget build(BuildContext context) { + projectViewModel = Provider.of(context); return AnimatedSwitcher( duration: Duration(microseconds: 350), child: BaseView( builder: (_, model, widget) => Scaffold( //baseViewModel: model, + body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -37,8 +50,12 @@ class LoginPage extends StatelessWidget { color: Theme.of(context).primaryColor, ), margin: EdgeInsets.only( - right: - MediaQuery.of(context).size.width * 0.15), + right: projectViewModel.isArabic + ? 0 + : MediaQuery.of(context).size.width * 0.15, + left: !projectViewModel.isArabic + ? 0 + : MediaQuery.of(context).size.width * 0.15), ), ], ), @@ -72,80 +89,127 @@ class LoginPage extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, children: [ CircleContainer( - child: Text( - "English", - style: TextStyle( - fontSize: 12, color: Colors.white), - ), - color: Theme.of(context).primaryColor, borderWidth: 0,borderColor: Colors.transparent,), + onTap: () => projectViewModel.changeLanguage('en'), + child: Text( + TranslationBase.of(context).lanEnglish, + style: TextStyle( + fontSize: 12, + color: projectViewModel.isArabic + ? Colors.black + : Colors.white), + ), + color: projectViewModel.isArabic + ? Colors.transparent + : Theme.of(context).primaryColor, + borderWidth: projectViewModel.isArabic ? 3 : 0, + borderColor: projectViewModel.isArabic + ? Theme.of(context).primaryColor + : Colors.transparent, + ), SizedBox( width: 20, ), CircleContainer( + onTap: () => + projectViewModel.changeLanguage('ar'), child: Text( - "Arabic", + TranslationBase.of(context).lanArabic, style: TextStyle( - fontSize: 12, color: Colors.black), + fontSize: 12, + color: !projectViewModel.isArabic + ? Colors.black + : Colors.white), ), - color: Colors.transparent, borderColor: Theme.of(context).primaryColor,borderWidth: 3,), + color: !projectViewModel.isArabic + ? Colors.transparent + : Theme.of(context).primaryColor, + borderWidth: !projectViewModel.isArabic ? 3 : 0, + borderColor: !projectViewModel.isArabic + ? Theme.of(context).primaryColor + : Colors.transparent), ], ), SizedBox( height: 10, ), - Column( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: Row( + Form( + key: loginFormKey, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Padding( + padding: + const EdgeInsets.symmetric(horizontal: 20), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Text( + TranslationBase.of(context).enterCredentialsMsg, + style: TextStyle( + fontSize: 13, color: Colors.grey), + ), + SizedBox( + height: 10, + ) + ], + ), + ), + SizedBox( + height: 10, + ), + Container( + child: TextFields( + onChanged: (value) => {}, + hintText: TranslationBase.of(context).enterId, + validator: (value) { + if (value.isEmpty) { + return TranslationBase.of(context) + .pleaseEnterYourID; + } + return null; + }, + onSaved: (value) { + loginRequest.userID = int.parse(value.trim()); + }, + ), + ), + SizedBox( + height: 20, + ), + Container( + child: TextFields( + borderRadiusValue: 6, + onChanged: (value) => {}, + hintText: + TranslationBase.of(context).enterPassword, + validator: (value) { + if (value.isEmpty) { + return TranslationBase.of(context) + .pleaseEnterPassword; + } + return null; + }, + onSaved: (value) { + loginRequest.password = value; + }, + ), + ), + SizedBox( + height: 25, + ), + Row( mainAxisAlignment: MainAxisAlignment.end, children: [ Text( - "Please insert username and password to login", + TranslationBase.of(context).forgotPassword, style: TextStyle( - fontSize: 13, color: Colors.grey), + fontSize: 14, + color: Theme.of(context).primaryColor), ), - SizedBox( - height: 10, - ) ], ), - ), - SizedBox( - height: 10, - ), - Container( - child: TextFields( - onChanged: (value) => {}, - hintText: "User Name", - ), - ), - SizedBox( - height: 20, - ), - Container( - child: TextFields( - borderRadiusValue: 6, - onChanged: (value) => {}, - hintText: "Password", - ), - ), - SizedBox( - height: 25, - ), - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Text( - "Forgot Password?", - style: TextStyle( - fontSize: 14, - color: Theme.of(context).primaryColor), - ), - ], - ), - ], + ], + ), ), ], ), @@ -164,7 +228,14 @@ class LoginPage extends StatelessWidget { height: MediaQuery.of(context).size.height * 0.12, child: Column( children: [ - SecondaryButton(label: "Login"), + SecondaryButton( + label: TranslationBase.of(context).login, + onTap: () { + login(model, context); + }, + disabled: model.state == ViewState.BusyLocal, + loading: model.state == ViewState.BusyLocal, + ), SizedBox( height: 30, ) @@ -174,32 +245,19 @@ class LoginPage extends StatelessWidget { ), ); } -} - -class CircleContainer extends StatelessWidget { - const CircleContainer( - {this.child, - this.color = Colors.white, - this.borderColor, - this.borderWidth = 2.0}); - final Widget child; - final Color color; - final Color borderColor; - final double borderWidth; - - @override - Widget build(BuildContext context) { - return Container( - child: Center(child: child), - decoration: BoxDecoration( - shape: BoxShape.circle, - color: color, - border: Border.all( - color: borderColor ?? Hexcolor("#707070"), - width: borderWidth)), - height: 60, - width: 60, - ); + login(AuthenticationViewModel model, BuildContext context) async { + if (loginFormKey.currentState.validate()) { + loginFormKey.currentState.save(); + await model.login(loginRequest); + if (model.state == ViewState.ErrorLocal) { + Utils.showErrorToast(model.error); + // Show error + } else { + Navigator.push( + context, MaterialPageRoute(builder: (context) => LandingPage())); + } + } } } + diff --git a/lib/uitl/translations_delegate_base.dart b/lib/uitl/translations_delegate_base.dart index 1a61090..400292e 100644 --- a/lib/uitl/translations_delegate_base.dart +++ b/lib/uitl/translations_delegate_base.dart @@ -39,6 +39,19 @@ class TranslationBase { String get logout => localizedValues['logout'][locale.languageCode]; String get booking => localizedValues['booking'][locale.languageCode]; + String get enterId => localizedValues['enterId'][locale.languageCode]; + String get pleaseEnterYourID => + localizedValues['pleaseEnterYourID'][locale.languageCode]; + String get enterPassword => + localizedValues['enterPassword'][locale.languageCode]; + String get pleaseEnterPassword => + localizedValues['pleaseEnterPassword'][locale.languageCode]; + String get english => localizedValues['english'][locale.languageCode]; + + String get arabic => localizedValues['arabic'][locale.languageCode]; + String get enterCredentialsMsg => localizedValues['enterCredentialsMsg'][locale.languageCode]; + String get forgotPassword => localizedValues['forgotPassword'][locale.languageCode]; + String get login => localizedValues['login'][locale.languageCode]; } class TranslationBaseDelegate extends LocalizationsDelegate { diff --git a/lib/widgets/data_display/circle-container.dart b/lib/widgets/data_display/circle-container.dart new file mode 100644 index 0000000..bb0ebdd --- /dev/null +++ b/lib/widgets/data_display/circle-container.dart @@ -0,0 +1,34 @@ +import 'package:flutter/material.dart'; +import 'package:hexcolor/hexcolor.dart'; + +class CircleContainer extends StatelessWidget { + const CircleContainer( + {this.child, + this.color = Colors.white, + this.borderColor, + this.borderWidth = 2.0, + this.onTap}); + + final Widget child; + final Color color; + final Color borderColor; + final double borderWidth; + final Function onTap; + + @override + Widget build(BuildContext context) { + return InkWell( + onTap: onTap, + child: Container( + child: Center(child: child), + decoration: BoxDecoration( + shape: BoxShape.circle, + color: color, + border: Border.all( + color: borderColor ?? Hexcolor("#707070"), width: borderWidth)), + height: 60, + width: 60, + ), + ); + } +} From 57e60178a30d0ef6e04b362bfb0a45746a442f1a Mon Sep 17 00:00:00 2001 From: Elham Rababah Date: Sun, 23 Aug 2020 16:49:08 +0300 Subject: [PATCH 4/4] Finish login Functionality --- ios/Runner.xcodeproj/project.pbxproj | 43 +- .../viewModels/authentication_view_model.dart | 6 +- lib/pages/authentication/login_page.dart | 382 +++++++++--------- 3 files changed, 235 insertions(+), 196 deletions(-) diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 90398e9..dd7be69 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -225,12 +225,47 @@ buildActionMask = 2147483647; files = ( ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", + "${PODS_ROOT}/../Flutter/Flutter.framework", + "${BUILT_PRODUCTS_DIR}/MTBBarcodeScanner/MTBBarcodeScanner.framework", + "${BUILT_PRODUCTS_DIR}/Reachability/Reachability.framework", + "${BUILT_PRODUCTS_DIR}/SwiftProtobuf/SwiftProtobuf.framework", + "${BUILT_PRODUCTS_DIR}/TOCropViewController/TOCropViewController.framework", + "${BUILT_PRODUCTS_DIR}/barcode_scan/barcode_scan.framework", + "${BUILT_PRODUCTS_DIR}/connectivity/connectivity.framework", + "${BUILT_PRODUCTS_DIR}/device_info/device_info.framework", + "${BUILT_PRODUCTS_DIR}/flutter_flexible_toast/flutter_flexible_toast.framework", + "${BUILT_PRODUCTS_DIR}/flutter_local_notifications/flutter_local_notifications.framework", + "${BUILT_PRODUCTS_DIR}/flutter_plugin_android_lifecycle/flutter_plugin_android_lifecycle.framework", + "${BUILT_PRODUCTS_DIR}/hexcolor/hexcolor.framework", + "${BUILT_PRODUCTS_DIR}/image_cropper/image_cropper.framework", + "${BUILT_PRODUCTS_DIR}/image_picker/image_picker.framework", + "${BUILT_PRODUCTS_DIR}/local_auth/local_auth.framework", + "${BUILT_PRODUCTS_DIR}/maps_launcher/maps_launcher.framework", + "${BUILT_PRODUCTS_DIR}/shared_preferences/shared_preferences.framework", + "${BUILT_PRODUCTS_DIR}/url_launcher/url_launcher.framework", ); name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MTBBarcodeScanner.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Reachability.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftProtobuf.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/TOCropViewController.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/barcode_scan.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/connectivity.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/device_info.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_flexible_toast.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_local_notifications.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_plugin_android_lifecycle.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/hexcolor.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/image_cropper.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/image_picker.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/local_auth.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/maps_launcher.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/url_launcher.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; diff --git a/lib/core/viewModels/authentication_view_model.dart b/lib/core/viewModels/authentication_view_model.dart index 32b7df8..b91b228 100644 --- a/lib/core/viewModels/authentication_view_model.dart +++ b/lib/core/viewModels/authentication_view_model.dart @@ -16,7 +16,7 @@ class AuthenticationViewModel extends BaseViewModel { if (state == ViewState.Busy || state == ViewState.BusyLocal) { return APP_STATUS.LOADING; } else { - if (user != null) { + if ( user != null) { return APP_STATUS.AUTHENTICATED; } else { return APP_STATUS.UNAUTHENTICATED; @@ -24,6 +24,10 @@ class AuthenticationViewModel extends BaseViewModel { } } + AuthenticationViewModel(){ + sharedPref.clear(); + } + login(LoginRequest loginRequest) async { setState(ViewState.BusyLocal); await _authenticationService.login(loginRequest); diff --git a/lib/pages/authentication/login_page.dart b/lib/pages/authentication/login_page.dart index 10fb9b6..634f6e4 100644 --- a/lib/pages/authentication/login_page.dart +++ b/lib/pages/authentication/login_page.dart @@ -12,6 +12,7 @@ import 'package:driverapp/widgets/data_display/circle-container.dart'; import 'package:driverapp/widgets/input/text_field.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:provider/provider.dart'; @@ -27,220 +28,220 @@ class LoginPage extends StatelessWidget { duration: Duration(microseconds: 350), child: BaseView( builder: (_, model, widget) => Scaffold( - //baseViewModel: model, - - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - FractionallySizedBox( - widthFactor: 0.80, - child: Column( - children: [ - SizedBox( - height: 40, - ), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - child: Icon( - DriverApp.logo, - size: 70, - color: Theme.of(context).primaryColor, + body: SingleChildScrollView( + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + FractionallySizedBox( + widthFactor: 0.80, + child: Column( + children: [ + SizedBox( + height: 40, + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + child: Icon( + DriverApp.logo, + size: 70, + color: Theme.of(context).primaryColor, + ), + margin: EdgeInsets.only( + right: projectViewModel.isArabic + ? 0 + : MediaQuery.of(context).size.width * 0.15, + left: !projectViewModel.isArabic + ? 0 + : MediaQuery.of(context).size.width * 0.15), ), - margin: EdgeInsets.only( - right: projectViewModel.isArabic - ? 0 - : MediaQuery.of(context).size.width * 0.15, - left: !projectViewModel.isArabic - ? 0 - : MediaQuery.of(context).size.width * 0.15), - ), - ], - ), - SizedBox( - height: 20, - ), - Column( - children: [ - Text( - "Driver", - style: TextStyle( - fontSize: 50, fontWeight: FontWeight.bold), - ), - Text( - "Delivery", - style: TextStyle(fontSize: 36, letterSpacing: 1), - ), - Text( - "APP", - style: TextStyle( - fontSize: 33, - letterSpacing: 33, - fontWeight: FontWeight.w400), - ), - ], - ), - SizedBox( - height: 30, - ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - CircleContainer( - onTap: () => projectViewModel.changeLanguage('en'), - child: Text( - TranslationBase.of(context).lanEnglish, + ], + ), + SizedBox( + height: 20, + ), + Column( + children: [ + Text( + "Driver", style: TextStyle( - fontSize: 12, - color: projectViewModel.isArabic - ? Colors.black - : Colors.white), + fontSize: 50, fontWeight: FontWeight.bold), ), - color: projectViewModel.isArabic - ? Colors.transparent - : Theme.of(context).primaryColor, - borderWidth: projectViewModel.isArabic ? 3 : 0, - borderColor: projectViewModel.isArabic - ? Theme.of(context).primaryColor - : Colors.transparent, - ), - SizedBox( - width: 20, - ), - CircleContainer( - onTap: () => - projectViewModel.changeLanguage('ar'), + Text( + "Delivery", + style: TextStyle(fontSize: 36, letterSpacing: 1), + ), + Text( + "APP", + style: TextStyle( + fontSize: 33, + letterSpacing: 33, + fontWeight: FontWeight.w400), + ), + ], + ), + SizedBox( + height: 30, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + CircleContainer( + onTap: () => projectViewModel.changeLanguage('en'), child: Text( - TranslationBase.of(context).lanArabic, + TranslationBase.of(context).lanEnglish, style: TextStyle( fontSize: 12, - color: !projectViewModel.isArabic + color: projectViewModel.isArabic ? Colors.black : Colors.white), ), - color: !projectViewModel.isArabic + color: projectViewModel.isArabic ? Colors.transparent : Theme.of(context).primaryColor, - borderWidth: !projectViewModel.isArabic ? 3 : 0, - borderColor: !projectViewModel.isArabic + borderWidth: projectViewModel.isArabic ? 3 : 0, + borderColor: projectViewModel.isArabic ? Theme.of(context).primaryColor - : Colors.transparent), - ], - ), - SizedBox( - height: 10, - ), - Form( - key: loginFormKey, - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Padding( - padding: - const EdgeInsets.symmetric(horizontal: 20), - child: Row( + : Colors.transparent, + ), + SizedBox( + width: 20, + ), + CircleContainer( + onTap: () => + projectViewModel.changeLanguage('ar'), + child: Text( + TranslationBase.of(context).lanArabic, + style: TextStyle( + fontSize: 12, + color: !projectViewModel.isArabic + ? Colors.black + : Colors.white), + ), + color: !projectViewModel.isArabic + ? Colors.transparent + : Theme.of(context).primaryColor, + borderWidth: !projectViewModel.isArabic ? 3 : 0, + borderColor: !projectViewModel.isArabic + ? Theme.of(context).primaryColor + : Colors.transparent), + ], + ), + SizedBox( + height: 10, + ), + Form( + key: loginFormKey, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Padding( + padding: + const EdgeInsets.symmetric(horizontal: 20), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Expanded( + child: Text( + TranslationBase.of(context).enterCredentialsMsg, + style: TextStyle( + fontSize: 13, color: Colors.grey), + ), + ), + SizedBox( + height: 10, + ) + ], + ), + ), + SizedBox( + height: 10, + ), + Container( + child: TextFields( + hintText: TranslationBase.of(context).enterId, + validator: (value) { + if (value.isEmpty) { + return TranslationBase.of(context) + .pleaseEnterYourID; + } + return null; + }, + onSaved: (value) { + loginRequest.userID = int.parse(value.trim()); + }, + ), + ), + SizedBox( + height: 20, + ), + Container( + child: TextFields( + borderRadiusValue: 6, + hintText: + TranslationBase.of(context).enterPassword, + validator: (value) { + if (value.isEmpty) { + return TranslationBase.of(context) + .pleaseEnterPassword; + } + return null; + }, + onSaved: (value) { + loginRequest.password = value; + }, + ), + ), + SizedBox( + height: 25, + ), + Row( mainAxisAlignment: MainAxisAlignment.end, children: [ Text( - TranslationBase.of(context).enterCredentialsMsg, + TranslationBase.of(context).forgotPassword, style: TextStyle( - fontSize: 13, color: Colors.grey), + fontSize: 14, + color: Theme.of(context).primaryColor), ), - SizedBox( - height: 10, - ) ], ), - ), - SizedBox( - height: 10, - ), - Container( - child: TextFields( - onChanged: (value) => {}, - hintText: TranslationBase.of(context).enterId, - validator: (value) { - if (value.isEmpty) { - return TranslationBase.of(context) - .pleaseEnterYourID; - } - return null; - }, - onSaved: (value) { - loginRequest.userID = int.parse(value.trim()); - }, - ), - ), - SizedBox( - height: 20, - ), - Container( - child: TextFields( - borderRadiusValue: 6, - onChanged: (value) => {}, - hintText: - TranslationBase.of(context).enterPassword, - validator: (value) { - if (value.isEmpty) { - return TranslationBase.of(context) - .pleaseEnterPassword; - } - return null; - }, - onSaved: (value) { - loginRequest.password = value; - }, - ), - ), - SizedBox( - height: 25, - ), - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Text( - TranslationBase.of(context).forgotPassword, - style: TextStyle( - fontSize: 14, - color: Theme.of(context).primaryColor), - ), - ], - ), - ], + ], + ), ), - ), - ], + ], + ), ), - ), - SizedBox( - height: 20, - ), - SizedBox( - height: 10, - ) - ], - ), - ), - bottomSheet: Container( - margin: EdgeInsets.all(10), - height: MediaQuery.of(context).size.height * 0.12, - child: Column( - children: [ - SecondaryButton( - label: TranslationBase.of(context).login, - onTap: () { - login(model, context); - }, - disabled: model.state == ViewState.BusyLocal, - loading: model.state == ViewState.BusyLocal, + SizedBox( + height: 20, ), SizedBox( - height: 30, - ) + height: 10, + ),Container( + margin: EdgeInsets.all(10), + height: MediaQuery.of(context).size.height * 0.22, + child: Column( + children: [ + SecondaryButton( + label: TranslationBase.of(context).login, + onTap: () { + login(model, context); + }, + disabled: model.state == ViewState.BusyLocal, + loading: model.state == ViewState.BusyLocal, + ), + SizedBox( + height: 30, + ) + ], + )) ], - )), + ), + ), + ), + ), ), ); @@ -252,7 +253,6 @@ class LoginPage extends StatelessWidget { await model.login(loginRequest); if (model.state == ViewState.ErrorLocal) { Utils.showErrorToast(model.error); - // Show error } else { Navigator.push( context, MaterialPageRoute(builder: (context) => LandingPage()));