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/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/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 0000000..a9e0e9f Binary files /dev/null and b/lib/app-icons/fonts/DriverApp.ttf differ 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/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..0329bd5 --- /dev/null +++ b/lib/core/model/authentication/authenticated_user.dart @@ -0,0 +1,64 @@ +class AuthenticatedUser { + int iD; + int userID; + String password; + String userName; + int roleID; + String name; + bool active; + String createdOn; + int createdBy; + Null editedOn; + Null editedBy; + String mobileNumber; + int realRoleID; + + 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) { + iD = json['ID']; + 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['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 new file mode 100644 index 0000000..266f2ae --- /dev/null +++ b/lib/core/service/authentication_service.dart @@ -0,0 +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'; + +class AuthenticationService extends BaseService { + String selectedClinicName; + bool isLogin = false; + bool isLoading = true; + AuthenticatedUser authenticatedUser; + String token; + + AuthenticationService() { +// getUserAuthentication(); + } + + 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/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..b91b228 --- /dev/null +++ b/lib/core/viewModels/authentication_view_model.dart @@ -0,0 +1,44 @@ +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'; + +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; + } + } + } + + AuthenticationViewModel(){ + sharedPref.clear(); + } + + login(LoginRequest loginRequest) async { + setState(ViewState.BusyLocal); + 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/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..9626777 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,3 +1,4 @@ +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'; @@ -6,7 +7,8 @@ import 'package:provider/provider.dart'; import 'config/size_config.dart'; import 'core/viewModels/project_view_model.dart'; import 'locator.dart'; -import 'pages/landing/landing_page.dart'; + + void main() { setupLocator(); @@ -25,7 +27,7 @@ class MyApp extends StatelessWidget { providers: [ ChangeNotifierProvider( create: (context) => ProjectViewModel(), - ), + ) ], child: Consumer( builder: (context, projectProvider, child) => MaterialApp( @@ -51,8 +53,12 @@ class MyApp extends StatelessWidget { TargetPlatform.iOS: CupertinoPageTransitionsBuilder(), }, ), + 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), @@ -60,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, @@ -73,7 +80,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..634f6e4 --- /dev/null +++ b/lib/pages/authentication/login_page.dart @@ -0,0 +1,263 @@ +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/rendering.dart'; +import 'package:flutter/widgets.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( + 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), + ), + ], + ), + 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, + 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( + 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).forgotPassword, + style: TextStyle( + fontSize: 14, + color: Theme.of(context).primaryColor), + ), + ], + ), + ], + ), + ), + ], + ), + ), + SizedBox( + height: 20, + ), + SizedBox( + 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, + ) + ], + )) + ], + ), + ), + ), + + ), + ), + ); + } + + 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); + } else { + Navigator.push( + context, MaterialPageRoute(builder: (context) => LandingPage())); + } + } + } +} + 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/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/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/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, + ), + ); + } +} 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), + )), ), )); } 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