Merge issue 1.0
@ -0,0 +1,93 @@
|
|||||||
|
Copyright (c) 2014-2015 Wei Huang (wweeiihhuuaanngg@gmail.com)
|
||||||
|
|
||||||
|
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||||
|
This license is copied below, and is also available with a FAQ at:
|
||||||
|
http://scripts.sil.org/OFL
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
PREAMBLE
|
||||||
|
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||||
|
development of collaborative font projects, to support the font creation
|
||||||
|
efforts of academic and linguistic communities, and to provide a free and
|
||||||
|
open framework in which fonts may be shared and improved in partnership
|
||||||
|
with others.
|
||||||
|
|
||||||
|
The OFL allows the licensed fonts to be used, studied, modified and
|
||||||
|
redistributed freely as long as they are not sold by themselves. The
|
||||||
|
fonts, including any derivative works, can be bundled, embedded,
|
||||||
|
redistributed and/or sold with any software provided that any reserved
|
||||||
|
names are not used by derivative works. The fonts and derivatives,
|
||||||
|
however, cannot be released under any other type of license. The
|
||||||
|
requirement for fonts to remain under this license does not apply
|
||||||
|
to any document created using the fonts or their derivatives.
|
||||||
|
|
||||||
|
DEFINITIONS
|
||||||
|
"Font Software" refers to the set of files released by the Copyright
|
||||||
|
Holder(s) under this license and clearly marked as such. This may
|
||||||
|
include source files, build scripts and documentation.
|
||||||
|
|
||||||
|
"Reserved Font Name" refers to any names specified as such after the
|
||||||
|
copyright statement(s).
|
||||||
|
|
||||||
|
"Original Version" refers to the collection of Font Software components as
|
||||||
|
distributed by the Copyright Holder(s).
|
||||||
|
|
||||||
|
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||||
|
or substituting -- in part or in whole -- any of the components of the
|
||||||
|
Original Version, by changing formats or by porting the Font Software to a
|
||||||
|
new environment.
|
||||||
|
|
||||||
|
"Author" refers to any designer, engineer, programmer, technical
|
||||||
|
writer or other person who contributed to the Font Software.
|
||||||
|
|
||||||
|
PERMISSION & CONDITIONS
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||||
|
redistribute, and sell modified and unmodified copies of the Font
|
||||||
|
Software, subject to the following conditions:
|
||||||
|
|
||||||
|
1) Neither the Font Software nor any of its individual components,
|
||||||
|
in Original or Modified Versions, may be sold by itself.
|
||||||
|
|
||||||
|
2) Original or Modified Versions of the Font Software may be bundled,
|
||||||
|
redistributed and/or sold with any software, provided that each copy
|
||||||
|
contains the above copyright notice and this license. These can be
|
||||||
|
included either as stand-alone text files, human-readable headers or
|
||||||
|
in the appropriate machine-readable metadata fields within text or
|
||||||
|
binary files as long as those fields can be easily viewed by the user.
|
||||||
|
|
||||||
|
3) No Modified Version of the Font Software may use the Reserved Font
|
||||||
|
Name(s) unless explicit written permission is granted by the corresponding
|
||||||
|
Copyright Holder. This restriction only applies to the primary font name as
|
||||||
|
presented to the users.
|
||||||
|
|
||||||
|
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||||
|
Software shall not be used to promote, endorse or advertise any
|
||||||
|
Modified Version, except to acknowledge the contribution(s) of the
|
||||||
|
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
5) The Font Software, modified or unmodified, in part or in whole,
|
||||||
|
must be distributed entirely under this license, and must not be
|
||||||
|
distributed under any other license. The requirement for fonts to
|
||||||
|
remain under this license does not apply to any document created
|
||||||
|
using the Font Software.
|
||||||
|
|
||||||
|
TERMINATION
|
||||||
|
This license becomes null and void if any of the above conditions are
|
||||||
|
not met.
|
||||||
|
|
||||||
|
DISCLAIMER
|
||||||
|
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||||
|
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||||
|
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||||
|
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||||
|
After Width: | Height: | Size: 488 B |
@ -0,0 +1,9 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="38.595" height="38.024" viewBox="0 0 38.595 38.024">
|
||||||
|
<g id="fingerprint1-scan" transform="translate(0.342 0.655)">
|
||||||
|
<path id="Path_4539" data-name="Path 4539" d="M38.892,0H33.378A1.379,1.379,0,0,0,32,1.378v8.27a1.378,1.378,0,0,0,2.757,0V2.757h4.135a1.378,1.378,0,1,0,0-2.757Z" transform="translate(-32.342 -0.655)" fill="#28323a"/>
|
||||||
|
<path id="Path_4540" data-name="Path 4540" d="M38.892,200.27H34.757v-6.892a1.378,1.378,0,1,0-2.757,0v8.27a1.379,1.379,0,0,0,1.378,1.378h5.514a1.378,1.378,0,1,0,0-2.757Z" transform="translate(-32.342 -165.658)" fill="#28323a"/>
|
||||||
|
<path id="Path_4541" data-name="Path 4541" d="M390.892,0h-5.514a1.378,1.378,0,0,0,0,2.757h4.135V9.649a1.378,1.378,0,0,0,2.757,0V1.378A1.379,1.379,0,0,0,390.892,0Z" transform="translate(-354.018 -0.655)" fill="#28323a"/>
|
||||||
|
<path id="Path_4542" data-name="Path 4542" d="M390.892,192a1.379,1.379,0,0,0-1.378,1.378v6.892h-4.135a1.378,1.378,0,0,0,0,2.757h5.514a1.379,1.379,0,0,0,1.378-1.378v-8.27A1.379,1.379,0,0,0,390.892,192Z" transform="translate(-354.018 -165.658)" fill="#28323a"/>
|
||||||
|
<path id="Path_4648" data-name="Path 4648" d="M13.343,0A13.343,13.343,0,1,0,26.686,13.343,13.343,13.343,0,0,0,13.343,0Zm4.924,8.9a1.911,1.911,0,1,1-1.911,1.911A1.912,1.912,0,0,1,18.267,8.9Zm-9.849,0a1.911,1.911,0,1,1-1.911,1.911A1.912,1.912,0,0,1,8.418,8.9Zm12.124,9.083a8.733,8.733,0,0,1-14.4,0A1.169,1.169,0,1,1,8.07,16.657a6.4,6.4,0,0,0,10.55,0,1.168,1.168,0,1,1,1.923,1.325Z" transform="translate(5.611 4.855)" fill="#28323a"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
@ -0,0 +1,11 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="38.595" height="38.024" viewBox="0 0 38.595 38.024">
|
||||||
|
<g id="sms-speech-bubble" transform="translate(-1 1.645)">
|
||||||
|
<g id="textsms">
|
||||||
|
<path id="Path_4529" data-name="Path 4529" d="M21.992,0H2.444A2.451,2.451,0,0,0,0,2.444V24.436l4.887-4.887h17.1A2.451,2.451,0,0,0,24.436,17.1V2.444A2.451,2.451,0,0,0,21.992,0ZM8.552,11H6.109V8.552H8.552Zm4.887,0H11V8.552H13.44Zm4.887,0H15.883V8.552h2.444Z" transform="translate(8.144 5.013)" fill="#28323a"/>
|
||||||
|
<path id="Path_4543" data-name="Path 4543" d="M38.892,0H33.378A1.379,1.379,0,0,0,32,1.378v8.27a1.378,1.378,0,0,0,2.757,0V2.757h4.135a1.378,1.378,0,1,0,0-2.757Z" transform="translate(-31 -1.645)" fill="#28323a"/>
|
||||||
|
<path id="Path_4544" data-name="Path 4544" d="M38.892,200.27H34.757v-6.892a1.378,1.378,0,1,0-2.757,0v8.27a1.379,1.379,0,0,0,1.378,1.378h5.514a1.378,1.378,0,1,0,0-2.757Z" transform="translate(-31 -166.648)" fill="#28323a"/>
|
||||||
|
<path id="Path_4545" data-name="Path 4545" d="M390.892,0h-5.514a1.378,1.378,0,0,0,0,2.757h4.135V9.649a1.378,1.378,0,0,0,2.757,0V1.378A1.379,1.379,0,0,0,390.892,0Z" transform="translate(-352.676 -1.645)" fill="#28323a"/>
|
||||||
|
<path id="Path_4546" data-name="Path 4546" d="M390.892,192a1.379,1.379,0,0,0-1.378,1.378v6.892h-4.135a1.378,1.378,0,0,0,0,2.757h5.514a1.379,1.379,0,0,0,1.378-1.378v-8.27A1.379,1.379,0,0,0,390.892,192Z" transform="translate(-352.676 -166.648)" fill="#28323a"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.4 KiB |
@ -0,0 +1,9 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="38.595" height="38.024" viewBox="0 0 38.595 38.024">
|
||||||
|
<g id="fingerprint-scan" transform="translate(0.342 0.655)">
|
||||||
|
<path id="Path_4535" data-name="Path 4535" d="M24,0H2.909A2.913,2.913,0,0,0,0,2.909V24a2.913,2.913,0,0,0,2.909,2.909H24A2.913,2.913,0,0,0,26.913,24V2.909A2.913,2.913,0,0,0,24,0ZM5,5.182c5.592-4.061,11.49-4.018,17,.072a.789.789,0,0,1-.47,1.422c-.894,0-6.986-6.478-15.607-.218A.788.788,0,0,1,5,5.182Zm7.349,20.277a.788.788,0,0,1-1.1-.2c-1.111-1.606-3.634-3.4-3.634-6.757a6.063,6.063,0,0,1,5.835-6.255A6.063,6.063,0,0,1,19.291,18.5v.841a.788.788,0,0,1-1.577,0V18.5a4.488,4.488,0,0,0-4.258-4.678A4.488,4.488,0,0,0,9.2,18.5C9.2,22.3,14.037,24.294,12.353,25.459Zm9.8-4.08a4.132,4.132,0,0,1-7.8-2.035c0-3.4-2.327-2.255-1.811-.191a.788.788,0,0,1-1.53.383c-1.074-4.295,4.917-6.037,4.917-.191A2.544,2.544,0,0,0,17.9,21.971c3.65.861,4.733-5.161,1.093-9.037-5.033-5.363-13.16-1.227-13.16,5.148A6.378,6.378,0,0,0,6.95,22.25a.788.788,0,0,1-1.284.916,8.033,8.033,0,0,1-1.408-5.084,9.351,9.351,0,0,1,9.2-9.2c6.8,0,11.128,7.628,8.7,12.5Zm.527-9.761a.788.788,0,0,1-1.075-.293C20.033,8.578,16.234,7.1,13.457,7.1a11.282,11.282,0,0,0-8.175,4.275A.788.788,0,0,1,3.97,10.5a12.781,12.781,0,0,1,9.487-4.977c5.841,0,11.056,5.05,9.222,6.1Z" transform="translate(5.793 4.943)" fill="#28323a"/>
|
||||||
|
<path id="Path_4539" data-name="Path 4539" d="M38.892,0H33.378A1.379,1.379,0,0,0,32,1.378v8.27a1.378,1.378,0,0,0,2.757,0V2.757h4.135a1.378,1.378,0,1,0,0-2.757Z" transform="translate(-32.342 -0.655)" fill="#28323a"/>
|
||||||
|
<path id="Path_4540" data-name="Path 4540" d="M38.892,200.27H34.757v-6.892a1.378,1.378,0,1,0-2.757,0v8.27a1.379,1.379,0,0,0,1.378,1.378h5.514a1.378,1.378,0,1,0,0-2.757Z" transform="translate(-32.342 -165.658)" fill="#28323a"/>
|
||||||
|
<path id="Path_4541" data-name="Path 4541" d="M390.892,0h-5.514a1.378,1.378,0,0,0,0,2.757h4.135V9.649a1.378,1.378,0,0,0,2.757,0V1.378A1.379,1.379,0,0,0,390.892,0Z" transform="translate(-354.018 -0.655)" fill="#28323a"/>
|
||||||
|
<path id="Path_4542" data-name="Path 4542" d="M390.892,192a1.379,1.379,0,0,0-1.378,1.378v6.892h-4.135a1.378,1.378,0,0,0,0,2.757h5.514a1.379,1.379,0,0,0,1.378-1.378v-8.27A1.379,1.379,0,0,0,390.892,192Z" transform="translate(-354.018 -165.658)" fill="#28323a"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.2 KiB |
@ -0,0 +1,12 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="38.595" height="38.024" viewBox="0 0 38.595 38.024">
|
||||||
|
<g id="whatsapp_1_" data-name="whatsapp (1)" transform="translate(0.233 -4.309)">
|
||||||
|
<g id="Group_7424" data-name="Group 7424" transform="translate(4.808 8.729)">
|
||||||
|
<path id="Path_4537" data-name="Path 4537" d="M0,28.186l2.424-7.271a13.848,13.848,0,1,1,5.468,5.195Z" fill="#2cb742"/>
|
||||||
|
<path id="Path_4538" data-name="Path 4538" d="M29.341,23.6c-.64-1.209-3-2.591-3-2.591-.534-.3-1.177-.338-1.482.2a12.215,12.215,0,0,1-.961,1.051,1.791,1.791,0,0,1-2.547-.253l-1.935-1.935-1.935-1.935A1.791,1.791,0,0,1,17.23,15.6a12.216,12.216,0,0,1,1.051-.961c.542-.3.508-.948.2-1.482,0,0-1.382-2.358-2.591-3a1.325,1.325,0,0,0-1.557.234l-.854.854c-2.71,2.71-1.376,5.77,1.334,8.48L17.3,22.2l2.477,2.477c2.71,2.71,5.77,4.045,8.48,1.334l.854-.854A1.326,1.326,0,0,0,29.341,23.6Z" transform="translate(-6.169 -5.141)" fill="#fff"/>
|
||||||
|
</g>
|
||||||
|
<path id="Path_4547" data-name="Path 4547" d="M38.892,0H33.378A1.379,1.379,0,0,0,32,1.378v8.27a1.378,1.378,0,0,0,2.757,0V2.757h4.135a1.378,1.378,0,1,0,0-2.757Z" transform="translate(-32.233 4.309)" fill="#28323a"/>
|
||||||
|
<path id="Path_4548" data-name="Path 4548" d="M38.892,200.27H34.757v-6.892a1.378,1.378,0,1,0-2.757,0v8.27a1.379,1.379,0,0,0,1.378,1.378h5.514a1.378,1.378,0,1,0,0-2.757Z" transform="translate(-32.233 -160.693)" fill="#28323a"/>
|
||||||
|
<path id="Path_4549" data-name="Path 4549" d="M390.892,0h-5.514a1.378,1.378,0,0,0,0,2.757h4.135V9.649a1.378,1.378,0,0,0,2.757,0V1.378A1.379,1.379,0,0,0,390.892,0Z" transform="translate(-353.909 4.309)" fill="#28323a"/>
|
||||||
|
<path id="Path_4550" data-name="Path 4550" d="M390.892,192a1.379,1.379,0,0,0-1.378,1.378v6.892h-4.135a1.378,1.378,0,0,0,0,2.757h5.514a1.379,1.379,0,0,0,1.378-1.378v-8.27A1.379,1.379,0,0,0,390.892,192Z" transform="translate(-353.909 -160.693)" fill="#28323a"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 549 B |
|
After Width: | Height: | Size: 453 B |
|
After Width: | Height: | Size: 453 B |
|
After Width: | Height: | Size: 988 B |
|
After Width: | Height: | Size: 652 B |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 733 B |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 940 B |
|
After Width: | Height: | Size: 417 B |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 995 B |
|
After Width: | Height: | Size: 854 B |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 399 B |
@ -1 +1,2 @@
|
|||||||
|
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
|
||||||
#include "Generated.xcconfig"
|
#include "Generated.xcconfig"
|
||||||
|
|||||||
@ -1 +1,2 @@
|
|||||||
|
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
|
||||||
#include "Generated.xcconfig"
|
#include "Generated.xcconfig"
|
||||||
|
|||||||
@ -0,0 +1,22 @@
|
|||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hmg_nurses/classes/enums.dart';
|
||||||
|
|
||||||
|
class BaseViewModel extends ChangeNotifier {
|
||||||
|
|
||||||
|
ViewState _state = ViewState.idle;
|
||||||
|
bool isInternetConnection = true;
|
||||||
|
|
||||||
|
ViewState get state => _state;
|
||||||
|
|
||||||
|
String error = "";
|
||||||
|
|
||||||
|
//TODO add the user login model when we need it
|
||||||
|
|
||||||
|
void setState(ViewState viewState) {
|
||||||
|
_state = viewState;
|
||||||
|
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
enum APPSTATUS { loading, unAuthenticated, authenticated, unverified }
|
||||||
|
enum AuthMethodTypes { sms, whatsApp, fingerPrint, faceID, moreOptions }
|
||||||
|
enum ViewState { idle, busy, error, busyLocal, errorLocal }
|
||||||
@ -0,0 +1,103 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:hmg_nurses/classes/consts.dart';
|
||||||
|
|
||||||
|
class SizeConfig {
|
||||||
|
static double _blockWidth = 0;
|
||||||
|
static double _blockHeight = 0;
|
||||||
|
|
||||||
|
static double? realScreenWidth;
|
||||||
|
static double? realScreenHeight;
|
||||||
|
static double? screenWidth;
|
||||||
|
static double? screenHeight;
|
||||||
|
static double? textMultiplier;
|
||||||
|
static double? imageSizeMultiplier;
|
||||||
|
static double? heightMultiplier;
|
||||||
|
static bool isPortrait = true;
|
||||||
|
static double? widthMultiplier;
|
||||||
|
static bool isMobilePortrait = false;
|
||||||
|
static bool isMobile = false;
|
||||||
|
static bool isHeightShort = false;
|
||||||
|
static bool isHeightVeryShort = false;
|
||||||
|
static bool isHeightMiddle = false;
|
||||||
|
static bool isHeightLarge = false;
|
||||||
|
static bool isWidthLarge = false;
|
||||||
|
|
||||||
|
void init(BoxConstraints constraints, Orientation orientation) {
|
||||||
|
realScreenHeight = constraints.maxHeight;
|
||||||
|
realScreenWidth = constraints.maxWidth;
|
||||||
|
if (constraints.maxWidth <= ApiConsts.MAX_SMALL_SCREEN) {
|
||||||
|
isMobile = true;
|
||||||
|
}
|
||||||
|
if (constraints.maxHeight < 600) {
|
||||||
|
isHeightVeryShort = true;
|
||||||
|
} else if (constraints.maxHeight < 800) {
|
||||||
|
isHeightShort = true;
|
||||||
|
} else if (constraints.maxHeight < 1000) {
|
||||||
|
isHeightMiddle = true;
|
||||||
|
} else {
|
||||||
|
isHeightLarge = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (constraints.maxWidth > 600) {
|
||||||
|
isWidthLarge = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (orientation == Orientation.portrait) {
|
||||||
|
isPortrait = true;
|
||||||
|
if (realScreenWidth! < 450) {
|
||||||
|
isMobilePortrait = true;
|
||||||
|
}
|
||||||
|
// textMultiplier = _blockHeight;
|
||||||
|
// imageSizeMultiplier = _blockWidth;
|
||||||
|
screenHeight = realScreenHeight;
|
||||||
|
screenWidth = realScreenWidth;
|
||||||
|
} else {
|
||||||
|
isPortrait = false;
|
||||||
|
isMobilePortrait = false;
|
||||||
|
// textMultiplier = _blockWidth;
|
||||||
|
// imageSizeMultiplier = _blockHeight;
|
||||||
|
screenHeight = realScreenWidth;
|
||||||
|
screenWidth = realScreenHeight;
|
||||||
|
}
|
||||||
|
_blockWidth = screenWidth! / 100;
|
||||||
|
_blockHeight = screenHeight! / 100;
|
||||||
|
|
||||||
|
textMultiplier = _blockHeight;
|
||||||
|
imageSizeMultiplier = _blockWidth;
|
||||||
|
heightMultiplier = _blockHeight;
|
||||||
|
widthMultiplier = _blockWidth;
|
||||||
|
|
||||||
|
print('realScreenWidth $realScreenWidth');
|
||||||
|
print('realScreenHeight $realScreenHeight');
|
||||||
|
print('textMultiplier $textMultiplier');
|
||||||
|
print('imageSizeMultiplier $imageSizeMultiplier');
|
||||||
|
print('heightMultiplier$heightMultiplier');
|
||||||
|
print('widthMultiplier $widthMultiplier');
|
||||||
|
print('isPortrait $isPortrait');
|
||||||
|
print('isMobilePortrait $isMobilePortrait');
|
||||||
|
}
|
||||||
|
|
||||||
|
static getTextMultiplierBasedOnWidth({double? width}) {
|
||||||
|
// TODO handel LandScape case
|
||||||
|
if (width != null) {
|
||||||
|
return width / 100;
|
||||||
|
}
|
||||||
|
return widthMultiplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
static getWidthMultiplier({double? width}) {
|
||||||
|
// TODO handel LandScape case
|
||||||
|
if (width != null) {
|
||||||
|
return width / 100;
|
||||||
|
}
|
||||||
|
return widthMultiplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
static getHeightMultiplier({double? height}) {
|
||||||
|
// TODO handel LandScape case
|
||||||
|
if (height != null) {
|
||||||
|
return height / 100;
|
||||||
|
}
|
||||||
|
return heightMultiplier;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,19 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
|
|
||||||
class AppProvider extends StatelessWidget {
|
|
||||||
final Widget child;
|
|
||||||
|
|
||||||
AppProvider({required this.child});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return child;
|
|
||||||
return MultiProvider(
|
|
||||||
providers: [
|
|
||||||
// ChangeNotifierProvider(create: (_) => Counter()),
|
|
||||||
],
|
|
||||||
child: child,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
import 'package:get_it/get_it.dart';
|
||||||
|
import 'package:hmg_nurses/ui/login/login_vm.dart';
|
||||||
|
|
||||||
|
GetIt getIt = GetIt.instance;
|
||||||
|
|
||||||
|
|
||||||
|
void initDependencies () {
|
||||||
|
// TODO; WE WILL REGISTER ALL THE SERVICES HERE AS LAZY SINGLETON
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//TODO: WE WILL REGISTER ALL THE VIEW MODELS AS FACTORY HERE
|
||||||
|
|
||||||
|
/// View Model
|
||||||
|
getIt.registerFactory(() => LoginViewModel());
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
import 'package:hmg_nurses/classes/enums.dart';
|
||||||
|
|
||||||
|
extension SelectedAuthMethodTypesService on AuthMethodTypes {
|
||||||
|
int getTypeIdService() {
|
||||||
|
switch (this) {
|
||||||
|
case AuthMethodTypes.sms:
|
||||||
|
return 1;
|
||||||
|
case AuthMethodTypes.whatsApp:
|
||||||
|
return 2;
|
||||||
|
case AuthMethodTypes.fingerPrint:
|
||||||
|
return 3;
|
||||||
|
case AuthMethodTypes.faceID:
|
||||||
|
return 4;
|
||||||
|
case AuthMethodTypes.moreOptions:
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static getMethodsTypeService(int typeId) {
|
||||||
|
switch (typeId) {
|
||||||
|
case 1:
|
||||||
|
return AuthMethodTypes.sms;
|
||||||
|
case 2:
|
||||||
|
return AuthMethodTypes.whatsApp;
|
||||||
|
case 3:
|
||||||
|
return AuthMethodTypes.fingerPrint;
|
||||||
|
case 4:
|
||||||
|
return AuthMethodTypes.faceID;
|
||||||
|
case 5:
|
||||||
|
return AuthMethodTypes.moreOptions;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,64 @@
|
|||||||
|
class GetMobileLoginInfoListModel {
|
||||||
|
int? iD;
|
||||||
|
int? employeeID;
|
||||||
|
int? channelID;
|
||||||
|
int? companyID;
|
||||||
|
String? deviceType;
|
||||||
|
String? deviceToken;
|
||||||
|
int? language;
|
||||||
|
int? gender;
|
||||||
|
int? loginType;
|
||||||
|
String? createdOn;
|
||||||
|
String? editedOn;
|
||||||
|
String? employeeName;
|
||||||
|
bool? businessCardPrivilege;
|
||||||
|
|
||||||
|
GetMobileLoginInfoListModel(
|
||||||
|
{this.iD,
|
||||||
|
this.employeeID,
|
||||||
|
this.channelID,
|
||||||
|
this.companyID,
|
||||||
|
this.deviceType,
|
||||||
|
this.deviceToken,
|
||||||
|
this.language,
|
||||||
|
this.gender,
|
||||||
|
this.loginType,
|
||||||
|
this.createdOn,
|
||||||
|
this.editedOn,
|
||||||
|
this.employeeName,
|
||||||
|
this.businessCardPrivilege});
|
||||||
|
|
||||||
|
GetMobileLoginInfoListModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
iD = json['ID'];
|
||||||
|
employeeID = json['EmployeeID'];
|
||||||
|
channelID = json['ChannelID'];
|
||||||
|
companyID = json['CompanyID'];
|
||||||
|
deviceType = json['DeviceType'];
|
||||||
|
deviceToken = json['DeviceToken'];
|
||||||
|
language = json['Language'];
|
||||||
|
gender = json['Gender'];
|
||||||
|
loginType = json['LoginType'];
|
||||||
|
createdOn = json['CreatedOn'];
|
||||||
|
editedOn = json['EditedOn'];
|
||||||
|
employeeName = json['EmployeeName'];
|
||||||
|
businessCardPrivilege = json['BusinessCardPrivilege'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
Map<String, dynamic> data = Map<String, dynamic>();
|
||||||
|
data['ID'] = iD;
|
||||||
|
data['EmployeeID'] = employeeID;
|
||||||
|
data['ChannelID'] = channelID;
|
||||||
|
data['CompanyID'] = companyID;
|
||||||
|
data['DeviceType'] = deviceType;
|
||||||
|
data['DeviceToken'] = deviceToken;
|
||||||
|
data['Language'] = language;
|
||||||
|
data['Gender'] = gender;
|
||||||
|
data['LoginType'] = loginType;
|
||||||
|
data['CreatedOn'] = createdOn;
|
||||||
|
data['EditedOn'] = editedOn;
|
||||||
|
data['EmployeeName'] = employeeName;
|
||||||
|
data['BusinessCardPrivilege'] = businessCardPrivilege;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,310 @@
|
|||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:hexcolor/hexcolor.dart';
|
||||||
|
import 'package:hmg_nurses/classes/colors.dart';
|
||||||
|
import 'package:hmg_nurses/classes/enums.dart';
|
||||||
|
import 'package:hmg_nurses/classes/size_config.dart';
|
||||||
|
import 'package:hmg_nurses/extensions/string_extensions.dart';
|
||||||
|
import 'package:hmg_nurses/extensions/util_extensions.dart';
|
||||||
|
import 'package:hmg_nurses/extensions/widget_extensions.dart';
|
||||||
|
import 'package:hmg_nurses/generated/locale_keys.g.dart';
|
||||||
|
import 'package:hmg_nurses/ui/login/login_vm.dart';
|
||||||
|
import 'package:hmg_nurses/ui/login/widgets/verification_method_card.dart';
|
||||||
|
import 'package:hmg_nurses/widgets/button/default_button.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:sizer/sizer.dart';
|
||||||
|
|
||||||
|
// WhatsApp 2
|
||||||
|
// SMS 1
|
||||||
|
// Face ID 3
|
||||||
|
// Finger Print 4
|
||||||
|
|
||||||
|
class LoginMethodsPage extends StatefulWidget {
|
||||||
|
const LoginMethodsPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
LoginMethodsPageState createState() => LoginMethodsPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class LoginMethodsPageState extends State<LoginMethodsPage> {
|
||||||
|
bool isMoreOption = false;
|
||||||
|
bool onlySMSBox = false;
|
||||||
|
late AuthMethodTypes fingerPrintBefore;
|
||||||
|
late AuthMethodTypes selectedOption;
|
||||||
|
late LoginViewModel loginViewModel;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
loginViewModel = context.read<LoginViewModel>();
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
leading: IconButton(
|
||||||
|
icon: const Icon(Icons.arrow_back_ios, color: MyColors.darkIconColor),
|
||||||
|
onPressed: () => Navigator.pop(context),
|
||||||
|
),
|
||||||
|
// actions: [Center(child: "Employee Digital ID".toText12(color: MyColors.textMixColor, isUnderLine: true).onPress(() {})), 21.width],
|
||||||
|
),
|
||||||
|
body: SingleChildScrollView(
|
||||||
|
child: Center(
|
||||||
|
child: FractionallySizedBox(
|
||||||
|
widthFactor: 0.9,
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: <Widget>[
|
||||||
|
SizedBox(height: 1.h),
|
||||||
|
if (loginViewModel.isFromLogin)
|
||||||
|
InkWell(
|
||||||
|
onTap: () {
|
||||||
|
loginViewModel.setUnverified(false, isFromLogin: false);
|
||||||
|
loginViewModel.setAppStatus(APPSTATUS.unAuthenticated);
|
||||||
|
},
|
||||||
|
child: const Icon(Icons.arrow_back_ios, color: MyColors.darkTextColor)),
|
||||||
|
Column(
|
||||||
|
children: <Widget>[
|
||||||
|
SizedBox(height: 1.h),
|
||||||
|
|
||||||
|
isMoreOption != null && isMoreOption == false
|
||||||
|
? Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: <Widget>[
|
||||||
|
LocaleKeys.welcomeBack.tr().toText12(),
|
||||||
|
SizedBox(height: 1.h),
|
||||||
|
"Faiz Hashmi".toText24(isBold: true),
|
||||||
|
SizedBox(height: 3.h),
|
||||||
|
LocaleKeys.wouldYouLikeToLoginWithCurrentUsername.tr().toText18(),
|
||||||
|
SizedBox(height: 3.h),
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.all(12),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: const BorderRadius.all(Radius.circular(10)),
|
||||||
|
border: Border.all(color: HexColor('#707070'), width: 0.1),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: <Widget>[
|
||||||
|
Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
LocaleKeys.lastLoginDetails.tr(),
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'Poppins',
|
||||||
|
fontSize: SizeConfig.getTextMultiplierBasedOnWidth() * 4.8,
|
||||||
|
color: Color(0xFF2E303A),
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
letterSpacing: -0.4),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
width: MediaQuery.of(context).size.width * 0.55,
|
||||||
|
child: RichText(
|
||||||
|
text: TextSpan(
|
||||||
|
text: "${LocaleKeys.verificationType.tr()} ",
|
||||||
|
style: TextStyle(
|
||||||
|
color: const Color(0xFF575757),
|
||||||
|
fontSize: SizeConfig.getTextMultiplierBasedOnWidth() * 3.5,
|
||||||
|
fontFamily: 'Poppins',
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
letterSpacing: -0.4),
|
||||||
|
children: <TextSpan>[
|
||||||
|
TextSpan(
|
||||||
|
text: loginViewModel.getType(1),
|
||||||
|
style: TextStyle(
|
||||||
|
color: MyColors.darkTextColor,
|
||||||
|
fontSize: SizeConfig.getTextMultiplierBasedOnWidth() * 3.5,
|
||||||
|
fontFamily: 'Poppins',
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
letterSpacing: -0.48),
|
||||||
|
)
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"12 NOV, 2022",
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'Poppins',
|
||||||
|
fontSize: SizeConfig.getTextMultiplierBasedOnWidth() * 4.2,
|
||||||
|
color: Color(0xFF2E303A),
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
letterSpacing: -0.4),
|
||||||
|
),
|
||||||
|
|
||||||
|
Text(
|
||||||
|
"09:56 AM",
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'Poppins',
|
||||||
|
fontSize: SizeConfig.getTextMultiplierBasedOnWidth() * 3.5,
|
||||||
|
color: Color(0xFF2E303A),
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
letterSpacing: -0.4),
|
||||||
|
),
|
||||||
|
// AppText(
|
||||||
|
// loginViewModel.user.editedOn != null
|
||||||
|
// ? AppDateUtils.getDayMonthYearDateFormatted(AppDateUtils.convertStringToDate(loginViewModel.user.editedOn), isMonthShort: true)
|
||||||
|
// : loginViewModel.user.createdOn != null
|
||||||
|
// ? AppDateUtils.getDayMonthYearDateFormatted(AppDateUtils.convertStringToDate(loginViewModel.user.createdOn), isMonthShort: true)
|
||||||
|
// : '--',
|
||||||
|
// textAlign: TextAlign.right,
|
||||||
|
// fontSize: SizeConfig.getTextMultiplierBasedOnWidth() * 4.5,
|
||||||
|
// color: Color(0xFF2E303A),
|
||||||
|
// fontWeight: FontWeight.w700,
|
||||||
|
// letterSpacing: -0.48,
|
||||||
|
// ),
|
||||||
|
// AppText(
|
||||||
|
// loginViewModel.user.editedOn != null
|
||||||
|
// ? AppDateUtils.getHour(AppDateUtils.convertStringToDate(loginViewModel.user.editedOn))
|
||||||
|
// : loginViewModel.user.createdOn != null
|
||||||
|
// ? AppDateUtils.getHour(AppDateUtils.convertStringToDate(loginViewModel.user.createdOn))
|
||||||
|
// : '--',
|
||||||
|
// textAlign: TextAlign.right,
|
||||||
|
// fontSize: SizeConfig.getTextMultiplierBasedOnWidth() * 3.5,
|
||||||
|
// fontWeight: FontWeight.w600,
|
||||||
|
// letterSpacing: -0.48,
|
||||||
|
// color: Color(0xFF575757),
|
||||||
|
// )
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: SizeConfig.heightMultiplier! * 3),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
//todo add translation
|
||||||
|
LocaleKeys.pleaseVerify.tr().toText18().paddingOnly(left: 8),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: SizeConfig.heightMultiplier! * 2,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
: Column(mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[
|
||||||
|
onlySMSBox == true
|
||||||
|
? Container(
|
||||||
|
margin: const EdgeInsets.only(bottom: 20, top: 30),
|
||||||
|
child: LocaleKeys.pleaseVerify.tr().toText16(),
|
||||||
|
)
|
||||||
|
: LocaleKeys.pleaseVerify.tr().toText16(),
|
||||||
|
]),
|
||||||
|
isMoreOption != null && isMoreOption == false
|
||||||
|
? Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[
|
||||||
|
Row(mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[
|
||||||
|
Expanded(
|
||||||
|
child: VerificationMethodsList(
|
||||||
|
loginViewModel: loginViewModel,
|
||||||
|
authMethodType: SelectedAuthMethodTypesService.getMethodsTypeService(1),
|
||||||
|
authenticateUser: (AuthMethodTypes authMethodType, isActive) {
|
||||||
|
loginViewModel.startSMSService(authMethodType, context: context);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: VerificationMethodsList(
|
||||||
|
loginViewModel: loginViewModel,
|
||||||
|
authMethodType: AuthMethodTypes.moreOptions,
|
||||||
|
onShowMore: () {
|
||||||
|
setState(() {
|
||||||
|
isMoreOption = true;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
))
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
: Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[
|
||||||
|
onlySMSBox == false
|
||||||
|
? Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: <Widget>[
|
||||||
|
Expanded(
|
||||||
|
child: VerificationMethodsList(
|
||||||
|
loginViewModel: loginViewModel,
|
||||||
|
authMethodType: AuthMethodTypes.fingerPrint,
|
||||||
|
authenticateUser: (AuthMethodTypes authMethodType, isActive) {
|
||||||
|
loginViewModel.startSMSService(authMethodType, context: context);
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
Expanded(
|
||||||
|
child: VerificationMethodsList(
|
||||||
|
loginViewModel: loginViewModel,
|
||||||
|
authMethodType: AuthMethodTypes.faceID,
|
||||||
|
authenticateUser: (AuthMethodTypes authMethodType, isActive) {
|
||||||
|
loginViewModel.startSMSService(authMethodType, context: context);
|
||||||
|
},
|
||||||
|
))
|
||||||
|
],
|
||||||
|
)
|
||||||
|
: const SizedBox(),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: <Widget>[
|
||||||
|
Expanded(
|
||||||
|
child: VerificationMethodsList(
|
||||||
|
loginViewModel: loginViewModel,
|
||||||
|
authMethodType: AuthMethodTypes.sms,
|
||||||
|
authenticateUser: (AuthMethodTypes authMethodType, isActive) {
|
||||||
|
loginViewModel.startSMSService(authMethodType, context: context);
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
Expanded(
|
||||||
|
child: VerificationMethodsList(
|
||||||
|
loginViewModel: loginViewModel,
|
||||||
|
authMethodType: AuthMethodTypes.whatsApp,
|
||||||
|
authenticateUser: (AuthMethodTypes authMethodType, isActive) {
|
||||||
|
loginViewModel.startSMSService(authMethodType, context: context);
|
||||||
|
},
|
||||||
|
))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
|
||||||
|
// )
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
bottomSheet: !isMoreOption
|
||||||
|
? null
|
||||||
|
: Container(
|
||||||
|
height: 10.h,
|
||||||
|
color: MyColors.backgroundColor,
|
||||||
|
width: double.infinity,
|
||||||
|
child: Center(
|
||||||
|
child: FractionallySizedBox(
|
||||||
|
widthFactor: 0.9,
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: <Widget>[
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 4.w),
|
||||||
|
child: DefaultButton(LocaleKeys.useAnotherAccount.tr(), () {}, colors: const [MyColors.redColor, MyColors.redColor]),
|
||||||
|
),
|
||||||
|
SizedBox(height: 3.h)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,103 @@
|
|||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hmg_nurses/classes/colors.dart';
|
||||||
|
import 'package:hmg_nurses/config/routes.dart';
|
||||||
|
import 'package:hmg_nurses/generated/locale_keys.g.dart';
|
||||||
|
import 'package:hmg_nurses/widgets/button/default_button.dart';
|
||||||
|
import 'package:hmg_nurses/widgets/cupertino_picker.dart';
|
||||||
|
import 'package:hmg_nurses/widgets/input_widget.dart';
|
||||||
|
import 'package:sizer/sizer.dart';
|
||||||
|
|
||||||
|
class LoginPage extends StatefulWidget {
|
||||||
|
const LoginPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<LoginPage> createState() => _LoginPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _LoginPageState extends State<LoginPage> {
|
||||||
|
final loginFormKey = GlobalKey<FormState>();
|
||||||
|
var projectIdController = TextEditingController();
|
||||||
|
var userIdController = TextEditingController();
|
||||||
|
var passwordController = TextEditingController();
|
||||||
|
|
||||||
|
SizedBox buildSpacer20h() => SizedBox(height: 3.h);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
body: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
SizedBox(height: 10.h),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(left: 8.w),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
LocaleKeys.welcomeTo.tr(),
|
||||||
|
style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w600, fontFamily: 'Poppins'),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
LocaleKeys.drSulaiman.tr(),
|
||||||
|
style: TextStyle(color: MyColors.blackColor, fontWeight: FontWeight.bold, fontSize: 24.sp, fontFamily: 'Poppins'),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"Nurses App",
|
||||||
|
style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w600, color: MyColors.redColor),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 4.h),
|
||||||
|
Form(
|
||||||
|
key: loginFormKey,
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 8.w),
|
||||||
|
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||||
|
buildSpacer20h(),
|
||||||
|
CustomTextField(LocaleKeys.userID.tr(), userIdController, isEnableBorder: true, ),
|
||||||
|
buildSpacer20h(),
|
||||||
|
CustomTextField(LocaleKeys.password.tr(), passwordController, isTextIsPassword: true),
|
||||||
|
buildSpacer20h(),
|
||||||
|
CustomTextField(
|
||||||
|
LocaleKeys.branch.tr(),
|
||||||
|
projectIdController,
|
||||||
|
hasSelection: true,
|
||||||
|
isEnable: false,
|
||||||
|
onClick: () => CustomCupertinoPicker.showCupertinoPicker(context, [], () {}),
|
||||||
|
),
|
||||||
|
buildSpacer20h()
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
bottomSheet: Container(
|
||||||
|
height: 12.h,
|
||||||
|
color: MyColors.backgroundColor,
|
||||||
|
width: double.infinity,
|
||||||
|
child: Center(
|
||||||
|
child: FractionallySizedBox(
|
||||||
|
widthFactor: 0.9,
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: <Widget>[
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 4.w),
|
||||||
|
child: DefaultButton(LocaleKeys.login.tr(), () {
|
||||||
|
Navigator.pushNamed(context, AppRoutes.loginMethodsPage);
|
||||||
|
}, colors: const [MyColors.redColor, MyColors.redColor]),
|
||||||
|
),
|
||||||
|
SizedBox(height: 3.h)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,141 @@
|
|||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:hmg_nurses/base/base_vm.dart';
|
||||||
|
import 'package:hmg_nurses/classes/enums.dart';
|
||||||
|
import 'package:hmg_nurses/classes/utils.dart';
|
||||||
|
import 'package:hmg_nurses/dialogs/otp_dialog.dart';
|
||||||
|
import 'package:hmg_nurses/generated/locale_keys.g.dart';
|
||||||
|
import 'package:local_auth/local_auth.dart';
|
||||||
|
|
||||||
|
class LoginViewModel extends BaseViewModel {
|
||||||
|
bool isLogin = false;
|
||||||
|
bool unverified = false;
|
||||||
|
bool isFromLogin = false;
|
||||||
|
APPSTATUS appStatus = APPSTATUS.loading;
|
||||||
|
String localToken = "";
|
||||||
|
|
||||||
|
String nurseProfile = "";
|
||||||
|
|
||||||
|
final LocalAuthentication auth = LocalAuthentication();
|
||||||
|
late List<BiometricType> _availableBiometrics;
|
||||||
|
|
||||||
|
LoginViewModel();
|
||||||
|
|
||||||
|
/// get type name based on id.
|
||||||
|
getType(type) {
|
||||||
|
switch (type) {
|
||||||
|
case 1:
|
||||||
|
return LocaleKeys.sms.tr();
|
||||||
|
case 3:
|
||||||
|
return LocaleKeys.fingerPrint.tr();
|
||||||
|
case 4:
|
||||||
|
return LocaleKeys.face.tr();
|
||||||
|
case 2:
|
||||||
|
return LocaleKeys.whatsapp.tr();
|
||||||
|
default:
|
||||||
|
return LocaleKeys.sms.tr();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ask user to add his biometric
|
||||||
|
showIOSAuthMessages() async {
|
||||||
|
try {
|
||||||
|
await auth.authenticate(
|
||||||
|
localizedReason: 'Scan your fingerprint to authenticate',
|
||||||
|
);
|
||||||
|
} on PlatformException catch (e) {
|
||||||
|
if (kDebugMode) {
|
||||||
|
print(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// check specific biometric if it available or not
|
||||||
|
Future<bool> checkIfBiometricAvailable(BiometricType biometricType) async {
|
||||||
|
bool isAvailable = false;
|
||||||
|
await _getAvailableBiometrics();
|
||||||
|
if (_availableBiometrics != null) {
|
||||||
|
for (var i = 0; i < _availableBiometrics.length; i++) {
|
||||||
|
if (biometricType == _availableBiometrics[i]) isAvailable = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return isAvailable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get all available biometric on the device for local Auth service
|
||||||
|
Future<void> _getAvailableBiometrics() async {
|
||||||
|
try {
|
||||||
|
_availableBiometrics = await auth.getAvailableBiometrics();
|
||||||
|
} on PlatformException catch (e) {
|
||||||
|
if (kDebugMode) {
|
||||||
|
print(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// determine the status of the app
|
||||||
|
APPSTATUS get status {
|
||||||
|
if (state == ViewState.busy) {
|
||||||
|
appStatus = APPSTATUS.loading;
|
||||||
|
} else {
|
||||||
|
if (nurseProfile != null) {
|
||||||
|
appStatus = APPSTATUS.authenticated;
|
||||||
|
} else if (unverified) {
|
||||||
|
appStatus = APPSTATUS.unverified;
|
||||||
|
} else if (isLogin) {
|
||||||
|
appStatus = APPSTATUS.authenticated;
|
||||||
|
} else {
|
||||||
|
appStatus = APPSTATUS.unAuthenticated;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return appStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
setAppStatus(APPSTATUS status) {
|
||||||
|
appStatus = status;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
setUnverified(bool unverified, {bool isFromLogin = false}) {
|
||||||
|
this.unverified = unverified;
|
||||||
|
this.isFromLogin = isFromLogin;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// logout function
|
||||||
|
logout({bool isFromLogin = false}) async {
|
||||||
|
// localToken = "";
|
||||||
|
// String lang = await sharedPref.getString(APP_Language);
|
||||||
|
// await Utils.clearSharedPref();
|
||||||
|
// doctorProfile = null;
|
||||||
|
// sharedPref.setString(APP_Language, lang);
|
||||||
|
// deleteUser();
|
||||||
|
// await getDeviceInfoFromFirebase();
|
||||||
|
// this.isFromLogin = isFromLogin;
|
||||||
|
// appStatus = APPSTATUS.unAuthenticated;
|
||||||
|
// setState(ViewState.Idle);
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteUser() {
|
||||||
|
// user = null;
|
||||||
|
// unverified = false;
|
||||||
|
// isLogin = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
startSMSService(AuthMethodTypes type, {isSilentLogin = false, required BuildContext context}) {
|
||||||
|
OtpDialog(
|
||||||
|
type: 1,
|
||||||
|
mobileNo: 0504278212,
|
||||||
|
onSuccess: (String otpCode, TextEditingController pinPut) {
|
||||||
|
Utils.showLoading();
|
||||||
|
//TODO: API CALL
|
||||||
|
// performDirectApiCall(_title, _icon, _flag, value);
|
||||||
|
},
|
||||||
|
onFailure: () => Navigator.pop(context),
|
||||||
|
onResendCode: () {})
|
||||||
|
.displayDialog(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,135 @@
|
|||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
import 'package:hexcolor/hexcolor.dart';
|
||||||
|
import 'package:hmg_nurses/classes/colors.dart';
|
||||||
|
import 'package:hmg_nurses/classes/enums.dart';
|
||||||
|
import 'package:hmg_nurses/classes/size_config.dart';
|
||||||
|
import 'package:hmg_nurses/generated/locale_keys.g.dart';
|
||||||
|
import 'package:hmg_nurses/ui/login/login_vm.dart';
|
||||||
|
import 'package:local_auth/local_auth.dart';
|
||||||
|
|
||||||
|
class VerificationMethodsList extends StatefulWidget {
|
||||||
|
final AuthMethodTypes authMethodType;
|
||||||
|
final Function(AuthMethodTypes type, bool isActive)? authenticateUser;
|
||||||
|
final Function? onShowMore;
|
||||||
|
final LoginViewModel loginViewModel;
|
||||||
|
|
||||||
|
const VerificationMethodsList({Key? key, required this.authMethodType, this.authenticateUser, this.onShowMore, required this.loginViewModel}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
VerificationMethodsListState createState() => VerificationMethodsListState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class VerificationMethodsListState extends State<VerificationMethodsList> {
|
||||||
|
final LocalAuthentication auth = LocalAuthentication();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
switch (widget.authMethodType) {
|
||||||
|
case AuthMethodTypes.whatsApp:
|
||||||
|
return MethodTypeCard(
|
||||||
|
assetPath: 'assets/images/login/verify_whatsapp.svg',
|
||||||
|
onTap: () => {widget.authenticateUser!(AuthMethodTypes.whatsApp, true)},
|
||||||
|
label: LocaleKeys.verifyThroughWhatsapp.tr(),
|
||||||
|
);
|
||||||
|
case AuthMethodTypes.sms:
|
||||||
|
return MethodTypeCard(
|
||||||
|
assetPath: "assets/images/login/verify_sms.svg",
|
||||||
|
onTap: () => {widget.authenticateUser!(AuthMethodTypes.sms, true)},
|
||||||
|
label: LocaleKeys.verifyThroughSMS.tr(),
|
||||||
|
);
|
||||||
|
case AuthMethodTypes.fingerPrint:
|
||||||
|
return MethodTypeCard(
|
||||||
|
assetPath: 'assets/images/login/verify_thumb.svg',
|
||||||
|
onTap: () => {widget.authenticateUser!(AuthMethodTypes.fingerPrint, true)},
|
||||||
|
label: LocaleKeys.verifyThroughFingerprint.tr(),
|
||||||
|
);
|
||||||
|
case AuthMethodTypes.faceID:
|
||||||
|
return MethodTypeCard(
|
||||||
|
assetPath: 'assets/images/login/verify_face.svg',
|
||||||
|
onTap: () => {widget.authenticateUser!(AuthMethodTypes.faceID, true)},
|
||||||
|
label: LocaleKeys.verifyThroughFace.tr(),
|
||||||
|
);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return MethodTypeCard(
|
||||||
|
assetPath: 'assets/images/login/more_icon.png',
|
||||||
|
onTap: () {
|
||||||
|
widget.onShowMore!();
|
||||||
|
},
|
||||||
|
isSvg: false,
|
||||||
|
label: LocaleKeys.moreVerificationOpts.tr(),
|
||||||
|
height: 0,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MethodTypeCard extends StatelessWidget {
|
||||||
|
const MethodTypeCard({
|
||||||
|
Key? key,
|
||||||
|
required this.assetPath,
|
||||||
|
required this.onTap,
|
||||||
|
required this.label,
|
||||||
|
this.height = 20,
|
||||||
|
this.isSvg = true,
|
||||||
|
}) : super(key: key);
|
||||||
|
final String assetPath;
|
||||||
|
final GestureTapCallback onTap;
|
||||||
|
final String label;
|
||||||
|
final double height;
|
||||||
|
final bool isSvg;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
double cardHeight = SizeConfig.heightMultiplier! *
|
||||||
|
(SizeConfig.isHeightVeryShort
|
||||||
|
? 22
|
||||||
|
: SizeConfig.isHeightLarge
|
||||||
|
? 25
|
||||||
|
: 20);
|
||||||
|
return InkWell(
|
||||||
|
onTap: onTap,
|
||||||
|
child: Container(
|
||||||
|
margin: const EdgeInsets.all(10),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: const BorderRadius.all(Radius.circular(10)),
|
||||||
|
border: Border.all(color: HexColor('#707070'), width: 0.1),
|
||||||
|
),
|
||||||
|
height: cardHeight,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(12.0),
|
||||||
|
child: Center(
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: <Widget>[
|
||||||
|
isSvg
|
||||||
|
? SvgPicture.asset(assetPath, width: SizeConfig.widthMultiplier! * (14), height: cardHeight * 0.20)
|
||||||
|
: Image.asset(
|
||||||
|
assetPath,
|
||||||
|
width: SizeConfig.widthMultiplier! * (12),
|
||||||
|
height: cardHeight * 0.35,
|
||||||
|
// height: ,
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: height,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
label,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: SizeConfig.getTextMultiplierBasedOnWidth() * (SizeConfig.isHeightVeryShort ? 3 : 3.7),
|
||||||
|
color: MyColors.darkTextColor,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
letterSpacing: -0.48,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,71 @@
|
|||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hmg_nurses/generated/locale_keys.g.dart';
|
||||||
|
import 'package:sizer/sizer.dart';
|
||||||
|
|
||||||
|
class CustomCupertinoPicker {
|
||||||
|
static TextStyle textStyle(context) => TextStyle(color: Theme.of(context).primaryColor);
|
||||||
|
|
||||||
|
static int cupertinoPickerIndex = 0;
|
||||||
|
|
||||||
|
static buildPickerItems(context, List items, onSelectFun) {
|
||||||
|
return CupertinoPicker(
|
||||||
|
magnification: 1.5,
|
||||||
|
scrollController: FixedExtentScrollController(initialItem: cupertinoPickerIndex),
|
||||||
|
itemExtent: 25,
|
||||||
|
looping: false,
|
||||||
|
onSelectedItemChanged: (int index) {
|
||||||
|
cupertinoPickerIndex = index;
|
||||||
|
},
|
||||||
|
children: items.map((item) {
|
||||||
|
return Text(
|
||||||
|
'${item.facilityName}',
|
||||||
|
style: TextStyle(fontSize: 12.sp),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static showCupertinoPicker(context, List items, onSelectFun) {
|
||||||
|
showModalBottomSheet(
|
||||||
|
isDismissible: false,
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext builder) {
|
||||||
|
return Container(
|
||||||
|
height: 40.h,
|
||||||
|
color: const Color(0xfff7f7f7),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: <Widget>[
|
||||||
|
Container(
|
||||||
|
color: const Color(0xfff7f7f7),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: <Widget>[
|
||||||
|
CupertinoButton(
|
||||||
|
child: Text(LocaleKeys.userID.tr(), style: textStyle(context)),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
CupertinoButton(
|
||||||
|
child: Text(
|
||||||
|
LocaleKeys.userID.tr(),
|
||||||
|
style: textStyle(context),
|
||||||
|
),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
onSelectFun(cupertinoPickerIndex);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(height: 3.h, color: const Color(0xfff7f7f7), child: buildPickerItems(context, items, onSelectFun))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||