diff --git a/lib/config/config.dart b/lib/config/config.dart index 9824883e..0bdf8395 100644 --- a/lib/config/config.dart +++ b/lib/config/config.dart @@ -5,6 +5,9 @@ import 'package:diplomaticquarterapp/uitl/app_shared_preferences.dart'; const MAX_SMALL_SCREEN = 660; +const BASE_URL = 'https://uat.hmgwebservices.com/Services'; + +const GET_PROJECT = '/Lists.svc/REST/GetProject'; const BASE_URL = 'https://hmgwebservices.com/'; // Production Environment //const BASE_URL = 'https://uat.hmgwebservices.com/'; // UAT Environment diff --git a/lib/core/enum/viewstate.dart b/lib/core/enum/viewstate.dart new file mode 100644 index 00000000..09b5d34b --- /dev/null +++ b/lib/core/enum/viewstate.dart @@ -0,0 +1 @@ +enum ViewState { Idle, Busy, Error } diff --git a/lib/core/model/hospitals/hospitals_model.dart b/lib/core/model/hospitals/hospitals_model.dart new file mode 100644 index 00000000..a0628c60 --- /dev/null +++ b/lib/core/model/hospitals/hospitals_model.dart @@ -0,0 +1,76 @@ +class HospitalsModel { + String desciption; + Null desciptionN; + int iD; + String legalName; + String legalNameN; + String name; + Null nameN; + String phoneNumber; + String setupID; + int distanceInKilometers; + bool isActive; + String latitude; + String longitude; + int mainProjectID; + Null projectOutSA; + bool usingInDoctorApp; + + HospitalsModel( + {this.desciption, + this.desciptionN, + this.iD, + this.legalName, + this.legalNameN, + this.name, + this.nameN, + this.phoneNumber, + this.setupID, + this.distanceInKilometers, + this.isActive, + this.latitude, + this.longitude, + this.mainProjectID, + this.projectOutSA, + this.usingInDoctorApp}); + + HospitalsModel.fromJson(Map json) { + desciption = json['Desciption']; + desciptionN = json['DesciptionN']; + iD = json['ID']; + legalName = json['LegalName']; + legalNameN = json['LegalNameN']; + name = json['Name']; + nameN = json['NameN']; + phoneNumber = json['PhoneNumber']; + setupID = json['SetupID']; + distanceInKilometers = json['DistanceInKilometers']; + isActive = json['IsActive']; + latitude = json['Latitude']; + longitude = json['Longitude']; + mainProjectID = json['MainProjectID']; + projectOutSA = json['ProjectOutSA']; + usingInDoctorApp = json['UsingInDoctorApp']; + } + + Map toJson() { + final Map data = new Map(); + data['Desciption'] = this.desciption; + data['DesciptionN'] = this.desciptionN; + data['ID'] = this.iD; + data['LegalName'] = this.legalName; + data['LegalNameN'] = this.legalNameN; + data['Name'] = this.name; + data['NameN'] = this.nameN; + data['PhoneNumber'] = this.phoneNumber; + data['SetupID'] = this.setupID; + data['DistanceInKilometers'] = this.distanceInKilometers; + data['IsActive'] = this.isActive; + data['Latitude'] = this.latitude; + data['Longitude'] = this.longitude; + data['MainProjectID'] = this.mainProjectID; + data['ProjectOutSA'] = this.projectOutSA; + data['UsingInDoctorApp'] = this.usingInDoctorApp; + return data; + } +} diff --git a/lib/core/model/hospitals/request_get_hospitals_model.dart b/lib/core/model/hospitals/request_get_hospitals_model.dart new file mode 100644 index 00000000..be163654 --- /dev/null +++ b/lib/core/model/hospitals/request_get_hospitals_model.dart @@ -0,0 +1,56 @@ +class RequestGetHospitalsModel { + int latitude; + int longitude; + double versionID; + int channel; + int languageID; + String iPAdress; + String generalid; + int patientOutSA; + String sessionID; + bool isDentalAllowedBackend; + int deviceTypeID; + + RequestGetHospitalsModel( + {this.latitude, + this.longitude, + this.versionID, + this.channel, + this.languageID, + this.iPAdress, + this.generalid, + this.patientOutSA, + this.sessionID, + this.isDentalAllowedBackend, + this.deviceTypeID}); + + RequestGetHospitalsModel.fromJson(Map json) { + latitude = json['Latitude']; + longitude = json['Longitude']; + versionID = json['VersionID']; + channel = json['Channel']; + languageID = json['LanguageID']; + iPAdress = json['IPAdress']; + generalid = json['generalid']; + patientOutSA = json['PatientOutSA']; + sessionID = json['SessionID']; + isDentalAllowedBackend = json['isDentalAllowedBackend']; + deviceTypeID = json['DeviceTypeID']; + } + + Map toJson() { + final Map data = new Map(); + data['Latitude'] = this.latitude; + data['Longitude'] = this.longitude; + data['VersionID'] = this.versionID; + data['Channel'] = this.channel; + data['LanguageID'] = this.languageID; + data['IPAdress'] = this.iPAdress; + data['generalid'] = this.generalid; + data['PatientOutSA'] = this.patientOutSA; + data['SessionID'] = this.sessionID; + data['isDentalAllowedBackend'] = this.isDentalAllowedBackend; + data['DeviceTypeID'] = this.deviceTypeID; + return data; + } +} diff --git a/lib/core/service/base_service.dart b/lib/core/service/base_service.dart new file mode 100644 index 00000000..828420c7 --- /dev/null +++ b/lib/core/service/base_service.dart @@ -0,0 +1,9 @@ + +import 'client/base_app_client.dart'; + +class BaseService{ + String error; + bool hasError = false; + BaseAppClient baseAppClient = BaseAppClient(); + +} \ No newline at end of file diff --git a/lib/client/base_app_client.dart b/lib/core/service/client/base_app_client.dart similarity index 99% rename from lib/client/base_app_client.dart rename to lib/core/service/client/base_app_client.dart index ec905586..72c38568 100644 --- a/lib/client/base_app_client.dart +++ b/lib/core/service/client/base_app_client.dart @@ -1,4 +1,5 @@ import 'dart:convert'; + import 'package:diplomaticquarterapp/config/config.dart'; import 'package:diplomaticquarterapp/uitl/app_shared_preferences.dart'; import 'package:diplomaticquarterapp/uitl/utils.dart'; @@ -13,7 +14,7 @@ AppSharedPreferences sharedPref = new AppSharedPreferences(); /// body: null); class BaseAppClient { - static post( + post( String endPoint, { Map body, Function(dynamic response, int statusCode) onSuccess, diff --git a/lib/core/service/hospital_service.dart b/lib/core/service/hospital_service.dart new file mode 100644 index 00000000..c131d94f --- /dev/null +++ b/lib/core/service/hospital_service.dart @@ -0,0 +1,36 @@ +import 'package:diplomaticquarterapp/config/config.dart'; +import 'package:diplomaticquarterapp/core/model/hospitals/hospitals_model.dart'; +import 'package:diplomaticquarterapp/core/model/hospitals/request_get_hospitals_model.dart'; +import 'package:diplomaticquarterapp/core/service/base_service.dart'; + +class HospitalService extends BaseService { + List _hospitals = List(); + + List get hospitals => _hospitals; + + RequestGetHospitalsModel _requestGetHospitalsModel = RequestGetHospitalsModel( + latitude: 0, + longitude: 0, + versionID: 5.2, + channel: 3, + languageID: 2, + iPAdress: '10.20.10.20', + generalid: 'Cs2020@2016\$2958', + patientOutSA: 0, + sessionID: 'JUWuiMBCEGkAAxQpakQ', + isDentalAllowedBackend: false, + deviceTypeID: 2); + + Future getHospitals() async { + await baseAppClient.post(GET_PROJECT, + onSuccess: (dynamic response, int statusCode) { + _hospitals.clear(); + response['ListProject'].forEach((hospital) { + _hospitals.add(HospitalsModel.fromJson(hospital)); + }); + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, body: _requestGetHospitalsModel.toJson()); + } +} diff --git a/lib/core/viewModels/base_view_model.dart b/lib/core/viewModels/base_view_model.dart new file mode 100644 index 00000000..497a96b6 --- /dev/null +++ b/lib/core/viewModels/base_view_model.dart @@ -0,0 +1,16 @@ +import 'package:diplomaticquarterapp/core/enum/viewstate.dart'; +import 'package:flutter/material.dart'; + +class BaseViewModel extends ChangeNotifier { + ViewState _state = ViewState.Idle; + bool isInternetConnection = true; + + ViewState get state => _state; + + String error = ""; + + void setState(ViewState viewState) { + _state = viewState; + notifyListeners(); + } +} diff --git a/lib/core/viewModels/hospital_view_model.dart b/lib/core/viewModels/hospital_view_model.dart new file mode 100644 index 00000000..66ad4b01 --- /dev/null +++ b/lib/core/viewModels/hospital_view_model.dart @@ -0,0 +1,22 @@ +import 'package:diplomaticquarterapp/core/enum/viewstate.dart'; +import 'package:diplomaticquarterapp/core/model/hospitals/hospitals_model.dart'; +import 'package:diplomaticquarterapp/core/service/hospital_service.dart'; + +import '../../locator.dart'; +import 'base_view_model.dart'; + +class HospitalViewModel extends BaseViewModel { + HospitalService _hospitalService = locator(); + + List get hospitals => _hospitalService.hospitals; + + Future getHospitals() async { + setState(ViewState.Busy); + await _hospitalService.getHospitals(); + if (_hospitalService.hasError) { + error = _hospitalService.error; + setState(ViewState.Error); + } else + setState(ViewState.Idle); + } +} diff --git a/lib/providers/project_provider.dart b/lib/core/viewModels/project_view_model.dart similarity index 96% rename from lib/providers/project_provider.dart rename to lib/core/viewModels/project_view_model.dart index da48ffb9..e91ea4f2 100644 --- a/lib/providers/project_provider.dart +++ b/lib/core/viewModels/project_view_model.dart @@ -5,7 +5,7 @@ import 'package:diplomaticquarterapp/config/shared_pref_kay.dart'; import 'package:diplomaticquarterapp/uitl/app_shared_preferences.dart'; import 'package:flutter/cupertino.dart'; -class ProjectProvider with ChangeNotifier { +class ProjectViewModel with ChangeNotifier { AppSharedPreferences sharedPref = AppSharedPreferences(); Locale _appLocale; String currentLanguage = 'ar'; @@ -20,7 +20,7 @@ class ProjectProvider with ChangeNotifier { bool get isArabic => _isArabic; StreamSubscription subscription; - ProjectProvider() { + ProjectViewModel() { loadSharedPrefLanguage(); subscription = Connectivity() diff --git a/lib/locator.dart b/lib/locator.dart new file mode 100644 index 00000000..3d44f4ce --- /dev/null +++ b/lib/locator.dart @@ -0,0 +1,15 @@ +import 'package:get_it/get_it.dart'; + +import 'core/service/hospital_service.dart'; +import 'core/viewModels/hospital_view_model.dart'; + +GetIt locator = GetIt.instance; + +///di +void setupLocator() { + /// Services + locator.registerLazySingleton(() => HospitalService()); + + /// View Model + locator.registerFactory(() => HospitalViewModel()); +} diff --git a/lib/main.dart b/lib/main.dart index dff61ac6..2eb5dd26 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,14 +1,14 @@ -import 'package:diplomaticquarterapp/pages/home_page.dart'; -import 'package:diplomaticquarterapp/pages/landing_page.dart'; -import 'package:diplomaticquarterapp/providers/project_provider.dart'; import 'package:diplomaticquarterapp/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/viewModels/project_view_model.dart'; +import 'locator.dart'; +import 'pages/landing/landing_page.dart'; void main() { + setupLocator(); runApp(MyApp()); } @@ -22,11 +22,11 @@ class MyApp extends StatelessWidget { SizeConfig().init(constraints, orientation); return MultiProvider( providers: [ - ChangeNotifierProvider( - create: (context) => ProjectProvider(), + ChangeNotifierProvider( + create: (context) => ProjectViewModel(), ), ], - child: Consumer( + child: Consumer( builder: (context, projectProvider, child) => MaterialApp( showSemanticsDebugger: false, title: 'Diplomatic Quarter App', @@ -61,11 +61,9 @@ class MyApp extends StatelessWidget { splashColor: Colors.transparent, primaryColor: Colors.grey, cursorColor: Color.fromRGBO(78, 62, 253, 1.0), - iconTheme:IconThemeData( - - ) , + iconTheme: IconThemeData(), appBarTheme: AppBarTheme( - color: Color.fromRGBO(247, 248, 251, 1), + color: Colors.grey, brightness: Brightness.light, elevation: 0.0, actionsIconTheme: IconThemeData( @@ -74,9 +72,7 @@ class MyApp extends StatelessWidget { ), ), initialRoute: '/', - routes: { - '/': (context) => LandingPage() - }, + routes: {'/': (context) => LandingPage()}, debugShowCheckedModeBanner: false, ), ), diff --git a/lib/pages/base/base_view.dart b/lib/pages/base/base_view.dart new file mode 100644 index 00000000..3ed2baad --- /dev/null +++ b/lib/pages/base/base_view.dart @@ -0,0 +1,38 @@ +import 'package:diplomaticquarterapp/core/viewModels/base_view_model.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +import '../../locator.dart'; + +class BaseView extends StatefulWidget { + final Widget Function(BuildContext context, T model, Widget child) builder; + final Function(T) onModelReady; + + BaseView({ + this.builder, + this.onModelReady, + }); + + @override + _BaseViewState createState() => _BaseViewState(); +} + +class _BaseViewState extends State> { + T model = locator(); + + @override + void initState() { + if (widget.onModelReady != null) { + widget.onModelReady(model); + } + super.initState(); + } + + @override + Widget build(BuildContext context) { + return ChangeNotifierProvider( + create: (BuildContext context) => model, + child: Consumer(builder: widget.builder), + ); + } +} diff --git a/lib/pages/home_page.dart b/lib/pages/home_page.dart deleted file mode 100644 index f76f7321..00000000 --- a/lib/pages/home_page.dart +++ /dev/null @@ -1,49 +0,0 @@ -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; - -class MyHomePage extends StatefulWidget { - MyHomePage({Key key, this.title}) : super(key: key); - - final String title; - - @override - _MyHomePageState createState() => _MyHomePageState(); -} - -class _MyHomePageState extends State { - int _counter = 0; - - void _incrementCounter() { - setState(() { - _counter++; - }); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text(widget.title), - ), - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - 'You have pushed the button this many times:', - ), - Text( - '$_counter', - style: Theme.of(context).textTheme.headline4, - ), - ], - ), - ), - floatingActionButton: FloatingActionButton( - onPressed: _incrementCounter, - tooltip: 'Increment', - child: Icon(Icons.add), - ), // This trailing comma makes auto-formatting nicer for build methods. - ); - } -} \ No newline at end of file diff --git a/lib/pages/landing/home_page.dart b/lib/pages/landing/home_page.dart new file mode 100644 index 00000000..0c449410 --- /dev/null +++ b/lib/pages/landing/home_page.dart @@ -0,0 +1,69 @@ +import 'package:diplomaticquarterapp/core/model/hospitals/hospitals_model.dart'; +import 'package:diplomaticquarterapp/core/viewModels/hospital_view_model.dart'; +import 'package:diplomaticquarterapp/widgets/data_display/text.dart'; +import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import '../base/base_view.dart'; + +class HomePage extends StatefulWidget { + @override + _HomePageState createState() => _HomePageState(); +} + +class _HomePageState extends State { + @override + Widget build(BuildContext context) { + return BaseView( + onModelReady: (model) => model.getHospitals(), + builder: (BuildContext context, HospitalViewModel model, Widget child) => + AppScaffold( + baseViewModel: model, + body: Column( + children: [ + InkWell( + onTap: () { + model.getHospitals(); + }, + child: Container( + child: Texts('call api '), + ), + + ), + Expanded( + child: _getHospitals(model.hospitals), + ) +// BaseView( +// onModelReady: (dctorViewModel) => dctorViewModel.getHospitals(), +// builder: (BuildContext context, DoctorViewModel dctorViewModel, +// Widget child) => +// InkWell( +// onTap: () { +// dctorViewModel.getHospitals(); +// }, +// child: Container( +// width: double.infinity, +// height: 150, +// child: NetworkBaseView( +// baseViewModel: dctorViewModel, +// child: Container( +// child: Texts('The API 2'), +// ), +// ), +// ), +// ), +// ), + ], + ), + ), + ); + } + + Widget _getHospitals(List hospitals) => ListView.builder( + itemCount: hospitals.length, + itemBuilder: (BuildContext context, int index) => Container( + child: Texts(hospitals[index].name), + ), + ); +} diff --git a/lib/pages/landing_page.dart b/lib/pages/landing/landing_page.dart similarity index 92% rename from lib/pages/landing_page.dart rename to lib/pages/landing/landing_page.dart index 20eac20a..16c94c4c 100644 --- a/lib/pages/landing_page.dart +++ b/lib/pages/landing/landing_page.dart @@ -1,9 +1,12 @@ +import 'package:diplomaticquarterapp/pages/landing/replay_page.dart'; import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; import 'package:diplomaticquarterapp/widgets/bottom_navigation/bottom_nav_bar.dart'; import 'package:diplomaticquarterapp/widgets/drawer/app_drawer_widget.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'home_page.dart'; + class LandingPage extends StatefulWidget { @override _LandingPageState createState() => _LandingPageState(); @@ -52,7 +55,7 @@ class _LandingPageState extends State { body: PageView( physics: NeverScrollableScrollPhysics(), controller: pageController, - children: [Container(), Container(), Container(), Container()], + children: [HomePage(), ReplayPage(), Container(), Container()], ), bottomNavigationBar: BottomNavBar(changeIndex: _changeCurrentTab), ); diff --git a/lib/pages/landing/replay_page.dart b/lib/pages/landing/replay_page.dart new file mode 100644 index 00000000..368f7a1c --- /dev/null +++ b/lib/pages/landing/replay_page.dart @@ -0,0 +1,15 @@ +import 'package:diplomaticquarterapp/widgets/data_display/text.dart'; +import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class ReplayPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return AppScaffold( + body: Center( + child: InkWell(onTap: () {}, child: Texts('Replay Page')), + ), + ); + } +} diff --git a/lib/uitl/utils.dart b/lib/uitl/utils.dart index 02d66c01..1c2da2b6 100644 --- a/lib/uitl/utils.dart +++ b/lib/uitl/utils.dart @@ -1,12 +1,12 @@ - import 'package:connectivity/connectivity.dart'; +import 'package:flutter/cupertino.dart'; + import 'app_shared_preferences.dart'; import 'app_toast.dart'; AppSharedPreferences sharedPref = new AppSharedPreferences(); class Utils { - ///show custom Error Toast /// [message] to show for user static showErrorToast([String message]) { @@ -37,4 +37,9 @@ class Utils { } return localMsg; } + + /// hides the keyboard if its already open + static hideKeyboard(BuildContext context) { + FocusScope.of(context).unfocus(); + } } diff --git a/lib/widgets/buttons/BottomButton.dart b/lib/widgets/buttons/BottomButton.dart new file mode 100644 index 00000000..3e85aa1e --- /dev/null +++ b/lib/widgets/buttons/BottomButton.dart @@ -0,0 +1,148 @@ +import 'package:diplomaticquarterapp/widgets/buttons/secondary_button.dart'; +import 'package:flutter/material.dart'; + +/// [label] button label +/// [icon] button icon its optional +/// [color] the background color +/// [textColor] the text color +/// [onTap] button function +/// [loading] show the progress indicator +/// [disabled] disabled the button +/// [borderColor] the button border color +/// [child] the child inside the button +/// [disabledPadding] remove padding +class BottomButton extends StatelessWidget { + final bool loading; + final bool disabled; + final String label; + final Widget icon; + final Color color; + final Color textColor; + final Color borderColor; + final Function onTap; + final Widget child; + final bool disabledPadding; + + BottomButton( + {Key key, + this.loading = false, + this.disabled = false, + this.label, + this.icon, + this.color, + this.textColor, + this.disabledPadding = false, + this.borderColor, + this.onTap, + this.child}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.bottomCenter, + end: Alignment.topCenter, + stops: [ + 0.0, + 0.9 + ], + colors: [ + Theme.of(context).backgroundColor, + Theme.of(context).backgroundColor.withOpacity(0) + ]), + ), + alignment: Alignment.center, + child: SafeArea( + top: false, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + margin: child != null + ? EdgeInsets.only( + left: 14.0, right: 14.0, top: 14.0, bottom: 14) + : EdgeInsets.only( + left: 30.0, right: 30.0, top: 14.0, bottom: 14), + decoration: BoxDecoration( + color: child != null + ? Theme.of(context).backgroundColor + : null, + border: child != null + ? Border.all( + color: Theme.of(context).dividerColor, width: 2.0) + : Border.all(color: Colors.transparent, width: 0.0), + borderRadius: child != null + ? BorderRadius.circular(16.0) + : BorderRadius.circular(0.0), + boxShadow: child != null + ? [ + BoxShadow( + color: Color.fromRGBO(0, 0, 0, 0.04), + spreadRadius: -0.0, + offset: Offset(0, 4.0), + blurRadius: 18.0) + ] + : []), + child: Column( + children: [ + if (child != null) + Padding( + padding: disabledPadding + ? EdgeInsets.only( + left: 0.0, + right: 0.0, + top: 14.0, + bottom: label != null ? 0.0 : 14) + : EdgeInsets.only( + left: 18.0, + right: 18.0, + top: 14.0, + bottom: label != null ? 0.0 : 14), + child: child, + ), + if (child != null) + Padding( + padding: EdgeInsets.only(top: 14.0, bottom: 14), + child: Divider(), + ), + if (label != null) + label == null + ? SizedBox(height: 50.0) + : Padding( + padding: child != null + ? EdgeInsets.only( + bottom: 16.0, left: 16.0, right: 16.0) + : EdgeInsets.zero, + child: SecondaryButton( + borderColor: borderColor, + onTap: () { + if (onTap != null) onTap(); + }, + loading: loading, + disabled: disabled, + label: label, + icon: icon, + color: color, + textColor: textColor), + ), + ], + ), + ), + if (label == null && child == null) + Padding( + padding: EdgeInsets.only( + left: 30.0, right: 30.0, top: 14.0, bottom: 14), + ), + ], + ), + ), + ), + ], + ); + } +} diff --git a/lib/widgets/buttons/button.dart b/lib/widgets/buttons/button.dart index d5d8f34e..d63babb5 100644 --- a/lib/widgets/buttons/button.dart +++ b/lib/widgets/buttons/button.dart @@ -1,4 +1,6 @@ import 'package:flutter/material.dart'; +import 'package:hexcolor/hexcolor.dart'; + /// Button widget /// [label] button label /// [icon] button icon its optional @@ -100,24 +102,12 @@ class _ButtonState extends State